summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux
diff options
context:
space:
mode:
authorEd Tanous <ed.tanous@intel.com>2019-06-19 01:53:56 +0300
committerEd Tanous <ed.tanous@intel.com>2019-06-19 20:26:17 +0300
commit2c7e8f4ce61f2e0407c37e98e22bbb13e562b414 (patch)
tree9ea192b408585fc2a19b54d196c3d56eaddc4acb /meta-openbmc-mods/meta-common/recipes-kernel/linux
parentaea9e7cbf9bd7677228747a8e7bab4d22bc80103 (diff)
downloadopenbmc-2c7e8f4ce61f2e0407c37e98e22bbb13e562b414.tar.xz
Update to internal 6-18-19
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch64
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch62
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch32
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0059-media-aspeed-remove-source-buffer-allocation-before-.patch75
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-media-aspeed-use-different-delays-for-triggering-VE-.patch60
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-media-aspeed-add-a-workaround-to-fix-a-silicon-bug.patch68
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch55
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch770
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend5
9 files changed, 923 insertions, 268 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch
index 7ba94a7bc..6c9d46d9d 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch
@@ -1,6 +1,6 @@
From 0b8b93851bb79e70e91159f310afd4b56084977f Mon Sep 17 00:00:00 2001
From: "Corona, Ernesto" <ernesto.corona@intel.com>
-Date: Mon, 6 May 2019 10:05:51 -0800
+Date: Fri, 7 Jun 2019 07:37:39 -0800
Subject: [PATCH v29 1/6] drivers: jtag: Add JTAG core driver
JTAG class driver provide infrastructure to support hardware/software
@@ -58,6 +58,9 @@ Comments pointed by Steven Filary <steven.a.filary@intel.com>
the driver is not in use to allow other HW to own the JTAG bus. Remove SCU
register accesses. This register controls the JTAG controller mode
(master/slave).
+- Fix static analysis issues
+- Add support for multichain. Set tap state and xfer operations now include
+ two tap state arguments: current state and end state.
v27->v28
Comments pointed by Steven Filary <steven.a.filary@intel.com>
@@ -253,10 +256,10 @@ Comments pointed by Tobias Klauser <tklauser@distanz.ch>
drivers/Makefile | 1 +
drivers/jtag/Kconfig | 17 +++
drivers/jtag/Makefile | 1 +
- drivers/jtag/jtag.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/jtag/jtag.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/jtag.h | 47 +++++++
- include/uapi/linux/jtag.h | 208 ++++++++++++++++++++++++++++++
- 7 files changed, 589 insertions(+)
+ include/uapi/linux/jtag.h | 214 ++++++++++++++++++++++++++++++
+ 7 files changed, 602 insertions(+)
create mode 100644 drivers/jtag/Kconfig
create mode 100644 drivers/jtag/Makefile
create mode 100644 drivers/jtag/jtag.c
@@ -317,7 +320,7 @@ new file mode 100644
index 0000000..47503a1
--- /dev/null
+++ b/drivers/jtag/jtag.c
-@@ -0,0 +1,314 @@
+@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018 Mellanox Technologies. All rights reserved.
+// Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com>
@@ -353,7 +356,7 @@ index 0000000..47503a1
+static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct jtag *jtag = file->private_data;
-+ struct jtag_end_tap_state endstate;
++ struct jtag_tap_state tapstate;
+ struct jtag_xfer xfer;
+ struct bitbang_packet bitbang;
+ struct tck_bitbang *bitbang_data;
@@ -392,17 +395,20 @@ index 0000000..47503a1
+ break;
+
+ case JTAG_SIOCSTATE:
-+ if (copy_from_user(&endstate, (const void __user *)arg,
-+ sizeof(struct jtag_end_tap_state)))
++ if (copy_from_user(&tapstate, (const void __user *)arg,
++ sizeof(struct jtag_tap_state)))
+ return -EFAULT;
+
-+ if (endstate.endstate > JTAG_STATE_UPDATEIR)
++ if (tapstate.from > JTAG_STATE_CURRENT)
+ return -EINVAL;
+
-+ if (endstate.reset > JTAG_FORCE_RESET)
++ if (tapstate.endstate > JTAG_STATE_CURRENT)
+ return -EINVAL;
+
-+ err = jtag->ops->status_set(jtag, &endstate);
++ if (tapstate.reset > JTAG_FORCE_RESET)
++ return -EINVAL;
++
++ err = jtag->ops->status_set(jtag, &tapstate);
+ break;
+
+ case JTAG_IOCXFER:
@@ -419,7 +425,10 @@ index 0000000..47503a1
+ if (xfer.direction > JTAG_READ_WRITE_XFER)
+ return -EINVAL;
+
-+ if (xfer.endstate > JTAG_STATE_UPDATEIR)
++ if (xfer.from > JTAG_STATE_CURRENT)
++ return -EINVAL;
++
++ if (xfer.endstate > JTAG_STATE_CURRENT)
+ return -EINVAL;
+
+ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE);
@@ -607,7 +616,8 @@ index 0000000..47503a1
+ struct jtag **ptr;
+ int ret;
+
-+ ptr = devres_alloc(devm_jtag_unregister, sizeof(*ptr), GFP_KERNEL);
++ ptr = devres_alloc(devm_jtag_unregister, sizeof(struct jtag *),
++ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
@@ -669,7 +679,7 @@ index 0000000..4153c90
+ int (*freq_get)(struct jtag *jtag, u32 *freq);
+ int (*freq_set)(struct jtag *jtag, u32 freq);
+ int (*status_get)(struct jtag *jtag, u32 *state);
-+ int (*status_set)(struct jtag *jtag, struct jtag_end_tap_state *endst);
++ int (*status_set)(struct jtag *jtag, struct jtag_tap_state *endst);
+ int (*xfer)(struct jtag *jtag, struct jtag_xfer *xfer, u8 *xfer_data);
+ int (*mode_set)(struct jtag *jtag, struct jtag_mode *jtag_mode);
+ int (*bitbang)(struct jtag *jtag, struct bitbang_packet *bitbang,
@@ -690,7 +700,7 @@ new file mode 100644
index 0000000..3f9e195
--- /dev/null
+++ b/include/uapi/linux/jtag.h
-@@ -0,0 +1,208 @@
+@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Mellanox Technologies. All rights reserved. */
+/* Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> */
@@ -732,7 +742,7 @@ index 0000000..3f9e195
+#define JTAG_XFER_SW_MODE 0
+
+/**
-+ * enum jtag_endstate:
++ * enum jtag_tapstate:
+ *
+ * @JTAG_STATE_TLRESET: JTAG state machine Test Logic Reset state
+ * @JTAG_STATE_IDLE: JTAG state machine IDLE state
@@ -750,8 +760,9 @@ index 0000000..3f9e195
+ * @JTAG_STATE_PAUSEIR: JTAG state machine PAUSE_IR state
+ * @JTAG_STATE_EXIT2IR: JTAG state machine EXIT-2 IR state
+ * @JTAG_STATE_UPDATEIR: JTAG state machine UPDATE IR state
++ * @JTAG_STATE_CURRENT: JTAG current state, saved by driver
+ */
-+enum jtag_endstate {
++enum jtag_tapstate {
+ JTAG_STATE_TLRESET,
+ JTAG_STATE_IDLE,
+ JTAG_STATE_SELECTDR,
@@ -767,7 +778,8 @@ index 0000000..3f9e195
+ JTAG_STATE_EXIT1IR,
+ JTAG_STATE_PAUSEIR,
+ JTAG_STATE_EXIT2IR,
-+ JTAG_STATE_UPDATEIR
++ JTAG_STATE_UPDATEIR,
++ JTAG_STATE_CURRENT
+};
+
+/**
@@ -806,7 +818,7 @@ index 0000000..3f9e195
+};
+
+/**
-+ * struct jtag_end_tap_state - forces JTAG state machine to go into a TAPC
++ * struct jtag_tap_state - forces JTAG state machine to go into a TAPC
+ * state
+ *
+ * @reset: 0 - run IDLE/PAUSE from current state
@@ -816,8 +828,9 @@ index 0000000..3f9e195
+ *
+ * Structure provide interface to JTAG device for JTAG set state execution.
+ */
-+struct jtag_end_tap_state {
++struct jtag_tap_state {
+ __u8 reset;
++ __u8 from;
+ __u8 endstate;
+ __u8 tck;
+};
@@ -827,15 +840,18 @@ index 0000000..3f9e195
+ *
+ * @type: transfer type
+ * @direction: xfer direction
-+ * @length: xfer bits len
++ * @from: xfer current state
++ * @endstate: xfer end state
++ * @padding: xfer padding
++ * @length: xfer bits length
+ * @tdio : xfer data array
-+ * @endir: xfer end state
+ *
+ * Structure provide interface to JTAG device for JTAG SDR/SIR xfer execution.
+ */
+struct jtag_xfer {
+ __u8 type;
+ __u8 direction;
++ __u8 from;
+ __u8 endstate;
+ __u8 padding;
+ __u32 length;
@@ -890,11 +906,11 @@ index 0000000..3f9e195
+/* ioctl interface */
+#define __JTAG_IOCTL_MAGIC 0xb2
+
-+#define JTAG_SIOCSTATE _IOW(__JTAG_IOCTL_MAGIC, 0, struct jtag_end_tap_state)
++#define JTAG_SIOCSTATE _IOW(__JTAG_IOCTL_MAGIC, 0, struct jtag_tap_state)
+#define JTAG_SIOCFREQ _IOW(__JTAG_IOCTL_MAGIC, 1, unsigned int)
+#define JTAG_GIOCFREQ _IOR(__JTAG_IOCTL_MAGIC, 2, unsigned int)
+#define JTAG_IOCXFER _IOWR(__JTAG_IOCTL_MAGIC, 3, struct jtag_xfer)
-+#define JTAG_GIOCSTATUS _IOWR(__JTAG_IOCTL_MAGIC, 4, enum jtag_endstate)
++#define JTAG_GIOCSTATUS _IOWR(__JTAG_IOCTL_MAGIC, 4, enum jtag_tapstate)
+#define JTAG_SIOCMODE _IOW(__JTAG_IOCTL_MAGIC, 5, unsigned int)
+#define JTAG_IOCBITBANG _IOW(__JTAG_IOCTL_MAGIC, 6, unsigned int)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch
index d5d43f31b..94722d6c4 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch
@@ -1,6 +1,6 @@
From 817a43d1b1e197e7eff43492599469bbc23bf0fd Mon Sep 17 00:00:00 2001
From: "Corona, Ernesto" <ernesto.corona@intel.com>
-Date: Fri, 17 May 2019 11:18:13 -0800
+Date: Mon, 3 Jun 2019 08:22:09 -0800
Subject: [PATCH v29 2/6] Add Aspeed SoC 24xx and 25xx families JTAG master
driver
@@ -46,6 +46,8 @@ Comments pointed by Steven Filary <steven.a.filary@intel.com>
(master/slave).
- Encansulate dev_dgb message into DEBUG_JTAG macros to improve driver's JTAG
performace.
+- Add support for multichain. Set tap state and xfer operations now include
+ two tap state arguments: current state and end state.
v27->v28
Comments pointed by Steven Filary <steven.a.filary@intel.com>
@@ -198,8 +200,8 @@ Comments pointed by kbuild test robot <lkp@intel.com>
---
drivers/jtag/Kconfig | 14 +
drivers/jtag/Makefile | 1 +
- drivers/jtag/jtag-aspeed.c | 1040 ++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 1055 insertions(+)
+ drivers/jtag/jtag-aspeed.c | 1050 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1065 insertions(+)
create mode 100644 drivers/jtag/jtag-aspeed.c
diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
@@ -236,7 +238,7 @@ new file mode 100644
index 0000000..1d41a66
--- /dev/null
+++ b/drivers/jtag/jtag-aspeed.c
-@@ -0,0 +1,1040 @@
+@@ -0,0 +1,1050 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Mellanox Technologies. All rights reserved.
+// Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com>
@@ -327,6 +329,7 @@ index 0000000..1d41a66
+#define WAIT_ITERATIONS 75
+
+/*#define USE_INTERRUPTS*/
++/*#define DEBUG_JTAG*/
+
+static const char * const regnames[] = {
+ [ASPEED_JTAG_DATA] = "ASPEED_JTAG_DATA",
@@ -344,7 +347,7 @@ index 0000000..1d41a66
+ void __iomem *reg_base;
+ struct device *dev;
+ struct clk *pclk;
-+ enum jtag_endstate status;
++ enum jtag_tapstate status;
+ int irq;
+ struct reset_control *rst;
+ u32 flag;
@@ -480,10 +483,12 @@ index 0000000..1d41a66
+ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x00, 0} },
+};
+
++#ifdef DEBUG_JTAG
+static char *end_status_str[] = {
+ "tlr", "idle", "selDR", "capDR", "sDR", "ex1DR", "pDR", "ex2DR",
+ "updDR", "selIR", "capIR", "sIR", "ex1IR", "pIR", "ex2IR", "updIR"
+};
++#endif
+
+static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg)
+{
@@ -776,24 +781,29 @@ index 0000000..1d41a66
+}
+
+static void aspeed_jtag_set_tap_state(struct aspeed_jtag *aspeed_jtag,
-+ enum jtag_endstate endstate)
++ enum jtag_tapstate from_state,
++ enum jtag_tapstate end_state)
+{
+ int i = 0;
-+ enum jtag_endstate from, to;
++ enum jtag_tapstate from, to;
++
++ from = from_state;
++ to = end_state;
++
++ if (from == JTAG_STATE_CURRENT)
++ from = aspeed_jtag->status;
+
-+ from = aspeed_jtag->status;
-+ to = endstate;
+ for (i = 0; i < _tms_cycle_lookup[from][to].count; i++)
+ aspeed_jtag_tck_cycle(aspeed_jtag,
+ ((_tms_cycle_lookup[from][to].tmsbits >> i) & 0x1), 0);
-+ aspeed_jtag->status = endstate;
++ aspeed_jtag->status = end_state;
+}
+
-+static void aspeed_jtag_end_tap_state_sw(struct aspeed_jtag *aspeed_jtag,
-+ struct jtag_end_tap_state *endstate)
++static void aspeed_jtag_set_tap_state_sw(struct aspeed_jtag *aspeed_jtag,
++ struct jtag_tap_state *tapstate)
+{
+ /* SW mode from curent tap state -> to end_state */
-+ if (endstate->reset) {
++ if (tapstate->reset) {
+ int i = 0;
+
+ for (i = 0; i < ASPEED_JTAG_RESET_CNTR; i++)
@@ -801,26 +811,27 @@ index 0000000..1d41a66
+ aspeed_jtag->status = JTAG_STATE_TLRESET;
+ }
+
-+ aspeed_jtag_set_tap_state(aspeed_jtag, endstate->endstate);
++ aspeed_jtag_set_tap_state(aspeed_jtag, tapstate->from,
++ tapstate->endstate);
+}
+
+static int aspeed_jtag_status_set(struct jtag *jtag,
-+ struct jtag_end_tap_state *endstate)
++ struct jtag_tap_state *tapstate)
+{
+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
+
+#ifdef DEBUG_JTAG
+ dev_dbg(aspeed_jtag->dev, "Set TAP state: %s\n",
-+ end_status_str[endstate->endstate]);
++ end_status_str[tapstate->endstate]);
+#endif
+
+ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
-+ aspeed_jtag_end_tap_state_sw(aspeed_jtag, endstate);
++ aspeed_jtag_set_tap_state_sw(aspeed_jtag, tapstate);
+ return 0;
+ }
+
+ /* x TMS high + 1 TMS low */
-+ if (endstate->reset) {
++ if (tapstate->reset) {
+ /* Disable sw mode */
+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
+ mdelay(1);
@@ -851,9 +862,11 @@ index 0000000..1d41a66
+#endif
+
+ if (xfer->type == JTAG_SIR_XFER)
-+ aspeed_jtag_set_tap_state(aspeed_jtag, JTAG_STATE_SHIFTIR);
++ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->from,
++ JTAG_STATE_SHIFTIR);
+ else
-+ aspeed_jtag_set_tap_state(aspeed_jtag, JTAG_STATE_SHIFTDR);
++ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->from,
++ JTAG_STATE_SHIFTDR);
+
+ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]);
+ data[index] = 0;
@@ -889,7 +902,8 @@ index 0000000..1d41a66
+ ASPEED_JTAG_DATA_CHUNK_SIZE);
+ aspeed_jtag->status = (xfer->type == JTAG_SIR_XFER) ?
+ JTAG_STATE_EXIT1IR : JTAG_STATE_EXIT1DR;
-+ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->endstate);
++ aspeed_jtag_set_tap_state(aspeed_jtag, aspeed_jtag->status,
++ xfer->endstate);
+ }
+}
+
@@ -916,8 +930,7 @@ index 0000000..1d41a66
+
+static int aspeed_jtag_xfer_push_data_last(struct aspeed_jtag *aspeed_jtag,
+ enum jtag_xfer_type type,
-+ u32 shift_bits,
-+ enum jtag_endstate endstate)
++ u32 shift_bits)
+{
+ int res = 0;
+
@@ -1014,8 +1027,7 @@ index 0000000..1d41a66
+ if (aspeed_jtag_xfer_push_data_last(
+ aspeed_jtag,
+ xfer->type,
-+ shift_bits,
-+ xfer->endstate) != 0) {
++ shift_bits) != 0) {
+ return -EFAULT;
+ }
+ } else {
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch
index af641ffe2..b91311d94 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch
@@ -86,8 +86,8 @@ Comments pointed by Pavel Machek <pavel@ucw.cz>
---
Documentation/ABI/testing/jtag-dev | 23 +++++++
Documentation/jtag/overview | 27 ++++++++
- Documentation/jtag/transactions | 138 +++++++++++++++++++++++++++++++++++++
- 3 files changed, 188 insertions(+)
+ Documentation/jtag/transactions | 145 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 195 insertions(+)
create mode 100644 Documentation/ABI/testing/jtag-dev
create mode 100644 Documentation/jtag/overview
create mode 100644 Documentation/jtag/transactions
@@ -159,7 +159,7 @@ new file mode 100644
index 0000000..76fd0b1
--- /dev/null
+++ b/Documentation/jtag/transactions
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,145 @@
+The JTAG API
+=============
+
@@ -204,8 +204,9 @@ index 0000000..76fd0b1
+------
+Force JTAG state machine to go into a TAPC state
+
-+struct jtag_end_tap_state {
++struct jtag_tap_state {
+ __u8 reset;
++ __u8 from;
+ __u8 endstate;
+ __u8 tck;
+};
@@ -217,21 +218,22 @@ index 0000000..76fd0b1
+tck: clock counter
+
+Example:
-+ struct jtag_end_tap_state end_state;
++ struct jtag_tap_state tap_state;
+
-+ end_state.endstate = JTAG_STATE_IDLE;
-+ end_state.reset = 0;
-+ end_state.tck = data_p->tck;
++ tap_state.from = JTAG_STATE_TLRESET;
++ tap_state.endstate = JTAG_STATE_IDLE;
++ tap_state.reset = 0;
++ tap_state.tck = data_p->tck;
+ usleep(25 * 1000);
-+ ioctl(jtag_fd, JTAG_SIOCSTATE, &end_state);
++ ioctl(jtag_fd, JTAG_SIOCSTATE, &tap_state);
+
+JTAG_GIOCSTATUS
+------
+Get JTAG TAPC machine state
+
+ unsigned int jtag_fd;
-+ jtag_endstate endstate;
-+ ioctl(jtag_fd, JTAG_GIOCSTATUS, &endstate);
++ jtag_tapstate tapstate;
++ ioctl(jtag_fd, JTAG_GIOCSTATUS, &tapstate);
+
+JTAG_IOCXFER
+------
@@ -240,6 +242,7 @@ index 0000000..76fd0b1
+struct jtag_xfer {
+ __u8 type;
+ __u8 direction;
++ __u8 from;
+ __u8 endstate;
+ __u8 padding;
+ __u32 length;
@@ -250,8 +253,11 @@ index 0000000..76fd0b1
+direction: xfer direction - JTAG_READ_XFER/JTAG_WRITE_XFER/JTAG_READ_WRITE_XFER
+length: xfer data length in bits
+tdio : xfer data array
++from: xfer from state can be current JTAG tap state saved by the driver
++ JTAG_STATE_CURRENT or in a multichain environment any state listed in
++ jtag_tapstate struct saved by your multichain controller software.
+endstate: xfer end state after transaction finish
-+ can be: any state listed in jtag_endstate struct
++ can be: any state listed in jtag_tapstate struct
+
+Example:
+ struct jtag_xfer xfer;
@@ -261,6 +267,7 @@ index 0000000..76fd0b1
+ xfer.type = JTAG_SDR_XFER;
+ xfer.tdio = (__u64)buf;
+ xfer.length = buf_len;
++ xfer.from = JTAG_STATE_TLRESET;
+ xfer.endstate = JTAG_STATE_IDLE;
+
+ if (is_read)
@@ -300,4 +307,3 @@ index 0000000..76fd0b1
+ tdo1 = bitbang_data[1].tdo;
--
2.7.4
-
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0059-media-aspeed-remove-source-buffer-allocation-before-.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0059-media-aspeed-remove-source-buffer-allocation-before-.patch
deleted file mode 100644
index 41bf4fb55..000000000
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0059-media-aspeed-remove-source-buffer-allocation-before-.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 28aa61a720d2db812d66b2b59681ba184771ff3e Mon Sep 17 00:00:00 2001
-From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
-Date: Tue, 21 May 2019 16:00:28 -0700
-Subject: [PATCH] media: aspeed: remove source buffer allocation before mode
- detection
-
-Mode detection doesn't require source buffer allocation so this
-commit removes that.
-
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
----
- drivers/media/platform/aspeed-video.c | 37 +++++------------------------------
- 1 file changed, 5 insertions(+), 32 deletions(-)
-
-diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
-index 1bb863b32836..fed51fd22ce2 100644
---- a/drivers/media/platform/aspeed-video.c
-+++ b/drivers/media/platform/aspeed-video.c
-@@ -733,27 +733,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
- det->height = MIN_HEIGHT;
- video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
-
-- /*
-- * Since we need max buffer size for detection, free the second source
-- * buffer first.
-- */
-- if (video->srcs[1].size)
-- aspeed_video_free_buf(video, &video->srcs[1]);
--
-- if (video->srcs[0].size < VE_MAX_SRC_BUFFER_SIZE) {
-- if (video->srcs[0].size)
-- aspeed_video_free_buf(video, &video->srcs[0]);
--
-- if (!aspeed_video_alloc_buf(video, &video->srcs[0],
-- VE_MAX_SRC_BUFFER_SIZE)) {
-- dev_err(video->dev,
-- "Failed to allocate source buffers\n");
-- return;
-- }
-- }
--
-- aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma);
--
- do {
- if (tries) {
- set_current_state(TASK_INTERRUPTIBLE);
-@@ -873,20 +852,14 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
-
- size *= 4;
-
-- if (size == video->srcs[0].size / 2) {
-- aspeed_video_write(video, VE_SRC1_ADDR,
-- video->srcs[0].dma + size);
-- } else if (size == video->srcs[0].size) {
-- if (!aspeed_video_alloc_buf(video, &video->srcs[1], size))
-- goto err_mem;
--
-- aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma);
-- } else {
-- aspeed_video_free_buf(video, &video->srcs[0]);
-+ if (size != video->srcs[0].size) {
-+ if (video->srcs[0].size)
-+ aspeed_video_free_buf(video, &video->srcs[0]);
-+ if (video->srcs[1].size)
-+ aspeed_video_free_buf(video, &video->srcs[1]);
-
- if (!aspeed_video_alloc_buf(video, &video->srcs[0], size))
- goto err_mem;
--
- if (!aspeed_video_alloc_buf(video, &video->srcs[1], size))
- goto err_mem;
-
---
-2.7.4
-
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-media-aspeed-use-different-delays-for-triggering-VE-.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-media-aspeed-use-different-delays-for-triggering-VE-.patch
deleted file mode 100644
index 3e158c628..000000000
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-media-aspeed-use-different-delays-for-triggering-VE-.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-From 431c7974302fad5ae835adb46d3c8fa4034c845a Mon Sep 17 00:00:00 2001
-From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
-Date: Tue, 21 May 2019 16:06:56 -0700
-Subject: [PATCH 2/4] media: aspeed: use different delays for triggering VE H/W
- reset
-
-In case of watchdog timeout detected while doing mode detection,
-it's better triggering video engine hardware reset immediately so
-this commit fixes code for the case. Other than the case, it will
-trigger video engine hardware reset after RESOLUTION_CHANGE_DELAY.
-
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
----
- drivers/media/platform/aspeed-video.c | 9 +++++----
- 1 file changed, 5 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
-index ee1f87a08c7c..b8540cc7848d 100644
---- a/drivers/media/platform/aspeed-video.c
-+++ b/drivers/media/platform/aspeed-video.c
-@@ -522,7 +522,7 @@ static void aspeed_video_bufs_done(struct aspeed_video *video,
- spin_unlock_irqrestore(&video->lock, flags);
- }
-
--static void aspeed_video_irq_res_change(struct aspeed_video *video)
-+static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay)
- {
- spin_lock(&video->lock);
- dev_dbg(video->dev, "Resolution changed; resetting\n");
-@@ -534,7 +534,7 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video)
- spin_unlock(&video->lock);
- aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
-
-- schedule_delayed_work(&video->res_work, RESOLUTION_CHANGE_DELAY);
-+ schedule_delayed_work(&video->res_work, delay);
- }
-
- static irqreturn_t aspeed_video_irq(int irq, void *arg)
-@@ -547,7 +547,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
- * re-initialize
- */
- if (sts & VE_INTERRUPT_MODE_DETECT_WD) {
-- aspeed_video_irq_res_change(video);
-+ aspeed_video_irq_res_change(video, 0);
- return IRQ_HANDLED;
- }
-
-@@ -565,7 +565,8 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
- * Signal acquired while NOT doing resolution
- * detection; reset the engine and re-initialize
- */
-- aspeed_video_irq_res_change(video);
-+ aspeed_video_irq_res_change(video,
-+ RESOLUTION_CHANGE_DELAY);
- return IRQ_HANDLED;
- }
- }
---
-2.21.0
-
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-media-aspeed-add-a-workaround-to-fix-a-silicon-bug.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-media-aspeed-add-a-workaround-to-fix-a-silicon-bug.patch
deleted file mode 100644
index a10963572..000000000
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-media-aspeed-add-a-workaround-to-fix-a-silicon-bug.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-From fa386f96691ed8501949daf5129667b72723a55e Mon Sep 17 00:00:00 2001
-From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
-Date: Thu, 23 May 2019 14:33:03 -0700
-Subject: [PATCH] media: aspeed: add a workaround to fix a silicon bug
-
-AST2500 silicon revision A1 and A2 have a silicon bug which causes
-extremly long capturing time on specific resolutions (1680 width).
-To fix the bug, this commit adjusts the capturing window register
-setting to 1728 if detected width is 1680. The compression window
-register setting will be kept as the original width so output
-result will be the same.
-
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
----
- drivers/media/platform/aspeed-video.c | 28 +++++++++++++++++++++-------
- 1 file changed, 21 insertions(+), 7 deletions(-)
-
-diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
-index 67d6380d4ef3..f58f44eab588 100644
---- a/drivers/media/platform/aspeed-video.c
-+++ b/drivers/media/platform/aspeed-video.c
-@@ -826,8 +826,29 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
- struct v4l2_bt_timings *act = &video->active_timings;
- unsigned int size = act->width * act->height;
-
-+ /* Set capture/compression frame sizes */
- aspeed_video_calc_compressed_size(video, size);
-
-+ if (video->active_timings.width == 1680) {
-+ /*
-+ * This is a workaround to fix a silicon bug on A1 and A2
-+ * revisions. Since it doesn't break capturing operation of
-+ * other revisions, use it for all revisions without checking
-+ * the revision ID. It picked 1728 which is a very next
-+ * 64-pixels aligned value to 1680 to minimize memory bandwidth
-+ * and to get better access speed from video engine.
-+ */
-+ aspeed_video_write(video, VE_CAP_WINDOW,
-+ 1728 << 16 | act->height);
-+ size += (1728 - 1680) * video->active_timings.height;
-+ } else {
-+ aspeed_video_write(video, VE_CAP_WINDOW,
-+ act->width << 16 | act->height);
-+ }
-+ aspeed_video_write(video, VE_COMP_WINDOW,
-+ act->width << 16 | act->height);
-+ aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4);
-+
- /* Don't use direct mode below 1024 x 768 (irqs don't fire) */
- if (size < DIRECT_FETCH_THRESHOLD) {
- aspeed_video_write(video, VE_TGS_0,
-@@ -844,13 +865,6 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
- aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH);
- }
-
-- /* Set capture/compression frame sizes */
-- aspeed_video_write(video, VE_CAP_WINDOW,
-- act->width << 16 | act->height);
-- aspeed_video_write(video, VE_COMP_WINDOW,
-- act->width << 16 | act->height);
-- aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4);
--
- size *= 4;
-
- if (size != video->srcs[0].size) {
---
-2.7.4
-
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch
new file mode 100644
index 000000000..3a86d5b25
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch
@@ -0,0 +1,55 @@
+From 50221ac92816333efcf961c5f22f8b9ffdccb31b Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 11 Jun 2019 14:59:53 -0700
+Subject: [PATCH] i2c: aspeed: fix master pending state handling
+
+In case of a master pending state, it should not trigger the master
+command because this H/W is sharing the same byte buffer for slave
+and master operation, so this commit fixes the issue with making
+the master command triggering happens when the state goes to active
+state.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/i2c/busses/i2c-aspeed.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index f96160e01a69..64bc68eaa88f 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -384,18 +384,19 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
+ struct i2c_msg *msg = &bus->msgs[bus->msgs_index];
+ u8 slave_addr = i2c_8bit_addr_from_msg(msg);
+
+- bus->master_state = ASPEED_I2C_MASTER_START;
+-
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+ /*
+ * If it's requested in the middle of a slave session, set the master
+ * state to 'pending' then H/W will continue handling this master
+ * command when the bus comes back to the idle state.
+ */
+- if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
++ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) {
+ bus->master_state = ASPEED_I2C_MASTER_PENDING;
++ return;
++ }
+ #endif /* CONFIG_I2C_SLAVE */
+
++ bus->master_state = ASPEED_I2C_MASTER_START;
+ bus->buf_index = 0;
+
+ if (msg->flags & I2C_M_RD) {
+@@ -480,7 +481,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
+ goto out_no_complete;
+
+- bus->master_state = ASPEED_I2C_MASTER_START;
++ aspeed_i2c_do_start(bus);
+ }
+ #endif /* CONFIG_I2C_SLAVE */
+
+--
+2.7.4
+
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
new file mode 100644
index 000000000..9480daeff
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch
@@ -0,0 +1,770 @@
+From efb710a6b3a39f28b988af717eefc1b72c4c43bd 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 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>
+---
+ arch/arm/boot/dts/aspeed-g4.dtsi | 42 ++++--
+ arch/arm/boot/dts/aspeed-g5.dtsi | 42 ++++--
+ drivers/i2c/busses/i2c-aspeed.c | 262 ++++++++++++++++++++++++++++++++----
+ drivers/irqchip/irq-aspeed-i2c-ic.c | 8 ++
+ 4 files changed, 301 insertions(+), 53 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index 47a5029f5bdb..c1c125add9fa 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -482,7 +482,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x40 0x40>;
++ reg = <0x40 0x40>, <0x800 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -498,7 +499,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x80 0x40>;
++ reg = <0x80 0x40>, <0x880 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -514,7 +516,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0xc0 0x40>;
++ reg = <0xc0 0x40>, <0x900 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -531,7 +534,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x100 0x40>;
++ reg = <0x100 0x40>, <0x980 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -548,7 +552,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x140 0x40>;
++ reg = <0x140 0x40>, <0xa00 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -565,7 +570,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x180 0x40>;
++ reg = <0x180 0x40>, <0xa80 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -582,7 +588,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x1c0 0x40>;
++ reg = <0x1c0 0x40>, <0xb00 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -599,7 +606,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x300 0x40>;
++ reg = <0x300 0x40>, <0xb80 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -616,7 +624,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x340 0x40>;
++ reg = <0x340 0x40>, <0xc00 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -633,7 +642,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x380 0x40>;
++ reg = <0x380 0x40>, <0xc80 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -650,7 +660,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x3c0 0x40>;
++ reg = <0x3c0 0x40>, <0xd00 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -667,7 +678,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x400 0x40>;
++ reg = <0x400 0x40>, <0xd80 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -684,7 +696,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x440 0x40>;
++ reg = <0x440 0x40>, <0xe00 0x80>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -701,7 +714,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x480 0x40>;
++ reg = <0x480 0x40>, <0xe80 0x80>;
++ reg-names = "bus-regs", "buf";
+ 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 9d5ed9499b1f..662249bc15f9 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -599,7 +599,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x40 0x40>;
++ reg = <0x40 0x40>, <0x200 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -615,7 +616,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x80 0x40>;
++ reg = <0x80 0x40>, <0x210 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -631,7 +633,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0xc0 0x40>;
++ reg = <0xc0 0x40>, <0x220 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -648,7 +651,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x100 0x40>;
++ reg = <0x100 0x40>, <0x230 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -665,7 +669,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x140 0x40>;
++ reg = <0x140 0x40>, <0x240 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -682,7 +687,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x180 0x40>;
++ reg = <0x180 0x40>, <0x250 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -699,7 +705,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x1c0 0x40>;
++ reg = <0x1c0 0x40>, <0x260 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -716,7 +723,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x300 0x40>;
++ reg = <0x300 0x40>, <0x270 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -733,7 +741,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x340 0x40>;
++ reg = <0x340 0x40>, <0x280 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -750,7 +759,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x380 0x40>;
++ reg = <0x380 0x40>, <0x290 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -767,7 +777,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x3c0 0x40>;
++ reg = <0x3c0 0x40>, <0x2a0 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -784,7 +795,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x400 0x40>;
++ reg = <0x400 0x40>, <0x2b0 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -801,7 +813,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x440 0x40>;
++ reg = <0x440 0x40>, <0x2c0 0x10>;
++ reg-names = "bus-regs", "buf";
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -818,7 +831,8 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x480 0x40>;
++ reg = <0x480 0x40>, <0x2d0 0x10>;
++ reg-names = "bus-regs", "buf";
+ 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 64bc68eaa88f..b21a4c87853e 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -10,6 +10,7 @@
+ * published by the Free Software Foundation.
+ */
+
++#include <linux/bitfield.h>
+ #include <linux/clk.h>
+ #include <linux/completion.h>
+ #include <linux/err.h>
+@@ -38,6 +39,7 @@
+ #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 */
+@@ -46,6 +48,7 @@
+
+ /* 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)
+@@ -107,6 +110,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)
+@@ -117,6 +122,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,
+@@ -164,6 +176,11 @@ struct aspeed_i2c_bus {
+ int master_xfer_result;
+ /* Multi-master */
+ bool multi_master;
++ /* Buffer/DMA 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;
+@@ -260,6 +277,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)
+@@ -288,7 +306,11 @@ 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)
++ 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)
+@@ -318,6 +340,18 @@ 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->buf_base &&
++ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED) {
++ 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;
+ }
+@@ -350,6 +384,15 @@ 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_GCALL_REQUESTED:
+ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED;
+@@ -357,6 +400,24 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ 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_STOP:
+ i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
+@@ -383,6 +444,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)
+ /*
+@@ -401,12 +464,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_TX_BUFF_ENABLE |
++ ASPEED_I2CD_RX_BUFF_ENABLE;
++
++ wbuf[0] = slave_addr;
++ writel(*(u32 *)wbuf, bus->buf_base);
++
++ 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_TX_COUNT_MASK, 0) |
++ 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;
++
++ 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);
+ }
+
+@@ -441,12 +558,22 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
+ return 0;
+ }
+
++static inline int aspeed_i2c_is_tx_error(struct aspeed_i2c_bus *bus)
++{
++ if (FIELD_GET(ASPEED_I2CD_BUF_TX_COUNT_MASK,
++ readl(bus->base + ASPEED_I2C_BUF_CTRL_REG)) !=
++ bus->buf_size - 1)
++ return -EIO;
++
++ return 0;
++}
++
+ 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;
+@@ -559,11 +686,46 @@ 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) {
++ if (bus->buf_base) {
++ u8 wbuf[4];
++ int i;
++
++ if (unlikely(aspeed_i2c_is_tx_error(bus)))
++ goto error_and_stop;
++
++ 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);
++ writel(ASPEED_I2CD_TX_BUFF_ENABLE |
++ ASPEED_I2CD_M_TX_CMD,
++ bus->base + ASPEED_I2C_CMD_REG);
++ } else {
++ 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);
++ }
+ 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);
+ }
+@@ -580,25 +742,57 @@ 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);
+@@ -948,6 +1142,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
+@@ -1010,17 +1207,32 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ struct aspeed_i2c_bus *bus;
+ struct clk *parent_clk;
+ struct resource *res;
++ void __iomem *gc_reg;
+ int irq, ret;
+
+ bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bus-regs");
+ bus->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(bus->base))
+ return PTR_ERR(bus->base);
+
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "buf");
++ 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;
++ }
++ }
++
+ parent_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(parent_clk))
+ return PTR_ERR(parent_clk);
+diff --git a/drivers/irqchip/irq-aspeed-i2c-ic.c b/drivers/irqchip/irq-aspeed-i2c-ic.c
+index f20200af0992..99985b22a9fa 100644
+--- a/drivers/irqchip/irq-aspeed-i2c-ic.c
++++ b/drivers/irqchip/irq-aspeed-i2c-ic.c
+@@ -18,6 +18,9 @@
+ #include <linux/of_irq.h>
+ #include <linux/io.h>
+
++/* I2C Global Control Register (AST2500) */
++#define ASPEED_I2C_GLOBAL_CTRL_REG 0xc
++#define ASPEED_I2C_SRAM_BUFFER_EN BIT(0)
+
+ #define ASPEED_I2C_IC_NUM_BUS 14
+
+@@ -100,6 +103,11 @@ static int __init aspeed_i2c_ic_of_init(struct device_node *node,
+ irq_set_chained_handler_and_data(i2c_ic->parent_irq,
+ aspeed_i2c_ic_irq_handler, i2c_ic);
+
++ /* Enable I2C SRAM buffer in case of AST2500 */
++ if (of_device_is_compatible(node, "aspeed,ast2500-i2c-ic"))
++ writel(ASPEED_I2C_SRAM_BUFFER_EN,
++ i2c_ic->base + ASPEED_I2C_GLOBAL_CTRL_REG);
++
+ pr_info("i2c controller registered, irq %d\n", i2c_ic->parent_irq);
+
+ return 0;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend
index 7ae4b5e64..ed5be3455 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend
@@ -41,7 +41,6 @@ SRC_URI += " \
file://0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch \
file://0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch \
file://0058-i2c-aspeed-add-general-call-support.patch \
- file://0059-media-aspeed-remove-source-buffer-allocation-before-.patch \
- file://0060-media-aspeed-use-different-delays-for-triggering-VE-.patch \
- file://0062-media-aspeed-add-a-workaround-to-fix-a-silicon-bug.patch \
+ file://0065-i2c-aspeed-fix-master-pending-state-handling.patch \
+ file://0066-i2c-aspeed-add-buffer-mode-transfer-support.patch \
"