1- From f3c0cb78c3982c60e9a5e2705c9939f1eef84002 Mon Sep 17 00:00:00 2001
1+ From 697b2b39c8e473c8a41b0a5d0947d36480b35354 Mon Sep 17 00:00:00 2001
22From: Shantanu Shrivastava <shanshri@amd.com>
33Date: Tue, 24 Oct 2023 08:36:35 +0000
4- Subject: [PATCH] i2c-designware: Support stuck SDA line recovery
4+ Subject: [PATCH 03/27 ] i2c-designware: Support stuck SDA line recovery
55
66This patch supports the Designware I2C stuck bus recovery feature.
77The procedure for stuck SDA recovery involves a polling loop in
@@ -14,17 +14,16 @@ a hard maximum on time in the recovery loop.
1414Signed-off-by: David Clear <dclear@amd.com>
1515Signed-off-by: Shantanu Shrivastava <shanshri@amd.com>
1616---
17- drivers/i2c/busses/i2c-designware-common.c | 2 +
18- drivers/i2c/busses/i2c-designware-core.h | 11 +++
19- drivers/i2c/busses/i2c-designware-master.c | 87 ++++++++++++++++++++-
20- drivers/i2c/busses/i2c-designware-platdrv.c | 3 +
21- 4 files changed, 101 insertions(+), 2 deletions(-)
17+ drivers/i2c/busses/i2c-designware-common.c | 2 +
18+ drivers/i2c/busses/i2c-designware-core.h | 9 +++
19+ drivers/i2c/busses/i2c-designware-master.c | 88 +++++++++++++++++++++++++++++-
20+ 3 files changed, 96 insertions(+), 3 deletions(-)
2221
2322diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
24- index 6fdb25a5f..8ac32dd41 100644
23+ index b328278..e6f1b29 100644
2524--- a/drivers/i2c/busses/i2c-designware-common.c
2625+++ b/drivers/i2c/busses/i2c-designware-common.c
27- @@ -57 ,6 +57 ,8 @@ static char *abort_sources[] = {
26+ @@ -63 ,6 +63 ,8 @@
2827 "slave lost the bus while transmitting data to a remote master",
2928 [ABRT_SLAVE_RD_INTX] =
3029 "incorrect slave-transmitter mode configuration",
@@ -34,70 +33,59 @@ index 6fdb25a5f..8ac32dd41 100644
3433
3534 static int dw_reg_read(void *context, unsigned int reg, unsigned int *val)
3635diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
37- index 56a029da4..54e6c44e6 100644
36+ index 2d32896..59d1eba 100644
3837--- a/drivers/i2c/busses/i2c-designware-core.h
3938+++ b/drivers/i2c/busses/i2c-designware-core.h
40- @@ -37,6 +37,7 @@
41- #define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7)
42- #define DW_IC_CON_TX_EMPTY_CTRL BIT(8)
43- #define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9)
44- + #define DW_IC_CON_BUS_CLEAR_FEATURE_CTL BIT(11)
45-
46- #define DW_IC_DATA_CMD_DAT GENMASK(7, 0)
47-
48- @@ -77,6 +78,8 @@
49- #define DW_IC_TX_ABRT_SOURCE 0x80
50- #define DW_IC_ENABLE_STATUS 0x9c
51- #define DW_IC_CLR_RESTART_DET 0xa8
39+ @@ -78,6 +78,8 @@
40+ #define DW_IC_TX_ABRT_SOURCE 0x80
41+ #define DW_IC_ENABLE_STATUS 0x9c
42+ #define DW_IC_CLR_RESTART_DET 0xa8
5243+ #define DW_IC_SCL_STUCK_AT_LOW 0xac
5344+ #define DW_IC_SDA_STUCK_AT_LOW 0xb0
54- #define DW_IC_COMP_PARAM_1 0xf4
55- #define DW_IC_COMP_VERSION 0xf8
56- #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
57- @@ -96 ,6 +99 ,7 @@
58- #define DW_IC_INTR_START_DET BIT(10 )
59- #define DW_IC_INTR_GEN_CALL BIT(11 )
60- #define DW_IC_INTR_RESTART_DET BIT(12 )
45+ #define DW_IC_COMP_PARAM_1 0xf4
46+ #define DW_IC_COMP_VERSION 0xf8
47+ #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */
48+ @@ -98 ,6 +100 ,7 @@
49+ #define DW_IC_INTR_GEN_CALL BIT(11 )
50+ #define DW_IC_INTR_RESTART_DET BIT(12 )
51+ #define DW_IC_INTR_MST_ON_HOLD BIT(13 )
6152+ #define DW_IC_INTR_SCL_STUCK_AT_LOW BIT(14)
6253
63- #define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
64- DW_IC_INTR_TX_ABRT | \
65- @@ -107,14 +111,18 @@
66- DW_IC_INTR_RX_UNDER | \
67- DW_IC_INTR_RD_REQ )
54+ #define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
55+ DW_IC_INTR_TX_ABRT | \
56+ @@ -111,12 +114,15 @@
57+ #define DW_IC_ENABLE_ENABLE BIT(0)
58+ #define DW_IC_ENABLE_ABORT BIT(1 )
6859
6960+ #define DW_IC_SDA_STUCK_RECOVERY_ENABLE BIT(3)
7061+
71- #define DW_IC_STATUS_ACTIVITY BIT(0)
72- #define DW_IC_STATUS_TFE BIT(2)
73- #define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
74- #define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
62+ #define DW_IC_STATUS_ACTIVITY BIT(0)
63+ #define DW_IC_STATUS_TFE BIT(2)
64+ #define DW_IC_STATUS_RFNE BIT(3)
65+ #define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
66+ #define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
67+ #define DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY BIT(7)
7568+ #define DW_IC_STATUS_SDA_STUCK_NOT_RECOVERED BIT(11)
7669
77- #define DW_IC_SDA_HOLD_RX_SHIFT 16
78- #define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16)
79-
80- +
81- #define DW_IC_ERR_TX_ABRT 0x1
82-
83- #define DW_IC_TAR_10BITADDR_MASTER BIT(12)
84- @@ -156,6 +164,7 @@
85- #define ABRT_SLAVE_FLUSH_TXFIFO 13
86- #define ABRT_SLAVE_ARBLOST 14
87- #define ABRT_SLAVE_RD_INTX 15
88- + #define ABRT_SDA_STUCK_AT_LOW 17
70+ #define DW_IC_SDA_HOLD_RX_SHIFT 16
71+ #define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16)
72+ @@ -162,6 +168,7 @@
73+ #define ABRT_SLAVE_FLUSH_TXFIFO 13
74+ #define ABRT_SLAVE_ARBLOST 14
75+ #define ABRT_SLAVE_RD_INTX 15
76+ + #define ABRT_SDA_STUCK_AT_LOW 17
8977
9078 #define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(ABRT_7B_ADDR_NOACK)
9179 #define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(ABRT_10ADDR1_NOACK)
92- @@ -168 ,6 +177 ,7 @@
80+ @@ -174 ,6 +181 ,7 @@
9381 #define DW_IC_TX_ABRT_10B_RD_NORSTRT BIT(ABRT_10B_RD_NORSTRT)
9482 #define DW_IC_TX_ABRT_MASTER_DIS BIT(ABRT_MASTER_DIS)
9583 #define DW_IC_TX_ARB_LOST BIT(ARB_LOST)
9684+ #define DW_IC_TX_ABRT_SDA_STUCK_AT_LOW BIT(ABRT_SDA_STUCK_AT_LOW)
9785 #define DW_IC_RX_ABRT_SLAVE_RD_INTX BIT(ABRT_SLAVE_RD_INTX)
9886 #define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST)
9987 #define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO)
100- @@ -277 ,6 +287 ,7 @@ struct dw_i2c_dev {
88+ @@ -283 ,6 +291 ,7 @@ struct dw_i2c_dev {
10189 int rx_outstanding;
10290 struct i2c_timings timings;
10391 u32 sda_hold_time;
@@ -106,10 +94,10 @@ index 56a029da4..54e6c44e6 100644
10694 u16 ss_lcnt;
10795 u16 fs_hcnt;
10896diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
109- index dc3c5a15a..9834137a0 100644
97+ index 52dc666..18423d0 100644
11098--- a/drivers/i2c/busses/i2c-designware-master.c
11199+++ b/drivers/i2c/busses/i2c-designware-master.c
112- @@ -37 ,6 +37 ,45 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
100+ @@ -41 ,6 +41 ,45 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
113101 regmap_write(dev->map, DW_IC_CON, dev->master_cfg);
114102 }
115103
@@ -154,10 +142,10 @@ index dc3c5a15a..9834137a0 100644
154142+
155143 static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
156144 {
157- u32 comp_param1;
158- @@ -599 ,6 +638 ,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num )
159- goto done;
160- }
145+ unsigned int comp_param1;
146+ @@ -846 ,6 +885 ,14 @@ static int i2c_dw_wait_transfer( struct dw_i2c_dev *dev )
147+ if (i2c_dw_is_controller_active(dev))
148+ dev_err(dev->dev, "controller active\n");
161149
162150+ /* Look for a stuck bus */
163151+ if (dev->cmd_err == DW_IC_ERR_TX_ABRT &&
@@ -170,7 +158,7 @@ index dc3c5a15a..9834137a0 100644
170158 /*
171159 * We must disable the adapter before returning and signaling the end
172160 * of the current transfer. Otherwise the hardware might continue
173- @@ -826 ,6 +873 ,39 @@ static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap)
161+ @@ -940 ,6 +987 ,39 @@ static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap)
174162 i2c_dw_init_master(dev);
175163 }
176164
@@ -192,14 +180,14 @@ index dc3c5a15a..9834137a0 100644
192180+ * bit in IC_CON. If the bit reads back set, then the feature is
193181+ * available, otherwise it is not.
194182+ */
195- + regmap_write(dev->map, DW_IC_CON, DW_IC_CON_BUS_CLEAR_FEATURE_CTL );
183+ + regmap_write(dev->map, DW_IC_CON, DW_IC_DATA_CMD_FIRST_DATA_BYTE );
196184+ regmap_read(dev->map, DW_IC_CON, &con);
197- + if (!(con & DW_IC_CON_BUS_CLEAR_FEATURE_CTL ))
185+ + if (!(con & DW_IC_DATA_CMD_FIRST_DATA_BYTE ))
198186+ goto out;
199187+ dev_info(dev->dev, "running with controller bus clear recovery mode!");
200188+ timeout = i2c_dw_clk_rate(dev) * dev->sda_timeout_ms; /* clk in kHz */
201189+ regmap_write(dev->map, DW_IC_SDA_STUCK_AT_LOW, timeout);
202- + dev->master_cfg |= DW_IC_CON_BUS_CLEAR_FEATURE_CTL ;
190+ + dev->master_cfg |= DW_IC_DATA_CMD_FIRST_DATA_BYTE ;
203191+ out:
204192+ regmap_write(dev->map, DW_IC_CON, dev->master_cfg);
205193+ i2c_dw_release_lock(dev);
@@ -210,34 +198,21 @@ index dc3c5a15a..9834137a0 100644
210198 static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
211199 {
212200 struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
213- @@ -833,8 +913 ,11 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
201+ @@ -947,9 +1027 ,11 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
214202 struct gpio_desc *gpio;
215203
216204 gpio = devm_gpiod_get_optional(dev->dev, "scl", GPIOD_OUT_HIGH);
217205- if (IS_ERR_OR_NULL(gpio))
218206- return PTR_ERR_OR_ZERO(gpio);
207+ -
219208+ if (IS_ERR_OR_NULL(gpio)) {
220209+ if (IS_ERR(gpio))
221210+ return PTR_ERR(gpio);
222211+ return i2c_dw_probe_bus_clear_feature(dev);
223212+ }
224-
225213 rinfo->scl_gpiod = gpio;
226214
227- diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
228- index 74182db03..7466d748b 100644
229- --- a/drivers/i2c/busses/i2c-designware-platdrv.c
230- +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
231- @@ -136,6 +136,9 @@ static int dw_i2c_of_configure(struct platform_device *pdev)
232- {
233- struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
234-
235- + device_property_read_u32(&pdev->dev, "snps,sda-timeout-ms",
236- + &dev->sda_timeout_ms);
237- +
238- switch (dev->flags & MODEL_MASK) {
239- case MODEL_MSCC_OCELOT:
240- dev->ext = devm_platform_ioremap_resource(pdev, 1);
215+ gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN);
241216- -
242- 2.39.2
217+ 1.8.3.1
243218
0 commit comments