Commit 33e76e06 authored by Josua Mayer's avatar Josua Mayer

atf: flush i2c channels hidden behind muxes

i2c muxes are reset with cpu reset and will default back to channel 0,
while any other channel may still be blocked by a slave.
Detect known muxes and flush all their channels if detected.

Further disable detection logic because it missed rare cases.
Reset unconditionally instead.
Signed-off-by: default avatarJosua Mayer <josua@solid-run.com>
parent 275c6a53
From 097f2c352af953cdb2515f8ffdff4f384f8c35c0 Mon Sep 17 00:00:00 2001 From d9118d3e9ff4d493d30a9fac19a1679b4e8913af Mon Sep 17 00:00:00 2001
From: Josua Mayer <josua@solid-run.com> From: Josua Mayer <josua@solid-run.com>
Date: Thu, 26 May 2022 11:22:53 +0300 Date: Thu, 26 May 2022 11:22:53 +0300
Subject: [PATCH] lx2160a: flush i2c bus before initialising ddr Subject: [PATCH 5/7] lx2160a: flush i2c bus before initialising ddr
The i2c bus can get locked by a slave device holding sda low, when the The i2c bus can get locked by a slave device holding sda low, when the
cpu is reset during a transaction. cpu is reset during a transaction.
...@@ -9,12 +9,11 @@ Implement workaround according to LX2160A Chip Errata 07/2020 A-010650. ...@@ -9,12 +9,11 @@ Implement workaround according to LX2160A Chip Errata 07/2020 A-010650.
Signed-off-by: Josua Mayer <josua@solid-run.com> Signed-off-by: Josua Mayer <josua@solid-run.com>
--- ---
plat/nxp/common/setup/common.mk | 1 + plat/nxp/common/setup/common.mk | 1 +
plat/nxp/common/setup/ls_bl2_el3_setup.c | 5 + plat/nxp/common/setup/ls_bl2_el3_setup.c | 5 +
plat/nxp/common/setup/ls_common.c | 1 + plat/nxp/common/setup/ls_common.c | 1 +
plat/nxp/common/setup/ls_i2c_init.c | 228 ++++++++++++++++++++ plat/nxp/common/setup/ls_i2c_init.c | 231 +++++++++++++++++++++++
plat/nxp/soc-lx2160a/lx2160acex7/ddr_init.c | 1 + 4 files changed, 238 insertions(+)
5 files changed, 236 insertions(+)
create mode 100644 plat/nxp/common/setup/ls_i2c_init.c create mode 100644 plat/nxp/common/setup/ls_i2c_init.c
diff --git a/plat/nxp/common/setup/common.mk b/plat/nxp/common/setup/common.mk diff --git a/plat/nxp/common/setup/common.mk b/plat/nxp/common/setup/common.mk
...@@ -66,10 +65,10 @@ index f8bc99130..6d9b6c9aa 100644 ...@@ -66,10 +65,10 @@ index f8bc99130..6d9b6c9aa 100644
#include <mmu_def.h> #include <mmu_def.h>
diff --git a/plat/nxp/common/setup/ls_i2c_init.c b/plat/nxp/common/setup/ls_i2c_init.c diff --git a/plat/nxp/common/setup/ls_i2c_init.c b/plat/nxp/common/setup/ls_i2c_init.c
new file mode 100644 new file mode 100644
index 000000000..ef113126c index 000000000..13b505c12
--- /dev/null --- /dev/null
+++ b/plat/nxp/common/setup/ls_i2c_init.c +++ b/plat/nxp/common/setup/ls_i2c_init.c
@@ -0,0 +1,228 @@ @@ -0,0 +1,231 @@
+#include <stdint.h> +#include <stdint.h>
+#include <stdio.h> +#include <stdio.h>
+#include <stdlib.h> +#include <stdlib.h>
...@@ -90,19 +89,19 @@ index 000000000..ef113126c ...@@ -90,19 +89,19 @@ index 000000000..ef113126c
+#define NXP_IIC8_ADDR 0x02070000 +#define NXP_IIC8_ADDR 0x02070000
+ +
+#define RCWSR12 0x70010012c +#define RCWSR12 0x70010012c
+#define RCWSR12_IIC2_PMUX_MASK 0x00000007 // [0..2] +#define RCWSR12_IIC2_PMUX_MASK 0x00000007 /* [0..2] */
+#define RCWSR12_IIC2_PMUX_IIC2 0x00000000 +#define RCWSR12_IIC2_PMUX_IIC2 0x00000000
+#define RCWSR12_IIC2_PMUX_GPIO 0x00000001 +#define RCWSR12_IIC2_PMUX_GPIO 0x00000001
+#define RCWSR12_IIC3_PMUX_MASK 0x00000038 // [3..5] +#define RCWSR12_IIC3_PMUX_MASK 0x00000038 /* [3..5] */
+#define RCWSR12_IIC3_PMUX_IIC3 0x00000000 +#define RCWSR12_IIC3_PMUX_IIC3 0x00000000
+#define RCWSR12_IIC3_PMUX_GPIO 0x00000008 +#define RCWSR12_IIC3_PMUX_GPIO 0x00000008
+#define RCWSR12_IIC4_PMUX_MASK 0x000001c0 // [6..8] +#define RCWSR12_IIC4_PMUX_MASK 0x000001c0 /* [6..8] */
+#define RCWSR12_IIC4_PMUX_IIC4 0x00000000 +#define RCWSR12_IIC4_PMUX_IIC4 0x00000000
+#define RCWSR12_IIC4_PMUX_GPIO 0x00000040 +#define RCWSR12_IIC4_PMUX_GPIO 0x00000040
+#define RCWSR12_IIC5_PMUX_MASK 0x00000e00 // [9..11] +#define RCWSR12_IIC5_PMUX_MASK 0x00000e00 /* [9..11] */
+#define RCWSR12_IIC5_PMUX_IIC5 0x00000000 +#define RCWSR12_IIC5_PMUX_IIC5 0x00000000
+#define RCWSR12_IIC5_PMUX_GPIO 0x00000200 +#define RCWSR12_IIC5_PMUX_GPIO 0x00000200
+#define RCWSR12_IIC6_PMUX_MASK 0x00007000 // [12..14] +#define RCWSR12_IIC6_PMUX_MASK 0x00007000 /* [12..14] */
+#define RCWSR12_IIC6_PMUX_IIC6 0x00000000 +#define RCWSR12_IIC6_PMUX_IIC6 0x00000000
+#define RCWSR12_IIC6_PMUX_GPIO 0x00001000 +#define RCWSR12_IIC6_PMUX_GPIO 0x00001000
+#define RCWSR13 0x700100130 +#define RCWSR13 0x700100130
...@@ -110,7 +109,7 @@ index 000000000..ef113126c ...@@ -110,7 +109,7 @@ index 000000000..ef113126c
+#define RCWSR12_SDHC2_DAT74_PMUX_SDHC2 0x00000000 +#define RCWSR12_SDHC2_DAT74_PMUX_SDHC2 0x00000000
+#define RCWSR12_SDHC2_DAT74_PMUX_IIC78 0x00000001 +#define RCWSR12_SDHC2_DAT74_PMUX_IIC78 0x00000001
+#define RCWSR14 0x700100134 +#define RCWSR14 0x700100134
+#define RCWSR14_IIC1_PMUX_MASK 0x00000400 // [10] +#define RCWSR14_IIC1_PMUX_MASK 0x00000400 /* [10] */
+#define RCWSR14_IIC1_PMUX_IIC1 0x00000000 +#define RCWSR14_IIC1_PMUX_IIC1 0x00000000
+#define RCWSR14_IIC1_PMUX_GPIO 0x00000400 +#define RCWSR14_IIC1_PMUX_GPIO 0x00000400
+ +
...@@ -121,15 +120,15 @@ index 000000000..ef113126c ...@@ -121,15 +120,15 @@ index 000000000..ef113126c
+ * in case the system was reset during a transaction. + * in case the system was reset during a transaction.
+ */ + */
+void bl2_i2c_init() { +void bl2_i2c_init() {
+ // IIC5 + /* IIC5 */
+ i2c_init(NXP_IIC5_ADDR); + i2c_init(NXP_IIC5_ADDR);
+ ls_i2c_flush(4, "IIC5"); + ls_i2c_flush(4, "IIC5");
+ +
+ // IIC3 + /* IIC3 */
+ i2c_init(NXP_IIC3_ADDR); + i2c_init(NXP_IIC3_ADDR);
+ ls_i2c_flush(2, "IIC3"); + ls_i2c_flush(2, "IIC3");
+ +
+ // IIC1 + /* IIC1 */
+ i2c_init(NXP_IIC1_ADDR); + i2c_init(NXP_IIC1_ADDR);
+ ls_i2c_flush(0, "IIC1"); + ls_i2c_flush(0, "IIC1");
+} +}
...@@ -144,67 +143,67 @@ index 000000000..ef113126c ...@@ -144,67 +143,67 @@ index 000000000..ef113126c
+} ls_i2c_bus_info[] = { +} ls_i2c_bus_info[] = {
+ { + {
+ .pinmux_addr = RCWSR14, + .pinmux_addr = RCWSR14,
+ .pinmux_mask = RCWSR14_IIC1_PMUX_MASK, // bit 10 - 0x200000? + .pinmux_mask = RCWSR14_IIC1_PMUX_MASK,
+ .pinmux_sel = RCWSR14_IIC1_PMUX_GPIO, + .pinmux_sel = RCWSR14_IIC1_PMUX_GPIO,
+ .gpio_addr = NXP_GPIO1_ADDR, + .gpio_addr = NXP_GPIO1_ADDR,
+ .gpio_scl = 3, // GPIO1_DAT03 + .gpio_scl = 3, /* GPIO1_DAT03 */
+ .gpio_sda = 2, // GPIO1_DAT02 + .gpio_sda = 2, /* GPIO1_DAT02 */
+ }, + },
+ { + {
+ .pinmux_addr = RCWSR12, + .pinmux_addr = RCWSR12,
+ .pinmux_mask = RCWSR12_IIC2_PMUX_MASK, + .pinmux_mask = RCWSR12_IIC2_PMUX_MASK,
+ .pinmux_sel = RCWSR12_IIC2_PMUX_GPIO, + .pinmux_sel = RCWSR12_IIC2_PMUX_GPIO,
+ .gpio_addr = NXP_GPIO1_ADDR, + .gpio_addr = NXP_GPIO1_ADDR,
+ .gpio_scl = 31, // GPIO1_DAT31 + .gpio_scl = 31, /* GPIO1_DAT31 */
+ .gpio_sda = 30, // GPIO1_DAT30 + .gpio_sda = 30, /* GPIO1_DAT30 */
+ }, + },
+ { + {
+ .pinmux_addr = RCWSR12, + .pinmux_addr = RCWSR12,
+ .pinmux_mask = RCWSR12_IIC3_PMUX_MASK, + .pinmux_mask = RCWSR12_IIC3_PMUX_MASK,
+ .pinmux_sel = RCWSR12_IIC3_PMUX_GPIO, + .pinmux_sel = RCWSR12_IIC3_PMUX_GPIO,
+ .gpio_addr = NXP_GPIO1_ADDR, + .gpio_addr = NXP_GPIO1_ADDR,
+ .gpio_scl = 29, // GPIO1_DAT29 + .gpio_scl = 29, /* GPIO1_DAT29 */
+ .gpio_sda = 28, // GPIO1_DAT28 + .gpio_sda = 28, /* GPIO1_DAT28 */
+ }, + },
+ { + {
+ .pinmux_addr = RCWSR12, + .pinmux_addr = RCWSR12,
+ .pinmux_mask = RCWSR12_IIC4_PMUX_MASK, + .pinmux_mask = RCWSR12_IIC4_PMUX_MASK,
+ .pinmux_sel = RCWSR12_IIC4_PMUX_GPIO, + .pinmux_sel = RCWSR12_IIC4_PMUX_GPIO,
+ .gpio_addr = NXP_GPIO1_ADDR, + .gpio_addr = NXP_GPIO1_ADDR,
+ .gpio_scl = 27, // GPIO1_DAT27 + .gpio_scl = 27, /* GPIO1_DAT27 */
+ .gpio_sda = 26, // GPIO1_DAT26 + .gpio_sda = 26, /* GPIO1_DAT26 */
+ }, + },
+ { + {
+ .pinmux_addr = RCWSR12, + .pinmux_addr = RCWSR12,
+ .pinmux_mask = RCWSR12_IIC5_PMUX_MASK, + .pinmux_mask = RCWSR12_IIC5_PMUX_MASK,
+ .pinmux_sel = RCWSR12_IIC5_PMUX_GPIO, + .pinmux_sel = RCWSR12_IIC5_PMUX_GPIO,
+ .gpio_addr = NXP_GPIO1_ADDR, + .gpio_addr = NXP_GPIO1_ADDR,
+ .gpio_scl = 25, // GPIO1_DAT25 + .gpio_scl = 25, /* GPIO1_DAT25 */
+ .gpio_sda = 24, // GPIO1_DAT24 + .gpio_sda = 24, /* GPIO1_DAT24 */
+ }, + },
+ { + {
+ .pinmux_addr = RCWSR12, + .pinmux_addr = RCWSR12,
+ .pinmux_mask = RCWSR12_IIC6_PMUX_MASK, + .pinmux_mask = RCWSR12_IIC6_PMUX_MASK,
+ .pinmux_sel = RCWSR12_IIC6_PMUX_GPIO, + .pinmux_sel = RCWSR12_IIC6_PMUX_GPIO,
+ .gpio_addr = NXP_GPIO1_ADDR, + .gpio_addr = NXP_GPIO1_ADDR,
+ .gpio_scl = 23, // GPIO1_DAT23 + .gpio_scl = 23, /* GPIO1_DAT23 */
+ .gpio_sda = 22, // GPIO1_DAT22 + .gpio_sda = 22, /* GPIO1_DAT22 */
+ }, + },
+ { + {
+ .pinmux_addr = RCWSR13, + .pinmux_addr = RCWSR13,
+ .pinmux_mask = RCWSR12_SDHC2_DAT74_PMUX_MASK, + .pinmux_mask = RCWSR12_SDHC2_DAT74_PMUX_MASK,
+ .pinmux_sel = RCWSR12_SDHC2_DAT74_PMUX_IIC78, + .pinmux_sel = RCWSR12_SDHC2_DAT74_PMUX_IIC78,
+ .gpio_addr = NXP_GPIO2_ADDR, + .gpio_addr = NXP_GPIO2_ADDR,
+ .gpio_scl = 16, // GPIO2_DAT16 + .gpio_scl = 16, /* GPIO2_DAT16 */
+ .gpio_sda = 15, // GPIO2_DAT15 + .gpio_sda = 15, /* GPIO2_DAT15 */
+ }, + },
+ { + {
+ .pinmux_addr = RCWSR13, + .pinmux_addr = RCWSR13,
+ .pinmux_mask = RCWSR12_SDHC2_DAT74_PMUX_MASK, + .pinmux_mask = RCWSR12_SDHC2_DAT74_PMUX_MASK,
+ .pinmux_sel = RCWSR12_SDHC2_DAT74_PMUX_IIC78, + .pinmux_sel = RCWSR12_SDHC2_DAT74_PMUX_IIC78,
+ .gpio_addr = NXP_GPIO2_ADDR, + .gpio_addr = NXP_GPIO2_ADDR,
+ .gpio_scl = 18, // GPIO2_DAT18 + .gpio_scl = 18, /* GPIO2_DAT18 */
+ .gpio_sda = 17, // GPIO2_DAT17 + .gpio_sda = 17, /* GPIO2_DAT17 */
+ }, + },
+}; +};
+ +
...@@ -250,7 +249,6 @@ index 000000000..ef113126c ...@@ -250,7 +249,6 @@ index 000000000..ef113126c
+ mmio_write_32(info->pinmux_addr, pinmux); + mmio_write_32(info->pinmux_addr, pinmux);
+ +
+ /* configure SCL as output open drain + SDA as input open drain */ + /* configure SCL as output open drain + SDA as input open drain */
+ //gpdir = (gpdir | scl_mask) & ~sda_mask;
+ gpdir = (gpdir | scl_mask) & ~sda_mask; + gpdir = (gpdir | scl_mask) & ~sda_mask;
+ gpodr |= scl_mask | sda_mask; + gpodr |= scl_mask | sda_mask;
+ gpdat |= scl_mask | sda_mask; + gpdat |= scl_mask | sda_mask;
...@@ -259,7 +257,9 @@ index 000000000..ef113126c ...@@ -259,7 +257,9 @@ index 000000000..ef113126c
+ mmio_write_32(gpodr_addr, gpodr); + mmio_write_32(gpodr_addr, gpodr);
+ mmio_write_32(gpdat_addr, gpdat); + mmio_write_32(gpdat_addr, gpdat);
+ mmio_write_32(gpibe_addr, gpibe); + mmio_write_32(gpibe_addr, gpibe);
+ udelay(1); +
+ /* delay at least one cycle to for a slave to complete one bit */
+ udelay(10);
+ +
+ /* + /*
+ * detect if bus is blocked: sda is expected high while scl is high. + * detect if bus is blocked: sda is expected high while scl is high.
...@@ -267,7 +267,7 @@ index 000000000..ef113126c ...@@ -267,7 +267,7 @@ index 000000000..ef113126c
+ */ + */
+ gpdat = mmio_read_32(gpdat_addr); + gpdat = mmio_read_32(gpdat_addr);
+ if(gpdat & sda_mask) { + if(gpdat & sda_mask) {
+ // not blocked, nothing to do + /* not blocked, nothing to do */
+ goto restore; + goto restore;
+ } + }
+ NOTICE("flushing blocked i2c bus %u (%s)\n", busno, busname); + NOTICE("flushing blocked i2c bus %u (%s)\n", busno, busname);
...@@ -280,6 +280,8 @@ index 000000000..ef113126c ...@@ -280,6 +280,8 @@ index 000000000..ef113126c
+ mmio_write_32(gpdat_addr, gpdat); + mmio_write_32(gpdat_addr, gpdat);
+ mmio_write_32(gpibe_addr, gpibe); + mmio_write_32(gpibe_addr, gpibe);
+ +
+ VERBOSE("flushing i2c bus %u (%s)\n", busno, busname);
+
+ /* toggle clock 9 times */ + /* toggle clock 9 times */
+ for(uint8_t i = 0; i < 9; i++) { + for(uint8_t i = 0; i < 9; i++) {
+ mmio_write_32(gpdat_addr, gpdat & ~scl_mask); + mmio_write_32(gpdat_addr, gpdat & ~scl_mask);
...@@ -298,18 +300,6 @@ index 000000000..ef113126c ...@@ -298,18 +300,6 @@ index 000000000..ef113126c
+ +
+ return; + return;
+} +}
diff --git a/plat/nxp/soc-lx2160a/lx2160acex7/ddr_init.c b/plat/nxp/soc-lx2160a/lx2160acex7/ddr_init.c
index eb28216e7..9f1c50449 100644
--- a/plat/nxp/soc-lx2160a/lx2160acex7/ddr_init.c
+++ b/plat/nxp/soc-lx2160a/lx2160acex7/ddr_init.c
@@ -101,6 +101,7 @@ long long init_ddr(void)
}
#endif
+ NOTICE("DDR init\n");
dram_size = dram_init(&info
#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
, NXP_CCN_HN_F_0_ADDR
-- --
2.35.3 2.35.3
From 8e43e0c3b8ea4d7d1ea8a0b03c2113b4ae22c4b1 Mon Sep 17 00:00:00 2001
From: Josua Mayer <josua@solid-run.com>
Date: Mon, 30 May 2022 18:57:37 +0300
Subject: [PATCH 6/7] lx2160a: flush i2c bus connected mux channels
Some i2c buses have multi-channel muxes connected.
During reset channel 0 is selected by default; However any other channel
may be in a blocked state.
Detect if known muxes are connected and flush all their channels.
Signed-off-by: Josua Mayer <josua@solid-run.com>
---
plat/nxp/common/setup/ls_i2c_init.c | 42 +++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/plat/nxp/common/setup/ls_i2c_init.c b/plat/nxp/common/setup/ls_i2c_init.c
index 13b505c12..cf1a7207a 100644
--- a/plat/nxp/common/setup/ls_i2c_init.c
+++ b/plat/nxp/common/setup/ls_i2c_init.c
@@ -42,6 +42,7 @@
#define RCWSR14_IIC1_PMUX_IIC1 0x00000000
#define RCWSR14_IIC1_PMUX_GPIO 0x00000400
+static void ls_i2c_flush_pca9547(uint8_t busno, const char *busname, uint8_t address);
static void ls_i2c_flush(uint8_t busno, const char *busname);
/**
@@ -57,9 +58,50 @@ void bl2_i2c_init() {
i2c_init(NXP_IIC3_ADDR);
ls_i2c_flush(2, "IIC3");
+ /* IIC3: twins: pca9547@77 */
+ ls_i2c_flush_pca9547(2, "IIC3", 0x77);
+
+ /* IIC3: twins: pca9547@76 */
+ ls_i2c_flush_pca9547(2, "IIC3", 0x76);
+
+ /* IIC3: half-twins: pca9547@73 */
+ ls_i2c_flush_pca9547(2, "IIC3", 0x73);
+
/* IIC1 */
i2c_init(NXP_IIC1_ADDR);
ls_i2c_flush(0, "IIC1");
+
+ /* IIC1: cex7: pca9547@77 */
+ ls_i2c_flush_pca9547(0, "IIC1", 0x77);
+}
+
+static void ls_i2c_flush_pca9547(uint8_t busno, const char *busname, uint8_t chip) {
+ uint8_t channel, creg = 0;
+ char buffer[64];
+ int ret;
+
+ /* try read configuration register */
+ ret = i2c_read(chip, 0x00, 1, &creg, 1);
+ if(ret != 0) {
+ /* no device responding at address, skip */
+ return;
+ }
+
+ /* after reset configuration register reads 0x08 */
+ if(creg != 0x08) {
+ /* probably not a pca9547, skip */
+ return;
+ }
+
+ for(uint8_t i = 8; i > 0; i--) {
+ /* select channel i */
+ channel = 0x08 | (i-1);
+ i2c_write(chip, 0x00, 1, &channel, 1);
+
+ /* flush channel */
+ snprintf(buffer, sizeof(buffer), "%s mux@%02x channel %u", busname, chip, i);
+ ls_i2c_flush(busno, buffer);
+ }
}
static struct i2c_bus_info {
--
2.35.3
From 9ff38bdb447c9c90c9e56101dba47410f67f1e09 Mon Sep 17 00:00:00 2001
From: Josua Mayer <josua@solid-run.com>
Date: Tue, 31 May 2022 10:16:49 +0300
Subject: [PATCH 7/7] lx2160a: flush i2c buses unconditionally
Detection of the error case is difficult because the value of sda
depends on the previously written bit.
Remove detection code and flush every time.
Signed-off-by: Josua Mayer <josua@solid-run.com>
---
plat/nxp/common/setup/ls_i2c_init.c | 38 ++++++-----------------------
1 file changed, 8 insertions(+), 30 deletions(-)
diff --git a/plat/nxp/common/setup/ls_i2c_init.c b/plat/nxp/common/setup/ls_i2c_init.c
index cf1a7207a..202fe2e6d 100644
--- a/plat/nxp/common/setup/ls_i2c_init.c
+++ b/plat/nxp/common/setup/ls_i2c_init.c
@@ -188,10 +188,10 @@ static struct i2c_bus_info {
*/
static void ls_i2c_flush(uint8_t busno, const char *busname) {
struct i2c_bus_info *info;
- uintptr_t gpdir_addr, gpodr_addr, gpdat_addr, gpibe_addr;
- uint32_t pinmux, gpdir, gpodr, gpdat, gpibe;
+ uintptr_t gpdir_addr, gpodr_addr, gpdat_addr;
+ uint32_t pinmux, gpdir, gpodr, gpdat;
struct {
- uint32_t pinmux, gpdir, gpodr, gpdat, gpibe;
+ uint32_t pinmux, gpdir, gpodr, gpdat;
} backup;
uint32_t scl_mask, sda_mask;
@@ -204,7 +204,6 @@ static void ls_i2c_flush(uint8_t busno, const char *busname) {
gpdir_addr = info->gpio_addr + 0x0;
gpodr_addr = info->gpio_addr + 0x4;
gpdat_addr = info->gpio_addr + 0x8;
- gpibe_addr = info->gpio_addr + 0x18;
scl_mask = 0x80000000 >> info->gpio_scl;
sda_mask = 0x80000000 >> info->gpio_sda;
@@ -213,43 +212,24 @@ static void ls_i2c_flush(uint8_t busno, const char *busname) {
gpdir = backup.gpdir = mmio_read_32(gpdir_addr);
gpodr = backup.gpodr = mmio_read_32(gpodr_addr);
gpdat = backup.gpdat = mmio_read_32(gpdat_addr);
- gpibe = backup.gpibe = mmio_read_32(gpibe_addr);
/* configure SCL+SDA as GPIOs */
pinmux = (pinmux & ~info->pinmux_mask) | info->pinmux_sel;
mmio_write_32(info->pinmux_addr, pinmux);
- /* configure SCL as output open drain + SDA as input open drain */
- gpdir = (gpdir | scl_mask) & ~sda_mask;
+ /* configure SCL+SDA as output open drain */
+ gpdir |= scl_mask | sda_mask;
gpodr |= scl_mask | sda_mask;
gpdat |= scl_mask | sda_mask;
- gpibe |= sda_mask;
mmio_write_32(gpdir_addr, gpdir);
mmio_write_32(gpodr_addr, gpodr);
mmio_write_32(gpdat_addr, gpdat);
- mmio_write_32(gpibe_addr, gpibe);
-
- /* delay at least one cycle to for a slave to complete one bit */
- udelay(10);
/*
- * detect if bus is blocked: sda is expected high while scl is high.
- * If sda is still low, a slave device is blocking it.
+ * reliable detection of blocked bus is hard
+ * because sda depends on the last sent bit.
+ * Flush unconditionally instead.
*/
- gpdat = mmio_read_32(gpdat_addr);
- if(gpdat & sda_mask) {
- /* not blocked, nothing to do */
- goto restore;
- }
- NOTICE("flushing blocked i2c bus %u (%s)\n", busno, busname);
-
- /* configure SCL+SDA as output open drain */
- gpdir |= sda_mask;
- gpdat |= sda_mask;
- gpibe &= ~sda_mask;
- mmio_write_32(gpdir_addr, gpdir);
- mmio_write_32(gpdat_addr, gpdat);
- mmio_write_32(gpibe_addr, gpibe);
VERBOSE("flushing i2c bus %u (%s)\n", busno, busname);
@@ -261,9 +241,7 @@ static void ls_i2c_flush(uint8_t busno, const char *busname) {
udelay(10);
}
-restore:
/* restore configuration registers */
- mmio_write_32(gpibe_addr, backup.gpibe);
mmio_write_32(gpdat_addr, backup.gpdat);
mmio_write_32(gpodr_addr, backup.gpodr);
mmio_write_32(gpdir_addr, backup.gpdir);
--
2.35.3
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment