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