git: e50e5090c165 - stable/12 - o Fix i2c read operation for large transfers (more than 32 bytes).

From: Andriy Gapon <avg_at_FreeBSD.org>
Date: Wed, 22 Dec 2021 07:32:36 UTC
The branch stable/12 has been updated by avg:

URL: https://cgit.FreeBSD.org/src/commit/?id=e50e5090c165b2eb32ecc3957ff24e5cfab182bf

commit e50e5090c165b2eb32ecc3957ff24e5cfab182bf
Author:     Ruslan Bukin <br@FreeBSD.org>
AuthorDate: 2021-05-26 09:55:23 +0000
Commit:     Andriy Gapon <avg@FreeBSD.org>
CommitDate: 2021-12-22 07:32:22 +0000

    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.
    
    (cherry picked from commit 38e7025a60b28623b5991622a6efd1b8a329ccb2)
---
 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 56d3e6cb2a1c..8edfaad771bf 100644
--- a/sys/arm64/rockchip/rk_i2c.c
+++ b/sys/arm64/rockchip/rk_i2c.c
@@ -298,6 +298,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);
 
@@ -331,11 +332,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 |
@@ -350,6 +356,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:
@@ -520,7 +543,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);