summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/hammer/board.h4
-rw-r--r--common/usb_i2c.c38
-rw-r--r--include/config.h3
-rw-r--r--include/usb_i2c.h19
4 files changed, 50 insertions, 14 deletions
diff --git a/board/hammer/board.h b/board/hammer/board.h
index f342acf06e..3bb4d6c0f4 100644
--- a/board/hammer/board.h
+++ b/board/hammer/board.h
@@ -128,6 +128,10 @@
#define CONFIG_BOARD_PRE_INIT
#define CONFIG_WATCHDOG_HELP
+/* Enlarge the allowed write count */
+#undef CONFIG_USB_I2C_MAX_WRITE_COUNT
+#define CONFIG_USB_I2C_MAX_WRITE_COUNT 124
+
/* No lid switch */
#undef CONFIG_LID_SWITCH
diff --git a/common/usb_i2c.c b/common/usb_i2c.c
index 4c8350e910..64d7135a89 100644
--- a/common/usb_i2c.c
+++ b/common/usb_i2c.c
@@ -50,12 +50,32 @@ static void usb_i2c_write_packet(struct usb_i2c_config const *config,
QUEUE_ADD_UNITS(config->tx_queue, config->buffer, count);
}
-void usb_i2c_deferred(struct usb_i2c_config const *config)
+static uint8_t usb_i2c_executable(struct usb_i2c_config const *config)
{
/*
- * And if there is a USB packet waiting we process it and generate a
- * response.
+ * In order to support larger write payload, we need to peek
+ * the queue to see if we need to wait for more data.
*/
+
+ uint8_t write_count;
+
+ if (queue_peek_units(config->consumer.queue, &write_count, 2, 1) == 1
+ && (write_count + 4) > queue_count(config->consumer.queue)) {
+ /*
+ * Feed me more data, please.
+ * Reuse the buffer in usb_i2c_config to send ACK packet.
+ */
+ config->buffer[0] = USB_I2C_SUCCESS;
+ config->buffer[1] = 0;
+ usb_i2c_write_packet(config, 4);
+ return 0;
+ }
+ return 1;
+}
+
+void usb_i2c_execute(struct usb_i2c_config const *config)
+{
+ /* Payload is ready to execute. */
uint8_t count = usb_i2c_read_packet(config);
int portindex = (config->buffer[0] >> 0) & 0xff;
/* Convert 7-bit slave address to chromium EC 8-bit address. */
@@ -70,8 +90,8 @@ void usb_i2c_deferred(struct usb_i2c_config const *config)
if (!count || (!read_count && !write_count))
return;
- if (write_count > USB_I2C_MAX_WRITE_COUNT ||
- write_count != (count - 4)) {
+ if (write_count > CONFIG_USB_I2C_MAX_WRITE_COUNT ||
+ write_count != (count - 4)) {
config->buffer[0] = USB_I2C_WRITE_COUNT_INVALID;
} else if (read_count > USB_I2C_MAX_READ_COUNT) {
config->buffer[0] = USB_I2C_READ_COUNT_INVALID;
@@ -86,10 +106,16 @@ void usb_i2c_deferred(struct usb_i2c_config const *config)
(uint8_t *)(config->buffer + 2),
read_count, I2C_XFER_SINGLE));
}
-
usb_i2c_write_packet(config, read_count + 4);
}
+void usb_i2c_deferred(struct usb_i2c_config const *config)
+{
+ /* Check if we can proceed the queue. */
+ if (usb_i2c_executable(config))
+ usb_i2c_execute(config);
+}
+
static void usb_i2c_written(struct consumer const *consumer, size_t count)
{
struct usb_i2c_config const *config =
diff --git a/include/config.h b/include/config.h
index b08f9296fa..f628673bd1 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2646,6 +2646,9 @@
/* USB I2C config */
#undef CONFIG_USB_I2C
+/* Allowed write count for USB over I2C */
+#define CONFIG_USB_I2C_MAX_WRITE_COUNT 60
+
/*****************************************************************************/
/* USB Power monitoring interface config */
#undef CONFIG_USB_POWER
diff --git a/include/usb_i2c.h b/include/usb_i2c.h
index a1fe5f10db..335550b66e 100644
--- a/include/usb_i2c.h
+++ b/include/usb_i2c.h
@@ -23,12 +23,13 @@
*
* slave address: 1 byte, i2c 7-bit bus address
*
- * write count: 1 byte, zero based count of bytes to write
+ * write count: 1 byte, zero based count of bytes to write. If write
+ * count exceed 60 bytes, following packets are expected
+ * to continue the payload without header.
*
* read count: 1 byte, zero based count of bytes to read
*
- * data: write payload up to 60 bytes of data to write,
- * length must match write count
+ * data: payload of data to write.
*
* Response:
* +-------------+---+---+-----------------------+
@@ -41,7 +42,7 @@
* 0x0002: Busy, try again
* This can happen if someone else has acquired the shared memory
* buffer that the I2C driver uses as /dev/null
- * 0x0003: Write count invalid (> 60 bytes, or mismatch with payload)
+ * 0x0003: Write count invalid (mismatch with merged payload)
* 0x0004: Read count invalid (> 60 bytes)
* 0x0005: The port specified is invalid.
* 0x8000: Unknown error mask
@@ -63,10 +64,11 @@ enum usb_i2c_error {
};
-#define USB_I2C_MAX_WRITE_COUNT 60
#define USB_I2C_MAX_READ_COUNT 60
+#define USB_I2C_CONFIG_BUFFER_SIZE \
+ ((CONFIG_USB_I2C_MAX_WRITE_COUNT+4) > USB_MAX_PACKET_SIZE ? \
+ (CONFIG_USB_I2C_MAX_WRITE_COUNT+4) : USB_MAX_PACKET_SIZE)
-BUILD_ASSERT(USB_MAX_PACKET_SIZE == (1 + 1 + 1 + 1 + USB_I2C_MAX_WRITE_COUNT));
BUILD_ASSERT(USB_MAX_PACKET_SIZE == (2 + 1 + 1 + USB_I2C_MAX_READ_COUNT));
/*
@@ -105,7 +107,8 @@ extern struct consumer_ops const usb_i2c_consumer_ops;
INTERFACE_NAME, \
ENDPOINT) \
static uint16_t \
- CONCAT2(NAME, _buffer_)[USB_MAX_PACKET_SIZE/2]; \
+ CONCAT2(NAME, _buffer_) \
+ [USB_I2C_CONFIG_BUFFER_SIZE / 2]; \
static void CONCAT2(NAME, _deferred_)(void); \
DECLARE_DEFERRED(CONCAT2(NAME, _deferred_)); \
static struct queue const CONCAT2(NAME, _to_usb_); \
@@ -134,7 +137,7 @@ extern struct consumer_ops const usb_i2c_consumer_ops;
QUEUE_DIRECT(USB_MAX_PACKET_SIZE, uint8_t, \
null_producer, CONCAT2(NAME, _usb_).consumer); \
static struct queue const CONCAT3(usb_to_, NAME, _) = \
- QUEUE_DIRECT(USB_MAX_PACKET_SIZE, uint8_t, \
+ QUEUE_DIRECT(CONFIG_USB_I2C_MAX_WRITE_COUNT+4, uint8_t, \
CONCAT2(NAME, _usb_).producer, NAME.consumer); \
static void CONCAT2(NAME, _deferred_)(void) \
{ usb_i2c_deferred(&NAME); }