1 /* 2 * Arm PrimeCell PL041 Advanced Audio Codec Interface 3 * 4 * Copyright (c) 2011 5 * Written by Mathieu Sonet - www.elasticsheep.com 6 * 7 * This code is licensed under the GPL. 8 * 9 * ***************************************************************** 10 * 11 * This driver emulates the ARM AACI interface 12 * connected to a LM4549 codec. 13 * 14 * Limitations: 15 * - Supports only a playback on one channel (Versatile/Vexpress) 16 * - Supports only one TX FIFO in compact-mode or non-compact mode. 17 * - Supports playback of 12, 16, 18 and 20 bits samples. 18 * - Record is not supported. 19 * - The PL041 is hardwired to a LM4549 codec. 20 * 21 */ 22 23 #include "qemu/osdep.h" 24 #include "hw/sysbus.h" 25 #include "qemu/log.h" 26 27 #include "pl041.h" 28 #include "lm4549.h" 29 30 #if 0 31 #define PL041_DEBUG_LEVEL 1 32 #endif 33 34 #if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 1) 35 #define DBG_L1(fmt, ...) \ 36 do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0) 37 #else 38 #define DBG_L1(fmt, ...) \ 39 do { } while (0) 40 #endif 41 42 #if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 2) 43 #define DBG_L2(fmt, ...) \ 44 do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0) 45 #else 46 #define DBG_L2(fmt, ...) \ 47 do { } while (0) 48 #endif 49 50 51 #define MAX_FIFO_DEPTH (1024) 52 #define DEFAULT_FIFO_DEPTH (8) 53 54 #define SLOT1_RW (1 << 19) 55 56 /* This FIFO only stores 20-bit samples on 32-bit words. 57 So its level is independent of the selected mode */ 58 typedef struct { 59 uint32_t level; 60 uint32_t data[MAX_FIFO_DEPTH]; 61 } pl041_fifo; 62 63 typedef struct { 64 pl041_fifo tx_fifo; 65 uint8_t tx_enabled; 66 uint8_t tx_compact_mode; 67 uint8_t tx_sample_size; 68 69 pl041_fifo rx_fifo; 70 uint8_t rx_enabled; 71 uint8_t rx_compact_mode; 72 uint8_t rx_sample_size; 73 } pl041_channel; 74 75 #define TYPE_PL041 "pl041" 76 #define PL041(obj) OBJECT_CHECK(PL041State, (obj), TYPE_PL041) 77 78 typedef struct PL041State { 79 SysBusDevice parent_obj; 80 81 MemoryRegion iomem; 82 qemu_irq irq; 83 84 uint32_t fifo_depth; /* FIFO depth in non-compact mode */ 85 86 pl041_regfile regs; 87 pl041_channel fifo1; 88 lm4549_state codec; 89 } PL041State; 90 91 92 static const unsigned char pl041_default_id[8] = { 93 0x41, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 94 }; 95 96 #if defined(PL041_DEBUG_LEVEL) 97 #define REGISTER(name, offset) #name, 98 static const char *pl041_regs_name[] = { 99 #include "pl041.hx" 100 }; 101 #undef REGISTER 102 #endif 103 104 105 #if defined(PL041_DEBUG_LEVEL) 106 static const char *get_reg_name(hwaddr offset) 107 { 108 if (offset <= PL041_dr1_7) { 109 return pl041_regs_name[offset >> 2]; 110 } 111 112 return "unknown"; 113 } 114 #endif 115 116 static uint8_t pl041_compute_periphid3(PL041State *s) 117 { 118 uint8_t id3 = 1; /* One channel */ 119 120 /* Add the fifo depth information */ 121 switch (s->fifo_depth) { 122 case 8: 123 id3 |= 0 << 3; 124 break; 125 case 32: 126 id3 |= 1 << 3; 127 break; 128 case 64: 129 id3 |= 2 << 3; 130 break; 131 case 128: 132 id3 |= 3 << 3; 133 break; 134 case 256: 135 id3 |= 4 << 3; 136 break; 137 case 512: 138 id3 |= 5 << 3; 139 break; 140 case 1024: 141 id3 |= 6 << 3; 142 break; 143 case 2048: 144 id3 |= 7 << 3; 145 break; 146 } 147 148 return id3; 149 } 150 151 static void pl041_reset(PL041State *s) 152 { 153 DBG_L1("pl041_reset\n"); 154 155 memset(&s->regs, 0x00, sizeof(pl041_regfile)); 156 157 s->regs.slfr = SL1TXEMPTY | SL2TXEMPTY | SL12TXEMPTY; 158 s->regs.sr1 = TXFE | RXFE | TXHE; 159 s->regs.isr1 = 0; 160 161 memset(&s->fifo1, 0x00, sizeof(s->fifo1)); 162 } 163 164 165 static void pl041_fifo1_write(PL041State *s, uint32_t value) 166 { 167 pl041_channel *channel = &s->fifo1; 168 pl041_fifo *fifo = &s->fifo1.tx_fifo; 169 170 /* Push the value in the FIFO */ 171 if (channel->tx_compact_mode == 0) { 172 /* Non-compact mode */ 173 174 if (fifo->level < s->fifo_depth) { 175 /* Pad the value with 0 to obtain a 20-bit sample */ 176 switch (channel->tx_sample_size) { 177 case 12: 178 value = (value << 8) & 0xFFFFF; 179 break; 180 case 16: 181 value = (value << 4) & 0xFFFFF; 182 break; 183 case 18: 184 value = (value << 2) & 0xFFFFF; 185 break; 186 case 20: 187 default: 188 break; 189 } 190 191 /* Store the sample in the FIFO */ 192 fifo->data[fifo->level++] = value; 193 } 194 #if defined(PL041_DEBUG_LEVEL) 195 else { 196 DBG_L1("fifo1 write: overrun\n"); 197 } 198 #endif 199 } else { 200 /* Compact mode */ 201 202 if ((fifo->level + 2) < s->fifo_depth) { 203 uint32_t i = 0; 204 uint32_t sample = 0; 205 206 for (i = 0; i < 2; i++) { 207 sample = value & 0xFFFF; 208 value = value >> 16; 209 210 /* Pad each sample with 0 to obtain a 20-bit sample */ 211 switch (channel->tx_sample_size) { 212 case 12: 213 sample = sample << 8; 214 break; 215 case 16: 216 default: 217 sample = sample << 4; 218 break; 219 } 220 221 /* Store the sample in the FIFO */ 222 fifo->data[fifo->level++] = sample; 223 } 224 } 225 #if defined(PL041_DEBUG_LEVEL) 226 else { 227 DBG_L1("fifo1 write: overrun\n"); 228 } 229 #endif 230 } 231 232 /* Update the status register */ 233 if (fifo->level > 0) { 234 s->regs.sr1 &= ~(TXUNDERRUN | TXFE); 235 } 236 237 if (fifo->level >= (s->fifo_depth / 2)) { 238 s->regs.sr1 &= ~TXHE; 239 } 240 241 if (fifo->level >= s->fifo_depth) { 242 s->regs.sr1 |= TXFF; 243 } 244 245 DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1); 246 } 247 248 static void pl041_fifo1_transmit(PL041State *s) 249 { 250 pl041_channel *channel = &s->fifo1; 251 pl041_fifo *fifo = &s->fifo1.tx_fifo; 252 uint32_t slots = s->regs.txcr1 & TXSLOT_MASK; 253 uint32_t written_samples; 254 255 /* Check if FIFO1 transmit is enabled */ 256 if ((channel->tx_enabled) && (slots & (TXSLOT3 | TXSLOT4))) { 257 if (fifo->level >= (s->fifo_depth / 2)) { 258 int i; 259 260 DBG_L1("Transfer FIFO level = %i\n", fifo->level); 261 262 /* Try to transfer the whole FIFO */ 263 for (i = 0; i < (fifo->level / 2); i++) { 264 uint32_t left = fifo->data[i * 2]; 265 uint32_t right = fifo->data[i * 2 + 1]; 266 267 /* Transmit two 20-bit samples to the codec */ 268 if (lm4549_write_samples(&s->codec, left, right) == 0) { 269 DBG_L1("Codec buffer full\n"); 270 break; 271 } 272 } 273 274 written_samples = i * 2; 275 if (written_samples > 0) { 276 /* Update the FIFO level */ 277 fifo->level -= written_samples; 278 279 /* Move back the pending samples to the start of the FIFO */ 280 for (i = 0; i < fifo->level; i++) { 281 fifo->data[i] = fifo->data[written_samples + i]; 282 } 283 284 /* Update the status register */ 285 s->regs.sr1 &= ~TXFF; 286 287 if (fifo->level <= (s->fifo_depth / 2)) { 288 s->regs.sr1 |= TXHE; 289 } 290 291 if (fifo->level == 0) { 292 s->regs.sr1 |= TXFE | TXUNDERRUN; 293 DBG_L1("Empty FIFO\n"); 294 } 295 } 296 } 297 } 298 } 299 300 static void pl041_isr1_update(PL041State *s) 301 { 302 /* Update ISR1 */ 303 if (s->regs.sr1 & TXUNDERRUN) { 304 s->regs.isr1 |= URINTR; 305 } else { 306 s->regs.isr1 &= ~URINTR; 307 } 308 309 if (s->regs.sr1 & TXHE) { 310 s->regs.isr1 |= TXINTR; 311 } else { 312 s->regs.isr1 &= ~TXINTR; 313 } 314 315 if (!(s->regs.sr1 & TXBUSY) && (s->regs.sr1 & TXFE)) { 316 s->regs.isr1 |= TXCINTR; 317 } else { 318 s->regs.isr1 &= ~TXCINTR; 319 } 320 321 /* Update the irq state */ 322 qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0); 323 DBG_L2("Set interrupt sr1 = 0x%08x isr1 = 0x%08x masked = 0x%08x\n", 324 s->regs.sr1, s->regs.isr1, s->regs.isr1 & s->regs.ie1); 325 } 326 327 static void pl041_request_data(void *opaque) 328 { 329 PL041State *s = (PL041State *)opaque; 330 331 /* Trigger pending transfers */ 332 pl041_fifo1_transmit(s); 333 pl041_isr1_update(s); 334 } 335 336 static uint64_t pl041_read(void *opaque, hwaddr offset, 337 unsigned size) 338 { 339 PL041State *s = (PL041State *)opaque; 340 int value; 341 342 if ((offset >= PL041_periphid0) && (offset <= PL041_pcellid3)) { 343 if (offset == PL041_periphid3) { 344 value = pl041_compute_periphid3(s); 345 } else { 346 value = pl041_default_id[(offset - PL041_periphid0) >> 2]; 347 } 348 349 DBG_L1("pl041_read [0x%08x] => 0x%08x\n", offset, value); 350 return value; 351 } else if (offset <= PL041_dr4_7) { 352 value = *((uint32_t *)&s->regs + (offset >> 2)); 353 } else { 354 DBG_L1("pl041_read: Reserved offset %x\n", (int)offset); 355 return 0; 356 } 357 358 switch (offset) { 359 case PL041_allints: 360 value = s->regs.isr1 & 0x7F; 361 break; 362 } 363 364 DBG_L1("pl041_read [0x%08x] %s => 0x%08x\n", offset, 365 get_reg_name(offset), value); 366 367 return value; 368 } 369 370 static void pl041_write(void *opaque, hwaddr offset, 371 uint64_t value, unsigned size) 372 { 373 PL041State *s = (PL041State *)opaque; 374 uint16_t control, data; 375 uint32_t result; 376 377 DBG_L1("pl041_write [0x%08x] %s <= 0x%08x\n", offset, 378 get_reg_name(offset), (unsigned int)value); 379 380 /* Write the register */ 381 if (offset <= PL041_dr4_7) { 382 *((uint32_t *)&s->regs + (offset >> 2)) = value; 383 } else { 384 DBG_L1("pl041_write: Reserved offset %x\n", (int)offset); 385 return; 386 } 387 388 /* Execute the actions */ 389 switch (offset) { 390 case PL041_txcr1: 391 { 392 pl041_channel *channel = &s->fifo1; 393 394 uint32_t txen = s->regs.txcr1 & TXEN; 395 uint32_t tsize = (s->regs.txcr1 & TSIZE_MASK) >> TSIZE_MASK_BIT; 396 uint32_t compact_mode = (s->regs.txcr1 & TXCOMPACT) ? 1 : 0; 397 #if defined(PL041_DEBUG_LEVEL) 398 uint32_t slots = (s->regs.txcr1 & TXSLOT_MASK) >> TXSLOT_MASK_BIT; 399 uint32_t txfen = (s->regs.txcr1 & TXFEN) > 0 ? 1 : 0; 400 #endif 401 402 DBG_L1("=> txen = %i slots = 0x%01x tsize = %i compact = %i " 403 "txfen = %i\n", txen, slots, tsize, compact_mode, txfen); 404 405 channel->tx_enabled = txen; 406 channel->tx_compact_mode = compact_mode; 407 408 switch (tsize) { 409 case 0: 410 channel->tx_sample_size = 16; 411 break; 412 case 1: 413 channel->tx_sample_size = 18; 414 break; 415 case 2: 416 channel->tx_sample_size = 20; 417 break; 418 case 3: 419 channel->tx_sample_size = 12; 420 break; 421 } 422 423 DBG_L1("TX enabled = %i\n", channel->tx_enabled); 424 DBG_L1("TX compact mode = %i\n", channel->tx_compact_mode); 425 DBG_L1("TX sample width = %i\n", channel->tx_sample_size); 426 427 /* Check if compact mode is allowed with selected tsize */ 428 if (channel->tx_compact_mode == 1) { 429 if ((channel->tx_sample_size == 18) || 430 (channel->tx_sample_size == 20)) { 431 channel->tx_compact_mode = 0; 432 DBG_L1("Compact mode not allowed with 18/20-bit sample size\n"); 433 } 434 } 435 436 break; 437 } 438 case PL041_sl1tx: 439 s->regs.slfr &= ~SL1TXEMPTY; 440 441 control = (s->regs.sl1tx >> 12) & 0x7F; 442 data = (s->regs.sl2tx >> 4) & 0xFFFF; 443 444 if ((s->regs.sl1tx & SLOT1_RW) == 0) { 445 /* Write operation */ 446 lm4549_write(&s->codec, control, data); 447 } else { 448 /* Read operation */ 449 result = lm4549_read(&s->codec, control); 450 451 /* Store the returned value */ 452 s->regs.sl1rx = s->regs.sl1tx & ~SLOT1_RW; 453 s->regs.sl2rx = result << 4; 454 455 s->regs.slfr &= ~(SL1RXBUSY | SL2RXBUSY); 456 s->regs.slfr |= SL1RXVALID | SL2RXVALID; 457 } 458 break; 459 460 case PL041_sl2tx: 461 s->regs.sl2tx = value; 462 s->regs.slfr &= ~SL2TXEMPTY; 463 break; 464 465 case PL041_intclr: 466 DBG_L1("=> Clear interrupt intclr = 0x%08x isr1 = 0x%08x\n", 467 s->regs.intclr, s->regs.isr1); 468 469 if (s->regs.intclr & TXUEC1) { 470 s->regs.sr1 &= ~TXUNDERRUN; 471 } 472 break; 473 474 case PL041_maincr: 475 { 476 #if defined(PL041_DEBUG_LEVEL) 477 char debug[] = " AACIFE SL1RXEN SL1TXEN"; 478 if (!(value & AACIFE)) { 479 debug[0] = '!'; 480 } 481 if (!(value & SL1RXEN)) { 482 debug[8] = '!'; 483 } 484 if (!(value & SL1TXEN)) { 485 debug[17] = '!'; 486 } 487 DBG_L1("%s\n", debug); 488 #endif 489 490 if ((s->regs.maincr & AACIFE) == 0) { 491 pl041_reset(s); 492 } 493 break; 494 } 495 496 case PL041_dr1_0: 497 case PL041_dr1_1: 498 case PL041_dr1_2: 499 case PL041_dr1_3: 500 pl041_fifo1_write(s, value); 501 break; 502 } 503 504 /* Transmit the FIFO content */ 505 pl041_fifo1_transmit(s); 506 507 /* Update the ISR1 register */ 508 pl041_isr1_update(s); 509 } 510 511 static void pl041_device_reset(DeviceState *d) 512 { 513 PL041State *s = PL041(d); 514 515 pl041_reset(s); 516 } 517 518 static const MemoryRegionOps pl041_ops = { 519 .read = pl041_read, 520 .write = pl041_write, 521 .endianness = DEVICE_NATIVE_ENDIAN, 522 }; 523 524 static void pl041_init(Object *obj) 525 { 526 SysBusDevice *dev = SYS_BUS_DEVICE(obj); 527 PL041State *s = PL041(dev); 528 529 DBG_L1("pl041_init 0x%08x\n", (uint32_t)s); 530 531 /* Connect the device to the sysbus */ 532 memory_region_init_io(&s->iomem, obj, &pl041_ops, s, "pl041", 0x1000); 533 sysbus_init_mmio(dev, &s->iomem); 534 sysbus_init_irq(dev, &s->irq); 535 } 536 537 static void pl041_realize(DeviceState *dev, Error **errp) 538 { 539 PL041State *s = PL041(dev); 540 541 /* Check the device properties */ 542 switch (s->fifo_depth) { 543 case 8: 544 case 32: 545 case 64: 546 case 128: 547 case 256: 548 case 512: 549 case 1024: 550 case 2048: 551 break; 552 case 16: 553 default: 554 /* NC FIFO depth of 16 is not allowed because its id bits in 555 AACIPERIPHID3 overlap with the id for the default NC FIFO depth */ 556 qemu_log_mask(LOG_UNIMP, 557 "pl041: unsupported non-compact fifo depth [%i]\n", 558 s->fifo_depth); 559 } 560 561 /* Init the codec */ 562 lm4549_init(&s->codec, &pl041_request_data, (void *)s); 563 } 564 565 static const VMStateDescription vmstate_pl041_regfile = { 566 .name = "pl041_regfile", 567 .version_id = 1, 568 .minimum_version_id = 1, 569 .fields = (VMStateField[]) { 570 #define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile), 571 #include "pl041.hx" 572 #undef REGISTER 573 VMSTATE_END_OF_LIST() 574 } 575 }; 576 577 static const VMStateDescription vmstate_pl041_fifo = { 578 .name = "pl041_fifo", 579 .version_id = 1, 580 .minimum_version_id = 1, 581 .fields = (VMStateField[]) { 582 VMSTATE_UINT32(level, pl041_fifo), 583 VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH), 584 VMSTATE_END_OF_LIST() 585 } 586 }; 587 588 static const VMStateDescription vmstate_pl041_channel = { 589 .name = "pl041_channel", 590 .version_id = 1, 591 .minimum_version_id = 1, 592 .fields = (VMStateField[]) { 593 VMSTATE_STRUCT(tx_fifo, pl041_channel, 0, 594 vmstate_pl041_fifo, pl041_fifo), 595 VMSTATE_UINT8(tx_enabled, pl041_channel), 596 VMSTATE_UINT8(tx_compact_mode, pl041_channel), 597 VMSTATE_UINT8(tx_sample_size, pl041_channel), 598 VMSTATE_STRUCT(rx_fifo, pl041_channel, 0, 599 vmstate_pl041_fifo, pl041_fifo), 600 VMSTATE_UINT8(rx_enabled, pl041_channel), 601 VMSTATE_UINT8(rx_compact_mode, pl041_channel), 602 VMSTATE_UINT8(rx_sample_size, pl041_channel), 603 VMSTATE_END_OF_LIST() 604 } 605 }; 606 607 static const VMStateDescription vmstate_pl041 = { 608 .name = "pl041", 609 .version_id = 1, 610 .minimum_version_id = 1, 611 .fields = (VMStateField[]) { 612 VMSTATE_UINT32(fifo_depth, PL041State), 613 VMSTATE_STRUCT(regs, PL041State, 0, 614 vmstate_pl041_regfile, pl041_regfile), 615 VMSTATE_STRUCT(fifo1, PL041State, 0, 616 vmstate_pl041_channel, pl041_channel), 617 VMSTATE_STRUCT(codec, PL041State, 0, 618 vmstate_lm4549_state, lm4549_state), 619 VMSTATE_END_OF_LIST() 620 } 621 }; 622 623 static Property pl041_device_properties[] = { 624 /* Non-compact FIFO depth property */ 625 DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth, 626 DEFAULT_FIFO_DEPTH), 627 DEFINE_PROP_END_OF_LIST(), 628 }; 629 630 static void pl041_device_class_init(ObjectClass *klass, void *data) 631 { 632 DeviceClass *dc = DEVICE_CLASS(klass); 633 634 dc->realize = pl041_realize; 635 set_bit(DEVICE_CATEGORY_SOUND, dc->categories); 636 dc->reset = pl041_device_reset; 637 dc->vmsd = &vmstate_pl041; 638 dc->props = pl041_device_properties; 639 } 640 641 static const TypeInfo pl041_device_info = { 642 .name = TYPE_PL041, 643 .parent = TYPE_SYS_BUS_DEVICE, 644 .instance_size = sizeof(PL041State), 645 .instance_init = pl041_init, 646 .class_init = pl041_device_class_init, 647 }; 648 649 static void pl041_register_types(void) 650 { 651 type_register_static(&pl041_device_info); 652 } 653 654 type_init(pl041_register_types) 655