blob: e4f7b8043f025335d4acf2f2dc95c37e58d16ca4 [file] [log] [blame]
Bryan Wu1394f032007-05-06 14:50:22 -07001/*
Mike Frysingerb03f2032009-01-07 23:14:38 +08002 * dma.h - Blackfin DMA defines/structures/etc...
Bryan Wu1394f032007-05-06 14:50:22 -07003 *
Mike Frysingerb03f2032009-01-07 23:14:38 +08004 * Copyright 2004-2008 Analog Devices Inc.
5 * Licensed under the GPL-2 or later.
Bryan Wu1394f032007-05-06 14:50:22 -07006 */
7
8#ifndef _BLACKFIN_DMA_H_
9#define _BLACKFIN_DMA_H_
10
Bryan Wu1394f032007-05-06 14:50:22 -070011#include <linux/interrupt.h>
Mike Frysinger4c1ed6a2009-01-07 23:14:38 +080012#include <mach/dma.h>
Bryan Wu1394f032007-05-06 14:50:22 -070013#include <asm/blackfin.h>
Mike Frysinger4c1ed6a2009-01-07 23:14:38 +080014#include <asm/page.h>
Bryan Wu1394f032007-05-06 14:50:22 -070015
16#define MAX_DMA_ADDRESS PAGE_OFFSET
17
18/*****************************************************************************
19* Generic DMA Declarations
20*
21****************************************************************************/
22enum dma_chan_status {
23 DMA_CHANNEL_FREE,
24 DMA_CHANNEL_REQUESTED,
25 DMA_CHANNEL_ENABLED,
26};
27
28/*-------------------------
29 * config reg bits value
30 *-------------------------*/
31#define DATA_SIZE_8 0
32#define DATA_SIZE_16 1
33#define DATA_SIZE_32 2
34
35#define DMA_FLOW_STOP 0
36#define DMA_FLOW_AUTO 1
37#define DMA_FLOW_ARRAY 4
38#define DMA_FLOW_SMALL 6
39#define DMA_FLOW_LARGE 7
40
41#define DIMENSION_LINEAR 0
42#define DIMENSION_2D 1
43
44#define DIR_READ 0
45#define DIR_WRITE 1
46
47#define INTR_DISABLE 0
48#define INTR_ON_BUF 2
49#define INTR_ON_ROW 3
50
Michael Hennerich2047e402008-01-22 15:29:18 +080051#define DMA_NOSYNC_KEEP_DMA_BUF 0
52#define DMA_SYNC_RESTART 1
53
Bryan Wu1394f032007-05-06 14:50:22 -070054struct dmasg {
Mike Frysinger6ab729d2009-01-07 23:14:38 +080055 void *next_desc_addr;
Bryan Wu1394f032007-05-06 14:50:22 -070056 unsigned long start_addr;
57 unsigned short cfg;
58 unsigned short x_count;
59 short x_modify;
60 unsigned short y_count;
61 short y_modify;
62} __attribute__((packed));
63
64struct dma_register {
Mike Frysinger6ab729d2009-01-07 23:14:38 +080065 void *next_desc_ptr; /* DMA Next Descriptor Pointer register */
Bryan Wu1394f032007-05-06 14:50:22 -070066 unsigned long start_addr; /* DMA Start address register */
67
68 unsigned short cfg; /* DMA Configuration register */
69 unsigned short dummy1; /* DMA Configuration register */
70
71 unsigned long reserved;
72
73 unsigned short x_count; /* DMA x_count register */
74 unsigned short dummy2;
75
76 short x_modify; /* DMA x_modify register */
77 unsigned short dummy3;
78
79 unsigned short y_count; /* DMA y_count register */
80 unsigned short dummy4;
81
82 short y_modify; /* DMA y_modify register */
83 unsigned short dummy5;
84
Mike Frysinger6ab729d2009-01-07 23:14:38 +080085 void *curr_desc_ptr; /* DMA Current Descriptor Pointer
Bryan Wu1394f032007-05-06 14:50:22 -070086 register */
Bryan Wu452af712007-10-22 00:02:14 +080087 unsigned long curr_addr_ptr; /* DMA Current Address Pointer
Bryan Wu1394f032007-05-06 14:50:22 -070088 register */
89 unsigned short irq_status; /* DMA irq status register */
90 unsigned short dummy6;
91
92 unsigned short peripheral_map; /* DMA peripheral map register */
93 unsigned short dummy7;
94
95 unsigned short curr_x_count; /* DMA Current x-count register */
96 unsigned short dummy8;
97
98 unsigned long reserved2;
99
100 unsigned short curr_y_count; /* DMA Current y-count register */
101 unsigned short dummy9;
102
103 unsigned long reserved3;
104
105};
106
Mike Frysinger4c1ed6a2009-01-07 23:14:38 +0800107struct mutex;
Bryan Wu1394f032007-05-06 14:50:22 -0700108struct dma_channel {
109 struct mutex dmalock;
Michael McTernan99532fd2009-01-07 23:14:38 +0800110 const char *device_id;
Bryan Wu1394f032007-05-06 14:50:22 -0700111 enum dma_chan_status chan_status;
Mike Frysinger4ce18732009-01-07 23:14:38 +0800112 volatile struct dma_register *regs;
Bryan Wu1394f032007-05-06 14:50:22 -0700113 struct dmasg *sg; /* large mode descriptor */
Michael Hennericha2ba8b12008-10-28 18:19:29 +0800114 unsigned int irq;
Bryan Wu1394f032007-05-06 14:50:22 -0700115 void *data;
Michael Hennerich1efc80b2008-07-19 16:57:32 +0800116#ifdef CONFIG_PM
117 unsigned short saved_peripheral_map;
118#endif
Bryan Wu1394f032007-05-06 14:50:22 -0700119};
120
Michael Hennerich1efc80b2008-07-19 16:57:32 +0800121#ifdef CONFIG_PM
122int blackfin_dma_suspend(void);
123void blackfin_dma_resume(void);
124#endif
125
Bryan Wu1394f032007-05-06 14:50:22 -0700126/*******************************************************************************
127* DMA API's
128*******************************************************************************/
Mike Frysinger9c417a42009-01-07 23:14:39 +0800129extern struct dma_channel dma_ch[MAX_DMA_CHANNELS];
130extern struct dma_register *dma_io_base_addr[MAX_DMA_CHANNELS];
131extern int channel2irq(unsigned int channel);
Bryan Wu1394f032007-05-06 14:50:22 -0700132
Mike Frysinger9c417a42009-01-07 23:14:39 +0800133static inline void set_dma_start_addr(unsigned int channel, unsigned long addr)
134{
135 dma_ch[channel].regs->start_addr = addr;
136}
Mike Frysinger6ab729d2009-01-07 23:14:38 +0800137static inline void set_dma_next_desc_addr(unsigned int channel, void *addr)
Mike Frysinger9c417a42009-01-07 23:14:39 +0800138{
139 dma_ch[channel].regs->next_desc_ptr = addr;
140}
Mike Frysinger6ab729d2009-01-07 23:14:38 +0800141static inline void set_dma_curr_desc_addr(unsigned int channel, void *addr)
Mike Frysinger9c417a42009-01-07 23:14:39 +0800142{
143 dma_ch[channel].regs->curr_desc_ptr = addr;
144}
145static inline void set_dma_x_count(unsigned int channel, unsigned short x_count)
146{
147 dma_ch[channel].regs->x_count = x_count;
148}
149static inline void set_dma_y_count(unsigned int channel, unsigned short y_count)
150{
151 dma_ch[channel].regs->y_count = y_count;
152}
153static inline void set_dma_x_modify(unsigned int channel, short x_modify)
154{
155 dma_ch[channel].regs->x_modify = x_modify;
156}
157static inline void set_dma_y_modify(unsigned int channel, short y_modify)
158{
159 dma_ch[channel].regs->y_modify = y_modify;
160}
161static inline void set_dma_config(unsigned int channel, unsigned short config)
162{
163 dma_ch[channel].regs->cfg = config;
164}
165static inline void set_dma_curr_addr(unsigned int channel, unsigned long addr)
166{
167 dma_ch[channel].regs->curr_addr_ptr = addr;
168}
Bryan Wu1394f032007-05-06 14:50:22 -0700169
Mike Frysinger9c417a42009-01-07 23:14:39 +0800170static inline unsigned short
171set_bfin_dma_config(char direction, char flow_mode,
172 char intr_mode, char dma_mode, char width, char syncmode)
173{
174 return (direction << 1) | (width << 2) | (dma_mode << 4) |
175 (intr_mode << 6) | (flow_mode << 12) | (syncmode << 5);
176}
Bryan Wu1394f032007-05-06 14:50:22 -0700177
Mike Frysinger9c417a42009-01-07 23:14:39 +0800178static inline unsigned short get_dma_curr_irqstat(unsigned int channel)
179{
180 return dma_ch[channel].regs->irq_status;
181}
182static inline unsigned short get_dma_curr_xcount(unsigned int channel)
183{
184 return dma_ch[channel].regs->curr_x_count;
185}
186static inline unsigned short get_dma_curr_ycount(unsigned int channel)
187{
188 return dma_ch[channel].regs->curr_y_count;
189}
Mike Frysinger6ab729d2009-01-07 23:14:38 +0800190static inline void *get_dma_next_desc_ptr(unsigned int channel)
Mike Frysinger9c417a42009-01-07 23:14:39 +0800191{
192 return dma_ch[channel].regs->next_desc_ptr;
193}
Mike Frysinger6ab729d2009-01-07 23:14:38 +0800194static inline void *get_dma_curr_desc_ptr(unsigned int channel)
Mike Frysinger9c417a42009-01-07 23:14:39 +0800195{
196 return dma_ch[channel].regs->curr_desc_ptr;
197}
Mike Frysinger71f5ca32009-01-07 23:14:38 +0800198static inline unsigned short get_dma_config(unsigned int channel)
199{
200 return dma_ch[channel].regs->cfg;
201}
Mike Frysinger9c417a42009-01-07 23:14:39 +0800202static inline unsigned long get_dma_curr_addr(unsigned int channel)
203{
204 return dma_ch[channel].regs->curr_addr_ptr;
205}
Bryan Wu1394f032007-05-06 14:50:22 -0700206
Mike Frysinger9c417a42009-01-07 23:14:39 +0800207static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize)
208{
Mike Frysingerd41e8002009-01-07 23:14:38 +0800209 dma_ch[channel].regs->cfg =
210 (dma_ch[channel].regs->cfg & ~(0xf << 8)) |
211 ((ndsize & 0xf) << 8);
Mike Frysinger6ab729d2009-01-07 23:14:38 +0800212 dma_ch[channel].regs->next_desc_ptr = sg;
Mike Frysinger9c417a42009-01-07 23:14:39 +0800213}
214
215static inline int dma_channel_active(unsigned int channel)
216{
217 if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE)
218 return 0;
219 else
220 return 1;
221}
222
223static inline void disable_dma(unsigned int channel)
224{
225 dma_ch[channel].regs->cfg &= ~DMAEN;
226 SSYNC();
227 dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
228}
229static inline void enable_dma(unsigned int channel)
230{
231 dma_ch[channel].regs->curr_x_count = 0;
232 dma_ch[channel].regs->curr_y_count = 0;
233 dma_ch[channel].regs->cfg |= DMAEN;
234 dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED;
235}
Bryan Wu1394f032007-05-06 14:50:22 -0700236void free_dma(unsigned int channel);
Michael McTernan99532fd2009-01-07 23:14:38 +0800237int request_dma(unsigned int channel, const char *device_id);
Mike Frysinger9c417a42009-01-07 23:14:39 +0800238int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data);
239
240static inline void dma_disable_irq(unsigned int channel)
241{
242 disable_irq(dma_ch[channel].irq);
243}
244static inline void dma_enable_irq(unsigned int channel)
245{
246 enable_irq(dma_ch[channel].irq);
247}
248static inline void clear_dma_irqstat(unsigned int channel)
249{
250 dma_ch[channel].regs->irq_status = DMA_DONE | DMA_ERR;
251}
252
Bryan Wu1394f032007-05-06 14:50:22 -0700253void *dma_memcpy(void *dest, const void *src, size_t count);
254void *safe_dma_memcpy(void *dest, const void *src, size_t count);
Mike Frysingerdd3dd382009-01-07 23:14:39 +0800255void blackfin_dma_early_init(void);
Bryan Wu1394f032007-05-06 14:50:22 -0700256
Bryan Wu1394f032007-05-06 14:50:22 -0700257#endif