Root/
Source at commit 0de2b2b3be81048189a32f7a3d3ba0ba9ec817b6 created 11 years 11 months ago. By Maarten ter Huurne, MIPS: JZ4740: Fixed value for round robin constant. | |
---|---|
1 | /* |
2 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> |
3 | * JZ4740 SoC DMA support |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License as published by the |
7 | * Free Software Foundation; either version 2 of the License, or (at your |
8 | * option) any later version. |
9 | * |
10 | * You should have received a copy of the GNU General Public License along |
11 | * with this program; if not, write to the Free Software Foundation, Inc., |
12 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
13 | * |
14 | */ |
15 | |
16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> |
18 | #include <linux/spinlock.h> |
19 | #include <linux/interrupt.h> |
20 | |
21 | #include <linux/dma-mapping.h> |
22 | #include <asm/mach-jz4740/dma.h> |
23 | #include <asm/mach-jz4740/base.h> |
24 | |
25 | #define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20) |
26 | #define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20) |
27 | #define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20) |
28 | #define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20) |
29 | #define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20) |
30 | #define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20) |
31 | #define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20) |
32 | |
33 | #define JZ_REG_DMA_CTRL 0x300 |
34 | #define JZ_REG_DMA_IRQ 0x304 |
35 | #define JZ_REG_DMA_DOORBELL 0x308 |
36 | #define JZ_REG_DMA_DOORBELL_SET 0x30C |
37 | |
38 | #define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31) |
39 | #define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6) |
40 | #define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4) |
41 | #define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3) |
42 | #define JZ_DMA_STATUS_CTRL_HALT BIT(2) |
43 | #define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1) |
44 | #define JZ_DMA_STATUS_CTRL_ENABLE BIT(0) |
45 | |
46 | #define JZ_DMA_CMD_SRC_INC BIT(23) |
47 | #define JZ_DMA_CMD_DST_INC BIT(22) |
48 | #define JZ_DMA_CMD_RDIL_MASK (0xf << 16) |
49 | #define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14) |
50 | #define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12) |
51 | #define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8) |
52 | #define JZ_DMA_CMD_BLOCK_MODE BIT(7) |
53 | #define JZ_DMA_CMD_DESC_VALID BIT(4) |
54 | #define JZ_DMA_CMD_DESC_VALID_MODE BIT(3) |
55 | #define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2) |
56 | #define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1) |
57 | #define JZ_DMA_CMD_LINK_ENABLE BIT(0) |
58 | |
59 | #define JZ_DMA_CMD_FLAGS_OFFSET 22 |
60 | #define JZ_DMA_CMD_RDIL_OFFSET 16 |
61 | #define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14 |
62 | #define JZ_DMA_CMD_DST_WIDTH_OFFSET 12 |
63 | #define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8 |
64 | #define JZ_DMA_CMD_MODE_OFFSET 7 |
65 | |
66 | #define JZ_DMA_CTRL_PRIORITY_012345 (0x0 << 8) |
67 | #define JZ_DMA_CTRL_PRIORITY_023145 (0x1 << 8) |
68 | #define JZ_DMA_CTRL_PRIORITY_201345 (0x2 << 8) |
69 | #define JZ_DMA_CTRL_PRIORITY_ROUND_ROBIN (0x3 << 8) |
70 | #define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8) |
71 | #define JZ_DMA_CTRL_HALT BIT(3) |
72 | #define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2) |
73 | #define JZ_DMA_CTRL_ENABLE BIT(0) |
74 | |
75 | |
76 | static void __iomem *jz4740_dma_base; |
77 | static spinlock_t jz4740_dma_lock; |
78 | |
79 | static inline uint32_t jz4740_dma_read(size_t reg) |
80 | { |
81 | return readl(jz4740_dma_base + reg); |
82 | } |
83 | |
84 | static inline void jz4740_dma_write(size_t reg, uint32_t val) |
85 | { |
86 | writel(val, jz4740_dma_base + reg); |
87 | } |
88 | |
89 | static inline void jz4740_dma_write_mask(size_t reg, uint32_t val, uint32_t mask) |
90 | { |
91 | uint32_t val2; |
92 | val2 = jz4740_dma_read(reg); |
93 | val2 &= ~mask; |
94 | val2 |= val; |
95 | jz4740_dma_write(reg, val2); |
96 | } |
97 | |
98 | struct jz4740_dma_chan { |
99 | unsigned int id; |
100 | void *dev; |
101 | const char *name; |
102 | |
103 | enum jz4740_dma_flags flags; |
104 | uint32_t transfer_shift; |
105 | |
106 | jz4740_dma_complete_callback_t complete_cb; |
107 | |
108 | unsigned used:1; |
109 | }; |
110 | |
111 | #define JZ4740_DMA_CHANNEL(_id) { .id = _id } |
112 | |
113 | struct jz4740_dma_chan jz4740_dma_channels[] = { |
114 | JZ4740_DMA_CHANNEL(0), |
115 | JZ4740_DMA_CHANNEL(1), |
116 | JZ4740_DMA_CHANNEL(2), |
117 | JZ4740_DMA_CHANNEL(3), |
118 | JZ4740_DMA_CHANNEL(4), |
119 | JZ4740_DMA_CHANNEL(5), |
120 | }; |
121 | |
122 | struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name, |
123 | int prio) |
124 | { |
125 | unsigned int i; |
126 | struct jz4740_dma_chan *dma = NULL; |
127 | |
128 | if (prio < 0 || prio > 1) |
129 | return NULL; |
130 | |
131 | spin_lock(&jz4740_dma_lock); |
132 | |
133 | for (i = prio * 3; i < prio * 3 + 3; ++i) { |
134 | if (!jz4740_dma_channels[i].used) { |
135 | dma = &jz4740_dma_channels[i]; |
136 | dma->used = 1; |
137 | break; |
138 | } |
139 | } |
140 | |
141 | spin_unlock(&jz4740_dma_lock); |
142 | |
143 | if (!dma) |
144 | return NULL; |
145 | |
146 | dma->dev = dev; |
147 | dma->name = name; |
148 | |
149 | return dma; |
150 | } |
151 | EXPORT_SYMBOL_GPL(jz4740_dma_request); |
152 | |
153 | void jz4740_dma_configure(struct jz4740_dma_chan *dma, |
154 | const struct jz4740_dma_config *config) |
155 | { |
156 | uint32_t cmd; |
157 | |
158 | switch (config->transfer_size) { |
159 | case JZ4740_DMA_TRANSFER_SIZE_2BYTE: |
160 | dma->transfer_shift = 1; |
161 | break; |
162 | case JZ4740_DMA_TRANSFER_SIZE_4BYTE: |
163 | dma->transfer_shift = 2; |
164 | break; |
165 | case JZ4740_DMA_TRANSFER_SIZE_16BYTE: |
166 | dma->transfer_shift = 4; |
167 | break; |
168 | case JZ4740_DMA_TRANSFER_SIZE_32BYTE: |
169 | dma->transfer_shift = 5; |
170 | break; |
171 | default: |
172 | dma->transfer_shift = 0; |
173 | break; |
174 | } |
175 | |
176 | cmd = config->flags << JZ_DMA_CMD_FLAGS_OFFSET; |
177 | cmd |= config->src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET; |
178 | cmd |= config->dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET; |
179 | cmd |= config->transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET; |
180 | cmd |= config->mode << JZ_DMA_CMD_MODE_OFFSET; |
181 | cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE; |
182 | |
183 | jz4740_dma_write(JZ_REG_DMA_CMD(dma->id), cmd); |
184 | jz4740_dma_write(JZ_REG_DMA_STATUS_CTRL(dma->id), 0); |
185 | jz4740_dma_write(JZ_REG_DMA_REQ_TYPE(dma->id), config->request_type); |
186 | } |
187 | EXPORT_SYMBOL_GPL(jz4740_dma_configure); |
188 | |
189 | void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src) |
190 | { |
191 | jz4740_dma_write(JZ_REG_DMA_SRC_ADDR(dma->id), src); |
192 | } |
193 | EXPORT_SYMBOL_GPL(jz4740_dma_set_src_addr); |
194 | |
195 | void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst) |
196 | { |
197 | jz4740_dma_write(JZ_REG_DMA_DST_ADDR(dma->id), dst); |
198 | } |
199 | EXPORT_SYMBOL_GPL(jz4740_dma_set_dst_addr); |
200 | |
201 | void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count) |
202 | { |
203 | count >>= dma->transfer_shift; |
204 | jz4740_dma_write(JZ_REG_DMA_TRANSFER_COUNT(dma->id), count); |
205 | } |
206 | EXPORT_SYMBOL_GPL(jz4740_dma_set_transfer_count); |
207 | |
208 | void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma, |
209 | jz4740_dma_complete_callback_t cb) |
210 | { |
211 | dma->complete_cb = cb; |
212 | } |
213 | EXPORT_SYMBOL_GPL(jz4740_dma_set_complete_cb); |
214 | |
215 | void jz4740_dma_free(struct jz4740_dma_chan *dma) |
216 | { |
217 | dma->dev = NULL; |
218 | dma->complete_cb = NULL; |
219 | dma->used = 0; |
220 | } |
221 | EXPORT_SYMBOL_GPL(jz4740_dma_free); |
222 | |
223 | void jz4740_dma_enable(struct jz4740_dma_chan *dma) |
224 | { |
225 | jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), |
226 | JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE, |
227 | JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC | |
228 | JZ_DMA_STATUS_CTRL_ENABLE); |
229 | |
230 | jz4740_dma_write_mask(JZ_REG_DMA_CTRL, |
231 | JZ_DMA_CTRL_ENABLE, |
232 | JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE); |
233 | } |
234 | EXPORT_SYMBOL_GPL(jz4740_dma_enable); |
235 | |
236 | void jz4740_dma_disable(struct jz4740_dma_chan *dma) |
237 | { |
238 | jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0, |
239 | JZ_DMA_STATUS_CTRL_ENABLE); |
240 | } |
241 | EXPORT_SYMBOL_GPL(jz4740_dma_disable); |
242 | |
243 | uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma) |
244 | { |
245 | uint32_t residue; |
246 | residue = jz4740_dma_read(JZ_REG_DMA_TRANSFER_COUNT(dma->id)); |
247 | return residue << dma->transfer_shift; |
248 | } |
249 | EXPORT_SYMBOL_GPL(jz4740_dma_get_residue); |
250 | |
251 | static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma) |
252 | { |
253 | (void) jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id)); |
254 | |
255 | jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0, |
256 | JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE); |
257 | |
258 | if (dma->complete_cb) |
259 | dma->complete_cb(dma, 0, dma->dev); |
260 | } |
261 | |
262 | static irqreturn_t jz4740_dma_irq(int irq, void *dev_id) |
263 | { |
264 | uint32_t irq_status; |
265 | unsigned int i; |
266 | |
267 | irq_status = readl(jz4740_dma_base + JZ_REG_DMA_IRQ); |
268 | |
269 | for (i = 0; i < 6; ++i) { |
270 | if (irq_status & (1 << i)) |
271 | jz4740_dma_chan_irq(&jz4740_dma_channels[i]); |
272 | } |
273 | |
274 | return IRQ_HANDLED; |
275 | } |
276 | |
277 | static int jz4740_dma_init(void) |
278 | { |
279 | unsigned int ret; |
280 | |
281 | jz4740_dma_base = ioremap(JZ4740_DMAC_BASE_ADDR, 0x400); |
282 | if (!jz4740_dma_base) |
283 | return -EBUSY; |
284 | |
285 | spin_lock_init(&jz4740_dma_lock); |
286 | |
287 | ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL); |
288 | if (ret) { |
289 | printk(KERN_ERR "JZ4740 DMA: Failed to request irq: %d\n", ret); |
290 | goto err_iounmap; |
291 | } |
292 | |
293 | jz4740_dma_write_mask(JZ_REG_DMA_CTRL, |
294 | JZ_DMA_CTRL_PRIORITY_ROUND_ROBIN, |
295 | JZ_DMA_CTRL_PRIORITY_MASK); |
296 | |
297 | return 0; |
298 | |
299 | err_iounmap: |
300 | iounmap(jz4740_dma_base); |
301 | return ret; |
302 | } |
303 | arch_initcall(jz4740_dma_init); |
304 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9