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