]> Git Repo - linux.git/commitdiff
Merge tag 'davinci-for-v3.16/edma' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorOlof Johansson <[email protected]>
Mon, 26 May 2014 21:59:05 +0000 (14:59 -0700)
committerOlof Johansson <[email protected]>
Mon, 26 May 2014 21:59:05 +0000 (14:59 -0700)
Merge "DaVinci EDMA clean-up for v3.16" from Sekhar Nori:

This series makes edma use configuration information available within
the IP instead of reading it from platform data or DT. Some other useful
clean-ups are included too.

* tag 'davinci-for-v3.16/edma' of git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci: (34 commits)
  ARM: edma: Remove redundant/unused parameters from edma_soc_info
  ARM: davinci: Remove redundant/unused parameters for edma
  ARM: dts: am4372: Remove obsolete properties from edma node
  ARM: dts: am33xx: Remove obsolete properties from edma node
  dt/bindings: ti,edma: Remove redundant properties from documentation
  ARM: edma: Get IP configuration from HW (number of channels, tc, etc)
  ARM: edma: Save number of regions from pdata to struct edma
  ARM: edma: Remove num_cc member from struct edma
  ARM: edma: Remove queue_tc_mapping data from edma_soc_info
  ARM: davinci: Remove eDMA3 queue_tc_mapping data from edma_soc_info
  ARM: edma: Do not change TC -> Queue mapping, leave it to default.
  ARM: edma: Take the number of tc from edma_soc_info (pdata)
  ARM: edma: No need to clean the pdata in edma_of_parse_dt()
  ARM: edma: Clean up and simplify the code around irq request
  dmaengine: edma: update DMA memcpy to use new param element
  dmaengine: edma: Document variables used for residue accounting
  dmaengine: edma: Provide granular accounting
  dmaengine: edma: Make reading the position of active channels work
  dmaengine: edma: Store transfer data in edma_desc and edma_pset
  dmaengine: edma: Create private pset struct
  ...

Signed-off-by: Olof Johansson <[email protected]>
1  2 
Documentation/devicetree/bindings/dma/ti-edma.txt
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/am4372.dtsi
arch/arm/common/edma.c

index 68ff2137bae7261e84409a472fbf432989fca0d6,ad67c41c38dffb7b187e64405c025f68eb1b9e7c..5ba525a10035b82eb1dda911a1e33c08e2d74746
@@@ -2,11 -2,8 +2,8 @@@ TI EDM
  
  Required properties:
  - compatible : "ti,edma3"
- - ti,edma-regions: Number of regions
- - ti,edma-slots: Number of slots
  - #dma-cells: Should be set to <1>
                Clients should use a single channel number per DMA request.
- - dma-channels: Specify total DMA channels per CC
  - reg: Memory map for accessing module
  - interrupt-parent: Interrupt controller the interrupt is routed through
  - interrupts: Exactly 3 interrupts need to be specified in the order:
@@@ -17,6 -14,13 +14,13 @@@ Optional properties
  - ti,hwmods: Name of the hwmods associated to the EDMA
  - ti,edma-xbar-event-map: Crossbar event to channel map
  
+ Deprecated properties:
+ Listed here in case one wants to boot an old kernel with new DTB. These
+ properties might need to be added to the new DTS files.
+ - ti,edma-regions: Number of regions
+ - ti,edma-slots: Number of slots
+ - dma-channels: Specify total DMA channels per CC
  Example:
  
  edma: edma@49000000 {
@@@ -26,9 -30,6 +30,6 @@@
        compatible = "ti,edma3";
        ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
        #dma-cells = <1>;
-       dma-channels = <64>;
-       ti,edma-regions = <4>;
-       ti,edma-slots = <256>;
 -      ti,edma-xbar-event-map = <1 12
 -                                2 13>;
 +      ti,edma-xbar-event-map = /bits/ 16 <1 12
 +                                          2 13>;
  };
