Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/audio/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,11 +651,11 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd)

/* only start the DAI if we are not XRUN handling */
if (dd->xrun == 0) {
/* start the DAI */
dai_trigger(dd->dai, cmd, dev->direction);
ret = dma_start(dd->chan);
if (ret < 0)
return ret;
/* start the DAI */
dai_trigger(dd->dai, cmd, dev->direction);
} else {
dd->xrun = 0;
}
Expand Down Expand Up @@ -695,8 +695,21 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd)
COMPILER_FALLTHROUGH;
case COMP_TRIGGER_STOP:
comp_dbg(dev, "dai_comp_trigger_internal(), STOP");
/*
* Some platforms cannot just simple disable
* DMA channel during the transfer,
* because it will hang the whole DMA controller.
* Therefore, stop the DMA first and let the DAI
* drain the FIFO in order to stop the channel
* as soon as possible.
*/
#if CONFIG_DMA_SUSPEND_DRAIN
ret = dma_stop(dd->chan);
dai_trigger(dd->dai, cmd, dev->direction);
#else
dai_trigger(dd->dai, cmd, dev->direction);
ret = dma_stop(dd->chan);
#endif
break;
case COMP_TRIGGER_PAUSE:
comp_dbg(dev, "dai_comp_trigger_internal(), PAUSE");
Expand Down
127 changes: 84 additions & 43 deletions src/drivers/imx/sai.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,41 +33,68 @@ static void sai_start(struct dai *dai, int direction)

uint32_t xcsr = 0U;

/* enable DMA requests */
if (direction == DAI_DIR_CAPTURE) {
/* Software Reset */
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_CAPTURE),
REG_SAI_CSR_SR, REG_SAI_CSR_SR);
/* Clear SR bit to finish the reset */
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_CAPTURE),
REG_SAI_CSR_SR, 0U);
/* Check if the opposite direction is also disabled */
xcsr = dai_read(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK));
if (!(xcsr & REG_SAI_CSR_FRDE)) {
/* Software Reset */
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK),
REG_SAI_CSR_SR, REG_SAI_CSR_SR);
/* Clear SR bit to finish the reset */
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK),
REG_SAI_CSR_SR, 0U);
/* Transmitter enable */
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK),
REG_SAI_CSR_TERE, REG_SAI_CSR_TERE);
}
} else {
/* Check if the opposite direction is also disabled */
xcsr = dai_read(dai, REG_SAI_XCSR(DAI_DIR_CAPTURE));
if (!(xcsr & REG_SAI_CSR_FRDE)) {
/* Software Reset */
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK),
REG_SAI_CSR_SR, REG_SAI_CSR_SR);
/* Clear SR bit to finish the reset */
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK),
REG_SAI_CSR_SR, 0U);
}
}

/* W1C */
dai_update_bits(dai, REG_SAI_XCSR(direction),
REG_SAI_CSR_FRDE, REG_SAI_CSR_FRDE);
#ifdef CONFIG_IMX8M
dai_update_bits(dai, REG_SAI_MCTL, REG_SAI_MCTL_MCLK_EN,
REG_SAI_MCTL_MCLK_EN);
#endif
REG_SAI_CSR_FEF, 1);
dai_update_bits(dai, REG_SAI_XCSR(direction),
REG_SAI_CSR_SEF, 1);
dai_update_bits(dai, REG_SAI_XCSR(direction),
REG_SAI_CSR_WSF, 1);

/* add one word to FIFO before TRCE is enabled */
if (direction == DAI_DIR_PLAYBACK)
dai_write(dai, REG_SAI_TDR0, 0x0);
else
dai_write(dai, REG_SAI_RDR0, 0x0);

/* transmitter enable */
/* enable DMA requests */
dai_update_bits(dai, REG_SAI_XCSR(direction),
REG_SAI_CSR_TERE, REG_SAI_CSR_TERE);
/* TODO: for the time being use half FIFO size as watermark */
dai_update_bits(dai, REG_SAI_XCR1(direction),
REG_SAI_CR1_RFW_MASK, SAI_FIFO_WORD_SIZE / 2);
REG_SAI_CSR_FRDE, REG_SAI_CSR_FRDE);
#ifdef CONFIG_IMX8M
dai_update_bits(dai, REG_SAI_MCTL, REG_SAI_MCTL_MCLK_EN,
REG_SAI_MCTL_MCLK_EN);
#endif

/* transmit/receive data channel enable */
dai_update_bits(dai, REG_SAI_XCR3(direction),
REG_SAI_CR3_TRCE_MASK, REG_SAI_CR3_TRCE(1));

if (direction == DAI_DIR_CAPTURE) {
xcsr = dai_read(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK));
if (!(xcsr & REG_SAI_CSR_FRDE)) {

dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK),
REG_SAI_CSR_TERE, REG_SAI_CSR_TERE);
dai_update_bits(dai, REG_SAI_XCR3(DAI_DIR_PLAYBACK),
REG_SAI_CR3_TRCE_MASK,
REG_SAI_CR3_TRCE(1));
}
}

