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