Revision e69954b9 hw/pl080.c
b/hw/pl080.c | ||
---|---|---|
1 | 1 |
/* |
2 |
* Arm PrimeCell PL080 DMA controller |
|
2 |
* Arm PrimeCell PL080/PL081 DMA controller
|
|
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2006 CodeSourcery. |
5 | 5 |
* Written by Paul Brook |
... | ... | |
9 | 9 |
|
10 | 10 |
#include "vl.h" |
11 | 11 |
|
12 |
#define PL080_NUM_CHANNELS 8
|
|
12 |
#define PL080_MAX_CHANNELS 8
|
|
13 | 13 |
#define PL080_CONF_E 0x1 |
14 | 14 |
#define PL080_CONF_M1 0x2 |
15 | 15 |
#define PL080_CONF_M2 0x4 |
... | ... | |
45 | 45 |
uint32_t sync; |
46 | 46 |
uint32_t req_single; |
47 | 47 |
uint32_t req_burst; |
48 |
pl080_channel chan[PL080_NUM_CHANNELS]; |
|
48 |
pl080_channel chan[PL080_MAX_CHANNELS]; |
|
49 |
int nchannels; |
|
49 | 50 |
/* Flag to avoid recursive DMA invocations. */ |
50 | 51 |
int running; |
51 | 52 |
void *pic; |
... | ... | |
55 | 56 |
static const unsigned char pl080_id[] = |
56 | 57 |
{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; |
57 | 58 |
|
59 |
static const unsigned char pl081_id[] = |
|
60 |
{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; |
|
61 |
|
|
58 | 62 |
static void pl080_update(pl080_state *s) |
59 | 63 |
{ |
60 | 64 |
if ((s->tc_int & s->tc_mask) |
... | ... | |
80 | 84 |
uint32_t req; |
81 | 85 |
|
82 | 86 |
s->tc_mask = 0; |
83 |
for (c = 0; c < PL080_NUM_CHANNELS; c++) {
|
|
87 |
for (c = 0; c < s->nchannels; c++) {
|
|
84 | 88 |
if (s->chan[c].conf & PL080_CCONF_ITC) |
85 | 89 |
s->tc_mask |= 1 << c; |
86 | 90 |
if (s->chan[c].conf & PL080_CCONF_IE) |
... | ... | |
99 | 103 |
} |
100 | 104 |
s->running = 1; |
101 | 105 |
while (s->running) { |
102 |
for (c = 0; c < PL080_NUM_CHANNELS; c++) {
|
|
106 |
for (c = 0; c < s->nchannels; c++) {
|
|
103 | 107 |
ch = &s->chan[c]; |
104 | 108 |
again: |
105 | 109 |
/* Test if thiws channel has any pending DMA requests. */ |
... | ... | |
185 | 189 |
|
186 | 190 |
offset -= s->base; |
187 | 191 |
if (offset >= 0xfe0 && offset < 0x1000) { |
188 |
return pl080_id[(offset - 0xfe0) >> 2]; |
|
192 |
if (s->nchannels == 8) { |
|
193 |
return pl080_id[(offset - 0xfe0) >> 2]; |
|
194 |
} else { |
|
195 |
return pl081_id[(offset - 0xfe0) >> 2]; |
|
196 |
} |
|
189 | 197 |
} |
190 | 198 |
if (offset >= 0x100 && offset < 0x200) { |
191 | 199 |
i = (offset & 0xe0) >> 5; |
200 |
if (i >= s->nchannels) |
|
201 |
goto bad_offset; |
|
192 | 202 |
switch (offset >> 2) { |
193 | 203 |
case 0: /* SrcAddr */ |
194 | 204 |
return s->chan[i].src; |
... | ... | |
217 | 227 |
return s->err_int; |
218 | 228 |
case 7: /* EnbldChns */ |
219 | 229 |
mask = 0; |
220 |
for (i = 0; i < PL080_NUM_CHANNELS; i++) {
|
|
230 |
for (i = 0; i < s->nchannels; i++) {
|
|
221 | 231 |
if (s->chan[i].conf & PL080_CCONF_E) |
222 | 232 |
mask |= 1 << i; |
223 | 233 |
} |
... | ... | |
248 | 258 |
offset -= s->base; |
249 | 259 |
if (offset >= 0x100 && offset < 0x200) { |
250 | 260 |
i = (offset & 0xe0) >> 5; |
261 |
if (i >= s->nchannels) |
|
262 |
goto bad_offset; |
|
251 | 263 |
switch (offset >> 2) { |
252 | 264 |
case 0: /* SrcAddr */ |
253 | 265 |
s->chan[i].src = value; |
... | ... | |
293 | 305 |
s->sync = value; |
294 | 306 |
break; |
295 | 307 |
default: |
308 |
bad_offset: |
|
296 | 309 |
cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset); |
297 | 310 |
} |
298 | 311 |
pl080_update(s); |
... | ... | |
310 | 323 |
pl080_write |
311 | 324 |
}; |
312 | 325 |
|
313 |
void *pl080_init(uint32_t base, void *pic, int irq) |
|
326 |
/* The PL080 and PL081 are the same except for the number of channels |
|
327 |
they implement (8 and 2 respectively). */ |
|
328 |
void *pl080_init(uint32_t base, void *pic, int irq, int nchannels) |
|
314 | 329 |
{ |
315 | 330 |
int iomemtype; |
316 | 331 |
pl080_state *s; |
... | ... | |
322 | 337 |
s->base = base; |
323 | 338 |
s->pic = pic; |
324 | 339 |
s->irq = irq; |
340 |
s->nchannels = nchannels; |
|
325 | 341 |
/* ??? Save/restore. */ |
326 | 342 |
return s; |
327 | 343 |
} |
Also available in: Unified diff