/* transmitter/receiver enable */
dai_update_bits(dai, REG_SAI_XCSR(direction),
REG_SAI_CSR_TERE, REG_SAI_CSR_TERE);
}

static void sai_stop(struct dai *dai, int direction)
Expand All @@ -76,32 +103,39 @@ static void sai_stop(struct dai *dai, int direction)

uint32_t xcsr = 0U;

/* Disable DMA request */
dai_update_bits(dai, REG_SAI_XCSR(direction),
REG_SAI_CSR_FRDE, 0);

/* Transmit/Receive data channel disable */
dai_update_bits(dai, REG_SAI_XCR3(direction),
REG_SAI_CR3_TRCE_MASK,
REG_SAI_CR3_TRCE(0));

/* Disable interrupts */
dai_update_bits(dai, REG_SAI_XCSR(direction),
REG_SAI_CSR_XIE_MASK, 0);

/* Check if the opposite direction is also disabled */
xcsr = dai_read(dai, REG_SAI_XCSR(!direction));
if (!(xcsr & REG_SAI_CSR_FRDE)) {
/* Disable both directions and reset their FIFOs */
dai_update_bits(dai, REG_SAI_TCSR, REG_SAI_CSR_TERE, 0);
poll_for_register_delay(dai_base(dai) + REG_SAI_TCSR,
REG_SAI_CSR_TERE, 0, 100);

dai_update_bits(dai, REG_SAI_RCSR, REG_SAI_CSR_TERE, 0);
poll_for_register_delay(dai_base(dai) + REG_SAI_RCSR,
/* Disable transmitter/receiver */
if (direction == DAI_DIR_CAPTURE) {
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_CAPTURE), REG_SAI_CSR_TERE, 0);
poll_for_register_delay(dai_base(dai) + REG_SAI_XCSR(DAI_DIR_CAPTURE),
REG_SAI_CSR_TERE, 0, 100);

/* Software Reset for both Tx and Rx */
dai_update_bits(dai, REG_SAI_TCSR, REG_SAI_CSR_SR,
REG_SAI_CSR_SR);
dai_update_bits(dai, REG_SAI_RCSR, REG_SAI_CSR_SR,
REG_SAI_CSR_SR);

/* Clear SR bit to finish the reset */
dai_update_bits(dai, REG_SAI_TCSR, REG_SAI_CSR_SR, 0U);
dai_update_bits(dai, REG_SAI_RCSR, REG_SAI_CSR_SR, 0U);
/* Check if the opposite direction is also disabled */
xcsr = dai_read(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK));
if (!(xcsr & REG_SAI_CSR_FRDE)) {
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK), REG_SAI_CSR_TERE, 0);
poll_for_register_delay(dai_base(dai) + REG_SAI_XCSR(DAI_DIR_PLAYBACK),
REG_SAI_CSR_TERE, 0, 100);
}
} else {
/* Check if the opposite direction is also disabled */
xcsr = dai_read(dai, REG_SAI_XCSR(DAI_DIR_CAPTURE));
if (!(xcsr & REG_SAI_CSR_FRDE)) {
dai_update_bits(dai, REG_SAI_XCSR(DAI_DIR_PLAYBACK), REG_SAI_CSR_TERE, 0);
poll_for_register_delay(dai_base(dai) + REG_SAI_XCSR(DAI_DIR_PLAYBACK),
REG_SAI_CSR_TERE, 0, 100);
}
}
}

Expand Down Expand Up @@ -255,6 +289,9 @@ static inline int sai_set_config(struct dai *dai,
mask_cr5 = REG_SAI_CR5_WNW_MASK | REG_SAI_CR5_W0W_MASK |
REG_SAI_CR5_FBT_MASK;

/* TODO: for the time being use half FIFO size as watermark */
dai_update_bits(dai, REG_SAI_XCR1(REG_TX_DIR),
REG_SAI_CR1_RFW_MASK, SAI_FIFO_WORD_SIZE / 2);
dai_update_bits(dai, REG_SAI_XCR2(REG_TX_DIR), mask_cr2, val_cr2);
dai_update_bits(dai, REG_SAI_XCR4(REG_TX_DIR), mask_cr4, val_cr4);
dai_update_bits(dai, REG_SAI_XCR5(REG_TX_DIR), mask_cr5, val_cr5);
Expand All @@ -264,6 +301,10 @@ static inline int sai_set_config(struct dai *dai,

val_cr2 |= REG_SAI_CR2_SYNC;
mask_cr2 |= REG_SAI_CR2_SYNC_MASK;

/* TODO: for the time being use half FIFO size as watermark */
dai_update_bits(dai, REG_SAI_XCR1(REG_RX_DIR),
REG_SAI_CR1_RFW_MASK, SAI_FIFO_WORD_SIZE / 2);
dai_update_bits(dai, REG_SAI_XCR2(REG_RX_DIR), mask_cr2, val_cr2);
dai_update_bits(dai, REG_SAI_XCR4(REG_RX_DIR), mask_cr4, val_cr4);
dai_update_bits(dai, REG_SAI_XCR5(REG_RX_DIR), mask_cr5, val_cr5);
Expand Down