master
c 427 lines 12.7 KB
Raw
1 /*
2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
3 *
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
6 */
7
8 #include "qemu/osdep.h"
9 #include "qapi/error.h"
10 #include "hw/dma/bcm2835_dma.h"
11 #include "hw/core/irq.h"
12 #include "migration/vmstate.h"
13 #include "qemu/log.h"
14 #include "qemu/module.h"
15
16 /* DMA CS Control and Status bits */
17 #define BCM2708_DMA_ACTIVE (1 << 0)
18 #define BCM2708_DMA_END (1 << 1) /* GE */
19 #define BCM2708_DMA_INT (1 << 2)
20 #define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */
21 #define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */
22 #define BCM2708_DMA_ERR (1 << 8)
23 #define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */
24 #define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */
25
26 /* DMA control block "info" field bits */
27 #define BCM2708_DMA_INT_EN (1 << 0)
28 #define BCM2708_DMA_TDMODE (1 << 1)
29 #define BCM2708_DMA_WAIT_RESP (1 << 3)
30 #define BCM2708_DMA_D_INC (1 << 4)
31 #define BCM2708_DMA_D_WIDTH (1 << 5)
32 #define BCM2708_DMA_D_DREQ (1 << 6)
33 #define BCM2708_DMA_D_IGNORE (1 << 7)
34 #define BCM2708_DMA_S_INC (1 << 8)
35 #define BCM2708_DMA_S_WIDTH (1 << 9)
36 #define BCM2708_DMA_S_DREQ (1 << 10)
37 #define BCM2708_DMA_S_IGNORE (1 << 11)
38
39 /* Register offsets */
40 #define BCM2708_DMA_CS 0x00 /* Control and Status */
41 #define BCM2708_DMA_ADDR 0x04 /* Control block address */
42 /* the current control block appears in the following registers - read only */
43 #define BCM2708_DMA_INFO 0x08
44 #define BCM2708_DMA_SOURCE_AD 0x0c
45 #define BCM2708_DMA_DEST_AD 0x10
46 #define BCM2708_DMA_TXFR_LEN 0x14
47 #define BCM2708_DMA_STRIDE 0x18
48 #define BCM2708_DMA_NEXTCB 0x1C
49 #define BCM2708_DMA_DEBUG 0x20
50
51 #define BCM2708_DMA_INT_STATUS 0xfe0 /* Interrupt status of each channel */
52 #define BCM2708_DMA_ENABLE 0xff0 /* Global enable bits for each channel */
53
54 #define BCM2708_DMA_CS_RW_MASK 0x30ff0001 /* All RW bits in DMA_CS */
55
56 static void bcm2835_dma_update(BCM2835DMAState *s, unsigned c)
57 {
58 BCM2835DMAChan *ch = &s->chan[c];
59 uint32_t data, xlen, xlen_td, ylen;
60 int16_t dst_stride, src_stride;
61
62 if (!(s->enable & (1 << c))) {
63 return;
64 }
65
66 while ((s->enable & (1 << c)) && (ch->conblk_ad != 0)) {
67 /* CB fetch */
68 ch->ti = ldl_le_phys(&s->dma_as, ch->conblk_ad);
69 ch->source_ad = ldl_le_phys(&s->dma_as, ch->conblk_ad + 4);
70 ch->dest_ad = ldl_le_phys(&s->dma_as, ch->conblk_ad + 8);
71 ch->txfr_len = ldl_le_phys(&s->dma_as, ch->conblk_ad + 12);
72 ch->stride = ldl_le_phys(&s->dma_as, ch->conblk_ad + 16);
73 ch->nextconbk = ldl_le_phys(&s->dma_as, ch->conblk_ad + 20);
74
75 ylen = 1;
76 if (ch->ti & BCM2708_DMA_TDMODE) {
77 /* 2D transfer mode */
78 ylen += (ch->txfr_len >> 16) & 0x3fff;
79 xlen = ch->txfr_len & 0xffff;
80 dst_stride = ch->stride >> 16;
81 src_stride = ch->stride & 0xffff;
82 } else {
83 xlen = ch->txfr_len;
84 dst_stride = 0;
85 src_stride = 0;
86 }
87 xlen_td = xlen;
88
89 if (ch->ti & BCM2708_DMA_D_WIDTH) {
90 qemu_log_mask(LOG_UNIMP, "%s: 128bit transfers not yet supported", __func__);
91 ch->cs |= BCM2708_DMA_ERR;
92 break;
93 }
94
95 /*
96 * Datasheet implies 32bit or 128bit transfers only
97 *
98 * TODO: test on real HW and report back.
99 */
100 if (xlen & 0x3) {
101 qemu_log_mask(LOG_GUEST_ERROR, "%s: bad transfer size\n", __func__);
102 ch->cs |= BCM2708_DMA_ERR;
103 break;
104 }
105
106 while (ylen != 0) {
107 /* Normal transfer mode */
108 while (xlen != 0) {
109 if (ch->ti & BCM2708_DMA_S_IGNORE) {
110 /* Ignore reads */
111 data = 0;
112 } else {
113 data = ldl_le_phys(&s->dma_as, ch->source_ad);
114 }
115 if (ch->ti & BCM2708_DMA_S_INC) {
116 ch->source_ad += 4;
117 }
118
119 if (ch->ti & BCM2708_DMA_D_IGNORE) {
120 /* Ignore writes */
121 } else {
122 stl_le_phys(&s->dma_as, ch->dest_ad, data);
123 }
124 if (ch->ti & BCM2708_DMA_D_INC) {
125 ch->dest_ad += 4;
126 }
127
128 /* update remaining transfer length */
129 xlen -= 4;
130 if (ch->ti & BCM2708_DMA_TDMODE) {
131 ch->txfr_len = (ylen << 16) | xlen;
132 } else {
133 ch->txfr_len = xlen;
134 }
135 }
136
137 if (--ylen != 0) {
138 ch->source_ad += src_stride;
139 ch->dest_ad += dst_stride;
140 xlen = xlen_td;
141 }
142 }
143 ch->cs |= BCM2708_DMA_END;
144 if (ch->ti & BCM2708_DMA_INT_EN) {
145 ch->cs |= BCM2708_DMA_INT;
146 s->int_status |= (1 << c);
147 qemu_set_irq(ch->irq, 1);
148 }
149
150 /* Process next CB */
151 ch->conblk_ad = ch->nextconbk;
152 }
153
154 ch->cs &= ~BCM2708_DMA_ACTIVE;
155 ch->cs |= BCM2708_DMA_ISPAUSED;
156 }
157
158 static void bcm2835_dma_chan_reset(BCM2835DMAChan *ch)
159 {
160 ch->cs = 0;
161 ch->conblk_ad = 0;
162 }
163
164 static uint64_t bcm2835_dma_read(BCM2835DMAState *s, hwaddr offset,
165 unsigned size, unsigned c)
166 {
167 BCM2835DMAChan *ch;
168 uint32_t res = 0;
169
170 assert(size == 4);
171 assert(c < BCM2835_DMA_NCHANS);
172
173 ch = &s->chan[c];
174
175 switch (offset) {
176 case BCM2708_DMA_CS:
177 res = ch->cs;
178 break;
179 case BCM2708_DMA_ADDR:
180 res = ch->conblk_ad;
181 break;
182 case BCM2708_DMA_INFO:
183 res = ch->ti;
184 break;
185 case BCM2708_DMA_SOURCE_AD:
186 res = ch->source_ad;
187 break;
188 case BCM2708_DMA_DEST_AD:
189 res = ch->dest_ad;
190 break;
191 case BCM2708_DMA_TXFR_LEN:
192 res = ch->txfr_len;
193 break;
194 case BCM2708_DMA_STRIDE:
195 res = ch->stride;
196 break;
197 case BCM2708_DMA_NEXTCB:
198 res = ch->nextconbk;
199 break;
200 case BCM2708_DMA_DEBUG:
201 res = ch->debug;
202 break;
203 default:
204 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
205 __func__, offset);
206 break;
207 }
208 return res;
209 }
210
211 static void bcm2835_dma_write(BCM2835DMAState *s, hwaddr offset,
212 uint64_t value, unsigned size, unsigned c)
213 {
214 BCM2835DMAChan *ch;
215 uint32_t oldcs;
216
217 assert(size == 4);
218 assert(c < BCM2835_DMA_NCHANS);
219
220 ch = &s->chan[c];
221
222 switch (offset) {
223 case BCM2708_DMA_CS:
224 oldcs = ch->cs;
225 if (value & BCM2708_DMA_RESET) {
226 bcm2835_dma_chan_reset(ch);
227 }
228 if (value & BCM2708_DMA_ABORT) {
229 /* abort is a no-op, since we always run to completion */
230 }
231 if (value & BCM2708_DMA_END) {
232 ch->cs &= ~BCM2708_DMA_END;
233 }
234 if (value & BCM2708_DMA_INT) {
235 ch->cs &= ~BCM2708_DMA_INT;
236 s->int_status &= ~(1 << c);
237 qemu_set_irq(ch->irq, 0);
238 }
239 ch->cs &= ~BCM2708_DMA_CS_RW_MASK;
240 ch->cs |= (value & BCM2708_DMA_CS_RW_MASK);
241 if (!(oldcs & BCM2708_DMA_ACTIVE) && (ch->cs & BCM2708_DMA_ACTIVE)) {
242 bcm2835_dma_update(s, c);
243 }
244 break;
245 case BCM2708_DMA_ADDR:
246 ch->conblk_ad = value;
247 break;
248 case BCM2708_DMA_DEBUG:
249 ch->debug = value;
250 break;
251 default:
252 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
253 __func__, offset);
254 break;
255 }
256 }
257
258 static uint64_t bcm2835_dma0_read(void *opaque, hwaddr offset, unsigned size)
259 {
260 BCM2835DMAState *s = opaque;
261
262 if (offset < 0xf00) {
263 return bcm2835_dma_read(s, (offset & 0xff), size, (offset >> 8) & 0xf);
264 } else {
265 switch (offset) {
266 case BCM2708_DMA_INT_STATUS:
267 return s->int_status;
268 case BCM2708_DMA_ENABLE:
269 return s->enable;
270 default:
271 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
272 __func__, offset);
273 return 0;
274 }
275 }
276 }
277
278 static uint64_t bcm2835_dma15_read(void *opaque, hwaddr offset, unsigned size)
279 {
280 return bcm2835_dma_read(opaque, (offset & 0xff), size, 15);
281 }
282
283 static void bcm2835_dma0_write(void *opaque, hwaddr offset, uint64_t value,
284 unsigned size)
285 {
286 BCM2835DMAState *s = opaque;
287
288 if (offset < 0xf00) {
289 bcm2835_dma_write(s, (offset & 0xff), value, size, (offset >> 8) & 0xf);
290 } else {
291 switch (offset) {
292 case BCM2708_DMA_INT_STATUS:
293 break;
294 case BCM2708_DMA_ENABLE:
295 s->enable = (value & 0xffff);
296 break;
297 default:
298 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
299 __func__, offset);
300 }
301 }
302
303 }
304
305 static void bcm2835_dma15_write(void *opaque, hwaddr offset, uint64_t value,
306 unsigned size)
307 {
308 bcm2835_dma_write(opaque, (offset & 0xff), value, size, 15);
309 }
310
311 static const MemoryRegionOps bcm2835_dma0_ops = {
312 .read = bcm2835_dma0_read,
313 .write = bcm2835_dma0_write,
314 .endianness = DEVICE_NATIVE_ENDIAN,
315 .valid.min_access_size = 4,
316 .valid.max_access_size = 4,
317 };
318
319 static const MemoryRegionOps bcm2835_dma15_ops = {
320 .read = bcm2835_dma15_read,
321 .write = bcm2835_dma15_write,
322 .endianness = DEVICE_NATIVE_ENDIAN,
323 .valid.min_access_size = 4,
324 .valid.max_access_size = 4,
325 };
326
327 static const VMStateDescription vmstate_bcm2835_dma_chan = {
328 .name = TYPE_BCM2835_DMA "-chan",
329 .version_id = 1,
330 .minimum_version_id = 1,
331 .fields = (const VMStateField[]) {
332 VMSTATE_UINT32(cs, BCM2835DMAChan),
333 VMSTATE_UINT32(conblk_ad, BCM2835DMAChan),
334 VMSTATE_UINT32(ti, BCM2835DMAChan),
335 VMSTATE_UINT32(source_ad, BCM2835DMAChan),
336 VMSTATE_UINT32(dest_ad, BCM2835DMAChan),
337 VMSTATE_UINT32(txfr_len, BCM2835DMAChan),
338 VMSTATE_UINT32(stride, BCM2835DMAChan),
339 VMSTATE_UINT32(nextconbk, BCM2835DMAChan),
340 VMSTATE_UINT32(debug, BCM2835DMAChan),
341 VMSTATE_END_OF_LIST()
342 }
343 };
344
345 static const VMStateDescription vmstate_bcm2835_dma = {
346 .name = TYPE_BCM2835_DMA,
347 .version_id = 1,
348 .minimum_version_id = 1,
349 .fields = (const VMStateField[]) {
350 VMSTATE_STRUCT_ARRAY(chan, BCM2835DMAState, BCM2835_DMA_NCHANS, 1,
351 vmstate_bcm2835_dma_chan, BCM2835DMAChan),
352 VMSTATE_UINT32(int_status, BCM2835DMAState),
353 VMSTATE_UINT32(enable, BCM2835DMAState),
354 VMSTATE_END_OF_LIST()
355 }
356 };
357
358 static void bcm2835_dma_init(Object *obj)
359 {
360 BCM2835DMAState *s = BCM2835_DMA(obj);
361 int n;
362
363 /* DMA channels 0-14 occupy a contiguous block of IO memory, along
364 * with the global enable and interrupt status bits. Channel 15
365 * has the same register map, but is mapped at a discontiguous
366 * address in a separate IO block.
367 */
368 memory_region_init_io(&s->iomem0, OBJECT(s), &bcm2835_dma0_ops, s,
369 TYPE_BCM2835_DMA, 0x1000);
370 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem0);
371
372 memory_region_init_io(&s->iomem15, OBJECT(s), &bcm2835_dma15_ops, s,
373 TYPE_BCM2835_DMA "-chan15", 0x100);
374 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem15);
375
376 for (n = 0; n < 16; n++) {
377 sysbus_init_irq(SYS_BUS_DEVICE(s), &s->chan[n].irq);
378 }
379 }
380
381 static void bcm2835_dma_reset(DeviceState *dev)
382 {
383 BCM2835DMAState *s = BCM2835_DMA(dev);
384 int n;
385
386 s->enable = 0xffff;
387 s->int_status = 0;
388 for (n = 0; n < BCM2835_DMA_NCHANS; n++) {
389 bcm2835_dma_chan_reset(&s->chan[n]);
390 }
391 }
392
393 static void bcm2835_dma_realize(DeviceState *dev, Error **errp)
394 {
395 BCM2835DMAState *s = BCM2835_DMA(dev);
396 Object *obj;
397
398 obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort);
399 s->dma_mr = MEMORY_REGION(obj);
400 address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_DMA "-memory");
401
402 bcm2835_dma_reset(dev);
403 }
404
405 static void bcm2835_dma_class_init(ObjectClass *klass, const void *data)
406 {
407 DeviceClass *dc = DEVICE_CLASS(klass);
408
409 dc->realize = bcm2835_dma_realize;
410 device_class_set_legacy_reset(dc, bcm2835_dma_reset);
411 dc->vmsd = &vmstate_bcm2835_dma;
412 }
413
414 static const TypeInfo bcm2835_dma_info = {
415 .name = TYPE_BCM2835_DMA,
416 .parent = TYPE_SYS_BUS_DEVICE,
417 .instance_size = sizeof(BCM2835DMAState),
418 .class_init = bcm2835_dma_class_init,
419 .instance_init = bcm2835_dma_init,
420 };
421
422 static void bcm2835_dma_register_types(void)
423 {
424 type_register_static(&bcm2835_dma_info);
425 }
426
427 type_init(bcm2835_dma_register_types)