From ca601f7df6e86f6142750e7034c5f7373538a79c Mon Sep 17 00:00:00 2001 From: Kilian Krause Date: Fri, 13 Feb 2026 13:08:52 +0100 Subject: [PATCH] drivers/i2c/rv3028c7: Use byte ops for i801 SMBus compatibility The RV3028-C7 driver currently uses i2c_dev_read_at() and i2c_dev_write_at() for block transfers when accessing RTC registers. These block transfer functions are not universally supported across all I2C/SMBus controller implementations in coreboot. Specifically, the Intel i801 SMBus controller does not implement block read/write operations, causing the RV3028-C7 driver to fail on platforms using this controller due to missing transfer ops. Replace block transfers with byte-by-byte operations i2c_dev_readb_at() and i2c_dev_writeb_at(). These functions are supported by i801. TEST=Verified new SMBus functionality on mc_ehl8 (i801 controller). Verified I2C functionality still works on mc_ehl2. Used i2ctools from OS to read out registers 0x00-0x06 and confirmed values match date/time set in coreboot. Change-Id: I8a40ae14e62e3acf7c3904a8654c1d58fe4eb813 Signed-off-by: Kilian Krause Reviewed-on: https://review.coreboot.org/c/coreboot/+/91199 Reviewed-by: Mario Scheithauer Tested-by: build bot (Jenkins) --- src/drivers/i2c/rv3028c7/rv3028c7.c | 38 +++++++++++++++++------------ 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/drivers/i2c/rv3028c7/rv3028c7.c b/src/drivers/i2c/rv3028c7/rv3028c7.c index 0a1e4b6872..a8ac33b5a2 100644 --- a/src/drivers/i2c/rv3028c7/rv3028c7.c +++ b/src/drivers/i2c/rv3028c7/rv3028c7.c @@ -86,29 +86,37 @@ static void rtc_set_time_date(struct device *dev) buf[6] = coreboot_build_date.year; printk(BIOS_DEBUG, "%s: Set to coreboot build date\n", dev->chip_ops->name); } - /* According to the datasheet, date and time should be transferred in "one go" - in order to avoid value corruption. */ - if (i2c_dev_write_at(dev, buf, sizeof(buf), 0) != sizeof(buf)) { - printk(BIOS_ERR, "%s: Not able to set date and time!\n", dev->chip_ops->name); + for (size_t i = 0; i < ARRAY_SIZE(buf); i++) { + if (i2c_dev_writeb_at(dev, i, buf[i]) < 0) { + printk(BIOS_ERR, "%s: Failed to write register 0x%02zx!\n", + dev->chip_ops->name, i); + return; + } } } static void rtc_final(struct device *dev) { uint8_t buf[7]; + int val; + /* Read back current RTC date and time byte by byte */ + printk(BIOS_DEBUG, "%s: Reading current date and time...\n", dev->chip_ops->name); - /* Read back current RTC date and time and print it to the console. - Date and time are read in "one go", the buffer contains seconds (byte 0) - through years (byte 6) after this read. */ - if (i2c_dev_read_at(dev, buf, sizeof(buf), 0) != sizeof(buf)) { - printk(BIOS_ERR, "%s: Not able to read current date and time!\n", - dev->chip_ops->name); - } else { - printk(BIOS_INFO, "%s: Current date %02d.%02d.%02d %02d:%02d:%02d\n", - dev->chip_ops->name, bcd2bin(buf[5]), bcd2bin(buf[4]), - bcd2bin(buf[6]), bcd2bin(buf[2]), bcd2bin(buf[1]), - bcd2bin(buf[0])); + for (size_t i = 0; i < ARRAY_SIZE(buf); i++) { + val = i2c_dev_readb_at(dev, i); + if (val < 0) { + printk(BIOS_ERR, "%s: Failed to read register 0x%02zx!\n", + dev->chip_ops->name, i); + return; + } + buf[i] = (uint8_t)val; } + + printk(BIOS_INFO, "%s: Current date %02d.%02d.%02d %02d:%02d:%02d\n", + dev->chip_ops->name, bcd2bin(buf[5]), bcd2bin(buf[4]), + bcd2bin(buf[6]), bcd2bin(buf[2]), bcd2bin(buf[1]), + bcd2bin(buf[0])); + /* Make sure the EEPROM automatic refresh is enabled. */ if (rtc_eep_auto_refresh(dev, EEP_REFRESH_EN) != CB_SUCCESS) { printk(BIOS_ERR, "%s: Not able to enable EEPROM auto refresh!\n",