diff options
author | Ed Tanous <ed.tanous@intel.com> | 2019-06-20 19:46:38 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-20 19:46:38 +0300 |
commit | 43a183cc0926da36e3a218efa02ab4838ace316f (patch) | |
tree | 9ea192b408585fc2a19b54d196c3d56eaddc4acb /meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed | |
parent | 5575b1d27fc222f973d96dc06af0f21ba7656f28 (diff) | |
parent | 2c7e8f4ce61f2e0407c37e98e22bbb13e562b414 (diff) | |
download | openbmc-43a183cc0926da36e3a218efa02ab4838ace316f.tar.xz |
Merge pull request #12 from Intel-BMC/update
Update
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed')
8 files changed, 921 insertions, 265 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 + |