aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/i3c/master/dw-i3c-master.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index d7df81c566672d..7eb09ad1017125 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -205,6 +205,10 @@
#define EXTENDED_CAPABILITY 0xe8
#define SLAVE_CONFIG 0xec
+#define DYN_ADDR_LO_MASK GENMASK(4, 0)
+#define DYN_ADDR_HI_MASK GENMASK(6, 5)
+#define IBI_SIR_BIT_MOD 32 /* 32-bit vector */
+
#define DW_I3C_DEV_NACK_RETRY_CNT_MAX 0x3
#define DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK GENMASK(30, 29)
#define DEV_ADDR_TABLE_DYNAMIC_MASK GENMASK(23, 16)
@@ -217,6 +221,7 @@
#define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) FIELD_PREP(DEV_ADDR_TABLE_DYNAMIC_MASK, x)
#define DEV_ADDR_TABLE_STATIC_ADDR(x) FIELD_PREP(DEV_ADDR_TABLE_STATIC_MASK, x)
#define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2))
+#define DEV_ADDR_TABLE_GET_DYNAMIC_ADDR(x) FIELD_GET(DEV_ADDR_TABLE_DYNAMIC_MASK, x)
#define I3C_BUS_SDR1_SCL_RATE 8000000
#define I3C_BUS_SDR2_SCL_RATE 6000000
@@ -264,6 +269,14 @@ struct dw_i3c_drvdata {
u32 flags;
};
+static inline u32 get_ibi_sir_bit_index(u8 addr)
+{
+ u32 lo = FIELD_GET(DYN_ADDR_LO_MASK, addr);
+ u32 hi = FIELD_GET(DYN_ADDR_HI_MASK, addr);
+
+ return (lo + hi) % IBI_SIR_BIT_MOD;
+}
+
static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
const struct i3c_ccc_cmd *cmd)
{
@@ -1237,11 +1250,19 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
{
u32 dat_entry, reg;
bool global;
+ u8 dynamic_addr;
dat_entry = DEV_ADDR_TABLE_LOC(master->datstartaddr, idx);
guard(spinlock_irqsave)(&master->devs_lock);
reg = readl(master->regs + dat_entry);
+ dynamic_addr = DEV_ADDR_TABLE_GET_DYNAMIC_ADDR(reg);
+
+ if (!dynamic_addr)
+ dev_warn(master->dev,
+ "<%s> unassigned slave device, dynamic addr:%x\n",
+ __func__, dynamic_addr);
+
if (enable) {
reg &= ~DEV_ADDR_TABLE_SIR_REJECT;
if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD)
@@ -1254,11 +1275,11 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
if (enable) {
global = (master->sir_rej_mask == IBI_REQ_REJECT_ALL);
- master->sir_rej_mask &= ~BIT(idx);
+ master->sir_rej_mask &= ~BIT(get_ibi_sir_bit_index(dynamic_addr));
} else {
bool hj_rejected = !!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_HOT_JOIN_NACK);
- master->sir_rej_mask |= BIT(idx);
+ master->sir_rej_mask |= BIT(get_ibi_sir_bit_index(dynamic_addr));
global = (master->sir_rej_mask == IBI_REQ_REJECT_ALL) && hj_rejected;
}
writel(master->sir_rej_mask, master->regs + IBI_SIR_REQ_REJECT);