Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: fsl_ssi.c: Roberto's problem: ssi hangs after some number of samples
@ 2015-11-05 21:34 Caleb Crome
  2015-11-05 22:08 ` Roberto Fichera
  0 siblings, 1 reply; 33+ messages in thread
From: Caleb Crome @ 2015-11-05 21:34 UTC (permalink / raw)
  To: Roberto Fichera
  Cc: Fabio Estevam, alsa-devel@alsa-project.org, Shengjiu Wang,
	Caleb Crome, Nicolin Chen, arnaud.mouiche@invoxia.com,
	Markus Pargmann, shawn.guo@linaro.org

On Thu, Nov 5, 2015 at 3:48 AM, Roberto Fichera <kernel@tekno-soft.it> wrote:
> 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.
>>

Yes, when I get something quite solid, I'd like to submit it all to
the list, and hope to get it into the kernel so nobody else has to go
through this pain again.

>
> 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.

I have implemented roberto's patch on the 4.2 kernel, and I get a huge
number of EVTERR interrupts.  Something like 7200/second at 16kHz
sample rate.  But strangely, the audio seems to be correct.

My patch is slightly different in that it just enables EVTERR for all
channels, not just for the SSI.  Might as well see if there are any
other problems.

And it puts the stats file at
/sys/kernel/debug/20ec000.sdma/stats

When I aplay a file for 10 seconds I get ~366 EVTERR interrupts.
When I arecord for 10 seconds, I get 1 EVTERR interrupt
When I run my application for 10 seconds, which does full duplex, I
get 72703 EVTERR interrupts, but the data integrity checks out okay.

Interstingly, when I enable dual fifo, it goes from about 7200
EVTERR's/sec to about 18 EVTERRs/sec.  Much better, but still a long
way from working perfectly.

When I get a 'hang' from my application (no more portaudio callbacks),
I'm actually getting repeated calls to sdma_prep_dma_cyclic, though I
don't know how that call gets triggered.  But once that starts
happening, no more audio data gets through.

Here is my version of Roberto's patch for reporting the EVTERR on a
4.2 kernel.  It includes Dual fifo.

The
/sys/kernel/debug/20ec000.sdma/stats
file is cleared by reading, so it's easy to check how many EVTERRs
since the last read of the file.


Thanks again for looking at this.

-Caleb

---------- Forwarded message ----------
From: Caleb Crome <caleb@crome.org>
Date: Thu, Nov 5, 2015 at 1:16 PM
Subject: [PATCH] DMA: imx-sdma: add reporting of EVTERR DMA errors to fsl dma.
To: ccrome@gmail.com
Cc: Caleb Crome <caleb@crome.org>


Add roberto's patch to the 4.x kernel for report EVTERR DMA errors in
SSI transfers.  From userspace, you can see errors in the

/sys/kernel/debug/20ec000.sdma/stats

file.
---
 drivers/dma/imx-sdma.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 9d375bc..a3a2317 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -38,6 +38,8 @@
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>

 #include <asm/irq.h>
 #include <linux/platform_data/dma-imx-sdma.h>
@@ -50,6 +52,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 +389,9 @@ struct sdma_engine {
        const struct sdma_driver_data   *drvdata;
        u32                             spba_start_addr;
        u32                             spba_end_addr;
+        u32                             evterrchannel[MAX_DMA_CHANNELS];
+       struct dentry *dbg_dir;
+       struct dentry *dbg_stats;
 };

 static struct sdma_driver_data sdma_imx31 = {
@@ -562,7 +569,19 @@ 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];
+       u32 msk;
+
        writel(BIT(channel), sdma->regs + SDMA_H_START);
+       /*
+        * enable EVTERR interrupts on this channel
+        */
+       if ((sdmac->peripheral_type == IMX_DMATYPE_SSI_SP) ||
+           (sdmac->peripheral_type == IMX_DMATYPE_SSI_DUAL)) {
+               msk = readl(sdma->regs + SDMA_H_INTRMSK);
+               writel(msk | BIT(channel), sdma->regs + SDMA_H_INTRMSK);
+               printk(KERN_INFO "%s: enabling EVTERR for channel
%d\n", __func__, channel);
+       }
 }

 /*
@@ -726,11 +745,25 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
        struct sdma_engine *sdma = dev_id;
        unsigned long stat;

+       long unsigned int 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];
@@ -904,10 +937,17 @@ static int sdma_disable_channel(struct dma_chan *chan)
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
        int channel = sdmac->channel;
+       u32 msk;

        writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
        sdmac->status = DMA_ERROR;

+       if ((sdmac->peripheral_type == IMX_DMATYPE_SSI_SP) ||
+           (sdmac->peripheral_type == IMX_DMATYPE_SSI_DUAL)) {
+               msk = readl(sdma->regs + SDMA_H_INTRMSK);
+               writel(msk & ~(BIT(channel)), sdma->regs + SDMA_H_INTRMSK);
+       }
+
        return 0;
 }

@@ -1166,6 +1206,8 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(

        dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
                        sg_len, channel);
+       printk(KERN_INFO "setting up %d entries for channel %d.\n",
+                       sg_len, channel);

        sdmac->direction = direction;
        ret = sdma_load_context(sdmac);
@@ -1259,6 +1301,8 @@ static struct dma_async_tx_descriptor
*sdma_prep_dma_cyclic(

        dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);

+       printk(KERN_INFO "%s channel: %d, periods = %d\n", __func__,
channel, num_periods);
+       printk(KERN_INFO "buf_len = %d, period_len = %d\n", buf_len,
period_len);
        if (sdmac->status == DMA_IN_PROGRESS)
                return NULL;

@@ -1650,6 +1694,71 @@ static struct dma_chan *sdma_xlate(struct
of_phandle_args *dma_spec,
        return dma_request_channel(mask, sdma_filter_fn, &data);
 }

+#define SDMA_SHOW_REG(reg) \
+    do { \
+                u32 _val = readl(sdma->regs + reg); \
+        seq_printf(s, "\t" #reg "=0x%08x\n", _val); \
+    } while (0)
+
+static int sdma_show_chan_status(struct seq_file *s, void *unused)
+{
+       struct sdma_engine *sdma = s->private;
+       // struct dma_chan *chan = (struct dma_chan *)priv;
+       //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 = %u\n", i,
sdma->evterrchannel[i]);
+                       sdma->evterrchannel[i] = 0;
+               }
+
+       return 0;
+}
+
+static int fsl_sdma_stats_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sdma_show_chan_status, inode->i_private);
+}
+
+static const struct file_operations fsl_sdma_stats_ops = {
+       .open = fsl_sdma_stats_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+int fsl_sdma_debugfs_create(struct sdma_engine *sdma, struct device *dev)
+{
+       sdma->dbg_dir = debugfs_create_dir(dev_name(dev), NULL);
+       if (!sdma->dbg_dir)
+               return -ENOMEM;
+
+       sdma->dbg_stats = debugfs_create_file("stats", S_IRUGO,
+                       sdma->dbg_dir, sdma, &fsl_sdma_stats_ops);
+       if (!sdma->dbg_stats) {
+               debugfs_remove(sdma->dbg_dir);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+
 static int sdma_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
@@ -1785,6 +1894,10 @@ static int sdma_probe(struct platform_device *pdev)
                }
        }

+       ret = fsl_sdma_debugfs_create(sdma, &pdev->dev);
+       if (ret)
+               goto err_init;
+
        sdma->dma_device.dev = &pdev->dev;

        sdma->dma_device.device_alloc_chan_resources =
sdma_alloc_chan_resources;
--
2.1.4

^ permalink raw reply related	[flat|nested] 33+ messages in thread
* Re: fsl_ssi.c: Roberto's problem: ssi hangs after some number of samples
@ 2015-10-30 18:01 Caleb Crome
  2015-10-31  9:16 ` Roberto Fichera
  0 siblings, 1 reply; 33+ messages in thread
