i.MX6DL I2C Master Mode Glitch

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MX6DL I2C Master Mode Glitch

Jump to solution
1,457 Views
nlbutts
Contributor III

We have a custom i.MX6DL board. We have I2C2 connected to the MMPF0100 PMIC. About every 1 in 146 boots the I2C from the i.MX6 to the PMIC glitches. U-boot can correctly and successfully communicate with the PMIC as seen below:

nlbutts_0-1654265743828.png

Then u-boot loads and hands control to the Kernel. But on the first transaction in kernel space the following happens:

nlbutts_1-1654265797273.png

The Kernel sends the PMIC I2C address, the PMIC ACKs it's address, but then the i.MX6 never sends another command. I enabled the I2C recovery mode, which generates a stop condition and attempts to communicate with the PMIC again. This fails. At this point the Kernel gives up and since the power rails are not up the Kernel fails to boot. 

nlbutts_2-1654265846175.png

It looks like someone had a similar issue: https://stackoverflow.com/questions/54092447/linux-i2c-communication-issues

I'm now trying different I2C drive strengths. What would cause the I2C module in the i.MX6 to never generate the next byte? 

Labels (1)
0 Kudos
Reply
1 Solution
1,403 Views
nlbutts
Contributor III

I found the root cause. There is a bug in the sdma code. We were using 4.9.9 kernel. Below is the offending function:

static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
        u32 address)
{
    struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
    void *buf_virt;
    dma_addr_t buf_phys;
    int ret;
    unsigned long flags;
 
    buf_virt = dma_alloc_coherent(NULL,
            size,
            &buf_phys, GFP_KERNEL);
    if (!buf_virt) {
        return -ENOMEM;
    }
 
    spin_lock_irqsave(&sdma->channel_0_lock, flags);
 
    bd0->mode.command = C0_SETPM;
    bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
    bd0->mode.count = size / 2;
    bd0->buffer_addr = buf_phys;
    bd0->ext_buffer_addr = address;
 
    memcpy(buf_virt, buf, size);
    ret = sdma_run_channel0(sdma);
    spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
    dma_free_coherent(NULL, size, buf_virt, buf_phys);
    return ret;
}

 

In the 4.9.11 kernel the BD_INTR flag was removed. After removing this flag, the unit booted thousands of times with no issues.

View solution in original post

2 Replies
1,406 Views
Dhruvit
NXP TechSupport
NXP TechSupport

Hi @nlbutts,

I hope you are doing well.

I am exploring the issue, and it looks like there might be a possibility of noise on the SCLK pin, which causes the glitch. For further debugging of the case, I have some queries which are as follows,

  • What frequency have you set for the i2c2 bus?
  • If possible, can you please provide me with the waveforms from the slave side when this glitch is there?

 

Best Regards,
Dhruvit.

0 Kudos
Reply
1,404 Views
nlbutts
Contributor III

I found the root cause. There is a bug in the sdma code. We were using 4.9.9 kernel. Below is the offending function:

static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
        u32 address)
{
    struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
    void *buf_virt;
    dma_addr_t buf_phys;
    int ret;
    unsigned long flags;
 
    buf_virt = dma_alloc_coherent(NULL,
            size,
            &buf_phys, GFP_KERNEL);
    if (!buf_virt) {
        return -ENOMEM;
    }
 
    spin_lock_irqsave(&sdma->channel_0_lock, flags);
 
    bd0->mode.command = C0_SETPM;
    bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
    bd0->mode.count = size / 2;
    bd0->buffer_addr = buf_phys;
    bd0->ext_buffer_addr = address;
 
    memcpy(buf_virt, buf, size);
    ret = sdma_run_channel0(sdma);
    spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
    dma_free_coherent(NULL, size, buf_virt, buf_phys);
    return ret;
}

 

In the 4.9.11 kernel the BD_INTR flag was removed. After removing this flag, the unit booted thousands of times with no issues.