xref: /openbmc/qemu/hw/audio/pl041.c (revision 37677d7d)
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