summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch
diff options
context:
space:
mode:
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.patch180
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
+