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