From: Caleb Crome @ 2015-10-30 18:01 UTC (permalink / raw)
  To: Roberto Fichera
  Cc: Fabio Estevam, alsa-devel@alsa-project.org, Shengjiu Wang,
	Nicolin Chen, arnaud.mouiche@invoxia.com, Markus Pargmann,
	shawn.guo@linaro.org, Fabio Estevam

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.

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2015-11-06  0:35 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-05 21:34 fsl_ssi.c: Roberto's problem: ssi hangs after some number of samples Caleb Crome
2015-11-05 22:08 ` Roberto Fichera
2015-11-05 22:25   ` Caleb Crome
2015-11-05 22:40     ` Roberto Fichera
2015-11-05 22:49       ` Caleb Crome
2015-11-05 23:01         ` Roberto Fichera
2015-11-05 23:21           ` Caleb Crome
2015-11-05 23:28             ` Roberto Fichera
2015-11-05 23:30               ` Caleb Crome
2015-11-05 23:46                 ` Roberto Fichera
2015-11-06  0:35                   ` Caleb Crome
  -- strict thread matches above, loose matches on Subject: below --
2015-10-30 18:01 Caleb Crome
2015-10-31  9:16 ` Roberto Fichera
2015-11-01 20:31   ` Fabio Estevam
2015-11-02  9:57     ` Roberto Fichera
2015-11-02 17:51   ` Roberto Fichera
2015-11-02 18:03     ` Roberto Fichera
2015-11-03  0:56       ` Caleb Crome
2015-11-03  8:21         ` Roberto Fichera
2015-11-03 21:26   ` Caleb Crome
2015-11-04 15:33     ` Roberto Fichera
2015-11-04 16:53       ` Roberto Fichera
2015-11-04 17:41         ` Caleb Crome
2015-11-04 17:52           ` Roberto Fichera
2015-11-04 18:11             ` Nicolin Chen
2015-11-04 21:47               ` Roberto Fichera
2015-11-05 10:03               ` Roberto Fichera
2015-11-05 11:30                 ` Fabio Estevam
2015-11-05 11:48                   ` Roberto Fichera
2015-11-04 17:58       ` Nicolin Chen
2015-11-04 18:09         ` Roberto Fichera
2015-11-04 18:18           ` Nicolin Chen
2015-11-04 21:48             ` Roberto Fichera

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox