From 8f8d017fb3e5f8d73bb415295495023353049f79 Mon Sep 17 00:00:00 2001 From: Ting Shen Date: Fri, 13 Nov 2020 12:56:34 +0800 Subject: i2c_master: extend i2c_xfer_no_retry to also support large write This CL extends CONFIG_I2C_XFER_LARGE_READ to also support large (greater than 255 bytes) write. Related config name is also updated to reflect the behavior change, BUG=b:169651794 TEST=flash fw successfully on Zed. BRANCH=none Signed-off-by: Ting Shen Change-Id: Icb889013da01f48708cd0227207561b8186bac63 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2537412 Reviewed-by: Nicolas Boichat Commit-Queue: Ting Shen Tested-by: Ting Shen --- board/c2d2/board.h | 2 +- board/hammer/board.h | 2 +- board/servo_micro/board.h | 2 +- chip/stm32/i2c_ite_flash_support.c | 8 +++--- common/i2c_master.c | 59 ++++++++++++++++++++++---------------- docs/configuration/i2c.md | 2 +- include/config.h | 10 +++---- include/i2c.h | 6 ++-- 8 files changed, 51 insertions(+), 40 deletions(-) diff --git a/board/c2d2/board.h b/board/c2d2/board.h index 770851332c..d3a8a35bdb 100644 --- a/board/c2d2/board.h +++ b/board/c2d2/board.h @@ -84,7 +84,7 @@ /* See i2c_ite_flash_support.c for more information about these values */ #define CONFIG_ITE_FLASH_SUPPORT -#define CONFIG_I2C_XFER_LARGE_READ +#define CONFIG_I2C_XFER_LARGE_TRANSFER #undef CONFIG_USB_I2C_MAX_WRITE_COUNT #undef CONFIG_USB_I2C_MAX_READ_COUNT #define CONFIG_USB_I2C_MAX_WRITE_COUNT ((1<<9) - 4) diff --git a/board/hammer/board.h b/board/hammer/board.h index 5903abe1df..60ec82eae7 100644 --- a/board/hammer/board.h +++ b/board/hammer/board.h @@ -180,7 +180,7 @@ #undef CONFIG_USB_I2C_MAX_READ_COUNT #define CONFIG_USB_I2C_MAX_READ_COUNT (1024 - 6) /* 6 is maximum header size */ -#define CONFIG_I2C_XFER_LARGE_READ +#define CONFIG_I2C_XFER_LARGE_TRANSFER /* No lid switch */ #undef CONFIG_LID_SWITCH diff --git a/board/servo_micro/board.h b/board/servo_micro/board.h index 1565a63f9a..c597861242 100644 --- a/board/servo_micro/board.h +++ b/board/servo_micro/board.h @@ -90,7 +90,7 @@ /* See i2c_ite_flash_support.c for more information about these values */ #define CONFIG_ITE_FLASH_SUPPORT -#define CONFIG_I2C_XFER_LARGE_READ +#define CONFIG_I2C_XFER_LARGE_TRANSFER #undef CONFIG_USB_I2C_MAX_WRITE_COUNT #undef CONFIG_USB_I2C_MAX_READ_COUNT #define CONFIG_USB_I2C_MAX_WRITE_COUNT ((1<<9) - 4) diff --git a/chip/stm32/i2c_ite_flash_support.c b/chip/stm32/i2c_ite_flash_support.c index eca3c999af..916a8c364c 100644 --- a/chip/stm32/i2c_ite_flash_support.c +++ b/chip/stm32/i2c_ite_flash_support.c @@ -42,11 +42,11 @@ /* * iteflash requires 256 byte reads for verifying ITE EC firmware. Without this - * the limit is CONFIG_I2C_CHIP_MAX_READ_SIZE which is 255 for STM32F0 due to an - * 8 bit field, per src/platform/ec/include/config.h comment. + * the limit is CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE which is 255 for STM32F0 due + * to an 8 bit field, per src/platform/ec/include/config.h comment. */ -#ifndef CONFIG_I2C_XFER_LARGE_READ -#error Must define CONFIG_I2C_XFER_LARGE_READ +#ifndef CONFIG_I2C_XFER_LARGE_TRANSFER +#error Must define CONFIG_I2C_XFER_LARGE_TRANSFER #endif #define KHz 1000 diff --git a/common/i2c_master.c b/common/i2c_master.c index 7702beebb3..ee54468dea 100644 --- a/common/i2c_master.c +++ b/common/i2c_master.c @@ -142,37 +142,48 @@ __maybe_unused static int chip_i2c_xfer_with_notify( return ret; } -#ifdef CONFIG_I2C_XFER_LARGE_READ +#ifdef CONFIG_I2C_XFER_LARGE_TRANSFER /* - * Internal function that splits reading into multiple chip_i2c_xfer() calls - * if in_size exceeds CONFIG_I2C_CHIP_MAX_READ_SIZE. + * Internal function that splits transfer into multiple chip_i2c_xfer() calls + * if in_size or out_size exceeds CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE. */ static int i2c_xfer_no_retry(const int port, const uint16_t slave_addr_flags, const uint8_t *out, int out_size, uint8_t *in, int in_size, int flags) { - int ret; - int out_flags = flags & I2C_XFER_START; - int in_chunk_size = MIN(in_size, CONFIG_I2C_CHIP_MAX_READ_SIZE); - - in_size -= in_chunk_size; - out_flags |= !in_size ? (flags & I2C_XFER_STOP) : 0; - ret = chip_i2c_xfer_with_notify(port, slave_addr_flags, - out, out_size, in, - in_chunk_size, out_flags); - in += in_chunk_size; - while (in_size && ret == EC_SUCCESS) { - in_chunk_size = MIN(in_size, CONFIG_I2C_CHIP_MAX_READ_SIZE); - in_size -= in_chunk_size; - ret = chip_i2c_xfer_with_notify(port, slave_addr_flags, - NULL, 0, in, - in_chunk_size, !in_size ? (flags & I2C_XFER_STOP) : 0); - in += in_chunk_size; + for (int offset = 0; offset < out_size; ) { + int chunk_size = MIN(out_size - offset, + CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE); + int out_flags = 0; + + if (offset == 0) + out_flags |= flags & I2C_XFER_START; + if (in_size == 0 && offset + chunk_size == out_size) + out_flags |= flags & I2C_XFER_STOP; + + RETURN_ERROR(chip_i2c_xfer_with_notify(port, slave_addr_flags, + out + offset, chunk_size, NULL, 0, + out_flags)); + offset += chunk_size; } - return ret; + for (int offset = 0; offset < in_size; ) { + int chunk_size = MIN(in_size - offset, + CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE); + int in_flags = 0; + + if (offset == 0) + in_flags |= flags & I2C_XFER_START; + if (offset + chunk_size == in_size) + in_flags |= flags & I2C_XFER_STOP; + + RETURN_ERROR(chip_i2c_xfer_with_notify(port, slave_addr_flags, + NULL, 0, in + offset, chunk_size, in_flags)); + offset += chunk_size; + } + return EC_SUCCESS; } -#endif /* CONFIG_I2C_XFER_LARGE_READ */ +#endif /* CONFIG_I2C_XFER_LARGE_TRANSFER */ int i2c_xfer_unlocked(const int port, const uint16_t slave_addr_flags, @@ -192,7 +203,7 @@ int i2c_xfer_unlocked(const int port, #ifdef CONFIG_ZEPHYR ret = i2c_write_read(i2c_get_device_for_port(port), addr_flags, out, out_size, in, in_size); -#elif defined(CONFIG_I2C_XFER_LARGE_READ) +#elif defined(CONFIG_I2C_XFER_LARGE_TRANSFER) ret = i2c_xfer_no_retry(port, addr_flags, out, out_size, in, in_size, flags); @@ -200,7 +211,7 @@ int i2c_xfer_unlocked(const int port, ret = chip_i2c_xfer_with_notify(port, addr_flags, out, out_size, in, in_size, flags); -#endif /* CONFIG_I2C_XFER_LARGE_READ */ +#endif /* CONFIG_I2C_XFER_LARGE_TRANSFER */ if (ret != EC_ERROR_BUSY) break; } diff --git a/docs/configuration/i2c.md b/docs/configuration/i2c.md index f258b3cca3..7a6241e349 100644 --- a/docs/configuration/i2c.md +++ b/docs/configuration/i2c.md @@ -14,7 +14,7 @@ The following parameters control the behavior of the I2C library. [config.h] defines a reasonable default value, but you may need to change the default value for your board. -- `CONFIG_I2C_CHIP_MAX_READ_SIZE ` +- `CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE ` - `CONFIG_I2C_NACK_RETRY_COUNT ` - `CONFIG_I2C_EXTRA_PACKET_SIZE ` - Only used on STM32 EC's if `CONFIG_HOSTCMD_I2C_ADDR_FLAGS` is defined. diff --git a/include/config.h b/include/config.h index 4891b36617..5d67079d9a 100644 --- a/include/config.h +++ b/include/config.h @@ -2313,16 +2313,16 @@ #undef CONFIG_I2C_BUS_MAY_BE_UNPOWERED /* - * Conservative I2C reading size per single transaction. For example, register - * of stm32f0 and stm32l4 are limited to be 8 bits for this field. + * Conservative I2C transmission size per single transaction. For example, + * register of stm32f0 and stm32l4 are limited to be 8 bits for this field. */ -#define CONFIG_I2C_CHIP_MAX_READ_SIZE 255 +#define CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE 255 /* * Enable i2c_xfer() for receiving request larger than - * CONFIG_I2C_CHIP_MAX_READ_SIZE. + * CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE. */ -#undef CONFIG_I2C_XFER_LARGE_READ +#undef CONFIG_I2C_XFER_LARGE_TRANSFER /* * If defined, makes i2c_xfer callback into board-provided functions before the diff --git a/include/i2c.h b/include/i2c.h index 4022976dcb..8b53f5e836 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -167,9 +167,9 @@ extern const int i2c_test_dev_used; /** * Transmit one block of raw data, then receive one block of raw data. However, - * received data might be capped at CONFIG_I2C_CHIP_MAX_READ_SIZE if - * CONFIG_I2C_XFER_LARGE_READ is not defined. The transfer is strictly atomic, - * by locking the I2C port and performing an I2C_XFER_SINGLE transfer. + * transferred data might be capped at CONFIG_I2C_CHIP_MAX_TRANSFER_SIZE if + * CONFIG_I2C_XFER_LARGE_TRANSFER is not defined. The transfer is strictly + * atomic, by locking the I2C port and performing an I2C_XFER_SINGLE transfer. * * @param port Port to access * @param slave_addr Slave device address -- cgit v1.2.1