Re: [alsa-devel] fsl_ssi.c: Roberto's problem: ssi hangs after some number of samples
Hi All, is it okay of we split Roberto's problem from mine? It's getting difficult to track which response goes to which problem :-)
I included Roberto's email, and Nicolin's reply below:
So, this thread is for the hanging problem, the prehistory for this thread is in, "fsl_ssi.c: Getting channel slips with fsl_ssi.c in TDM (network) mode."
-Caleb
On Fri, Oct 30, 2015 at 4:42 AM, Roberto Fichera kernel@tekno-soft.it wrote:
On 10/30/2015 12:04 AM, Nicolin Chen wrote:
On Wed, Oct 28, 2015 at 09:11:39AM +0100, Roberto Fichera wrote:
I'm also having the same issue but employing SSI in TDM master mode against a SLIC Si32178 using its PCM mode. PCLK is at 2048KHz, FSYNC is 8KHz slot length is 32 bits (SSI wants this since when in master mode) but valid data set to be 8bits in the SSI register. My Current situation is that I've a custom fsl_ssi.c driver to control the SSI in TDM master mode both PCLK and FSYNC works perfectly fine, the SLIC has a register that I can check via SPI for such purpose, I can see the clocking status from its side. The main problem I've is exactly the same Caleb is having, after a certain amount of SDMA transfers, roughly 1000 or so, everything stops without any apparent reason.
I will start to help you to figure out your problem. But it seems that you are having a different issue here with clock generation. I don't get why you said *same issue*. For double confirm, the the "everything stops" mentioned, does it mean that clock from SSI stops?
Definitively yes! My problem is different than Caleb's one. Just to summarize the things. I've the SSI1 connected to a SiLabs SLIC Si32178 via AUDMUX6 padmux is below:
pinctrl_audmux_1: audmuxgrp-3 { fsl,pins = < MX6SX_PAD_SD3_DATA1__AUDMUX_AUD6_TXC 0x130b0 /* PCLK */ MX6SX_PAD_SD3_DATA2__AUDMUX_AUD6_TXFS 0x130b0 /* FSYNC */ MX6SX_PAD_SD3_DATA0__AUDMUX_AUD6_RXD 0x130b0 /* DTX */ MX6SX_PAD_SD3_DATA3__AUDMUX_AUD6_TXD 0x120b0 /* DRX */ >; };
The Si32178 is slave device so the SSI1 has to generate both BCLK and FSYNC. I've configured the AUDMUX as:
int si3217x_audmux_config(unsigned int master, unsigned int slave) { unsigned int ptcr, pdcr;
ptcr = IMX_AUDMUX_V2_PTCR_SYN | IMX_AUDMUX_V2_PTCR_TFSDIR | IMX_AUDMUX_V2_PTCR_TFSEL(master) | IMX_AUDMUX_V2_PTCR_TCLKDIR | IMX_AUDMUX_V2_PTCR_TCSEL(master); pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master); si3217x_audmux_v2_configure_port(slave, ptcr, pdcr); /* configure internal port */
ptcr = IMX_AUDMUX_V2_PTCR_SYN; pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave); si3217x_audmux_v2_configure_port(master, ptcr, pdcr); /* configure external port */
return 0; }
BCLK is 2048KHz, FSYNC@8KHz, frame is 32 slots at 8bits each. Looking at TXC and TXFS with a logical analyzer everything looks ok.
The SSI is setup at beginning as:
unsigned long flags; struct ccsr_ssi __iomem *ssi = ssi_private->ssi; u32 srcr; u8 wm; clk_prepare_enable(ssi_private->clk); /* * Section 16.5 of the MPC8610 reference manual says that the * SSI needs to be disabled before updating the registers we set * here. */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); /* * Program the SSI into I2S Master Network Synchronous mode. * Also enable the transmit and receive FIFO. */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_NET | CCSR_SSI_SCR_SYS_CLK_EN); /* * TX falling edge PCLK is mandatory because the RX SLIC side works in this way */ writel( CCSR_SSI_STCR_TXBIT0 /* LSB Aligned */ | CCSR_SSI_STCR_TFEN0 /* Enable TX FIFO0 */ | CCSR_SSI_STCR_TSCKP /* Transmit Clock Polarity - Data Clocked out on falling edge */ | CCSR_SSI_STCR_TFDIR /* Transmit Frame Direction Internal - generated internally */ | CCSR_SSI_STCR_TXDIR, /* Transmit Clock Direction Internal - generated internally */ &ssi->stcr); srcr = readl(&ssi->srcr); /* * clear out RFDIR and RXDIR because the clock is synchronous */ srcr &= ~(CCSR_SSI_SRCR_RFDIR | CCSR_SSI_SRCR_RXDIR); srcr |= CCSR_SSI_SRCR_RXBIT0 /* LSB Aligned */ | CCSR_SSI_SRCR_RFEN0 /* Enable RX FIFO0 */ | CCSR_SSI_SRCR_RSCKP /* Receive Clock Polarity - Data latched on rising edge */ ; writel(srcr, &ssi->srcr); /* do not service the isr yet */ writel(0, &ssi->sier); /* * Set the watermark for transmit FIFI 0 and receive FIFO 0. We * don't use FIFO 1. We program the transmit water to signal a * DMA transfer if there are only two (or fewer) elements left * in the FIFO. */ /* * tdm_real_slots is 2 because mask all except first 2 slots * our buffer is 2 slots * 8 bytes each, so set watermarks to a multiple of it * 8 words in our case */ wm = ssi_private->tdm_real_slots * 4; //ssi_private->use_dma ? ssi_private->fifo_depth - 2 :
ssi_private->fifo_depth;
writel(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm), &ssi->sfcsr); /* enable one FIFO */ write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1, 0); write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1, 0); /* disable SSI two-channel mode operation */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN, 0); /* * We keep the SSI disabled because if we enable it, then the * DMA controller will start. It's not supposed to start until * the SCR.TE (or SCR.RE) bit is set, but it does anyway. The * DMA controller will transfer one "BWC" of data (i.e. the * amount of data that the MR.BWC bits are set to). The reason * this is bad is because at this point, the PCM driver has not * finished initializing the DMA controller. */ /* Set default slot number -- 32 in our case */ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(ssi_private->tdm_slots)); write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(ssi_private->tdm_slots)); /* Set default word length -- 8 bits */ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, CCSR_SSI_SxCCR_WL(ssi_private->tdm_word_size)); write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, CCSR_SSI_SxCCR_WL(ssi_private->tdm_word_size)); /* enable the SSI */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN); /* * we are interested only at first 2 slots */ writel(~ssi_private->tdm_slots_enabled, &ssi->stmsk); writel(~ssi_private->tdm_slots_enabled, &ssi->srmsk); return 0;
}
SSI clock calculated and then enabled. Both TX and RX DMA channel are requested in the probe() function as below. and the corresponding TX and RX SDMA event in DTS are using the default from imx6sx.dtsi:
slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0); slave_config.dst_addr_width = width; slave_config.dst_maxburst = ssi_private->tdm_real_slots * 4; ret = dmaengine_slave_config(ssi_private->tx_chan, &slave_config); ssi_private->rx_chan = dma_request_slave_channel_reason(&pdev->dev, "rx"); slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0); slave_config.src_addr_width = width; slave_config.src_maxburst = ssi_private->tdm_real_slots * 4; ret = dmaengine_slave_config(ssi_private->rx_chan, &slave_config);
and setup before RDMAE and TDMAE bits, like this:
ssi_private->tx_buf = dma_alloc_coherent(NULL, buffer_len, &ssi_private->tx_dmaaddr, GFP_KERNEL); desc = dmaengine_prep_dma_cyclic(ssi_private->tx_chan, ssi_private->tx_dmaaddr, buffer_len, ssi_private->tdm_real_slots*4, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); desc->callback = dma_tx_callback; desc->callback_param = ssi_private; printk("TX: prepare for the DMA.\n"); dmaengine_submit(desc); dma_async_issue_pending(ssi_private->tx_chan); ssi_private->rx_buf = dma_alloc_coherent(NULL, buffer_len, &ssi_private->rx_dmaaddr, GFP_KERNEL); desc = dmaengine_prep_dma_cyclic(ssi_private->rx_chan, ssi_private->rx_dmaaddr, buffer_len, ssi_private->tdm_real_slots*4, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); desc->callback = dma_rx_callback; desc->callback_param = ssi_private; printk("RX: prepare for the DMA.\n"); dmaengine_submit(desc); dma_async_issue_pending(ssi_private->rx_chan);
Finally, the SSI's TX and RX parts are now enabled
scr = readl(&ssi->scr); scr |= CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE; /* enable both TX and RX SSI sections */ writel(scr, &ssi->scr);
Finally the SIER si programmed as:
struct ccsr_ssi __iomem *ssi = ssi_private->ssi; u32 sier = CCSR_SSI_SIER_RFF0_EN | CCSR_SSI_SIER_TFE0_EN;
/* * if DMA is enabled than allow SSI request for DMA transfers * otherwise normal interrupt requests */ if (ssi_private->use_dma>0) { sier |= CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_TDMAE; } if (ssi_private->use_dma>1 || !ssi_private->use_dma) { sier |= CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_TIE; } sier &= ~(CCSR_SSI_SIER_TDE1_EN | CCSR_SSI_SIER_TFE1_EN | CCSR_SSI_SIER_TFE0_EN | CCSR_SSI_SIER_TDE0_EN); writel(sier, &ssi->sier);
At this time I should see the DMA callbacks called every burst_size words. This behaviour doesn't really happen as I wish because I can see from a proc file that such callbacks are called from 1 to 20000 times and then anymore. This is also confirmed by the fact that the interrupt 34 (sdma) doesn't increase anymore but matches my internal counters collected within my callbacks. Here is what I can inspect from the data I have collected:
root@voneus-domus-imx6sx:~# cat /proc/domus_ssi_stats SSI TDM Info: PLL clk=66000000 SSI baudclk=49152000 ssi_phy=0x02028000 irq=78 fifo_depth=15 <---- this is what is read from DTS but not as watermark tdm_frame_rate=8000 tdm_slots=32 (real 2) tdm_word_size=8 tdm_slots_enabled=00000000000000000000000000000011 clk_frequency=2048000 clock_running=yes DMA=yes Dual FIFO=no RX DMA frame count=17121 RX DMA addr=0x9c692000 RX DMA buffer len=16 TX DMA frame count=17121 TX DMA addr=0x9c4aa000 TX DMA buffer len=16
SSI Registers: ssi_scr=0x0000009f ssi_sier=0x00500004 ssi_stcr=0x000002e8 ssi_srcr=0x00000288 ssi_stccr=0x00007f0b ssi_srccr=0x00007f0b ssi_sfcsr=0x0088f088 ssi_stmsk=0xfffffffc ssi_srmsk=0xfffffffc
Cheers, Roberto Fichera.
And here's Nicolin's reply:
On Fri, Oct 30, 2015 at 12:42:53PM +0100, Roberto Fichera wrote:
/* * Set the watermark for transmit FIFI 0 and receive FIFO 0. We * don't use FIFO 1. We program the transmit water to signal a * DMA transfer if there are only two (or fewer) elements left * in the FIFO. */
SSI clock calculated and then enabled. Both TX and RX DMA channel are requested in the probe() function as below. and the corresponding TX and RX SDMA event in DTS are using the default from imx6sx.dtsi:
Since you are using single FIFO configuration, which SDMA script are you using? This should reflects in the Device Tree. As far as I learned, FSL 3.14 is using number 22 for SSIs which is the one for Dual FIFO Mode.
At this time I should see the DMA callbacks called every burst_size words. This behaviour doesn't really happen as I wish because I can see from a proc file that such callbacks are called from 1 to 20000 times and then anymore. This is also confirmed by the fact that the interrupt 34 (sdma) doesn't increase anymore but matches my internal counters collected within my callbacks. Here is what I can inspect from the data I have collected:
Just for clarification, the behaviour doesn't happen as you wish is just the DMA stopped? I remember you also mentioned bit clock has stopped as you can check the clock status from the Codec chip.
SSI Registers: ssi_sfcsr=0x0088f088
At this point you have data in RxFIFO and get empty in TxFIFO, so the DMA requests from both side should be issued. If the DMA stops as you described, you must check those two channels from the SDMA side by dumping SDMAARM_STOP_STAT, SDMAARM_HSTART, SDMAARM_EVTOVR, SDMAARM_EVTPEND, SDMAARM_EVTERR, SDMAARM_DSPOVR and SDMAARM_HOSTOVR registers.
Overall, I don't see an obvious defect from you SSI side, but you may also try to toggle TDMAE and RDMAE at the point that callback stops -- re-raise the DMA requests by disabling and enabling TDMAE and RDMAE again and see if it works. I think either something did intervene register controls of SDMA or SSI, or SDMA have missed the request signals from SSI.
On 10/30/2015 07:01 PM, Caleb Crome wrote:
Hi All, is it okay of we split Roberto's problem from mine? It's getting difficult to track which response goes to which problem :-)
I included Roberto's email, and Nicolin's reply below:
So, this thread is for the hanging problem, the prehistory for this thread is in, "fsl_ssi.c: Getting channel slips with fsl_ssi.c in TDM (network) mode."
That's fine! Thanks Calab!
-Caleb
On Fri, Oct 30, 2015 at 4:42 AM, Roberto Fichera kernel@tekno-soft.it wrote:
On 10/30/2015 12:04 AM, Nicolin Chen wrote:
On Wed, Oct 28, 2015 at 09:11:39AM +0100, Roberto Fichera wrote:
I'm also having the same issue but employing SSI in TDM master mode against a SLIC Si32178 using its PCM mode. PCLK is at 2048KHz, FSYNC is 8KHz slot length is 32 bits (SSI wants this since when in master mode) but valid data set to be 8bits in the SSI register. My Current situation is that I've a custom fsl_ssi.c driver to control the SSI in TDM master mode both PCLK and FSYNC works perfectly fine, the SLIC has a register that I can check via SPI for such purpose, I can see the clocking status from its side. The main problem I've is exactly the same Caleb is having, after a certain amount of SDMA transfers, roughly 1000 or so, everything stops without any apparent reason.
I will start to help you to figure out your problem. But it seems that you are having a different issue here with clock generation. I don't get why you said *same issue*. For double confirm, the the "everything stops" mentioned, does it mean that clock from SSI stops?
Definitively yes! My problem is different than Caleb's one. Just to summarize the things. I've the SSI1 connected to a SiLabs SLIC Si32178 via AUDMUX6 padmux is below:
pinctrl_audmux_1: audmuxgrp-3 { fsl,pins = < MX6SX_PAD_SD3_DATA1__AUDMUX_AUD6_TXC 0x130b0 /* PCLK */ MX6SX_PAD_SD3_DATA2__AUDMUX_AUD6_TXFS 0x130b0 /* FSYNC */ MX6SX_PAD_SD3_DATA0__AUDMUX_AUD6_RXD 0x130b0 /* DTX */ MX6SX_PAD_SD3_DATA3__AUDMUX_AUD6_TXD 0x120b0 /* DRX */ >; };
The Si32178 is slave device so the SSI1 has to generate both BCLK and FSYNC. I've configured the AUDMUX as:
int si3217x_audmux_config(unsigned int master, unsigned int slave) { unsigned int ptcr, pdcr;
ptcr = IMX_AUDMUX_V2_PTCR_SYN | IMX_AUDMUX_V2_PTCR_TFSDIR | IMX_AUDMUX_V2_PTCR_TFSEL(master) | IMX_AUDMUX_V2_PTCR_TCLKDIR | IMX_AUDMUX_V2_PTCR_TCSEL(master); pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master); si3217x_audmux_v2_configure_port(slave, ptcr, pdcr); /* configure internal port */
ptcr = IMX_AUDMUX_V2_PTCR_SYN; pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave); si3217x_audmux_v2_configure_port(master, ptcr, pdcr); /* configure external port */
return 0; }
BCLK is 2048KHz, FSYNC@8KHz, frame is 32 slots at 8bits each. Looking at TXC and TXFS with a logical analyzer everything looks ok.
The SSI is setup at beginning as:
unsigned long flags; struct ccsr_ssi __iomem *ssi = ssi_private->ssi; u32 srcr; u8 wm; clk_prepare_enable(ssi_private->clk); /* * Section 16.5 of the MPC8610 reference manual says that the * SSI needs to be disabled before updating the registers we set * here. */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); /* * Program the SSI into I2S Master Network Synchronous mode. * Also enable the transmit and receive FIFO. */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_NET | CCSR_SSI_SCR_SYS_CLK_EN); /* * TX falling edge PCLK is mandatory because the RX SLIC side works in this way */ writel( CCSR_SSI_STCR_TXBIT0 /* LSB Aligned */ | CCSR_SSI_STCR_TFEN0 /* Enable TX FIFO0 */ | CCSR_SSI_STCR_TSCKP /* Transmit Clock Polarity - Data Clocked out on falling edge */ | CCSR_SSI_STCR_TFDIR /* Transmit Frame Direction Internal - generated internally */ | CCSR_SSI_STCR_TXDIR, /* Transmit Clock Direction Internal - generated internally */ &ssi->stcr); srcr = readl(&ssi->srcr); /* * clear out RFDIR and RXDIR because the clock is synchronous */ srcr &= ~(CCSR_SSI_SRCR_RFDIR | CCSR_SSI_SRCR_RXDIR); srcr |= CCSR_SSI_SRCR_RXBIT0 /* LSB Aligned */ | CCSR_SSI_SRCR_RFEN0 /* Enable RX FIFO0 */ | CCSR_SSI_SRCR_RSCKP /* Receive Clock Polarity - Data latched on rising edge */ ; writel(srcr, &ssi->srcr); /* do not service the isr yet */ writel(0, &ssi->sier); /* * Set the watermark for transmit FIFI 0 and receive FIFO 0. We * don't use FIFO 1. We program the transmit water to signal a * DMA transfer if there are only two (or fewer) elements left * in the FIFO. */ /* * tdm_real_slots is 2 because mask all except first 2 slots * our buffer is 2 slots * 8 bytes each, so set watermarks to a multiple of it * 8 words in our case */ wm = ssi_private->tdm_real_slots * 4; //ssi_private->use_dma ? ssi_private->fifo_depth - 2 :
ssi_private->fifo_depth;
writel(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm), &ssi->sfcsr); /* enable one FIFO */ write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1, 0); write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1, 0); /* disable SSI two-channel mode operation */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN, 0); /* * We keep the SSI disabled because if we enable it, then the * DMA controller will start. It's not supposed to start until * the SCR.TE (or SCR.RE) bit is set, but it does anyway. The * DMA controller will transfer one "BWC" of data (i.e. the * amount of data that the MR.BWC bits are set to). The reason * this is bad is because at this point, the PCM driver has not * finished initializing the DMA controller. */ /* Set default slot number -- 32 in our case */ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(ssi_private->tdm_slots)); write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(ssi_private->tdm_slots)); /* Set default word length -- 8 bits */ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, CCSR_SSI_SxCCR_WL(ssi_private->tdm_word_size)); write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, CCSR_SSI_SxCCR_WL(ssi_private->tdm_word_size)); /* enable the SSI */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN); /* * we are interested only at first 2 slots */ writel(~ssi_private->tdm_slots_enabled, &ssi->stmsk); writel(~ssi_private->tdm_slots_enabled, &ssi->srmsk); return 0;
}
SSI clock calculated and then enabled. Both TX and RX DMA channel are requested in the probe() function as below. and the corresponding TX and RX SDMA event in DTS are using the default from imx6sx.dtsi:
slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0); slave_config.dst_addr_width = width; slave_config.dst_maxburst = ssi_private->tdm_real_slots * 4; ret = dmaengine_slave_config(ssi_private->tx_chan, &slave_config); ssi_private->rx_chan = dma_request_slave_channel_reason(&pdev->dev, "rx"); slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0); slave_config.src_addr_width = width; slave_config.src_maxburst = ssi_private->tdm_real_slots * 4; ret = dmaengine_slave_config(ssi_private->rx_chan, &slave_config);
and setup before RDMAE and TDMAE bits, like this:
ssi_private->tx_buf = dma_alloc_coherent(NULL, buffer_len, &ssi_private->tx_dmaaddr, GFP_KERNEL); desc = dmaengine_prep_dma_cyclic(ssi_private->tx_chan, ssi_private->tx_dmaaddr, buffer_len, ssi_private->tdm_real_slots*4, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); desc->callback = dma_tx_callback; desc->callback_param = ssi_private; printk("TX: prepare for the DMA.\n"); dmaengine_submit(desc); dma_async_issue_pending(ssi_private->tx_chan); ssi_private->rx_buf = dma_alloc_coherent(NULL, buffer_len, &ssi_private->rx_dmaaddr, GFP_KERNEL); desc = dmaengine_prep_dma_cyclic(ssi_private->rx_chan, ssi_private->rx_dmaaddr, buffer_len, ssi_private->tdm_real_slots*4, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); desc->callback = dma_rx_callback; desc->callback_param = ssi_private; printk("RX: prepare for the DMA.\n"); dmaengine_submit(desc); dma_async_issue_pending(ssi_private->rx_chan);
Finally, the SSI's TX and RX parts are now enabled
scr = readl(&ssi->scr); scr |= CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE; /* enable both TX and RX SSI sections */ writel(scr, &ssi->scr);
Finally the SIER si programmed as:
struct ccsr_ssi __iomem *ssi = ssi_private->ssi; u32 sier = CCSR_SSI_SIER_RFF0_EN | CCSR_SSI_SIER_TFE0_EN;
/* * if DMA is enabled than allow SSI request for DMA transfers * otherwise normal interrupt requests */ if (ssi_private->use_dma>0) { sier |= CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_TDMAE; } if (ssi_private->use_dma>1 || !ssi_private->use_dma) { sier |= CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_TIE; } sier &= ~(CCSR_SSI_SIER_TDE1_EN | CCSR_SSI_SIER_TFE1_EN | CCSR_SSI_SIER_TFE0_EN | CCSR_SSI_SIER_TDE0_EN); writel(sier, &ssi->sier);
At this time I should see the DMA callbacks called every burst_size words. This behaviour doesn't really happen as I wish because I can see from a proc file that such callbacks are called from 1 to 20000 times and then anymore. This is also confirmed by the fact that the interrupt 34 (sdma) doesn't increase anymore but matches my internal counters collected within my callbacks. Here is what I can inspect from the data I have collected:
root@voneus-domus-imx6sx:~# cat /proc/domus_ssi_stats SSI TDM Info: PLL clk=66000000 SSI baudclk=49152000 ssi_phy=0x02028000 irq=78 fifo_depth=15 <---- this is what is read from DTS but not as watermark tdm_frame_rate=8000 tdm_slots=32 (real 2) tdm_word_size=8 tdm_slots_enabled=00000000000000000000000000000011 clk_frequency=2048000 clock_running=yes DMA=yes Dual FIFO=no RX DMA frame count=17121 RX DMA addr=0x9c692000 RX DMA buffer len=16 TX DMA frame count=17121 TX DMA addr=0x9c4aa000 TX DMA buffer len=16
SSI Registers: ssi_scr=0x0000009f ssi_sier=0x00500004 ssi_stcr=0x000002e8 ssi_srcr=0x00000288 ssi_stccr=0x00007f0b ssi_srccr=0x00007f0b ssi_sfcsr=0x0088f088 ssi_stmsk=0xfffffffc ssi_srmsk=0xfffffffc
Cheers, Roberto Fichera.
And here's Nicolin's reply:
On Fri, Oct 30, 2015 at 12:42:53PM +0100, Roberto Fichera wrote:
/* * Set the watermark for transmit FIFI 0 and receive FIFO 0. We * don't use FIFO 1. We program the transmit water to signal a * DMA transfer if there are only two (or fewer) elements left * in the FIFO. */
SSI clock calculated and then enabled. Both TX and RX DMA channel are requested in the probe() function as below. and the corresponding TX and RX SDMA event in DTS are using the default from imx6sx.dtsi:
Since you are using single FIFO configuration, which SDMA script are you using? This should reflects in the Device Tree. As far as I learned, FSL 3.14 is using number 22 for SSIs which is the one for Dual FIFO Mode.
No! Currently is 1. Here the Freescale's v3.14.28 GA imx6sx.dtsi entry
ssi1: ssi@02028000 { compatible = "fsl,imx6sx-ssi", "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_SSI1_IPG>, <&clks IMX6SX_CLK_SSI1>; clock-names = "ipg", "baud"; dmas = <&sdma 37 1 0>, <&sdma 38 1 0>; dma-names = "rx", "tx"; status = "disabled"; };
At this time I should see the DMA callbacks called every burst_size words. This behaviour doesn't really happen as I wish because I can see from a proc file that such callbacks are called from 1 to 20000 times and then anymore. This is also confirmed by the fact that the interrupt 34 (sdma) doesn't increase anymore but matches my internal counters collected within my callbacks. Here is what I can inspect from the data I have collected:
Just for clarification, the behaviour doesn't happen as you wish is just the DMA stopped? I remember you also mentioned bit clock has stopped as you can check the clock status from the Codec chip.
Sorry, maybe I've used a wrong sentence. All clocks to SLIC are currently ok, checked with a logical analyser and both are working as expected.
SSI Registers: ssi_sfcsr=0x0088f088
At this point you have data in RxFIFO and get empty in TxFIFO, so the DMA requests from both side should be issued. If the DMA stops as you described, you must check those two channels from the SDMA side by dumping SDMAARM_STOP_STAT, SDMAARM_HSTART, SDMAARM_EVTOVR, SDMAARM_EVTPEND, SDMAARM_EVTERR, SDMAARM_DSPOVR and SDMAARM_HOSTOVR registers.
Ok! I will do! Should I do within the SDMA isr or do you prefer another place?
Overall, I don't see an obvious defect from you SSI side, but you may also try to toggle TDMAE and RDMAE at the point that callback stops -- re-raise the DMA requests by disabling and enabling TDMAE and RDMAE again and see if it works. I think either something did intervene register controls of SDMA or SSI,
I will try this one.
or SDMA have missed the request signals from SSI.
This is my current thought. However since the SSI is not operating at so high rate and the Cabel's problem seems going to a solution then I think there is something else I'm missing.
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Hi Roberto,
On Sat, Oct 31, 2015 at 7:16 AM, Roberto Fichera kernel@tekno-soft.it wrote:
Since you are using single FIFO configuration, which SDMA script are you using? This should reflects in the Device Tree. As far as I learned, FSL 3.14 is using number 22 for SSIs which is the one for Dual FIFO Mode.
No! Currently is 1. Here the Freescale's v3.14.28 GA imx6sx.dtsi entry
ssi1: ssi@02028000 { compatible = "fsl,imx6sx-ssi", "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_SSI1_IPG>, <&clks IMX6SX_CLK_SSI1>; clock-names = "ipg", "baud"; dmas = <&sdma 37 1 0>, <&sdma 38 1 0>; dma-names = "rx", "tx"; status = "disabled"; };
Take a look at imx_3.14.38_6ul_ga branch; It does use 22 in the dmas nodes: http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/arch/arm/bo...
However, this list is only about mainline kernel, so please run all your tests with mainline instead of FSL 3.14.
On 11/01/2015 09:31 PM, Fabio Estevam wrote:
Hi Fabio,
Hi Roberto,
On Sat, Oct 31, 2015 at 7:16 AM, Roberto Fichera kernel@tekno-soft.it wrote:
Since you are using single FIFO configuration, which SDMA script are you using? This should reflects in the Device Tree. As far as I learned, FSL 3.14 is using number 22 for SSIs which is the one for Dual FIFO Mode.
No! Currently is 1. Here the Freescale's v3.14.28 GA imx6sx.dtsi entry
ssi1: ssi@02028000 { compatible = "fsl,imx6sx-ssi", "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_SSI1_IPG>, <&clks IMX6SX_CLK_SSI1>; clock-names = "ipg", "baud"; dmas = <&sdma 37 1 0>, <&sdma 38 1 0>; dma-names = "rx", "tx"; status = "disabled"; };
Take a look at imx_3.14.38_6ul_ga branch; It does use 22 in the dmas nodes: http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/arch/arm/bo...
However, this list is only about mainline kernel, so please run all your tests with mainline instead of FSL 3.14.
Ok! I'm doing that right now.
On 10/31/2015 10:16 AM, Roberto Fichera wrote:
And here's Nicolin's reply: On Fri, Oct 30, 2015 at 12:42:53PM +0100, Roberto Fichera wrote:
/* * Set the watermark for transmit FIFI 0 and receive FIFO 0. We * don't use FIFO 1. We program the transmit water to signal a * DMA transfer if there are only two (or fewer) elements left * in the FIFO. */
SSI clock calculated and then enabled. Both TX and RX DMA channel are requested in the probe() function as below. and the corresponding TX and RX SDMA event in DTS are using the default from imx6sx.dtsi:
Since you are using single FIFO configuration, which SDMA script are you using? This should reflects in the Device Tree. As far as I learned, FSL 3.14 is using number 22 for SSIs which is the one for Dual FIFO Mode.
No! Currently is 1. Here the Freescale's v3.14.28 GA imx6sx.dtsi entry
ssi1: ssi@02028000 { compatible = "fsl,imx6sx-ssi", "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_SSI1_IPG>, <&clks IMX6SX_CLK_SSI1>; clock-names = "ipg", "baud"; dmas = <&sdma 37 1 0>, <&sdma 38 1 0>; dma-names = "rx", "tx"; status = "disabled"; };
At this time I should see the DMA callbacks called every burst_size words. This behaviour doesn't really happen as I wish because I can see from a proc file that such callbacks are called from 1 to 20000 times and then anymore. This is also confirmed by the fact that the interrupt 34 (sdma) doesn't increase anymore but matches my internal counters collected within my callbacks. Here is what I can inspect from the data I have collected:
Just for clarification, the behaviour doesn't happen as you wish is just the DMA stopped? I remember you also mentioned bit clock has stopped as you can check the clock status from the Codec chip.
Sorry, maybe I've used a wrong sentence. All clocks to SLIC are currently ok, checked with a logical analyser and both are working as expected.
SSI Registers: ssi_sfcsr=0x0088f088
At this point you have data in RxFIFO and get empty in TxFIFO, so the DMA requests from both side should be issued. If the DMA stops as you described, you must check those two channels from the SDMA side by dumping SDMAARM_STOP_STAT, SDMAARM_HSTART, SDMAARM_EVTOVR, SDMAARM_EVTPEND, SDMAARM_EVTERR, SDMAARM_DSPOVR and SDMAARM_HOSTOVR registers.
Ok! I will do! Should I do within the SDMA isr or do you prefer another place?
Below there is both SSI and SDMA status as soon as SDMA stops operating, I've also moved all code to kernel v4.3 just published this morning:
root@voneus-domus-imx6sx:~# cat /proc/domus_ssi_stats SSI TDM Info: PLL clk=66000000 SSI baudclk=49152000 ssi_phy=0x02028000 irq=21 fifo_depth=8 tdm_frame_rate=8000 tdm_slots=32 (real 2) tdm_word_size=8 tdm_slots_enabled=00000000000000000000000000000011 clk_frequency=2048000 clock_running=yes DMA=yes Dual FIFO=no RX DMA frame count=33758 RX DMA addr=0x9edad000 RX DMA buffer len=16 TX DMA frame count=33758 TX DMA addr=0x9ed7f000 TX DMA buffer len=16
SSI Registers: ssi_scr=0x0000009f ssi_sier=0x00500004 ssi_stcr=0x000002e8 ssi_srcr=0x00000288 ssi_stccr=0x00007f0b ssi_srccr=0x00007f0b ssi_sfcsr=0x0088f088 ssi_stmsk=0xfffffffc ssi_srmsk=0xfffffffc
SSI SISR Register: rfrc=0 tfrc=0 cmdau=0 cmddu=0 rxt=0 rdr1=0 rdr0=0 tde1=0 tde0=0 roe1=0 roe0=0 tue1=0 tue0=0 tfs=0 rfs=0 tls=0 rls=0 rff1=0 rff0=0 tfe1=0 tfe0=0
SDMA RX channel: SDMA channel 4 status SDMA_H_STATSTOP=0x00000000 SDMA_H_START=0x00000000 SDMA_H_EVTOVR=0x00000001 SDMA_H_EVTPEND=0x0000001a SDMA_H_EVTERR=0x00000018 SDMA_H_DSPOVR=0xffffffff SDMA_H_HOSTOVR=0x00000000
SDMA TX channel: SDMA channel 3 status SDMA_H_STATSTOP=0x00000000 SDMA_H_START=0x00000000 SDMA_H_EVTOVR=0x00000001 SDMA_H_EVTPEND=0x0000001a SDMA_H_EVTERR=0x00000000 SDMA_H_DSPOVR=0xffffffff SDMA_H_HOSTOVR=0x00000000
Overall, I don't see an obvious defect from you SSI side, but you may also try to toggle TDMAE and RDMAE at the point that callback stops -- re-raise the DMA requests by disabling and enabling TDMAE and RDMAE again and see if it works. I think either something did intervene register controls of SDMA or SSI,
I will try this one.
I will go over this tomorrow morning.
or SDMA have missed the request signals from SSI.
This is my current thought. However since the SSI is not operating at so high rate and the Cabel's problem seems going to a solution then I think there is something else I'm missing.
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On 11/02/2015 06:51 PM, Roberto Fichera wrote:
Overall, I don't see an obvious defect from you SSI side, but you may also try to toggle TDMAE and RDMAE at the point that callback stops -- re-raise the DMA requests by disabling and enabling TDMAE and RDMAE again and see if it works. I think either something did intervene register controls of SDMA or SSI,
I will try this one.
I will go over this tomorrow morning.
I've tried it just now but doesn't work at all! I'm getting only 2 sdma transfers.
On Mon, Nov 2, 2015 at 10:03 AM, Roberto Fichera kernel@tekno-soft.it wrote:
On 11/02/2015 06:51 PM, Roberto Fichera wrote:
Overall, I don't see an obvious defect from you SSI side, but you may also try to toggle TDMAE and RDMAE at the point that callback stops -- re-raise the DMA requests by disabling and enabling TDMAE and RDMAE again and see if it works. I think either something did intervene register controls of SDMA or SSI,
I will try this one.
I will go over this tomorrow morning.
I've tried it just now but doesn't work at all! I'm getting only 2 sdma transfers.
Heh, now I'm getting perhaps a similar issue -- transfers just stop for no good reason.
I can use aplay all day long, and the transfers work great. Even arecord + aplay together seem to work fine.
However, when I use my portaudio based ramp checker, it runs from between 1 frame and several thousand, then the callbacks stop. I don't know if this is a portaudio problem or an alsa problem -- i don't think I've seen the issue outside portaudio.
Jackd seems to run okay too (I'm running an overnight full duplex test now).
roberto, what user space library are you using? Alsa directly, or portaudio, or something else? it looks like your data rate is quite manageable, right? 8kHz, 8 slots, 8 bits? For me, it's a little better at 16kHz than 48kHz, but still just quits working after a while.
What's your experience of play vs. record, vs. full duplex?
-Caleb
On 11/03/2015 01:56 AM, Caleb Crome wrote:
On Mon, Nov 2, 2015 at 10:03 AM, Roberto Fichera kernel@tekno-soft.it wrote:
On 11/02/2015 06:51 PM, Roberto Fichera wrote:
> Overall, I don't see an obvious defect from you SSI side, but you > may also try to toggle TDMAE and RDMAE at the point that callback > stops -- re-raise the DMA requests by disabling and enabling TDMAE > and RDMAE again and see if it works. I think either something did > intervene register controls of SDMA or SSI,
I will try this one.
I will go over this tomorrow morning.
I've tried it just now but doesn't work at all! I'm getting only 2 sdma transfers.
Heh, now I'm getting perhaps a similar issue -- transfers just stop for no good reason.
I can use aplay all day long, and the transfers work great. Even arecord + aplay together seem to work fine.
However, when I use my portaudio based ramp checker, it runs from between 1 frame and several thousand, then the callbacks stop. I don't know if this is a portaudio problem or an alsa problem -- i don't think I've seen the issue outside portaudio.
Jackd seems to run okay too (I'm running an overnight full duplex test now).
roberto, what user space library are you using? Alsa directly, or portaudio, or something else?
All is in kernel space, and as I've already said it's dahdi driver for a voip app. The starting point I've used is fsl_ssi.c. I've removed most of the code not related to TDM. Then I've added my dma support to move samples from TDM to a dahdi audio sample buffer. So it's supposed to be a very skinny TDM driver for SSI in normal and synch mode.
it looks like your data rate is quite manageable, right? 8kHz, 8 slots, 8 bits? For me, it's a little better at 16kHz than 48kHz, but still just quits working after a while.
BCLK@2048KHz, FSYNC@8KHz, 32 slots at 8 bits but I'm masking all except the first 2 I need.
What's your experience of play vs. record, vs. full duplex?
Channels should be full duplex, and the samples has to go in dahdi buffer finally used by asterisk as audio channel.
I'm currently thinking if would be better to write my driver as plain audio codec. This means that I'll have to write my dahdi driver on top of either PCM or SND framework, all within kernel space. But I guess this will over-complicate the things compared to a straight TDM byte sequence, considering also that I'll have to learn the sound API.
-Caleb
On Sat, Oct 31, 2015 at 2:16 AM, Roberto Fichera kernel@tekno-soft.it wrote:
On 10/30/2015 07:01 PM, Caleb Crome wrote:
Hi All, is it okay of we split Roberto's problem from mine? It's getting difficult to track which response goes to which problem :-)
I included Roberto's email, and Nicolin's reply below:
So, this thread is for the hanging problem, the prehistory for this thread is in, "fsl_ssi.c: Getting channel slips with fsl_ssi.c in TDM (network) mode."
That's fine! Thanks Calab!
-Caleb
On Fri, Oct 30, 2015 at 4:42 AM, Roberto Fichera kernel@tekno-soft.it wrote:
On 10/30/2015 12:04 AM, Nicolin Chen wrote:
On Wed, Oct 28, 2015 at 09:11:39AM +0100, Roberto Fichera wrote:
I'm also having the same issue but employing SSI in TDM master mode against a SLIC Si32178 using its PCM mode. PCLK is at 2048KHz, FSYNC is 8KHz slot length is 32 bits (SSI wants this since when in master mode) but valid data set to be 8bits in the SSI register. My Current situation is that I've a custom fsl_ssi.c driver to control the SSI in TDM master mode both PCLK and FSYNC works perfectly fine, the SLIC has a register that I can check via SPI for such purpose, I can see the clocking status from its side. The main problem I've is exactly the same Caleb is having, after a certain amount of SDMA transfers, roughly 1000 or so, everything stops without any apparent reason.
I will start to help you to figure out your problem. But it seems that you are having a different issue here with clock generation. I don't get why you said *same issue*. For double confirm, the the "everything stops" mentioned, does it mean that clock from SSI stops?
Definitively yes! My problem is different than Caleb's one. Just to summarize the things. I've the SSI1 connected to a SiLabs SLIC Si32178 via AUDMUX6 padmux is below:
pinctrl_audmux_1: audmuxgrp-3 { fsl,pins = < MX6SX_PAD_SD3_DATA1__AUDMUX_AUD6_TXC 0x130b0 /* PCLK */ MX6SX_PAD_SD3_DATA2__AUDMUX_AUD6_TXFS 0x130b0 /* FSYNC */ MX6SX_PAD_SD3_DATA0__AUDMUX_AUD6_RXD 0x130b0 /* DTX */ MX6SX_PAD_SD3_DATA3__AUDMUX_AUD6_TXD 0x120b0 /* DRX */ >; };
The Si32178 is slave device so the SSI1 has to generate both BCLK and FSYNC. I've configured the AUDMUX as:
int si3217x_audmux_config(unsigned int master, unsigned int slave) { unsigned int ptcr, pdcr;
ptcr = IMX_AUDMUX_V2_PTCR_SYN | IMX_AUDMUX_V2_PTCR_TFSDIR | IMX_AUDMUX_V2_PTCR_TFSEL(master) | IMX_AUDMUX_V2_PTCR_TCLKDIR | IMX_AUDMUX_V2_PTCR_TCSEL(master); pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master); si3217x_audmux_v2_configure_port(slave, ptcr, pdcr); /* configure internal port */
ptcr = IMX_AUDMUX_V2_PTCR_SYN; pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave); si3217x_audmux_v2_configure_port(master, ptcr, pdcr); /* configure external port */
return 0; }
BCLK is 2048KHz, FSYNC@8KHz, frame is 32 slots at 8bits each. Looking at TXC and TXFS with a logical analyzer everything looks ok.
The SSI is setup at beginning as:
unsigned long flags; struct ccsr_ssi __iomem *ssi = ssi_private->ssi; u32 srcr; u8 wm; clk_prepare_enable(ssi_private->clk); /* * Section 16.5 of the MPC8610 reference manual says that the * SSI needs to be disabled before updating the registers we set * here. */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); /* * Program the SSI into I2S Master Network Synchronous mode. * Also enable the transmit and receive FIFO. */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_NET | CCSR_SSI_SCR_SYS_CLK_EN); /* * TX falling edge PCLK is mandatory because the RX SLIC side works in this way */ writel( CCSR_SSI_STCR_TXBIT0 /* LSB Aligned */ | CCSR_SSI_STCR_TFEN0 /* Enable TX FIFO0 */ | CCSR_SSI_STCR_TSCKP /* Transmit Clock Polarity - Data Clocked out on falling edge */ | CCSR_SSI_STCR_TFDIR /* Transmit Frame Direction Internal - generated internally */ | CCSR_SSI_STCR_TXDIR, /* Transmit Clock Direction Internal - generated internally */ &ssi->stcr); srcr = readl(&ssi->srcr); /* * clear out RFDIR and RXDIR because the clock is synchronous */ srcr &= ~(CCSR_SSI_SRCR_RFDIR | CCSR_SSI_SRCR_RXDIR); srcr |= CCSR_SSI_SRCR_RXBIT0 /* LSB Aligned */ | CCSR_SSI_SRCR_RFEN0 /* Enable RX FIFO0 */ | CCSR_SSI_SRCR_RSCKP /* Receive Clock Polarity - Data latched on rising edge */ ; writel(srcr, &ssi->srcr); /* do not service the isr yet */ writel(0, &ssi->sier); /* * Set the watermark for transmit FIFI 0 and receive FIFO 0. We * don't use FIFO 1. We program the transmit water to signal a * DMA transfer if there are only two (or fewer) elements left * in the FIFO. */ /* * tdm_real_slots is 2 because mask all except first 2 slots * our buffer is 2 slots * 8 bytes each, so set watermarks to a multiple of it * 8 words in our case */ wm = ssi_private->tdm_real_slots * 4; //ssi_private->use_dma ? ssi_private->fifo_depth - 2 :
ssi_private->fifo_depth;
writel(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm), &ssi->sfcsr); /* enable one FIFO */ write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1, 0); write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1, 0); /* disable SSI two-channel mode operation */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN, 0); /* * We keep the SSI disabled because if we enable it, then the * DMA controller will start. It's not supposed to start until * the SCR.TE (or SCR.RE) bit is set, but it does anyway. The * DMA controller will transfer one "BWC" of data (i.e. the * amount of data that the MR.BWC bits are set to). The reason * this is bad is because at this point, the PCM driver has not * finished initializing the DMA controller. */ /* Set default slot number -- 32 in our case */ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(ssi_private->tdm_slots)); write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(ssi_private->tdm_slots)); /* Set default word length -- 8 bits */ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, CCSR_SSI_SxCCR_WL(ssi_private->tdm_word_size)); write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, CCSR_SSI_SxCCR_WL(ssi_private->tdm_word_size)); /* enable the SSI */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN); /* * we are interested only at first 2 slots */ writel(~ssi_private->tdm_slots_enabled, &ssi->stmsk); writel(~ssi_private->tdm_slots_enabled, &ssi->srmsk); return 0;
}
SSI clock calculated and then enabled. Both TX and RX DMA channel are requested in the probe() function as below. and the corresponding TX and RX SDMA event in DTS are using the default from imx6sx.dtsi:
slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0); slave_config.dst_addr_width = width; slave_config.dst_maxburst = ssi_private->tdm_real_slots * 4; ret = dmaengine_slave_config(ssi_private->tx_chan, &slave_config); ssi_private->rx_chan = dma_request_slave_channel_reason(&pdev->dev, "rx"); slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0); slave_config.src_addr_width = width; slave_config.src_maxburst = ssi_private->tdm_real_slots * 4; ret = dmaengine_slave_config(ssi_private->rx_chan, &slave_config);
and setup before RDMAE and TDMAE bits, like this:
ssi_private->tx_buf = dma_alloc_coherent(NULL, buffer_len, &ssi_private->tx_dmaaddr, GFP_KERNEL); desc = dmaengine_prep_dma_cyclic(ssi_private->tx_chan, ssi_private->tx_dmaaddr, buffer_len, ssi_private->tdm_real_slots*4, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); desc->callback = dma_tx_callback; desc->callback_param = ssi_private; printk("TX: prepare for the DMA.\n"); dmaengine_submit(desc); dma_async_issue_pending(ssi_private->tx_chan); ssi_private->rx_buf = dma_alloc_coherent(NULL, buffer_len, &ssi_private->rx_dmaaddr, GFP_KERNEL); desc = dmaengine_prep_dma_cyclic(ssi_private->rx_chan, ssi_private->rx_dmaaddr, buffer_len, ssi_private->tdm_real_slots*4, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); desc->callback = dma_rx_callback; desc->callback_param = ssi_private; printk("RX: prepare for the DMA.\n"); dmaengine_submit(desc); dma_async_issue_pending(ssi_private->rx_chan);
Finally, the SSI's TX and RX parts are now enabled
scr = readl(&ssi->scr); scr |= CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE; /* enable both TX and RX SSI sections */ writel(scr, &ssi->scr);
Finally the SIER si programmed as:
struct ccsr_ssi __iomem *ssi = ssi_private->ssi; u32 sier = CCSR_SSI_SIER_RFF0_EN | CCSR_SSI_SIER_TFE0_EN;
/* * if DMA is enabled than allow SSI request for DMA transfers * otherwise normal interrupt requests */ if (ssi_private->use_dma>0) { sier |= CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_TDMAE; } if (ssi_private->use_dma>1 || !ssi_private->use_dma) { sier |= CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_TIE; } sier &= ~(CCSR_SSI_SIER_TDE1_EN | CCSR_SSI_SIER_TFE1_EN | CCSR_SSI_SIER_TFE0_EN | CCSR_SSI_SIER_TDE0_EN); writel(sier, &ssi->sier);
At this time I should see the DMA callbacks called every burst_size words. This behaviour doesn't really happen as I wish because I can see from a proc file that such callbacks are called from 1 to 20000 times and then anymore. This is also confirmed by the fact that the interrupt 34 (sdma) doesn't increase anymore but matches my internal counters collected within my callbacks. Here is what I can inspect from the data I have collected:
root@voneus-domus-imx6sx:~# cat /proc/domus_ssi_stats SSI TDM Info: PLL clk=66000000 SSI baudclk=49152000 ssi_phy=0x02028000 irq=78 fifo_depth=15 <---- this is what is read from DTS but not as watermark tdm_frame_rate=8000 tdm_slots=32 (real 2) tdm_word_size=8 tdm_slots_enabled=00000000000000000000000000000011 clk_frequency=2048000 clock_running=yes DMA=yes Dual FIFO=no RX DMA frame count=17121 RX DMA addr=0x9c692000 RX DMA buffer len=16 TX DMA frame count=17121 TX DMA addr=0x9c4aa000 TX DMA buffer len=16
SSI Registers: ssi_scr=0x0000009f ssi_sier=0x00500004 ssi_stcr=0x000002e8 ssi_srcr=0x00000288 ssi_stccr=0x00007f0b ssi_srccr=0x00007f0b ssi_sfcsr=0x0088f088 ssi_stmsk=0xfffffffc ssi_srmsk=0xfffffffc
Cheers, Roberto Fichera.
And here's Nicolin's reply:
On Fri, Oct 30, 2015 at 12:42:53PM +0100, Roberto Fichera wrote:
/* * Set the watermark for transmit FIFI 0 and receive FIFO 0. We * don't use FIFO 1. We program the transmit water to signal a * DMA transfer if there are only two (or fewer) elements left * in the FIFO. */
SSI clock calculated and then enabled. Both TX and RX DMA channel are requested in the probe() function as below. and the corresponding TX and RX SDMA event in DTS are using the default from imx6sx.dtsi:
Since you are using single FIFO configuration, which SDMA script are you using? This should reflects in the Device Tree. As far as I learned, FSL 3.14 is using number 22 for SSIs which is the one for Dual FIFO Mode.
No! Currently is 1. Here the Freescale's v3.14.28 GA imx6sx.dtsi entry
ssi1: ssi@02028000 { compatible = "fsl,imx6sx-ssi", "fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SX_CLK_SSI1_IPG>, <&clks IMX6SX_CLK_SSI1>; clock-names = "ipg", "baud"; dmas = <&sdma 37 1 0>, <&sdma 38 1 0>; dma-names = "rx", "tx"; status = "disabled"; };
At this time I should see the DMA callbacks called every burst_size words. This behaviour doesn't really happen as I wish because I can see from a proc file that such callbacks are called from 1 to 20000 times and then anymore. This is also confirmed by the fact that the interrupt 34 (sdma) doesn't increase anymore but matches my internal counters collected within my callbacks. Here is what I can inspect from the data I have collected:
Just for clarification, the behaviour doesn't happen as you wish is just the DMA stopped? I remember you also mentioned bit clock has stopped as you can check the clock status from the Codec chip.
Sorry, maybe I've used a wrong sentence. All clocks to SLIC are currently ok, checked with a logical analyser and both are working as expected.
SSI Registers: ssi_sfcsr=0x0088f088
At this point you have data in RxFIFO and get empty in TxFIFO, so the DMA requests from both side should be issued. If the DMA stops as you described, you must check those two channels from the SDMA side by dumping SDMAARM_STOP_STAT, SDMAARM_HSTART, SDMAARM_EVTOVR, SDMAARM_EVTPEND, SDMAARM_EVTERR, SDMAARM_DSPOVR and SDMAARM_HOSTOVR registers.
Ok! I will do! Should I do within the SDMA isr or do you prefer another place?
Overall, I don't see an obvious defect from you SSI side, but you may also try to toggle TDMAE and RDMAE at the point that callback stops -- re-raise the DMA requests by disabling and enabling TDMAE and RDMAE again and see if it works. I think either something did intervene register controls of SDMA or SSI,
I will try this one.
or SDMA have missed the request signals from SSI.
This is my current thought. However since the SSI is not operating at so high rate and the Cabel's problem seems going to a solution then I think there is something else I'm missing.
Is it possible that the event type below in the reference manual section 55.10.5 is happening? It looks like the SDMA script is supposed to deal with it. Perhaps there's a bug in the script?
55.10.5 External DMA Requests Mirror (SDMACORE_EVENTS) NOTE This register is very useful in the case of DMA requests that are active when a peripheral FIFO level is above the programmed watermark. The activation of the DMA request (rising edge) is detected by the SDMA logic and it can enable one or several channels. One of the channels accesses the peripheral and reads or writes a number of data that matches the watermark level (for example, if the watermark is four words, the channel reads or writes four words). If the channel is effectively executed long after the DMA request was received, reading or writing the watermark number of data may not be sufficient to reset the DMA request (for example, if the FIFO watermark is four and at the channel execution it already contains nine pieces of data). This means no new rising edge may be detected by the SDMA, although there still remains transfers to perform. Therefore, if the channel were terminated at that time, it would not be restarted, causing potential overrun or underrun of the peripheral. The proposed mechanism is for the channel to check this register after it has performed the "watermark" number of accesses to the peripheral. If the bit for the DMA request that triggers this channel is set, it means there is still another watermark number of data to transfer. This goes on until the bit is cleared. The same script can be used for multiple channels that require this behavior. The script can determine its channel number from the CCR register and infer the corresponding DMA request bit to check. It needs a reference table that is coherent with the request-channel matrix that the ARM platform programmed.
On 11/03/2015 10:26 PM, Caleb Crome wrote:
or SDMA have missed the request signals from SSI.
This is my current thought. However since the SSI is not operating at so high rate and the Cabel's problem seems going to a solution then I think there is something else I'm missing.
Is it possible that the event type below in the reference manual section 55.10.5 is happening? It looks like the SDMA script is supposed to deal with it. Perhaps there's a bug in the script?
55.10.5 External DMA Requests Mirror (SDMACORE_EVENTS) NOTE This register is very useful in the case of DMA requests that are active when a peripheral FIFO level is above the programmed watermark. The activation of the DMA request (rising edge) is detected by the SDMA logic and it can enable one or several channels. One of the channels accesses the peripheral and reads or writes a number of data that matches the watermark level (for example, if the watermark is four words, the channel reads or writes four words). If the channel is effectively executed long after the DMA request was received, reading or writing the watermark number of data may not be sufficient to reset the DMA request (for example, if the FIFO watermark is four and at the channel execution it already contains nine pieces of data). This means no new rising edge may be detected by the SDMA, although there still remains transfers to perform. Therefore, if the channel were terminated at that time, it would not be restarted, causing potential overrun or underrun of the peripheral. The proposed mechanism is for the channel to check this register after it has performed the "watermark" number of accesses to the peripheral. If the bit for the DMA request that triggers this channel is set, it means there is still another watermark number of data to transfer. This goes on until the bit is cleared. The same script can be used for multiple channels that require this behavior. The script can determine its channel number from the CCR register and infer the corresponding DMA request bit to check. It needs a reference table that is coherent with the request-channel matrix that the ARM platform programmed.
Maybe this is the cause! I've explored a bit what's going on with my DMA stall and I've found that both RX and TX channels are getting an error, at least this is what the EVTERR register is reporting. See the log below:
root@voneus-domus-imx6sx:~# cat /proc/domus_ssi_stats SSI TDM Info: IPG clk=66000000 SSI baudclk=8192000 ssi_phy=0x02028000 irq=21 fifo_depth=10 tdm_frame_rate=8000 tdm_slots=32 (real 2) tdm_word_size=8 tdm_slots_enabled=00000000000000000000000000000011 clk_frequency=2048000 clock_running=yes DMA=yes Dual FIFO=no *RX DMA frame count=36795* RX DMA addr=0x9ef0e000 RX DMA buffer len=16 *TX DMA frame count=36795* TX DMA addr=0x9ee49000 TX DMA buffer len=16
SSI Registers: ssi_scr=0x0000109f ssi_sier=0x00500504 ssi_stcr=0x000002e8 ssi_srcr=0x00000288 ssi_stccr=0x00007f01 ssi_srccr=0x00007f01 ssi_sfcsr=0x00aaf0aa ssi_stmsk=0xfffffffc ssi_srmsk=0xfffffffc
SDMA RX channel: SDMA channel 4 status SDMA_H_STATSTOP=0x00000000 SDMA_H_START=0x00000000 SDMA_H_EVTOVR=0x00000001 SDMA_H_EVTPEND=0x0000001a SDMA_H_EVTERR=0x00000000 SDMA_H_DSPOVR=0xffffffff SDMA_H_HOSTOVR=0x00000000 SDMA_H_INTR=0x00000000 SDMA_H_INTRMSK=0x00000018 SDMACORE_EVENTS=0x00000000 SDMACORE_EVENTS2=0x00000000
SDMA EVTERR channel counters: * 003 = 1** ** 004 = 1*
SDMA TX channel: SDMA channel 3 status SDMA_H_STATSTOP=0x00000000 SDMA_H_START=0x00000000 SDMA_H_EVTOVR=0x00000001 SDMA_H_EVTPEND=0x0000001a SDMA_H_EVTERR=0x00000000 SDMA_H_DSPOVR=0xffffffff SDMA_H_HOSTOVR=0x00000000 SDMA_H_INTR=0x00000000 SDMA_H_INTRMSK=0x00000018 SDMACORE_EVENTS=0x00000000 SDMACORE_EVENTS2=0x00000000
SDMA EVTERR channel counters: * 003 = 1** ** 004 = 1*
root@voneus-domus-imx6sx:~# cat /proc/interrupts CPU0 16: 39485 GPC 55 Edge i.MX Timer Tick 20: 2310 GPC 26 Edge 2020000.serial 21: 0 GPC 46 Edge ssi-tdm 39: 0 gpio-mxc 12 Edge si3217x-irq 123: 0 gpio-mxc 28 Edge 2194000.usdhc cd 266: 0 GPC 49 Edge imx_thermal 271: 0 GPC 19 Edge rtc alarm *277: 36800 GPC 2 Edge sdma* 278: 0 GPC 43 Edge 2184000.usb 279: 2994 GPC 23 Edge mmc0 280: 245 GPC 25 Edge mmc1 283: 9 GPC 109 Edge 21e4000.qspi 284: 0 GPC 27 Edge 21e8000.serial 287: 50274 GPC 18 Edge 228c000.ecspi IPI0: 0 CPU wakeup interrupts IPI1: 0 Timer broadcast interrupts IPI2: 0 Rescheduling interrupts IPI3: 0 Function call interrupts IPI4: 0 Single function call interrupts IPI5: 0 CPU stop interrupts IPI6: 1 IRQ work interrupts IPI7: 0 completion interrupts Err: 0
This is the relevant part of the dmesg
[ 993.283774] dahdi: Version: [ 993.317161] dahdi: Telephony Interface Registered on major 196 [ 997.013802] si3217x_audmux_probe: AUDMUX base is 0xa0b10000 *[ 999.313971] sdma_disable_channel: Disabling EVTERR for channel 3** **[ 999.320620] sdma_disable_channel: Disabling EVTERR for channel 4* [ 999.326866] si3217x_ssi_probe: SSI base is 0xa0b20000 clock rate is 2048000Hz, TDM Frame rate 8000Hz, channels 32 having 8 bits word length [ 1002.733512] si3217x_probe: SPI setup mode 3, 8 bits/w, 10000000 Hz max [ 1002.740962] RX: prepare for the DMA. *[ 1002.744960] sdma_enable_channel: Enabling EVTERR for channel 4* [ 1002.752305] TX: prepare for the DMA. *[ 1002.756111] sdma_enable_channel: Enabling EVTERR for channel 3* [ 1002.762739] si3217x_ssi_set_clock: BIT_CLK=8192000, IPGCLK=66000000, PM=1 [ 1003.278453] Si3217x: isVerifiedProslic : chan(0) REG PCMTXHI VAL = 00 [ 1003.285624] Si3217x: isVerifiedProslic : Not a VDAA chan(0) REG PCMMODE VAL = 05 [ 1003.306492] SLIC verification OK [ 1003.310461] SPI ret=0, MSTRSTAT=0x1f [ 1003.314068] PCLK_VALID = 1 [ 1003.317115] FS_VALID = 1 [ 1003.319850] FS_DETECT = 1 [ 1003.322661] PLL_LOCK = 1 [ 1003.325385] SRAM_CLR = 1 [ 1003.328181] PCLK_FAULT = 0 [ 1003.331083] FS_FAULT = 0 [ 1003.333807] PLL_FAULT = 0 [ 1003.341485] Si3217x: isVerifiedProslic : chan(0) REG PCMTXHI VAL = 00 [ 1003.349140] Si3217x: isVerifiedProslic : Not a VDAA chan(0) REG PCMMODE VAL = 05 [ 1003.356601] Si3217x: Channel 0 : Type = PROSLIC [ 1003.362536] Si3217x: isVerifiedProslic : chan(1) REG PCMTXHI VAL = 40 [ 1003.369863] Si3217x: Channel 1 : Type = DAA [ 1003.374358] si3217x: Channel 0 : Type = 26 [ 1003.378515] si3217x: Channel 0 : Rev = 1 [ 1003.385623] Si3217x: loading patch: 12102012 [ 1007.624105] Si3217x: Channel 0 : VBAT Up = 62.754 v [ 1008.556990] Si3217x: PCMStart [ 1008.560526] Channel 0: FXS model Si32178 [ 1008.567449] Channel 1: FXO model Si32919 rev A [ 1008.591259] Found: Quadplay FXS/FXO Card
Basically for every DMA channel attached to a SSI peripheral I will enable the corresponding EVTERR bit for the given channel in order to detect if a DMA overflow condition might happen or not.
With the patch below I'm able to see the error happening. And more likely it happen just just afterwards the EVTERR notify the problem to the ISR. At this point the DMA simply stalls due to some problems, most likely because the SSI FIFO is in overflow or underflow condition. I will do add the code to dump the SSI registers once EVTERR is triggered.
I think that at this point we should in theory restart the DMA channel, but however how to fix this and why this is happening?
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 9d375bc..b9faf2d 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -50,6 +50,8 @@
/* SDMA registers */ #define SDMA_H_C0PTR 0x000 +#define SDMACORE_EVENTS 0x005 +#define SDMACORE_EVENTS2 0x01f #define SDMA_H_INTR 0x004 #define SDMA_H_STATSTOP 0x008 #define SDMA_H_START 0x00c @@ -385,6 +387,7 @@ struct sdma_engine { const struct sdma_driver_data *drvdata; u32 spba_start_addr; u32 spba_end_addr; + u32 evterrchannel[MAX_DMA_CHANNELS]; };
static struct sdma_driver_data sdma_imx31 = { @@ -562,7 +565,17 @@ static int sdma_config_ownership(struct sdma_channel *sdmac,
static void sdma_enable_channel(struct sdma_engine *sdma, int channel) { + struct sdma_channel *sdmac = &sdma->channel[channel]; + writel(BIT(channel), sdma->regs + SDMA_H_START); + + if ( sdmac->peripheral_type == IMX_DMATYPE_SSI_SP ) + { + u32 msk = readl(sdma->regs + SDMA_H_INTRMSK); + + writel(msk | BIT(channel), sdma->regs + SDMA_H_INTRMSK); + printk("%s: Enabling EVTERR for channel %d\n", __func__, channel); + } }
/* @@ -725,12 +738,26 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id) { struct sdma_engine *sdma = dev_id; unsigned long stat; + u32 evterr; + + /* read the EVTERR register */ + evterr = readl_relaxed(sdma->regs + SDMA_H_EVTERR); + if ( evterr ) + { + int bitnr; + + for_each_set_bit(bitnr, &evterr, sizeof(u32) * BITS_PER_BYTE) + sdma->evterrchannel[bitnr]++; + }
stat = readl_relaxed(sdma->regs + SDMA_H_INTR); /* not interested in channel 0 interrupts */ stat &= ~1; writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
+ /* we are interested only to channels not in error status */ + stat &= ~evterr; + while (stat) { int channel = fls(stat) - 1; struct sdma_channel *sdmac = &sdma->channel[channel]; @@ -908,6 +935,14 @@ static int sdma_disable_channel(struct dma_chan *chan) writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP); sdmac->status = DMA_ERROR;
+ if ( sdmac->peripheral_type == IMX_DMATYPE_SSI_SP ) + { + u32 msk = readl(sdma->regs + SDMA_H_INTRMSK); + + writel(msk & ~(BIT(channel)), sdma->regs + SDMA_H_INTRMSK); + printk("%s: Disabling EVTERR for channel %d\n", __func__, channel); + } + return 0; }
@@ -1650,6 +1685,44 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec, return dma_request_channel(mask, sdma_filter_fn, &data); }
+#include <linux/seq_file.h> + +#define SDMA_SHOW_REG(reg) \ + do { \ + u32 _val = readl(sdma->regs + reg); \ + seq_printf(s, "\t" #reg "=0x%08lx\n", _val); \ + } while (0) + +void sdma_show_chan_status(struct seq_file *s, struct dma_chan *chan) +{ + struct sdma_channel *sdmac = to_sdma_chan(chan); + struct sdma_engine *sdma = sdmac->sdma; + int i; + + seq_printf(s, "SDMA channel %d status\n", sdmac->channel); + SDMA_SHOW_REG(SDMA_H_STATSTOP); + SDMA_SHOW_REG(SDMA_H_START); + SDMA_SHOW_REG(SDMA_H_EVTOVR); + SDMA_SHOW_REG(SDMA_H_EVTPEND); + SDMA_SHOW_REG(SDMA_H_EVTERR); + SDMA_SHOW_REG(SDMA_H_DSPOVR); + SDMA_SHOW_REG(SDMA_H_HOSTOVR); + SDMA_SHOW_REG(SDMA_H_INTR); + SDMA_SHOW_REG(SDMA_H_INTRMSK); + SDMA_SHOW_REG(SDMACORE_EVENTS); + SDMA_SHOW_REG(SDMACORE_EVENTS2); + + seq_printf(s, "\nSDMA EVTERR channel counters:\n"); + for(i=0; i < MAX_DMA_CHANNELS; i++) + { + if (sdma->evterrchannel[i]) + { + seq_printf(s, "\t%03d = %lu\n", i, sdma->evterrchannel[i]); + } + } +} +EXPORT_SYMBOL_GPL(sdma_show_chan_status); + static int sdma_probe(struct platform_device *pdev) { const struct of_device_id *of_id =
On 11/04/2015 04:33 PM, Roberto Fichera wrote:
On 11/03/2015 10:26 PM, Caleb Crome wrote:
or SDMA have missed the request signals from SSI.
This is my current thought. However since the SSI is not operating at so high rate and the Cabel's problem seems going to a solution then I think there is something else I'm missing.
Is it possible that the event type below in the reference manual section 55.10.5 is happening? It looks like the SDMA script is supposed to deal with it. Perhaps there's a bug in the script?
55.10.5 External DMA Requests Mirror (SDMACORE_EVENTS) NOTE This register is very useful in the case of DMA requests that are active when a peripheral FIFO level is above the programmed watermark. The activation of the DMA request (rising edge) is detected by the SDMA logic and it can enable one or several channels. One of the channels accesses the peripheral and reads or writes a number of data that matches the watermark level (for example, if the watermark is four words, the channel reads or writes four words). If the channel is effectively executed long after the DMA request was received, reading or writing the watermark number of data may not be sufficient to reset the DMA request (for example, if the FIFO watermark is four and at the channel execution it already contains nine pieces of data). This means no new rising edge may be detected by the SDMA, although there still remains transfers to perform. Therefore, if the channel were terminated at that time, it would not be restarted, causing potential overrun or underrun of the peripheral. The proposed mechanism is for the channel to check this register after it has performed the "watermark" number of accesses to the peripheral. If the bit for the DMA request that triggers this channel is set, it means there is still another watermark number of data to transfer. This goes on until the bit is cleared. The same script can be used for multiple channels that require this behavior. The script can determine its channel number from the CCR register and infer the corresponding DMA request bit to check. It needs a reference table that is coherent with the request-channel matrix that the ARM platform programmed.
Maybe this is the cause! I've explored a bit what's going on with my DMA stall and I've found that both RX and TX channels are getting an error, at least this is what the EVTERR register is reporting. See the log below:
root@voneus-domus-imx6sx:~# cat /proc/domus_ssi_stats SSI TDM Info: IPG clk=66000000 SSI baudclk=8192000 ssi_phy=0x02028000 irq=21 fifo_depth=10 tdm_frame_rate=8000 tdm_slots=32 (real 2) tdm_word_size=8 tdm_slots_enabled=00000000000000000000000000000011 clk_frequency=2048000 clock_running=yes DMA=yes Dual FIFO=no *RX DMA frame count=36795* RX DMA addr=0x9ef0e000 RX DMA buffer len=16 *TX DMA frame count=36795* TX DMA addr=0x9ee49000 TX DMA buffer len=16
SSI Registers: ssi_scr=0x0000109f ssi_sier=0x00500504 ssi_stcr=0x000002e8 ssi_srcr=0x00000288 ssi_stccr=0x00007f01 ssi_srccr=0x00007f01 ssi_sfcsr=0x00aaf0aa ssi_stmsk=0xfffffffc ssi_srmsk=0xfffffffc
SDMA RX channel: SDMA channel 4 status SDMA_H_STATSTOP=0x00000000 SDMA_H_START=0x00000000 SDMA_H_EVTOVR=0x00000001 SDMA_H_EVTPEND=0x0000001a SDMA_H_EVTERR=0x00000000 SDMA_H_DSPOVR=0xffffffff SDMA_H_HOSTOVR=0x00000000 SDMA_H_INTR=0x00000000 SDMA_H_INTRMSK=0x00000018 SDMACORE_EVENTS=0x00000000 SDMACORE_EVENTS2=0x00000000
SDMA EVTERR channel counters:
003 = 1**
** 004 = 1*
SDMA TX channel: SDMA channel 3 status SDMA_H_STATSTOP=0x00000000 SDMA_H_START=0x00000000 SDMA_H_EVTOVR=0x00000001 SDMA_H_EVTPEND=0x0000001a SDMA_H_EVTERR=0x00000000 SDMA_H_DSPOVR=0xffffffff SDMA_H_HOSTOVR=0x00000000 SDMA_H_INTR=0x00000000 SDMA_H_INTRMSK=0x00000018 SDMACORE_EVENTS=0x00000000 SDMACORE_EVENTS2=0x00000000
SDMA EVTERR channel counters:
003 = 1**
** 004 = 1*
root@voneus-domus-imx6sx:~# cat /proc/interrupts CPU0 16: 39485 GPC 55 Edge i.MX Timer Tick 20: 2310 GPC 26 Edge 2020000.serial 21: 0 GPC 46 Edge ssi-tdm 39: 0 gpio-mxc 12 Edge si3217x-irq 123: 0 gpio-mxc 28 Edge 2194000.usdhc cd 266: 0 GPC 49 Edge imx_thermal 271: 0 GPC 19 Edge rtc alarm *277: 36800 GPC 2 Edge sdma* 278: 0 GPC 43 Edge 2184000.usb 279: 2994 GPC 23 Edge mmc0 280: 245 GPC 25 Edge mmc1 283: 9 GPC 109 Edge 21e4000.qspi 284: 0 GPC 27 Edge 21e8000.serial 287: 50274 GPC 18 Edge 228c000.ecspi IPI0: 0 CPU wakeup interrupts IPI1: 0 Timer broadcast interrupts IPI2: 0 Rescheduling interrupts IPI3: 0 Function call interrupts IPI4: 0 Single function call interrupts IPI5: 0 CPU stop interrupts IPI6: 1 IRQ work interrupts IPI7: 0 completion interrupts Err: 0
This is the relevant part of the dmesg
[ 993.283774] dahdi: Version: [ 993.317161] dahdi: Telephony Interface Registered on major 196 [ 997.013802] si3217x_audmux_probe: AUDMUX base is 0xa0b10000 *[ 999.313971] sdma_disable_channel: Disabling EVTERR for channel 3** **[ 999.320620] sdma_disable_channel: Disabling EVTERR for channel 4* [ 999.326866] si3217x_ssi_probe: SSI base is 0xa0b20000 clock rate is 2048000Hz, TDM Frame rate 8000Hz, channels 32 having 8 bits word length [ 1002.733512] si3217x_probe: SPI setup mode 3, 8 bits/w, 10000000 Hz max [ 1002.740962] RX: prepare for the DMA. *[ 1002.744960] sdma_enable_channel: Enabling EVTERR for channel 4* [ 1002.752305] TX: prepare for the DMA. *[ 1002.756111] sdma_enable_channel: Enabling EVTERR for channel 3* [ 1002.762739] si3217x_ssi_set_clock: BIT_CLK=8192000, IPGCLK=66000000, PM=1 [ 1003.278453] Si3217x: isVerifiedProslic : chan(0) REG PCMTXHI VAL = 00 [ 1003.285624] Si3217x: isVerifiedProslic : Not a VDAA chan(0) REG PCMMODE VAL = 05 [ 1003.306492] SLIC verification OK [ 1003.310461] SPI ret=0, MSTRSTAT=0x1f [ 1003.314068] PCLK_VALID = 1 [ 1003.317115] FS_VALID = 1 [ 1003.319850] FS_DETECT = 1 [ 1003.322661] PLL_LOCK = 1 [ 1003.325385] SRAM_CLR = 1 [ 1003.328181] PCLK_FAULT = 0 [ 1003.331083] FS_FAULT = 0 [ 1003.333807] PLL_FAULT = 0 [ 1003.341485] Si3217x: isVerifiedProslic : chan(0) REG PCMTXHI VAL = 00 [ 1003.349140] Si3217x: isVerifiedProslic : Not a VDAA chan(0) REG PCMMODE VAL = 05 [ 1003.356601] Si3217x: Channel 0 : Type = PROSLIC [ 1003.362536] Si3217x: isVerifiedProslic : chan(1) REG PCMTXHI VAL = 40 [ 1003.369863] Si3217x: Channel 1 : Type = DAA [ 1003.374358] si3217x: Channel 0 : Type = 26 [ 1003.378515] si3217x: Channel 0 : Rev = 1 [ 1003.385623] Si3217x: loading patch: 12102012 [ 1007.624105] Si3217x: Channel 0 : VBAT Up = 62.754 v [ 1008.556990] Si3217x: PCMStart [ 1008.560526] Channel 0: FXS model Si32178 [ 1008.567449] Channel 1: FXO model Si32919 rev A [ 1008.591259] Found: Quadplay FXS/FXO Card
Basically for every DMA channel attached to a SSI peripheral I will enable the corresponding EVTERR bit for the given channel in order to detect if a DMA overflow condition might happen or not.
With the patch below I'm able to see the error happening. And more likely it happen just just afterwards the EVTERR notify the problem to the ISR. At this point the DMA simply stalls due to some problems, most likely because the SSI FIFO is in overflow or underflow condition. I will do add the code to dump the SSI registers once EVTERR is triggered.
After apply the changes to dump the SSI register once the ISR is triggered by EVTERR the situation is the following:
[ 57.426204] SSI Registers: [ 57.428955] ssi_scr=0x0000109f [ 57.432117] ssi_sier=0x00500504 [ 57.435361] ssi_stcr=0x000002e8 [ 57.438603] ssi_srcr=0x00000288 [ 57.441845] ssi_stccr=0x00007f01 [ 57.445175] ssi_srccr=0x00007f01 [ 57.448504] ssi_sfcsr=0x00aaf0aa [ 57.451833] ssi_stmsk=0xfffffffc [ 57.455164] ssi_srmsk=0xfffffffc
Both TX and RX FIFO watermarks are set to maxburst + 2 = 10 in this run, the SFCSR register reports TX FIFO empty and RX FIFO full and SIER is asserting the related flags associated to this condition.
So why this is happening and the DMA transfer is not triggered? Maybe trying to increase the DMA priority might solve this problem?
On Wed, Nov 4, 2015 at 8:53 AM, Roberto Fichera kernel@tekno-soft.it wrote:
On 11/04/2015 04:33 PM, Roberto Fichera wrote:
*RX DMA frame count=36795* RX DMA addr=0x9ef0e000 RX DMA buffer len=16 *TX DMA frame count=36795* TX DMA addr=0x9ee49000 TX DMA buffer len=16
I notice your DMA buffer length is very short, which would require very frequency interrupts to service, right? Can you increase your DMA buffer length by increasing the period size? Maybe that would help reduce the likelyhood of a failure. Although it would be good to be able to recover from a failure gracefully. -Caleb
On 11/04/2015 06:41 PM, Caleb Crome wrote:
On Wed, Nov 4, 2015 at 8:53 AM, Roberto Fichera kernel@tekno-soft.it wrote:
On 11/04/2015 04:33 PM, Roberto Fichera wrote:
*RX DMA frame count=36795* RX DMA addr=0x9ef0e000 RX DMA buffer len=16 *TX DMA frame count=36795* TX DMA addr=0x9ee49000 TX DMA buffer len=16
I notice your DMA buffer length is very short, which would require very frequency interrupts to service, right? Can you increase your DMA buffer length by increasing the period size? Maybe that would help reduce the likelyhood of a failure.
Not sure if this can help! SSI TDM is set to 32 slots but only 2 are masked. So every frame only 2 slots are pushed/pulled from the FIFOs. maxburst is set to pull a block of 8 elements from the FIFOs, DMA cyclic call it period. So the full DMA buffer is filled in buffer size / period DMA iterations.
Although it would be good to be able to recover from a failure gracefully.
Yep! I will try to restart the DMA channels from a failure to see if this might work or not.
-Caleb _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On Wed, Nov 04, 2015 at 06:52:12PM +0100, Roberto Fichera wrote:
I notice your DMA buffer length is very short, which would require very frequency interrupts to service, right? Can you increase your DMA buffer length by increasing the period size? Maybe that would help reduce the likelyhood of a failure.
Not sure if this can help! SSI TDM is set to 32 slots but only 2 are masked. So every frame only 2 slots are pushed/pulled from the FIFOs. maxburst is set to pull a block of 8 elements from the FIFOs, DMA cyclic call it period. So the full DMA buffer is filled in buffer size / period DMA iterations.
A smaller period size may course DMA buffer over/underrun -- ALSA over/underrun even though it seems that you didn't report any.
And apparently SDMA would get more interrupt/callbacks. I would suggest a larger period size and buffer size although I cannot tie your problem with the size. But you may try.
On 11/04/2015 07:11 PM, Nicolin Chen wrote:
On Wed, Nov 04, 2015 at 06:52:12PM +0100, Roberto Fichera wrote:
I notice your DMA buffer length is very short, which would require very frequency interrupts to service, right? Can you increase your DMA buffer length by increasing the period size? Maybe that would help reduce the likelyhood of a failure.
Not sure if this can help! SSI TDM is set to 32 slots but only 2 are masked. So every frame only 2 slots are pushed/pulled from the FIFOs. maxburst is set to pull a block of 8 elements from the FIFOs, DMA cyclic call it period. So the full DMA buffer is filled in buffer size / period DMA iterations.
A smaller period size may course DMA buffer over/underrun -- ALSA over/underrun even though it seems that you didn't report any.
And apparently SDMA would get more interrupt/callbacks. I would suggest a larger period size and buffer size although I cannot tie your problem with the size. But you may try.
Do you mean something like 2KB buffer and a period of 64 or 128 frames? SDMA is supposed to wait the FIFO capacity to complete a period, right?
On 11/04/2015 07:11 PM, Nicolin Chen wrote:
On Wed, Nov 04, 2015 at 06:52:12PM +0100, Roberto Fichera wrote:
I notice your DMA buffer length is very short, which would require very frequency interrupts to service, right? Can you increase your DMA buffer length by increasing the period size? Maybe that would help reduce the likelyhood of a failure.
Not sure if this can help! SSI TDM is set to 32 slots but only 2 are masked. So every frame only 2 slots are pushed/pulled from the FIFOs. maxburst is set to pull a block of 8 elements from the FIFOs, DMA cyclic call it period. So the full DMA buffer is filled in buffer size / period DMA iterations.
A smaller period size may course DMA buffer over/underrun -- ALSA over/underrun even though it seems that you didn't report any.
And apparently SDMA would get more interrupt/callbacks. I would suggest a larger period size and buffer size although I cannot tie your problem with the size. But you may try.
Following your suggestion, I've increased the buffer size to 2K and set the period to fifo_length - 2 (13), with that I'm now running substantially smooth except 3 EVTERR on RX DMA over 4 million of interrupts.
Thanks Nicolin! I'm quite happy now!
On Thu, Nov 5, 2015 at 8:03 AM, Roberto Fichera kernel@tekno-soft.it wrote:
Following your suggestion, I've increased the buffer size to 2K and set the period to fifo_length - 2 (13), with that I'm now running substantially smooth except 3 EVTERR on RX DMA over 4 million of interrupts.
Thanks Nicolin! I'm quite happy now!
That's good progress, Roberto.
It would be nice if you and Caleb could post the patches to the mailing list.
On 11/05/2015 12:30 PM, Fabio Estevam wrote:
On Thu, Nov 5, 2015 at 8:03 AM, Roberto Fichera kernel@tekno-soft.it wrote:
Following your suggestion, I've increased the buffer size to 2K and set the period to fifo_length - 2 (13), with that I'm now running substantially smooth except 3 EVTERR on RX DMA over 4 million of interrupts.
Thanks Nicolin! I'm quite happy now!
That's good progress, Roberto.
It would be nice if you and Caleb could post the patches to the mailing list.
Indeed! Now the TDM is stable, I've also found the reason of the EVTERRs, which was related to some stale code I've used to enable and disable both RDMAE and TDMAE bits to try to reset the transfers. Once removed that code everything is looks ok now.
Regarding patches, well, from my side there isn't nothing special compared to the original fsl_ssi.c code. I'm basically running against a very skinny fsl_ssi.c version, I've just setup a bit larger DMA buffer, from 16bytes to 2K, and now reduced the DMA period to 8 because I'm mostly comfortable with that size to simplify sampling exchange against DAHDI subsystem within my DMA callbacks.
In a few words, my problem was related due to a DMA buffer too small.
What eventually might be interesting to have is the INTRMASK and EVTERR DMA setting to trigger DMA related errors, but I guess this need to be discussed elsewhere.
On Wed, Nov 04, 2015 at 04:33:16PM +0100, Roberto Fichera wrote:
With the patch below I'm able to see the error happening. And more likely it happen just just afterwards the EVTERR notify the problem to the ISR. At this point the DMA simply stalls due to some problems, most likely because the SSI FIFO is in overflow or underflow condition. I will do add the code to dump the SSI
No, SSI FIFO under/overflow were caused by the DMA stall as their channels got error out -- SSI was still consuming the TX FIFO and filling the RX FIFO while DMA didn't move the data at all so SSI FIFOs got under/overflowed.
I think that at this point we should in theory restart the DMA channel, but however how to fix this and why this is happening?
According to Reference Manual: ----
1) The CHNERR[i] bit is set when a DMA request that triggers channel i is received through the corresponding input pins and the EP[i] bit is already set;
2) Externally triggered channel pending flag EP[i] is set by the scheduler when the channel was activated by a DMA request. It can be cleared by the ith channel script.
----
It looks like your system made another DMA request while the SDMA was still in the middle of the transaction for the same channel. I guess you should find a way to make less frequent DMA requests, making higher watermarks and larger burst size for example.
On 11/04/2015 06:58 PM, Nicolin Chen wrote:
On Wed, Nov 04, 2015 at 04:33:16PM +0100, Roberto Fichera wrote:
With the patch below I'm able to see the error happening. And more likely it happen just just afterwards the EVTERR notify the problem to the ISR. At this point the DMA simply stalls due to some problems, most likely because the SSI FIFO is in overflow or underflow condition. I will do add the code to dump the SSI
No, SSI FIFO under/overflow were caused by the DMA stall as their channels got error out -- SSI was still consuming the TX FIFO and filling the RX FIFO while DMA didn't move the data at all so SSI FIFOs got under/overflowed.
Yeah! The SSI is correctly reporting this problem because DMA is stalled for some reason.
I think that at this point we should in theory restart the DMA channel, but however how to fix this and why this is happening?
According to Reference Manual:
- The CHNERR[i] bit is set when a DMA request that triggers channel
i is received through the corresponding input pins and the EP[i] bit is already set;
- Externally triggered channel pending flag EP[i] is set by the
scheduler when the channel was activated by a DMA request. It can be cleared by the ith channel script.
It looks like your system made another DMA request while the SDMA was still in the middle of the transaction for the same channel.
I don't know because this is something I cannot control. I'm just setting up 2 cyclic dma for both TX and RX before to set both RDMAE and TDMAE and nothing else. The rest is done by the SDMA ISR.
I guess you should find a way to make less frequent DMA requests, making higher watermarks and larger burst size for example.
I can try to increase the FIFO watermark up to 15 elements, but after that I don't have more choices. The problem is that the TDM has to run continuously because the SLIC need it. I can eventually enable and disable the DMA requests depending by the active channels for optimization, but the problem still,why the DMA transfer is not triggered?
On Wed, Nov 04, 2015 at 07:09:14PM +0100, Roberto Fichera wrote:
I can try to increase the FIFO watermark up to 15 elements, but after that I don't have more choices. The problem is that the TDM has to run continuously because the SLIC need it. I can eventually enable and disable the DMA requests depending by the active channels for optimization, but the problem still,why the DMA transfer is not triggered?
There's nothing you can do from SSI side. If you don't clear the Channel Error bit, the channel might be still hanging there until you clear the bit or reset the channel. You may read SDMA chapter for details.
On 11/04/2015 07:18 PM, Nicolin Chen wrote:
On Wed, Nov 04, 2015 at 07:09:14PM +0100, Roberto Fichera wrote:
I can try to increase the FIFO watermark up to 15 elements, but after that I don't have more choices. The problem is that the TDM has to run continuously because the SLIC need it. I can eventually enable and disable the DMA requests depending by the active channels for optimization, but the problem still,why the DMA transfer is not triggered?
There's nothing you can do from SSI side. If you don't clear the Channel Error bit, the channel might be still hanging there until you clear the bit or reset the channel. You may read SDMA chapter for details.
Ok! Will have a look tomorrow morning.
participants (4)
-
Caleb Crome
-
Fabio Estevam
-
Nicolin Chen
-
Roberto Fichera