DMA: shdma: support the new CHCLR register layout
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Wed, 10 Jul 2013 10:09:47 +0000 (12:09 +0200)
committerVinod Koul <vinod.koul@intel.com>
Tue, 27 Aug 2013 08:54:07 +0000 (14:24 +0530)
On newer r-car SoCs the CHCLR register only contains one bit per channel,
to which a 1 has to be written to reset the channel. Older SoC versions had
one CHCLR register per channel, to which a 0 must be written to reset the
channel and clear its buffers. This patch adds support for the newer
layout.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski+renesas@gmail.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/sh/shdma.c
include/linux/sh_dma.h

index 9ee1272604b4e62fdb8ddaf38c113acb8cc2f766..53bd6308fc2fffdbaa678228b03b19756b02bf9f 100644 (file)
 static DEFINE_SPINLOCK(sh_dmae_lock);
 static LIST_HEAD(sh_dmae_devices);
 
+/*
+ * Different DMAC implementations provide different ways to clear DMA channels:
+ * (1) none - no CHCLR registers are available
+ * (2) one CHCLR register per channel - 0 has to be written to it to clear
+ *     channel buffers
+ * (3) one CHCLR per several channels - 1 has to be written to the bit,
+ *     corresponding to the specific channel to reset it
+ */
 static void channel_clear(struct sh_dmae_chan *sh_dc)
 {
        struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+       const struct sh_dmae_channel *chan_pdata = shdev->pdata->channel +
+               sh_dc->shdma_chan.id;
+       u32 val = shdev->pdata->chclr_bitwise ? 1 << chan_pdata->chclr_bit : 0;
 
-       __raw_writel(0, shdev->chan_reg +
-               shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset);
+       __raw_writel(val, shdev->chan_reg + chan_pdata->chclr_offset);
 }
 
 static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
index 4e83f3e034f3873d531580550a1940b4b49f6461..776ed9d682f498d27da12a38307b358481b6e32e 100644 (file)
@@ -33,13 +33,44 @@ struct sh_dmae_slave_config {
        char            mid_rid;
 };
 
+/**
+ * struct sh_dmae_channel - DMAC channel platform data
+ * @offset:            register offset within the main IOMEM resource
+ * @dmars:             channel DMARS register offset
+ * @chclr_offset:      channel CHCLR register offset
+ * @dmars_bit:         channel DMARS field offset within the register
+ * @chclr_bit:         bit position, to be set to reset the channel
+ */
 struct sh_dmae_channel {
        unsigned int    offset;
        unsigned int    dmars;
-       unsigned int    dmars_bit;
        unsigned int    chclr_offset;
+       unsigned char   dmars_bit;
+       unsigned char   chclr_bit;
 };
 
+/**
+ * struct sh_dmae_pdata - DMAC platform data
+ * @slave:             array of slaves
+ * @slave_num:         number of slaves in the above array
+ * @channel:           array of DMA channels
+ * @channel_num:       number of channels in the above array
+ * @ts_low_shift:      shift of the low part of the TS field
+ * @ts_low_mask:       low TS field mask
+ * @ts_high_shift:     additional shift of the high part of the TS field
+ * @ts_high_mask:      high TS field mask
+ * @ts_shift:          array of Transfer Size shifts, indexed by TS value
+ * @ts_shift_num:      number of shifts in the above array
+ * @dmaor_init:                DMAOR initialisation value
+ * @chcr_offset:       CHCR address offset
+ * @chcr_ie_bit:       CHCR Interrupt Enable bit
+ * @dmaor_is_32bit:    DMAOR is a 32-bit register
+ * @needs_tend_set:    the TEND register has to be set
+ * @no_dmars:          DMAC has no DMARS registers
+ * @chclr_present:     DMAC has one or several CHCLR registers
+ * @chclr_bitwise:     channel CHCLR registers are bitwise
+ * @slave_only:                DMAC cannot be used for MEMCPY
+ */
 struct sh_dmae_pdata {
        const struct sh_dmae_slave_config *slave;
        int slave_num;
@@ -59,6 +90,7 @@ struct sh_dmae_pdata {
        unsigned int needs_tend_set:1;
        unsigned int no_dmars:1;
        unsigned int chclr_present:1;
+       unsigned int chclr_bitwise:1;
        unsigned int slave_only:1;
 };