Blame view
drivers/dma/fsldma.c
34.6 KB
ea2305f6a treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
173acc7ce dmaengine: add dr... |
2 3 4 |
/* * Freescale MPC85xx, MPC83xx DMA Engine support * |
e2c8e425b fsldma: add suppo... |
5 |
* Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved. |
173acc7ce dmaengine: add dr... |
6 7 8 9 10 11 12 13 |
* * Author: * Zhang Wei <wei.zhang@freescale.com>, Jul 2007 * Ebony Zhu <ebony.zhu@freescale.com>, May 2007 * * Description: * DMA engine driver for Freescale MPC8540 DMA controller, which is * also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc. |
c2e07b3a9 Fix spelling cont... |
14 |
* The support for MPC8349 DMA controller is also added. |
173acc7ce dmaengine: add dr... |
15 |
* |
a7aea373b fsldma: use PCI R... |
16 17 18 19 |
* This driver instructs the DMA controller to issue the PCI Read Multiple * command for PCI read operations, instead of using the default PCI Read Line * command. Please be aware that this setting may result in read pre-fetching * on some platforms. |
173acc7ce dmaengine: add dr... |
20 21 22 23 24 |
*/ #include <linux/init.h> #include <linux/module.h> #include <linux/pci.h> |
5a0e3ad6a include cleanup: ... |
25 |
#include <linux/slab.h> |
173acc7ce dmaengine: add dr... |
26 27 28 29 30 |
#include <linux/interrupt.h> #include <linux/dmaengine.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmapool.h> |
5af507300 drivers: clean-up... |
31 32 |
#include <linux/of_address.h> #include <linux/of_irq.h> |
173acc7ce dmaengine: add dr... |
33 |
#include <linux/of_platform.h> |
0a5642be0 dmaengine: freesc... |
34 |
#include <linux/fsldma.h> |
d2ebfb335 dmaengine: add pr... |
35 |
#include "dmaengine.h" |
173acc7ce dmaengine: add dr... |
36 |
#include "fsldma.h" |
b158471ef fsldma: use chann... |
37 38 39 40 |
#define chan_dbg(chan, fmt, arg...) \ dev_dbg(chan->dev, "%s: " fmt, chan->name, ##arg) #define chan_err(chan, fmt, arg...) \ dev_err(chan->dev, "%s: " fmt, chan->name, ##arg) |
c14330417 fsldma: implement... |
41 |
|
b158471ef fsldma: use chann... |
42 |
static const char msg_ld_oom[] = "No free memory for link descriptor"; |
173acc7ce dmaengine: add dr... |
43 |
|
e8bd84df2 fsldma: move rela... |
44 45 46 |
/* * Register Helpers */ |
173acc7ce dmaengine: add dr... |
47 |
|
a1c033190 fsldma: rename fs... |
48 |
static void set_sr(struct fsldma_chan *chan, u32 val) |
173acc7ce dmaengine: add dr... |
49 |
{ |
a7359e762 dmaengine: fsldma... |
50 |
FSL_DMA_OUT(chan, &chan->regs->sr, val, 32); |
173acc7ce dmaengine: add dr... |
51 |
} |
a1c033190 fsldma: rename fs... |
52 |
static u32 get_sr(struct fsldma_chan *chan) |
173acc7ce dmaengine: add dr... |
53 |
{ |
a7359e762 dmaengine: fsldma... |
54 |
return FSL_DMA_IN(chan, &chan->regs->sr, 32); |
173acc7ce dmaengine: add dr... |
55 |
} |
ccdce9a04 DMA: Freescale: u... |
56 57 |
static void set_mr(struct fsldma_chan *chan, u32 val) { |
a7359e762 dmaengine: fsldma... |
58 |
FSL_DMA_OUT(chan, &chan->regs->mr, val, 32); |
ccdce9a04 DMA: Freescale: u... |
59 60 61 62 |
} static u32 get_mr(struct fsldma_chan *chan) { |
a7359e762 dmaengine: fsldma... |
63 |
return FSL_DMA_IN(chan, &chan->regs->mr, 32); |
ccdce9a04 DMA: Freescale: u... |
64 |
} |
e8bd84df2 fsldma: move rela... |
65 66 |
static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr) { |
a7359e762 dmaengine: fsldma... |
67 |
FSL_DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64); |
e8bd84df2 fsldma: move rela... |
68 69 70 71 |
} static dma_addr_t get_cdar(struct fsldma_chan *chan) { |
a7359e762 dmaengine: fsldma... |
72 |
return FSL_DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; |
e8bd84df2 fsldma: move rela... |
73 |
} |
ccdce9a04 DMA: Freescale: u... |
74 75 |
static void set_bcr(struct fsldma_chan *chan, u32 val) { |
a7359e762 dmaengine: fsldma... |
76 |
FSL_DMA_OUT(chan, &chan->regs->bcr, val, 32); |
ccdce9a04 DMA: Freescale: u... |
77 |
} |
e8bd84df2 fsldma: move rela... |
78 79 |
static u32 get_bcr(struct fsldma_chan *chan) { |
a7359e762 dmaengine: fsldma... |
80 |
return FSL_DMA_IN(chan, &chan->regs->bcr, 32); |
e8bd84df2 fsldma: move rela... |
81 82 83 84 85 |
} /* * Descriptor Helpers */ |
a1c033190 fsldma: rename fs... |
86 |
static void set_desc_cnt(struct fsldma_chan *chan, |
173acc7ce dmaengine: add dr... |
87 88 |
struct fsl_dma_ld_hw *hw, u32 count) { |
a1c033190 fsldma: rename fs... |
89 |
hw->count = CPU_TO_DMA(chan, count, 32); |
173acc7ce dmaengine: add dr... |
90 |
} |
a1c033190 fsldma: rename fs... |
91 |
static void set_desc_src(struct fsldma_chan *chan, |
31f4306c8 fsldma: minor cod... |
92 |
struct fsl_dma_ld_hw *hw, dma_addr_t src) |
173acc7ce dmaengine: add dr... |
93 94 |
{ u64 snoop_bits; |
a1c033190 fsldma: rename fs... |
95 |
snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) |
173acc7ce dmaengine: add dr... |
96 |
? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0; |
a1c033190 fsldma: rename fs... |
97 |
hw->src_addr = CPU_TO_DMA(chan, snoop_bits | src, 64); |
173acc7ce dmaengine: add dr... |
98 |
} |
a1c033190 fsldma: rename fs... |
99 |
static void set_desc_dst(struct fsldma_chan *chan, |
31f4306c8 fsldma: minor cod... |
100 |
struct fsl_dma_ld_hw *hw, dma_addr_t dst) |
173acc7ce dmaengine: add dr... |
101 102 |
{ u64 snoop_bits; |
a1c033190 fsldma: rename fs... |
103 |
snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) |
173acc7ce dmaengine: add dr... |
104 |
? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0; |
a1c033190 fsldma: rename fs... |
105 |
hw->dst_addr = CPU_TO_DMA(chan, snoop_bits | dst, 64); |
173acc7ce dmaengine: add dr... |
106 |
} |
a1c033190 fsldma: rename fs... |
107 |
static void set_desc_next(struct fsldma_chan *chan, |
31f4306c8 fsldma: minor cod... |
108 |
struct fsl_dma_ld_hw *hw, dma_addr_t next) |
173acc7ce dmaengine: add dr... |
109 110 |
{ u64 snoop_bits; |
a1c033190 fsldma: rename fs... |
111 |
snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX) |
173acc7ce dmaengine: add dr... |
112 |
? FSL_DMA_SNEN : 0; |
a1c033190 fsldma: rename fs... |
113 |
hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64); |
173acc7ce dmaengine: add dr... |
114 |
} |
31f4306c8 fsldma: minor cod... |
115 |
static void set_ld_eol(struct fsldma_chan *chan, struct fsl_desc_sw *desc) |
173acc7ce dmaengine: add dr... |
116 |
{ |
e8bd84df2 fsldma: move rela... |
117 |
u64 snoop_bits; |
173acc7ce dmaengine: add dr... |
118 |
|
e8bd84df2 fsldma: move rela... |
119 120 |
snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX) ? FSL_DMA_SNEN : 0; |
173acc7ce dmaengine: add dr... |
121 |
|
e8bd84df2 fsldma: move rela... |
122 123 124 |
desc->hw.next_ln_addr = CPU_TO_DMA(chan, DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL | snoop_bits, 64); |
173acc7ce dmaengine: add dr... |
125 |
} |
e8bd84df2 fsldma: move rela... |
126 127 128 129 130 |
/* * DMA Engine Hardware Control Helpers */ static void dma_init(struct fsldma_chan *chan) |
f79abb627 fsldma: Fix the D... |
131 |
{ |
e8bd84df2 fsldma: move rela... |
132 |
/* Reset the channel */ |
ccdce9a04 DMA: Freescale: u... |
133 |
set_mr(chan, 0); |
e8bd84df2 fsldma: move rela... |
134 135 136 137 138 |
switch (chan->feature & FSL_DMA_IP_MASK) { case FSL_DMA_IP_85XX: /* Set the channel to below modes: * EIE - Error interrupt enable |
e8bd84df2 fsldma: move rela... |
139 140 141 |
* EOLNIE - End of links interrupt enable * BWC - Bandwidth sharing among channels */ |
ccdce9a04 DMA: Freescale: u... |
142 143 |
set_mr(chan, FSL_DMA_MR_BWC | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE); |
e8bd84df2 fsldma: move rela... |
144 145 146 147 148 149 |
break; case FSL_DMA_IP_83XX: /* Set the channel to below modes: * EOTIE - End-of-transfer interrupt enable * PRC_RM - PCI read multiple */ |
ccdce9a04 DMA: Freescale: u... |
150 |
set_mr(chan, FSL_DMA_MR_EOTIE | FSL_DMA_MR_PRC_RM); |
e8bd84df2 fsldma: move rela... |
151 152 |
break; } |
f79abb627 fsldma: Fix the D... |
153 |
} |
a1c033190 fsldma: rename fs... |
154 |
static int dma_is_idle(struct fsldma_chan *chan) |
173acc7ce dmaengine: add dr... |
155 |
{ |
a1c033190 fsldma: rename fs... |
156 |
u32 sr = get_sr(chan); |
173acc7ce dmaengine: add dr... |
157 158 |
return (!(sr & FSL_DMA_SR_CB)) || (sr & FSL_DMA_SR_CH); } |
f04cd4070 fsldma: fix contr... |
159 160 161 162 163 164 165 |
/* * Start the DMA controller * * Preconditions: * - the CDAR register must point to the start descriptor * - the MRn[CS] bit must be cleared */ |
a1c033190 fsldma: rename fs... |
166 |
static void dma_start(struct fsldma_chan *chan) |
173acc7ce dmaengine: add dr... |
167 |
{ |
272ca6550 fsldma: reduce ke... |
168 |
u32 mode; |
ccdce9a04 DMA: Freescale: u... |
169 |
mode = get_mr(chan); |
272ca6550 fsldma: reduce ke... |
170 |
|
f04cd4070 fsldma: fix contr... |
171 |
if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) { |
ccdce9a04 DMA: Freescale: u... |
172 |
set_bcr(chan, 0); |
f04cd4070 fsldma: fix contr... |
173 174 175 |
mode |= FSL_DMA_MR_EMP_EN; } else { mode &= ~FSL_DMA_MR_EMP_EN; |
43a1a3ed6 fsldma: do not cl... |
176 |
} |
173acc7ce dmaengine: add dr... |
177 |
|
f04cd4070 fsldma: fix contr... |
178 |
if (chan->feature & FSL_DMA_CHAN_START_EXT) { |
272ca6550 fsldma: reduce ke... |
179 |
mode |= FSL_DMA_MR_EMS_EN; |
f04cd4070 fsldma: fix contr... |
180 181 |
} else { mode &= ~FSL_DMA_MR_EMS_EN; |
272ca6550 fsldma: reduce ke... |
182 |
mode |= FSL_DMA_MR_CS; |
f04cd4070 fsldma: fix contr... |
183 |
} |
173acc7ce dmaengine: add dr... |
184 |
|
ccdce9a04 DMA: Freescale: u... |
185 |
set_mr(chan, mode); |
173acc7ce dmaengine: add dr... |
186 |
} |
a1c033190 fsldma: rename fs... |
187 |
static void dma_halt(struct fsldma_chan *chan) |
173acc7ce dmaengine: add dr... |
188 |
{ |
272ca6550 fsldma: reduce ke... |
189 |
u32 mode; |
900325a6c fsldma: fix off b... |
190 |
int i; |
a00ae34ac fsldma: make halt... |
191 |
/* read the mode register */ |
ccdce9a04 DMA: Freescale: u... |
192 |
mode = get_mr(chan); |
272ca6550 fsldma: reduce ke... |
193 |
|
a00ae34ac fsldma: make halt... |
194 195 196 197 198 199 200 |
/* * The 85xx controller supports channel abort, which will stop * the current transfer. On 83xx, this bit is the transfer error * mask bit, which should not be changed. */ if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { mode |= FSL_DMA_MR_CA; |
ccdce9a04 DMA: Freescale: u... |
201 |
set_mr(chan, mode); |
a00ae34ac fsldma: make halt... |
202 203 204 205 206 207 |
mode &= ~FSL_DMA_MR_CA; } /* stop the DMA controller */ mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN); |
ccdce9a04 DMA: Freescale: u... |
208 |
set_mr(chan, mode); |
173acc7ce dmaengine: add dr... |
209 |
|
a00ae34ac fsldma: make halt... |
210 |
/* wait for the DMA controller to become idle */ |
900325a6c fsldma: fix off b... |
211 |
for (i = 0; i < 100; i++) { |
a1c033190 fsldma: rename fs... |
212 |
if (dma_is_idle(chan)) |
9c3a50b7d fsldma: major cle... |
213 |
return; |
173acc7ce dmaengine: add dr... |
214 |
udelay(10); |
900325a6c fsldma: fix off b... |
215 |
} |
272ca6550 fsldma: reduce ke... |
216 |
|
9c3a50b7d fsldma: major cle... |
217 |
if (!dma_is_idle(chan)) |
b158471ef fsldma: use chann... |
218 219 |
chan_err(chan, "DMA halt timeout! "); |
173acc7ce dmaengine: add dr... |
220 |
} |
173acc7ce dmaengine: add dr... |
221 222 |
/** * fsl_chan_set_src_loop_size - Set source address hold transfer size |
a1c033190 fsldma: rename fs... |
223 |
* @chan : Freescale DMA channel |
173acc7ce dmaengine: add dr... |
224 225 226 227 228 229 230 231 |
* @size : Address loop size, 0 for disable loop * * The set source address hold transfer size. The source * address hold or loop transfer size is when the DMA transfer * data from source address (SA), if the loop size is 4, the DMA will * read data from SA, SA + 1, SA + 2, SA + 3, then loop back to SA, * SA + 1 ... and so on. */ |
a1c033190 fsldma: rename fs... |
232 |
static void fsl_chan_set_src_loop_size(struct fsldma_chan *chan, int size) |
173acc7ce dmaengine: add dr... |
233 |
{ |
272ca6550 fsldma: reduce ke... |
234 |
u32 mode; |
ccdce9a04 DMA: Freescale: u... |
235 |
mode = get_mr(chan); |
272ca6550 fsldma: reduce ke... |
236 |
|
173acc7ce dmaengine: add dr... |
237 238 |
switch (size) { case 0: |
272ca6550 fsldma: reduce ke... |
239 |
mode &= ~FSL_DMA_MR_SAHE; |
173acc7ce dmaengine: add dr... |
240 241 242 243 244 |
break; case 1: case 2: case 4: case 8: |
ccc077292 dmaengine: fsldma... |
245 |
mode &= ~FSL_DMA_MR_SAHTS_MASK; |
272ca6550 fsldma: reduce ke... |
246 |
mode |= FSL_DMA_MR_SAHE | (__ilog2(size) << 14); |
173acc7ce dmaengine: add dr... |
247 248 |
break; } |
272ca6550 fsldma: reduce ke... |
249 |
|
ccdce9a04 DMA: Freescale: u... |
250 |
set_mr(chan, mode); |
173acc7ce dmaengine: add dr... |
251 252 253 |
} /** |
738f5f7e1 fsldma: rename de... |
254 |
* fsl_chan_set_dst_loop_size - Set destination address hold transfer size |
a1c033190 fsldma: rename fs... |
255 |
* @chan : Freescale DMA channel |
173acc7ce dmaengine: add dr... |
256 257 258 259 260 261 262 263 |
* @size : Address loop size, 0 for disable loop * * The set destination address hold transfer size. The destination * address hold or loop transfer size is when the DMA transfer * data to destination address (TA), if the loop size is 4, the DMA will * write data to TA, TA + 1, TA + 2, TA + 3, then loop back to TA, * TA + 1 ... and so on. */ |
a1c033190 fsldma: rename fs... |
264 |
static void fsl_chan_set_dst_loop_size(struct fsldma_chan *chan, int size) |
173acc7ce dmaengine: add dr... |
265 |
{ |
272ca6550 fsldma: reduce ke... |
266 |
u32 mode; |
ccdce9a04 DMA: Freescale: u... |
267 |
mode = get_mr(chan); |
272ca6550 fsldma: reduce ke... |
268 |
|
173acc7ce dmaengine: add dr... |
269 270 |
switch (size) { case 0: |
272ca6550 fsldma: reduce ke... |
271 |
mode &= ~FSL_DMA_MR_DAHE; |
173acc7ce dmaengine: add dr... |
272 273 274 275 276 |
break; case 1: case 2: case 4: case 8: |
ccc077292 dmaengine: fsldma... |
277 |
mode &= ~FSL_DMA_MR_DAHTS_MASK; |
272ca6550 fsldma: reduce ke... |
278 |
mode |= FSL_DMA_MR_DAHE | (__ilog2(size) << 16); |
173acc7ce dmaengine: add dr... |
279 280 |
break; } |
272ca6550 fsldma: reduce ke... |
281 |
|
ccdce9a04 DMA: Freescale: u... |
282 |
set_mr(chan, mode); |
173acc7ce dmaengine: add dr... |
283 284 285 |
} /** |
e6c7ecb64 fsldma: split apa... |
286 |
* fsl_chan_set_request_count - Set DMA Request Count for external control |
a1c033190 fsldma: rename fs... |
287 |
* @chan : Freescale DMA channel |
e6c7ecb64 fsldma: split apa... |
288 289 290 291 292 293 |
* @size : Number of bytes to transfer in a single request * * The Freescale DMA channel can be controlled by the external signal DREQ#. * The DMA request count is how many bytes are allowed to transfer before * pausing the channel, after which a new assertion of DREQ# resumes channel * operation. |
173acc7ce dmaengine: add dr... |
294 |
* |
e6c7ecb64 fsldma: split apa... |
295 |
* A size of 0 disables external pause control. The maximum size is 1024. |
173acc7ce dmaengine: add dr... |
296 |
*/ |
a1c033190 fsldma: rename fs... |
297 |
static void fsl_chan_set_request_count(struct fsldma_chan *chan, int size) |
173acc7ce dmaengine: add dr... |
298 |
{ |
272ca6550 fsldma: reduce ke... |
299 |
u32 mode; |
e6c7ecb64 fsldma: split apa... |
300 |
BUG_ON(size > 1024); |
272ca6550 fsldma: reduce ke... |
301 |
|
ccdce9a04 DMA: Freescale: u... |
302 |
mode = get_mr(chan); |
ccc077292 dmaengine: fsldma... |
303 304 |
mode &= ~FSL_DMA_MR_BWC_MASK; mode |= (__ilog2(size) << 24) & FSL_DMA_MR_BWC_MASK; |
272ca6550 fsldma: reduce ke... |
305 |
|
ccdce9a04 DMA: Freescale: u... |
306 |
set_mr(chan, mode); |
e6c7ecb64 fsldma: split apa... |
307 |
} |
173acc7ce dmaengine: add dr... |
308 |
|
e6c7ecb64 fsldma: split apa... |
309 310 |
/** * fsl_chan_toggle_ext_pause - Toggle channel external pause status |
a1c033190 fsldma: rename fs... |
311 |
* @chan : Freescale DMA channel |
e6c7ecb64 fsldma: split apa... |
312 313 314 315 316 317 |
* @enable : 0 is disabled, 1 is enabled. * * The Freescale DMA channel can be controlled by the external signal DREQ#. * The DMA Request Count feature should be used in addition to this feature * to set the number of bytes to transfer before pausing the channel. */ |
a1c033190 fsldma: rename fs... |
318 |
static void fsl_chan_toggle_ext_pause(struct fsldma_chan *chan, int enable) |
e6c7ecb64 fsldma: split apa... |
319 320 |
{ if (enable) |
a1c033190 fsldma: rename fs... |
321 |
chan->feature |= FSL_DMA_CHAN_PAUSE_EXT; |
e6c7ecb64 fsldma: split apa... |
322 |
else |
a1c033190 fsldma: rename fs... |
323 |
chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT; |
173acc7ce dmaengine: add dr... |
324 325 326 327 |
} /** * fsl_chan_toggle_ext_start - Toggle channel external start status |
a1c033190 fsldma: rename fs... |
328 |
* @chan : Freescale DMA channel |
173acc7ce dmaengine: add dr... |
329 330 331 332 333 334 335 |
* @enable : 0 is disabled, 1 is enabled. * * If enable the external start, the channel can be started by an * external DMA start pin. So the dma_start() does not start the * transfer immediately. The DMA channel will wait for the * control pin asserted. */ |
a1c033190 fsldma: rename fs... |
336 |
static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable) |
173acc7ce dmaengine: add dr... |
337 338 |
{ if (enable) |
a1c033190 fsldma: rename fs... |
339 |
chan->feature |= FSL_DMA_CHAN_START_EXT; |
173acc7ce dmaengine: add dr... |
340 |
else |
a1c033190 fsldma: rename fs... |
341 |
chan->feature &= ~FSL_DMA_CHAN_START_EXT; |
173acc7ce dmaengine: add dr... |
342 |
} |
0a5642be0 dmaengine: freesc... |
343 344 345 346 347 348 349 350 351 352 353 354 355 |
int fsl_dma_external_start(struct dma_chan *dchan, int enable) { struct fsldma_chan *chan; if (!dchan) return -EINVAL; chan = to_fsl_chan(dchan); fsl_chan_toggle_ext_start(chan, enable); return 0; } EXPORT_SYMBOL_GPL(fsl_dma_external_start); |
31f4306c8 fsldma: minor cod... |
356 |
static void append_ld_queue(struct fsldma_chan *chan, struct fsl_desc_sw *desc) |
9c3a50b7d fsldma: major cle... |
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
{ struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev); if (list_empty(&chan->ld_pending)) goto out_splice; /* * Add the hardware descriptor to the chain of hardware descriptors * that already exists in memory. * * This will un-set the EOL bit of the existing transaction, and the * last link in this transaction will become the EOL descriptor. */ set_desc_next(chan, &tail->hw, desc->async_tx.phys); /* * Add the software descriptor and all children to the list * of pending transactions */ out_splice: list_splice_tail_init(&desc->tx_list, &chan->ld_pending); } |
173acc7ce dmaengine: add dr... |
379 380 |
static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) { |
a1c033190 fsldma: rename fs... |
381 |
struct fsldma_chan *chan = to_fsl_chan(tx->chan); |
eda342345 fsldma: implement... |
382 383 |
struct fsl_desc_sw *desc = tx_to_fsl_desc(tx); struct fsl_desc_sw *child; |
bbc76560d dma: fix fsldma b... |
384 |
dma_cookie_t cookie = -EINVAL; |
173acc7ce dmaengine: add dr... |
385 |
|
2baff5700 dmaengine: Freesc... |
386 |
spin_lock_bh(&chan->desc_lock); |
173acc7ce dmaengine: add dr... |
387 |
|
14c6a3333 dmaengine: Freesc... |
388 389 390 391 392 393 394 395 |
#ifdef CONFIG_PM if (unlikely(chan->pm_state != RUNNING)) { chan_dbg(chan, "cannot submit due to suspend "); spin_unlock_bh(&chan->desc_lock); return -1; } #endif |
9c3a50b7d fsldma: major cle... |
396 397 398 399 |
/* * assign cookies to all of the software descriptors * that make up this transaction */ |
eda342345 fsldma: implement... |
400 |
list_for_each_entry(child, &desc->tx_list, node) { |
884485e1f dmaengine: consol... |
401 |
cookie = dma_cookie_assign(&child->async_tx); |
bcfb7465c fsldma: fix infin... |
402 |
} |
9c3a50b7d fsldma: major cle... |
403 |
/* put this transaction onto the tail of the pending queue */ |
a1c033190 fsldma: rename fs... |
404 |
append_ld_queue(chan, desc); |
173acc7ce dmaengine: add dr... |
405 |
|
2baff5700 dmaengine: Freesc... |
406 |
spin_unlock_bh(&chan->desc_lock); |
173acc7ce dmaengine: add dr... |
407 408 409 410 411 |
return cookie; } /** |
86d19a549 DMA: Freescale: a... |
412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
* fsl_dma_free_descriptor - Free descriptor from channel's DMA pool. * @chan : Freescale DMA channel * @desc: descriptor to be freed */ static void fsl_dma_free_descriptor(struct fsldma_chan *chan, struct fsl_desc_sw *desc) { list_del(&desc->node); chan_dbg(chan, "LD %p free ", desc); dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); } /** |
173acc7ce dmaengine: add dr... |
426 |
* fsl_dma_alloc_descriptor - Allocate descriptor from channel's DMA pool. |
a1c033190 fsldma: rename fs... |
427 |
* @chan : Freescale DMA channel |
173acc7ce dmaengine: add dr... |
428 429 430 |
* * Return - The descriptor allocated. NULL for failed. */ |
31f4306c8 fsldma: minor cod... |
431 |
static struct fsl_desc_sw *fsl_dma_alloc_descriptor(struct fsldma_chan *chan) |
173acc7ce dmaengine: add dr... |
432 |
{ |
9c3a50b7d fsldma: major cle... |
433 |
struct fsl_desc_sw *desc; |
173acc7ce dmaengine: add dr... |
434 |
dma_addr_t pdesc; |
9c3a50b7d fsldma: major cle... |
435 |
|
437645572 dmaengine: fsldma... |
436 |
desc = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &pdesc); |
9c3a50b7d fsldma: major cle... |
437 |
if (!desc) { |
b158471ef fsldma: use chann... |
438 439 |
chan_dbg(chan, "out of memory for link descriptor "); |
9c3a50b7d fsldma: major cle... |
440 |
return NULL; |
173acc7ce dmaengine: add dr... |
441 |
} |
9c3a50b7d fsldma: major cle... |
442 443 444 445 |
INIT_LIST_HEAD(&desc->tx_list); dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); desc->async_tx.tx_submit = fsl_dma_tx_submit; desc->async_tx.phys = pdesc; |
0ab09c368 fsldma: improve l... |
446 447 |
chan_dbg(chan, "LD %p allocated ", desc); |
0ab09c368 fsldma: improve l... |
448 |
|
9c3a50b7d fsldma: major cle... |
449 |
return desc; |
173acc7ce dmaengine: add dr... |
450 |
} |
173acc7ce dmaengine: add dr... |
451 |
/** |
43452fadd dmaengine: Freesc... |
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
* fsldma_clean_completed_descriptor - free all descriptors which * has been completed and acked * @chan: Freescale DMA channel * * This function is used on all completed and acked descriptors. * All descriptors should only be freed in this function. */ static void fsldma_clean_completed_descriptor(struct fsldma_chan *chan) { struct fsl_desc_sw *desc, *_desc; /* Run the callback for each descriptor, in order */ list_for_each_entry_safe(desc, _desc, &chan->ld_completed, node) if (async_tx_test_ack(&desc->async_tx)) fsl_dma_free_descriptor(chan, desc); } /** * fsldma_run_tx_complete_actions - cleanup a single link descriptor * @chan: Freescale DMA channel * @desc: descriptor to cleanup and free * @cookie: Freescale DMA transaction identifier * * This function is used on a descriptor which has been executed by the DMA * controller. It will run any callbacks, submit any dependencies. */ static dma_cookie_t fsldma_run_tx_complete_actions(struct fsldma_chan *chan, struct fsl_desc_sw *desc, dma_cookie_t cookie) { struct dma_async_tx_descriptor *txd = &desc->async_tx; dma_cookie_t ret = cookie; BUG_ON(txd->cookie < 0); if (txd->cookie > 0) { ret = txd->cookie; |
9b335978f dmaengine: fsldma... |
488 |
dma_descriptor_unmap(txd); |
43452fadd dmaengine: Freesc... |
489 |
/* Run the link descriptor callback function */ |
af1a5a511 dmaengine: fsldma... |
490 |
dmaengine_desc_get_callback_invoke(txd, NULL); |
43452fadd dmaengine: Freesc... |
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
} /* Run any dependencies */ dma_run_dependencies(txd); return ret; } /** * fsldma_clean_running_descriptor - move the completed descriptor from * ld_running to ld_completed * @chan: Freescale DMA channel * @desc: the descriptor which is completed * * Free the descriptor directly if acked by async_tx api, or move it to * queue ld_completed. */ static void fsldma_clean_running_descriptor(struct fsldma_chan *chan, struct fsl_desc_sw *desc) { /* Remove from the list of transactions */ list_del(&desc->node); /* * the client is allowed to attach dependent operations * until 'ack' is set */ if (!async_tx_test_ack(&desc->async_tx)) { /* * Move this descriptor to the list of descriptors which is * completed, but still awaiting the 'ack' bit to be set. */ list_add_tail(&desc->node, &chan->ld_completed); return; } dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); } /** |
2a5ecb791 DMA: Freescale: m... |
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 |
* fsl_chan_xfer_ld_queue - transfer any pending transactions * @chan : Freescale DMA channel * * HARDWARE STATE: idle * LOCKING: must hold chan->desc_lock */ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) { struct fsl_desc_sw *desc; /* * If the list of pending descriptors is empty, then we * don't need to do any work at all */ if (list_empty(&chan->ld_pending)) { chan_dbg(chan, "no pending LDs "); return; } /* * The DMA controller is not idle, which means that the interrupt * handler will start any queued transactions when it runs after * this transaction finishes */ if (!chan->idle) { chan_dbg(chan, "DMA controller still busy "); return; } /* * If there are some link descriptors which have not been * transferred, we need to start the controller */ /* * Move all elements from the queue of pending transactions * onto the list of running transactions */ chan_dbg(chan, "idle, starting controller "); desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node); list_splice_tail_init(&chan->ld_pending, &chan->ld_running); /* * The 85xx DMA controller doesn't clear the channel start bit * automatically at the end of a transfer. Therefore we must clear * it in software before starting the transfer. */ if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { u32 mode; mode = get_mr(chan); mode &= ~FSL_DMA_MR_CS; set_mr(chan, mode); } /* * Program the descriptor's address into the DMA controller, * then start the DMA transaction */ set_cdar(chan, desc->async_tx.phys); get_cdar(chan); dma_start(chan); chan->idle = false; } /** |
43452fadd dmaengine: Freesc... |
601 602 |
* fsldma_cleanup_descriptors - cleanup link descriptors which are completed * and move them to ld_completed to free until flag 'ack' is set |
2a5ecb791 DMA: Freescale: m... |
603 |
* @chan: Freescale DMA channel |
2a5ecb791 DMA: Freescale: m... |
604 |
* |
43452fadd dmaengine: Freesc... |
605 606 607 |
* This function is used on descriptors which have been executed by the DMA * controller. It will run any callbacks, submit any dependencies, then * free these descriptors if flag 'ack' is set. |
2a5ecb791 DMA: Freescale: m... |
608 |
*/ |
43452fadd dmaengine: Freesc... |
609 |
static void fsldma_cleanup_descriptors(struct fsldma_chan *chan) |
2a5ecb791 DMA: Freescale: m... |
610 |
{ |
43452fadd dmaengine: Freesc... |
611 612 613 614 |
struct fsl_desc_sw *desc, *_desc; dma_cookie_t cookie = 0; dma_addr_t curr_phys = get_cdar(chan); int seen_current = 0; |
2a5ecb791 DMA: Freescale: m... |
615 |
|
43452fadd dmaengine: Freesc... |
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 |
fsldma_clean_completed_descriptor(chan); /* Run the callback for each descriptor, in order */ list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) { /* * do not advance past the current descriptor loaded into the * hardware channel, subsequent descriptors are either in * process or have not been submitted */ if (seen_current) break; /* * stop the search if we reach the current descriptor and the * channel is busy */ if (desc->async_tx.phys == curr_phys) { seen_current = 1; if (!dma_is_idle(chan)) break; } cookie = fsldma_run_tx_complete_actions(chan, desc, cookie); fsldma_clean_running_descriptor(chan, desc); |
2a5ecb791 DMA: Freescale: m... |
641 |
} |
43452fadd dmaengine: Freesc... |
642 643 644 645 646 647 648 |
/* * Start any pending transactions automatically * * In the ideal case, we keep the DMA controller busy while we go * ahead and free the descriptors below. */ fsl_chan_xfer_ld_queue(chan); |
2a5ecb791 DMA: Freescale: m... |
649 |
|
43452fadd dmaengine: Freesc... |
650 651 |
if (cookie > 0) chan->common.completed_cookie = cookie; |
2a5ecb791 DMA: Freescale: m... |
652 653 654 |
} /** |
173acc7ce dmaengine: add dr... |
655 |
* fsl_dma_alloc_chan_resources - Allocate resources for DMA channel. |
a1c033190 fsldma: rename fs... |
656 |
* @chan : Freescale DMA channel |
173acc7ce dmaengine: add dr... |
657 658 659 660 661 |
* * This function will create a dma pool for descriptor allocation. * * Return - The number of descriptors allocated. */ |
a1c033190 fsldma: rename fs... |
662 |
static int fsl_dma_alloc_chan_resources(struct dma_chan *dchan) |
173acc7ce dmaengine: add dr... |
663 |
{ |
a1c033190 fsldma: rename fs... |
664 |
struct fsldma_chan *chan = to_fsl_chan(dchan); |
77cd62e80 fsldma: allow Fre... |
665 666 |
/* Has this channel already been allocated? */ |
a1c033190 fsldma: rename fs... |
667 |
if (chan->desc_pool) |
77cd62e80 fsldma: allow Fre... |
668 |
return 1; |
173acc7ce dmaengine: add dr... |
669 |
|
9c3a50b7d fsldma: major cle... |
670 671 |
/* * We need the descriptor to be aligned to 32bytes |
173acc7ce dmaengine: add dr... |
672 673 |
* for meeting FSL DMA specification requirement. */ |
b158471ef fsldma: use chann... |
674 |
chan->desc_pool = dma_pool_create(chan->name, chan->dev, |
9c3a50b7d fsldma: major cle... |
675 676 |
sizeof(struct fsl_desc_sw), __alignof__(struct fsl_desc_sw), 0); |
a1c033190 fsldma: rename fs... |
677 |
if (!chan->desc_pool) { |
b158471ef fsldma: use chann... |
678 679 |
chan_err(chan, "unable to allocate descriptor pool "); |
9c3a50b7d fsldma: major cle... |
680 |
return -ENOMEM; |
173acc7ce dmaengine: add dr... |
681 |
} |
9c3a50b7d fsldma: major cle... |
682 |
/* there is at least one descriptor free to be allocated */ |
173acc7ce dmaengine: add dr... |
683 684 685 686 |
return 1; } /** |
9c3a50b7d fsldma: major cle... |
687 688 689 690 691 692 693 694 695 696 |
* fsldma_free_desc_list - Free all descriptors in a queue * @chan: Freescae DMA channel * @list: the list to free * * LOCKING: must hold chan->desc_lock */ static void fsldma_free_desc_list(struct fsldma_chan *chan, struct list_head *list) { struct fsl_desc_sw *desc, *_desc; |
86d19a549 DMA: Freescale: a... |
697 698 |
list_for_each_entry_safe(desc, _desc, list, node) fsl_dma_free_descriptor(chan, desc); |
9c3a50b7d fsldma: major cle... |
699 700 701 702 703 704 |
} static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan, struct list_head *list) { struct fsl_desc_sw *desc, *_desc; |
86d19a549 DMA: Freescale: a... |
705 706 |
list_for_each_entry_safe_reverse(desc, _desc, list, node) fsl_dma_free_descriptor(chan, desc); |
9c3a50b7d fsldma: major cle... |
707 708 709 |
} /** |
173acc7ce dmaengine: add dr... |
710 |
* fsl_dma_free_chan_resources - Free all resources of the channel. |
a1c033190 fsldma: rename fs... |
711 |
* @chan : Freescale DMA channel |
173acc7ce dmaengine: add dr... |
712 |
*/ |
a1c033190 fsldma: rename fs... |
713 |
static void fsl_dma_free_chan_resources(struct dma_chan *dchan) |
173acc7ce dmaengine: add dr... |
714 |
{ |
a1c033190 fsldma: rename fs... |
715 |
struct fsldma_chan *chan = to_fsl_chan(dchan); |
173acc7ce dmaengine: add dr... |
716 |
|
b158471ef fsldma: use chann... |
717 718 |
chan_dbg(chan, "free all channel resources "); |
2baff5700 dmaengine: Freesc... |
719 |
spin_lock_bh(&chan->desc_lock); |
43452fadd dmaengine: Freesc... |
720 |
fsldma_cleanup_descriptors(chan); |
9c3a50b7d fsldma: major cle... |
721 722 |
fsldma_free_desc_list(chan, &chan->ld_pending); fsldma_free_desc_list(chan, &chan->ld_running); |
43452fadd dmaengine: Freesc... |
723 |
fsldma_free_desc_list(chan, &chan->ld_completed); |
2baff5700 dmaengine: Freesc... |
724 |
spin_unlock_bh(&chan->desc_lock); |
77cd62e80 fsldma: allow Fre... |
725 |
|
9c3a50b7d fsldma: major cle... |
726 |
dma_pool_destroy(chan->desc_pool); |
a1c033190 fsldma: rename fs... |
727 |
chan->desc_pool = NULL; |
173acc7ce dmaengine: add dr... |
728 |
} |
2187c269a fsldma: Add devic... |
729 |
static struct dma_async_tx_descriptor * |
31f4306c8 fsldma: minor cod... |
730 731 |
fsl_dma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src, |
173acc7ce dmaengine: add dr... |
732 733 |
size_t len, unsigned long flags) { |
a1c033190 fsldma: rename fs... |
734 |
struct fsldma_chan *chan; |
173acc7ce dmaengine: add dr... |
735 736 |
struct fsl_desc_sw *first = NULL, *prev = NULL, *new; size_t copy; |
173acc7ce dmaengine: add dr... |
737 |
|
a1c033190 fsldma: rename fs... |
738 |
if (!dchan) |
173acc7ce dmaengine: add dr... |
739 740 741 742 |
return NULL; if (!len) return NULL; |
a1c033190 fsldma: rename fs... |
743 |
chan = to_fsl_chan(dchan); |
173acc7ce dmaengine: add dr... |
744 745 746 747 |
do { /* Allocate the link descriptor from DMA pool */ |
a1c033190 fsldma: rename fs... |
748 |
new = fsl_dma_alloc_descriptor(chan); |
173acc7ce dmaengine: add dr... |
749 |
if (!new) { |
b158471ef fsldma: use chann... |
750 751 |
chan_err(chan, "%s ", msg_ld_oom); |
2e077f8e8 fsldma: fix memor... |
752 |
goto fail; |
173acc7ce dmaengine: add dr... |
753 |
} |
173acc7ce dmaengine: add dr... |
754 |
|
56822843f fsldma: Fix fsldm... |
755 |
copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT); |
173acc7ce dmaengine: add dr... |
756 |
|
a1c033190 fsldma: rename fs... |
757 758 759 |
set_desc_cnt(chan, &new->hw, copy); set_desc_src(chan, &new->hw, dma_src); set_desc_dst(chan, &new->hw, dma_dst); |
173acc7ce dmaengine: add dr... |
760 761 762 763 |
if (!first) first = new; else |
a1c033190 fsldma: rename fs... |
764 |
set_desc_next(chan, &prev->hw, new->async_tx.phys); |
173acc7ce dmaengine: add dr... |
765 766 |
new->async_tx.cookie = 0; |
636bdeaa1 dmaengine: ack to... |
767 |
async_tx_ack(&new->async_tx); |
173acc7ce dmaengine: add dr... |
768 769 770 771 |
prev = new; len -= copy; dma_src += copy; |
738f5f7e1 fsldma: rename de... |
772 |
dma_dst += copy; |
173acc7ce dmaengine: add dr... |
773 774 |
/* Insert the link descriptor to the LD ring */ |
eda342345 fsldma: implement... |
775 |
list_add_tail(&new->node, &first->tx_list); |
173acc7ce dmaengine: add dr... |
776 |
} while (len); |
636bdeaa1 dmaengine: ack to... |
777 |
new->async_tx.flags = flags; /* client is in control of this ack */ |
173acc7ce dmaengine: add dr... |
778 |
new->async_tx.cookie = -EBUSY; |
31f4306c8 fsldma: minor cod... |
779 |
/* Set End-of-link to the last link descriptor of new list */ |
a1c033190 fsldma: rename fs... |
780 |
set_ld_eol(chan, new); |
173acc7ce dmaengine: add dr... |
781 |
|
2e077f8e8 fsldma: fix memor... |
782 783 784 785 786 |
return &first->async_tx; fail: if (!first) return NULL; |
9c3a50b7d fsldma: major cle... |
787 |
fsldma_free_desc_list_reverse(chan, &first->tx_list); |
2e077f8e8 fsldma: fix memor... |
788 |
return NULL; |
173acc7ce dmaengine: add dr... |
789 |
} |
b7f7552bf dmaengine: fsl-dm... |
790 |
static int fsl_dma_device_terminate_all(struct dma_chan *dchan) |
bbea0b6e0 fsldma: Add DMA_S... |
791 |
{ |
a1c033190 fsldma: rename fs... |
792 |
struct fsldma_chan *chan; |
c3635c78e DMAENGINE: generi... |
793 |
|
a1c033190 fsldma: rename fs... |
794 |
if (!dchan) |
c3635c78e DMAENGINE: generi... |
795 |
return -EINVAL; |
bbea0b6e0 fsldma: Add DMA_S... |
796 |
|
a1c033190 fsldma: rename fs... |
797 |
chan = to_fsl_chan(dchan); |
bbea0b6e0 fsldma: Add DMA_S... |
798 |
|
b7f7552bf dmaengine: fsl-dm... |
799 |
spin_lock_bh(&chan->desc_lock); |
bbea0b6e0 fsldma: Add DMA_S... |
800 |
|
b7f7552bf dmaengine: fsl-dm... |
801 802 |
/* Halt the DMA engine */ dma_halt(chan); |
bbea0b6e0 fsldma: Add DMA_S... |
803 |
|
b7f7552bf dmaengine: fsl-dm... |
804 805 806 807 808 |
/* Remove and free all of the descriptors in the LD queue */ fsldma_free_desc_list(chan, &chan->ld_pending); fsldma_free_desc_list(chan, &chan->ld_running); fsldma_free_desc_list(chan, &chan->ld_completed); chan->idle = true; |
968f19ae8 fsldma: improved ... |
809 |
|
b7f7552bf dmaengine: fsl-dm... |
810 811 812 |
spin_unlock_bh(&chan->desc_lock); return 0; } |
968f19ae8 fsldma: improved ... |
813 |
|
b7f7552bf dmaengine: fsl-dm... |
814 815 816 817 818 |
static int fsl_dma_device_config(struct dma_chan *dchan, struct dma_slave_config *config) { struct fsldma_chan *chan; int size; |
968f19ae8 fsldma: improved ... |
819 |
|
b7f7552bf dmaengine: fsl-dm... |
820 821 |
if (!dchan) return -EINVAL; |
968f19ae8 fsldma: improved ... |
822 |
|
b7f7552bf dmaengine: fsl-dm... |
823 |
chan = to_fsl_chan(dchan); |
968f19ae8 fsldma: improved ... |
824 |
|
b7f7552bf dmaengine: fsl-dm... |
825 826 |
/* make sure the channel supports setting burst size */ if (!chan->set_request_count) |
968f19ae8 fsldma: improved ... |
827 |
return -ENXIO; |
c3635c78e DMAENGINE: generi... |
828 |
|
b7f7552bf dmaengine: fsl-dm... |
829 830 831 832 833 834 835 |
/* we set the controller burst size depending on direction */ if (config->direction == DMA_MEM_TO_DEV) size = config->dst_addr_width * config->dst_maxburst; else size = config->src_addr_width * config->src_maxburst; chan->set_request_count(chan, size); |
c3635c78e DMAENGINE: generi... |
836 |
return 0; |
bbea0b6e0 fsldma: Add DMA_S... |
837 |
} |
b7f7552bf dmaengine: fsl-dm... |
838 |
|
bbea0b6e0 fsldma: Add DMA_S... |
839 |
/** |
173acc7ce dmaengine: add dr... |
840 |
* fsl_dma_memcpy_issue_pending - Issue the DMA start command |
a1c033190 fsldma: rename fs... |
841 |
* @chan : Freescale DMA channel |
173acc7ce dmaengine: add dr... |
842 |
*/ |
a1c033190 fsldma: rename fs... |
843 |
static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan) |
173acc7ce dmaengine: add dr... |
844 |
{ |
a1c033190 fsldma: rename fs... |
845 |
struct fsldma_chan *chan = to_fsl_chan(dchan); |
dc8d40915 fsldma: reduce lo... |
846 |
|
2baff5700 dmaengine: Freesc... |
847 |
spin_lock_bh(&chan->desc_lock); |
a1c033190 fsldma: rename fs... |
848 |
fsl_chan_xfer_ld_queue(chan); |
2baff5700 dmaengine: Freesc... |
849 |
spin_unlock_bh(&chan->desc_lock); |
173acc7ce dmaengine: add dr... |
850 |
} |
173acc7ce dmaengine: add dr... |
851 |
/** |
079344818 DMAENGINE: generi... |
852 |
* fsl_tx_status - Determine the DMA status |
a1c033190 fsldma: rename fs... |
853 |
* @chan : Freescale DMA channel |
173acc7ce dmaengine: add dr... |
854 |
*/ |
079344818 DMAENGINE: generi... |
855 |
static enum dma_status fsl_tx_status(struct dma_chan *dchan, |
173acc7ce dmaengine: add dr... |
856 |
dma_cookie_t cookie, |
079344818 DMAENGINE: generi... |
857 |
struct dma_tx_state *txstate) |
173acc7ce dmaengine: add dr... |
858 |
{ |
43452fadd dmaengine: Freesc... |
859 860 861 862 863 864 865 866 867 868 |
struct fsldma_chan *chan = to_fsl_chan(dchan); enum dma_status ret; ret = dma_cookie_status(dchan, cookie, txstate); if (ret == DMA_COMPLETE) return ret; spin_lock_bh(&chan->desc_lock); fsldma_cleanup_descriptors(chan); spin_unlock_bh(&chan->desc_lock); |
9b0b0bdc6 fsldma: remove us... |
869 |
return dma_cookie_status(dchan, cookie, txstate); |
173acc7ce dmaengine: add dr... |
870 |
} |
d3f620b2c fsldma: simplify ... |
871 872 873 |
/*----------------------------------------------------------------------------*/ /* Interrupt Handling */ /*----------------------------------------------------------------------------*/ |
e7a29151d fsldma: clean up ... |
874 |
static irqreturn_t fsldma_chan_irq(int irq, void *data) |
173acc7ce dmaengine: add dr... |
875 |
{ |
a1c033190 fsldma: rename fs... |
876 |
struct fsldma_chan *chan = data; |
a1c033190 fsldma: rename fs... |
877 |
u32 stat; |
173acc7ce dmaengine: add dr... |
878 |
|
9c3a50b7d fsldma: major cle... |
879 |
/* save and clear the status register */ |
a1c033190 fsldma: rename fs... |
880 |
stat = get_sr(chan); |
9c3a50b7d fsldma: major cle... |
881 |
set_sr(chan, stat); |
b158471ef fsldma: use chann... |
882 883 |
chan_dbg(chan, "irq: stat = 0x%x ", stat); |
173acc7ce dmaengine: add dr... |
884 |
|
f04cd4070 fsldma: fix contr... |
885 |
/* check that this was really our device */ |
173acc7ce dmaengine: add dr... |
886 887 888 889 890 |
stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH); if (!stat) return IRQ_NONE; if (stat & FSL_DMA_SR_TE) |
b158471ef fsldma: use chann... |
891 892 |
chan_err(chan, "Transfer Error! "); |
173acc7ce dmaengine: add dr... |
893 |
|
9c3a50b7d fsldma: major cle... |
894 895 |
/* * Programming Error |
f79abb627 fsldma: Fix the D... |
896 |
* The DMA_INTERRUPT async_tx is a NULL transfer, which will |
d73111c6d dma: fix comments |
897 |
* trigger a PE interrupt. |
f79abb627 fsldma: Fix the D... |
898 899 |
*/ if (stat & FSL_DMA_SR_PE) { |
b158471ef fsldma: use chann... |
900 901 |
chan_dbg(chan, "irq: Programming Error INT "); |
f79abb627 fsldma: Fix the D... |
902 |
stat &= ~FSL_DMA_SR_PE; |
f04cd4070 fsldma: fix contr... |
903 904 905 |
if (get_bcr(chan) != 0) chan_err(chan, "Programming Error! "); |
1c62979ed fsldma: Split the... |
906 |
} |
9c3a50b7d fsldma: major cle... |
907 908 |
/* * For MPC8349, EOCDI event need to update cookie |
1c62979ed fsldma: Split the... |
909 910 911 |
* and start the next transfer if it exist. */ if (stat & FSL_DMA_SR_EOCDI) { |
b158471ef fsldma: use chann... |
912 913 |
chan_dbg(chan, "irq: End-of-Chain link INT "); |
1c62979ed fsldma: Split the... |
914 |
stat &= ~FSL_DMA_SR_EOCDI; |
173acc7ce dmaengine: add dr... |
915 |
} |
9c3a50b7d fsldma: major cle... |
916 917 |
/* * If it current transfer is the end-of-transfer, |
173acc7ce dmaengine: add dr... |
918 919 920 |
* we should clear the Channel Start bit for * prepare next transfer. */ |
1c62979ed fsldma: Split the... |
921 |
if (stat & FSL_DMA_SR_EOLNI) { |
b158471ef fsldma: use chann... |
922 923 |
chan_dbg(chan, "irq: End-of-link INT "); |
173acc7ce dmaengine: add dr... |
924 |
stat &= ~FSL_DMA_SR_EOLNI; |
173acc7ce dmaengine: add dr... |
925 |
} |
f04cd4070 fsldma: fix contr... |
926 927 928 929 930 931 |
/* check that the DMA controller is really idle */ if (!dma_is_idle(chan)) chan_err(chan, "irq: controller not idle! "); /* check that we handled all of the bits */ |
173acc7ce dmaengine: add dr... |
932 |
if (stat) |
f04cd4070 fsldma: fix contr... |
933 934 |
chan_err(chan, "irq: unhandled sr 0x%08x ", stat); |
173acc7ce dmaengine: add dr... |
935 |
|
f04cd4070 fsldma: fix contr... |
936 937 938 939 940 |
/* * Schedule the tasklet to handle all cleanup of the current * transaction. It will start a new transaction if there is * one pending. */ |
a1c033190 fsldma: rename fs... |
941 |
tasklet_schedule(&chan->tasklet); |
f04cd4070 fsldma: fix contr... |
942 943 |
chan_dbg(chan, "irq: Exit "); |
173acc7ce dmaengine: add dr... |
944 945 |
return IRQ_HANDLED; } |
59cd81876 dmaengine: fsl: c... |
946 |
static void dma_do_tasklet(struct tasklet_struct *t) |
d3f620b2c fsldma: simplify ... |
947 |
{ |
59cd81876 dmaengine: fsl: c... |
948 |
struct fsldma_chan *chan = from_tasklet(chan, t, tasklet); |
f04cd4070 fsldma: fix contr... |
949 950 951 |
chan_dbg(chan, "tasklet entry "); |
1297b647c dmaengine: fsldma... |
952 |
spin_lock(&chan->desc_lock); |
dc8d40915 fsldma: reduce lo... |
953 |
|
dc8d40915 fsldma: reduce lo... |
954 |
/* the hardware is now idle and ready for more */ |
f04cd4070 fsldma: fix contr... |
955 |
chan->idle = true; |
f04cd4070 fsldma: fix contr... |
956 |
|
43452fadd dmaengine: Freesc... |
957 958 |
/* Run all cleanup for descriptors which have been completed */ fsldma_cleanup_descriptors(chan); |
dc8d40915 fsldma: reduce lo... |
959 |
|
1297b647c dmaengine: fsldma... |
960 |
spin_unlock(&chan->desc_lock); |
dc8d40915 fsldma: reduce lo... |
961 |
|
f04cd4070 fsldma: fix contr... |
962 963 |
chan_dbg(chan, "tasklet exit "); |
d3f620b2c fsldma: simplify ... |
964 965 966 |
} static irqreturn_t fsldma_ctrl_irq(int irq, void *data) |
173acc7ce dmaengine: add dr... |
967 |
{ |
a4f56d4b1 fsldma: rename st... |
968 |
struct fsldma_device *fdev = data; |
d3f620b2c fsldma: simplify ... |
969 970 971 972 |
struct fsldma_chan *chan; unsigned int handled = 0; u32 gsr, mask; int i; |
173acc7ce dmaengine: add dr... |
973 |
|
e7a29151d fsldma: clean up ... |
974 |
gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->regs) |
d3f620b2c fsldma: simplify ... |
975 976 977 978 |
: in_le32(fdev->regs); mask = 0xff000000; dev_dbg(fdev->dev, "IRQ: gsr 0x%.8x ", gsr); |
173acc7ce dmaengine: add dr... |
979 |
|
d3f620b2c fsldma: simplify ... |
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { chan = fdev->chan[i]; if (!chan) continue; if (gsr & mask) { dev_dbg(fdev->dev, "IRQ: chan %d ", chan->id); fsldma_chan_irq(irq, chan); handled++; } gsr &= ~mask; mask >>= 8; } return IRQ_RETVAL(handled); |
173acc7ce dmaengine: add dr... |
997 |
} |
d3f620b2c fsldma: simplify ... |
998 |
static void fsldma_free_irqs(struct fsldma_device *fdev) |
173acc7ce dmaengine: add dr... |
999 |
{ |
d3f620b2c fsldma: simplify ... |
1000 1001 |
struct fsldma_chan *chan; int i; |
aa570be6d dmaengine: NO_IRQ... |
1002 |
if (fdev->irq) { |
d3f620b2c fsldma: simplify ... |
1003 1004 1005 1006 1007 1008 1009 1010 |
dev_dbg(fdev->dev, "free per-controller IRQ "); free_irq(fdev->irq, fdev); return; } for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { chan = fdev->chan[i]; |
aa570be6d dmaengine: NO_IRQ... |
1011 |
if (chan && chan->irq) { |
b158471ef fsldma: use chann... |
1012 1013 |
chan_dbg(chan, "free per-channel IRQ "); |
d3f620b2c fsldma: simplify ... |
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 |
free_irq(chan->irq, chan); } } } static int fsldma_request_irqs(struct fsldma_device *fdev) { struct fsldma_chan *chan; int ret; int i; /* if we have a per-controller IRQ, use that */ |
aa570be6d dmaengine: NO_IRQ... |
1026 |
if (fdev->irq) { |
d3f620b2c fsldma: simplify ... |
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 |
dev_dbg(fdev->dev, "request per-controller IRQ "); ret = request_irq(fdev->irq, fsldma_ctrl_irq, IRQF_SHARED, "fsldma-controller", fdev); return ret; } /* no per-controller IRQ, use the per-channel IRQs */ for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { chan = fdev->chan[i]; if (!chan) continue; |
aa570be6d dmaengine: NO_IRQ... |
1039 |
if (!chan->irq) { |
b158471ef fsldma: use chann... |
1040 1041 |
chan_err(chan, "interrupts property missing in device tree "); |
d3f620b2c fsldma: simplify ... |
1042 1043 1044 |
ret = -ENODEV; goto out_unwind; } |
b158471ef fsldma: use chann... |
1045 1046 |
chan_dbg(chan, "request per-channel IRQ "); |
d3f620b2c fsldma: simplify ... |
1047 1048 1049 |
ret = request_irq(chan->irq, fsldma_chan_irq, IRQF_SHARED, "fsldma-chan", chan); if (ret) { |
b158471ef fsldma: use chann... |
1050 1051 |
chan_err(chan, "unable to request per-channel IRQ "); |
d3f620b2c fsldma: simplify ... |
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 |
goto out_unwind; } } return 0; out_unwind: for (/* none */; i >= 0; i--) { chan = fdev->chan[i]; if (!chan) continue; |
aa570be6d dmaengine: NO_IRQ... |
1063 |
if (!chan->irq) |
d3f620b2c fsldma: simplify ... |
1064 1065 1066 1067 1068 1069 |
continue; free_irq(chan->irq, chan); } return ret; |
173acc7ce dmaengine: add dr... |
1070 |
} |
a4f56d4b1 fsldma: rename st... |
1071 1072 1073 |
/*----------------------------------------------------------------------------*/ /* OpenFirmware Subsystem */ /*----------------------------------------------------------------------------*/ |
463a1f8b3 dma: remove use o... |
1074 |
static int fsl_dma_chan_probe(struct fsldma_device *fdev, |
77cd62e80 fsldma: allow Fre... |
1075 |
struct device_node *node, u32 feature, const char *compatible) |
173acc7ce dmaengine: add dr... |
1076 |
{ |
a1c033190 fsldma: rename fs... |
1077 |
struct fsldma_chan *chan; |
4ce0e953f fsldma: remove un... |
1078 |
struct resource res; |
173acc7ce dmaengine: add dr... |
1079 |
int err; |
173acc7ce dmaengine: add dr... |
1080 |
/* alloc channel */ |
a1c033190 fsldma: rename fs... |
1081 1082 |
chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) { |
e7a29151d fsldma: clean up ... |
1083 1084 1085 1086 1087 |
err = -ENOMEM; goto out_return; } /* ioremap registers for use */ |
a1c033190 fsldma: rename fs... |
1088 1089 |
chan->regs = of_iomap(node, 0); if (!chan->regs) { |
e7a29151d fsldma: clean up ... |
1090 1091 1092 |
dev_err(fdev->dev, "unable to ioremap registers "); err = -ENOMEM; |
a1c033190 fsldma: rename fs... |
1093 |
goto out_free_chan; |
173acc7ce dmaengine: add dr... |
1094 |
} |
4ce0e953f fsldma: remove un... |
1095 |
err = of_address_to_resource(node, 0, &res); |
173acc7ce dmaengine: add dr... |
1096 |
if (err) { |
e7a29151d fsldma: clean up ... |
1097 1098 1099 |
dev_err(fdev->dev, "unable to find 'reg' property "); goto out_iounmap_regs; |
173acc7ce dmaengine: add dr... |
1100 |
} |
a1c033190 fsldma: rename fs... |
1101 |
chan->feature = feature; |
173acc7ce dmaengine: add dr... |
1102 |
if (!fdev->feature) |
a1c033190 fsldma: rename fs... |
1103 |
fdev->feature = chan->feature; |
173acc7ce dmaengine: add dr... |
1104 |
|
e7a29151d fsldma: clean up ... |
1105 1106 1107 |
/* * If the DMA device's feature is different than the feature * of its channels, report the bug |
173acc7ce dmaengine: add dr... |
1108 |
*/ |
a1c033190 fsldma: rename fs... |
1109 |
WARN_ON(fdev->feature != chan->feature); |
e7a29151d fsldma: clean up ... |
1110 |
|
a1c033190 fsldma: rename fs... |
1111 |
chan->dev = fdev->dev; |
8de7a7d95 DMA: Freescale: u... |
1112 1113 1114 |
chan->id = (res.start & 0xfff) < 0x300 ? ((res.start - 0x100) & 0xfff) >> 7 : ((res.start - 0x200) & 0xfff) >> 7; |
a1c033190 fsldma: rename fs... |
1115 |
if (chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) { |
e7a29151d fsldma: clean up ... |
1116 1117 |
dev_err(fdev->dev, "too many channels for device "); |
173acc7ce dmaengine: add dr... |
1118 |
err = -EINVAL; |
e7a29151d fsldma: clean up ... |
1119 |
goto out_iounmap_regs; |
173acc7ce dmaengine: add dr... |
1120 |
} |
173acc7ce dmaengine: add dr... |
1121 |
|
a1c033190 fsldma: rename fs... |
1122 |
fdev->chan[chan->id] = chan; |
59cd81876 dmaengine: fsl: c... |
1123 |
tasklet_setup(&chan->tasklet, dma_do_tasklet); |
b158471ef fsldma: use chann... |
1124 |
snprintf(chan->name, sizeof(chan->name), "chan%d", chan->id); |
e7a29151d fsldma: clean up ... |
1125 1126 |
/* Initialize the channel */ |
a1c033190 fsldma: rename fs... |
1127 |
dma_init(chan); |
173acc7ce dmaengine: add dr... |
1128 1129 |
/* Clear cdar registers */ |
a1c033190 fsldma: rename fs... |
1130 |
set_cdar(chan, 0); |
173acc7ce dmaengine: add dr... |
1131 |
|
a1c033190 fsldma: rename fs... |
1132 |
switch (chan->feature & FSL_DMA_IP_MASK) { |
173acc7ce dmaengine: add dr... |
1133 |
case FSL_DMA_IP_85XX: |
a1c033190 fsldma: rename fs... |
1134 |
chan->toggle_ext_pause = fsl_chan_toggle_ext_pause; |
df561f668 treewide: Use fal... |
1135 |
fallthrough; |
173acc7ce dmaengine: add dr... |
1136 |
case FSL_DMA_IP_83XX: |
a1c033190 fsldma: rename fs... |
1137 1138 1139 1140 |
chan->toggle_ext_start = fsl_chan_toggle_ext_start; chan->set_src_loop_size = fsl_chan_set_src_loop_size; chan->set_dst_loop_size = fsl_chan_set_dst_loop_size; chan->set_request_count = fsl_chan_set_request_count; |
173acc7ce dmaengine: add dr... |
1141 |
} |
a1c033190 fsldma: rename fs... |
1142 |
spin_lock_init(&chan->desc_lock); |
9c3a50b7d fsldma: major cle... |
1143 1144 |
INIT_LIST_HEAD(&chan->ld_pending); INIT_LIST_HEAD(&chan->ld_running); |
43452fadd dmaengine: Freesc... |
1145 |
INIT_LIST_HEAD(&chan->ld_completed); |
f04cd4070 fsldma: fix contr... |
1146 |
chan->idle = true; |
14c6a3333 dmaengine: Freesc... |
1147 1148 1149 |
#ifdef CONFIG_PM chan->pm_state = RUNNING; #endif |
173acc7ce dmaengine: add dr... |
1150 |
|
a1c033190 fsldma: rename fs... |
1151 |
chan->common.device = &fdev->common; |
8ac695463 dmaengine: ensure... |
1152 |
dma_cookie_init(&chan->common); |
173acc7ce dmaengine: add dr... |
1153 |
|
d3f620b2c fsldma: simplify ... |
1154 |
/* find the IRQ line, if it exists in the device tree */ |
a1c033190 fsldma: rename fs... |
1155 |
chan->irq = irq_of_parse_and_map(node, 0); |
d3f620b2c fsldma: simplify ... |
1156 |
|
173acc7ce dmaengine: add dr... |
1157 |
/* Add the channel to DMA device channel list */ |
a1c033190 fsldma: rename fs... |
1158 |
list_add_tail(&chan->common.device_node, &fdev->common.channels); |
173acc7ce dmaengine: add dr... |
1159 |
|
a1c033190 fsldma: rename fs... |
1160 1161 |
dev_info(fdev->dev, "#%d (%s), irq %d ", chan->id, compatible, |
aa570be6d dmaengine: NO_IRQ... |
1162 |
chan->irq ? chan->irq : fdev->irq); |
173acc7ce dmaengine: add dr... |
1163 1164 |
return 0; |
51ee87f27 fsldma: fix incor... |
1165 |
|
e7a29151d fsldma: clean up ... |
1166 |
out_iounmap_regs: |
a1c033190 fsldma: rename fs... |
1167 1168 1169 |
iounmap(chan->regs); out_free_chan: kfree(chan); |
e7a29151d fsldma: clean up ... |
1170 |
out_return: |
173acc7ce dmaengine: add dr... |
1171 1172 |
return err; } |
a1c033190 fsldma: rename fs... |
1173 |
static void fsl_dma_chan_remove(struct fsldma_chan *chan) |
173acc7ce dmaengine: add dr... |
1174 |
{ |
a1c033190 fsldma: rename fs... |
1175 1176 1177 1178 |
irq_dispose_mapping(chan->irq); list_del(&chan->common.device_node); iounmap(chan->regs); kfree(chan); |
173acc7ce dmaengine: add dr... |
1179 |
} |
463a1f8b3 dma: remove use o... |
1180 |
static int fsldma_of_probe(struct platform_device *op) |
173acc7ce dmaengine: add dr... |
1181 |
{ |
a4f56d4b1 fsldma: rename st... |
1182 |
struct fsldma_device *fdev; |
77cd62e80 fsldma: allow Fre... |
1183 |
struct device_node *child; |
e7a29151d fsldma: clean up ... |
1184 |
int err; |
173acc7ce dmaengine: add dr... |
1185 |
|
a4f56d4b1 fsldma: rename st... |
1186 |
fdev = kzalloc(sizeof(*fdev), GFP_KERNEL); |
173acc7ce dmaengine: add dr... |
1187 |
if (!fdev) { |
e7a29151d fsldma: clean up ... |
1188 1189 |
err = -ENOMEM; goto out_return; |
173acc7ce dmaengine: add dr... |
1190 |
} |
e7a29151d fsldma: clean up ... |
1191 1192 |
fdev->dev = &op->dev; |
173acc7ce dmaengine: add dr... |
1193 |
INIT_LIST_HEAD(&fdev->common.channels); |
e7a29151d fsldma: clean up ... |
1194 |
/* ioremap the registers for use */ |
61c7a080a of: Always use 's... |
1195 |
fdev->regs = of_iomap(op->dev.of_node, 0); |
e7a29151d fsldma: clean up ... |
1196 1197 1198 1199 |
if (!fdev->regs) { dev_err(&op->dev, "unable to ioremap registers "); err = -ENOMEM; |
585a1db1b dmaengine: fsldma... |
1200 |
goto out_free; |
173acc7ce dmaengine: add dr... |
1201 |
} |
d3f620b2c fsldma: simplify ... |
1202 |
/* map the channel IRQ if it exists, but don't hookup the handler yet */ |
61c7a080a of: Always use 's... |
1203 |
fdev->irq = irq_of_parse_and_map(op->dev.of_node, 0); |
d3f620b2c fsldma: simplify ... |
1204 |
|
173acc7ce dmaengine: add dr... |
1205 |
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); |
bbea0b6e0 fsldma: Add DMA_S... |
1206 |
dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); |
173acc7ce dmaengine: add dr... |
1207 1208 1209 |
fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; |
079344818 DMAENGINE: generi... |
1210 |
fdev->common.device_tx_status = fsl_tx_status; |
173acc7ce dmaengine: add dr... |
1211 |
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; |
b7f7552bf dmaengine: fsl-dm... |
1212 1213 |
fdev->common.device_config = fsl_dma_device_config; fdev->common.device_terminate_all = fsl_dma_device_terminate_all; |
e7a29151d fsldma: clean up ... |
1214 |
fdev->common.dev = &op->dev; |
173acc7ce dmaengine: add dr... |
1215 |
|
75dc1775e dmaengine: fsldma... |
1216 1217 1218 1219 |
fdev->common.src_addr_widths = FSL_DMA_BUSWIDTHS; fdev->common.dst_addr_widths = FSL_DMA_BUSWIDTHS; fdev->common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); fdev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; |
e2c8e425b fsldma: add suppo... |
1220 |
dma_set_mask(&(op->dev), DMA_BIT_MASK(36)); |
dd3daca16 dma: use platform... |
1221 |
platform_set_drvdata(op, fdev); |
77cd62e80 fsldma: allow Fre... |
1222 |
|
e7a29151d fsldma: clean up ... |
1223 1224 1225 |
/* * We cannot use of_platform_bus_probe() because there is no * of_platform_bus_remove(). Instead, we manually instantiate every DMA |
77cd62e80 fsldma: allow Fre... |
1226 1227 |
* channel object. */ |
61c7a080a of: Always use 's... |
1228 |
for_each_child_of_node(op->dev.of_node, child) { |
e7a29151d fsldma: clean up ... |
1229 |
if (of_device_is_compatible(child, "fsl,eloplus-dma-channel")) { |
77cd62e80 fsldma: allow Fre... |
1230 1231 1232 |
fsl_dma_chan_probe(fdev, child, FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN, "fsl,eloplus-dma-channel"); |
e7a29151d fsldma: clean up ... |
1233 1234 1235 |
} if (of_device_is_compatible(child, "fsl,elo-dma-channel")) { |
77cd62e80 fsldma: allow Fre... |
1236 1237 1238 |
fsl_dma_chan_probe(fdev, child, FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN, "fsl,elo-dma-channel"); |
e7a29151d fsldma: clean up ... |
1239 |
} |
77cd62e80 fsldma: allow Fre... |
1240 |
} |
173acc7ce dmaengine: add dr... |
1241 |
|
d3f620b2c fsldma: simplify ... |
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 |
/* * Hookup the IRQ handler(s) * * If we have a per-controller interrupt, we prefer that to the * per-channel interrupts to reduce the number of shared interrupt * handlers on the same IRQ line */ err = fsldma_request_irqs(fdev); if (err) { dev_err(fdev->dev, "unable to request IRQs "); goto out_free_fdev; } |
173acc7ce dmaengine: add dr... |
1255 1256 |
dma_async_device_register(&fdev->common); return 0; |
e7a29151d fsldma: clean up ... |
1257 |
out_free_fdev: |
d3f620b2c fsldma: simplify ... |
1258 |
irq_dispose_mapping(fdev->irq); |
585a1db1b dmaengine: fsldma... |
1259 1260 |
iounmap(fdev->regs); out_free: |
173acc7ce dmaengine: add dr... |
1261 |
kfree(fdev); |
e7a29151d fsldma: clean up ... |
1262 |
out_return: |
173acc7ce dmaengine: add dr... |
1263 1264 |
return err; } |
2dc115813 of/device: Replac... |
1265 |
static int fsldma_of_remove(struct platform_device *op) |
77cd62e80 fsldma: allow Fre... |
1266 |
{ |
a4f56d4b1 fsldma: rename st... |
1267 |
struct fsldma_device *fdev; |
77cd62e80 fsldma: allow Fre... |
1268 |
unsigned int i; |
dd3daca16 dma: use platform... |
1269 |
fdev = platform_get_drvdata(op); |
77cd62e80 fsldma: allow Fre... |
1270 |
dma_async_device_unregister(&fdev->common); |
d3f620b2c fsldma: simplify ... |
1271 |
fsldma_free_irqs(fdev); |
e7a29151d fsldma: clean up ... |
1272 |
for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { |
77cd62e80 fsldma: allow Fre... |
1273 1274 |
if (fdev->chan[i]) fsl_dma_chan_remove(fdev->chan[i]); |
e7a29151d fsldma: clean up ... |
1275 |
} |
77cd62e80 fsldma: allow Fre... |
1276 |
|
e7a29151d fsldma: clean up ... |
1277 |
iounmap(fdev->regs); |
77cd62e80 fsldma: allow Fre... |
1278 |
kfree(fdev); |
77cd62e80 fsldma: allow Fre... |
1279 1280 1281 |
return 0; } |
14c6a3333 dmaengine: Freesc... |
1282 1283 1284 |
#ifdef CONFIG_PM static int fsldma_suspend_late(struct device *dev) { |
03bf2793f dmaengine: fsldma... |
1285 |
struct fsldma_device *fdev = dev_get_drvdata(dev); |
14c6a3333 dmaengine: Freesc... |
1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 |
struct fsldma_chan *chan; int i; for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { chan = fdev->chan[i]; if (!chan) continue; spin_lock_bh(&chan->desc_lock); if (unlikely(!chan->idle)) goto out; chan->regs_save.mr = get_mr(chan); chan->pm_state = SUSPENDED; spin_unlock_bh(&chan->desc_lock); } return 0; out: for (; i >= 0; i--) { chan = fdev->chan[i]; if (!chan) continue; chan->pm_state = RUNNING; spin_unlock_bh(&chan->desc_lock); } return -EBUSY; } static int fsldma_resume_early(struct device *dev) { |
03bf2793f dmaengine: fsldma... |
1316 |
struct fsldma_device *fdev = dev_get_drvdata(dev); |
14c6a3333 dmaengine: Freesc... |
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 |
struct fsldma_chan *chan; u32 mode; int i; for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { chan = fdev->chan[i]; if (!chan) continue; spin_lock_bh(&chan->desc_lock); mode = chan->regs_save.mr & ~FSL_DMA_MR_CS & ~FSL_DMA_MR_CC & ~FSL_DMA_MR_CA; set_mr(chan, mode); chan->pm_state = RUNNING; spin_unlock_bh(&chan->desc_lock); } return 0; } static const struct dev_pm_ops fsldma_pm_ops = { .suspend_late = fsldma_suspend_late, .resume_early = fsldma_resume_early, }; #endif |
4b1cf1fac dma: make Open Fi... |
1342 |
static const struct of_device_id fsldma_of_ids[] = { |
8de7a7d95 DMA: Freescale: u... |
1343 |
{ .compatible = "fsl,elo3-dma", }, |
049c9d455 [POWERPC] fsldma:... |
1344 1345 |
{ .compatible = "fsl,eloplus-dma", }, { .compatible = "fsl,elo-dma", }, |
173acc7ce dmaengine: add dr... |
1346 1347 |
{} }; |
7522c2402 dmaengine: fsldma... |
1348 |
MODULE_DEVICE_TABLE(of, fsldma_of_ids); |
173acc7ce dmaengine: add dr... |
1349 |
|
8faa7cf82 dt/fsldma: fix bu... |
1350 |
static struct platform_driver fsldma_of_driver = { |
4018294b5 of: Remove duplic... |
1351 1352 |
.driver = { .name = "fsl-elo-dma", |
4018294b5 of: Remove duplic... |
1353 |
.of_match_table = fsldma_of_ids, |
14c6a3333 dmaengine: Freesc... |
1354 1355 1356 |
#ifdef CONFIG_PM .pm = &fsldma_pm_ops, #endif |
4018294b5 of: Remove duplic... |
1357 1358 1359 |
}, .probe = fsldma_of_probe, .remove = fsldma_of_remove, |
173acc7ce dmaengine: add dr... |
1360 |
}; |
a4f56d4b1 fsldma: rename st... |
1361 1362 1363 1364 1365 |
/*----------------------------------------------------------------------------*/ /* Module Init / Exit */ /*----------------------------------------------------------------------------*/ static __init int fsldma_init(void) |
173acc7ce dmaengine: add dr... |
1366 |
{ |
8de7a7d95 DMA: Freescale: u... |
1367 1368 |
pr_info("Freescale Elo series DMA driver "); |
000061245 dt/powerpc: Elimi... |
1369 |
return platform_driver_register(&fsldma_of_driver); |
77cd62e80 fsldma: allow Fre... |
1370 |
} |
a4f56d4b1 fsldma: rename st... |
1371 |
static void __exit fsldma_exit(void) |
77cd62e80 fsldma: allow Fre... |
1372 |
{ |
000061245 dt/powerpc: Elimi... |
1373 |
platform_driver_unregister(&fsldma_of_driver); |
173acc7ce dmaengine: add dr... |
1374 |
} |
a4f56d4b1 fsldma: rename st... |
1375 1376 |
subsys_initcall(fsldma_init); module_exit(fsldma_exit); |
77cd62e80 fsldma: allow Fre... |
1377 |
|
8de7a7d95 DMA: Freescale: u... |
1378 |
MODULE_DESCRIPTION("Freescale Elo series DMA driver"); |
77cd62e80 fsldma: allow Fre... |
1379 |
MODULE_LICENSE("GPL"); |