]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
i3c: master: dw-i3c-master: Fix OD_TIMING for spike filter
authorDinesh Maniyam <dinesh.maniyam@altera.com>
Wed, 6 Aug 2025 04:32:31 +0000 (12:32 +0800)
committerHeiko Schocher <hs@denx.de>
Wed, 6 Aug 2025 06:41:14 +0000 (08:41 +0200)
Fix the I3C device with spike filter unable to detect issue by setting
tHIGH_INIT to 200ns for first broadcast address.
This is according to MIPI SPEC 1.1.1 for first broadcast address
which is already part of linux upstreamed patch.

Signed-off-by: Dinesh Maniyam <dinesh.maniyam@altera.com>
drivers/i3c/master/dw-i3c-master.c
include/dw-i3c.h
include/linux/i3c/master.h

index 8b3d5531a7f9349115f2f744fe159687361baf70..6d3d2ab5e7194b735f9fcee4c6840180fc1a97ee 100644 (file)
@@ -334,6 +334,14 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
        if (hcnt < SCL_I3C_TIMING_CNT_MIN)
                hcnt = SCL_I3C_TIMING_CNT_MIN;
 
+       /* set back to THIGH_MAX_NS, after disable spike filter */
+       if (!master->first_broadcast) {
+               lcnt = SCL_I3C_TIMING_LCNT(readl(master->regs + SCL_I3C_OD_TIMING));
+               scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | lcnt;
+               writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
+               return 0;
+       }
+
        lcnt = DIV_ROUND_UP(core_rate, master->base.bus.scl_rate.i3c) - hcnt;
        if (lcnt < SCL_I3C_TIMING_CNT_MIN)
                lcnt = SCL_I3C_TIMING_CNT_MIN;
@@ -351,6 +359,9 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
        lcnt = max_t(u8,
                     DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period), lcnt);
 
+       /* first broadcast thigh to 200ns, to disable spike filter */
+       hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_INIT_OD_MIN_NS, core_period);
+
        scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
        writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
 
@@ -406,6 +417,9 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
        u32 thld_ctrl;
        int ret;
 
+       /* first broadcast to disable spike filter */
+       master->first_broadcast = true;
+
        switch (bus->mode) {
        case I3C_BUS_MODE_MIXED_FAST:
        case I3C_BUS_MODE_MIXED_LIMITED:
@@ -485,6 +499,15 @@ static void dw_i3c_master_irq_handler(struct dw_i3c_master *master)
        if (status & INTR_TRANSFER_ERR_STAT)
                writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS);
 
+       /* set back to THIGH_MAX_NS, after disable spike filter */
+       if (master->first_broadcast) {
+               master->first_broadcast = false;
+               int ret = dw_i3c_clk_cfg(master);
+
+               if (ret)
+                       pr_err("Failed to set clk cfg\n");
+       }
+
        spin_unlock(&master->xferqueue.lock);
 }
 
index 920f18bccb441535c1e43f8406124fc39d5d9585..42c37d6dfa213eb1aab89a66cb3746266026d193 100644 (file)
@@ -240,6 +240,7 @@ struct dw_i3c_master {
        char version[5];
        char type[5];
        u8 addrs[MAX_DEVS];
+       bool first_broadcast;
 };
 
 struct dw_i3c_i2c_dev_data {
index 213de4ca06ad91fd667054c94eb06f20e8940652..04017f34822c143d895ad717085d2539d9973c14 100644 (file)
@@ -278,6 +278,7 @@ struct i3c_device {
 #define I3C_BUS_I2C_FM_PLUS_SCL_RATE   1000000
 #define I3C_BUS_I2C_FM_SCL_RATE                400000
 #define I3C_BUS_TLOW_OD_MIN_NS         200
+#define I3C_BUS_THIGH_INIT_OD_MIN_NS   200
 
 /**
  * enum i3c_bus_mode - I3C bus mode