diff options
Diffstat (limited to 'arch/blackfin')
-rw-r--r-- | arch/blackfin/include/asm/dma.h | 156 | ||||
-rw-r--r-- | arch/blackfin/kernel/bfin_dma_5xx.c | 233 |
2 files changed, 137 insertions, 252 deletions
diff --git a/arch/blackfin/include/asm/dma.h b/arch/blackfin/include/asm/dma.h index 4928e7aa4801..690c25f5f992 100644 --- a/arch/blackfin/include/asm/dma.h +++ b/arch/blackfin/include/asm/dma.h | |||
@@ -129,50 +129,126 @@ void blackfin_dma_resume(void); | |||
129 | /******************************************************************************* | 129 | /******************************************************************************* |
130 | * DMA API's | 130 | * DMA API's |
131 | *******************************************************************************/ | 131 | *******************************************************************************/ |
132 | /* functions to set register mode */ | 132 | extern struct dma_channel dma_ch[MAX_DMA_CHANNELS]; |
133 | void set_dma_start_addr(unsigned int channel, unsigned long addr); | 133 | extern struct dma_register *dma_io_base_addr[MAX_DMA_CHANNELS]; |
134 | void set_dma_next_desc_addr(unsigned int channel, unsigned long addr); | 134 | extern int channel2irq(unsigned int channel); |
135 | void set_dma_curr_desc_addr(unsigned int channel, unsigned long addr); | 135 | |
136 | void set_dma_x_count(unsigned int channel, unsigned short x_count); | 136 | static inline void set_dma_start_addr(unsigned int channel, unsigned long addr) |
137 | void set_dma_x_modify(unsigned int channel, short x_modify); | 137 | { |
138 | void set_dma_y_count(unsigned int channel, unsigned short y_count); | 138 | dma_ch[channel].regs->start_addr = addr; |
139 | void set_dma_y_modify(unsigned int channel, short y_modify); | 139 | } |
140 | void set_dma_config(unsigned int channel, unsigned short config); | 140 | static inline void set_dma_next_desc_addr(unsigned int channel, unsigned long addr) |
141 | unsigned short set_bfin_dma_config(char direction, char flow_mode, | 141 | { |
142 | char intr_mode, char dma_mode, char width, | 142 | dma_ch[channel].regs->next_desc_ptr = addr; |
143 | char syncmode); | 143 | } |
144 | void set_dma_curr_addr(unsigned int channel, unsigned long addr); | 144 | static inline void set_dma_curr_desc_addr(unsigned int channel, unsigned long addr) |
145 | 145 | { | |
146 | /* get curr status for polling */ | 146 | dma_ch[channel].regs->curr_desc_ptr = addr; |
147 | unsigned short get_dma_curr_irqstat(unsigned int channel); | 147 | } |
148 | unsigned short get_dma_curr_xcount(unsigned int channel); | 148 | static inline void set_dma_x_count(unsigned int channel, unsigned short x_count) |
149 | unsigned short get_dma_curr_ycount(unsigned int channel); | 149 | { |
150 | unsigned long get_dma_next_desc_ptr(unsigned int channel); | 150 | dma_ch[channel].regs->x_count = x_count; |
151 | unsigned long get_dma_curr_desc_ptr(unsigned int channel); | 151 | } |
152 | unsigned long get_dma_curr_addr(unsigned int channel); | 152 | static inline void set_dma_y_count(unsigned int channel, unsigned short y_count) |
153 | 153 | { | |
154 | /* set large DMA mode descriptor */ | 154 | dma_ch[channel].regs->y_count = y_count; |
155 | void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg); | 155 | } |
156 | 156 | static inline void set_dma_x_modify(unsigned int channel, short x_modify) | |
157 | /* check if current channel is in use */ | 157 | { |
158 | int dma_channel_active(unsigned int channel); | 158 | dma_ch[channel].regs->x_modify = x_modify; |
159 | 159 | } | |
160 | /* common functions must be called in any mode */ | 160 | static inline void set_dma_y_modify(unsigned int channel, short y_modify) |
161 | { | ||
162 | dma_ch[channel].regs->y_modify = y_modify; | ||
163 | } | ||
164 | static inline void set_dma_config(unsigned int channel, unsigned short config) | ||
165 | { | ||
166 | dma_ch[channel].regs->cfg = config; | ||
167 | } | ||
168 | static inline void set_dma_curr_addr(unsigned int channel, unsigned long addr) | ||
169 | { | ||
170 | dma_ch[channel].regs->curr_addr_ptr = addr; | ||
171 | } | ||
172 | |||
173 | static inline unsigned short | ||
174 | set_bfin_dma_config(char direction, char flow_mode, | ||
175 | char intr_mode, char dma_mode, char width, char syncmode) | ||
176 | { | ||
177 | return (direction << 1) | (width << 2) | (dma_mode << 4) | | ||
178 | (intr_mode << 6) | (flow_mode << 12) | (syncmode << 5); | ||
179 | } | ||
180 | |||
181 | static inline unsigned short get_dma_curr_irqstat(unsigned int channel) | ||
182 | { | ||
183 | return dma_ch[channel].regs->irq_status; | ||
184 | } | ||
185 | static inline unsigned short get_dma_curr_xcount(unsigned int channel) | ||
186 | { | ||
187 | return dma_ch[channel].regs->curr_x_count; | ||
188 | } | ||
189 | static inline unsigned short get_dma_curr_ycount(unsigned int channel) | ||
190 | { | ||
191 | return dma_ch[channel].regs->curr_y_count; | ||
192 | } | ||
193 | static inline unsigned long get_dma_next_desc_ptr(unsigned int channel) | ||
194 | { | ||
195 | return dma_ch[channel].regs->next_desc_ptr; | ||
196 | } | ||
197 | static inline unsigned long get_dma_curr_desc_ptr(unsigned int channel) | ||
198 | { | ||
199 | return dma_ch[channel].regs->curr_desc_ptr; | ||
200 | } | ||
201 | static inline unsigned long get_dma_curr_addr(unsigned int channel) | ||
202 | { | ||
203 | return dma_ch[channel].regs->curr_addr_ptr; | ||
204 | } | ||
205 | |||
206 | static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize) | ||
207 | { | ||
208 | dma_ch[channel].regs->cfg |= ((ndsize & 0x0F) << 8); | ||
209 | dma_ch[channel].regs->next_desc_ptr = (unsigned long)sg; | ||
210 | } | ||
211 | |||
212 | static inline int dma_channel_active(unsigned int channel) | ||
213 | { | ||
214 | if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) | ||
215 | return 0; | ||
216 | else | ||
217 | return 1; | ||
218 | } | ||
219 | |||
220 | static inline void disable_dma(unsigned int channel) | ||
221 | { | ||
222 | dma_ch[channel].regs->cfg &= ~DMAEN; | ||
223 | SSYNC(); | ||
224 | dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED; | ||
225 | } | ||
226 | static inline void enable_dma(unsigned int channel) | ||
227 | { | ||
228 | dma_ch[channel].regs->curr_x_count = 0; | ||
229 | dma_ch[channel].regs->curr_y_count = 0; | ||
230 | dma_ch[channel].regs->cfg |= DMAEN; | ||
231 | dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED; | ||
232 | } | ||
161 | void free_dma(unsigned int channel); | 233 | void free_dma(unsigned int channel); |
162 | int dma_channel_active(unsigned int channel); /* check if a channel is in use */ | ||
163 | void disable_dma(unsigned int channel); | ||
164 | void enable_dma(unsigned int channel); | ||
165 | int request_dma(unsigned int channel, const char *device_id); | 234 | int request_dma(unsigned int channel, const char *device_id); |
166 | int set_dma_callback(unsigned int channel, irq_handler_t callback, | 235 | int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data); |
167 | void *data); | 236 | |
168 | void dma_disable_irq(unsigned int channel); | 237 | static inline void dma_disable_irq(unsigned int channel) |
169 | void dma_enable_irq(unsigned int channel); | 238 | { |
170 | void clear_dma_irqstat(unsigned int channel); | 239 | disable_irq(dma_ch[channel].irq); |
240 | } | ||
241 | static inline void dma_enable_irq(unsigned int channel) | ||
242 | { | ||
243 | enable_irq(dma_ch[channel].irq); | ||
244 | } | ||
245 | static inline void clear_dma_irqstat(unsigned int channel) | ||
246 | { | ||
247 | dma_ch[channel].regs->irq_status = DMA_DONE | DMA_ERR; | ||
248 | } | ||
249 | |||
171 | void *dma_memcpy(void *dest, const void *src, size_t count); | 250 | void *dma_memcpy(void *dest, const void *src, size_t count); |
172 | void *safe_dma_memcpy(void *dest, const void *src, size_t count); | 251 | void *safe_dma_memcpy(void *dest, const void *src, size_t count); |
173 | void blackfin_dma_early_init(void); | 252 | void blackfin_dma_early_init(void); |
174 | 253 | ||
175 | extern int channel2irq(unsigned int channel); | ||
176 | extern struct dma_register *dma_io_base_addr[MAX_DMA_CHANNELS]; | ||
177 | |||
178 | #endif | 254 | #endif |
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index ed7d2859a626..917b5b8e32c8 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * bfin_dma_5xx.c - Blackfin DMA implementation | 2 | * bfin_dma_5xx.c - Blackfin DMA implementation |
3 | * | 3 | * |
4 | * Copyright 2004-2006 Analog Devices Inc. | 4 | * Copyright 2004-2008 Analog Devices Inc. |
5 | * Licensed under the GPL-2 or later. | 5 | * Licensed under the GPL-2 or later. |
6 | */ | 6 | */ |
7 | 7 | ||
@@ -20,22 +20,8 @@ | |||
20 | #include <asm/dma.h> | 20 | #include <asm/dma.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | 22 | ||
23 | /************************************************************************** | 23 | struct dma_channel dma_ch[MAX_DMA_CHANNELS]; |
24 | * Global Variables | 24 | EXPORT_SYMBOL(dma_ch); |
25 | ***************************************************************************/ | ||
26 | |||
27 | static struct dma_channel dma_ch[MAX_DMA_CHANNELS]; | ||
28 | |||
29 | /*------------------------------------------------------------------------------ | ||
30 | * Set the Buffer Clear bit in the Configuration register of specific DMA | ||
31 | * channel. This will stop the descriptor based DMA operation. | ||
32 | *-----------------------------------------------------------------------------*/ | ||
33 | static void clear_dma_buffer(unsigned int channel) | ||
34 | { | ||
35 | dma_ch[channel].regs->cfg |= RESTART; | ||
36 | SSYNC(); | ||
37 | dma_ch[channel].regs->cfg &= ~RESTART; | ||
38 | } | ||
39 | 25 | ||
40 | static int __init blackfin_dma_init(void) | 26 | static int __init blackfin_dma_init(void) |
41 | { | 27 | { |
@@ -92,9 +78,11 @@ static int __init proc_dma_init(void) | |||
92 | late_initcall(proc_dma_init); | 78 | late_initcall(proc_dma_init); |
93 | #endif | 79 | #endif |
94 | 80 | ||
95 | /*------------------------------------------------------------------------------ | 81 | /** |
96 | * Request the specific DMA channel from the system. | 82 | * request_dma - request a DMA channel |
97 | *-----------------------------------------------------------------------------*/ | 83 | * |
84 | * Request the specific DMA channel from the system if it's available. | ||
85 | */ | ||
98 | int request_dma(unsigned int channel, const char *device_id) | 86 | int request_dma(unsigned int channel, const char *device_id) |
99 | { | 87 | { |
100 | pr_debug("request_dma() : BEGIN \n"); | 88 | pr_debug("request_dma() : BEGIN \n"); |
@@ -172,6 +160,19 @@ int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data) | |||
172 | } | 160 | } |
173 | EXPORT_SYMBOL(set_dma_callback); | 161 | EXPORT_SYMBOL(set_dma_callback); |
174 | 162 | ||
163 | /** | ||
164 | * clear_dma_buffer - clear DMA fifos for specified channel | ||
165 | * | ||
166 | * Set the Buffer Clear bit in the Configuration register of specific DMA | ||
167 | * channel. This will stop the descriptor based DMA operation. | ||
168 | */ | ||
169 | static void clear_dma_buffer(unsigned int channel) | ||
170 | { | ||
171 | dma_ch[channel].regs->cfg |= RESTART; | ||
172 | SSYNC(); | ||
173 | dma_ch[channel].regs->cfg &= ~RESTART; | ||
174 | } | ||
175 | |||
175 | void free_dma(unsigned int channel) | 176 | void free_dma(unsigned int channel) |
176 | { | 177 | { |
177 | pr_debug("freedma() : BEGIN \n"); | 178 | pr_debug("freedma() : BEGIN \n"); |
@@ -194,198 +195,6 @@ void free_dma(unsigned int channel) | |||
194 | } | 195 | } |
195 | EXPORT_SYMBOL(free_dma); | 196 | EXPORT_SYMBOL(free_dma); |
196 | 197 | ||
197 | void dma_enable_irq(unsigned int channel) | ||
198 | { | ||
199 | pr_debug("dma_enable_irq() : BEGIN \n"); | ||
200 | enable_irq(dma_ch[channel].irq); | ||
201 | } | ||
202 | EXPORT_SYMBOL(dma_enable_irq); | ||
203 | |||
204 | void dma_disable_irq(unsigned int channel) | ||
205 | { | ||
206 | pr_debug("dma_disable_irq() : BEGIN \n"); | ||
207 | disable_irq(dma_ch[channel].irq); | ||
208 | } | ||
209 | EXPORT_SYMBOL(dma_disable_irq); | ||
210 | |||
211 | int dma_channel_active(unsigned int channel) | ||
212 | { | ||
213 | if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) { | ||
214 | return 0; | ||
215 | } else { | ||
216 | return 1; | ||
217 | } | ||
218 | } | ||
219 | EXPORT_SYMBOL(dma_channel_active); | ||
220 | |||
221 | /*------------------------------------------------------------------------------ | ||
222 | * stop the specific DMA channel. | ||
223 | *-----------------------------------------------------------------------------*/ | ||
224 | void disable_dma(unsigned int channel) | ||
225 | { | ||
226 | pr_debug("stop_dma() : BEGIN \n"); | ||
227 | dma_ch[channel].regs->cfg &= ~DMAEN; /* Clean the enable bit */ | ||
228 | SSYNC(); | ||
229 | dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED; | ||
230 | /* Needs to be enabled Later */ | ||
231 | pr_debug("stop_dma() : END \n"); | ||
232 | return; | ||
233 | } | ||
234 | EXPORT_SYMBOL(disable_dma); | ||
235 | |||
236 | void enable_dma(unsigned int channel) | ||
237 | { | ||
238 | pr_debug("enable_dma() : BEGIN \n"); | ||
239 | dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED; | ||
240 | dma_ch[channel].regs->curr_x_count = 0; | ||
241 | dma_ch[channel].regs->curr_y_count = 0; | ||
242 | |||
243 | dma_ch[channel].regs->cfg |= DMAEN; /* Set the enable bit */ | ||
244 | pr_debug("enable_dma() : END \n"); | ||
245 | return; | ||
246 | } | ||
247 | EXPORT_SYMBOL(enable_dma); | ||
248 | |||
249 | /*------------------------------------------------------------------------------ | ||
250 | * Set the Start Address register for the specific DMA channel | ||
251 | * This function can be used for register based DMA, | ||
252 | * to setup the start address | ||
253 | * addr: Starting address of the DMA Data to be transferred. | ||
254 | *-----------------------------------------------------------------------------*/ | ||
255 | void set_dma_start_addr(unsigned int channel, unsigned long addr) | ||
256 | { | ||
257 | pr_debug("set_dma_start_addr() : BEGIN \n"); | ||
258 | dma_ch[channel].regs->start_addr = addr; | ||
259 | pr_debug("set_dma_start_addr() : END\n"); | ||
260 | } | ||
261 | EXPORT_SYMBOL(set_dma_start_addr); | ||
262 | |||
263 | void set_dma_next_desc_addr(unsigned int channel, unsigned long addr) | ||
264 | { | ||
265 | pr_debug("set_dma_next_desc_addr() : BEGIN \n"); | ||
266 | dma_ch[channel].regs->next_desc_ptr = addr; | ||
267 | pr_debug("set_dma_next_desc_addr() : END\n"); | ||
268 | } | ||
269 | EXPORT_SYMBOL(set_dma_next_desc_addr); | ||
270 | |||
271 | void set_dma_curr_desc_addr(unsigned int channel, unsigned long addr) | ||
272 | { | ||
273 | pr_debug("set_dma_curr_desc_addr() : BEGIN \n"); | ||
274 | dma_ch[channel].regs->curr_desc_ptr = addr; | ||
275 | pr_debug("set_dma_curr_desc_addr() : END\n"); | ||
276 | } | ||
277 | EXPORT_SYMBOL(set_dma_curr_desc_addr); | ||
278 | |||
279 | void set_dma_x_count(unsigned int channel, unsigned short x_count) | ||
280 | { | ||
281 | dma_ch[channel].regs->x_count = x_count; | ||
282 | } | ||
283 | EXPORT_SYMBOL(set_dma_x_count); | ||
284 | |||
285 | void set_dma_y_count(unsigned int channel, unsigned short y_count) | ||
286 | { | ||
287 | dma_ch[channel].regs->y_count = y_count; | ||
288 | } | ||
289 | EXPORT_SYMBOL(set_dma_y_count); | ||
290 | |||
291 | void set_dma_x_modify(unsigned int channel, short x_modify) | ||
292 | { | ||
293 | dma_ch[channel].regs->x_modify = x_modify; | ||
294 | } | ||
295 | EXPORT_SYMBOL(set_dma_x_modify); | ||
296 | |||
297 | void set_dma_y_modify(unsigned int channel, short y_modify) | ||
298 | { | ||
299 | dma_ch[channel].regs->y_modify = y_modify; | ||
300 | } | ||
301 | EXPORT_SYMBOL(set_dma_y_modify); | ||
302 | |||
303 | void set_dma_config(unsigned int channel, unsigned short config) | ||
304 | { | ||
305 | dma_ch[channel].regs->cfg = config; | ||
306 | } | ||
307 | EXPORT_SYMBOL(set_dma_config); | ||
308 | |||
309 | unsigned short | ||
310 | set_bfin_dma_config(char direction, char flow_mode, | ||
311 | char intr_mode, char dma_mode, char width, char syncmode) | ||
312 | { | ||
313 | unsigned short config; | ||
314 | |||
315 | config = | ||
316 | ((direction << 1) | (width << 2) | (dma_mode << 4) | | ||
317 | (intr_mode << 6) | (flow_mode << 12) | (syncmode << 5)); | ||
318 | return config; | ||
319 | } | ||
320 | EXPORT_SYMBOL(set_bfin_dma_config); | ||
321 | |||
322 | void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg) | ||
323 | { | ||
324 | dma_ch[channel].regs->cfg |= ((nr_sg & 0x0F) << 8); | ||
325 | dma_ch[channel].regs->next_desc_ptr = (unsigned int)sg; | ||
326 | } | ||
327 | EXPORT_SYMBOL(set_dma_sg); | ||
328 | |||
329 | void set_dma_curr_addr(unsigned int channel, unsigned long addr) | ||
330 | { | ||
331 | dma_ch[channel].regs->curr_addr_ptr = addr; | ||
332 | } | ||
333 | EXPORT_SYMBOL(set_dma_curr_addr); | ||
334 | |||
335 | /*------------------------------------------------------------------------------ | ||
336 | * Get the DMA status of a specific DMA channel from the system. | ||
337 | *-----------------------------------------------------------------------------*/ | ||
338 | unsigned short get_dma_curr_irqstat(unsigned int channel) | ||
339 | { | ||
340 | return dma_ch[channel].regs->irq_status; | ||
341 | } | ||
342 | EXPORT_SYMBOL(get_dma_curr_irqstat); | ||
343 | |||
344 | /*------------------------------------------------------------------------------ | ||
345 | * Clear the DMA_DONE bit in DMA status. Stop the DMA completion interrupt. | ||
346 | *-----------------------------------------------------------------------------*/ | ||
347 | void clear_dma_irqstat(unsigned int channel) | ||
348 | { | ||
349 | dma_ch[channel].regs->irq_status |= 3; | ||
350 | } | ||
351 | EXPORT_SYMBOL(clear_dma_irqstat); | ||
352 | |||
353 | /*------------------------------------------------------------------------------ | ||
354 | * Get current DMA xcount of a specific DMA channel from the system. | ||
355 | *-----------------------------------------------------------------------------*/ | ||
356 | unsigned short get_dma_curr_xcount(unsigned int channel) | ||
357 | { | ||
358 | return dma_ch[channel].regs->curr_x_count; | ||
359 | } | ||
360 | EXPORT_SYMBOL(get_dma_curr_xcount); | ||
361 | |||
362 | /*------------------------------------------------------------------------------ | ||
363 | * Get current DMA ycount of a specific DMA channel from the system. | ||
364 | *-----------------------------------------------------------------------------*/ | ||
365 | unsigned short get_dma_curr_ycount(unsigned int channel) | ||
366 | { | ||
367 | return dma_ch[channel].regs->curr_y_count; | ||
368 | } | ||
369 | EXPORT_SYMBOL(get_dma_curr_ycount); | ||
370 | |||
371 | unsigned long get_dma_next_desc_ptr(unsigned int channel) | ||
372 | { | ||
373 | return dma_ch[channel].regs->next_desc_ptr; | ||
374 | } | ||
375 | EXPORT_SYMBOL(get_dma_next_desc_ptr); | ||
376 | |||
377 | unsigned long get_dma_curr_desc_ptr(unsigned int channel) | ||
378 | { | ||
379 | return dma_ch[channel].regs->curr_desc_ptr; | ||
380 | } | ||
381 | EXPORT_SYMBOL(get_dma_curr_desc_ptr); | ||
382 | |||
383 | unsigned long get_dma_curr_addr(unsigned int channel) | ||
384 | { | ||
385 | return dma_ch[channel].regs->curr_addr_ptr; | ||
386 | } | ||
387 | EXPORT_SYMBOL(get_dma_curr_addr); | ||
388 | |||
389 | #ifdef CONFIG_PM | 198 | #ifdef CONFIG_PM |
390 | # ifndef MAX_DMA_SUSPEND_CHANNELS | 199 | # ifndef MAX_DMA_SUSPEND_CHANNELS |
391 | # define MAX_DMA_SUSPEND_CHANNELS MAX_DMA_CHANNELS | 200 | # define MAX_DMA_SUSPEND_CHANNELS MAX_DMA_CHANNELS |