diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch | 886 |
1 files changed, 0 insertions, 886 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch deleted file mode 100644 index 9b96b400b..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch +++ /dev/null @@ -1,886 +0,0 @@ -From 36128aacdc8b642b9ee080e493abbc00de345f1d Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> -Date: Tue, 11 Jun 2019 15:07:08 -0700 -Subject: [PATCH] i2c: aspeed: add buffer mode transfer support - -Byte mode currently this driver uses makes lots of interrupt call -which isn't good for performance and it makes the driver very -timing sensitive. To improve performance of the driver, this commit -adds buffer mode transfer support which uses I2C SRAM buffer -instead of using a single byte buffer. - -AST2400: -It has 2 KBytes (256 Bytes x 8 pages) of I2C SRAM buffer pool from -0x1e78a800 to 0x1e78afff that can be used for all busses with -buffer pool manipulation. To simplify implementation for supporting -both AST2400 and AST2500, it assigns each 128 Bytes per bus without -using buffer pool manipulation so total 1792 Bytes of I2C SRAM -buffer will be used. - -AST2500: -It has 16 Bytes of individual I2C SRAM buffer per each bus and its -range is from 0x1e78a200 to 0x1e78a2df, so it doesn't have 'buffer -page selection' bit field in the Function control register, and -neither 'base address pointer' bit field in the Pool buffer control -register it has. To simplify implementation for supporting both -AST2400 and AST2500, it writes zeros on those register bit fields -but it's okay because it does nothing in AST2500. - -It provides buffer based master and slave data transfer. - -Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> ---- - .../devicetree/bindings/i2c/i2c-aspeed.txt | 40 ++- - arch/arm/boot/dts/aspeed-g4.dtsi | 47 ++-- - arch/arm/boot/dts/aspeed-g5.dtsi | 47 ++-- - drivers/i2c/busses/i2c-aspeed.c | 294 ++++++++++++++++++--- - 4 files changed, 349 insertions(+), 79 deletions(-) - -diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -index 724ee9f35c10..e1a0ae7a8c08 100644 ---- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -+++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -@@ -3,7 +3,10 @@ Device tree configuration for the I2C busses on the AST24XX and AST25XX SoCs. - Required Properties: - - #address-cells : should be 1 - - #size-cells : should be 0 --- reg : address offset and range of bus -+- reg : Address offset and range of bus registers. -+ An additional SRAM buffer address offset and range is -+ optional in case of enabling I2C dedicated SRAM for -+ buffer mode transfer support. - - compatible : should be "aspeed,ast2400-i2c-bus" - or "aspeed,ast2500-i2c-bus" - - clocks : root clock of bus, should reference the APB -@@ -29,12 +32,21 @@ i2c { - #size-cells = <1>; - ranges = <0 0x1e78a000 0x1000>; - -- i2c_ic: interrupt-controller@0 { -- #interrupt-cells = <1>; -- compatible = "aspeed,ast2400-i2c-ic"; -+ i2c_gr: i2c-global-regs@0 { -+ compatible = "aspeed,ast2500-i2c-gr", "syscon"; - reg = <0x0 0x40>; -- interrupts = <12>; -- interrupt-controller; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0x0 0x0 0x40>; -+ -+ i2c_ic: interrupt-controller@0 { -+ #interrupt-cells = <1>; -+ compatible = "aspeed,ast2500-i2c-ic"; -+ reg = <0x0 0x4>; -+ interrupts = <12>; -+ interrupt-controller; -+ }; - }; - - i2c0: i2c-bus@40 { -@@ -42,11 +54,25 @@ i2c { - #size-cells = <0>; - #interrupt-cells = <1>; - reg = <0x40 0x40>; -- compatible = "aspeed,ast2400-i2c-bus"; -+ compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; - bus-frequency = <100000>; - interrupts = <0>; - interrupt-parent = <&i2c_ic>; - }; -+ -+ /* buffer mode transfer enabled */ -+ i2c1: i2c-bus@80 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #interrupt-cells = <1>; -+ reg = <0x80 0x40>, <0x210 0x10>; -+ compatible = "aspeed,ast2500-i2c-bus"; -+ clocks = <&syscon ASPEED_CLK_APB>; -+ resets = <&syscon ASPEED_RESET_I2C>; -+ bus-frequency = <100000>; -+ interrupts = <1>; -+ interrupt-parent = <&i2c_ic>; -+ }; - }; -diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index 47a5029f5bdb..052b1b6b4dc7 100644 ---- a/arch/arm/boot/dts/aspeed-g4.dtsi -+++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -469,12 +469,21 @@ - }; - - &i2c { -- i2c_ic: interrupt-controller@0 { -- #interrupt-cells = <1>; -- compatible = "aspeed,ast2400-i2c-ic"; -+ i2c_gr: i2c-global-regs@0 { -+ compatible = "aspeed,ast2400-i2c-gr", "syscon"; - reg = <0x0 0x40>; -- interrupts = <12>; -- interrupt-controller; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0x0 0x0 0x40>; -+ -+ i2c_ic: interrupt-controller@0 { -+ #interrupt-cells = <1>; -+ compatible = "aspeed,ast2400-i2c-ic"; -+ reg = <0x0 0x4>; -+ interrupts = <12>; -+ interrupt-controller; -+ }; - }; - - i2c0: i2c-bus@40 { -@@ -482,7 +491,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x40 0x40>; -+ reg = <0x40 0x40>, <0x800 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -498,7 +507,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x80 0x40>; -+ reg = <0x80 0x40>, <0x880 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -514,7 +523,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0xc0 0x40>; -+ reg = <0xc0 0x40>, <0x900 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -531,7 +540,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x100 0x40>; -+ reg = <0x100 0x40>, <0x980 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -548,7 +557,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x140 0x40>; -+ reg = <0x140 0x40>, <0xa00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -565,7 +574,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x180 0x40>; -+ reg = <0x180 0x40>, <0xa80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -582,7 +591,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x1c0 0x40>; -+ reg = <0x1c0 0x40>, <0xb00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -599,7 +608,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x300 0x40>; -+ reg = <0x300 0x40>, <0xb80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -616,7 +625,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x340 0x40>; -+ reg = <0x340 0x40>, <0xc00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -633,7 +642,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x380 0x40>; -+ reg = <0x380 0x40>, <0xc80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -650,7 +659,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x3c0 0x40>; -+ reg = <0x3c0 0x40>, <0xd00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -667,7 +676,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x400 0x40>; -+ reg = <0x400 0x40>, <0xd80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -684,7 +693,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x440 0x40>; -+ reg = <0x440 0x40>, <0xe00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -701,7 +710,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x480 0x40>; -+ reg = <0x480 0x40>, <0xe80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 89a9febf6f14..2d2173d598e4 100644 ---- a/arch/arm/boot/dts/aspeed-g5.dtsi -+++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -586,12 +586,21 @@ - }; - - &i2c { -- i2c_ic: interrupt-controller@0 { -- #interrupt-cells = <1>; -- compatible = "aspeed,ast2500-i2c-ic"; -+ i2c_gr: i2c-global-regs@0 { -+ compatible = "aspeed,ast2500-i2c-gr", "syscon"; - reg = <0x0 0x40>; -- interrupts = <12>; -- interrupt-controller; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0x0 0x0 0x40>; -+ -+ i2c_ic: interrupt-controller@0 { -+ #interrupt-cells = <1>; -+ compatible = "aspeed,ast2500-i2c-ic"; -+ reg = <0x0 0x4>; -+ interrupts = <12>; -+ interrupt-controller; -+ }; - }; - - i2c0: i2c-bus@40 { -@@ -599,7 +608,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x40 0x40>; -+ reg = <0x40 0x40>, <0x200 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -615,7 +624,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x80 0x40>; -+ reg = <0x80 0x40>, <0x210 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -631,7 +640,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0xc0 0x40>; -+ reg = <0xc0 0x40>, <0x220 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -648,7 +657,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x100 0x40>; -+ reg = <0x100 0x40>, <0x230 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -665,7 +674,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x140 0x40>; -+ reg = <0x140 0x40>, <0x240 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -682,7 +691,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x180 0x40>; -+ reg = <0x180 0x40>, <0x250 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -699,7 +708,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x1c0 0x40>; -+ reg = <0x1c0 0x40>, <0x260 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -716,7 +725,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x300 0x40>; -+ reg = <0x300 0x40>, <0x270 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -733,7 +742,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x340 0x40>; -+ reg = <0x340 0x40>, <0x280 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -750,7 +759,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x380 0x40>; -+ reg = <0x380 0x40>, <0x290 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -767,7 +776,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x3c0 0x40>; -+ reg = <0x3c0 0x40>, <0x2a0 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -784,7 +793,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x400 0x40>; -+ reg = <0x400 0x40>, <0x2b0 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -801,7 +810,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x440 0x40>; -+ reg = <0x440 0x40>, <0x2c0 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -818,7 +827,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x480 0x40>; -+ reg = <0x480 0x40>, <0x2d0 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index d8143c24d3a7..b721fb1d6d4c 100644 ---- a/drivers/i2c/busses/i2c-aspeed.c -+++ b/drivers/i2c/busses/i2c-aspeed.c -@@ -7,6 +7,7 @@ - * Copyright 2017 Google, Inc. - */ - -+#include <linux/bitfield.h> - #include <linux/clk.h> - #include <linux/completion.h> - #include <linux/err.h> -@@ -19,15 +20,24 @@ - #include <linux/irqchip/chained_irq.h> - #include <linux/irqdomain.h> - #include <linux/kernel.h> -+#include <linux/mfd/syscon.h> - #include <linux/module.h> - #include <linux/of_address.h> - #include <linux/of_irq.h> - #include <linux/of_platform.h> - #include <linux/platform_device.h> -+#include <linux/regmap.h> - #include <linux/reset.h> - #include <linux/slab.h> - --/* I2C Register */ -+/* I2C Global Registers */ -+/* 0x00 : I2CG Interrupt Status Register */ -+/* 0x08 : I2CG Interrupt Target Assignment */ -+/* 0x0c : I2CG Global Control Register (AST2500) */ -+#define ASPEED_I2CG_GLOBAL_CTRL_REG 0x0c -+#define ASPEED_I2CG_SRAM_BUFFER_EN BIT(0) -+ -+/* I2C Bus Registers */ - #define ASPEED_I2C_FUN_CTRL_REG 0x00 - #define ASPEED_I2C_AC_TIMING_REG1 0x04 - #define ASPEED_I2C_AC_TIMING_REG2 0x08 -@@ -35,14 +45,12 @@ - #define ASPEED_I2C_INTR_STS_REG 0x10 - #define ASPEED_I2C_CMD_REG 0x14 - #define ASPEED_I2C_DEV_ADDR_REG 0x18 -+#define ASPEED_I2C_BUF_CTRL_REG 0x1c - #define ASPEED_I2C_BYTE_BUF_REG 0x20 - --/* Global Register Definition */ --/* 0x00 : I2C Interrupt Status Register */ --/* 0x08 : I2C Interrupt Target Assignment */ -- - /* Device Register Definition */ - /* 0x00 : I2CD Function Control Register */ -+#define ASPEED_I2CD_BUFFER_PAGE_SEL_MASK GENMASK(22, 20) - #define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15) - #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) - #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) -@@ -104,6 +112,8 @@ - #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11) - - /* Command Bit */ -+#define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7) -+#define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6) - #define ASPEED_I2CD_M_STOP_CMD BIT(5) - #define ASPEED_I2CD_M_S_RX_CMD_LAST BIT(4) - #define ASPEED_I2CD_M_RX_CMD BIT(3) -@@ -114,6 +124,13 @@ - /* 0x18 : I2CD Slave Device Address Register */ - #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) - -+/* 0x1c : I2CD Buffer Control Register */ -+/* Use 8-bits or 6-bits wide bit fileds to support both AST2400 and AST2500 */ -+#define ASPEED_I2CD_BUF_RX_COUNT_MASK GENMASK(31, 24) -+#define ASPEED_I2CD_BUF_RX_SIZE_MASK GENMASK(23, 16) -+#define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8) -+#define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0) -+ - enum aspeed_i2c_master_state { - ASPEED_I2C_MASTER_INACTIVE, - ASPEED_I2C_MASTER_PENDING, -@@ -161,6 +178,11 @@ struct aspeed_i2c_bus { - int master_xfer_result; - /* Multi-master */ - bool multi_master; -+ /* Buffer mode */ -+ void __iomem *buf_base; -+ size_t buf_size; -+ u8 buf_offset; -+ u8 buf_page; - #if IS_ENABLED(CONFIG_I2C_SLAVE) - struct i2c_client *slave; - enum aspeed_i2c_slave_state slave_state; -@@ -259,6 +281,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - { - u32 command, irq_handled = 0; - struct i2c_client *slave = bus->slave; -+ int i, len; - u8 value; - - if (!slave) -@@ -287,7 +310,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - - /* Slave was sent something. */ - if (irq_status & ASPEED_I2CD_INTR_RX_DONE) { -- value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; -+ if (bus->buf_base && -+ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && -+ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) -+ value = readb(bus->buf_base); -+ else -+ value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; - /* Handle address frame. */ - if (bus->slave_state == ASPEED_I2C_SLAVE_START) { - if (value & 0x1) -@@ -317,6 +345,20 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - - /* Slave was asked to stop. */ - if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { -+ if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && -+ irq_status & ASPEED_I2CD_INTR_RX_DONE) { -+ if (bus->buf_base) { -+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, -+ readl(bus->base + -+ ASPEED_I2C_BUF_CTRL_REG)); -+ for (i = 0; i < len; i++) { -+ value = readb(bus->buf_base + i); -+ i2c_slave_event(slave, -+ I2C_SLAVE_WRITE_RECEIVED, -+ &value); -+ } -+ } -+ } - irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; - bus->slave_state = ASPEED_I2C_SLAVE_STOP; - } -@@ -349,9 +391,36 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - case ASPEED_I2C_SLAVE_WRITE_REQUESTED: - bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; - i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); -+ if (bus->buf_base) { -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, -+ bus->buf_size - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ writel(ASPEED_I2CD_RX_BUFF_ENABLE, -+ bus->base + ASPEED_I2C_CMD_REG); -+ } - break; - case ASPEED_I2C_SLAVE_WRITE_RECEIVED: - i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); -+ if (bus->buf_base) { -+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, -+ readl(bus->base + -+ ASPEED_I2C_BUF_CTRL_REG)); -+ for (i = 1; i < len; i++) { -+ value = readb(bus->buf_base + i); -+ i2c_slave_event(slave, -+ I2C_SLAVE_WRITE_RECEIVED, -+ &value); -+ } -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, -+ bus->buf_size - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ writel(ASPEED_I2CD_RX_BUFF_ENABLE, -+ bus->base + ASPEED_I2C_CMD_REG); -+ } - break; - case ASPEED_I2C_SLAVE_GCALL_REQUESTED: - bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; -@@ -382,6 +451,8 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) - u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD; - struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; - u8 slave_addr = i2c_8bit_addr_from_msg(msg); -+ u8 wbuf[4]; -+ int len; - - #if IS_ENABLED(CONFIG_I2C_SLAVE) - /* -@@ -400,12 +471,66 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) - - if (msg->flags & I2C_M_RD) { - command |= ASPEED_I2CD_M_RX_CMD; -- /* Need to let the hardware know to NACK after RX. */ -- if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) -- command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ -+ if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { -+ command |= ASPEED_I2CD_RX_BUFF_ENABLE; -+ -+ if (msg->len > bus->buf_size) { -+ len = bus->buf_size; -+ } else { -+ len = msg->len; -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } -+ -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, -+ len - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ } else { -+ /* Need to let the hardware know to NACK after RX. */ -+ if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } -+ } else { -+ if (bus->buf_base) { -+ int i; -+ -+ command |= ASPEED_I2CD_TX_BUFF_ENABLE; -+ -+ if (msg->len + 1 > bus->buf_size) -+ len = bus->buf_size; -+ else -+ len = msg->len + 1; -+ -+ /* -+ * Yeah, it looks clumsy but byte writings on a remapped -+ * I2C SRAM cause corruptions so use this way to make -+ * dword writings. -+ */ -+ wbuf[0] = slave_addr; -+ for (i = 1; i < len; i++) { -+ wbuf[i % 4] = msg->buf[i - 1]; -+ if (i % 4 == 3) -+ writel(*(u32 *)wbuf, -+ bus->buf_base + i - 3); -+ } -+ if (--i % 4 != 3) -+ writel(*(u32 *)wbuf, -+ bus->buf_base + i - (i % 4)); -+ -+ bus->buf_index = len - 1; -+ -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, -+ len - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ } - } - -- writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); -+ if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) -+ writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); - writel(command, bus->base + ASPEED_I2C_CMD_REG); - } - -@@ -445,7 +570,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - u32 irq_handled = 0, command = 0; - struct i2c_msg *msg; - u8 recv_byte; -- int ret; -+ int ret, len; - - if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) { - bus->master_state = ASPEED_I2C_MASTER_INACTIVE; -@@ -558,11 +683,43 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - /* fall through */ - case ASPEED_I2C_MASTER_TX_FIRST: - if (bus->buf_index < msg->len) { -+ command = ASPEED_I2CD_M_TX_CMD; -+ -+ if (bus->buf_base) { -+ u8 wbuf[4]; -+ int i; -+ -+ command |= ASPEED_I2CD_TX_BUFF_ENABLE; -+ -+ if (msg->len - bus->buf_index > bus->buf_size) -+ len = bus->buf_size; -+ else -+ len = msg->len - bus->buf_index; -+ -+ for (i = 0; i < len; i++) { -+ wbuf[i % 4] = msg->buf[bus->buf_index -+ + i]; -+ if (i % 4 == 3) -+ writel(*(u32 *)wbuf, -+ bus->buf_base + i - 3); -+ } -+ if (--i % 4 != 3) -+ writel(*(u32 *)wbuf, -+ bus->buf_base + i - (i % 4)); -+ -+ bus->buf_index += len; -+ -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, -+ len - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ } else { -+ writel(msg->buf[bus->buf_index++], -+ bus->base + ASPEED_I2C_BYTE_BUF_REG); -+ } -+ writel(command, bus->base + ASPEED_I2C_CMD_REG); - bus->master_state = ASPEED_I2C_MASTER_TX; -- writel(msg->buf[bus->buf_index++], -- bus->base + ASPEED_I2C_BYTE_BUF_REG); -- writel(ASPEED_I2CD_M_TX_CMD, -- bus->base + ASPEED_I2C_CMD_REG); - } else { - aspeed_i2c_next_msg_or_stop(bus); - } -@@ -579,25 +736,56 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - } - irq_handled |= ASPEED_I2CD_INTR_RX_DONE; - -- recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; -- msg->buf[bus->buf_index++] = recv_byte; -- -- if (msg->flags & I2C_M_RECV_LEN) { -- if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) { -- bus->cmd_err = -EPROTO; -- aspeed_i2c_do_stop(bus); -- goto out_no_complete; -+ if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { -+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, -+ readl(bus->base + -+ ASPEED_I2C_BUF_CTRL_REG)); -+ memcpy_fromio(msg->buf + bus->buf_index, -+ bus->buf_base, len); -+ bus->buf_index += len; -+ } else { -+ recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) -+ >> 8; -+ msg->buf[bus->buf_index++] = recv_byte; -+ -+ if (msg->flags & I2C_M_RECV_LEN) { -+ if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) { -+ bus->cmd_err = -EPROTO; -+ aspeed_i2c_do_stop(bus); -+ goto out_no_complete; -+ } -+ msg->len = recv_byte + -+ ((msg->flags & I2C_CLIENT_PEC) ? -+ 2 : 1); -+ msg->flags &= ~I2C_M_RECV_LEN; - } -- msg->len = recv_byte + -- ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1); -- msg->flags &= ~I2C_M_RECV_LEN; - } - - if (bus->buf_index < msg->len) { -- bus->master_state = ASPEED_I2C_MASTER_RX; - command = ASPEED_I2CD_M_RX_CMD; -- if (bus->buf_index + 1 == msg->len) -- command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ bus->master_state = ASPEED_I2C_MASTER_RX; -+ if (bus->buf_base) { -+ command |= ASPEED_I2CD_RX_BUFF_ENABLE; -+ -+ if (msg->len - bus->buf_index > -+ bus->buf_size) { -+ len = bus->buf_size; -+ } else { -+ len = msg->len - bus->buf_index; -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } -+ -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, -+ len - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, -+ 0) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ } else { -+ if (bus->buf_index + 1 == msg->len) -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } - writel(command, bus->base + ASPEED_I2C_CMD_REG); - } else { - aspeed_i2c_next_msg_or_stop(bus); -@@ -947,6 +1135,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, - if (ret < 0) - return ret; - -+ fun_ctrl_reg |= FIELD_PREP(ASPEED_I2CD_BUFFER_PAGE_SEL_MASK, -+ bus->buf_page); -+ - if (of_property_read_bool(pdev->dev.of_node, "multi-master")) - bus->multi_master = true; - else -@@ -1007,16 +1198,15 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - { - const struct of_device_id *match; - struct aspeed_i2c_bus *bus; -+ bool sram_enabled = true; - struct clk *parent_clk; -- struct resource *res; - int irq, ret; - - bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); - if (!bus) - return -ENOMEM; - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- bus->base = devm_ioremap_resource(&pdev->dev, res); -+ bus->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(bus->base)) - return PTR_ERR(bus->base); - -@@ -1050,6 +1240,42 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - bus->get_clk_reg_val = (u32 (*)(struct device *, u32)) - match->data; - -+ /* Enable I2C SRAM in case of AST2500 */ -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2500-i2c-bus")) { -+ struct regmap *gr_regmap = syscon_regmap_lookup_by_compatible( -+ "aspeed,ast2500-i2c-gr"); -+ if (IS_ERR(gr_regmap)) -+ ret = PTR_ERR(gr_regmap); -+ else -+ ret = regmap_update_bits(gr_regmap, -+ ASPEED_I2CG_GLOBAL_CTRL_REG, -+ ASPEED_I2CG_SRAM_BUFFER_EN, -+ ASPEED_I2CG_SRAM_BUFFER_EN); -+ -+ if (ret) -+ sram_enabled = false; -+ } -+ -+ if (sram_enabled) { -+ struct resource *res = platform_get_resource(pdev, -+ IORESOURCE_MEM, 1); -+ -+ bus->buf_base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(bus->buf_base) || resource_size(res) < 2) { -+ bus->buf_base = NULL; -+ } else { -+ bus->buf_size = resource_size(res); -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2400-i2c-bus")) { -+ bus->buf_page = ((res->start >> 8) & -+ GENMASK(3, 0)) - 8; -+ bus->buf_offset = (res->start >> 2) & -+ ASPEED_I2CD_BUF_OFFSET_MASK; -+ } -+ } -+ } -+ - /* Initialize the I2C adapter */ - spin_lock_init(&bus->lock); - init_completion(&bus->cmd_complete); -@@ -1085,8 +1311,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - - platform_set_drvdata(pdev, bus); - -- dev_info(bus->dev, "i2c bus %d registered, irq %d\n", -- bus->adap.nr, irq); -+ dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", -+ bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq); - - return 0; - } --- -2.7.4 - |