diff options
author | Ed Tanous <ed.tanous@intel.com> | 2019-07-31 20:43:37 +0300 |
---|---|---|
committer | Ed Tanous <ed.tanous@intel.com> | 2019-08-01 18:19:38 +0300 |
commit | d0f63ef62c76c932a2003eaa42c0b250065ae06f (patch) | |
tree | 4c0e3cb32dc80f80460bdbf82ff6d401d4ff194f /meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch | |
parent | b4f66bacb1b8e661d794fa7a189e2f66f5092e2e (diff) | |
download | openbmc-d0f63ef62c76c932a2003eaa42c0b250065ae06f.tar.xz |
Update to internal 7-31-19
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch new file mode 100644 index 000000000..f4dfd6cfa --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch @@ -0,0 +1,181 @@ +From 9a43b47fb794fd195912c6956783b021a46307f8 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 11 Jul 2019 13:53:34 -0700 +Subject: [PATCH] i2c: aspeed: add H/W timeout support + +This commit adds I2C H/W timeout support. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/i2c/busses/i2c-aspeed.c | 79 +++++++++++++++++++++++++++++++++++++---- + 1 file changed, 73 insertions(+), 6 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 0ed9a27850e6..ecb5793036cc 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -71,10 +71,14 @@ + #define ASPEED_I2CD_TIME_SCL_HIGH_MASK GENMASK(19, 16) + #define ASPEED_I2CD_TIME_SCL_LOW_SHIFT 12 + #define ASPEED_I2CD_TIME_SCL_LOW_MASK GENMASK(15, 12) ++#define ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_SHIFT 8 ++#define ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK GENMASK(9, 8) + #define ASPEED_I2CD_TIME_BASE_DIVISOR_MASK GENMASK(3, 0) + #define ASPEED_I2CD_TIME_SCL_REG_MAX GENMASK(3, 0) ++ + /* 0x08 : I2CD Clock and AC Timing Control Register #2 */ +-#define ASPEED_NO_TIMEOUT_CTRL 0 ++#define ASPEED_I2CD_TIMEOUT_CYCLES_SHIFT 0 ++#define ASPEED_I2CD_TIMEOUT_CYCLES_MASK GENMASK(4, 0) + + /* 0x0c : I2CD Interrupt Control Register & + * 0x10 : I2CD Interrupt Status Register +@@ -82,6 +86,7 @@ + * These share bit definitions, so use the same values for the enable & + * status bits. + */ ++#define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15) + #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) +@@ -98,8 +103,11 @@ + ASPEED_I2CD_INTR_SCL_TIMEOUT | \ + ASPEED_I2CD_INTR_ABNORMAL | \ + ASPEED_I2CD_INTR_ARBIT_LOSS) ++#define ASPEED_I2CD_INTR_SLAVE_ERRORS \ ++ ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT + #define ASPEED_I2CD_INTR_ALL \ +- (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \ ++ (ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT | \ ++ ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \ + ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \ + ASPEED_I2CD_INTR_SCL_TIMEOUT | \ + ASPEED_I2CD_INTR_ABNORMAL | \ +@@ -180,6 +188,7 @@ struct aspeed_i2c_bus { + u32 divisor); + unsigned long parent_clk_frequency; + u32 bus_frequency; ++ u32 hw_timeout_ms; + /* Transaction state. */ + enum aspeed_i2c_master_state master_state; + struct i2c_msg *msgs; +@@ -297,6 +306,14 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) + } + + #if IS_ENABLED(CONFIG_I2C_SLAVE) ++static int aspeed_i2c_check_slave_error(u32 irq_status) ++{ ++ if (irq_status & ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT) ++ return -EIO; ++ ++ return 0; ++} ++ + static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + { + u32 command, irq_handled = 0; +@@ -307,6 +324,14 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (!slave) + return 0; + ++ if (aspeed_i2c_check_slave_error(irq_status)) { ++ dev_dbg(bus->dev, "received slave error interrupt: 0x%08x\n", ++ irq_status); ++ irq_handled |= (irq_status & ASPEED_I2CD_INTR_SLAVE_ERRORS); ++ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; ++ return irq_handled; ++ } ++ + command = readl(bus->base + ASPEED_I2C_CMD_REG); + + /* Slave was requested, restart state machine. */ +@@ -649,7 +674,7 @@ static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus) + } + } + +-static int aspeed_i2c_is_irq_error(u32 irq_status) ++static int aspeed_i2c_check_master_error(u32 irq_status) + { + if (irq_status & ASPEED_I2CD_INTR_ARBIT_LOSS) + return -EAGAIN; +@@ -680,9 +705,9 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + * should clear the command queue effectively taking us back to the + * INACTIVE state. + */ +- ret = aspeed_i2c_is_irq_error(irq_status); ++ ret = aspeed_i2c_check_master_error(irq_status); + if (ret) { +- dev_dbg(bus->dev, "received error interrupt: 0x%08x\n", ++ dev_dbg(bus->dev, "received master error interrupt: 0x%08x\n", + irq_status); + irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS); + if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) { +@@ -1251,6 +1276,7 @@ static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor) + /* precondition: bus.lock has been acquired. */ + static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus) + { ++ u32 timeout_base_divisor, timeout_tick_us, timeout_cycles; + u32 divisor, clk_reg_val; + + divisor = DIV_ROUND_UP(bus->parent_clk_frequency, bus->bus_frequency); +@@ -1259,8 +1285,46 @@ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus) + ASPEED_I2CD_TIME_THDSTA_MASK | + ASPEED_I2CD_TIME_TACST_MASK); + clk_reg_val |= bus->get_clk_reg_val(bus->dev, divisor); ++ ++ if (bus->hw_timeout_ms) { ++ u8 div_max = ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK >> ++ ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_SHIFT; ++ u8 cycles_max = ASPEED_I2CD_TIMEOUT_CYCLES_MASK >> ++ ASPEED_I2CD_TIMEOUT_CYCLES_SHIFT; ++ ++ timeout_base_divisor = 0; ++ ++ do { ++ timeout_tick_us = 1000 * (16384 << ++ (timeout_base_divisor << 1)) / ++ (bus->parent_clk_frequency / 1000); ++ ++ if (timeout_base_divisor == div_max || ++ timeout_tick_us * ASPEED_I2CD_TIMEOUT_CYCLES_MASK >= ++ bus->hw_timeout_ms * 1000) ++ break; ++ } while (timeout_base_divisor++ < div_max); ++ ++ if (timeout_tick_us) { ++ timeout_cycles = DIV_ROUND_UP(bus->hw_timeout_ms * 1000, ++ timeout_tick_us); ++ if (timeout_cycles == 0) ++ timeout_cycles = 1; ++ else if (timeout_cycles > cycles_max) ++ timeout_cycles = cycles_max; ++ } else { ++ timeout_cycles = 0; ++ } ++ } else { ++ timeout_base_divisor = 0; ++ timeout_cycles = 0; ++ } ++ ++ clk_reg_val |= FIELD_PREP(ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK, ++ timeout_base_divisor); ++ + writel(clk_reg_val, bus->base + ASPEED_I2C_AC_TIMING_REG1); +- writel(ASPEED_NO_TIMEOUT_CTRL, bus->base + ASPEED_I2C_AC_TIMING_REG2); ++ writel(timeout_cycles, bus->base + ASPEED_I2C_AC_TIMING_REG2); + + return 0; + } +@@ -1464,6 +1528,9 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + } + } + ++ device_property_read_u32(&pdev->dev, "aspeed,hw-timeout-ms", ++ &bus->hw_timeout_ms); ++ + /* Initialize the I2C adapter */ + spin_lock_init(&bus->lock); + init_completion(&bus->cmd_complete); +-- +2.7.4 + |