index 7ad75b4e066358f5229d93d0d017c754a711ca32,50d8d2f934907e8a6829be877ada1fce7a82fe66..99e572c45244b834fa2085e3de95ded3b7244cc9
@@@ -72,7 -72,7 +72,7 @@@
        };
  
        /*
 -       * The soc node represents the soc top level view. It is uses for IPs
 +       * The soc node represents the soc top level view. It is used for IPs
         * that are not memory mapped in the MPU view or for the MPU itself.
         */
        soc {
@@@ -94,8 -94,8 +94,8 @@@
  
        /*
         * XXX: Use a flat representation of the AM33XX interconnect.
 -       * The real AM33XX interconnect network is quite complex.Since
 -       * that will not bring real advantage to represent that in DT
 +       * The real AM33XX interconnect network is quite complex. Since
 +       * it will not bring real advantage to represent that in DT
         * for the moment, just use a fake OCP bus entry to represent
         * the whole bus hierarchy.
         */
                        compatible = "ti,edma3";
                        ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
                        reg =   <0x49000000 0x10000>,
 -                              <0x44e10f90 0x10>;
 +                              <0x44e10f90 0x40>;
                        interrupts = <12 13 14>;
                        #dma-cells = <1>;
-                       dma-channels = <64>;
-                       ti,edma-regions = <4>;
-                       ti,edma-slots = <256>;
                };
  
                gpio0: gpio@44e07000 {
                              <0x46000000 0x400000>;
                        reg-names = "mpu", "dat";
                        interrupts = <80>, <81>;
 -                      interrupts-names = "tx", "rx";
 +                      interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 8>,
                                <&edma 9>;
                              <0x46400000 0x400000>;
                        reg-names = "mpu", "dat";
                        interrupts = <82>, <83>;
 -                      interrupts-names = "tx", "rx";
 +                      interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 10>,
                                <&edma 11>;
index d1f8707ff1dfc46d65815ef5ae2c36dbc1c46006,94bdcc1b1ab9b12e3320f0b0e8fdec09578ae6e6..befb680e5719a69353dad2bd093d77fdd4daecf9
                                        <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
                                        <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
-                       dma-channels = <64>;
-                       ti,edma-regions = <4>;
-                       ti,edma-slots = <256>;
                };
  
                uart0: serial@44e09000 {
                              <0x46000000 0x400000>;
                        reg-names = "mpu", "dat";
                        interrupts = <80>, <81>;
 -                      interrupts-names = "tx", "rx";
 +                      interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 8>,
                               <&edma 9>;
                              <0x46400000 0x400000>;
                        reg-names = "mpu", "dat";
                        interrupts = <82>, <83>;
 -                      interrupts-names = "tx", "rx";
 +                      interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 10>,
                               <&edma 11>;
diff --combined arch/arm/common/edma.c
index 5339009b3c0ce648df92244b5d9274e78273290b,eeea011480eba8609bf993d4cb5b3e626474eebd..485be42519b96ddec1dcceafd19c84431e45cd99
  #define PARM_OFFSET(param_no) (EDMA_PARM + ((param_no) << 5))
  
  #define EDMA_DCHMAP   0x0100  /* 64 registers */
- #define CHMAP_EXIST   BIT(24)
+ /* CCCFG register */
+ #define GET_NUM_DMACH(x)      (x & 0x7) /* bits 0-2 */
+ #define GET_NUM_PAENTRY(x)    ((x & 0x7000) >> 12) /* bits 12-14 */
+ #define GET_NUM_EVQUE(x)      ((x & 0x70000) >> 16) /* bits 16-18 */
+ #define GET_NUM_REGN(x)               ((x & 0x300000) >> 20) /* bits 20-21 */
+ #define CHMAP_EXIST           BIT(24)
  
  #define EDMA_MAX_DMACH           64
  #define EDMA_MAX_PARAMENTRY     512
@@@ -233,7 -239,6 +239,6 @@@ struct edma 
        unsigned        num_region;
        unsigned        num_slots;
        unsigned        num_tc;
-       unsigned        num_cc;
        enum dma_event_q        default_queue;
  
        /* list of channels with no even trigger; terminated by "-1" */
@@@ -290,12 -295,6 +295,6 @@@ static void map_dmach_queue(unsigned ct
                        ~(0x7 << bit), queue_no << bit);
  }
  
