diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch new file mode 100644 index 000000000..381197a64 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch @@ -0,0 +1,180 @@ +From f9f2e586985f90197b30208599bd37a9fd7a7f63 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 1 May 2019 13:27:34 -0700 +Subject: [PATCH] i2c: aspeed: add general call support + +This commit adds general call support into Aspeed I2C driver. +This is downstream only customization so it should not go into +upstream. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../devicetree/bindings/i2c/i2c-aspeed.txt | 1 + + drivers/i2c/busses/i2c-aspeed.c | 39 ++++++++++++++++++++++ + drivers/i2c/i2c-slave-mqueue.c | 4 ++- + include/linux/i2c.h | 1 + + 4 files changed, 44 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index d3f4a39f7ba6..c1ee99398517 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -19,6 +19,7 @@ Optional Properties: + - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not + specified + - multi-master : states that there is another master active on this bus. ++- general-call : enables general call receiving. + - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not + specified. + - #retries : Number of retries for master transfer. +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 4567ec3498dc..3e72068f6a2b 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -59,6 +59,7 @@ + #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) + #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) + #define ASPEED_I2CD_M_HIGH_SPEED_EN BIT(6) ++#define ASPEED_I2CD_GCALL_EN BIT(2) + #define ASPEED_I2CD_SLAVE_EN BIT(1) + #define ASPEED_I2CD_MASTER_EN BIT(0) + +@@ -83,6 +84,7 @@ + */ + #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) + #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) ++#define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8) + #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7) + #define ASPEED_I2CD_INTR_SCL_TIMEOUT BIT(6) + #define ASPEED_I2CD_INTR_ABNORMAL BIT(5) +@@ -161,6 +163,8 @@ enum aspeed_i2c_slave_state { + ASPEED_I2C_SLAVE_READ_PROCESSED, + ASPEED_I2C_SLAVE_WRITE_REQUESTED, + ASPEED_I2C_SLAVE_WRITE_RECEIVED, ++ ASPEED_I2C_SLAVE_GCALL_START, ++ ASPEED_I2C_SLAVE_GCALL_REQUESTED, + ASPEED_I2C_SLAVE_STOP, + }; + +@@ -202,6 +206,8 @@ struct aspeed_i2c_bus { + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; + enum aspeed_i2c_slave_state slave_state; ++ /* General call */ ++ bool general_call; + #endif /* CONFIG_I2C_SLAVE */ + }; + +@@ -309,6 +315,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + bus->slave_state = ASPEED_I2C_SLAVE_START; + } + ++ /* General call was requested, restart state machine. */ ++ if (irq_status & ASPEED_I2CD_INTR_GCALL_ADDR) { ++ irq_handled |= ASPEED_I2CD_INTR_GCALL_ADDR; ++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_START; ++ } ++ + /* Slave is not currently active, irq was for someone else. */ + if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE) + return irq_handled; +@@ -336,6 +348,21 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + else + bus->slave_state = + ASPEED_I2C_SLAVE_WRITE_REQUESTED; ++ } else if (bus->slave_state == ASPEED_I2C_SLAVE_GCALL_START) { ++ /* ++ * I2C spec defines the second byte meaning like below. ++ * 0x06 : Reset and write programmable part of slave ++ * address by hardware. ++ * 0x04 : Write programmable part of slave address by ++ * hardware. ++ * 0x00 : No allowed. ++ * ++ * But in OpenBMC, we are going to use this ++ * 'General call' feature for IPMB message broadcasting ++ * so it delivers all data as is without any specific ++ * handling of the second byte. ++ */ ++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_REQUESTED; + } + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; + } +@@ -456,11 +483,16 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + bus->base + ASPEED_I2C_CMD_REG); + } + break; ++ case ASPEED_I2C_SLAVE_GCALL_REQUESTED: ++ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; ++ i2c_slave_event(slave, I2C_SLAVE_GCALL_REQUESTED, &value); ++ break; + case ASPEED_I2C_SLAVE_STOP: + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; + break; + case ASPEED_I2C_SLAVE_START: ++ case ASPEED_I2C_SLAVE_GCALL_START: + /* Slave was just started. Waiting for the next event. */; + break; + default: +@@ -1071,6 +1103,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr) + /* Turn on slave mode. */ + func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); + func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN; ++ if (bus->general_call) ++ func_ctrl_reg_val |= ASPEED_I2CD_GCALL_EN; + writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); + } + +@@ -1109,6 +1143,8 @@ static int aspeed_i2c_unreg_slave(struct i2c_client *client) + /* Turn off slave mode. */ + func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); + func_ctrl_reg_val &= ~ASPEED_I2CD_SLAVE_EN; ++ if (bus->general_call) ++ func_ctrl_reg_val &= ~ASPEED_I2CD_GCALL_EN; + writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); + + bus->slave = NULL; +@@ -1256,6 +1292,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, + bus->base + ASPEED_I2C_FUN_CTRL_REG); + + #if IS_ENABLED(CONFIG_I2C_SLAVE) ++ if (of_property_read_bool(pdev->dev.of_node, "general-call")) ++ bus->general_call = true; ++ + /* If slave has already been registered, re-enable it. */ + if (bus->slave) + __aspeed_i2c_reg_slave(bus, bus->slave->addr); +diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c +index 2c7a6038409c..1d4db584b393 100644 +--- a/drivers/i2c/i2c-slave-mqueue.c ++++ b/drivers/i2c/i2c-slave-mqueue.c +@@ -56,10 +56,12 @@ static int i2c_slave_mqueue_callback(struct i2c_client *client, + + switch (event) { + case I2C_SLAVE_WRITE_REQUESTED: ++ case I2C_SLAVE_GCALL_REQUESTED: + mq->truncated = 0; + + msg->len = 1; +- msg->buf[0] = client->addr << 1; ++ msg->buf[0] = event == I2C_SLAVE_GCALL_REQUESTED ? ++ 0 : client->addr << 1; + break; + + case I2C_SLAVE_WRITE_RECEIVED: +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +index 92c795ce9081..1e5c74888160 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -365,6 +365,7 @@ enum i2c_slave_event { + I2C_SLAVE_WRITE_REQUESTED, + I2C_SLAVE_READ_PROCESSED, + I2C_SLAVE_WRITE_RECEIVED, ++ I2C_SLAVE_GCALL_REQUESTED, + I2C_SLAVE_STOP, + }; + +-- +2.7.4 + |