blob: d7661f1fb36e72af87ded7a20c81d4d74db863cf [file] [log] [blame]
From 7f6c7de2533bab63212a164b29e1fa352880a05b Mon Sep 17 00:00:00 2001
From: Jinliang Wang <jinliangw@google.com>
Date: Tue, 28 Mar 2023 11:16:27 -0700
Subject: [PATCH] i2c: npcm: quirk to fix multiple master xfer failure
This patch is backported from Avi.Fishman@nuvoton.com and
tali.perry@nuvoton.com 's debug version driver v15.
Link (https://drive.google.com/corp/drive/folders/19RaTMJcarpN-dpuAlbTFPm_0xKx7TKjU?resourcekey=0-UI41jAZA4xd_5VINmDcN0Q)
It contains some quirk to detect MCTP packet and then apply some
special handling. Nuvoton is still trying to find a more proper way to
support multiple master mode in upstream i2c-npcm7xx.c.
Signed-off-by: Jinliang Wang <jinliangw@google.com>
Patch Tracking Bug: b/275108914
Upstream info / review: N/A
Upstream-Status: Pending
Justification: The patch is upstreamable however Nuvoton is still
working on more appropriate and general implementation
Signed-off-by: William A. Kennington III <wak@google.com>
---
drivers/i2c/busses/i2c-npcm7xx.c | 62 ++++++++++++++++++++++++--------
1 file changed, 48 insertions(+), 14 deletions(-)
diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c
index bfef6ae45988..f2a4a7ee14f2 100644
--- a/drivers/i2c/busses/i2c-npcm7xx.c
+++ b/drivers/i2c/busses/i2c-npcm7xx.c
@@ -433,6 +433,7 @@ struct npcm_i2c {
bool read_block_use;
unsigned long int_time_stamp;
unsigned long bus_freq; /* in Hz */
+ bool multi_master;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
u8 own_slave_addr;
struct i2c_client *slave;
@@ -1218,7 +1219,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
* master ( for a channel which is master\slave switching)
*/
if (completion_done(&bus->cmd_complete) == false) {
- bus->cmd_err = -EIO;
+ bus->cmd_err = -EAGAIN;
complete(&bus->cmd_complete);
}
bus->own_slave_addr = 0xFF;
@@ -1643,6 +1644,7 @@ static void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus)
bus->stop_ind = I2C_BUS_ERR_IND;
if (npcm_i2c_is_master(bus)) {
npcm_i2c_master_abort(bus);
+ bus->cmd_err = -EAGAIN;
} else {
bus->ber_state = true;
npcm_i2c_clear_master_status(bus);
@@ -1788,6 +1790,14 @@ static int npcm_i2c_int_master_handler(struct npcm_i2c *bus)
(FIELD_GET(NPCM_I2CCST3_EO_BUSY,
ioread8(bus->reg + NPCM_I2CCST3)))) {
npcm_i2c_irq_handle_eob(bus);
+
+/* VIVEK */
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ /* reenable slave if it was enabled */
+ if (bus->slave)
+ iowrite8((bus->slave->addr & 0x7F) | NPCM_I2CADDR_SAEN,
+ bus->reg + NPCM_I2CADDR1);
+#endif
return 0;
}
@@ -1819,11 +1829,16 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap)
/* Allow 3 bytes (27 toggles) to be read from the slave: */
int iter = 27;
+ bus->ber_state = false;
+
+ if (bus->multi_master) {
+ return 0;
+ }
+
if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) {
dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck",
bus->num, bus->dest_addr);
npcm_i2c_reset(bus);
- bus->ber_state = false;
return 0;
}
@@ -1888,7 +1903,6 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap)
if (bus->rec_succ_cnt < ULLONG_MAX)
bus->rec_succ_cnt++;
}
- bus->ber_state = false;
return status;
}
@@ -2107,7 +2121,7 @@ static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus,
bool use_PEC, bool use_read_block)
{
if (bus->state != I2C_IDLE) {
- bus->cmd_err = -EBUSY;
+ bus->cmd_err = -EAGAIN;
return false;
}
bus->dest_addr = slave_addr << 1;
@@ -2184,6 +2198,11 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
write_data = msg0->buf;
nread = 0;
read_data = NULL;
+ if ((num == 1) && (nwrite > 7) && (write_data[0] == 0xF) && ((write_data[1] + 3) == nwrite))
+ {
+ printk_once("i2c%d: Met MCTP packet\n", bus->num);
+ bus->multi_master = true;
+ }
if (num == 2) {
msg1 = &msgs[1];
read_data = msg1->buf;
@@ -2201,6 +2220,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
if (nwrite >= 32 * 1024 || nread >= 32 * 1024) {
dev_err(bus->dev, "i2c%d buffer too big\n", bus->num);
+ bus->multi_master = false;
return -EINVAL;
}
@@ -2212,7 +2232,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
* entire while since it is too long.
*/
spin_lock_irqsave(&bus->lock, flags);
- bus_busy = ioread8(bus->reg + NPCM_I2CCST) & NPCM_I2CCST_BB;
+ bus_busy = (ioread8(bus->reg + NPCM_I2CCST) & NPCM_I2CCST_BB) || (bus->state != I2C_IDLE);
#if IS_ENABLED(CONFIG_I2C_SLAVE)
if (!bus_busy && bus->slave)
iowrite8((bus->slave->addr & 0x7F),
@@ -2225,15 +2245,19 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
bus->dest_addr = slave_addr << 1;
if (bus_busy || bus->ber_state) {
iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST);
- npcm_i2c_reset(bus);
- i2c_recover_bus(adap);
- return -EAGAIN;
+ if(bus->multi_master == false)
+ {
+ npcm_i2c_reset(bus);
+ i2c_recover_bus(adap);
+ }
+ bus->cmd_err = -EAGAIN;
+ goto npcm_i2c_xfer_complete;
}
npcm_i2c_init_params(bus);
bus->msgs = msgs;
bus->msgs_num = num;
- bus->cmd_err = 0;
+ bus->cmd_err = -EAGAIN;
bus->read_block_use = read_block;
reinit_completion(&bus->cmd_complete);
@@ -2258,8 +2282,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
if (bus->timeout_cnt < ULLONG_MAX)
bus->timeout_cnt++;
if (bus->master_or_slave == I2C_MASTER) {
- i2c_recover_bus(adap);
- bus->cmd_err = -EIO;
+ bus->cmd_err = -EAGAIN;
bus->state = I2C_IDLE;
}
}
@@ -2267,7 +2290,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
/* if there was BER, check if need to recover the bus: */
if (bus->cmd_err == -EAGAIN)
- bus->cmd_err = i2c_recover_bus(adap);
+ i2c_recover_bus(adap);
/*
* After any type of error, check if LAST bit is still set,
@@ -2282,6 +2305,15 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
npcm_i2c_stall_after_start(bus, false);
npcm_i2c_eob_int(bus, false);
+npcm_i2c_xfer_complete:
+ if (bus->multi_master) {
+ if ((bus->cmd_err < 0 && bus->cmd_err != -EAGAIN)||
+ (bus->cmd_err >= 0 && bus->cmd_err != num)){
+ dev_err(bus->dev, "i2c%d xfer returned %d\n", bus->num, bus->cmd_err);
+ }
+ /* reset it to false upon exit */
+ bus->multi_master = false;
+ }
#if IS_ENABLED(CONFIG_I2C_SLAVE)
/* reenable slave if it was enabled */
if (bus->slave)
@@ -2423,8 +2455,10 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
adap = &bus->adap;
adap->owner = THIS_MODULE;
- adap->retries = 3;
- adap->timeout = 2 * HZ;
+ /* 10 retries x 400 ms = 4 seconds(HZ) */
+ adap->retries = 10;
+ adap->timeout = msecs_to_jiffies(400) * adap->retries;
+ bus->multi_master = false;
adap->algo = &npcm_i2c_algo;
adap->quirks = &npcm_i2c_quirks;
adap->algo_data = bus;
--
2.40.1.495.gc816e09b53d-goog