diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2013-07-10 06:09:47 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2013-08-27 04:54:07 -0400 |
commit | ca8b387803072a16baf6d8090591b10bfdf4e253 (patch) | |
tree | 369a7e9cc93d4ff6d7e9445d57ef933a107eb75f | |
parent | 115357e9774ff8d70a84d3c31f271209913637b0 (diff) |
DMA: shdma: support the new CHCLR register layout
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>
-rw-r--r-- | drivers/dma/sh/shdma.c | 14 | ||||
-rw-r--r-- | include/linux/sh_dma.h | 34 |
2 files changed, 45 insertions, 3 deletions
diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index 9ee1272604b4..53bd6308fc2f 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c | |||
@@ -49,12 +49,22 @@ | |||
49 | static DEFINE_SPINLOCK(sh_dmae_lock); | 49 | static DEFINE_SPINLOCK(sh_dmae_lock); |
50 | static LIST_HEAD(sh_dmae_devices); | 50 | static LIST_HEAD(sh_dmae_devices); |
51 | 51 | ||
52 | /* | ||
53 | * Different DMAC implementations provide different ways to clear DMA channels: | ||
54 | * (1) none - no CHCLR registers are available | ||
55 | * (2) one CHCLR register per channel - 0 has to be written to it to clear | ||
56 | * channel buffers | ||
57 | * (3) one CHCLR per several channels - 1 has to be written to the bit, | ||
58 | * corresponding to the specific channel to reset it | ||
59 | */ | ||
52 | static void channel_clear(struct sh_dmae_chan *sh_dc) | 60 | static void channel_clear(struct sh_dmae_chan *sh_dc) |
53 | { | 61 | { |
54 | struct sh_dmae_device *shdev = to_sh_dev(sh_dc); | 62 | struct sh_dmae_device *shdev = to_sh_dev(sh_dc); |
63 | const struct sh_dmae_channel *chan_pdata = shdev->pdata->channel + | ||
64 | sh_dc->shdma_chan.id; | ||
65 | u32 val = shdev->pdata->chclr_bitwise ? 1 << chan_pdata->chclr_bit : 0; | ||
55 | 66 | ||
56 | __raw_writel(0, shdev->chan_reg + | 67 | __raw_writel(val, shdev->chan_reg + chan_pdata->chclr_offset); |
57 | shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset); | ||
58 | } | 68 | } |
59 | 69 | ||
60 | static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) | 70 | static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) |
diff --git a/include/linux/sh_dma.h b/include/linux/sh_dma.h index 4e83f3e034f3..776ed9d682f4 100644 --- a/include/linux/sh_dma.h +++ b/include/linux/sh_dma.h | |||
@@ -33,13 +33,44 @@ struct sh_dmae_slave_config { | |||
33 | char mid_rid; | 33 | char mid_rid; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | /** | ||
37 | * struct sh_dmae_channel - DMAC channel platform data | ||
38 | * @offset: register offset within the main IOMEM resource | ||
39 | * @dmars: channel DMARS register offset | ||
40 | * @chclr_offset: channel CHCLR register offset | ||
41 | * @dmars_bit: channel DMARS field offset within the register | ||
42 | * @chclr_bit: bit position, to be set to reset the channel | ||
43 | */ | ||
36 | struct sh_dmae_channel { | 44 | struct sh_dmae_channel { |
37 | unsigned int offset; | 45 | unsigned int offset; |
38 | unsigned int dmars; | 46 | unsigned int dmars; |
39 | unsigned int dmars_bit; | ||
40 | unsigned int chclr_offset; | 47 | unsigned int chclr_offset; |
48 | unsigned char dmars_bit; | ||
49 | unsigned char chclr_bit; | ||
41 | }; | 50 | }; |
42 | 51 | ||
52 | /** | ||
53 | * struct sh_dmae_pdata - DMAC platform data | ||
54 | * @slave: array of slaves | ||
55 | * @slave_num: number of slaves in the above array | ||
56 | * @channel: array of DMA channels | ||
57 | * @channel_num: number of channels in the above array | ||
58 | * @ts_low_shift: shift of the low part of the TS field | ||
59 | * @ts_low_mask: low TS field mask | ||
60 | * @ts_high_shift: additional shift of the high part of the TS field | ||
61 | * @ts_high_mask: high TS field mask | ||
62 | * @ts_shift: array of Transfer Size shifts, indexed by TS value | ||
63 | * @ts_shift_num: number of shifts in the above array | ||
64 | * @dmaor_init: DMAOR initialisation value | ||
65 | * @chcr_offset: CHCR address offset | ||
66 | * @chcr_ie_bit: CHCR Interrupt Enable bit | ||
67 | * @dmaor_is_32bit: DMAOR is a 32-bit register | ||
68 | * @needs_tend_set: the TEND register has to be set | ||
69 | * @no_dmars: DMAC has no DMARS registers | ||
70 | * @chclr_present: DMAC has one or several CHCLR registers | ||
71 | * @chclr_bitwise: channel CHCLR registers are bitwise | ||
72 | * @slave_only: DMAC cannot be used for MEMCPY | ||
73 | */ | ||
43 | struct sh_dmae_pdata { | 74 | struct sh_dmae_pdata { |
44 | const struct sh_dmae_slave_config *slave; | 75 | const struct sh_dmae_slave_config *slave; |
45 | int slave_num; | 76 | int slave_num; |
@@ -59,6 +90,7 @@ struct sh_dmae_pdata { | |||
59 | unsigned int needs_tend_set:1; | 90 | unsigned int needs_tend_set:1; |
60 | unsigned int no_dmars:1; | 91 | unsigned int no_dmars:1; |
61 | unsigned int chclr_present:1; | 92 | unsigned int chclr_present:1; |
93 | unsigned int chclr_bitwise:1; | ||
62 | unsigned int slave_only:1; | 94 | unsigned int slave_only:1; |
63 | }; | 95 | }; |
64 | 96 | ||