i.MX6DL I2C Master Mode Glitch

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

i.MX6DL I2C Master Mode Glitch

跳至解决方案
1,363 次查看
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? 

标签 (1)
0 项奖励
回复
1 解答
1,309 次查看
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.

在原帖中查看解决方案

2 回复数
1,312 次查看
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 项奖励
回复
1,310 次查看
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.