diff options
author | Lothar Waßmann <LW@KARO-electronics.de> | 2011-08-08 08:47:47 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2011-08-16 09:03:42 -0400 |
commit | ef298c21c0d9c06ed89ea2fa724c3a018acfff39 (patch) | |
tree | 1b43a0b45cc2d5cb863bea0ea9e8e1271ffd378f | |
parent | a16e470caa173d323ef68dcac98c899b95fa4f84 (diff) |
mxs-dma: enable CLKGATE before accessing registers
After calling mxs_dma_disable_chan() for a channel, that channel
becomes unusable because some controller registers can only be written
when the clock is enabled via CLKGATE.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r-- | drivers/dma/mxs-dma.c | 45 |
1 files changed, 24 insertions, 21 deletions
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index be641cbd36fc..b4588bdd98bb 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c | |||
@@ -130,6 +130,23 @@ struct mxs_dma_engine { | |||
130 | struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; | 130 | struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; |
131 | }; | 131 | }; |
132 | 132 | ||
133 | static inline void mxs_dma_clkgate(struct mxs_dma_chan *mxs_chan, int enable) | ||
134 | { | ||
135 | struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; | ||
136 | int chan_id = mxs_chan->chan.chan_id; | ||
137 | int set_clr = enable ? MXS_CLR_ADDR : MXS_SET_ADDR; | ||
138 | |||
139 | /* enable apbh channel clock */ | ||
140 | if (dma_is_apbh()) { | ||
141 | if (apbh_is_old()) | ||
142 | writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), | ||
143 | mxs_dma->base + HW_APBHX_CTRL0 + set_clr); | ||
144 | else | ||
145 | writel(1 << chan_id, | ||
146 | mxs_dma->base + HW_APBHX_CTRL0 + set_clr); | ||
147 | } | ||
148 | } | ||
149 | |||
133 | static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan) | 150 | static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan) |
134 | { | 151 | { |
135 | struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; | 152 | struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; |
@@ -148,38 +165,21 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan) | |||
148 | struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; | 165 | struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; |
149 | int chan_id = mxs_chan->chan.chan_id; | 166 | int chan_id = mxs_chan->chan.chan_id; |
150 | 167 | ||
168 | /* clkgate needs to be enabled before writing other registers */ | ||
169 | mxs_dma_clkgate(mxs_chan, 1); | ||
170 | |||
151 | /* set cmd_addr up */ | 171 | /* set cmd_addr up */ |
152 | writel(mxs_chan->ccw_phys, | 172 | writel(mxs_chan->ccw_phys, |
153 | mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id)); | 173 | mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id)); |
154 | 174 | ||
155 | /* enable apbh channel clock */ | ||
156 | if (dma_is_apbh()) { | ||
157 | if (apbh_is_old()) | ||
158 | writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), | ||
159 | mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); | ||
160 | else | ||
161 | writel(1 << chan_id, | ||
162 | mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); | ||
163 | } | ||
164 | |||
165 | /* write 1 to SEMA to kick off the channel */ | 175 | /* write 1 to SEMA to kick off the channel */ |
166 | writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id)); | 176 | writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id)); |
167 | } | 177 | } |
168 | 178 | ||
169 | static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan) | 179 | static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan) |
170 | { | 180 | { |
171 | struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; | ||
172 | int chan_id = mxs_chan->chan.chan_id; | ||
173 | |||
174 | /* disable apbh channel clock */ | 181 | /* disable apbh channel clock */ |
175 | if (dma_is_apbh()) { | 182 | mxs_dma_clkgate(mxs_chan, 0); |
176 | if (apbh_is_old()) | ||
177 | writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), | ||
178 | mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); | ||
179 | else | ||
180 | writel(1 << chan_id, | ||
181 | mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); | ||
182 | } | ||
183 | 183 | ||
184 | mxs_chan->status = DMA_SUCCESS; | 184 | mxs_chan->status = DMA_SUCCESS; |
185 | } | 185 | } |
@@ -338,7 +338,10 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan) | |||
338 | if (ret) | 338 | if (ret) |
339 | goto err_clk; | 339 | goto err_clk; |
340 | 340 | ||
341 | /* clkgate needs to be enabled for reset to finish */ | ||
342 | mxs_dma_clkgate(mxs_chan, 1); | ||
341 | mxs_dma_reset_chan(mxs_chan); | 343 | mxs_dma_reset_chan(mxs_chan); |
344 | mxs_dma_clkgate(mxs_chan, 0); | ||
342 | 345 | ||
343 | dma_async_tx_descriptor_init(&mxs_chan->desc, chan); | 346 | dma_async_tx_descriptor_init(&mxs_chan->desc, chan); |
344 | mxs_chan->desc.tx_submit = mxs_dma_tx_submit; | 347 | mxs_chan->desc.tx_submit = mxs_dma_tx_submit; |