aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2009-02-21 16:42:50 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-02-21 16:42:50 -0500
commit22b61a11fd4e6d7a48d694ce350331bebc0394ed (patch)
treef4be46c8154f5094c248fcd9fdf644b236f591b3 /arch/arm/kernel
parent423145a5d4def58cff760809d48cfb21316d59a9 (diff)
parentfa4e998999322bc1b11d2c8b19b9fa2016fd1548 (diff)
Merge branch 'dma' into devel
Conflicts: arch/arm/plat-mxc/dma-mx1-mx2.c
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/dma-isa.c67
-rw-r--r--arch/arm/kernel/dma.c119
2 files changed, 101 insertions, 85 deletions
diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c
index 4a3a50495c60..0e88e46fc732 100644
--- a/arch/arm/kernel/dma-isa.c
+++ b/arch/arm/kernel/dma-isa.c
@@ -24,11 +24,6 @@
24#include <asm/dma.h> 24#include <asm/dma.h>
25#include <asm/mach/dma.h> 25#include <asm/mach/dma.h>
26 26
27#define ISA_DMA_MODE_READ 0x44
28#define ISA_DMA_MODE_WRITE 0x48
29#define ISA_DMA_MODE_CASCADE 0xc0
30#define ISA_DMA_AUTOINIT 0x10
31
32#define ISA_DMA_MASK 0 27#define ISA_DMA_MASK 0
33#define ISA_DMA_MODE 1 28#define ISA_DMA_MODE 1
34#define ISA_DMA_CLRFF 2 29#define ISA_DMA_CLRFF 2
@@ -49,38 +44,35 @@ static unsigned int isa_dma_port[8][7] = {
49 { 0xd4, 0xd6, 0xd8, 0x48a, 0x08a, 0xcc, 0xce } 44 { 0xd4, 0xd6, 0xd8, 0x48a, 0x08a, 0xcc, 0xce }
50}; 45};
51 46
52static int isa_get_dma_residue(dmach_t channel, dma_t *dma) 47static int isa_get_dma_residue(unsigned int chan, dma_t *dma)
53{ 48{
54 unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT]; 49 unsigned int io_port = isa_dma_port[chan][ISA_DMA_COUNT];
55 int count; 50 int count;
56 51
57 count = 1 + inb(io_port); 52 count = 1 + inb(io_port);
58 count |= inb(io_port) << 8; 53 count |= inb(io_port) << 8;
59 54
60 return channel < 4 ? count : (count << 1); 55 return chan < 4 ? count : (count << 1);
61} 56}
62 57
63static void isa_enable_dma(dmach_t channel, dma_t *dma) 58static void isa_enable_dma(unsigned int chan, dma_t *dma)
64{ 59{
65 if (dma->invalid) { 60 if (dma->invalid) {
66 unsigned long address, length; 61 unsigned long address, length;
67 unsigned int mode; 62 unsigned int mode;
68 enum dma_data_direction direction; 63 enum dma_data_direction direction;
69 64
70 mode = channel & 3; 65 mode = (chan & 3) | dma->dma_mode;
71 switch (dma->dma_mode & DMA_MODE_MASK) { 66 switch (dma->dma_mode & DMA_MODE_MASK) {
72 case DMA_MODE_READ: 67 case DMA_MODE_READ:
73 mode |= ISA_DMA_MODE_READ;
74 direction = DMA_FROM_DEVICE; 68 direction = DMA_FROM_DEVICE;
75 break; 69 break;
76 70
77 case DMA_MODE_WRITE: 71 case DMA_MODE_WRITE:
78 mode |= ISA_DMA_MODE_WRITE;
79 direction = DMA_TO_DEVICE; 72 direction = DMA_TO_DEVICE;
80 break; 73 break;
81 74
82 case DMA_MODE_CASCADE: 75 case DMA_MODE_CASCADE:
83 mode |= ISA_DMA_MODE_CASCADE;
84 direction = DMA_BIDIRECTIONAL; 76 direction = DMA_BIDIRECTIONAL;
85 break; 77 break;
86 78
@@ -105,34 +97,31 @@ static void isa_enable_dma(dmach_t channel, dma_t *dma)
105 address = dma->buf.dma_address; 97 address = dma->buf.dma_address;
106 length = dma->buf.length - 1; 98 length = dma->buf.length - 1;
107 99
108 outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); 100 outb(address >> 16, isa_dma_port[chan][ISA_DMA_PGLO]);
109 outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); 101 outb(address >> 24, isa_dma_port[chan][ISA_DMA_PGHI]);
110 102
111 if (channel >= 4) { 103 if (chan >= 4) {
112 address >>= 1; 104 address >>= 1;
113 length >>= 1; 105 length >>= 1;
114 } 106 }
115 107
116 outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); 108 outb(0, isa_dma_port[chan][ISA_DMA_CLRFF]);
117
118 outb(address, isa_dma_port[channel][ISA_DMA_ADDR]);
119 outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]);
120 109
121 outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); 110 outb(address, isa_dma_port[chan][ISA_DMA_ADDR]);
122 outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); 111 outb(address >> 8, isa_dma_port[chan][ISA_DMA_ADDR]);
123 112
124 if (dma->dma_mode & DMA_AUTOINIT) 113 outb(length, isa_dma_port[chan][ISA_DMA_COUNT]);
125 mode |= ISA_DMA_AUTOINIT; 114 outb(length >> 8, isa_dma_port[chan][ISA_DMA_COUNT]);
126 115
127 outb(mode, isa_dma_port[channel][ISA_DMA_MODE]); 116 outb(mode, isa_dma_port[chan][ISA_DMA_MODE]);
128 dma->invalid = 0; 117 dma->invalid = 0;
129 } 118 }
130 outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]); 119 outb(chan & 3, isa_dma_port[chan][ISA_DMA_MASK]);
131} 120}
132 121
133static void isa_disable_dma(dmach_t channel, dma_t *dma) 122static void isa_disable_dma(unsigned int chan, dma_t *dma)
134{ 123{
135 outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); 124 outb(chan | 4, isa_dma_port[chan][ISA_DMA_MASK]);
136} 125}
137 126
138static struct dma_ops isa_dma_ops = { 127static struct dma_ops isa_dma_ops = {
@@ -160,7 +149,12 @@ static struct resource dma_resources[] = { {
160 .end = 0x048f 149 .end = 0x048f
161} }; 150} };
162 151
163void __init isa_init_dma(dma_t *dma) 152static dma_t isa_dma[8];
153
154/*
155 * ISA DMA always starts at channel 0
156 */
157void __init isa_init_dma(void)
164{ 158{
165 /* 159 /*
166 * Try to autodetect presence of an ISA DMA controller. 160 * Try to autodetect presence of an ISA DMA controller.
@@ -178,11 +172,11 @@ void __init isa_init_dma(dma_t *dma)
178 outb(0xaa, 0x00); 172 outb(0xaa, 0x00);
179 173
180 if (inb(0) == 0x55 && inb(0) == 0xaa) { 174 if (inb(0) == 0x55 && inb(0) == 0xaa) {
181 int channel, i; 175 unsigned int chan, i;
182 176
183 for (channel = 0; channel < 8; channel++) { 177 for (chan = 0; chan < 8; chan++) {
184 dma[channel].d_ops = &isa_dma_ops; 178 isa_dma[chan].d_ops = &isa_dma_ops;
185 isa_disable_dma(channel, NULL); 179 isa_disable_dma(chan, NULL);
186 } 180 }
187 181
188 outb(0x40, 0x0b); 182 outb(0x40, 0x0b);
@@ -217,5 +211,12 @@ void __init isa_init_dma(dma_t *dma)
217 211
218 for (i = 0; i < ARRAY_SIZE(dma_resources); i++) 212 for (i = 0; i < ARRAY_SIZE(dma_resources); i++)
219 request_resource(&ioport_resource, dma_resources + i); 213 request_resource(&ioport_resource, dma_resources + i);
214
215 for (chan = 0; chan < 8; chan++) {
216 int ret = isa_dma_add(chan, &isa_dma[chan]);
217 if (ret)
218 printk(KERN_ERR "ISADMA%u: unable to register: %d\n",
219 chan, ret);
220 }
220 } 221 }
221} 222}
diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c
index d006085ed7e7..7d5b9fb01e71 100644
--- a/arch/arm/kernel/dma.c
+++ b/arch/arm/kernel/dma.c
@@ -15,6 +15,7 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/spinlock.h> 16#include <linux/spinlock.h>
17#include <linux/errno.h> 17#include <linux/errno.h>
18#include <linux/scatterlist.h>
18 19
19#include <asm/dma.h> 20#include <asm/dma.h>
20 21
@@ -23,19 +24,40 @@
23DEFINE_SPINLOCK(dma_spin_lock); 24DEFINE_SPINLOCK(dma_spin_lock);
24EXPORT_SYMBOL(dma_spin_lock); 25EXPORT_SYMBOL(dma_spin_lock);
25 26
26static dma_t dma_chan[MAX_DMA_CHANNELS]; 27static dma_t *dma_chan[MAX_DMA_CHANNELS];
28
29static inline dma_t *dma_channel(unsigned int chan)
30{
31 if (chan >= MAX_DMA_CHANNELS)
32 return NULL;
33
34 return dma_chan[chan];
35}
36
37int __init isa_dma_add(unsigned int chan, dma_t *dma)
38{
39 if (!dma->d_ops)
40 return -EINVAL;
41
42 sg_init_table(&dma->buf, 1);
43
44 if (dma_chan[chan])
45 return -EBUSY;
46 dma_chan[chan] = dma;
47 return 0;
48}
27 49
28/* 50/*
29 * Request DMA channel 51 * Request DMA channel
30 * 52 *
31 * On certain platforms, we have to allocate an interrupt as well... 53 * On certain platforms, we have to allocate an interrupt as well...
32 */ 54 */
33int request_dma(dmach_t channel, const char *device_id) 55int request_dma(unsigned int chan, const char *device_id)
34{ 56{
35 dma_t *dma = dma_chan + channel; 57 dma_t *dma = dma_channel(chan);
36 int ret; 58 int ret;
37 59
38 if (channel >= MAX_DMA_CHANNELS || !dma->d_ops) 60 if (!dma)
39 goto bad_dma; 61 goto bad_dma;
40 62
41 if (xchg(&dma->lock, 1) != 0) 63 if (xchg(&dma->lock, 1) != 0)
@@ -47,7 +69,7 @@ int request_dma(dmach_t channel, const char *device_id)
47 69
48 ret = 0; 70 ret = 0;
49 if (dma->d_ops->request) 71 if (dma->d_ops->request)
50 ret = dma->d_ops->request(channel, dma); 72 ret = dma->d_ops->request(chan, dma);
51 73
52 if (ret) 74 if (ret)
53 xchg(&dma->lock, 0); 75 xchg(&dma->lock, 0);
@@ -55,7 +77,7 @@ int request_dma(dmach_t channel, const char *device_id)
55 return ret; 77 return ret;
56 78
57bad_dma: 79bad_dma:
58 printk(KERN_ERR "dma: trying to allocate DMA%d\n", channel); 80 printk(KERN_ERR "dma: trying to allocate DMA%d\n", chan);
59 return -EINVAL; 81 return -EINVAL;
60 82
61busy: 83busy:
@@ -68,42 +90,42 @@ EXPORT_SYMBOL(request_dma);
68 * 90 *
69 * On certain platforms, we have to free interrupt as well... 91 * On certain platforms, we have to free interrupt as well...
70 */ 92 */
71void free_dma(dmach_t channel) 93void free_dma(unsigned int chan)
72{ 94{
73 dma_t *dma = dma_chan + channel; 95 dma_t *dma = dma_channel(chan);
74 96
75 if (channel >= MAX_DMA_CHANNELS || !dma->d_ops) 97 if (!dma)
76 goto bad_dma; 98 goto bad_dma;
77 99
78 if (dma->active) { 100 if (dma->active) {
79 printk(KERN_ERR "dma%d: freeing active DMA\n", channel); 101 printk(KERN_ERR "dma%d: freeing active DMA\n", chan);
80 dma->d_ops->disable(channel, dma); 102 dma->d_ops->disable(chan, dma);
81 dma->active = 0; 103 dma->active = 0;
82 } 104 }
83 105
84 if (xchg(&dma->lock, 0) != 0) { 106 if (xchg(&dma->lock, 0) != 0) {
85 if (dma->d_ops->free) 107 if (dma->d_ops->free)
86 dma->d_ops->free(channel, dma); 108 dma->d_ops->free(chan, dma);
87 return; 109 return;
88 } 110 }
89 111
90 printk(KERN_ERR "dma%d: trying to free free DMA\n", channel); 112 printk(KERN_ERR "dma%d: trying to free free DMA\n", chan);
91 return; 113 return;
92 114
93bad_dma: 115bad_dma:
94 printk(KERN_ERR "dma: trying to free DMA%d\n", channel); 116 printk(KERN_ERR "dma: trying to free DMA%d\n", chan);
95} 117}
96EXPORT_SYMBOL(free_dma); 118EXPORT_SYMBOL(free_dma);
97 119
98/* Set DMA Scatter-Gather list 120/* Set DMA Scatter-Gather list
99 */ 121 */
100void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) 122void set_dma_sg (unsigned int chan, struct scatterlist *sg, int nr_sg)
101{ 123{
102 dma_t *dma = dma_chan + channel; 124 dma_t *dma = dma_channel(chan);
103 125
104 if (dma->active) 126 if (dma->active)
105 printk(KERN_ERR "dma%d: altering DMA SG while " 127 printk(KERN_ERR "dma%d: altering DMA SG while "
106 "DMA active\n", channel); 128 "DMA active\n", chan);
107 129
108 dma->sg = sg; 130 dma->sg = sg;
109 dma->sgcount = nr_sg; 131 dma->sgcount = nr_sg;
@@ -115,13 +137,13 @@ EXPORT_SYMBOL(set_dma_sg);
115 * 137 *
116 * Copy address to the structure, and set the invalid bit 138 * Copy address to the structure, and set the invalid bit
117 */ 139 */
118void __set_dma_addr (dmach_t channel, void *addr) 140void __set_dma_addr (unsigned int chan, void *addr)
119{ 141{
120 dma_t *dma = dma_chan + channel; 142 dma_t *dma = dma_channel(chan);
121 143
122 if (dma->active) 144 if (dma->active)
123 printk(KERN_ERR "dma%d: altering DMA address while " 145 printk(KERN_ERR "dma%d: altering DMA address while "
124 "DMA active\n", channel); 146 "DMA active\n", chan);
125 147
126 dma->sg = NULL; 148 dma->sg = NULL;
127 dma->addr = addr; 149 dma->addr = addr;
@@ -133,13 +155,13 @@ EXPORT_SYMBOL(__set_dma_addr);
133 * 155 *
134 * Copy address to the structure, and set the invalid bit 156 * Copy address to the structure, and set the invalid bit
135 */ 157 */
136void set_dma_count (dmach_t channel, unsigned long count) 158void set_dma_count (unsigned int chan, unsigned long count)
137{ 159{
138 dma_t *dma = dma_chan + channel; 160 dma_t *dma = dma_channel(chan);
139 161
140 if (dma->active) 162 if (dma->active)
141 printk(KERN_ERR "dma%d: altering DMA count while " 163 printk(KERN_ERR "dma%d: altering DMA count while "
142 "DMA active\n", channel); 164 "DMA active\n", chan);
143 165
144 dma->sg = NULL; 166 dma->sg = NULL;
145 dma->count = count; 167 dma->count = count;
@@ -149,13 +171,13 @@ EXPORT_SYMBOL(set_dma_count);
149 171
150/* Set DMA direction mode 172/* Set DMA direction mode
151 */ 173 */
152void set_dma_mode (dmach_t channel, dmamode_t mode) 174void set_dma_mode (unsigned int chan, unsigned int mode)
153{ 175{
154 dma_t *dma = dma_chan + channel; 176 dma_t *dma = dma_channel(chan);
155 177
156 if (dma->active) 178 if (dma->active)
157 printk(KERN_ERR "dma%d: altering DMA mode while " 179 printk(KERN_ERR "dma%d: altering DMA mode while "
158 "DMA active\n", channel); 180 "DMA active\n", chan);
159 181
160 dma->dma_mode = mode; 182 dma->dma_mode = mode;
161 dma->invalid = 1; 183 dma->invalid = 1;
@@ -164,42 +186,42 @@ EXPORT_SYMBOL(set_dma_mode);
164 186
165/* Enable DMA channel 187/* Enable DMA channel
166 */ 188 */
167void enable_dma (dmach_t channel) 189void enable_dma (unsigned int chan)
168{ 190{
169 dma_t *dma = dma_chan + channel; 191 dma_t *dma = dma_channel(chan);
170 192
171 if (!dma->lock) 193 if (!dma->lock)
172 goto free_dma; 194 goto free_dma;
173 195
174 if (dma->active == 0) { 196 if (dma->active == 0) {
175 dma->active = 1; 197 dma->active = 1;
176 dma->d_ops->enable(channel, dma); 198 dma->d_ops->enable(chan, dma);
177 } 199 }
178 return; 200 return;
179 201
180free_dma: 202free_dma:
181 printk(KERN_ERR "dma%d: trying to enable free DMA\n", channel); 203 printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan);
182 BUG(); 204 BUG();
183} 205}
184EXPORT_SYMBOL(enable_dma); 206EXPORT_SYMBOL(enable_dma);
185 207
186/* Disable DMA channel 208/* Disable DMA channel
187 */ 209 */
188void disable_dma (dmach_t channel) 210void disable_dma (unsigned int chan)
189{ 211{
190 dma_t *dma = dma_chan + channel; 212 dma_t *dma = dma_channel(chan);
191 213
192 if (!dma->lock) 214 if (!dma->lock)
193 goto free_dma; 215 goto free_dma;
194 216
195 if (dma->active == 1) { 217 if (dma->active == 1) {
196 dma->active = 0; 218 dma->active = 0;
197 dma->d_ops->disable(channel, dma); 219 dma->d_ops->disable(chan, dma);
198 } 220 }
199 return; 221 return;
200 222
201free_dma: 223free_dma:
202 printk(KERN_ERR "dma%d: trying to disable free DMA\n", channel); 224 printk(KERN_ERR "dma%d: trying to disable free DMA\n", chan);
203 BUG(); 225 BUG();
204} 226}
205EXPORT_SYMBOL(disable_dma); 227EXPORT_SYMBOL(disable_dma);
@@ -207,45 +229,38 @@ EXPORT_SYMBOL(disable_dma);
207/* 229/*
208 * Is the specified DMA channel active? 230 * Is the specified DMA channel active?
209 */ 231 */
210int dma_channel_active(dmach_t channel) 232int dma_channel_active(unsigned int chan)
211{ 233{
212 return dma_chan[channel].active; 234 dma_t *dma = dma_channel(chan);
235 return dma->active;
213} 236}
214EXPORT_SYMBOL(dma_channel_active); 237EXPORT_SYMBOL(dma_channel_active);
215 238
216void set_dma_page(dmach_t channel, char pagenr) 239void set_dma_page(unsigned int chan, char pagenr)
217{ 240{
218 printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel); 241 printk(KERN_ERR "dma%d: trying to set_dma_page\n", chan);
219} 242}
220EXPORT_SYMBOL(set_dma_page); 243EXPORT_SYMBOL(set_dma_page);
221 244
222void set_dma_speed(dmach_t channel, int cycle_ns) 245void set_dma_speed(unsigned int chan, int cycle_ns)
223{ 246{
224 dma_t *dma = dma_chan + channel; 247 dma_t *dma = dma_channel(chan);
225 int ret = 0; 248 int ret = 0;
226 249
227 if (dma->d_ops->setspeed) 250 if (dma->d_ops->setspeed)
228 ret = dma->d_ops->setspeed(channel, dma, cycle_ns); 251 ret = dma->d_ops->setspeed(chan, dma, cycle_ns);
229 dma->speed = ret; 252 dma->speed = ret;
230} 253}
231EXPORT_SYMBOL(set_dma_speed); 254EXPORT_SYMBOL(set_dma_speed);
232 255
233int get_dma_residue(dmach_t channel) 256int get_dma_residue(unsigned int chan)
234{ 257{
235 dma_t *dma = dma_chan + channel; 258 dma_t *dma = dma_channel(chan);
236 int ret = 0; 259 int ret = 0;
237 260
238 if (dma->d_ops->residue) 261 if (dma->d_ops->residue)
239 ret = dma->d_ops->residue(channel, dma); 262 ret = dma->d_ops->residue(chan, dma);
240 263
241 return ret; 264 return ret;
242} 265}
243EXPORT_SYMBOL(get_dma_residue); 266EXPORT_SYMBOL(get_dma_residue);
244
245static int __init init_dma(void)
246{
247 arch_dma_init(dma_chan);
248 return 0;
249}
250
251core_initcall(init_dma);