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
This commit is contained in:
Ruslan Bukin 2021-05-26 10:55:23 +01:00
parent 14803ec8d1
commit 38e7025a60

View File

@ -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);