- static void __init map_queue_tc(unsigned ctlr, int queue_no, int tc_no)
- {
-       int bit = queue_no * 4;
-       edma_modify(ctlr, EDMA_QUETCMAP, ~(0x7 << bit), ((tc_no & 0x7) << bit));
- }
  static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
                int priority)
  {
@@@ -994,29 -993,23 +993,23 @@@ void edma_set_dest(unsigned slot, dma_a
  EXPORT_SYMBOL(edma_set_dest);
  
  /**
-  * edma_get_position - returns the current transfer points
+  * edma_get_position - returns the current transfer point
   * @slot: parameter RAM slot being examined
-  * @src: pointer to source port position
-  * @dst: pointer to destination port position
+  * @dst:  true selects the dest position, false the source
   *
-  * Returns current source and destination addresses for a particular
-  * parameter RAM slot.  Its channel should not be active when this is called.
+  * Returns the position of the current active slot
   */
void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst)
dma_addr_t edma_get_position(unsigned slot, bool dst)
  {
-       struct edmacc_param temp;
-       unsigned ctlr;
+       u32 offs, ctlr = EDMA_CTLR(slot);
  
-       ctlr = EDMA_CTLR(slot);
        slot = EDMA_CHAN_SLOT(slot);
  
-       edma_read_slot(EDMA_CTLR_CHAN(ctlr, slot), &temp);
-       if (src != NULL)
-               *src = temp.src;
-       if (dst != NULL)
-               *dst = temp.dst;
+       offs = PARM_OFFSET(slot);
+       offs += dst ? PARM_DST : PARM_SRC;
+       return edma_read(ctlr, offs);
  }
- EXPORT_SYMBOL(edma_get_position);
  
  /**
   * edma_set_src_index - configure DMA source address indexing
@@@ -1421,40 -1414,118 +1414,101 @@@ void edma_clear_event(unsigned channel
  }
  EXPORT_SYMBOL(edma_clear_event);
  
+ static int edma_setup_from_hw(struct device *dev, struct edma_soc_info *pdata,
+                             struct edma *edma_cc)
+ {
+       int i;
+       u32 value, cccfg;
+       s8 (*queue_priority_map)[2];
+       /* Decode the eDMA3 configuration from CCCFG register */
+       cccfg = edma_read(0, EDMA_CCCFG);
+       value = GET_NUM_REGN(cccfg);
+       edma_cc->num_region = BIT(value);
+       value = GET_NUM_DMACH(cccfg);
+       edma_cc->num_channels = BIT(value + 1);
+       value = GET_NUM_PAENTRY(cccfg);
+       edma_cc->num_slots = BIT(value + 4);
+       value = GET_NUM_EVQUE(cccfg);
+       edma_cc->num_tc = value + 1;
+       dev_dbg(dev, "eDMA3 HW configuration (cccfg: 0x%08x):\n", cccfg);
+       dev_dbg(dev, "num_region: %u\n", edma_cc->num_region);
+       dev_dbg(dev, "num_channel: %u\n", edma_cc->num_channels);
+       dev_dbg(dev, "num_slot: %u\n", edma_cc->num_slots);
+       dev_dbg(dev, "num_tc: %u\n", edma_cc->num_tc);
+       /* Nothing need to be done if queue priority is provided */
+       if (pdata->queue_priority_mapping)
+               return 0;
+       /*
+        * Configure TC/queue priority as follows:
+        * Q0 - priority 0
+        * Q1 - priority 1
+        * Q2 - priority 2
+        * ...
+        * The meaning of priority numbers: 0 highest priority, 7 lowest
+        * priority. So Q0 is the highest priority queue and the last queue has
+        * the lowest priority.
+        */
+       queue_priority_map = devm_kzalloc(dev,
+                                         (edma_cc->num_tc + 1) * sizeof(s8),
+                                         GFP_KERNEL);
+       if (!queue_priority_map)
+               return -ENOMEM;
+       for (i = 0; i < edma_cc->num_tc; i++) {
+               queue_priority_map[i][0] = i;
+               queue_priority_map[i][1] = i;
+       }
+       queue_priority_map[i][0] = -1;
+       queue_priority_map[i][1] = -1;
+       pdata->queue_priority_mapping = queue_priority_map;
+       pdata->default_queue = 0;
+       return 0;
+ }
  #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DMADEVICES)
  
 -static int edma_of_read_u32_to_s16_array(const struct device_node *np,
 -                                       const char *propname, s16 *out_values,
 -                                       size_t sz)
 +static int edma_xbar_event_map(struct device *dev, struct device_node *node,
 +                             struct edma_soc_info *pdata, size_t sz)
  {
 -      int ret;
 -
 -      ret = of_property_read_u16_array(np, propname, out_values, sz);
 -      if (ret)
 -              return ret;
 -
 -      /* Terminate it */
 -      *out_values++ = -1;
 -      *out_values++ = -1;
 -
 -      return 0;
 -}
 -
 -static int edma_xbar_event_map(struct device *dev,
 -                             struct device_node *node,
 -                             struct edma_soc_info *pdata, int len)
 -{
 -      int ret, i;
 +      const char pname[] = "ti,edma-xbar-event-map";
        struct resource res;
        void __iomem *xbar;
 -      const s16 (*xbar_chans)[2];
 +      s16 (*xbar_chans)[2];
 +      size_t nelm = sz / sizeof(s16);
        u32 shift, offset, mux;
 +      int ret, i;
  
 -      xbar_chans = devm_kzalloc(dev,
 -                                len/sizeof(s16) + 2*sizeof(s16),
 -                                GFP_KERNEL);
 +      xbar_chans = devm_kzalloc(dev, (nelm + 2) * sizeof(s16), GFP_KERNEL);
        if (!xbar_chans)
                return -ENOMEM;
  
        ret = of_address_to_resource(node, 1, &res);
        if (ret)
 -              return -EIO;
 +              return -ENOMEM;
  
        xbar = devm_ioremap(dev, res.start, resource_size(&res));
        if (!xbar)
                return -ENOMEM;
  
 -      ret = edma_of_read_u32_to_s16_array(node,
 -                                          "ti,edma-xbar-event-map",
 -                                          (s16 *)xbar_chans,
 -                                          len/sizeof(u32));
 +      ret = of_property_read_u16_array(node, pname, (u16 *)xbar_chans, nelm);
        if (ret)
                return -EIO;
  
 -      for (i = 0; xbar_chans[i][0] != -1; i++) {
 +      /* Invalidate last entry for the other user of this mess */
 +      nelm >>= 1;
 +      xbar_chans[nelm][0] = xbar_chans[nelm][1] = -1;
 +
 +      for (i = 0; i < nelm; i++) {
                shift = (xbar_chans[i][1] & 0x03) << 3;
                offset = xbar_chans[i][1] & 0xfffffffc;
                mux = readl(xbar + offset);
                writel(mux, (xbar + offset));
        }
  
 -      pdata->xbar_chans = xbar_chans;
 -
 +      pdata->xbar_chans = (const s16 (*)[2]) xbar_chans;
        return 0;
  }
  
@@@ -1471,65 -1543,16 +1525,16 @@@ static int edma_of_parse_dt(struct devi
                            struct device_node *node,
                            struct edma_soc_info *pdata)
  {
-       int ret = 0, i;
-       u32 value;
+       int ret = 0;
        struct property *prop;
        size_t sz;
        struct edma_rsv_info *rsv_info;
-       s8 (*queue_tc_map)[2], (*queue_priority_map)[2];
-       memset(pdata, 0, sizeof(struct edma_soc_info));
-       ret = of_property_read_u32(node, "dma-channels", &value);
-       if (ret < 0)
-               return ret;
-       pdata->n_channel = value;
-       ret = of_property_read_u32(node, "ti,edma-regions", &value);
-       if (ret < 0)
-               return ret;
-       pdata->n_region = value;
-       ret = of_property_read_u32(node, "ti,edma-slots", &value);
-       if (ret < 0)
-               return ret;
-       pdata->n_slot = value;
-       pdata->n_cc = 1;
  
        rsv_info = devm_kzalloc(dev, sizeof(struct edma_rsv_info), GFP_KERNEL);
        if (!rsv_info)
                return -ENOMEM;
        pdata->rsv = rsv_info;
  
-       queue_tc_map = devm_kzalloc(dev, 8*sizeof(s8), GFP_KERNEL);
-       if (!queue_tc_map)
-               return -ENOMEM;
-       for (i = 0; i < 3; i++) {
-               queue_tc_map[i][0] = i;
-               queue_tc_map[i][1] = i;
-       }
-       queue_tc_map[i][0] = -1;
-       queue_tc_map[i][1] = -1;
-       pdata->queue_tc_mapping = queue_tc_map;
-       queue_priority_map = devm_kzalloc(dev, 8*sizeof(s8), GFP_KERNEL);
-       if (!queue_priority_map)
-               return -ENOMEM;
-       for (i = 0; i < 3; i++) {
-               queue_priority_map[i][0] = i;
-               queue_priority_map[i][1] = i;
-       }
-       queue_priority_map[i][0] = -1;
-       queue_priority_map[i][1] = -1;
-       pdata->queue_priority_mapping = queue_priority_map;
-       pdata->default_queue = 0;
        prop = of_find_property(node, "ti,edma-xbar-event-map", &sz);
        if (prop)
                ret = edma_xbar_event_map(dev, node, pdata, sz);
@@@ -1556,6 -1579,7 +1561,7 @@@ static struct edma_soc_info *edma_setup
                return ERR_PTR(ret);
  
        dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap);
+       dma_cap_set(DMA_CYCLIC, edma_filter_info.dma_cap);
        of_dma_controller_register(dev->of_node, of_dma_simple_xlate,
                                   &edma_filter_info);
  
@@@ -1574,7 -1598,6 +1580,6 @@@ static int edma_probe(struct platform_d
        struct edma_soc_info    **info = pdev->dev.platform_data;
        struct edma_soc_info    *ninfo[EDMA_MAX_CC] = {NULL};
        s8              (*queue_priority_mapping)[2];
-       s8              (*queue_tc_mapping)[2];
        int                     i, j, off, ln, found = 0;
        int                     status = -1;
        const s16               (*rsv_chans)[2];
        struct resource         *r[EDMA_MAX_CC] = {NULL};
        struct resource         res[EDMA_MAX_CC];
        char                    res_name[10];
-       char                    irq_name[10];
        struct device_node      *node = pdev->dev.of_node;
        struct device           *dev = &pdev->dev;
        int                     ret;
                if (!edma_cc[j])
                        return -ENOMEM;
  
-               edma_cc[j]->num_channels = min_t(unsigned, info[j]->n_channel,
-                                                       EDMA_MAX_DMACH);
-               edma_cc[j]->num_slots = min_t(unsigned, info[j]->n_slot,
-                                                       EDMA_MAX_PARAMENTRY);
-               edma_cc[j]->num_cc = min_t(unsigned, info[j]->n_cc,
-                                                       EDMA_MAX_CC);
+               /* Get eDMA3 configuration from IP */
+               ret = edma_setup_from_hw(dev, info[j], edma_cc[j]);
+               if (ret)
+                       return ret;
  
                edma_cc[j]->default_queue = info[j]->default_queue;
  
  
                if (node) {
                        irq[j] = irq_of_parse_and_map(node, 0);
+                       err_irq[j] = irq_of_parse_and_map(node, 2);
                } else {
+                       char irq_name[10];
                        sprintf(irq_name, "edma%d", j);
                        irq[j] = platform_get_irq_byname(pdev, irq_name);
+                       sprintf(irq_name, "edma%d_err", j);
+                       err_irq[j] = platform_get_irq_byname(pdev, irq_name);
                }
                edma_cc[j]->irq_res_start = irq[j];
-               status = devm_request_irq(&pdev->dev, irq[j],
-                                         dma_irq_handler, 0, "edma",
-                                         &pdev->dev);
+               edma_cc[j]->irq_res_end = err_irq[j];
+               status = devm_request_irq(dev, irq[j], dma_irq_handler, 0,
+                                         "edma", dev);
                if (status < 0) {
                        dev_dbg(&pdev->dev,
                                "devm_request_irq %d failed --> %d\n",
                        return status;
                }
  
-               if (node) {
-                       err_irq[j] = irq_of_parse_and_map(node, 2);
-               } else {
-                       sprintf(irq_name, "edma%d_err", j);
-                       err_irq[j] = platform_get_irq_byname(pdev, irq_name);
-               }
-               edma_cc[j]->irq_res_end = err_irq[j];
-               status = devm_request_irq(&pdev->dev, err_irq[j],
-                                         dma_ccerr_handler, 0,
-                                         "edma_error", &pdev->dev);
+               status = devm_request_irq(dev, err_irq[j], dma_ccerr_handler, 0,
+                                         "edma_error", dev);
                if (status < 0) {
                        dev_dbg(&pdev->dev,
                                "devm_request_irq %d failed --> %d\n",
                for (i = 0; i < edma_cc[j]->num_channels; i++)
                        map_dmach_queue(j, i, info[j]->default_queue);
  
-               queue_tc_mapping = info[j]->queue_tc_mapping;
                queue_priority_mapping = info[j]->queue_priority_mapping;
  
-               /* Event queue to TC mapping */
-               for (i = 0; queue_tc_mapping[i][0] != -1; i++)
-                       map_queue_tc(j, queue_tc_mapping[i][0],
-                                       queue_tc_mapping[i][1]);
                /* Event queue priority mapping */
                for (i = 0; queue_priority_mapping[i][0] != -1; i++)
                        assign_priority_to_queue(j,
                if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST)
                        map_dmach_param(j);
  
-               for (i = 0; i < info[j]->n_region; i++) {
+               for (i = 0; i < edma_cc[j]->num_region; i++) {
                        edma_write_array2(j, EDMA_DRAE, i, 0, 0x0);
                        edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
                        edma_write_array(j, EDMA_QRAE, i, 0x0);
This page took 0.100118 seconds and 4 git commands to generate.