From 38e7025a60b28623b5991622a6efd1b8a329ccb2 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 26 May 2021 10:55:23 +0100 Subject: [PATCH] o Fix i2c read operation for large transfers (more than 32 bytes). o Fix slave address setting. This allows to read the EDID from an HDMI monitor. Reviewed by: manu Sponsored by: UKRI Differential Revision: https://reviews.freebsd.org/D27139 --- sys/arm64/rockchip/rk_i2c.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/sys/arm64/rockchip/rk_i2c.c b/sys/arm64/rockchip/rk_i2c.c index fa824c76003b..c54f523088fe 100644 --- a/sys/arm64/rockchip/rk_i2c.c +++ b/sys/arm64/rockchip/rk_i2c.c @@ -291,6 +291,7 @@ static void rk_i2c_intr_locked(struct rk_i2c_softc *sc) { uint32_t reg; + int transfer_len; sc->ipd = RK_I2C_READ(sc, RK_I2C_IPD); @@ -324,11 +325,16 @@ rk_i2c_intr_locked(struct rk_i2c_softc *sc) RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBRFIEN | RK_I2C_IEN_NAKRCVIEN); - reg = RK_I2C_READ(sc, RK_I2C_CON); - reg |= RK_I2C_CON_LASTACK; - RK_I2C_WRITE(sc, RK_I2C_CON, reg); + if ((sc->msg->len - sc->cnt) > 32) + transfer_len = 32; + else { + transfer_len = sc->msg->len - sc->cnt; + reg = RK_I2C_READ(sc, RK_I2C_CON); + reg |= RK_I2C_CON_LASTACK; + RK_I2C_WRITE(sc, RK_I2C_CON, reg); + } - RK_I2C_WRITE(sc, RK_I2C_MRXCNT, sc->msg->len); + RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len); } else { sc->state = STATE_WRITE; RK_I2C_WRITE(sc, RK_I2C_IEN, RK_I2C_IEN_MBTFIEN | @@ -344,6 +350,23 @@ rk_i2c_intr_locked(struct rk_i2c_softc *sc) if (sc->cnt == sc->msg->len) rk_i2c_send_stop(sc); + else { + sc->mode = RK_I2C_CON_MODE_RX; + reg = RK_I2C_READ(sc, RK_I2C_CON) & \ + ~RK_I2C_CON_CTRL_MASK; + reg |= sc->mode << RK_I2C_CON_MODE_SHIFT; + reg |= RK_I2C_CON_EN; + + if ((sc->msg->len - sc->cnt) > 32) + transfer_len = 32; + else { + transfer_len = sc->msg->len - sc->cnt; + reg |= RK_I2C_CON_LASTACK; + } + + RK_I2C_WRITE(sc, RK_I2C_CON, reg); + RK_I2C_WRITE(sc, RK_I2C_MRXCNT, transfer_len); + } break; case STATE_WRITE: @@ -509,7 +532,7 @@ rk_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) sc->mode = RK_I2C_CON_MODE_RX; } else { sc->mode = RK_I2C_CON_MODE_RRX; - reg = msgs[i].slave & LSB; + reg = msgs[i].slave & ~LSB; reg |= RK_I2C_MRXADDR_VALID(0); RK_I2C_WRITE(sc, RK_I2C_MRXADDR, reg); RK_I2C_WRITE(sc, RK_I2C_MRXRADDR, 0);