Lines Matching +full:tx +full:- +full:fifo +full:- +full:depth
5 * Written by Mathieu Sonet - www.elasticsheep.com
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.
25 #include "hw/qdev-properties.h"
61 /* This FIFO only stores 20-bit samples on 32-bit words.
89 uint32_t fifo_depth; /* FIFO depth in non-compact mode */
125 /* Add the fifo depth information */ in pl041_compute_periphid3()
126 switch (s->fifo_depth) { in pl041_compute_periphid3()
160 memset(&s->regs, 0x00, sizeof(pl041_regfile)); in pl041_reset()
162 s->regs.slfr = SL1TXEMPTY | SL2TXEMPTY | SL12TXEMPTY; in pl041_reset()
163 s->regs.sr1 = TXFE | RXFE | TXHE; in pl041_reset()
164 s->regs.isr1 = 0; in pl041_reset()
166 memset(&s->fifo1, 0x00, sizeof(s->fifo1)); in pl041_reset()
172 pl041_channel *channel = &s->fifo1; in pl041_fifo1_write()
173 pl041_fifo *fifo = &s->fifo1.tx_fifo; in pl041_fifo1_write() local
175 /* Push the value in the FIFO */ in pl041_fifo1_write()
176 if (channel->tx_compact_mode == 0) { in pl041_fifo1_write()
177 /* Non-compact mode */ in pl041_fifo1_write()
179 if (fifo->level < s->fifo_depth) { in pl041_fifo1_write()
180 /* Pad the value with 0 to obtain a 20-bit sample */ in pl041_fifo1_write()
181 switch (channel->tx_sample_size) { in pl041_fifo1_write()
196 /* Store the sample in the FIFO */ in pl041_fifo1_write()
197 fifo->data[fifo->level++] = value; in pl041_fifo1_write()
207 if ((fifo->level + 2) < s->fifo_depth) { in pl041_fifo1_write()
215 /* Pad each sample with 0 to obtain a 20-bit sample */ in pl041_fifo1_write()
216 switch (channel->tx_sample_size) { in pl041_fifo1_write()
226 /* Store the sample in the FIFO */ in pl041_fifo1_write()
227 fifo->data[fifo->level++] = sample; in pl041_fifo1_write()
238 if (fifo->level > 0) { in pl041_fifo1_write()
239 s->regs.sr1 &= ~(TXUNDERRUN | TXFE); in pl041_fifo1_write()
242 if (fifo->level >= (s->fifo_depth / 2)) { in pl041_fifo1_write()
243 s->regs.sr1 &= ~TXHE; in pl041_fifo1_write()
246 if (fifo->level >= s->fifo_depth) { in pl041_fifo1_write()
247 s->regs.sr1 |= TXFF; in pl041_fifo1_write()
250 DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1); in pl041_fifo1_write()
255 pl041_channel *channel = &s->fifo1; in pl041_fifo1_transmit()
256 pl041_fifo *fifo = &s->fifo1.tx_fifo; in pl041_fifo1_transmit() local
257 uint32_t slots = s->regs.txcr1 & TXSLOT_MASK; in pl041_fifo1_transmit()
261 if ((channel->tx_enabled) && (slots & (TXSLOT3 | TXSLOT4))) { in pl041_fifo1_transmit()
262 if (fifo->level >= (s->fifo_depth / 2)) { in pl041_fifo1_transmit()
265 DBG_L1("Transfer FIFO level = %i\n", fifo->level); in pl041_fifo1_transmit()
267 /* Try to transfer the whole FIFO */ in pl041_fifo1_transmit()
268 for (i = 0; i < (fifo->level / 2); i++) { in pl041_fifo1_transmit()
269 uint32_t left = fifo->data[i * 2]; in pl041_fifo1_transmit()
270 uint32_t right = fifo->data[i * 2 + 1]; in pl041_fifo1_transmit()
272 /* Transmit two 20-bit samples to the codec */ in pl041_fifo1_transmit()
273 if (lm4549_write_samples(&s->codec, left, right) == 0) { in pl041_fifo1_transmit()
281 /* Update the FIFO level */ in pl041_fifo1_transmit()
282 fifo->level -= written_samples; in pl041_fifo1_transmit()
284 /* Move back the pending samples to the start of the FIFO */ in pl041_fifo1_transmit()
285 for (i = 0; i < fifo->level; i++) { in pl041_fifo1_transmit()
286 fifo->data[i] = fifo->data[written_samples + i]; in pl041_fifo1_transmit()
290 s->regs.sr1 &= ~TXFF; in pl041_fifo1_transmit()
292 if (fifo->level <= (s->fifo_depth / 2)) { in pl041_fifo1_transmit()
293 s->regs.sr1 |= TXHE; in pl041_fifo1_transmit()
296 if (fifo->level == 0) { in pl041_fifo1_transmit()
297 s->regs.sr1 |= TXFE | TXUNDERRUN; in pl041_fifo1_transmit()
298 DBG_L1("Empty FIFO\n"); in pl041_fifo1_transmit()
308 if (s->regs.sr1 & TXUNDERRUN) { in pl041_isr1_update()
309 s->regs.isr1 |= URINTR; in pl041_isr1_update()
311 s->regs.isr1 &= ~URINTR; in pl041_isr1_update()
314 if (s->regs.sr1 & TXHE) { in pl041_isr1_update()
315 s->regs.isr1 |= TXINTR; in pl041_isr1_update()
317 s->regs.isr1 &= ~TXINTR; in pl041_isr1_update()
320 if (!(s->regs.sr1 & TXBUSY) && (s->regs.sr1 & TXFE)) { in pl041_isr1_update()
321 s->regs.isr1 |= TXCINTR; in pl041_isr1_update()
323 s->regs.isr1 &= ~TXCINTR; in pl041_isr1_update()
327 qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0); in pl041_isr1_update()
329 s->regs.sr1, s->regs.isr1, s->regs.isr1 & s->regs.ie1); in pl041_isr1_update()
351 value = pl041_default_id[(offset - PL041_periphid0) >> 2]; in pl041_read()
357 value = *((uint32_t *)&s->regs + (offset >> 2)); in pl041_read()
365 value = s->regs.isr1 & 0x7F; in pl041_read()
387 *((uint32_t *)&s->regs + (offset >> 2)) = value; in pl041_write()
397 pl041_channel *channel = &s->fifo1; in pl041_write()
399 uint32_t txen = s->regs.txcr1 & TXEN; in pl041_write()
400 uint32_t tsize = (s->regs.txcr1 & TSIZE_MASK) >> TSIZE_MASK_BIT; in pl041_write()
401 uint32_t compact_mode = (s->regs.txcr1 & TXCOMPACT) ? 1 : 0; in pl041_write()
403 uint32_t slots = (s->regs.txcr1 & TXSLOT_MASK) >> TXSLOT_MASK_BIT; in pl041_write()
404 uint32_t txfen = (s->regs.txcr1 & TXFEN) > 0 ? 1 : 0; in pl041_write()
410 channel->tx_enabled = txen; in pl041_write()
411 channel->tx_compact_mode = compact_mode; in pl041_write()
415 channel->tx_sample_size = 16; in pl041_write()
418 channel->tx_sample_size = 18; in pl041_write()
421 channel->tx_sample_size = 20; in pl041_write()
424 channel->tx_sample_size = 12; in pl041_write()
428 DBG_L1("TX enabled = %i\n", channel->tx_enabled); in pl041_write()
429 DBG_L1("TX compact mode = %i\n", channel->tx_compact_mode); in pl041_write()
430 DBG_L1("TX sample width = %i\n", channel->tx_sample_size); in pl041_write()
433 if (channel->tx_compact_mode == 1) { in pl041_write()
434 if ((channel->tx_sample_size == 18) || in pl041_write()
435 (channel->tx_sample_size == 20)) { in pl041_write()
436 channel->tx_compact_mode = 0; in pl041_write()
437 DBG_L1("Compact mode not allowed with 18/20-bit sample size\n"); in pl041_write()
444 s->regs.slfr &= ~SL1TXEMPTY; in pl041_write()
446 control = (s->regs.sl1tx >> 12) & 0x7F; in pl041_write()
447 data = (s->regs.sl2tx >> 4) & 0xFFFF; in pl041_write()
449 if ((s->regs.sl1tx & SLOT1_RW) == 0) { in pl041_write()
451 lm4549_write(&s->codec, control, data); in pl041_write()
454 result = lm4549_read(&s->codec, control); in pl041_write()
457 s->regs.sl1rx = s->regs.sl1tx & ~SLOT1_RW; in pl041_write()
458 s->regs.sl2rx = result << 4; in pl041_write()
460 s->regs.slfr &= ~(SL1RXBUSY | SL2RXBUSY); in pl041_write()
461 s->regs.slfr |= SL1RXVALID | SL2RXVALID; in pl041_write()
466 s->regs.sl2tx = value; in pl041_write()
467 s->regs.slfr &= ~SL2TXEMPTY; in pl041_write()
472 s->regs.intclr, s->regs.isr1); in pl041_write()
474 if (s->regs.intclr & TXUEC1) { in pl041_write()
475 s->regs.sr1 &= ~TXUNDERRUN; in pl041_write()
495 if ((s->regs.maincr & AACIFE) == 0) { in pl041_write()
509 /* Transmit the FIFO content */ in pl041_write()
537 memory_region_init_io(&s->iomem, obj, &pl041_ops, s, "pl041", 0x1000); in pl041_init()
538 sysbus_init_mmio(dev, &s->iomem); in pl041_init()
539 sysbus_init_irq(dev, &s->irq); in pl041_init()
547 switch (s->fifo_depth) { in pl041_realize()
559 /* NC FIFO depth of 16 is not allowed because its id bits in in pl041_realize()
560 AACIPERIPHID3 overlap with the id for the default NC FIFO depth */ in pl041_realize()
562 "pl041: unsupported non-compact fifo depth [%i]\n", in pl041_realize()
563 s->fifo_depth); in pl041_realize()
567 lm4549_init(&s->codec, &pl041_request_data, (void *)s, errp); in pl041_realize()
630 /* Non-compact FIFO depth property */
640 dc->realize = pl041_realize; in pl041_device_class_init()
641 set_bit(DEVICE_CATEGORY_SOUND, dc->categories); in pl041_device_class_init()
643 dc->vmsd = &vmstate_pl041; in pl041_device_class_init()