dw_dmac: autoconfigure data_width or get it via platform data
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Fri, 21 Sep 2012 12:05:48 +0000 (15:05 +0300)
committerVinod Koul <vinod.koul@linux.intel.com>
Thu, 27 Sep 2012 10:05:23 +0000 (15:35 +0530)
Not all of the controllers support the 64 bit data width. Make it configurable
via platform data. The driver will try to get a value from the component
parameters, otherwise it will use the platform data.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
arch/arm/mach-spear13xx/spear13xx.c
arch/avr32/mach-at32ap/at32ap700x.c
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h
include/linux/dw_dmac.h

index c64d8123518f29207d0c6ad81bc3c4a17b141583..6a7dfe1857b62d6f8c3564a1068269f3d780121f 100644 (file)
@@ -79,6 +79,8 @@ struct dw_dma_platform_data dmac_plat_data = {
        .chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
        .chan_priority = CHAN_PRIORITY_DESCENDING,
        .block_size = 4095U,
+       .nr_masters = 2,
+       .data_width = { 3, 3, 0, 0 },
 };
 
 void __init spear13xx_l2x0_init(void)
index 2c4aefeb86b57de8da6b7b0875f1bbbc339f33ca..b323d8d3185b35b91a21da1857bcd340d935449c 100644 (file)
@@ -606,6 +606,8 @@ static void __init genclk_init_parent(struct clk *clk)
 static struct dw_dma_platform_data dw_dmac0_data = {
        .nr_channels    = 3,
        .block_size     = 4095U,
+       .nr_masters     = 2,
+       .data_width     = { 2, 2, 0, 0 },
 };
 
 static struct resource dw_dmac0_resource[] = {
index c143b7e40716ec805e26095a245c1ed7dcf9c473..cdc0a1fe2c6481f27bd2c08c047214bdf07dfddf 100644 (file)
  * which does not support descriptor writeback.
  */
 
+static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
+{
+       return slave ? slave->dst_master : 0;
+}
+
+static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
+{
+       return slave ? slave->src_master : 1;
+}
+
 #define DWC_DEFAULT_CTLLO(_chan) ({                            \
                struct dw_dma_slave *__slave = (_chan->private);        \
                struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan);       \
                struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \
-               int _dms = __slave ? __slave->dst_master : 0;   \
-               int _sms = __slave ? __slave->src_master : 1;   \
+               int _dms = dwc_get_dms(__slave);                \
+               int _sms = dwc_get_sms(__slave);                \
                u8 _smsize = __slave ? _sconfig->src_maxburst : \
                        DW_DMA_MSIZE_16;                        \
                u8 _dmsize = __slave ? _sconfig->dst_maxburst : \
@@ -631,6 +641,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                size_t len, unsigned long flags)
 {
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
+       struct dw_dma_slave     *dws = chan->private;
        struct dw_desc          *desc;
        struct dw_desc          *first;
        struct dw_desc          *prev;
@@ -650,7 +661,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                return NULL;
        }
 
-       src_width = dst_width = dwc_fast_fls(src | dest | len);
+       src_width = min_t(unsigned int, dwc->dw->data_width[dwc_get_sms(dws)],
+                         dwc_fast_fls(src | len));
+
+       dst_width = min_t(unsigned int, dwc->dw->data_width[dwc_get_dms(dws)],
+                         dwc_fast_fls(dest | len));
 
        ctllo = DWC_DEFAULT_CTLLO(chan)
                        | DWC_CTLL_DST_WIDTH(dst_width)
@@ -720,6 +735,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        dma_addr_t              reg;
        unsigned int            reg_width;
        unsigned int            mem_width;
+       unsigned int            data_width;
        unsigned int            i;
        struct scatterlist      *sg;
        size_t                  total_len = 0;
@@ -743,6 +759,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
                        DWC_CTLL_FC(DW_DMA_FC_D_M2P);
 
