i3c: dw: Fix IBI intr programming
authorAniket <aniketmaurya@google.com>
Fri, 7 Jun 2024 07:20:30 +0000 (07:20 +0000)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Fri, 26 Jul 2024 12:21:29 +0000 (14:21 +0200)
IBI_SIR_REQ_REJECT register is not present if the IP has
IC_HAS_IBI_DATA = 1 set. So don't rely on doing read-
modify-write op on this register.
Instead maintain a variable to store the sir reject mask
and use it to set IBI_SIR_REQ_REJECT.

Signed-off-by: Aniket <aniketmaurya@google.com>
Reviewed-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/i3c/master/dw-i3c-master.c
drivers/i3c/master/dw-i3c-master.h

index 0ba4960aa77b2e24c7985112729f2694ead5dbb6..77a2a1c3fd1de5937d3ffe84d4f34390f4824219 100644 (file)
@@ -658,7 +658,9 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
        if (ret)
                return ret;
 
-       writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT);
+       master->sir_rej_mask = IBI_REQ_REJECT_ALL;
+       writel(master->sir_rej_mask, master->regs + IBI_SIR_REQ_REJECT);
+
        writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT);
 
        /* For now don't support Hot-Join */
@@ -1175,17 +1177,16 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
        master->platform_ops->set_dat_ibi(master, dev, enable, &reg);
        writel(reg, master->regs + dat_entry);
 
-       reg = readl(master->regs + IBI_SIR_REQ_REJECT);
        if (enable) {
-               global = reg == 0xffffffff;
-               reg &= ~BIT(idx);
+               global = (master->sir_rej_mask == IBI_REQ_REJECT_ALL);
+               master->sir_rej_mask &= ~BIT(idx);
        } else {
                bool hj_rejected = !!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_HOT_JOIN_NACK);
 
-               reg |= BIT(idx);
-               global = (reg == 0xffffffff) && hj_rejected;
+               master->sir_rej_mask |= BIT(idx);
+               global = (master->sir_rej_mask == IBI_REQ_REJECT_ALL) && hj_rejected;
        }
-       writel(reg, master->regs + IBI_SIR_REQ_REJECT);
+       writel(master->sir_rej_mask, master->regs + IBI_SIR_REQ_REJECT);
 
        if (global)
                dw_i3c_master_enable_sir_signal(master, enable);
index 4ab94aa72252e4db7a55ffe5a989f86ca769f5d1..8cb617b8147e133ff88bfa9013ea80ae15302f8b 100644 (file)
@@ -39,7 +39,7 @@ struct dw_i3c_master {
        char version[5];
        char type[5];
        bool ibi_capable;
-
+       u32 sir_rej_mask;
        /*
         * Per-device hardware data, used to manage the device address table
         * (DAT)