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