+               data_width = dwc->dw->data_width[dwc_get_sms(dws)];
+
                for_each_sg(sgl, sg, sg_len, i) {
                        struct dw_desc  *desc;
                        u32             len, dlen, mem;
@@ -750,7 +768,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        mem = sg_dma_address(sg);
                        len = sg_dma_len(sg);
 
-                       mem_width = dwc_fast_fls(mem | len);
+                       mem_width = min_t(unsigned int,
+                                         data_width, dwc_fast_fls(mem | len));
 
 slave_sg_todev_fill_desc:
                        desc = dwc_desc_get(dwc);
@@ -803,6 +822,8 @@ slave_sg_todev_fill_desc:
                ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
                        DWC_CTLL_FC(DW_DMA_FC_D_P2M);
 
+               data_width = dwc->dw->data_width[dwc_get_dms(dws)];
+
                for_each_sg(sgl, sg, sg_len, i) {
                        struct dw_desc  *desc;
                        u32             len, dlen, mem;
@@ -810,7 +831,8 @@ slave_sg_todev_fill_desc:
                        mem = sg_dma_address(sg);
                        len = sg_dma_len(sg);
 
-                       mem_width = dwc_fast_fls(mem | len);
+                       mem_width = min_t(unsigned int,
+                                         data_width, dwc_fast_fls(mem | len));
 
 slave_sg_fromdev_fill_desc:
                        desc = dwc_desc_get(dwc);
@@ -1415,9 +1437,19 @@ static int __devinit dw_probe(struct platform_device *pdev)
        dw->regs = regs;
 
        /* get hardware configuration parameters */
-       if (autocfg)
+       if (autocfg) {
                max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
 
+               dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
+               for (i = 0; i < dw->nr_masters; i++) {
+                       dw->data_width[i] =
+                               (dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
+               }
+       } else {
+               dw->nr_masters = pdata->nr_masters;
+               memcpy(dw->data_width, pdata->data_width, 4);
+       }
+
        /* Calculate all channel mask before DMA setup */
        dw->all_chan_mask = (1 << nr_channels) - 1;
 
@@ -1464,6 +1496,8 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
                channel_clear_bit(dw, CH_EN, dwc->mask);
 
+               dwc->dw = dw;
+
                /* hardware configuration */
                if (autocfg)
                        /* Decode maximum block size for given channel. The
index 2a1cc533f0c88c05ea1ddad6740a33b789fc66c3..06f03914f02282f779d1a4afbd29ad0d81e677c2 100644 (file)
@@ -198,6 +198,9 @@ struct dw_dma_chan {
 
        /* configuration passed via DMA_SLAVE_CONFIG */
        struct dma_slave_config dma_sconfig;
+
+       /* backlink to dw_dma */
+       struct dw_dma           *dw;
 };
 
 static inline struct dw_dma_chan_regs __iomem *
@@ -224,6 +227,10 @@ struct dw_dma {
 
        u8                      all_chan_mask;
 
+       /* hardware configuration */
+       unsigned char           nr_masters;
+       unsigned char           data_width[4];
+
        struct dw_dma_chan      chan[0];
 };
 
index 3315ef9c785b74ac37dec589efa892bc3bf2a664..e1c8c9e919ac74401b566ccc08f9eeee67ca0a45 100644 (file)
@@ -20,6 +20,9 @@
  * @is_private: The device channels should be marked as private and not for
  *     by the general purpose DMA channel allocator.
  * @block_size: Maximum block size supported by the controller
+ * @nr_masters: Number of AHB masters supported by the controller
+ * @data_width: Maximum data width supported by hardware per AHB master
+ *             (0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
  */
 struct dw_dma_platform_data {
        unsigned int    nr_channels;
@@ -31,6 +34,8 @@ struct dw_dma_platform_data {
 #define CHAN_PRIORITY_DESCENDING       1       /* chan7 highest */
        unsigned char   chan_priority;
        unsigned short  block_size;
+       unsigned char   nr_masters;
+       unsigned char   data_width[4];
 };
 
 /* bursts size */