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 <kilian.krause@siemens.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/91199
Reviewed-by: Mario Scheithauer <mario.scheithauer@siemens.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Kilian Krause 2026-02-13 13:08:52 +01:00 committed by Matt DeVillier
commit ca601f7df6

View file

@ -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",