summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed
diff options
context:
space:
mode:
authorEd Tanous <ed.tanous@intel.com>2019-05-29 20:29:58 +0300
committerEd Tanous <ed.tanous@intel.com>2019-06-06 04:30:22 +0300
commit87a65e63bac789bca0607e0b4ab09d62517b95e7 (patch)
tree3254b912d6468012543e127a19ba2f1cd13b108f /meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed
parent5364646cb66fa75cdcbf148e039e0383cda94f2a (diff)
downloadopenbmc-87a65e63bac789bca0607e0b4ab09d62517b95e7.tar.xz
Update to internal
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch1375
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch39
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch1057
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch291
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch35
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch174
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch177
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0050-media-platform-Fix-a-kernel-warning-on-clk-control.patch177
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch35
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch904
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch1282
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch108
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch303
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch57
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch50
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch182
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0059-media-aspeed-remove-source-buffer-allocation-before-.patch49
-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/0061-media-aspeed-fix-an-incorrect-timeout-checking-in-mo.patch30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-media-aspeed-add-a-workaround-to-fix-a-silicon-bug.patch66
24 files changed, 4382 insertions, 2104 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch
index db21250bb..d2ecdfd72 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch
@@ -1,4 +1,4 @@
-From 63ccbbe64f7e6560233971b886f6166fc59d20ef Mon Sep 17 00:00:00 2001
+From 9c27803dd432c7a9fc57dd3e16f0fd724919575e Mon Sep 17 00:00:00 2001
From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Date: Mon, 7 Jan 2019 09:56:10 -0800
Subject: [PATCH] Update PECI drivers to sync with linux upstreaming version
@@ -10,28 +10,32 @@ Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
Documentation/hwmon/peci-cputemp | 34 +-
drivers/hwmon/Kconfig | 4 +-
- drivers/hwmon/peci-cputemp.c | 156 ++++--
+ drivers/hwmon/peci-cputemp.c | 162 ++++--
drivers/hwmon/peci-dimmtemp.c | 69 +--
drivers/hwmon/peci-hwmon.h | 9 +-
drivers/mfd/Kconfig | 5 +-
- drivers/mfd/intel-peci-client.c | 43 +-
- drivers/peci/Kconfig | 35 +-
- drivers/peci/Makefile | 6 +-
- drivers/peci/busses/Kconfig | 19 +
- drivers/peci/busses/Makefile | 6 +
+ drivers/mfd/intel-peci-client.c | 49 +-
+ drivers/peci/Kconfig | 46 +-
+ drivers/peci/Makefile | 7 +-
+ drivers/peci/busses/Kconfig | 32 ++
+ drivers/peci/busses/Makefile | 7 +
drivers/peci/busses/peci-aspeed.c | 494 +++++++++++++++++++
+ drivers/peci/busses/peci-npcm.c | 410 +++++++++++++++
drivers/peci/peci-aspeed.c | 505 -------------------
- drivers/peci/peci-core.c | 889 ++++++++++++++++++----------------
- drivers/peci/peci-dev.c | 340 +++++++++++++
- include/linux/mfd/intel-peci-client.h | 6 +-
+ drivers/peci/peci-core.c | 905 +++++++++++++++++++---------------
+ drivers/peci/peci-dev.c | 346 +++++++++++++
+ drivers/peci/peci-npcm.c | 410 ---------------
+ include/linux/mfd/intel-peci-client.h | 32 +-
include/linux/peci.h | 30 +-
- include/uapi/linux/peci-ioctl.h | 394 ++++++++-------
- 18 files changed, 1805 insertions(+), 1239 deletions(-)
+ include/uapi/linux/peci-ioctl.h | 416 +++++++++-------
+ 20 files changed, 2296 insertions(+), 1676 deletions(-)
create mode 100644 drivers/peci/busses/Kconfig
create mode 100644 drivers/peci/busses/Makefile
create mode 100644 drivers/peci/busses/peci-aspeed.c
+ create mode 100644 drivers/peci/busses/peci-npcm.c
delete mode 100644 drivers/peci/peci-aspeed.c
create mode 100644 drivers/peci/peci-dev.c
+ delete mode 100644 drivers/peci/peci-npcm.c
diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp
index 821a9258f2e6..a3a3e465c888 100644
@@ -89,7 +93,7 @@ index 821a9258f2e6..a3a3e465c888 100644
+temp[6-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
the core.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
-index 996e80590b5b..93945eb19261 100644
+index 18cd3b17f660..0bd06a938526 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1321,7 +1321,7 @@ config SENSORS_PECI_CPUTEMP
@@ -111,7 +115,7 @@ index 996e80590b5b..93945eb19261 100644
source "drivers/hwmon/pmbus/Kconfig"
diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
-index 11880c86a854..30ba1638e358 100644
+index 11880c86a854..3cb2db2fdf0a 100644
--- a/drivers/hwmon/peci-cputemp.c
+++ b/drivers/hwmon/peci-cputemp.c
@@ -1,5 +1,5 @@
@@ -214,7 +218,7 @@ index 11880c86a854..30ba1638e358 100644
/* Note that the tjmax should be available before calling it */
priv->temp.die.value = priv->temp.tjmax.value +
-@@ -144,24 +151,67 @@ static int get_die_temp(struct peci_cputemp *priv)
+@@ -144,24 +151,70 @@ static int get_die_temp(struct peci_cputemp *priv)
return 0;
}
@@ -237,6 +241,9 @@ index 11880c86a854..30ba1638e358 100644
+ if (ret)
+ return ret;
+
++ if (msg.cc != PECI_DEV_CC_SUCCESS)
++ return -EAGAIN;
++
+ dts_margin = (msg.pkg_config[1] << 8) | msg.pkg_config[0];
+
+ /**
@@ -289,7 +296,7 @@ index 11880c86a854..30ba1638e358 100644
* Processors return a value of the core DTS reading in 10.6 format
* (10 bits signed decimal, 6 bits fractional).
* Error codes:
-@@ -192,6 +242,7 @@ static int cputemp_read_string(struct device *dev,
+@@ -192,6 +245,7 @@ static int cputemp_read_string(struct device *dev,
return -EOPNOTSUPP;
*str = cputemp_label[channel];
@@ -297,7 +304,7 @@ index 11880c86a854..30ba1638e358 100644
return 0;
}
-@@ -200,26 +251,33 @@ static int cputemp_read(struct device *dev,
+@@ -200,26 +254,33 @@ static int cputemp_read(struct device *dev,
u32 attr, int channel, long *val)
{
struct peci_cputemp *priv = dev_get_drvdata(dev);
@@ -337,7 +344,7 @@ index 11880c86a854..30ba1638e358 100644
case channel_tcontrol:
*val = priv->temp.tcontrol.value;
break;
-@@ -231,8 +289,8 @@ static int cputemp_read(struct device *dev,
+@@ -231,8 +292,8 @@ static int cputemp_read(struct device *dev,
break;
default:
core_index = channel - DEFAULT_CHANNEL_NUMS;
@@ -348,7 +355,7 @@ index 11880c86a854..30ba1638e358 100644
break;
*val = priv->temp.core[core_index].value;
-@@ -249,11 +307,11 @@ static int cputemp_read(struct device *dev,
+@@ -249,11 +310,11 @@ static int cputemp_read(struct device *dev,
*val = priv->temp.tjmax.value - priv->temp.tcontrol.value;
break;
default:
@@ -362,7 +369,7 @@ index 11880c86a854..30ba1638e358 100644
}
static umode_t cputemp_is_visible(const void *data,
-@@ -262,11 +320,11 @@ static umode_t cputemp_is_visible(const void *data,
+@@ -262,11 +323,11 @@ static umode_t cputemp_is_visible(const void *data,
{
const struct peci_cputemp *priv = data;
@@ -379,7 +386,7 @@ index 11880c86a854..30ba1638e358 100644
return 0;
}
-@@ -280,7 +338,7 @@ static const struct hwmon_ops cputemp_ops = {
+@@ -280,7 +341,7 @@ static const struct hwmon_ops cputemp_ops = {
static int check_resolved_cores(struct peci_cputemp *priv)
{
struct peci_rd_pci_cfg_local_msg msg;
@@ -388,7 +395,7 @@ index 11880c86a854..30ba1638e358 100644
/* Get the RESOLVED_CORES register value */
msg.addr = priv->mgr->client->addr;
-@@ -290,30 +348,31 @@ static int check_resolved_cores(struct peci_cputemp *priv)
+@@ -290,30 +351,34 @@ static int check_resolved_cores(struct peci_cputemp *priv)
msg.reg = REG_RESOLVED_CORES_OFFSET;
msg.rx_len = 4;
@@ -400,6 +407,9 @@ index 11880c86a854..30ba1638e358 100644
+ PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
+ if (ret)
+ return ret;
++
++ if (msg.cc != PECI_DEV_CC_SUCCESS)
++ return -EAGAIN;
priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config);
if (!priv->core_mask)
@@ -429,7 +439,7 @@ index 11880c86a854..30ba1638e358 100644
priv->temp_config[priv->config_idx++] =
config_table[channel_core];
-@@ -326,7 +385,7 @@ static int peci_cputemp_probe(struct platform_device *pdev)
+@@ -326,7 +391,7 @@ static int peci_cputemp_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct peci_cputemp *priv;
struct device *hwmon_dev;
@@ -438,7 +448,7 @@ index 11880c86a854..30ba1638e358 100644
if ((mgr->client->adapter->cmd_mask &
(BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
-@@ -346,12 +405,13 @@ static int peci_cputemp_probe(struct platform_device *pdev)
+@@ -346,12 +411,13 @@ static int peci_cputemp_probe(struct platform_device *pdev)
mgr->client->addr - PECI_BASE_ADDR);
priv->temp_config[priv->config_idx++] = config_table[channel_die];
@@ -686,7 +696,7 @@ index 9af5730ad7ba..28087e9cd4da 100644
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
depends on SA1100_H3100 || SA1100_H3600
diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
-index d53e4f1078ac..d62442438512 100644
+index d53e4f1078ac..466085fd43b9 100644
--- a/drivers/mfd/intel-peci-client.c
+++ b/drivers/mfd/intel-peci-client.c
@@ -1,12 +1,12 @@
@@ -717,7 +727,7 @@ index d53e4f1078ac..d62442438512 100644
static struct mfd_cell peci_functions[] = {
{ .name = "peci-cputemp", },
{ .name = "peci-dimmtemp", },
-@@ -31,19 +25,19 @@ static struct mfd_cell peci_functions[] = {
+@@ -31,19 +25,25 @@ static struct mfd_cell peci_functions[] = {
};
static const struct cpu_gen_info cpu_gen_info_table[] = {
@@ -736,11 +746,17 @@ index d53e4f1078ac..d62442438512 100644
.chan_rank_max = CHAN_RANK_MAX_ON_BDX,
.dimm_idx_max = DIMM_IDX_MAX_ON_BDX },
- [CPU_GEN_SKX] = {
++ { /* Broadwell Xeon D */
++ .family = 6, /* Family code */
++ .model = INTEL_FAM6_BROADWELL_XEON_D,
++ .core_max = CORE_MAX_ON_XD,
++ .chan_rank_max = CHAN_RANK_MAX_ON_XD,
++ .dimm_idx_max = DIMM_IDX_MAX_ON_XD },
+ { /* Skylake Xeon */
.family = 6, /* Family code */
.model = INTEL_FAM6_SKYLAKE_X,
.core_max = CORE_MAX_ON_SKX,
-@@ -53,16 +47,17 @@ static const struct cpu_gen_info cpu_gen_info_table[] = {
+@@ -53,16 +53,17 @@ static const struct cpu_gen_info cpu_gen_info_table[] = {
static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv)
{
@@ -763,7 +779,7 @@ index d53e4f1078ac..d62442438512 100644
family = FIELD_PREP(LOWER_BYTE_MASK,
FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id)) |
-@@ -83,11 +78,11 @@ static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv)
+@@ -83,11 +84,11 @@ static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv)
}
if (!priv->gen_info) {
@@ -778,7 +794,7 @@ index d53e4f1078ac..d62442438512 100644
}
static int peci_client_probe(struct peci_client *client)
-@@ -103,31 +98,29 @@ static int peci_client_probe(struct peci_client *client)
+@@ -103,31 +104,29 @@ static int peci_client_probe(struct peci_client *client)
dev_set_drvdata(dev, priv);
priv->client = client;
@@ -815,7 +831,7 @@ index d53e4f1078ac..d62442438512 100644
static const struct peci_device_id peci_client_ids[] = {
{ .name = "peci-client" },
diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig
-index 9e9845ebcff4..9752feee2454 100644
+index 7293108fb543..9752feee2454 100644
--- a/drivers/peci/Kconfig
+++ b/drivers/peci/Kconfig
@@ -2,10 +2,12 @@
@@ -833,7 +849,7 @@ index 9e9845ebcff4..9752feee2454 100644
help
The Platform Environment Control Interface (PECI) is a one-wire bus
interface that provides a communication channel from Intel processors
-@@ -14,26 +16,23 @@ config PECI
+@@ -14,37 +16,23 @@ config PECI
If you want PECI support, you should say Y here and also to the
specific driver for your bus adapter(s) below.
@@ -842,42 +858,53 @@ index 9e9845ebcff4..9752feee2454 100644
-#
-# PECI hardware bus configuration
-#
+-
+-menu "PECI Hardware Bus support"
+-
+-config PECI_ASPEED
+- tristate "ASPEED PECI support"
+- select REGMAP_MMIO
+- depends on OF
+- depends on ARCH_ASPEED || COMPILE_TEST
+- help
+- Say Y here if you want support for the Platform Environment Control
+- Interface (PECI) bus adapter driver on the ASPEED SoCs.
+ This support is also available as a module. If so, the module
+ will be called peci-core.
--menu "PECI Hardware Bus support"
+- This support is also available as a module. If so, the module
+- will be called peci-aspeed.
+if PECI
--config PECI_ASPEED
-- tristate "ASPEED PECI support"
+-config PECI_NPCM
+- tristate "Nuvoton NPCM PECI support"
- select REGMAP_MMIO
- depends on OF
-- depends on ARCH_ASPEED || COMPILE_TEST
+- depends on ARCH_NPCM || COMPILE_TEST
+config PECI_CHARDEV
+ tristate "PECI device interface"
help
- Say Y here if you want support for the Platform Environment Control
-- Interface (PECI) bus adapter driver on the ASPEED SoCs.
+- Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs.
+ Say Y here to use peci-* device files, usually found in the /dev
+ directory on your system. They make it possible to have user-space
+ programs use the PECI bus.
-- This support is also available as a module. If so, the module
-- will be called peci-aspeed.
-+ This support is also available as a module. If so, the module
-+ will be called peci-dev.
-
+ This support is also available as a module. If so, the module
+- will be called peci-npcm.
-endmenu
++ will be called peci-dev.
++
+source "drivers/peci/busses/Kconfig"
endif # PECI
+
+endmenu
diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile
-index 886285e69765..da8b0a33fa42 100644
+index 3326da54a21a..da8b0a33fa42 100644
--- a/drivers/peci/Makefile
+++ b/drivers/peci/Makefile
-@@ -1,9 +1,11 @@
+@@ -1,10 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
#
-# Makefile for the PECI core and bus drivers.
@@ -890,13 +917,14 @@ index 886285e69765..da8b0a33fa42 100644
# Hardware specific bus drivers
-obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o
+-obj-$(CONFIG_PECI_NPCM) += peci-npcm.o
+obj-y += busses/
diff --git a/drivers/peci/busses/Kconfig b/drivers/peci/busses/Kconfig
new file mode 100644
-index 000000000000..a20d470b4250
+index 000000000000..bfacafb7a7ba
--- /dev/null
+++ b/drivers/peci/busses/Kconfig
-@@ -0,0 +1,19 @@
+@@ -0,0 +1,32 @@
+#
+# PECI hardware bus configuration
+#
@@ -912,22 +940,36 @@ index 000000000000..a20d470b4250
+ Say Y here if you want support for the Platform Environment Control
+ Interface (PECI) bus adapter driver on the ASPEED SoCs.
+
-+ This support is also available as a module. If so, the module
++ This support is also available as a module. If so, the module
+ will be called peci-aspeed.
+
++config PECI_NPCM
++ tristate "Nuvoton NPCM PECI support"
++ select REGMAP_MMIO
++ depends on OF
++ depends on ARCH_NPCM || COMPILE_TEST
++ depends on PECI
++ help
++ Say Y here if you want support for the Platform Environment Control
++ Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs.
++
++ This support is also available as a module. If so, the module
++ will be called peci-npcm.
++
+endmenu
diff --git a/drivers/peci/busses/Makefile b/drivers/peci/busses/Makefile
new file mode 100644
-index 000000000000..69e31dfaca19
+index 000000000000..aa8ce3ae5947
--- /dev/null
+++ b/drivers/peci/busses/Makefile
-@@ -0,0 +1,6 @@
+@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the PECI hardware bus drivers.
+#
+
+obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o
++obj-$(CONFIG_PECI_NPCM) += peci-npcm.o
diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c
new file mode 100644
index 000000000000..8a0dd40730cc
@@ -1428,6 +1470,422 @@ index 000000000000..8a0dd40730cc
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("ASPEED PECI driver");
+MODULE_LICENSE("GPL v2");
+diff --git a/drivers/peci/busses/peci-npcm.c b/drivers/peci/busses/peci-npcm.c
+new file mode 100644
+index 000000000000..f632365b1416
+--- /dev/null
++++ b/drivers/peci/busses/peci-npcm.c
+@@ -0,0 +1,410 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2019 Nuvoton Technology corporation.
++
++#include <linux/bitfield.h>
++#include <linux/clk.h>
++#include <linux/interrupt.h>
++#include <linux/jiffies.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/peci.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/mfd/syscon.h>
++#include <linux/reset.h>
++
++/* NPCM7xx GCR module */
++#define NPCM7XX_INTCR3_OFFSET 0x9C
++#define NPCM7XX_INTCR3_PECIVSEL BIT(19)
++
++/* NPCM PECI Registers */
++#define NPCM_PECI_CTL_STS 0x00
++#define NPCM_PECI_RD_LENGTH 0x04
++#define NPCM_PECI_ADDR 0x08
++#define NPCM_PECI_CMD 0x0C
++#define NPCM_PECI_CTL2 0x10
++#define NPCM_PECI_WR_LENGTH 0x1C
++#define NPCM_PECI_PDDR 0x2C
++#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4))
++
++#define NPCM_PECI_MAX_REG 0x200
++
++/* NPCM_PECI_CTL_STS - 0x00 : Control Register */
++#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6)
++#define NPCM_PECI_CTRL_ABRT_ERR BIT(4)
++#define NPCM_PECI_CTRL_CRC_ERR BIT(3)
++#define NPCM_PECI_CTRL_DONE BIT(1)
++#define NPCM_PECI_CTRL_START_BUSY BIT(0)
++
++/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */
++#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0)
++
++/* NPCM_PECI_CMD - 0x10 : Command Register */
++#define NPCM_PECI_CTL2_MASK GENMASK(7, 6)
++
++/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */
++#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0)
++
++/* NPCM_PECI_PDDR - 0x2C : Command Register */
++#define NPCM_PECI_PDDR_MASK GENMASK(4, 0)
++
++#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \
++ NPCM_PECI_CTRL_CRC_ERR | \
++ NPCM_PECI_CTRL_DONE)
++
++#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000
++#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000
++#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000
++#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000
++#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31
++#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7
++#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15
++#define NPCM_PECI_PULL_DOWN_DEFAULT 0
++#define NPCM_PECI_PULL_DOWN_MAX 2
++
++struct npcm_peci {
++ u32 cmd_timeout_ms;
++ u32 host_bit_rate;
++ struct completion xfer_complete;
++ struct regmap *gcr_regmap;
++ struct peci_adapter *adapter;
++ struct regmap *regmap;
++ u32 status;
++ spinlock_t lock; /* to sync completion status handling */
++ struct device *dev;
++ struct clk *clk;
++ int irq;
++};
++
++static int npcm_peci_xfer_native(struct npcm_peci *priv,
++ struct peci_xfer_msg *msg)
++{
++ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms);
++ unsigned long flags;
++ unsigned int msg_rd;
++ u32 cmd_sts;
++ int i, rc;
++
++ /* Check command sts and bus idle state */
++ rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts,
++ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY),
++ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC,
++ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC);
++ if (rc)
++ return rc; /* -ETIMEDOUT */
++
++ spin_lock_irqsave(&priv->lock, flags);
++ reinit_completion(&priv->xfer_complete);
++
++ regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr);
++ regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH,
++ NPCM_PECI_WR_LEN_MASK & msg->rx_len);
++ regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH,
++ NPCM_PECI_WR_LEN_MASK & msg->tx_len);
++
++ if (msg->tx_len) {
++ regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]);
++
++ for (i = 0; i < (msg->tx_len - 1); i++)
++ regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i),
++ msg->tx_buf[i + 1]);
++ }
++
++ priv->status = 0;
++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS,
++ NPCM_PECI_CTRL_START_BUSY,
++ NPCM_PECI_CTRL_START_BUSY);
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete,
++ timeout);
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ regmap_write(priv->regmap, NPCM_PECI_CMD, 0);
++
++ if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) {
++ if (err < 0) { /* -ERESTARTSYS */
++ rc = (int)err;
++ goto err_irqrestore;
++ } else if (err == 0) {
++ dev_dbg(priv->dev, "Timeout waiting for a response!\n");
++ rc = -ETIMEDOUT;
++ goto err_irqrestore;
++ }
++
++ dev_dbg(priv->dev, "No valid response!\n");
++ rc = -EIO;
++ goto err_irqrestore;
++ }
++
++ for (i = 0; i < msg->rx_len; i++) {
++ regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd);
++ msg->rx_buf[i] = (u8)msg_rd;
++ }
++
++err_irqrestore:
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return rc;
++}
++
++static irqreturn_t npcm_peci_irq_handler(int irq, void *arg)
++{
++ struct npcm_peci *priv = arg;
++ u32 status_ack = 0;
++ u32 status;
++
++ spin_lock(&priv->lock);
++ regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status);
++ priv->status |= (status & NPCM_PECI_INT_MASK);
++
++ if (status & NPCM_PECI_CTRL_CRC_ERR) {
++ dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n");
++ status_ack |= NPCM_PECI_CTRL_CRC_ERR;
++ }
++
++ if (status & NPCM_PECI_CTRL_ABRT_ERR) {
++ dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n");
++ status_ack |= NPCM_PECI_CTRL_ABRT_ERR;
++ }
++
++ /*
++ * All commands should be ended up with a NPCM_PECI_CTRL_DONE
++ * bit set even in an error case.
++ */
++ if (status & NPCM_PECI_CTRL_DONE) {
++ dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n");
++ status_ack |= NPCM_PECI_CTRL_DONE;
++ complete(&priv->xfer_complete);
++ }
++
++ regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS,
++ NPCM_PECI_INT_MASK, status_ack);
++
++ spin_unlock(&priv->lock);
++ return IRQ_HANDLED;
++}
++
++static int npcm_peci_init_ctrl(struct npcm_peci *priv)
++{
++ u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0;
++ int ret;
++ bool volt;
++
++ priv->clk = devm_clk_get(priv->dev, NULL);
++ if (IS_ERR(priv->clk)) {
++ dev_err(priv->dev, "Failed to get clk source.\n");
++ return PTR_ERR(priv->clk);
++ }
++
++ ret = clk_prepare_enable(priv->clk);
++ if (ret) {
++ dev_err(priv->dev, "Failed to enable clock.\n");
++ return ret;
++ }
++
++ ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms",
++ &priv->cmd_timeout_ms);
++ if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX ||
++ priv->cmd_timeout_ms == 0) {
++ if (ret)
++ dev_warn(priv->dev,
++ "cmd-timeout-ms not found, use default : %u\n",
++ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT);
++ else
++ dev_warn(priv->dev,
++ "Invalid cmd-timeout-ms : %u. Use default : %u\n",
++ priv->cmd_timeout_ms,
++ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT);
++
++ priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT;
++ }
++
++ if (of_device_is_compatible(priv->dev->of_node,
++ "nuvoton,npcm750-peci")) {
++ priv->gcr_regmap = syscon_regmap_lookup_by_compatible
++ ("nuvoton,npcm750-gcr");
++ if (!IS_ERR(priv->gcr_regmap)) {
++ volt = of_property_read_bool(priv->dev->of_node,
++ "high-volt-range");
++ if (volt)
++ regmap_update_bits(priv->gcr_regmap,
++ NPCM7XX_INTCR3_OFFSET,
++ NPCM7XX_INTCR3_PECIVSEL,
++ NPCM7XX_INTCR3_PECIVSEL);
++ else
++ regmap_update_bits(priv->gcr_regmap,
++ NPCM7XX_INTCR3_OFFSET,
++ NPCM7XX_INTCR3_PECIVSEL, 0);
++ }
++ }
++
++ ret = of_property_read_u32(priv->dev->of_node, "pull-down",
++ &pull_down);
++ if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) {
++ if (ret)
++ dev_warn(priv->dev,
++ "pull-down not found, use default : %u\n",
++ NPCM_PECI_PULL_DOWN_DEFAULT);
++ else
++ dev_warn(priv->dev,
++ "Invalid pull-down : %u. Use default : %u\n",
++ pull_down,
++ NPCM_PECI_PULL_DOWN_DEFAULT);
++ pull_down = NPCM_PECI_PULL_DOWN_DEFAULT;
++ }
++
++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK,
++ pull_down << 6);
++
++ ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate",
++ &host_neg_bit_rate);
++ if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX ||
++ host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) {
++ if (ret)
++ dev_warn(priv->dev,
++ "host-neg-bit-rate not found, use default : %u\n",
++ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT);
++ else
++ dev_warn(priv->dev,
++ "Invalid host-neg-bit-rate : %u. Use default : %u\n",
++ host_neg_bit_rate,
++ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT);
++ host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT;
++ }
++
++ regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK,
++ host_neg_bit_rate);
++
++ priv->host_bit_rate = clk_get_rate(priv->clk) /
++ (4 * (host_neg_bit_rate + 1));
++
++ ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts,
++ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY),
++ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC,
++ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC);
++ if (ret)
++ return ret; /* -ETIMEDOUT */
++
++ /* PECI interrupt enable */
++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS,
++ NPCM_PECI_CTRL_DONE_INT_EN,
++ NPCM_PECI_CTRL_DONE_INT_EN);
++
++ return 0;
++}
++
++static const struct regmap_config npcm_peci_regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = NPCM_PECI_MAX_REG,
++ .fast_io = true,
++};
++
++static int npcm_peci_xfer(struct peci_adapter *adapter,
++ struct peci_xfer_msg *msg)
++{
++ struct npcm_peci *priv = peci_get_adapdata(adapter);
++
++ return npcm_peci_xfer_native(priv, msg);
++}
++
++static int npcm_peci_probe(struct platform_device *pdev)
++{
++ struct peci_adapter *adapter;
++ struct npcm_peci *priv;
++ struct resource *res;
++ void __iomem *base;
++ int ret;
++
++ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv));
++ if (!adapter)
++ return -ENOMEM;
++
++ priv = peci_get_adapdata(adapter);
++ priv->adapter = adapter;
++ priv->dev = &pdev->dev;
++ dev_set_drvdata(&pdev->dev, priv);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(base)) {
++ ret = PTR_ERR(base);
++ goto err_put_adapter_dev;
++ }
++
++ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
++ &npcm_peci_regmap_config);
++ if (IS_ERR(priv->regmap)) {
++ ret = PTR_ERR(priv->regmap);
++ goto err_put_adapter_dev;
++ }
++
++ priv->irq = platform_get_irq(pdev, 0);
++ if (!priv->irq) {
++ ret = -ENODEV;
++ goto err_put_adapter_dev;
++ }
++
++ ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler,
++ 0, "peci-npcm-irq", priv);
++ if (ret)
++ goto err_put_adapter_dev;
++
++ init_completion(&priv->xfer_complete);
++ spin_lock_init(&priv->lock);
++
++ priv->adapter->owner = THIS_MODULE;
++ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev));
++ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name));
++ priv->adapter->xfer = npcm_peci_xfer;
++
++ ret = npcm_peci_init_ctrl(priv);
++ if (ret)
++ goto err_put_adapter_dev;
++
++ ret = peci_add_adapter(priv->adapter);
++ if (ret)
++ goto err_put_adapter_dev;
++
++ dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz",
++ priv->adapter->nr, priv->host_bit_rate);
++
++ return 0;
++
++err_put_adapter_dev:
++ put_device(&adapter->dev);
++ return ret;
++}
++
++static int npcm_peci_remove(struct platform_device *pdev)
++{
++ struct npcm_peci *priv = dev_get_drvdata(&pdev->dev);
++
++ clk_disable_unprepare(priv->clk);
++ peci_del_adapter(priv->adapter);
++ of_node_put(priv->adapter->dev.of_node);
++
++ return 0;
++}
++
++static const struct of_device_id npcm_peci_of_table[] = {
++ { .compatible = "nuvoton,npcm750-peci", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, npcm_peci_of_table);
++
++static struct platform_driver npcm_peci_driver = {
++ .probe = npcm_peci_probe,
++ .remove = npcm_peci_remove,
++ .driver = {
++ .name = "peci-npcm",
++ .of_match_table = of_match_ptr(npcm_peci_of_table),
++ },
++};
++module_platform_driver(npcm_peci_driver);
++
++MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
++MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver");
++MODULE_LICENSE("GPL v2");
diff --git a/drivers/peci/peci-aspeed.c b/drivers/peci/peci-aspeed.c
deleted file mode 100644
index 51cb2563ceb6..000000000000
@@ -1940,7 +2398,7 @@ index 51cb2563ceb6..000000000000
-MODULE_DESCRIPTION("ASPEED PECI driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
-index 6f241469ec7e..e2ef013e5002 100644
+index 6f241469ec7e..d1f0df8b139a 100644
--- a/drivers/peci/peci-core.c
+++ b/drivers/peci/peci-core.c
@@ -1,38 +1,31 @@
@@ -2040,7 +2498,8 @@ index 6f241469ec7e..e2ef013e5002 100644
+ * This function must only be called from process context!
+ */
+struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len)
-+{
+ {
+- return crc8(peci_crc8_table, data, (size_t)len, 0);
+ struct peci_xfer_msg *msg;
+ u8 *tx_buf, *rx_buf;
+
@@ -2097,8 +2556,7 @@ index 6f241469ec7e..e2ef013e5002 100644
+
+/* Calculate an Assured Write Frame Check Sequence byte */
+static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs)
- {
-- return crc8(peci_crc8_table, data, (size_t)len, 0);
++{
+ u8 *tmp_buf;
+
+ /* Allocate a temporary buffer to use a contiguous byte array */
@@ -2127,8 +2585,7 @@ index 6f241469ec7e..e2ef013e5002 100644
+ ulong timeout = jiffies;
+ u8 aw_fcs;
+ int ret;
-
-- /**
++
+ /*
+ * In case if adapter uses DMA, check at here whether tx and rx buffers
+ * are DMA capable or not.
@@ -2144,12 +2601,13 @@ index 6f241469ec7e..e2ef013e5002 100644
+ return -EAGAIN;
+ }
+ }
-+
+
+- /**
+ /*
* For some commands, the PECI originator may need to retry a command if
* the processor PECI client responds with a 0x8x completion code. In
* each instance, the processor PECI client may have started the
-@@ -125,55 +223,56 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg,
+@@ -125,55 +223,51 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg,
*/
if (do_retry)
@@ -2162,11 +2620,10 @@ index 6f241469ec7e..e2ef013e5002 100644
+ ret = adapter->xfer(adapter, msg);
- if (!do_retry || rc)
-+ if (!do_retry || ret)
- break;
-
+- break;
+-
- if (msg->rx_buf[0] == DEV_PECI_CC_SUCCESS)
-+ if (msg->rx_buf[0] == PECI_DEV_CC_SUCCESS)
++ if (!do_retry || ret || !msg->rx_buf)
break;
/* Retry is needed when completion code is 0x8x */
@@ -2174,10 +2631,9 @@ index 6f241469ec7e..e2ef013e5002 100644
- DEV_PECI_CC_NEED_RETRY) {
- rc = -EIO;
+ if ((msg->rx_buf[0] & PECI_DEV_CC_RETRY_CHECK_MASK) !=
-+ PECI_DEV_CC_NEED_RETRY) {
-+ ret = -EIO;
++ PECI_DEV_CC_NEED_RETRY)
break;
- }
+- }
/* Set the retry bit to indicate a retry attempt */
- msg->tx_buf[1] |= DEV_PECI_RETRY_BIT;
@@ -2192,11 +2648,11 @@ index 6f241469ec7e..e2ef013e5002 100644
+ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs);
+ if (ret)
+ break;
-
-- /**
++
+ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs;
+ }
-+
+
+- /**
+ /*
* Retry for at least 250ms before returning an error.
* Retry interval guideline:
@@ -2230,7 +2686,7 @@ index 6f241469ec7e..e2ef013e5002 100644
}
static int peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg)
-@@ -190,34 +289,37 @@ static int peci_xfer_with_retries(struct peci_adapter *adapter,
+@@ -190,34 +284,37 @@ static int peci_xfer_with_retries(struct peci_adapter *adapter,
static int peci_scan_cmd_mask(struct peci_adapter *adapter)
{
@@ -2274,13 +2730,14 @@ index 6f241469ec7e..e2ef013e5002 100644
+ goto out;
}
- /**
+- /**
- * Setting up the supporting commands based on minor revision number.
++ /*
+ * Setting up the supporting commands based on revision number.
* See PECI Spec Table 3-1.
*/
revision = FIELD_GET(REVISION_NUM_MASK, dib);
-@@ -243,10 +345,14 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter)
+@@ -243,10 +340,14 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter)
adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB);
adapter->cmd_mask |= BIT(PECI_CMD_PING);
@@ -2297,7 +2754,7 @@ index 6f241469ec7e..e2ef013e5002 100644
{
if (!(adapter->cmd_mask & BIT(PECI_CMD_PING)) &&
peci_scan_cmd_mask(adapter) < 0) {
-@@ -262,70 +368,87 @@ static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd)
+@@ -262,70 +363,87 @@ static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd)
return 0;
}
@@ -2316,19 +2773,19 @@ index 6f241469ec7e..e2ef013e5002 100644
- struct peci_xfer_msg msg;
+ struct peci_xfer_msg *msg;
+ int ret;
++
++ msg = peci_get_xfer_msg(0, 0);
++ if (!msg)
++ return -ENOMEM;
++
++ msg->addr = umsg->addr;
- msg.addr = umsg->addr;
- msg.tx_len = 0;
- msg.rx_len = 0;
-+ msg = peci_get_xfer_msg(0, 0);
-+ if (!msg)
-+ return -ENOMEM;
++ ret = peci_xfer(adapter, msg);
- return peci_xfer(adapter, &msg);
-+ msg->addr = umsg->addr;
-+
-+ ret = peci_xfer(adapter, msg);
-+
+ peci_put_xfer_msg(msg);
+
+ return ret;
@@ -2419,7 +2876,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Per the PECI spec, the read length must be a byte, word, or dword */
if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) {
-@@ -334,29 +457,34 @@ static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
+@@ -334,29 +452,35 @@ static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
return -EINVAL;
}
@@ -2445,17 +2902,18 @@ index 6f241469ec7e..e2ef013e5002 100644
+ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */
+ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */
+ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */
-+
-+ ret = peci_xfer_with_retries(adapter, msg, false);
-+ if (!ret)
-+ memcpy(umsg->pkg_config, &msg->rx_buf[1], umsg->rx_len);
- rc = peci_xfer_with_retries(adapter, &msg, false);
- if (!rc)
- memcpy(umsg->pkg_config, &msg.rx_buf[1], umsg->rx_len);
-+ peci_put_xfer_msg(msg);
++ ret = peci_xfer_with_retries(adapter, msg, false);
++ if (!ret)
++ memcpy(umsg->pkg_config, &msg->rx_buf[1], umsg->rx_len);
- return rc;
++ umsg->cc = msg->rx_buf[0];
++ peci_put_xfer_msg(msg);
++
+ return ret;
}
@@ -2471,7 +2929,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Per the PECI spec, the write length must be a dword */
if (umsg->tx_len != 4) {
-@@ -365,86 +493,113 @@ static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
+@@ -365,86 +489,116 @@ static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
return -EINVAL;
}
@@ -2504,19 +2962,20 @@ index 6f241469ec7e..e2ef013e5002 100644
+ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs);
+ if (ret)
+ goto out;
-+
-+ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs;
- /* Add an Assure Write Frame Check Sequence byte */
- msg.tx_buf[5 + i] = 0x80 ^
- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len);
-+ ret = peci_xfer_with_retries(adapter, msg, true);
++ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs;
- rc = peci_xfer_with_retries(adapter, &msg, true);
-+out:
-+ peci_put_xfer_msg(msg);
++ ret = peci_xfer_with_retries(adapter, msg, true);
- return rc;
++out:
++ umsg->cc = msg->rx_buf[0];
++ peci_put_xfer_msg(msg);
++
+ return ret;
}
@@ -2559,17 +3018,18 @@ index 6f241469ec7e..e2ef013e5002 100644
+ if (!ret)
+ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t));
+
++ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
-+}
-+
-+static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg)
-+{
-+ return -ENOSYS; /* Not implemented yet */
}
-static int peci_ioctl_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg)
++{
++ return -ENOSYS; /* Not implemented yet */
++}
++
+static int peci_cmd_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg)
{
struct peci_rd_pci_cfg_msg *umsg = vmsg;
@@ -2614,6 +3074,7 @@ index 6f241469ec7e..e2ef013e5002 100644
- rc = peci_xfer_with_retries(adapter, &msg, false);
- if (!rc)
- memcpy(umsg->pci_config, &msg.rx_buf[1], 4);
++ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
- return rc;
@@ -2637,7 +3098,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Per the PECI spec, the read length must be a byte, word, or dword */
if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) {
-@@ -453,34 +608,41 @@ static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+@@ -453,34 +607,42 @@ static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
return -EINVAL;
}
@@ -2676,6 +3137,7 @@ index 6f241469ec7e..e2ef013e5002 100644
- rc = peci_xfer_with_retries(adapter, &msg, false);
- if (!rc)
- memcpy(umsg->pci_config, &msg.rx_buf[1], umsg->rx_len);
++ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
- return rc;
@@ -2695,7 +3157,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Per the PECI spec, the write length must be a byte, word, or dword */
if (umsg->tx_len != 1 && umsg->tx_len != 2 && umsg->tx_len != 4) {
-@@ -489,47 +651,56 @@ static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+@@ -489,47 +651,57 @@ static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
return -EINVAL;
}
@@ -2743,6 +3205,7 @@ index 6f241469ec7e..e2ef013e5002 100644
- rc = peci_xfer_with_retries(adapter, &msg, true);
+out:
++ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
- return rc;
@@ -2782,7 +3245,7 @@ index 6f241469ec7e..e2ef013e5002 100644
};
/**
-@@ -545,109 +716,28 @@ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = {
+@@ -545,109 +717,28 @@ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = {
*/
int peci_command(struct peci_adapter *adapter, enum peci_cmd cmd, void *vmsg)
{
@@ -2901,7 +3364,7 @@ index 6f241469ec7e..e2ef013e5002 100644
static int peci_detect(struct peci_adapter *adapter, u8 addr)
{
struct peci_ping_msg msg;
-@@ -666,9 +756,9 @@ peci_of_match_device(const struct of_device_id *matches,
+@@ -666,9 +757,9 @@ peci_of_match_device(const struct of_device_id *matches,
return NULL;
return of_match_device(matches, &client->dev);
@@ -2913,7 +3376,7 @@ index 6f241469ec7e..e2ef013e5002 100644
}
static const struct peci_device_id *
-@@ -737,6 +827,7 @@ static int peci_device_probe(struct device *dev)
+@@ -737,6 +828,7 @@ static int peci_device_probe(struct device *dev)
err_detach_pm_domain:
dev_pm_domain_detach(&client->dev, true);
@@ -2921,7 +3384,7 @@ index 6f241469ec7e..e2ef013e5002 100644
return status;
}
-@@ -775,13 +866,14 @@ static void peci_device_shutdown(struct device *dev)
+@@ -775,13 +867,14 @@ static void peci_device_shutdown(struct device *dev)
driver->shutdown(client);
}
@@ -2937,7 +3400,7 @@ index 6f241469ec7e..e2ef013e5002 100644
static int peci_check_addr_validity(u8 addr)
{
-@@ -814,18 +906,18 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p)
+@@ -814,18 +907,23 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p)
int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id)
{
struct peci_rd_pkg_cfg_msg msg;
@@ -2953,16 +3416,22 @@ index 6f241469ec7e..e2ef013e5002 100644
- rc = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg);
- if (!rc)
+- *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config);
+ ret = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg);
-+ if (!ret)
- *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config);
++ if (ret)
++ return ret;
++
++ if (msg.cc != PECI_DEV_CC_SUCCESS)
++ return -EAGAIN;
++
++ *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config);
- return rc;
-+ return ret;
++ return 0;
}
EXPORT_SYMBOL_GPL(peci_get_cpu_id);
-@@ -833,7 +925,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
+@@ -833,7 +931,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
struct peci_board_info const *info)
{
struct peci_client *client;
@@ -2971,7 +3440,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Increase reference count for the adapter assigned */
if (!peci_get_adapter(adapter->nr))
-@@ -847,46 +939,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
+@@ -847,46 +945,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
client->addr = info->addr;
strlcpy(client->name, info->type, sizeof(client->name));
@@ -3033,7 +3502,7 @@ index 6f241469ec7e..e2ef013e5002 100644
return NULL;
}
-@@ -895,8 +990,10 @@ static void peci_unregister_device(struct peci_client *client)
+@@ -895,8 +996,10 @@ static void peci_unregister_device(struct peci_client *client)
if (!client)
return;
@@ -3045,7 +3514,7 @@ index 6f241469ec7e..e2ef013e5002 100644
device_unregister(&client->dev);
}
-@@ -916,7 +1013,7 @@ static void peci_adapter_dev_release(struct device *dev)
+@@ -916,7 +1019,7 @@ static void peci_adapter_dev_release(struct device *dev)
dev_dbg(dev, "%s: %s\n", __func__, adapter->name);
mutex_destroy(&adapter->userspace_clients_lock);
@@ -3054,7 +3523,7 @@ index 6f241469ec7e..e2ef013e5002 100644
kfree(adapter);
}
-@@ -928,7 +1025,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+@@ -928,7 +1031,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
struct peci_board_info info = {};
struct peci_client *client;
char *blank, end;
@@ -3064,7 +3533,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Parse device type */
blank = strchr(buf, ' ');
-@@ -943,16 +1041,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+@@ -943,16 +1047,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
memcpy(info.type, buf, blank - buf);
/* Parse remaining parameters, reject extra parameters */
@@ -3085,7 +3554,7 @@ index 6f241469ec7e..e2ef013e5002 100644
client = peci_new_device(adapter, &info);
if (!client)
return -EINVAL;
-@@ -961,8 +1060,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+@@ -961,8 +1066,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
mutex_lock(&adapter->userspace_clients_lock);
list_add_tail(&client->detected, &adapter->userspace_clients);
mutex_unlock(&adapter->userspace_clients_lock);
@@ -3096,7 +3565,7 @@ index 6f241469ec7e..e2ef013e5002 100644
return count;
}
-@@ -975,9 +1074,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
+@@ -975,9 +1080,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
struct peci_adapter *adapter = to_peci_adapter(dev);
struct peci_client *client, *next;
struct peci_board_info info = {};
@@ -3108,7 +3577,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Parse device type */
blank = strchr(buf, ' ');
-@@ -992,41 +1091,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
+@@ -992,41 +1097,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
memcpy(info.type, buf, blank - buf);
/* Parse remaining parameters, reject extra parameters */
@@ -3162,7 +3631,7 @@ index 6f241469ec7e..e2ef013e5002 100644
}
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL,
peci_sysfs_delete_device);
-@@ -1039,10 +1138,11 @@ static struct attribute *peci_adapter_attrs[] = {
+@@ -1039,10 +1144,11 @@ static struct attribute *peci_adapter_attrs[] = {
};
ATTRIBUTE_GROUPS(peci_adapter);
@@ -3175,7 +3644,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/**
* peci_verify_adapter - return parameter as peci_adapter, or NULL
-@@ -1063,32 +1163,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter,
+@@ -1063,32 +1169,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter,
struct device_node *node)
{
struct peci_board_info info = {};
@@ -3220,7 +3689,7 @@ index 6f241469ec7e..e2ef013e5002 100644
}
static void peci_of_register_devices(struct peci_adapter *adapter)
-@@ -1119,7 +1213,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter)
+@@ -1119,7 +1219,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter)
of_node_put(bus);
}
@@ -3229,7 +3698,7 @@ index 6f241469ec7e..e2ef013e5002 100644
static void peci_of_register_devices(struct peci_adapter *adapter) { }
#endif /* CONFIG_OF */
-@@ -1163,9 +1257,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node)
+@@ -1163,9 +1263,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node)
return adapter;
}
@@ -3240,7 +3709,7 @@ index 6f241469ec7e..e2ef013e5002 100644
{
struct of_reconfig_data *rd = arg;
struct peci_adapter *adapter;
-@@ -1216,7 +1308,7 @@ static int peci_of_notify(struct notifier_block *nb,
+@@ -1216,7 +1314,7 @@ static int peci_of_notify(struct notifier_block *nb,
static struct notifier_block peci_of_notifier = {
.notifier_call = peci_of_notify,
};
@@ -3249,7 +3718,7 @@ index 6f241469ec7e..e2ef013e5002 100644
extern struct notifier_block peci_of_notifier;
#endif /* CONFIG_OF_DYNAMIC */
-@@ -1240,7 +1332,7 @@ extern struct notifier_block peci_of_notifier;
+@@ -1240,7 +1338,7 @@ extern struct notifier_block peci_of_notifier;
*
* Return: the peci_adapter structure on success, else NULL.
*/
@@ -3258,7 +3727,7 @@ index 6f241469ec7e..e2ef013e5002 100644
{
struct peci_adapter *adapter;
-@@ -1263,7 +1355,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter);
+@@ -1263,7 +1361,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter);
static int peci_register_adapter(struct peci_adapter *adapter)
{
@@ -3267,7 +3736,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Can't register until after driver model init */
if (WARN_ON(!is_registered))
-@@ -1275,27 +1367,17 @@ static int peci_register_adapter(struct peci_adapter *adapter)
+@@ -1275,27 +1373,17 @@ static int peci_register_adapter(struct peci_adapter *adapter)
if (WARN(!adapter->xfer, "peci adapter has no xfer function\n"))
goto err_free_idr;
@@ -3300,7 +3769,7 @@ index 6f241469ec7e..e2ef013e5002 100644
}
dev_dbg(&adapter->dev, "adapter [%s] registered\n", adapter->name);
-@@ -1309,13 +1391,11 @@ static int peci_register_adapter(struct peci_adapter *adapter)
+@@ -1309,13 +1397,11 @@ static int peci_register_adapter(struct peci_adapter *adapter)
return 0;
@@ -3315,7 +3784,7 @@ index 6f241469ec7e..e2ef013e5002 100644
}
static int peci_add_numbered_adapter(struct peci_adapter *adapter)
-@@ -1411,7 +1491,7 @@ void peci_del_adapter(struct peci_adapter *adapter)
+@@ -1411,7 +1497,7 @@ void peci_del_adapter(struct peci_adapter *adapter)
}
mutex_unlock(&adapter->userspace_clients_lock);
@@ -3324,7 +3793,7 @@ index 6f241469ec7e..e2ef013e5002 100644
* Detach any active clients. This can't fail, thus we do not
* check the returned value.
*/
-@@ -1420,13 +1500,8 @@ void peci_del_adapter(struct peci_adapter *adapter)
+@@ -1420,13 +1506,8 @@ void peci_del_adapter(struct peci_adapter *adapter)
/* device name is gone after device_unregister */
dev_dbg(&adapter->dev, "adapter [%s] unregistered\n", adapter->name);
@@ -3338,7 +3807,7 @@ index 6f241469ec7e..e2ef013e5002 100644
device_unregister(&adapter->dev);
/* free bus id */
-@@ -1436,6 +1511,18 @@ void peci_del_adapter(struct peci_adapter *adapter)
+@@ -1436,6 +1517,18 @@ void peci_del_adapter(struct peci_adapter *adapter)
}
EXPORT_SYMBOL_GPL(peci_del_adapter);
@@ -3357,7 +3826,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/**
* peci_register_driver - register a PECI driver
* @owner: owner module of the driver being registered
-@@ -1446,7 +1533,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter);
+@@ -1446,7 +1539,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter);
*/
int peci_register_driver(struct module *owner, struct peci_driver *driver)
{
@@ -3366,7 +3835,7 @@ index 6f241469ec7e..e2ef013e5002 100644
/* Can't register until after driver model init */
if (WARN_ON(!is_registered))
-@@ -1456,13 +1543,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver)
+@@ -1456,13 +1549,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver)
driver->driver.owner = owner;
driver->driver.bus = &peci_bus_type;
@@ -3384,7 +3853,7 @@ index 6f241469ec7e..e2ef013e5002 100644
pr_debug("driver [%s] registered\n", driver->driver.name);
-@@ -1492,13 +1579,6 @@ static int __init peci_init(void)
+@@ -1492,13 +1585,6 @@ static int __init peci_init(void)
return ret;
}
@@ -3398,7 +3867,7 @@ index 6f241469ec7e..e2ef013e5002 100644
crc8_populate_msb(peci_crc8_table, PECI_CRC8_POLYNOMIAL);
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
-@@ -1514,11 +1594,10 @@ static void __exit peci_exit(void)
+@@ -1514,11 +1600,10 @@ static void __exit peci_exit(void)
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
WARN_ON(of_reconfig_notifier_unregister(&peci_of_notifier));
@@ -3413,10 +3882,10 @@ index 6f241469ec7e..e2ef013e5002 100644
MODULE_AUTHOR("Jason M Biils <jason.m.bills@linux.intel.com>");
diff --git a/drivers/peci/peci-dev.c b/drivers/peci/peci-dev.c
new file mode 100644
-index 000000000000..5de0683206bc
+index 000000000000..ac9cba0fb429
--- /dev/null
+++ b/drivers/peci/peci-dev.c
-@@ -0,0 +1,340 @@
+@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 Intel Corporation
+
@@ -3517,9 +3986,9 @@ index 000000000000..5de0683206bc
+static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg)
+{
+ struct peci_dev *peci_dev = file->private_data;
-+ struct peci_xfer_msg __user *uxmsg;
++ void __user *umsg = (void __user *)arg;
+ struct peci_xfer_msg *xmsg = NULL;
-+ void __user *umsg;
++ struct peci_xfer_msg uxmsg;
+ enum peci_cmd cmd;
+ u8 *msg = NULL;
+ uint msg_len;
@@ -3535,30 +4004,35 @@ index 000000000000..5de0683206bc
+ break;
+ }
+
-+ uxmsg = (struct peci_xfer_msg __user *)arg;
-+ xmsg = peci_get_xfer_msg(uxmsg->tx_len, uxmsg->rx_len);
++ if (copy_from_user(&uxmsg, umsg, msg_len)) {
++ ret = -EFAULT;
++ break;
++ }
++
++ xmsg = peci_get_xfer_msg(uxmsg.tx_len, uxmsg.rx_len);
+ if (IS_ERR(xmsg)) {
+ ret = PTR_ERR(xmsg);
+ break;
+ }
+
-+ if (uxmsg->tx_len &&
-+ copy_from_user(uxmsg->tx_buf, xmsg->tx_buf,
-+ uxmsg->tx_len)) {
++ if (uxmsg.tx_len &&
++ copy_from_user(xmsg->tx_buf, uxmsg.tx_buf, uxmsg.tx_len)) {
+ ret = -EFAULT;
+ break;
+ }
+
++ xmsg->addr = uxmsg.addr;
++ xmsg->tx_len = uxmsg.tx_len;
++ xmsg->rx_len = uxmsg.rx_len;
++
+ ret = peci_command(peci_dev->adapter, cmd, xmsg);
-+ if (!ret && uxmsg->rx_len &&
-+ copy_to_user(xmsg->rx_buf, uxmsg->rx_buf,
-+ uxmsg->rx_len))
++ if (!ret && xmsg->rx_len &&
++ copy_to_user(uxmsg.rx_buf, xmsg->rx_buf, xmsg->rx_len))
+ ret = -EFAULT;
+
+ break;
+
+ default:
-+ umsg = (void __user *)arg;
+ msg = memdup_user(umsg, msg_len);
+ if (IS_ERR(msg)) {
+ ret = PTR_ERR(msg);
@@ -3566,7 +4040,8 @@ index 000000000000..5de0683206bc
+ }
+
+ ret = peci_command(peci_dev->adapter, cmd, msg);
-+ if (!ret && copy_to_user(umsg, msg, msg_len))
++ if ((!ret || ret == -ETIMEDOUT) &&
++ copy_to_user(umsg, msg, msg_len))
+ ret = -EFAULT;
+
+ break;
@@ -3757,8 +4232,424 @@ index 000000000000..5de0683206bc
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI /dev entries driver");
+MODULE_LICENSE("GPL v2");
+diff --git a/drivers/peci/peci-npcm.c b/drivers/peci/peci-npcm.c
+deleted file mode 100644
+index f632365b1416..000000000000
+--- a/drivers/peci/peci-npcm.c
++++ /dev/null
+@@ -1,410 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-// Copyright (c) 2019 Nuvoton Technology corporation.
+-
+-#include <linux/bitfield.h>
+-#include <linux/clk.h>
+-#include <linux/interrupt.h>
+-#include <linux/jiffies.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/peci.h>
+-#include <linux/platform_device.h>
+-#include <linux/regmap.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/reset.h>
+-
+-/* NPCM7xx GCR module */
+-#define NPCM7XX_INTCR3_OFFSET 0x9C
+-#define NPCM7XX_INTCR3_PECIVSEL BIT(19)
+-
+-/* NPCM PECI Registers */
+-#define NPCM_PECI_CTL_STS 0x00
+-#define NPCM_PECI_RD_LENGTH 0x04
+-#define NPCM_PECI_ADDR 0x08
+-#define NPCM_PECI_CMD 0x0C
+-#define NPCM_PECI_CTL2 0x10
+-#define NPCM_PECI_WR_LENGTH 0x1C
+-#define NPCM_PECI_PDDR 0x2C
+-#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4))
+-
+-#define NPCM_PECI_MAX_REG 0x200
+-
+-/* NPCM_PECI_CTL_STS - 0x00 : Control Register */
+-#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6)
+-#define NPCM_PECI_CTRL_ABRT_ERR BIT(4)
+-#define NPCM_PECI_CTRL_CRC_ERR BIT(3)
+-#define NPCM_PECI_CTRL_DONE BIT(1)
+-#define NPCM_PECI_CTRL_START_BUSY BIT(0)
+-
+-/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */
+-#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0)
+-
+-/* NPCM_PECI_CMD - 0x10 : Command Register */
+-#define NPCM_PECI_CTL2_MASK GENMASK(7, 6)
+-
+-/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */
+-#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0)
+-
+-/* NPCM_PECI_PDDR - 0x2C : Command Register */
+-#define NPCM_PECI_PDDR_MASK GENMASK(4, 0)
+-
+-#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \
+- NPCM_PECI_CTRL_CRC_ERR | \
+- NPCM_PECI_CTRL_DONE)
+-
+-#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000
+-#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000
+-#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000
+-#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000
+-#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31
+-#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7
+-#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15
+-#define NPCM_PECI_PULL_DOWN_DEFAULT 0
+-#define NPCM_PECI_PULL_DOWN_MAX 2
+-
+-struct npcm_peci {
+- u32 cmd_timeout_ms;
+- u32 host_bit_rate;
+- struct completion xfer_complete;
+- struct regmap *gcr_regmap;
+- struct peci_adapter *adapter;
+- struct regmap *regmap;
+- u32 status;
+- spinlock_t lock; /* to sync completion status handling */
+- struct device *dev;
+- struct clk *clk;
+- int irq;
+-};
+-
+-static int npcm_peci_xfer_native(struct npcm_peci *priv,
+- struct peci_xfer_msg *msg)
+-{
+- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms);
+- unsigned long flags;
+- unsigned int msg_rd;
+- u32 cmd_sts;
+- int i, rc;
+-
+- /* Check command sts and bus idle state */
+- rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts,
+- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY),
+- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC,
+- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC);
+- if (rc)
+- return rc; /* -ETIMEDOUT */
+-
+- spin_lock_irqsave(&priv->lock, flags);
+- reinit_completion(&priv->xfer_complete);
+-
+- regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr);
+- regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH,
+- NPCM_PECI_WR_LEN_MASK & msg->rx_len);
+- regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH,
+- NPCM_PECI_WR_LEN_MASK & msg->tx_len);
+-
+- if (msg->tx_len) {
+- regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]);
+-
+- for (i = 0; i < (msg->tx_len - 1); i++)
+- regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i),
+- msg->tx_buf[i + 1]);
+- }
+-
+- priv->status = 0;
+- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS,
+- NPCM_PECI_CTRL_START_BUSY,
+- NPCM_PECI_CTRL_START_BUSY);
+-
+- spin_unlock_irqrestore(&priv->lock, flags);
+-
+- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete,
+- timeout);
+-
+- spin_lock_irqsave(&priv->lock, flags);
+-
+- regmap_write(priv->regmap, NPCM_PECI_CMD, 0);
+-
+- if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) {
+- if (err < 0) { /* -ERESTARTSYS */
+- rc = (int)err;
+- goto err_irqrestore;
+- } else if (err == 0) {
+- dev_dbg(priv->dev, "Timeout waiting for a response!\n");
+- rc = -ETIMEDOUT;
+- goto err_irqrestore;
+- }
+-
+- dev_dbg(priv->dev, "No valid response!\n");
+- rc = -EIO;
+- goto err_irqrestore;
+- }
+-
+- for (i = 0; i < msg->rx_len; i++) {
+- regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd);
+- msg->rx_buf[i] = (u8)msg_rd;
+- }
+-
+-err_irqrestore:
+- spin_unlock_irqrestore(&priv->lock, flags);
+- return rc;
+-}
+-
+-static irqreturn_t npcm_peci_irq_handler(int irq, void *arg)
+-{
+- struct npcm_peci *priv = arg;
+- u32 status_ack = 0;
+- u32 status;
+-
+- spin_lock(&priv->lock);
+- regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status);
+- priv->status |= (status & NPCM_PECI_INT_MASK);
+-
+- if (status & NPCM_PECI_CTRL_CRC_ERR) {
+- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n");
+- status_ack |= NPCM_PECI_CTRL_CRC_ERR;
+- }
+-
+- if (status & NPCM_PECI_CTRL_ABRT_ERR) {
+- dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n");
+- status_ack |= NPCM_PECI_CTRL_ABRT_ERR;
+- }
+-
+- /*
+- * All commands should be ended up with a NPCM_PECI_CTRL_DONE
+- * bit set even in an error case.
+- */
+- if (status & NPCM_PECI_CTRL_DONE) {
+- dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n");
+- status_ack |= NPCM_PECI_CTRL_DONE;
+- complete(&priv->xfer_complete);
+- }
+-
+- regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS,
+- NPCM_PECI_INT_MASK, status_ack);
+-
+- spin_unlock(&priv->lock);
+- return IRQ_HANDLED;
+-}
+-
+-static int npcm_peci_init_ctrl(struct npcm_peci *priv)
+-{
+- u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0;
+- int ret;
+- bool volt;
+-
+- priv->clk = devm_clk_get(priv->dev, NULL);
+- if (IS_ERR(priv->clk)) {
+- dev_err(priv->dev, "Failed to get clk source.\n");
+- return PTR_ERR(priv->clk);
+- }
+-
+- ret = clk_prepare_enable(priv->clk);
+- if (ret) {
+- dev_err(priv->dev, "Failed to enable clock.\n");
+- return ret;
+- }
+-
+- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms",
+- &priv->cmd_timeout_ms);
+- if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX ||
+- priv->cmd_timeout_ms == 0) {
+- if (ret)
+- dev_warn(priv->dev,
+- "cmd-timeout-ms not found, use default : %u\n",
+- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT);
+- else
+- dev_warn(priv->dev,
+- "Invalid cmd-timeout-ms : %u. Use default : %u\n",
+- priv->cmd_timeout_ms,
+- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT);
+-
+- priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT;
+- }
+-
+- if (of_device_is_compatible(priv->dev->of_node,
+- "nuvoton,npcm750-peci")) {
+- priv->gcr_regmap = syscon_regmap_lookup_by_compatible
+- ("nuvoton,npcm750-gcr");
+- if (!IS_ERR(priv->gcr_regmap)) {
+- volt = of_property_read_bool(priv->dev->of_node,
+- "high-volt-range");
+- if (volt)
+- regmap_update_bits(priv->gcr_regmap,
+- NPCM7XX_INTCR3_OFFSET,
+- NPCM7XX_INTCR3_PECIVSEL,
+- NPCM7XX_INTCR3_PECIVSEL);
+- else
+- regmap_update_bits(priv->gcr_regmap,
+- NPCM7XX_INTCR3_OFFSET,
+- NPCM7XX_INTCR3_PECIVSEL, 0);
+- }
+- }
+-
+- ret = of_property_read_u32(priv->dev->of_node, "pull-down",
+- &pull_down);
+- if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) {
+- if (ret)
+- dev_warn(priv->dev,
+- "pull-down not found, use default : %u\n",
+- NPCM_PECI_PULL_DOWN_DEFAULT);
+- else
+- dev_warn(priv->dev,
+- "Invalid pull-down : %u. Use default : %u\n",
+- pull_down,
+- NPCM_PECI_PULL_DOWN_DEFAULT);
+- pull_down = NPCM_PECI_PULL_DOWN_DEFAULT;
+- }
+-
+- regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK,
+- pull_down << 6);
+-
+- ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate",
+- &host_neg_bit_rate);
+- if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX ||
+- host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) {
+- if (ret)
+- dev_warn(priv->dev,
+- "host-neg-bit-rate not found, use default : %u\n",
+- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT);
+- else
+- dev_warn(priv->dev,
+- "Invalid host-neg-bit-rate : %u. Use default : %u\n",
+- host_neg_bit_rate,
+- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT);
+- host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT;
+- }
+-
+- regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK,
+- host_neg_bit_rate);
+-
+- priv->host_bit_rate = clk_get_rate(priv->clk) /
+- (4 * (host_neg_bit_rate + 1));
+-
+- ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts,
+- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY),
+- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC,
+- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC);
+- if (ret)
+- return ret; /* -ETIMEDOUT */
+-
+- /* PECI interrupt enable */
+- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS,
+- NPCM_PECI_CTRL_DONE_INT_EN,
+- NPCM_PECI_CTRL_DONE_INT_EN);
+-
+- return 0;
+-}
+-
+-static const struct regmap_config npcm_peci_regmap_config = {
+- .reg_bits = 8,
+- .val_bits = 8,
+- .max_register = NPCM_PECI_MAX_REG,
+- .fast_io = true,
+-};
+-
+-static int npcm_peci_xfer(struct peci_adapter *adapter,
+- struct peci_xfer_msg *msg)
+-{
+- struct npcm_peci *priv = peci_get_adapdata(adapter);
+-
+- return npcm_peci_xfer_native(priv, msg);
+-}
+-
+-static int npcm_peci_probe(struct platform_device *pdev)
+-{
+- struct peci_adapter *adapter;
+- struct npcm_peci *priv;
+- struct resource *res;
+- void __iomem *base;
+- int ret;
+-
+- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv));
+- if (!adapter)
+- return -ENOMEM;
+-
+- priv = peci_get_adapdata(adapter);
+- priv->adapter = adapter;
+- priv->dev = &pdev->dev;
+- dev_set_drvdata(&pdev->dev, priv);
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- base = devm_ioremap_resource(&pdev->dev, res);
+- if (IS_ERR(base)) {
+- ret = PTR_ERR(base);
+- goto err_put_adapter_dev;
+- }
+-
+- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+- &npcm_peci_regmap_config);
+- if (IS_ERR(priv->regmap)) {
+- ret = PTR_ERR(priv->regmap);
+- goto err_put_adapter_dev;
+- }
+-
+- priv->irq = platform_get_irq(pdev, 0);
+- if (!priv->irq) {
+- ret = -ENODEV;
+- goto err_put_adapter_dev;
+- }
+-
+- ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler,
+- 0, "peci-npcm-irq", priv);
+- if (ret)
+- goto err_put_adapter_dev;
+-
+- init_completion(&priv->xfer_complete);
+- spin_lock_init(&priv->lock);
+-
+- priv->adapter->owner = THIS_MODULE;
+- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev));
+- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name));
+- priv->adapter->xfer = npcm_peci_xfer;
+-
+- ret = npcm_peci_init_ctrl(priv);
+- if (ret)
+- goto err_put_adapter_dev;
+-
+- ret = peci_add_adapter(priv->adapter);
+- if (ret)
+- goto err_put_adapter_dev;
+-
+- dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz",
+- priv->adapter->nr, priv->host_bit_rate);
+-
+- return 0;
+-
+-err_put_adapter_dev:
+- put_device(&adapter->dev);
+- return ret;
+-}
+-
+-static int npcm_peci_remove(struct platform_device *pdev)
+-{
+- struct npcm_peci *priv = dev_get_drvdata(&pdev->dev);
+-
+- clk_disable_unprepare(priv->clk);
+- peci_del_adapter(priv->adapter);
+- of_node_put(priv->adapter->dev.of_node);
+-
+- return 0;
+-}
+-
+-static const struct of_device_id npcm_peci_of_table[] = {
+- { .compatible = "nuvoton,npcm750-peci", },
+- { }
+-};
+-MODULE_DEVICE_TABLE(of, npcm_peci_of_table);
+-
+-static struct platform_driver npcm_peci_driver = {
+- .probe = npcm_peci_probe,
+- .remove = npcm_peci_remove,
+- .driver = {
+- .name = "peci-npcm",
+- .of_match_table = of_match_ptr(npcm_peci_of_table),
+- },
+-};
+-module_platform_driver(npcm_peci_driver);
+-
+-MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
+-MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver");
+-MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
-index 8f6d823a59cd..1f1b07a9aeab 100644
+index 8f6d823a59cd..7b62a02e46ee 100644
--- a/include/linux/mfd/intel-peci-client.h
+++ b/include/linux/mfd/intel-peci-client.h
@@ -1,5 +1,5 @@
@@ -3768,7 +4659,7 @@ index 8f6d823a59cd..1f1b07a9aeab 100644
#ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H
#define __LINUX_MFD_INTEL_PECI_CLIENT_H
-@@ -9,7 +9,7 @@
+@@ -9,14 +9,15 @@
#if IS_ENABLED(CONFIG_X86)
#include <asm/intel-family.h>
#else
@@ -3777,7 +4668,29 @@ index 8f6d823a59cd..1f1b07a9aeab 100644
* Architectures other than x86 cannot include the header file so define these
* at here. These are needed for detecting type of client x86 CPUs behind a PECI
* connection.
-@@ -58,7 +58,6 @@ struct cpu_gen_info {
+ */
+-#define INTEL_FAM6_HASWELL_X 0x3F
+-#define INTEL_FAM6_BROADWELL_X 0x4F
+-#define INTEL_FAM6_SKYLAKE_X 0x55
++#define INTEL_FAM6_HASWELL_X 0x3F
++#define INTEL_FAM6_BROADWELL_X 0x4F
++#define INTEL_FAM6_BROADWELL_XEON_D 0x56
++#define INTEL_FAM6_SKYLAKE_X 0x55
+ #endif
+
+ #define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */
+@@ -27,6 +28,10 @@
+ #define CHAN_RANK_MAX_ON_BDX 4 /* Max number of channel ranks on Broadwell */
+ #define DIMM_IDX_MAX_ON_BDX 3 /* Max DIMM index per channel on Broadwell */
+
++#define CORE_MAX_ON_XD 16 /* Max number of cores on Xeon D */
++#define CHAN_RANK_MAX_ON_XD 2 /* Max number of channel ranks on Xeon D */
++#define DIMM_IDX_MAX_ON_XD 2 /* Max DIMM index per channel on Xeon D */
++
+ #define CORE_MAX_ON_SKX 28 /* Max number of cores on Skylake */
+ #define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */
+ #define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */
+@@ -58,7 +63,6 @@ struct cpu_gen_info {
/**
* struct peci_client_manager - PECI client manager information
* @client; pointer to the PECI client
@@ -3785,7 +4698,7 @@ index 8f6d823a59cd..1f1b07a9aeab 100644
* @name: PECI client manager name
* @gen_info: CPU generation info of the detected CPU
*
-@@ -67,7 +66,6 @@ struct cpu_gen_info {
+@@ -67,7 +71,6 @@ struct cpu_gen_info {
*/
struct peci_client_manager {
struct peci_client *client;
@@ -3793,6 +4706,35 @@ index 8f6d823a59cd..1f1b07a9aeab 100644
char name[PECI_NAME_SIZE];
const struct cpu_gen_info *gen_info;
};
+@@ -93,18 +96,23 @@ peci_client_read_package_config(struct peci_client_manager *priv,
+ u8 index, u16 param, u8 *data)
+ {
+ struct peci_rd_pkg_cfg_msg msg;
+- int rc;
++ int ret;
+
+ msg.addr = priv->client->addr;
+ msg.index = index;
+ msg.param = param;
+ msg.rx_len = 4;
+
+- rc = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg);
+- if (!rc)
+- memcpy(data, msg.pkg_config, 4);
++ ret = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg);
++ if (ret)
++ return ret;
++
++ if (msg.cc != PECI_DEV_CC_SUCCESS)
++ return -EAGAIN;
++
++ memcpy(data, msg.pkg_config, 4);
+
+- return rc;
++ return 0;
+ }
+
+ #endif /* __LINUX_MFD_INTEL_PECI_CLIENT_H */
diff --git a/include/linux/peci.h b/include/linux/peci.h
index d0e47d45d1d0..6fc424dc2a73 100644
--- a/include/linux/peci.h
@@ -3890,7 +4832,7 @@ index d0e47d45d1d0..6fc424dc2a73 100644
int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id);
diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h
-index a6dae71cbff5..8467b2fbee1f 100644
+index a6dae71cbff5..253fb42e38b7 100644
--- a/include/uapi/linux/peci-ioctl.h
+++ b/include/uapi/linux/peci-ioctl.h
@@ -1,5 +1,5 @@
@@ -3900,7 +4842,7 @@ index a6dae71cbff5..8467b2fbee1f 100644
#ifndef __PECI_IOCTL_H
#define __PECI_IOCTL_H
-@@ -7,136 +7,34 @@
+@@ -7,136 +7,35 @@
#include <linux/ioctl.h>
#include <linux/types.h>
@@ -3981,13 +4923,13 @@ index a6dae71cbff5..8467b2fbee1f 100644
-#define MBX_INDEX_DIMM_AMBIENT 19
-#define MBX_INDEX_DIMM_TEMP 24
+/* The PECI client's default address of 0x30 */
-+#define PECI_BASE_ADDR 0x30
++#define PECI_BASE_ADDR 0x30
+
+/* Max number of CPU clients */
-+#define PECI_OFFSET_MAX 8
++#define PECI_OFFSET_MAX 8
+
+/* PECI read/write data buffer size max */
-+#define PECI_BUFFER_SIZE 255
++#define PECI_BUFFER_SIZE 255
/* Device Specific Completion Code (CC) Definition */
-#define DEV_PECI_CC_SUCCESS 0x40
@@ -3995,17 +4937,22 @@ index a6dae71cbff5..8467b2fbee1f 100644
-#define DEV_PECI_CC_OUT_OF_RESOURCE 0x81
-#define DEV_PECI_CC_UNAVAIL_RESOURCE 0x82
-#define DEV_PECI_CC_INVALID_REQ 0x90
-+#define PECI_DEV_CC_SUCCESS 0x40
-+#define PECI_DEV_CC_TIMEOUT 0x80
-+#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81
-+#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82
-+#define PECI_DEV_CC_INVALID_REQ 0x90
++#define PECI_DEV_CC_SUCCESS 0x40
++#define PECI_DEV_CC_NEED_RETRY 0x80
++#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81
++#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82
++#define PECI_DEV_CC_INVALID_REQ 0x90
++#define PECI_DEV_CC_MCA_ERROR 0x91
++#define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93
++#define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94
++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98
++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B
++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C
/* Completion Code mask to check retry needs */
-#define DEV_PECI_CC_RETRY_CHECK_MASK 0xf0
-#define DEV_PECI_CC_NEED_RETRY 0x80
-+#define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0
-+#define PECI_DEV_CC_NEED_RETRY 0x80
++#define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0
/* Skylake EDS says to retry for 250ms */
-#define DEV_PECI_RETRY_TIME_MS 250
@@ -4037,13 +4984,9 @@ index a6dae71cbff5..8467b2fbee1f 100644
-#define RDPCICFG_WRITE_LEN 6
-#define RDPCICFG_READ_LEN 5
-#define RDPCICFG_PECI_CMD 0x61
-+#define PECI_DEV_RETRY_TIME_MS 250
-+#define PECI_DEV_RETRY_INTERVAL_USEC 10000
-+#define PECI_DEV_RETRY_BIT 0x01
-
+-
-#define WRPCICFG_PECI_CMD 0x65
-+#define PECI_WRIAMSR_CMD 0xb5
-
+-
-#define RDPCICFGLOCAL_WRITE_LEN 5
-#define RDPCICFGLOCAL_READ_LEN_BASE 1
-#define RDPCICFGLOCAL_PECI_CMD 0xe1
@@ -4053,11 +4996,13 @@ index a6dae71cbff5..8467b2fbee1f 100644
-#define WRPCICFGLOCAL_PECI_CMD 0xe5
-
-#define PECI_BUFFER_SIZE 32
-+#define PECI_WRPCICFG_CMD 0x65
++#define PECI_DEV_RETRY_TIME_MS 250
++#define PECI_DEV_RETRY_INTERVAL_USEC 10000
++#define PECI_DEV_RETRY_BIT 0x01
/**
* enum peci_cmd - PECI client commands
-@@ -186,11 +84,12 @@ enum peci_cmd {
+@@ -186,11 +85,12 @@ enum peci_cmd {
* raw PECI transfer
*/
struct peci_xfer_msg {
@@ -4075,7 +5020,7 @@ index a6dae71cbff5..8467b2fbee1f 100644
} __attribute__((__packed__));
/**
-@@ -202,7 +101,8 @@ struct peci_xfer_msg {
+@@ -202,7 +102,8 @@ struct peci_xfer_msg {
* powered-off, etc.
*/
struct peci_ping_msg {
@@ -4085,7 +5030,7 @@ index a6dae71cbff5..8467b2fbee1f 100644
} __attribute__((__packed__));
/**
-@@ -216,8 +116,13 @@ struct peci_ping_msg {
+@@ -216,8 +117,13 @@ struct peci_ping_msg {
* command.
*/
struct peci_get_dib_msg {
@@ -4101,7 +5046,7 @@ index a6dae71cbff5..8467b2fbee1f 100644
} __attribute__((__packed__));
/**
-@@ -232,8 +137,14 @@ struct peci_get_dib_msg {
+@@ -232,8 +138,13 @@ struct peci_get_dib_msg {
* below the maximum processor junction temperature.
*/
struct peci_get_temp_msg {
@@ -4112,13 +5057,20 @@ index a6dae71cbff5..8467b2fbee1f 100644
+#define PECI_GET_TEMP_CMD 0x01
+
+ __u8 addr;
-+ __u8 padding0[3];
++ __u8 padding;
+ __s16 temp_raw;
-+ __u8 padding1[2];
} __attribute__((__packed__));
/**
-@@ -251,11 +162,72 @@ struct peci_get_temp_msg {
+@@ -242,6 +153,7 @@ struct peci_get_temp_msg {
+ * @index: encoding index for the requested service
+ * @param: specific data being requested
+ * @rx_len: number of data to be read in bytes
++ * @cc: completion code
+ * @pkg_config: package config data to be read
+ *
+ * The RdPkgConfig() command provides read access to the Package Configuration
+@@ -251,11 +163,73 @@ struct peci_get_temp_msg {
* DIMM temperatures and so on.
*/
struct peci_rd_pkg_cfg_msg {
@@ -4191,12 +5143,21 @@ index a6dae71cbff5..8467b2fbee1f 100644
+#define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */
+
+ __u8 rx_len;
-+ __u8 padding[3];
++ __u8 cc;
++ __u8 padding[2];
+ __u8 pkg_config[4];
} __attribute__((__packed__));
/**
-@@ -272,11 +244,19 @@ struct peci_rd_pkg_cfg_msg {
+@@ -264,6 +238,7 @@ struct peci_rd_pkg_cfg_msg {
+ * @index: encoding index for the requested service
+ * @param: specific data being requested
+ * @tx_len: number of data to be written in bytes
++ * @cc: completion code
+ * @value: package config data to be written
+ *
+ * The WrPkgConfig() command provides write access to the Package Configuration
+@@ -272,11 +247,20 @@ struct peci_rd_pkg_cfg_msg {
* may include power limiting, thermal averaging constant programming and so on.
*/
struct peci_wr_pkg_cfg_msg {
@@ -4216,12 +5177,20 @@ index a6dae71cbff5..8467b2fbee1f 100644
+
+ __u16 param;
+ __u8 tx_len;
-+ __u8 padding[3];
++ __u8 cc;
++ __u8 padding[2];
+ __u32 value;
} __attribute__((__packed__));
/**
-@@ -290,10 +270,34 @@ struct peci_wr_pkg_cfg_msg {
+@@ -284,16 +268,47 @@ struct peci_wr_pkg_cfg_msg {
+ * @addr: address of the client
+ * @thread_id: ID of the specific logical processor
+ * @address: address of MSR to read from
++ * @cc: completion code
+ * @value: data to be read
+ *
+ * The RdIAMSR() PECI command provides read access to Model Specific Registers
* (MSRs) defined in the processor's Intel Architecture (IA).
*/
struct peci_rd_ia_msr_msg {
@@ -4236,6 +5205,8 @@ index a6dae71cbff5..8467b2fbee1f 100644
+ __u8 addr;
+ __u8 thread_id;
+ __u16 address;
++ __u8 cc;
++ __u8 padding[3];
+ __u64 value;
+} __attribute__((__packed__));
+
@@ -4245,22 +5216,34 @@ index a6dae71cbff5..8467b2fbee1f 100644
+ * @thread_id: ID of the specific logical processor
+ * @address: address of MSR to write to
+ * @tx_len: number of data to be written in bytes
++ * @cc: completion code
+ * @value: data to be written
+ *
+ * The WrIAMSR() PECI command provides write access to Model Specific Registers
+ * (MSRs) defined in the processor's Intel Architecture (IA).
+ */
+struct peci_wr_ia_msr_msg {
++#define PECI_WRIAMSR_CMD 0xb5
++
+ __u8 addr;
+ __u8 thread_id;
+ __u16 address;
+ __u8 tx_len;
-+ __u8 padding[3];
++ __u8 cc;
++ __u8 padding[2];
+ __u64 value;
} __attribute__((__packed__));
/**
-@@ -310,12 +314,52 @@ struct peci_rd_ia_msr_msg {
+@@ -303,6 +318,7 @@ struct peci_rd_ia_msr_msg {
+ * @device: PCI device number
+ * @function: specific function to read from
+ * @reg: specific register to read from
++ * @cc: completion code
+ * @pci_config: config data to be read
+ *
+ * The RdPCIConfig() command provides sideband read access to the PCI
+@@ -310,12 +326,56 @@ struct peci_rd_ia_msr_msg {
* processor.
*/
struct peci_rd_pci_cfg_msg {
@@ -4289,7 +5272,8 @@ index a6dae71cbff5..8467b2fbee1f 100644
+ __u8 device;
+ __u8 function;
+ __u16 reg;
-+ __u8 padding[2];
++ __u8 cc;
++ __u8 padding[1];
+ __u8 pci_config[4];
+} __attribute__((__packed__));
+
@@ -4301,6 +5285,7 @@ index a6dae71cbff5..8467b2fbee1f 100644
+ * @function: specific function to write to
+ * @reg: specific register to write to
+ * @tx_len: number of data to be written in bytes
++ * @cc: completion code
+ * @pci_config: config data to be written
+ *
+ * The RdPCIConfig() command provides sideband write access to the PCI
@@ -4308,18 +5293,28 @@ index a6dae71cbff5..8467b2fbee1f 100644
+ * processor.
+ */
+struct peci_wr_pci_cfg_msg {
++#define PECI_WRPCICFG_CMD 0x65
++
+ __u8 addr;
+ __u8 bus;
+ __u8 device;
+ __u8 function;
+ __u16 reg;
+ __u8 tx_len;
-+ __u8 padding;
++ __u8 cc;
+ __u8 pci_config[4];
} __attribute__((__packed__));
/**
-@@ -333,13 +377,18 @@ struct peci_rd_pci_cfg_msg {
+@@ -326,6 +386,7 @@ struct peci_rd_pci_cfg_msg {
+ * @function: specific function to read from
+ * @reg: specific register to read from
+ * @rx_len: number of data to be read in bytes
++ * @cc: completion code
+ * @pci_config: config data to be read
+ *
+ * The RdPCIConfigLocal() command provides sideband read access to the PCI
+@@ -333,13 +394,18 @@ struct peci_rd_pci_cfg_msg {
* processor IIO and uncore registers within the PCI configuration space.
*/
struct peci_rd_pci_cfg_local_msg {
@@ -4340,12 +5335,20 @@ index a6dae71cbff5..8467b2fbee1f 100644
+ __u8 function;
+ __u16 reg;
+ __u8 rx_len;
-+ __u8 padding[3];
++ __u8 cc;
+ __u8 pci_config[4];
} __attribute__((__packed__));
/**
-@@ -357,13 +406,18 @@ struct peci_rd_pci_cfg_local_msg {
+@@ -350,6 +416,7 @@ struct peci_rd_pci_cfg_local_msg {
+ * @function: specific function to read from
+ * @reg: specific register to read from
+ * @tx_len: number of data to be written in bytes
++ * @cc: completion code
+ * @value: config data to be written
+ *
+ * The WrPCIConfigLocal() command provides sideband write access to the PCI
+@@ -357,13 +424,18 @@ struct peci_rd_pci_cfg_local_msg {
* access this space even before BIOS enumeration of the system buses.
*/
struct peci_wr_pci_cfg_local_msg {
@@ -4366,12 +5369,12 @@ index a6dae71cbff5..8467b2fbee1f 100644
+ __u8 function;
+ __u16 reg;
+ __u8 tx_len;
-+ __u8 padding[3];
++ __u8 cc;
+ __u32 value;
} __attribute__((__packed__));
#define PECI_IOC_BASE 0xb7
-@@ -389,9 +443,15 @@ struct peci_wr_pci_cfg_local_msg {
+@@ -389,9 +461,15 @@ struct peci_wr_pci_cfg_local_msg {
#define PECI_IOC_RD_IA_MSR \
_IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSR, struct peci_rd_ia_msr_msg)
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch
index e6dd44cd7..d1745ce5f 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch
@@ -104,17 +104,14 @@ diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 768278b059c3..de2d5c6d186c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
-@@ -56,6 +56,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/
+@@ -53,6 +53,7 @@ obj-$(CONFIG_GENWQE) += genwqe/
+ obj-$(CONFIG_ECHO) += echo/
+ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
+ obj-$(CONFIG_CXL_BASE) += cxl/
++obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o
-+obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
- obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
- obj-$(CONFIG_OCXL) += ocxl/
- obj-y += cardreader/
-diff --git a/drivers/misc/aspeed-lpc-sio.c b/drivers/misc/aspeed-lpc-sio.c
-new file mode 100644
-index 000000000000..c717a3182320
--- /dev/null
+++ b/drivers/misc/aspeed-lpc-sio.c
@@ -0,0 +1,450 @@
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch
index 216c750de..303bff0b1 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch
@@ -225,10 +225,10 @@ diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7b018962cad3..89b051f82391 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
-@@ -53,6 +53,7 @@ obj-$(CONFIG_GENWQE) += genwqe/
- obj-$(CONFIG_ECHO) += echo/
+@@ -54,6 +54,7 @@ obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
obj-$(CONFIG_CXL_BASE) += cxl/
+ obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
+obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi-slave.o
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
index 922a45787..1532a5642 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
@@ -1,19 +1,19 @@
-From 23a7407c3f1bab7c01b93eeced4e137601ac1c94 Mon Sep 17 00:00:00 2001
+From d1d221aedb9b366e3477f253386b1cf829c56193 Mon Sep 17 00:00:00 2001
From: "Jason M. Bills" <jason.m.bills@intel.com>
Date: Wed, 4 Apr 2018 13:52:39 -0700
Subject: [PATCH] Add support for new PECI commands
Signed-off-by: Jason M. Bills <jason.m.bills@intel.com>
---
- drivers/peci/peci-core.c | 223 ++++++++++++++++++++++++++++++++++++++++
- include/uapi/linux/peci-ioctl.h | 102 ++++++++++++++++++
- 2 files changed, 325 insertions(+)
+ drivers/peci/peci-core.c | 226 ++++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/peci-ioctl.h | 104 ++++++++++++++++++
+ 2 files changed, 330 insertions(+)
diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
-index 14048a13ef8a..2f7e795158ce 100644
+index e282f9ef383b..9af11accc1d4 100644
--- a/drivers/peci/peci-core.c
+++ b/drivers/peci/peci-core.c
-@@ -344,6 +344,9 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter)
+@@ -345,6 +345,9 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter)
adapter->cmd_mask |= BIT(PECI_CMD_GET_TEMP);
adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB);
adapter->cmd_mask |= BIT(PECI_CMD_PING);
@@ -23,7 +23,7 @@ index 14048a13ef8a..2f7e795158ce 100644
out:
peci_put_xfer_msg(msg);
-@@ -686,6 +689,223 @@ static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+@@ -693,6 +696,226 @@ static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
return ret;
}
@@ -157,6 +157,7 @@ index 14048a13ef8a..2f7e795158ce 100644
+ if (!ret)
+ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
+
++ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
@@ -197,6 +198,7 @@ index 14048a13ef8a..2f7e795158ce 100644
+ if (!ret)
+ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
+
++ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
@@ -239,6 +241,7 @@ index 14048a13ef8a..2f7e795158ce 100644
+ if (!ret)
+ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
+
++ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
@@ -247,7 +250,7 @@ index 14048a13ef8a..2f7e795158ce 100644
typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *);
static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = {
-@@ -701,6 +921,9 @@ static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = {
+@@ -708,6 +931,9 @@ static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = {
peci_cmd_wr_pci_cfg,
peci_cmd_rd_pci_cfg_local,
peci_cmd_wr_pci_cfg_local,
@@ -258,10 +261,10 @@ index 14048a13ef8a..2f7e795158ce 100644
/**
diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h
-index 8467b2fbee1f..090b02c4de49 100644
+index 4c28abe2c17a..e67b0735f606 100644
--- a/include/uapi/linux/peci-ioctl.h
+++ b/include/uapi/linux/peci-ioctl.h
-@@ -70,6 +70,9 @@ enum peci_cmd {
+@@ -72,6 +72,9 @@ enum peci_cmd {
PECI_CMD_WR_PCI_CFG,
PECI_CMD_RD_PCI_CFG_LOCAL,
PECI_CMD_WR_PCI_CFG_LOCAL,
@@ -271,7 +274,7 @@ index 8467b2fbee1f..090b02c4de49 100644
PECI_CMD_MAX
};
-@@ -420,6 +423,93 @@ struct peci_wr_pci_cfg_local_msg {
+@@ -439,6 +442,95 @@ struct peci_wr_pci_cfg_local_msg {
__u32 value;
} __attribute__((__packed__));
@@ -311,7 +314,8 @@ index 8467b2fbee1f..090b02c4de49 100644
+ } mmio;
+ } params;
+ __u8 rx_len;
-+ __u8 padding[3];
++ __u8 cc;
++ __u8 padding[2];
+ __u8 data[8];
+} __attribute__((__packed__));
+
@@ -333,8 +337,8 @@ index 8467b2fbee1f..090b02c4de49 100644
+#define PECI_CRASHDUMP_NUM_AGENTS 0x01
+#define PECI_CRASHDUMP_AGENT_DATA 0x02
+
++ __u8 cc;
+ __u8 param0;
-+ __u8 padding;
+ __u16 param1;
+ __u8 param2;
+ __u8 rx_len;
@@ -344,11 +348,11 @@ index 8467b2fbee1f..090b02c4de49 100644
+struct peci_crashdump_get_frame_msg {
+#define PECI_CRASHDUMP_DISC_WRITE_LEN 9
+#define PECI_CRASHDUMP_DISC_READ_LEN_BASE 1
-+#define PECI_CRASHDUMP_DISC_VERSION 1
++#define PECI_CRASHDUMP_DISC_VERSION 0
+#define PECI_CRASHDUMP_DISC_OPCODE 1
+#define PECI_CRASHDUMP_GET_FRAME_WRITE_LEN 10
+#define PECI_CRASHDUMP_GET_FRAME_READ_LEN_BASE 1
-+#define PECI_CRASHDUMP_GET_FRAME_VERSION 3
++#define PECI_CRASHDUMP_GET_FRAME_VERSION 0
+#define PECI_CRASHDUMP_GET_FRAME_OPCODE 3
+#define PECI_CRASHDUMP_CMD 0x71
+
@@ -358,14 +362,15 @@ index 8467b2fbee1f..090b02c4de49 100644
+ __u16 param1;
+ __u16 param2;
+ __u8 rx_len;
-+ __u8 padding1[3];
++ __u8 cc;
++ __u8 padding1[2];
+ __u8 data[16];
+} __attribute__((__packed__));
+
#define PECI_IOC_BASE 0xb7
#define PECI_IOC_XFER \
-@@ -460,4 +550,16 @@ struct peci_wr_pci_cfg_local_msg {
+@@ -479,4 +571,16 @@ struct peci_wr_pci_cfg_local_msg {
_IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG_LOCAL, \
struct peci_wr_pci_cfg_local_msg)
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch
index 89a667e95..56dca7345 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch
@@ -1,1059 +1,14 @@
-From 409ea2cede8588a59badd5dd7cf8721879d4c68a Mon Sep 17 00:00:00 2001
-From: "Hunt, Bryan" <bryan.hunt@intel.com>
-Date: Fri, 30 Mar 2018 10:48:01 -0700
-Subject: [PATCH] Add AST2500d JTAG driver
+From 43470f186979483ba6c1e6374c7ea3a129622862 Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Mon, 1 Mar 2019 11:46:09 -0700
+Subject: [PATCH] Update AST2500d JTAG driver. Step 1
-Adding aspeed jtag driver
+Update AST2500d JTAG driver. Remove Legacy driver but keep headers.
-Signed-off-by: Hunt, Bryan <bryan.hunt@intel.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
---
- arch/arm/boot/dts/aspeed-g5.dtsi | 9 +
- drivers/Kconfig | 1 +
- drivers/Makefile | 1 +
- drivers/jtag/Kconfig | 13 +
- drivers/jtag/Makefile | 1 +
- drivers/jtag/jtag_aspeed.c | 963 +++++++++++++++++++++++++++++++++++++++
- include/uapi/linux/jtag_drv.h | 73 +++
- 7 files changed, 1061 insertions(+)
- create mode 100644 drivers/jtag/Kconfig
- create mode 100644 drivers/jtag/Makefile
- create mode 100644 drivers/jtag/jtag_aspeed.c
create mode 100644 include/uapi/linux/jtag_drv.h
-diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
-index 01d27e845982..adde826ac1d9 100644
---- a/arch/arm/boot/dts/aspeed-g5.dtsi
-+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
-@@ -367,6 +367,15 @@
- pinctrl-0 = <&pinctrl_espi_default>;
- };
-
-+ jtag: jtag@1e6e4000 {
-+ compatible = "aspeed,ast2500-jtag";
-+ reg = <0x1e6e2004 0x4 0x1e6e4000 0x1c>;
-+ clocks = <&syscon ASPEED_CLK_APB>;
-+ resets = <&syscon ASPEED_RESET_JTAG_MASTER>;
-+ interrupts = <43>;
-+ status = "disabled";
-+ };
-+
- lpc: lpc@1e789000 {
- compatible = "aspeed,ast2500-lpc", "simple-mfd";
- reg = <0x1e789000 0x1000>;
-diff --git a/drivers/Kconfig b/drivers/Kconfig
-index bbb66439a307..a1579d66f47d 100644
---- a/drivers/Kconfig
-+++ b/drivers/Kconfig
-@@ -230,4 +230,5 @@ source "drivers/slimbus/Kconfig"
-
- source "drivers/peci/Kconfig"
-
-+source "drivers/jtag/Kconfig"
- endmenu
-diff --git a/drivers/Makefile b/drivers/Makefile
-index 9ec44c032a42..69b201766154 100644
---- a/drivers/Makefile
-+++ b/drivers/Makefile
-@@ -187,3 +187,4 @@ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/
- obj-$(CONFIG_SIOX) += siox/
- obj-$(CONFIG_GNSS) += gnss/
- obj-$(CONFIG_PECI) += peci/
-+obj-$(CONFIG_JTAG_ASPEED) += jtag/
-diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
-new file mode 100644
-index 000000000000..2e5d0a5bea90
---- /dev/null
-+++ b/drivers/jtag/Kconfig
-@@ -0,0 +1,13 @@
-+menuconfig JTAG_ASPEED
-+ tristate "ASPEED SoC JTAG controller support"
-+ depends on HAS_IOMEM
-+ depends on ARCH_ASPEED || COMPILE_TEST
-+ help
-+ This provides a support for ASPEED JTAG device, equipped on
-+ ASPEED SoC 24xx and 25xx families. Drivers allows programming
-+ of hardware devices, connected to SoC through the JTAG interface.
-+
-+ If you want this support, you should say Y here.
-+
-+ To compile this driver as a module, choose M here: the module will
-+ be called jtag_aspeed.
-diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile
-new file mode 100644
-index 000000000000..db9b660e9f90
---- /dev/null
-+++ b/drivers/jtag/Makefile
-@@ -0,0 +1 @@
-+obj-$(CONFIG_JTAG_ASPEED) += jtag_aspeed.o
-diff --git a/drivers/jtag/jtag_aspeed.c b/drivers/jtag/jtag_aspeed.c
-new file mode 100644
-index 000000000000..42e2a131873c
---- /dev/null
-+++ b/drivers/jtag/jtag_aspeed.c
-@@ -0,0 +1,963 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Copyright (C) 2012-2017 ASPEED Technology Inc.
-+// Copyright (c) 2018 Intel Corporation
-+
-+#include <linux/bitfield.h>
-+#include <linux/delay.h>
-+#include <linux/fs.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/jtag_drv.h>
-+#include <linux/miscdevice.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/uaccess.h>
-+
-+#define SCU_RESET_JTAG BIT(22)
-+
-+#define AST_JTAG_DATA 0x00
-+#define AST_JTAG_INST 0x04
-+#define AST_JTAG_CTRL 0x08
-+#define AST_JTAG_ISR 0x0C
-+#define AST_JTAG_SW 0x10
-+#define AST_JTAG_TCK 0x14
-+#define AST_JTAG_IDLE 0x18
-+
-+/* AST_JTAG_CTRL - 0x08 : Engine Control */
-+#define JTAG_ENG_EN BIT(31)
-+#define JTAG_ENG_OUT_EN BIT(30)
-+#define JTAG_ENGINE_EN (JTAG_ENG_EN | JTAG_ENG_OUT_EN)
-+#define JTAG_FORCE_TMS BIT(29)
-+
-+#define JTAG_IR_UPDATE BIT(26) /* AST2500 only */
-+#define JTAG_INST_LEN_MASK GENMASK(25, 20)
-+#define JTAG_LAST_INST BIT(17)
-+#define JTAG_INST_EN BIT(16)
-+#define JTAG_DATA_LEN_MASK GENMASK(9, 4)
-+
-+#define JTAG_DR_UPDATE BIT(10) /* AST2500 only */
-+#define JTAG_LAST_DATA BIT(1)
-+#define JTAG_DATA_EN BIT(0)
-+
-+/* AST_JTAG_ISR - 0x0C : Interrupt status and enable */
-+#define JTAG_INST_PAUSE BIT(19)
-+#define JTAG_INST_COMPLETE BIT(18)
-+#define JTAG_DATA_PAUSE BIT(17)
-+#define JTAG_DATA_COMPLETE BIT(16)
-+
-+#define JTAG_INST_PAUSE_EN BIT(3)
-+#define JTAG_INST_COMPLETE_EN BIT(2)
-+#define JTAG_DATA_PAUSE_EN BIT(1)
-+#define JTAG_DATA_COMPLETE_EN BIT(0)
-+
-+/* AST_JTAG_SW - 0x10 : Software Mode and Status */
-+#define JTAG_SW_MODE_EN BIT(19)
-+#define JTAG_SW_MODE_TCK BIT(18)
-+#define JTAG_SW_MODE_TMS BIT(17)
-+#define JTAG_SW_MODE_TDIO BIT(16)
-+
-+/* AST_JTAG_TCK - 0x14 : TCK Control */
-+#define JTAG_TCK_DIVISOR_MASK GENMASK(10, 0)
-+
-+/* #define USE_INTERRUPTS */
-+#define AST_JTAG_NAME "jtag"
-+
-+static DEFINE_SPINLOCK(jtag_state_lock);
-+
-+struct ast_jtag_info {
-+ void __iomem *reg_base;
-+ void __iomem *reg_base_scu;
-+ int irq;
-+ u32 flag;
-+ wait_queue_head_t jtag_wq;
-+ bool is_open;
-+ struct device *dev;
-+ struct miscdevice miscdev;
-+};
-+
-+/*
-+ * This structure represents a TMS cycle, as expressed in a set of bits and a
-+ * count of bits (note: there are no start->end state transitions that require
-+ * more than 1 byte of TMS cycles)
-+ */
-+struct tms_cycle {
-+ unsigned char tmsbits;
-+ unsigned char count;
-+};
-+
-+/*
-+ * These are the string representations of the TAP states corresponding to the
-+ * enums literals in JtagStateEncode
-+ */
-+static const char * const c_statestr[] = {"TLR", "RTI", "SelDR", "CapDR",
-+ "ShfDR", "Ex1DR", "PauDR", "Ex2DR",
-+ "UpdDR", "SelIR", "CapIR", "ShfIR",
-+ "Ex1IR", "PauIR", "Ex2IR", "UpdIR"};
-+
-+/*
-+ * This is the complete set TMS cycles for going from any TAP state to any
-+ * other TAP state, following a “shortest path” rule.
-+ */
-+static const struct tms_cycle _tms_cycle_lookup[][16] = {
-+/* TLR RTI SelDR CapDR SDR Ex1DR PDR Ex2DR UpdDR SelIR CapIR SIR Ex1IR PIR Ex2IR UpdIR*/
-+/* TLR */{ {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x02, 4}, {0x0a, 4}, {0x0a, 5}, {0x2a, 6}, {0x1a, 5}, {0x06, 3}, {0x06, 4}, {0x06, 5}, {0x16, 5}, {0x16, 6}, {0x56, 7}, {0x36, 6} },
-+/* RTI */{ {0x07, 3}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5} },
-+/* SelDR*/{ {0x03, 2}, {0x03, 3}, {0x00, 0}, {0x00, 1}, {0x00, 2}, {0x02, 2}, {0x02, 3}, {0x0a, 4}, {0x06, 3}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4} },
-+/* CapDR*/{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x00, 0}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
-+/* SDR */{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
-+/* Ex1DR*/{ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x02, 3}, {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x01, 1}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6} },
-+/* PDR */{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x01, 2}, {0x05, 3}, {0x00, 0}, {0x01, 1}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
-+/* Ex2DR*/{ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x00, 0}, {0x01, 1}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6} },
-+/* UpdDR*/{ {0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x00, 0}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5} },
-+/* SelIR*/{ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x05, 4}, {0x05, 5}, {0x15, 5}, {0x15, 6}, {0x55, 7}, {0x35, 6}, {0x00, 0}, {0x00, 1}, {0x00, 2}, {0x02, 2}, {0x02, 3}, {0x0a, 4}, {0x06, 3} },
-+/* CapIR*/{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x00, 0}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2} },
-+/* SIR */{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x0f, 5}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2} },
-+/* Ex1IR*/{ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, {0x07, 4}, {0x02, 3}, {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x01, 1} },
-+/* PIR */{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x0f, 5}, {0x01, 2}, {0x05, 3}, {0x00, 0}, {0x01, 1}, {0x03, 2} },
-+/* Ex2IR*/{ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, {0x07, 4}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x00, 0}, {0x01, 1} },
-+/* UpdIR*/{ {0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x00, 0} },
-+};
-+
-+static const char * const regnames[] = {
-+ [AST_JTAG_DATA] = "AST_JTAG_DATA",
-+ [AST_JTAG_INST] = "AST_JTAG_INST",
-+ [AST_JTAG_CTRL] = "AST_JTAG_CTRL",
-+ [AST_JTAG_ISR] = "AST_JTAG_ISR",
-+ [AST_JTAG_SW] = "AST_JTAG_SW",
-+ [AST_JTAG_TCK] = "AST_JTAG_TCK",
-+ [AST_JTAG_IDLE] = "AST_JTAG_IDLE",
-+};
-+
-+static inline u32 ast_jtag_read(struct ast_jtag_info *ast_jtag, u32 reg)
-+{
-+ u32 val = readl(ast_jtag->reg_base + reg);
-+
-+ dev_dbg(ast_jtag->dev, "read:%s val = 0x%08x\n", regnames[reg], val);
-+ return val;
-+}
-+
-+static inline void ast_jtag_write(struct ast_jtag_info *ast_jtag, u32 val,
-+ u32 reg)
-+{
-+ dev_dbg(ast_jtag->dev, "write:%s val = 0x%08x\n", regnames[reg], val);
-+ writel(val, ast_jtag->reg_base + reg);
-+}
-+
-+static void ast_jtag_set_tck(struct ast_jtag_info *ast_jtag,
-+ enum xfer_mode mode, uint tck)
-+{
-+ u32 read_value;
-+
-+ if (tck == 0)
-+ tck = 1;
-+ else if (tck > JTAG_TCK_DIVISOR_MASK)
-+ tck = JTAG_TCK_DIVISOR_MASK;
-+ read_value = ast_jtag_read(ast_jtag, AST_JTAG_TCK);
-+ ast_jtag_write(ast_jtag,
-+ ((read_value & ~JTAG_TCK_DIVISOR_MASK) | tck),
-+ AST_JTAG_TCK);
-+}
-+
-+static void ast_jtag_get_tck(struct ast_jtag_info *ast_jtag,
-+ enum xfer_mode mode, uint *tck)
-+{
-+ *tck = FIELD_GET(JTAG_TCK_DIVISOR_MASK,
-+ ast_jtag_read(ast_jtag, AST_JTAG_TCK));
-+}
-+
-+/*
-+ * Used only in SW mode to walk the JTAG state machine.
-+ */
-+static u8 tck_cycle(struct ast_jtag_info *ast_jtag, u8 TMS, u8 TDI,
-+ bool do_read)
-+{
-+ u8 result = 0;
-+ u32 regwriteval = JTAG_SW_MODE_EN | (TMS * JTAG_SW_MODE_TMS)
-+ | (TDI * JTAG_SW_MODE_TDIO);
-+
-+ /* TCK = 0 */
-+ ast_jtag_write(ast_jtag, regwriteval, AST_JTAG_SW);
-+
-+ ast_jtag_read(ast_jtag, AST_JTAG_SW);
-+
-+ /* TCK = 1 */
-+ ast_jtag_write(ast_jtag, JTAG_SW_MODE_TCK | regwriteval, AST_JTAG_SW);
-+
-+ if (do_read) {
-+ result = (ast_jtag_read(ast_jtag, AST_JTAG_SW)
-+ & JTAG_SW_MODE_TDIO) ? 1 : 0;
-+ }
-+ return result;
-+}
-+
-+#define WAIT_ITERATIONS 75
-+
-+static int ast_jtag_wait_instr_pause_complete(struct ast_jtag_info *ast_jtag)
-+{
-+ int res = 0;
-+#ifdef USE_INTERRUPTS
-+ res = wait_event_interruptible(ast_jtag->jtag_wq,
-+ (ast_jtag->flag == JTAG_INST_PAUSE));
-+ ast_jtag->flag = 0;
-+#else
-+ u32 status = 0;
-+ u32 iterations = 0;
-+
-+ while ((status & JTAG_INST_PAUSE) == 0) {
-+ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
-+ dev_dbg(ast_jtag->dev, "%s = 0x%08x\n", __func__, status);
-+ iterations++;
-+ if (iterations > WAIT_ITERATIONS) {
-+ dev_err(ast_jtag->dev,
-+ "ast_jtag driver timed out waiting for instruction pause complete\n");
-+ res = -EFAULT;
-+ break;
-+ }
-+ if ((status & JTAG_DATA_COMPLETE) == 0) {
-+ if (iterations % 25 == 0)
-+ usleep_range(1, 5);
-+ else
-+ udelay(1);
-+ }
-+ }
-+ ast_jtag_write(ast_jtag, JTAG_INST_PAUSE | (status & 0xf),
-+ AST_JTAG_ISR);
-+#endif
-+ return res;
-+}
-+
-+static int ast_jtag_wait_instr_complete(struct ast_jtag_info *ast_jtag)
-+{
-+ int res = 0;
-+#ifdef USE_INTERRUPTS
-+ res = wait_event_interruptible(ast_jtag->jtag_wq,
-+ (ast_jtag->flag == JTAG_INST_COMPLETE));
-+ ast_jtag->flag = 0;
-+#else
-+ u32 status = 0;
-+ u32 iterations = 0;
-+
-+ while ((status & JTAG_INST_COMPLETE) == 0) {
-+ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
-+ dev_dbg(ast_jtag->dev, "%s = 0x%08x\n", __func__, status);
-+ iterations++;
-+ if (iterations > WAIT_ITERATIONS) {
-+ dev_err(ast_jtag->dev,
-+ "ast_jtag driver timed out waiting for instruction complete\n");
-+ res = -EFAULT;
-+ break;
-+ }
-+ if ((status & JTAG_DATA_COMPLETE) == 0) {
-+ if (iterations % 25 == 0)
-+ usleep_range(1, 5);
-+ else
-+ udelay(1);
-+ }
-+ }
-+ ast_jtag_write(ast_jtag, JTAG_INST_COMPLETE | (status & 0xf),
-+ AST_JTAG_ISR);
-+#endif
-+ return res;
-+}
-+
-+static int ast_jtag_wait_data_pause_complete(struct ast_jtag_info *ast_jtag)
-+{
-+ int res = 0;
-+#ifdef USE_INTERRUPTS
-+ res = wait_event_interruptible(ast_jtag->jtag_wq,
-+ (ast_jtag->flag == JTAG_DATA_PAUSE));
-+ ast_jtag->flag = 0;
-+#else
-+ u32 status = 0;
-+ u32 iterations = 0;
-+
-+ while ((status & JTAG_DATA_PAUSE) == 0) {
-+ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
-+ dev_dbg(ast_jtag->dev, "%s = 0x%08x\n", __func__, status);
-+ iterations++;
-+ if (iterations > WAIT_ITERATIONS) {
-+ dev_err(ast_jtag->dev,
-+ "ast_jtag driver timed out waiting for data pause complete\n");
-+ res = -EFAULT;
-+ break;
-+ }
-+ if ((status & JTAG_DATA_COMPLETE) == 0) {
-+ if (iterations % 25 == 0)
-+ usleep_range(1, 5);
-+ else
-+ udelay(1);
-+ }
-+ }
-+ ast_jtag_write(ast_jtag, JTAG_DATA_PAUSE | (status & 0xf),
-+ AST_JTAG_ISR);
-+#endif
-+ return res;
-+}
-+
-+static int ast_jtag_wait_data_complete(struct ast_jtag_info *ast_jtag)
-+{
-+ int res = 0;
-+#ifdef USE_INTERRUPTS
-+ res = wait_event_interruptible(ast_jtag->jtag_wq,
-+ (ast_jtag->flag == JTAG_DATA_COMPLETE));
-+ ast_jtag->flag = 0;
-+#else
-+ u32 status = 0;
-+ u32 iterations = 0;
-+
-+ while ((status & JTAG_DATA_COMPLETE) == 0) {
-+ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
-+ dev_dbg(ast_jtag->dev, "%s = 0x%08x\n", __func__, status);
-+ iterations++;
-+ if (iterations > WAIT_ITERATIONS) {
-+ dev_err(ast_jtag->dev,
-+ "ast_jtag driver timed out waiting for data complete\n");
-+ res = -EFAULT;
-+ break;
-+ }
-+ if ((status & JTAG_DATA_COMPLETE) == 0) {
-+ if (iterations % 25 == 0)
-+ usleep_range(1, 5);
-+ else
-+ udelay(1);
-+ }
-+ }
-+ ast_jtag_write(ast_jtag,
-+ JTAG_DATA_COMPLETE | (status & 0xf),
-+ AST_JTAG_ISR);
-+#endif
-+ return res;
-+}
-+
-+static void ast_jtag_bitbang(struct ast_jtag_info *ast_jtag,
-+ struct tck_bitbang *bit_bang)
-+{
-+ bit_bang->tdo = tck_cycle(ast_jtag, bit_bang->tms, bit_bang->tdi, true);
-+}
-+
-+static void reset_tap(struct ast_jtag_info *ast_jtag, enum xfer_mode mode)
-+{
-+ unsigned char i;
-+
-+ if (mode == SW_MODE) {
-+ for (i = 0; i < 9; i++)
-+ tck_cycle(ast_jtag, 1, 0, false);
-+ } else {
-+ ast_jtag_write(ast_jtag, 0, AST_JTAG_SW);
-+ mdelay(1);
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_FORCE_TMS,
-+ AST_JTAG_CTRL);
-+ mdelay(1);
-+ ast_jtag_write(ast_jtag,
-+ JTAG_SW_MODE_EN | JTAG_SW_MODE_TDIO,
-+ AST_JTAG_SW);
-+ }
-+}
-+
-+static int ast_jtag_set_tapstate(struct ast_jtag_info *ast_jtag,
-+ enum xfer_mode mode, uint from, uint to)
-+{
-+ unsigned char num_cycles;
-+ unsigned char cycle;
-+ unsigned char tms_bits;
-+
-+ /*
-+ * Ensure that the requested and current tap states are within
-+ * 0 to 15.
-+ */
-+ if (from >= ARRAY_SIZE(_tms_cycle_lookup[0]) || /* Column */
-+ to >= ARRAY_SIZE(_tms_cycle_lookup)) { /* row */
-+ return -1;
-+ }
-+
-+ dev_dbg(ast_jtag->dev, "Set TAP state: %s\n", c_statestr[to]);
-+
-+ if (mode == SW_MODE) {
-+ ast_jtag_write(ast_jtag,
-+ JTAG_SW_MODE_EN | JTAG_SW_MODE_TDIO,
-+ AST_JTAG_SW);
-+
-+ if (to == jtag_tlr) {
-+ reset_tap(ast_jtag, mode);
-+ } else {
-+ tms_bits = _tms_cycle_lookup[from][to].tmsbits;
-+ num_cycles = _tms_cycle_lookup[from][to].count;
-+
-+ if (num_cycles == 0)
-+ return 0;
-+
-+ for (cycle = 0; cycle < num_cycles; cycle++) {
-+ tck_cycle(ast_jtag, (tms_bits & 1), 0, false);
-+ tms_bits >>= 1;
-+ }
-+ }
-+ } else if (to == jtag_tlr) {
-+ reset_tap(ast_jtag, mode);
-+ }
-+ return 0;
-+}
-+
-+static void software_readwrite_scan(struct ast_jtag_info *ast_jtag,
-+ struct scan_xfer *scan_xfer)
-+{
-+ uint bit_index = 0;
-+ bool is_IR = (scan_xfer->tap_state == jtag_shf_ir);
-+ uint exit_tap_state = is_IR ? jtag_ex1_ir : jtag_ex1_dr;
-+ unsigned char *tdi = scan_xfer->tdi;
-+ unsigned char *tdo = scan_xfer->tdo;
-+
-+ dev_dbg(ast_jtag->dev, "SW JTAG SHIFT %s, length = %d\n",
-+ is_IR ? "IR" : "DR", scan_xfer->length);
-+
-+ ast_jtag_write(ast_jtag,
-+ JTAG_SW_MODE_EN | JTAG_SW_MODE_TDIO,
-+ AST_JTAG_SW);
-+
-+ while (bit_index < scan_xfer->length) {
-+ int bit_offset = (bit_index % 8);
-+ int this_input_bit = 0;
-+ int tms_high_or_low;
-+ int this_output_bit;
-+
-+ if (bit_index / 8 < scan_xfer->tdi_bytes) {
-+ /*
-+ * If we are on a byte boundary, increment the byte
-+ * pointers. Don't increment on 0, pointer is already
-+ * on the first byte.
-+ */
-+ if (bit_index % 8 == 0 && bit_index != 0)
-+ tdi++;
-+ this_input_bit = (*tdi >> bit_offset) & 1;
-+ }
-+ /* If this is the last bit, leave TMS high */
-+ tms_high_or_low = (bit_index == scan_xfer->length - 1) &&
-+ (scan_xfer->end_tap_state != jtag_shf_dr) &&
-+ (scan_xfer->end_tap_state != jtag_shf_ir);
-+ this_output_bit = tck_cycle(ast_jtag, tms_high_or_low,
-+ this_input_bit, !!tdo);
-+ /*
-+ * If it was the last bit in the scan and the end_tap_state is
-+ * something other than shiftDR or shiftIR then go to Exit1.
-+ * IMPORTANT Note: if the end_tap_state is ShiftIR/DR and
-+ * the next call to this function is a shiftDR/IR then the
-+ * driver will not change state!
-+ */
-+ if (tms_high_or_low)
-+ scan_xfer->tap_state = exit_tap_state;
-+ if (tdo && bit_index / 8 < scan_xfer->tdo_bytes) {
-+ if (bit_index % 8 == 0) {
-+ if (bit_index != 0)
-+ tdo++;
-+ *tdo = 0;
-+ }
-+ *tdo |= this_output_bit << bit_offset;
-+ }
-+ bit_index++;
-+ }
-+ ast_jtag_set_tapstate(ast_jtag, scan_xfer->mode, scan_xfer->tap_state,
-+ scan_xfer->end_tap_state);
-+}
-+
-+static int fire_ir_command(struct ast_jtag_info *ast_jtag, bool last,
-+ u32 length)
-+{
-+ int res;
-+
-+ if (last) {
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_LAST_INST
-+ | FIELD_PREP(JTAG_INST_LEN_MASK, length),
-+ AST_JTAG_CTRL);
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_LAST_INST
-+ | FIELD_PREP(JTAG_INST_LEN_MASK, length)
-+ | JTAG_INST_EN,
-+ AST_JTAG_CTRL);
-+ res = ast_jtag_wait_instr_complete(ast_jtag);
-+ } else {
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_IR_UPDATE
-+ | FIELD_PREP(JTAG_INST_LEN_MASK, length),
-+ AST_JTAG_CTRL);
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_IR_UPDATE
-+ | FIELD_PREP(JTAG_INST_LEN_MASK, length)
-+ | JTAG_INST_EN,
-+ AST_JTAG_CTRL);
-+ res = ast_jtag_wait_instr_pause_complete(ast_jtag);
-+ }
-+ return res;
-+}
-+
-+static int fire_dr_command(struct ast_jtag_info *ast_jtag, bool last,
-+ u32 length)
-+{
-+ int res;
-+
-+ if (last) {
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_LAST_DATA
-+ | FIELD_PREP(JTAG_DATA_LEN_MASK, length),
-+ AST_JTAG_CTRL);
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_LAST_DATA
-+ | FIELD_PREP(JTAG_DATA_LEN_MASK, length)
-+ | JTAG_DATA_EN,
-+ AST_JTAG_CTRL);
-+ res = ast_jtag_wait_data_complete(ast_jtag);
-+ } else {
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_DR_UPDATE
-+ | FIELD_PREP(JTAG_DATA_LEN_MASK, length),
-+ AST_JTAG_CTRL);
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_DR_UPDATE
-+ | FIELD_PREP(JTAG_DATA_LEN_MASK, length)
-+ | JTAG_DATA_EN,
-+ AST_JTAG_CTRL);
-+ res = ast_jtag_wait_data_pause_complete(ast_jtag);
-+ }
-+ return res;
-+}
-+
-+static int hardware_readwrite_scan(struct ast_jtag_info *ast_jtag,
-+ struct scan_xfer *scan_xfer)
-+{
-+ int res = 0;
-+ u32 bits_received = 0;
-+ u32 bits_to_send = 0;
-+ u32 chunk_len = 0;
-+ bool is_IR = (scan_xfer->tap_state == jtag_shf_ir);
-+ bool is_last = false;
-+ u32 length = scan_xfer->length;
-+ u32 *tdi = (u32 *)scan_xfer->tdi;
-+ u32 *tdo = (u32 *)scan_xfer->tdo;
-+ u32 remaining_bytes;
-+ int scan_end = 0;
-+ u32 ast_reg = is_IR ? AST_JTAG_INST : AST_JTAG_DATA;
-+
-+ dev_dbg(ast_jtag->dev, "HW JTAG SHIFT %s, length = %d\n",
-+ is_IR ? "IR" : "DR", length);
-+
-+ ast_jtag_write(ast_jtag, 0, AST_JTAG_SW);
-+ if (scan_xfer->end_tap_state == jtag_pau_dr ||
-+ scan_xfer->end_tap_state == jtag_pau_ir ||
-+ scan_xfer->end_tap_state == jtag_shf_dr ||
-+ scan_xfer->end_tap_state == jtag_shf_ir) {
-+ scan_end = 0;
-+ } else {
-+ scan_end = 1;
-+ }
-+
-+ while (length > 0) {
-+ chunk_len = (length > 32) ? 32 : length;
-+
-+ if (length <= 32 && scan_end == 1)
-+ is_last = true;
-+
-+ dev_dbg(ast_jtag->dev, "HW SHIFT, length=%d, scan_end=%d, chunk_len=%d, is_last=%d\n",
-+ length, scan_end, chunk_len, is_last);
-+
-+ remaining_bytes = (scan_xfer->length - length) / 8;
-+ if (tdi && remaining_bytes < scan_xfer->tdi_bytes) {
-+ bits_to_send = *tdi++;
-+ ast_jtag_write(ast_jtag, bits_to_send, ast_reg);
-+ } else {
-+ bits_to_send = 0;
-+ ast_jtag_write(ast_jtag, 0, ast_reg);
-+ }
-+
-+ dev_dbg(ast_jtag->dev, "HW SHIFT, len=%d chunk_len=%d is_last=%x bits_to_send=%x\n",
-+ length, chunk_len, is_last, bits_to_send);
-+
-+ if (is_IR)
-+ res = fire_ir_command(ast_jtag, is_last, chunk_len);
-+ else
-+ res = fire_dr_command(ast_jtag, is_last, chunk_len);
-+ if (res != 0)
-+ break;
-+
-+ if (tdo) {
-+ bits_received = ast_jtag_read(ast_jtag, ast_reg);
-+ bits_received >>= (32 - chunk_len);
-+ *tdo++ = bits_received;
-+ }
-+ dev_dbg(ast_jtag->dev,
-+ "HW SHIFT, len=%d chunk_len=%d is_last=%x bits_received=%x\n",
-+ length, chunk_len, is_last,
-+ bits_received);
-+ length -= chunk_len;
-+ }
-+ return res;
-+}
-+
-+static int ast_jtag_readwrite_scan(struct ast_jtag_info *ast_jtag,
-+ struct scan_xfer *scan_xfer)
-+{
-+ int res = 0;
-+
-+ if (scan_xfer->tap_state != jtag_shf_dr &&
-+ scan_xfer->tap_state != jtag_shf_ir) {
-+ if (scan_xfer->tap_state < ARRAY_SIZE(c_statestr))
-+ dev_err(ast_jtag->dev,
-+ "readwrite_scan bad current tap state = %s\n",
-+ c_statestr[scan_xfer->tap_state]);
-+ else
-+ dev_err(ast_jtag->dev,
-+ "readwrite_scan bad current tap state = %u\n",
-+ scan_xfer->tap_state);
-+ return -EFAULT;
-+ }
-+
-+ if (scan_xfer->length == 0) {
-+ dev_err(ast_jtag->dev, "readwrite_scan bad length 0\n");
-+ return -EFAULT;
-+ }
-+
-+ if (!scan_xfer->tdi && scan_xfer->tdi_bytes != 0) {
-+ dev_err(ast_jtag->dev,
-+ "readwrite_scan null tdi with non-zero length %u!\n",
-+ scan_xfer->tdi_bytes);
-+ return -EFAULT;
-+ }
-+
-+ if (!scan_xfer->tdo && scan_xfer->tdo_bytes != 0) {
-+ dev_err(ast_jtag->dev,
-+ "readwrite_scan null tdo with non-zero length %u!\n",
-+ scan_xfer->tdo_bytes);
-+ return -EFAULT;
-+ }
-+
-+ if (!scan_xfer->tdi && !scan_xfer->tdo) {
-+ dev_err(ast_jtag->dev, "readwrite_scan null tdo and tdi!\n");
-+ return -EFAULT;
-+ }
-+
-+ if (scan_xfer->mode == SW_MODE)
-+ software_readwrite_scan(ast_jtag, scan_xfer);
-+ else
-+ res = hardware_readwrite_scan(ast_jtag, scan_xfer);
-+ return res;
-+}
-+
-+#ifdef USE_INTERRUPTS
-+static irqreturn_t ast_jtag_interrupt(int this_irq, void *dev_id)
-+{
-+ u32 status;
-+ struct ast_jtag_info *ast_jtag = dev_id;
-+
-+ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
-+
-+ if (status & JTAG_INST_PAUSE) {
-+ ast_jtag_write(ast_jtag,
-+ JTAG_INST_PAUSE | (status & 0xf),
-+ AST_JTAG_ISR);
-+ ast_jtag->flag = JTAG_INST_PAUSE;
-+ }
-+
-+ if (status & JTAG_INST_COMPLETE) {
-+ ast_jtag_write(ast_jtag,
-+ JTAG_INST_COMPLETE | (status & 0xf),
-+ AST_JTAG_ISR);
-+ ast_jtag->flag = JTAG_INST_COMPLETE;
-+ }
-+
-+ if (status & JTAG_DATA_PAUSE) {
-+ ast_jtag_write(ast_jtag,
-+ JTAG_DATA_PAUSE | (status & 0xf), AST_JTAG_ISR);
-+ ast_jtag->flag = JTAG_DATA_PAUSE;
-+ }
-+
-+ if (status & JTAG_DATA_COMPLETE) {
-+ ast_jtag_write(ast_jtag,
-+ JTAG_DATA_COMPLETE | (status & 0xf),
-+ AST_JTAG_ISR);
-+ ast_jtag->flag = JTAG_DATA_COMPLETE;
-+ }
-+
-+ if (ast_jtag->flag) {
-+ wake_up_interruptible(&ast_jtag->jtag_wq);
-+ return IRQ_HANDLED;
-+ } else {
-+ return IRQ_NONE;
-+ }
-+}
-+#endif
-+
-+static inline void ast_jtag_slave(struct ast_jtag_info *ast_jtag)
-+{
-+ u32 currReg = readl((void *)(ast_jtag->reg_base_scu));
-+
-+ writel(currReg | SCU_RESET_JTAG, (void *)ast_jtag->reg_base_scu);
-+}
-+
-+static inline void ast_jtag_master(struct ast_jtag_info *ast_jtag)
-+{
-+ u32 currReg = readl((void *)(ast_jtag->reg_base_scu));
-+
-+ writel(currReg & ~SCU_RESET_JTAG, (void *)ast_jtag->reg_base_scu);
-+ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN, AST_JTAG_CTRL);
-+ ast_jtag_write(ast_jtag, JTAG_SW_MODE_EN | JTAG_SW_MODE_TDIO,
-+ AST_JTAG_SW);
-+ ast_jtag_write(ast_jtag, JTAG_INST_PAUSE | JTAG_INST_COMPLETE |
-+ JTAG_DATA_PAUSE | JTAG_DATA_COMPLETE |
-+ JTAG_INST_PAUSE_EN | JTAG_INST_COMPLETE_EN |
-+ JTAG_DATA_PAUSE_EN | JTAG_DATA_COMPLETE_EN,
-+ AST_JTAG_ISR); /* Enable Interrupt */
-+}
-+
-+static long jtag_ioctl(struct file *file, uint cmd, ulong arg)
-+{
-+ int ret = 0;
-+ struct ast_jtag_info *ast_jtag = file->private_data;
-+ void __user *argp = (void __user *)arg;
-+ struct tck_bitbang bitbang;
-+ struct scan_xfer xfer;
-+ struct set_tck_param set_tck_param;
-+ struct get_tck_param get_tck_param;
-+ struct tap_state_param tap_state_param;
-+ unsigned char *kern_tdi = NULL;
-+ unsigned char *kern_tdo = NULL;
-+ unsigned char *user_tdi;
-+ unsigned char *user_tdo;
-+
-+ switch (cmd) {
-+ case AST_JTAG_SET_TCK:
-+ if (copy_from_user(&set_tck_param, argp,
-+ sizeof(struct set_tck_param))) {
-+ ret = -EFAULT;
-+ } else {
-+ ast_jtag_set_tck(ast_jtag,
-+ set_tck_param.mode,
-+ set_tck_param.tck);
-+ }
-+ break;
-+ case AST_JTAG_GET_TCK:
-+ if (copy_from_user(&get_tck_param, argp,
-+ sizeof(struct get_tck_param)))
-+ ret = -EFAULT;
-+ else
-+ ast_jtag_get_tck(ast_jtag,
-+ get_tck_param.mode,
-+ &get_tck_param.tck);
-+ if (copy_to_user(argp, &get_tck_param,
-+ sizeof(struct get_tck_param)))
-+ ret = -EFAULT;
-+ break;
-+ case AST_JTAG_BITBANG:
-+ if (copy_from_user(&bitbang, argp,
-+ sizeof(struct tck_bitbang))) {
-+ ret = -EFAULT;
-+ } else {
-+ if (bitbang.tms > 1 || bitbang.tdi > 1)
-+ ret = -EFAULT;
-+ else
-+ ast_jtag_bitbang(ast_jtag, &bitbang);
-+ }
-+ if (copy_to_user(argp, &bitbang, sizeof(struct tck_bitbang)))
-+ ret = -EFAULT;
-+ break;
-+ case AST_JTAG_SET_TAPSTATE:
-+ if (copy_from_user(&tap_state_param, argp,
-+ sizeof(struct tap_state_param)))
-+ ret = -EFAULT;
-+ else
-+ ast_jtag_set_tapstate(ast_jtag, tap_state_param.mode,
-+ tap_state_param.from_state,
-+ tap_state_param.to_state);
-+ break;
-+ case AST_JTAG_READWRITESCAN:
-+ if (copy_from_user(&xfer, argp,
-+ sizeof(struct scan_xfer))) {
-+ ret = -EFAULT;
-+ } else {
-+ if (xfer.tdi) {
-+ user_tdi = xfer.tdi;
-+ kern_tdi = memdup_user(user_tdi,
-+ xfer.tdi_bytes);
-+ if (IS_ERR(kern_tdi))
-+ ret = -EFAULT;
-+ else
-+ xfer.tdi = kern_tdi;
-+ }
-+
-+ if (ret == 0 && xfer.tdo) {
-+ user_tdo = xfer.tdo;
-+ kern_tdo = memdup_user(user_tdo,
-+ xfer.tdo_bytes);
-+ if (IS_ERR(kern_tdo))
-+ ret = -EFAULT;
-+ else
-+ xfer.tdo = kern_tdo;
-+ }
-+
-+ if (ret == 0)
-+ ret = ast_jtag_readwrite_scan(ast_jtag, &xfer);
-+
-+ kfree(kern_tdi);
-+ if (kern_tdo) {
-+ if (ret == 0) {
-+ if (copy_to_user(user_tdo,
-+ xfer.tdo,
-+ xfer.tdo_bytes))
-+ ret = -EFAULT;
-+ }
-+ kfree(kern_tdo);
-+ }
-+ }
-+ break;
-+ default:
-+ return -ENOTTY;
-+ }
-+
-+ return ret;
-+}
-+
-+static int jtag_open(struct inode *inode, struct file *file)
-+{
-+ struct ast_jtag_info *ast_jtag = container_of(file->private_data,
-+ struct ast_jtag_info,
-+ miscdev);
-+
-+ spin_lock(&jtag_state_lock);
-+ if (ast_jtag->is_open) {
-+ spin_unlock(&jtag_state_lock);
-+ return -EBUSY;
-+ }
-+
-+ ast_jtag->is_open = true;
-+ file->private_data = ast_jtag;
-+ ast_jtag_master(ast_jtag);
-+ spin_unlock(&jtag_state_lock);
-+
-+ return 0;
-+}
-+
-+static int jtag_release(struct inode *inode, struct file *file)
-+{
-+ struct ast_jtag_info *ast_jtag = file->private_data;
-+
-+ spin_lock(&jtag_state_lock);
-+ ast_jtag_slave(ast_jtag);
-+ ast_jtag->is_open = false;
-+
-+ spin_unlock(&jtag_state_lock);
-+
-+ return 0;
-+}
-+
-+static const struct file_operations ast_jtag_fops = {
-+ .owner = THIS_MODULE,
-+ .unlocked_ioctl = jtag_ioctl,
-+ .open = jtag_open,
-+ .release = jtag_release,
-+};
-+
-+static int ast_jtag_probe(struct platform_device *pdev)
-+{
-+ struct resource *scu_res;
-+ struct resource *jtag_res;
-+ int ret = 0;
-+ struct ast_jtag_info *ast_jtag;
-+
-+ dev_dbg(&pdev->dev, "%s started\n", __func__);
-+
-+ scu_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!scu_res) {
-+ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM for SCU\n");
-+ ret = -ENOENT;
-+ goto out;
-+ }
-+
-+ jtag_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ if (!jtag_res) {
-+ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM for JTAG\n");
-+ ret = -ENOENT;
-+ goto out;
-+ }
-+
-+ ast_jtag = devm_kzalloc(&pdev->dev, sizeof(*ast_jtag), GFP_KERNEL);
-+ if (!ast_jtag)
-+ return -ENOMEM;
-+
-+ ast_jtag->reg_base_scu = devm_ioremap_resource(&pdev->dev, scu_res);
-+ if (!ast_jtag->reg_base_scu) {
-+ ret = -EIO;
-+ goto out;
-+ }
-+
-+ ast_jtag->reg_base = devm_ioremap_resource(&pdev->dev, jtag_res);
-+ if (!ast_jtag->reg_base) {
-+ ret = -EIO;
-+ goto out;
-+ }
-+
-+ ast_jtag->dev = &pdev->dev;
-+
-+#ifdef USE_INTERRUPTS
-+ ast_jtag->irq = platform_get_irq(pdev, 0);
-+ if (ast_jtag->irq < 0) {
-+ dev_err(&pdev->dev, "no irq specified.\n");
-+ ret = -ENOENT;
-+ goto out;
-+ }
-+
-+ ret = devm_request_irq(&pdev->dev, ast_jtag->irq, ast_jtag_interrupt,
-+ IRQF_SHARED, "ast-jtag", ast_jtag);
-+ if (ret) {
-+ dev_err(ast_jtag->dev, "JTAG Unable to get IRQ.\n");
-+ goto out;
-+ }
-+#endif
-+
-+ ast_jtag->flag = 0;
-+ init_waitqueue_head(&ast_jtag->jtag_wq);
-+
-+ ast_jtag->miscdev.minor = MISC_DYNAMIC_MINOR,
-+ ast_jtag->miscdev.name = AST_JTAG_NAME,
-+ ast_jtag->miscdev.fops = &ast_jtag_fops,
-+ ast_jtag->miscdev.parent = &pdev->dev;
-+ ret = misc_register(&ast_jtag->miscdev);
-+ if (ret) {
-+ dev_err(ast_jtag->dev, "Unable to register misc device.\n");
-+ goto out;
-+ }
-+
-+ platform_set_drvdata(pdev, ast_jtag);
-+
-+ ast_jtag_slave(ast_jtag);
-+
-+ dev_dbg(&pdev->dev, "%s completed\n", __func__);
-+ return 0;
-+
-+out:
-+ dev_warn(&pdev->dev, "ast_jtag: driver init failed (ret=%d).\n", ret);
-+ return ret;
-+}
-+
-+static int ast_jtag_remove(struct platform_device *pdev)
-+{
-+ dev_dbg(&pdev->dev, "%s\n", __func__);
-+
-+ platform_set_drvdata(pdev, NULL);
-+
-+ dev_dbg(&pdev->dev, "JTAG driver removed successfully.\n");
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id ast_jtag_of_match[] = {
-+ { .compatible = "aspeed,ast2400-jtag", },
-+ { .compatible = "aspeed,ast2500-jtag", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, ast_jtag_of_match);
-+
-+static struct platform_driver ast_jtag_driver = {
-+ .probe = ast_jtag_probe,
-+ .remove = ast_jtag_remove,
-+ .driver = {
-+ .name = AST_JTAG_NAME,
-+ .of_match_table = of_match_ptr(ast_jtag_of_match),
-+ },
-+};
-+module_platform_driver(ast_jtag_driver);
-+
-+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
-+MODULE_AUTHOR("Bryan Hunt <bryan.hunt@intel.com>");
-+MODULE_DESCRIPTION("ASPEED JTAG driver");
-+MODULE_LICENSE("GPL v2");
diff --git a/include/uapi/linux/jtag_drv.h b/include/uapi/linux/jtag_drv.h
new file mode 100644
index 000000000000..4df638f8fa43
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch
deleted file mode 100644
index e2dee0d5b..000000000
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch
+++ /dev/null
@@ -1,291 +0,0 @@
-From a7ad8d09cdf0ec86612df0714d3e69ee92e6140b Mon Sep 17 00:00:00 2001
-From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
-Date: Tue, 20 Nov 2018 09:30:17 -0800
-Subject: [PATCH] i2c: aspeed: Improve driver to support multi-master use cases
- stably
-
-In multi-master environment, this driver's master cannot know
-exactly when peer master sends data to this driver's slave so
-cases can be happened that this master tries to send data through
-the master_xfer function but slave data from a peer master is still
-being processed or slave xfer is started by a peer very after it
-queues a master command.
-
-To prevent state corruption in these cases, this patch adds the
-'pending' state of master and its handling code so that the pending
-master xfer can be continued after slave mode session.
-
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
----
- drivers/i2c/busses/i2c-aspeed.c | 119 ++++++++++++++++++++++++++++++----------
- 1 file changed, 91 insertions(+), 28 deletions(-)
-
-diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
-index 8dc9161ced38..d11b2ea97259 100644
---- a/drivers/i2c/busses/i2c-aspeed.c
-+++ b/drivers/i2c/busses/i2c-aspeed.c
-@@ -117,6 +117,7 @@
-
- enum aspeed_i2c_master_state {
- ASPEED_I2C_MASTER_INACTIVE,
-+ ASPEED_I2C_MASTER_PENDING,
- ASPEED_I2C_MASTER_START,
- ASPEED_I2C_MASTER_TX_FIRST,
- ASPEED_I2C_MASTER_TX,
-@@ -126,12 +127,13 @@ enum aspeed_i2c_master_state {
- };
-
- enum aspeed_i2c_slave_state {
-- ASPEED_I2C_SLAVE_STOP,
-+ ASPEED_I2C_SLAVE_INACTIVE,
- ASPEED_I2C_SLAVE_START,
- ASPEED_I2C_SLAVE_READ_REQUESTED,
- ASPEED_I2C_SLAVE_READ_PROCESSED,
- ASPEED_I2C_SLAVE_WRITE_REQUESTED,
- ASPEED_I2C_SLAVE_WRITE_RECEIVED,
-+ ASPEED_I2C_SLAVE_STOP,
- };
-
- struct aspeed_i2c_bus {
-@@ -156,6 +158,8 @@ struct aspeed_i2c_bus {
- int cmd_err;
- /* Protected only by i2c_lock_bus */
- int master_xfer_result;
-+ /* Multi-master */
-+ bool multi_master;
- #if IS_ENABLED(CONFIG_I2C_SLAVE)
- struct i2c_client *slave;
- enum aspeed_i2c_slave_state slave_state;
-@@ -251,7 +255,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
- }
-
- /* Slave is not currently active, irq was for someone else. */
-- if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
-+ if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)
- return irq_handled;
-
- dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
-@@ -277,16 +281,15 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
- irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
- bus->slave_state = ASPEED_I2C_SLAVE_STOP;
- }
-- if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
-+ if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
-+ bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {
- irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
- bus->slave_state = ASPEED_I2C_SLAVE_STOP;
- }
-- if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
-- irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
-
- switch (bus->slave_state) {
- case ASPEED_I2C_SLAVE_READ_REQUESTED:
-- if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
-+ if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_ACK))
- dev_err(bus->dev, "Unexpected ACK on read request.\n");
- bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
- i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
-@@ -294,9 +297,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
- writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
- break;
- case ASPEED_I2C_SLAVE_READ_PROCESSED:
-- if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
-+ if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
- dev_err(bus->dev,
- "Expected ACK after processed read.\n");
-+ break;
-+ }
-+ irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
- i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
- writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
- writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
-@@ -310,10 +316,15 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
- break;
- case ASPEED_I2C_SLAVE_STOP:
- i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
-+ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
-+ break;
-+ case ASPEED_I2C_SLAVE_START:
-+ /* Slave was just started. Waiting for the next event. */;
- break;
- default:
-- dev_err(bus->dev, "unhandled slave_state: %d\n",
-+ dev_err(bus->dev, "unknown slave_state: %d\n",
- bus->slave_state);
-+ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
- break;
- }
-
-@@ -328,7 +339,17 @@ 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 idle state.
-+ */
-+ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
-+ bus->master_state = ASPEED_I2C_MASTER_PENDING;
-+ else
-+#endif /* CONFIG_I2C_SLAVE */
-+ bus->master_state = ASPEED_I2C_MASTER_START;
- bus->buf_index = 0;
-
- if (msg->flags & I2C_M_RD) {
-@@ -384,10 +405,6 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
- bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
- irq_handled |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
- goto out_complete;
-- } else {
-- /* Master is not currently active, irq was for someone else. */
-- if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
-- goto out_no_complete;
- }
-
- /*
-@@ -399,12 +416,33 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
- if (ret) {
- dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
- irq_status);
-- bus->cmd_err = ret;
-- bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
- irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
-- goto out_complete;
-+ if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
-+ bus->cmd_err = ret;
-+ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
-+ goto out_complete;
-+ }
- }
-
-+#if IS_ENABLED(CONFIG_I2C_SLAVE)
-+ /*
-+ * A pending master command will be started by H/W when the bus comes
-+ * back to idle state after completing a slave operation so change the
-+ * master state from 'pending' to 'start' at here if slave is inactive.
-+ */
-+ if (bus->master_state == ASPEED_I2C_MASTER_PENDING) {
-+ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
-+ goto out_no_complete;
-+
-+ bus->master_state = ASPEED_I2C_MASTER_START;
-+ }
-+#endif /* CONFIG_I2C_SLAVE */
-+
-+ /* Master is not currently active, irq was for someone else. */
-+ if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE ||
-+ bus->master_state == ASPEED_I2C_MASTER_PENDING)
-+ goto out_no_complete;
-+
- /* We are in an invalid state; reset bus to a known state. */
- if (!bus->msgs) {
- dev_err(bus->dev, "bus in unknown state. irq_status: 0x%x\n",
-@@ -423,6 +461,20 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
- * then update the state and handle the new state below.
- */
- if (bus->master_state == ASPEED_I2C_MASTER_START) {
-+#if IS_ENABLED(CONFIG_I2C_SLAVE)
-+ /*
-+ * If a peer master starts a xfer very after it queues a master
-+ * command, change its state to 'pending' then H/W will continue
-+ * the queued master xfer just after completing the slave mode
-+ * session.
-+ */
-+ if (unlikely(irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH)) {
-+ bus->master_state = ASPEED_I2C_MASTER_PENDING;
-+ dev_dbg(bus->dev,
-+ "master goes pending due to a slave start\n");
-+ goto out_no_complete;
-+ }
-+#endif /* CONFIG_I2C_SLAVE */
- if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
- if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_NAK))) {
- bus->cmd_err = -ENXIO;
-@@ -566,7 +618,8 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
- * interrupt bits. Each case needs to be handled using corresponding
- * handlers depending on the current state.
- */
-- if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
-+ if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE &&
-+ bus->master_state != ASPEED_I2C_MASTER_PENDING) {
- irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
- irq_remaining &= ~irq_handled;
- if (irq_remaining)
-@@ -601,15 +654,14 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
- {
- struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap);
- unsigned long time_left, flags;
-- int ret = 0;
-+ int ret;
-
- spin_lock_irqsave(&bus->lock, flags);
- bus->cmd_err = 0;
-
-- /* If bus is busy, attempt recovery. We assume a single master
-- * environment.
-- */
-- if (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS) {
-+ /* If bus is busy in a single master environment, attempt recovery. */
-+ if (!bus->multi_master &&
-+ (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS)) {
- spin_unlock_irqrestore(&bus->lock, flags);
- ret = aspeed_i2c_recover_bus(bus);
- if (ret)
-@@ -629,10 +681,20 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
- time_left = wait_for_completion_timeout(&bus->cmd_complete,
- bus->adap.timeout);
-
-- if (time_left == 0)
-+ if (time_left == 0) {
-+ /*
-+ * If timed out and bus is still busy in a multi master
-+ * environment, attempt recovery at here.
-+ */
-+ if (bus->multi_master &&
-+ (readl(bus->base + ASPEED_I2C_CMD_REG) &
-+ ASPEED_I2CD_BUS_BUSY_STS))
-+ ret = aspeed_i2c_recover_bus(bus);
-+
- return -ETIMEDOUT;
-- else
-- return bus->master_xfer_result;
-+ }
-+
-+ return bus->master_xfer_result;
- }
-
- static u32 aspeed_i2c_functionality(struct i2c_adapter *adap)
-@@ -672,7 +734,7 @@ static int aspeed_i2c_reg_slave(struct i2c_client *client)
- __aspeed_i2c_reg_slave(bus, client->addr);
-
- bus->slave = client;
-- bus->slave_state = ASPEED_I2C_SLAVE_STOP;
-+ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
- spin_unlock_irqrestore(&bus->lock, flags);
-
- return 0;
-@@ -827,7 +889,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
- if (ret < 0)
- return ret;
-
-- if (!of_property_read_bool(pdev->dev.of_node, "multi-master"))
-+ if (of_property_read_bool(pdev->dev.of_node, "multi-master"))
-+ bus->multi_master = true;
-+ else
- fun_ctrl_reg |= ASPEED_I2CD_MULTI_MASTER_DIS;
-
- /* Enable Master Mode */
-@@ -930,7 +994,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
- init_completion(&bus->cmd_complete);
- bus->adap.owner = THIS_MODULE;
- bus->adap.retries = 0;
-- bus->adap.timeout = 5 * HZ;
- bus->adap.algo = &aspeed_i2c_algo;
- bus->adap.dev.parent = &pdev->dev;
- bus->adap.dev.of_node = pdev->dev.of_node;
---
-2.7.4
-
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch
index b735ab38b..e984623ba 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch
@@ -1,4 +1,4 @@
-From 577b65960842f4098cdfc85a311261477c051d84 Mon Sep 17 00:00:00 2001
+From f4c13be7b95899d6eca3fa7ae38224bc9c7d7902 Mon Sep 17 00:00:00 2001
From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Date: Fri, 29 Jun 2018 11:00:02 -0700
Subject: [PATCH] Add dump debug code into I2C drivers
@@ -16,11 +16,11 @@ echo 1 > /sys/module/i2c_slave_mqueue/parameters/dump_debug
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
drivers/i2c/busses/i2c-aspeed.c | 25 +++++++++++++++++++++++++
- drivers/i2c/i2c-slave-mqueue.c | 24 ++++++++++++++++++++++++
- 2 files changed, 49 insertions(+)
+ drivers/i2c/i2c-slave-mqueue.c | 22 ++++++++++++++++++++++
+ 2 files changed, 47 insertions(+)
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
-index d11b2ea97259..506d867b43d9 100644
+index 6c8b38fd6e64..77dbd37b7b51 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -166,6 +166,19 @@ struct aspeed_i2c_bus {
@@ -44,14 +44,14 @@ index d11b2ea97259..506d867b43d9 100644
static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
@@ -655,6 +668,7 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
+ {
struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap);
unsigned long time_left, flags;
- int ret;
+ int i;
spin_lock_irqsave(&bus->lock, flags);
bus->cmd_err = 0;
-@@ -694,6 +708,11 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
+@@ -697,6 +711,11 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
return -ETIMEDOUT;
}
@@ -63,7 +63,7 @@ index d11b2ea97259..506d867b43d9 100644
return bus->master_xfer_result;
}
-@@ -1061,6 +1080,12 @@ static struct platform_driver aspeed_i2c_bus_driver = {
+@@ -1064,6 +1083,12 @@ static struct platform_driver aspeed_i2c_bus_driver = {
};
module_platform_driver(aspeed_i2c_bus_driver);
@@ -77,7 +77,7 @@ index d11b2ea97259..506d867b43d9 100644
MODULE_DESCRIPTION("Aspeed I2C Bus Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c
-index 6014bca0ff2a..0140c0dc4c03 100644
+index 6014bca0ff2a..4548088e1922 100644
--- a/drivers/i2c/i2c-slave-mqueue.c
+++ b/drivers/i2c/i2c-slave-mqueue.c
@@ -21,6 +21,7 @@ struct mq_msg {
@@ -88,7 +88,7 @@ index 6014bca0ff2a..0140c0dc4c03 100644
spinlock_t lock; /* spinlock for queue index handling */
int in;
-@@ -31,6 +32,19 @@ struct mq_queue {
+@@ -31,6 +32,18 @@ struct mq_queue {
struct mq_msg *queue;
};
@@ -99,8 +99,7 @@ index 6014bca0ff2a..0140c0dc4c03 100644
+ if (dump_debug && client->adapter->nr == dump_debug_bus_id) { \
+ char dump_info[100] = {0,}; \
+ snprintf(dump_info, sizeof(dump_info), \
-+ "%s (bus_id:%d, addr:0x%02x): ", \
-+ __func__, client->adapter->nr, client->addr); \
++ "%s (bus_id:%d): ", __func__, client->adapter->nr); \
+ print_hex_dump(KERN_ERR, dump_info, DUMP_PREFIX_NONE, 16, 1, \
+ buf, len, true); \
+ }
@@ -108,15 +107,7 @@ index 6014bca0ff2a..0140c0dc4c03 100644
static int i2c_slave_mqueue_callback(struct i2c_client *client,
enum i2c_slave_event event, u8 *val)
{
-@@ -49,6 +63,7 @@ static int i2c_slave_mqueue_callback(struct i2c_client *client,
- case I2C_SLAVE_WRITE_RECEIVED:
- if (msg->len < MQ_MSGBUF_SIZE) {
- msg->buf[msg->len++] = *val;
-+ I2C_HEX_DUMP(client, val, 1);
- } else {
- dev_err(&client->dev, "message is truncated!\n");
- mq->truncated = 1;
-@@ -101,6 +116,7 @@ static ssize_t i2c_slave_mqueue_bin_read(struct file *filp,
+@@ -101,6 +114,7 @@ static ssize_t i2c_slave_mqueue_bin_read(struct file *filp,
if (msg->len <= count) {
ret = msg->len;
memcpy(buf, msg->buf, ret);
@@ -124,7 +115,7 @@ index 6014bca0ff2a..0140c0dc4c03 100644
} else {
ret = -EOVERFLOW; /* Drop this HUGE one. */
}
-@@ -131,6 +147,8 @@ static int i2c_slave_mqueue_probe(struct i2c_client *client,
+@@ -131,6 +145,8 @@ static int i2c_slave_mqueue_probe(struct i2c_client *client,
BUILD_BUG_ON(!is_power_of_2(MQ_QUEUE_SIZE));
@@ -133,7 +124,7 @@ index 6014bca0ff2a..0140c0dc4c03 100644
buf = devm_kmalloc_array(dev, MQ_QUEUE_SIZE, MQ_MSGBUF_SIZE,
GFP_KERNEL);
if (!buf)
-@@ -212,6 +230,12 @@ static struct i2c_driver i2c_slave_mqueue_driver = {
+@@ -212,6 +228,12 @@ static struct i2c_driver i2c_slave_mqueue_driver = {
};
module_i2c_driver(i2c_slave_mqueue_driver);
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch
index 3863ea8f6..bb6465023 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch
@@ -69,14 +69,14 @@ diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 8f70b888a9ca..30ee065491ef 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
-@@ -59,6 +59,7 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
- obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
- obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o
- obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
+@@ -55,6 +55,7 @@ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpres
+ obj-$(CONFIG_CXL_BASE) += cxl/
+ obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
+ obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi-slave.o
+obj-$(CONFIG_ASPEED_VGA_SHAREDMEM) += aspeed-vga-sharedmem.o
- obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
- obj-$(CONFIG_OCXL) += ocxl/
- obj-y += cardreader/
+ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
+ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+ obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
diff --git a/drivers/misc/aspeed-vga-sharedmem.c b/drivers/misc/aspeed-vga-sharedmem.c
new file mode 100644
index 000000000000..76f60cd67d3a
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch
deleted file mode 100644
index 92d0a045d..000000000
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch
+++ /dev/null
@@ -1,174 +0,0 @@
-From 13d6fd0f71b3d0d69370878613bf7eb78fefa18f Mon Sep 17 00:00:00 2001
-From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
-Date: Fri, 9 Nov 2018 11:32:27 -0800
-Subject: [PATCH] Add Aspeed Video Engine Driver
-
-media: platform: Fix missing spin_lock_init()
-
-The driver allocates the spinlock but not initialize it.
-Use spin_lock_init() on it to initialize it correctly.
-
-This is detected by Coccinelle semantic patch.
-
-Fixes: d2b4387f3bdf ("media: platform: Add Aspeed Video Engine driver")
-
-Signed-off-by: Eddie James <eajames@linux.ibm.com>
-Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
-Reviewed-by: Rob Herring <robh@kernel.org>
-Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
----
- arch/arm/boot/dts/aspeed-g5.dtsi | 11 +++++++++
- drivers/clk/clk-aspeed.c | 41 ++++++++++++++++++++++++++++++--
- drivers/media/platform/aspeed-video.c | 1 +
- include/dt-bindings/clock/aspeed-clock.h | 1 +
- 4 files changed, 52 insertions(+), 2 deletions(-)
-
-diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
-index 6f26e0d323d6..d5783eaf30ae 100644
---- a/arch/arm/boot/dts/aspeed-g5.dtsi
-+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
-@@ -243,6 +243,17 @@
- interrupts = <0x19>;
- };
-
-+ video: video@1e700000 {
-+ compatible = "aspeed,ast2500-video-engine";
-+ reg = <0x1e700000 0x20000>;
-+ clocks = <&syscon ASPEED_CLK_GATE_VCLK>,
-+ <&syscon ASPEED_CLK_GATE_ECLK>;
-+ clock-names = "vclk", "eclk";
-+ resets = <&syscon ASPEED_RESET_VIDEO>;
-+ interrupts = <7>;
-+ status = "disabled";
-+ };
-+
- adc: adc@1e6e9000 {
- compatible = "aspeed,ast2500-adc";
- reg = <0x1e6e9000 0xb0>;
-diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
-index 3bbb4fbf00c9..6cea55de485f 100644
---- a/drivers/clk/clk-aspeed.c
-+++ b/drivers/clk/clk-aspeed.c
-@@ -95,7 +95,7 @@ struct aspeed_clk_gate {
- /* TODO: ask Aspeed about the actual parent data */
- static const struct aspeed_gate_data aspeed_gates[] = {
- /* clk rst name parent flags */
-- [ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */
-+ [ASPEED_CLK_GATE_ECLK] = { 0, 6, "eclk-gate", "eclk", 0 }, /* Video Engine */
- [ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */
- [ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */
- [ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */
-@@ -121,6 +121,24 @@ static const struct aspeed_gate_data aspeed_gates[] = {
- [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
- };
-
-+static const char * const eclk_parent_names[] = {
-+ "mpll",
-+ "hpll",
-+ "dpll",
-+};
-+
-+static const struct clk_div_table ast2500_eclk_div_table[] = {
-+ { 0x0, 2 },
-+ { 0x1, 2 },
-+ { 0x2, 3 },
-+ { 0x3, 4 },
-+ { 0x4, 5 },
-+ { 0x5, 6 },
-+ { 0x6, 7 },
-+ { 0x7, 8 },
-+ { 0 }
-+};
-+
- static const struct clk_div_table ast2500_mac_div_table[] = {
- { 0x0, 4 }, /* Yep, really. Aspeed confirmed this is correct */
- { 0x1, 4 },
-@@ -200,18 +218,21 @@ static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val)
-
- struct aspeed_clk_soc_data {
- const struct clk_div_table *div_table;
-+ const struct clk_div_table *eclk_div_table;
- const struct clk_div_table *mac_div_table;
- struct clk_hw *(*calc_pll)(const char *name, u32 val);
- };
-
- static const struct aspeed_clk_soc_data ast2500_data = {
- .div_table = ast2500_div_table,
-+ .eclk_div_table = ast2500_eclk_div_table,
- .mac_div_table = ast2500_mac_div_table,
- .calc_pll = aspeed_ast2500_calc_pll,
- };
-
- static const struct aspeed_clk_soc_data ast2400_data = {
- .div_table = ast2400_div_table,
-+ .eclk_div_table = ast2400_div_table,
- .mac_div_table = ast2400_div_table,
- .calc_pll = aspeed_ast2400_calc_pll,
- };
-@@ -325,6 +346,7 @@ static const u8 aspeed_resets[] = {
- [ASPEED_RESET_PECI] = 10,
- [ASPEED_RESET_I2C] = 2,
- [ASPEED_RESET_AHB] = 1,
-+ [ASPEED_RESET_VIDEO] = 6,
-
- /*
- * SCUD4 resets start at an offset to separate them from
-@@ -538,6 +560,22 @@ static int aspeed_clk_probe(struct platform_device *pdev)
- return PTR_ERR(hw);
- aspeed_clk_data->hws[ASPEED_CLK_24M] = hw;
-
-+ hw = clk_hw_register_mux(dev, "eclk-mux", eclk_parent_names,
-+ ARRAY_SIZE(eclk_parent_names), 0,
-+ scu_base + ASPEED_CLK_SELECTION, 2, 0x3, 0,
-+ &aspeed_clk_lock);
-+ if (IS_ERR(hw))
-+ return PTR_ERR(hw);
-+ aspeed_clk_data->hws[ASPEED_CLK_ECLK_MUX] = hw;
-+
-+ hw = clk_hw_register_divider_table(dev, "eclk", "eclk-mux", 0,
-+ scu_base + ASPEED_CLK_SELECTION, 28,
-+ 3, 0, soc_data->eclk_div_table,
-+ &aspeed_clk_lock);
-+ if (IS_ERR(hw))
-+ return PTR_ERR(hw);
-+ aspeed_clk_data->hws[ASPEED_CLK_ECLK] = hw;
-+
- /*
- * TODO: There are a number of clocks that not included in this driver
- * as more information is required:
-@@ -547,7 +585,6 @@ static int aspeed_clk_probe(struct platform_device *pdev)
- * RGMII
- * RMII
- * UART[1..5] clock source mux
-- * Video Engine (ECLK) mux and clock divider
- */
-
- /* Get the uart clock source configuration from SCU4C*/
-diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
-index dfec813f50a9..692e08ef38c0 100644
---- a/drivers/media/platform/aspeed-video.c
-+++ b/drivers/media/platform/aspeed-video.c
-@@ -1661,6 +1661,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
-
- video->frame_rate = 30;
- video->dev = &pdev->dev;
-+ spin_lock_init(&video->lock);
- mutex_init(&video->video_lock);
- init_waitqueue_head(&video->wait);
- INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work);
-diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h
-index 335879505a72..0b0f3a0ebe9b 100644
---- a/include/dt-bindings/clock/aspeed-clock.h
-+++ b/include/dt-bindings/clock/aspeed-clock.h
-@@ -52,5 +52,6 @@
- #define ASPEED_RESET_I2C 7
- #define ASPEED_RESET_AHB 8
- #define ASPEED_RESET_CRT1 9
-+#define ASPEED_RESET_VIDEO 10
-
- #endif
---
-2.7.4
-
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch
index 02ca65e9f..3e8f86666 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch
@@ -1,4 +1,4 @@
-From 95bae3d3051ee13627e5ef92bb9d60cfb5731118 Mon Sep 17 00:00:00 2001
+From ef2e1d9d2e8c97daf806f4da74738a84de054116 Mon Sep 17 00:00:00 2001
From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Date: Mon, 11 Feb 2019 17:02:35 -0800
Subject: [PATCH] Add Aspeed PWM driver which uses FTTMR010 timer IP
@@ -10,21 +10,18 @@ structure changes only for Aspeed SoCs.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
- arch/arm/boot/dts/aspeed-g5.dtsi | 2 +-
- drivers/clocksource/timer-fttmr010.c | 25 ++
- drivers/pwm/Kconfig | 9 +
- drivers/pwm/Makefile | 1 +
- drivers/pwm/pwm-fttmr010.c | 465 +++++++++++++++++++++++++++++++++++
- include/clocksource/timer-fttmr010.h | 17 ++
- 6 files changed, 514 insertions(+), 5 deletions(-)
+ arch/arm/boot/dts/aspeed-g5.dtsi | 2 +-
+ drivers/pwm/Kconfig | 9 +
+ drivers/pwm/Makefile | 1 +
+ drivers/pwm/pwm-fttmr010.c | 437 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 448 insertions(+), 1 deletion(-)
create mode 100644 drivers/pwm/pwm-fttmr010.c
- create mode 100644 include/clocksource/timer-fttmr010.h
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
-index d5783eaf30ae..992de63d7a19 100644
+index 8a7c4257b917..c24197232385 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
-@@ -301,7 +301,7 @@
+@@ -300,7 +300,7 @@
timer: timer@1e782000 {
/* This timer is a Faraday FTTMR010 derivative */
@@ -33,109 +30,6 @@ index d5783eaf30ae..992de63d7a19 100644
reg = <0x1e782000 0x90>;
interrupts = <16 17 18 35 36 37 38 39>;
clocks = <&syscon ASPEED_CLK_APB>;
-diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c
-index fadff7915dd9..49a790924360 100644
---- a/drivers/clocksource/timer-fttmr010.c
-+++ b/drivers/clocksource/timer-fttmr010.c
-@@ -20,6 +20,8 @@
- #include <linux/bitops.h>
- #include <linux/delay.h>
-
-+#include <clocksource/timer-fttmr010.h>
-+
- /*
- * Register definitions common for all the timer variants.
- */
-@@ -91,6 +93,9 @@
- #define TIMER_3_INT_OVERFLOW BIT(8)
- #define TIMER_INT_ALL_MASK 0x1ff
-
-+DEFINE_SPINLOCK(timer_fttmr010_lock);
-+EXPORT_SYMBOL(timer_fttmr010_lock);
-+
- struct fttmr010 {
- void __iomem *base;
- unsigned int tick_rate;
-@@ -137,8 +142,11 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
- struct clock_event_device *evt)
- {
- struct fttmr010 *fttmr010 = to_fttmr010(evt);
-+ unsigned long flags;
- u32 cr;
-
-+ spin_lock_irqsave(&timer_fttmr010_lock, flags);
-+
- /* Stop */
- cr = readl(fttmr010->base + TIMER_CR);
- cr &= ~fttmr010->t1_enable_val;
-@@ -161,27 +169,37 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
- cr |= fttmr010->t1_enable_val;
- writel(cr, fttmr010->base + TIMER_CR);
-
-+ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
-+
- return 0;
- }
-
- static int fttmr010_timer_shutdown(struct clock_event_device *evt)
- {
- struct fttmr010 *fttmr010 = to_fttmr010(evt);
-+ unsigned long flags;
- u32 cr;
-
-+ spin_lock_irqsave(&timer_fttmr010_lock, flags);
-+
- /* Stop */
- cr = readl(fttmr010->base + TIMER_CR);
- cr &= ~fttmr010->t1_enable_val;
- writel(cr, fttmr010->base + TIMER_CR);
-
-+ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
-+
- return 0;
- }
-
- static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
- {
- struct fttmr010 *fttmr010 = to_fttmr010(evt);
-+ unsigned long flags;
- u32 cr;
-
-+ spin_lock_irqsave(&timer_fttmr010_lock, flags);
-+
- /* Stop */
- cr = readl(fttmr010->base + TIMER_CR);
- cr &= ~fttmr010->t1_enable_val;
-@@ -201,6 +219,8 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
- writel(cr, fttmr010->base + TIMER_INTR_MASK);
- }
-
-+ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
-+
- return 0;
- }
-
-@@ -208,8 +228,11 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
- {
- struct fttmr010 *fttmr010 = to_fttmr010(evt);
- u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ);
-+ unsigned long flags;
- u32 cr;
-
-+ spin_lock_irqsave(&timer_fttmr010_lock, flags);
-+
- /* Stop */
- cr = readl(fttmr010->base + TIMER_CR);
- cr &= ~fttmr010->t1_enable_val;
-@@ -235,6 +258,8 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
- cr |= fttmr010->t1_enable_val;
- writel(cr, fttmr010->base + TIMER_CR);
-
-+ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
-+
- return 0;
- }
-
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index a8f47df0655a..92a8fbebe2d9 100644
--- a/drivers/pwm/Kconfig
@@ -170,10 +64,10 @@ index 9c676a0dadf5..13b7b20ad5ab 100644
obj-$(CONFIG_PWM_IMX) += pwm-imx.o
diff --git a/drivers/pwm/pwm-fttmr010.c b/drivers/pwm/pwm-fttmr010.c
new file mode 100644
-index 000000000000..459ace3eba6a
+index 000000000000..32e508c962dc
--- /dev/null
+++ b/drivers/pwm/pwm-fttmr010.c
-@@ -0,0 +1,465 @@
+@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Intel Corporation
+
@@ -185,9 +79,6 @@ index 000000000000..459ace3eba6a
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
-+/* For timer_fttmr010_lock */
-+#include <clocksource/timer-fttmr010.h>
-+
+#define TIMER_CR 0x30
+
+#define TIMER5_ASPEED_COUNT 0x50
@@ -265,21 +156,6 @@ index 000000000000..459ace3eba6a
+ u32 clk_tick_ns;
+};
+
-+#if !defined(CONFIG_FTTMR010_TIMER)
-+/*
-+ * Timer block is shared between timer-fttmr010 and pwm-fttmr010 drivers
-+ * and some registers need access synchronization. If both drivers are
-+ * compiled in, the spinlock is defined in the clocksource driver,
-+ * otherwise following definition is used.
-+ *
-+ * Currently we do not need any more complex synchronization method
-+ * because all the supported SoCs contain only one instance of the Timer
-+ * IP. Once this changes, both drivers will need to be modified to
-+ * properly synchronize accesses to particular instances.
-+ */
-+static DEFINE_SPINLOCK(timer_fttmr010_lock);
-+#endif
-+
+static inline
+struct pwm_fttmr010 *to_pwm_fttmr010(struct pwm_chip *chip)
+{
@@ -319,8 +195,6 @@ index 000000000000..459ace3eba6a
+ ulong flags;
+ u32 cr;
+
-+ spin_lock_irqsave(&timer_fttmr010_lock, flags);
-+
+ cr = readl(priv->base + TIMER_CR);
+
+ switch (pwm->hwpwm) {
@@ -339,9 +213,6 @@ index 000000000000..459ace3eba6a
+ }
+
+ writel(cr, priv->base + TIMER_CR);
-+
-+ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
-+
+ priv->disabled_mask &= ~BIT(pwm->hwpwm);
+
+ return 0;
@@ -353,8 +224,6 @@ index 000000000000..459ace3eba6a
+ ulong flags;
+ u32 cr;
+
-+ spin_lock_irqsave(&timer_fttmr010_lock, flags);
-+
+ cr = readl(priv->base + TIMER_CR);
+
+ switch (pwm->hwpwm) {
@@ -373,9 +242,6 @@ index 000000000000..459ace3eba6a
+ }
+
+ writel(cr, priv->base + TIMER_CR);
-+
-+ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
-+
+ priv->disabled_mask |= BIT(pwm->hwpwm);
+}
+
@@ -639,29 +505,6 @@ index 000000000000..459ace3eba6a
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("FTTMR010 PWM Driver for timer pulse outputs");
+MODULE_LICENSE("GPL v2");
-diff --git a/include/clocksource/timer-fttmr010.h b/include/clocksource/timer-fttmr010.h
-new file mode 100644
-index 000000000000..d8d6a2f14130
---- /dev/null
-+++ b/include/clocksource/timer-fttmr010.h
-@@ -0,0 +1,17 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+#ifndef __CLOCKSOURCE_TIMER_FTTMR010_H
-+#define __CLOCKSOURCE_TIMER_FTTMR010_H
-+
-+#include <linux/spinlock.h>
-+
-+/*
-+ * Following declaration must be in an ifdef due to this symbol being static
-+ * in timer-fttmr010 driver if the clocksource driver is not compiled in and the
-+ * spinlock is not shared between both drivers.
-+ */
-+#ifdef CONFIG_FTTMR010_TIMER
-+extern spinlock_t timer_fttmr010_lock;
-+#endif
-+
-+#endif /* __CLOCKSOURCE_TIMER_FTTMR010_H */
--
2.7.4
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch
index 9aee6f0c0..7a4b090ec 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch
@@ -198,10 +198,10 @@ index d1adfdf50fb3..4f9fdd25c6d7 100644
+ val = !!val;
+ if (test_bit(FLAG_PASS_THROUGH, &desc->flags)) {
+ if (val)
-+ gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
++ gpio_set_config(gc, gpio_chip_hwgpio(desc),
+ PIN_CONFIG_PASS_THROUGH_ENABLE);
+ else
-+ gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
++ gpio_set_config(gc, gpio_chip_hwgpio(desc),
+ PIN_CONFIG_PASS_THROUGH_DISABLE);
+ } else {
+ gpiod_err(desc,
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0050-media-platform-Fix-a-kernel-warning-on-clk-control.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0050-media-platform-Fix-a-kernel-warning-on-clk-control.patch
deleted file mode 100644
index a0168c889..000000000
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0050-media-platform-Fix-a-kernel-warning-on-clk-control.patch
+++ /dev/null
@@ -1,177 +0,0 @@
-From 1775e41d085b24a672dc271d08bfc83401288f0b Mon Sep 17 00:00:00 2001
-From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
-Date: Fri, 22 Mar 2019 16:34:54 -0700
-Subject: [PATCH] media: platform: Fix a kernel warning on clk control
-
-Video engine clock control functions in the Aspeed video engine driver are
-being called from multiple context without any protection so video clocks
-can be disabled twice and eventually it causes a kernel warning with stack
-dump printing out like below:
-
-[ 120.034729] WARNING: CPU: 0 PID: 1334 at drivers/clk/clk.c:684 clk_core_unprepare+0x13c/0x170
-[ 120.043252] eclk-gate already unprepared
-[ 120.047283] CPU: 0 PID: 1334 Comm: obmc-ikvm Tainted: G W 5.0.3-b94b74e8b52db91fe4e99e0bb481ec8bf2b5b47c #1
-[ 120.058417] Hardware name: Generic DT based system
-[ 120.063219] Backtrace:
-[ 120.065787] [<80107cdc>] (dump_backtrace) from [<80107f10>] (show_stack+0x20/0x24)
-[ 120.073371] r7:803a4ff0 r6:00000009 r5:00000000 r4:96197e1c
-[ 120.079152] [<80107ef0>] (show_stack) from [<8068f7d8>] (dump_stack+0x20/0x28)
-[ 120.086479] [<8068f7b8>] (dump_stack) from [<8011604c>] (__warn.part.3+0xb4/0xdc)
-[ 120.094068] [<80115f98>] (__warn.part.3) from [<801160e0>] (warn_slowpath_fmt+0x6c/0x90)
-[ 120.102164] r6:000002ac r5:8080c0b8 r4:80a07008
-[ 120.106893] [<80116078>] (warn_slowpath_fmt) from [<803a4ff0>] (clk_core_unprepare+0x13c/0x170)
-[ 120.115686] r3:8080cf8c r2:8080c17c
-[ 120.119276] r7:97d68e58 r6:9df23200 r5:9668c260 r4:96459260
-[ 120.125046] [<803a4eb4>] (clk_core_unprepare) from [<803a707c>] (clk_unprepare+0x34/0x3c)
-[ 120.133226] r5:9668c260 r4:96459260
-[ 120.136932] [<803a7048>] (clk_unprepare) from [<804f34bc>] (aspeed_video_off+0x44/0x48)
-[ 120.145031] r5:9668c260 r4:9668cbc0
-[ 120.148647] [<804f3478>] (aspeed_video_off) from [<804f3fd0>] (aspeed_video_release+0x94/0x118)
-[ 120.157435] r5:966a0cb8 r4:966a0800
-[ 120.161049] [<804f3f3c>] (aspeed_video_release) from [<804d2c58>] (v4l2_release+0xd4/0xe8)
-[ 120.169404] r7:97d68e58 r6:9d087810 r5:9df23200 r4:966a0b20
-[ 120.175168] [<804d2b84>] (v4l2_release) from [<80236224>] (__fput+0x98/0x1c4)
-[ 120.182316] r5:96698e78 r4:9df23200
-[ 120.185994] [<8023618c>] (__fput) from [<802363b8>] (____fput+0x18/0x1c)
-[ 120.192712] r9:80a0700c r8:801011e4 r7:00000000 r6:80a64bbc r5:961dd560 r4:961dd89c
-[ 120.200562] [<802363a0>] (____fput) from [<80131c08>] (task_work_run+0x7c/0xa4)
-[ 120.207994] [<80131b8c>] (task_work_run) from [<80106884>] (do_work_pending+0x4a8/0x578)
-[ 120.216163] r7:801011e4 r6:80a07008 r5:96197fb0 r4:ffffe000
-[ 120.221856] [<801063dc>] (do_work_pending) from [<8010106c>] (slow_work_pending+0xc/0x20)
-[ 120.230116] Exception stack(0x96197fb0 to 0x96197ff8)
-[ 120.235254] 7fa0: 00000000 76ccf094 00000000 00000000
-[ 120.243438] 7fc0: 00000008 00a11978 7eab3c30 00000006 00000000 00000000 475b0fa4 00000000
-[ 120.251692] 7fe0: 00000002 7eab3a40 00000000 47720e38 80000010 00000008
-[ 120.258396] r10:00000000 r9:96196000 r8:801011e4 r7:00000006 r6:7eab3c30 r5:00a11978
-[ 120.266291] r4:00000008
-
-To prevent this issue, this commit adds spinlock protection and clock
-status checking logic into the Aspeed video engine driver.
-
-Fixes: d2b4387f3bdf ("media: platform: Add Aspeed Video Engine driver")
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
-Cc: Eddie James <eajames@linux.ibm.com>
-Cc: Mauro Carvalho Chehab <mchehab@kernel.org>
-Cc: Joel Stanley <joel@jms.id.au>
-Cc: Andrew Jeffery <andrew@aj.id.au>
----
- drivers/media/platform/aspeed-video.c | 32 +++++++++++++++++++++++++++++---
- 1 file changed, 29 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
-index 8144fe36ad48..e70be8fdbde5 100644
---- a/drivers/media/platform/aspeed-video.c
-+++ b/drivers/media/platform/aspeed-video.c
-@@ -187,6 +187,7 @@ enum {
- VIDEO_STREAMING,
- VIDEO_FRAME_INPRG,
- VIDEO_STOPPED,
-+ VIDEO_CLOCKS_ON,
- };
-
- struct aspeed_video_addr {
-@@ -483,19 +484,29 @@ static void aspeed_video_enable_mode_detect(struct aspeed_video *video)
-
- static void aspeed_video_off(struct aspeed_video *video)
- {
-+ if (!test_bit(VIDEO_CLOCKS_ON, &video->flags))
-+ return;
-+
- /* Disable interrupts */
- aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
-
- /* Turn off the relevant clocks */
- clk_disable_unprepare(video->vclk);
- clk_disable_unprepare(video->eclk);
-+
-+ clear_bit(VIDEO_CLOCKS_ON, &video->flags);
- }
-
- static void aspeed_video_on(struct aspeed_video *video)
- {
-+ if (test_bit(VIDEO_CLOCKS_ON, &video->flags))
-+ return;
-+
- /* Turn on the relevant clocks */
- clk_prepare_enable(video->eclk);
- clk_prepare_enable(video->vclk);
-+
-+ set_bit(VIDEO_CLOCKS_ON, &video->flags);
- }
-
- static void aspeed_video_bufs_done(struct aspeed_video *video,
-@@ -513,12 +524,14 @@ static void aspeed_video_bufs_done(struct aspeed_video *video,
-
- static void aspeed_video_irq_res_change(struct aspeed_video *video)
- {
-+ spin_lock(&video->lock);
- dev_dbg(video->dev, "Resolution changed; resetting\n");
-
- set_bit(VIDEO_RES_CHANGE, &video->flags);
- clear_bit(VIDEO_FRAME_INPRG, &video->flags);
-
- aspeed_video_off(video);
-+ spin_unlock(&video->lock);
- aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
-
- schedule_delayed_work(&video->res_work, RESOLUTION_CHANGE_DELAY);
-@@ -938,9 +951,13 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
-
- static void aspeed_video_start(struct aspeed_video *video)
- {
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&video->lock, flags);
- aspeed_video_on(video);
-
- aspeed_video_init_regs(video);
-+ spin_unlock_irqrestore(&video->lock, flags);
-
- /* Resolution set to 640x480 if no signal found */
- aspeed_video_get_resolution(video);
-@@ -956,6 +973,9 @@ static void aspeed_video_start(struct aspeed_video *video)
-
- static void aspeed_video_stop(struct aspeed_video *video)
- {
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&video->lock, flags);
- set_bit(VIDEO_STOPPED, &video->flags);
- cancel_delayed_work_sync(&video->res_work);
-
-@@ -969,6 +989,7 @@ static void aspeed_video_stop(struct aspeed_video *video)
-
- video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
- video->flags = 0;
-+ spin_unlock_irqrestore(&video->lock, flags);
- }
-
- static int aspeed_video_querycap(struct file *file, void *fh,
-@@ -1306,16 +1327,21 @@ static void aspeed_video_resolution_work(struct work_struct *work)
- struct delayed_work *dwork = to_delayed_work(work);
- struct aspeed_video *video = container_of(dwork, struct aspeed_video,
- res_work);
-- u32 input_status = video->v4l2_input_status;
-+ unsigned long flags;
-+ u32 input_status;
-
-+ spin_lock_irqsave(&video->lock, flags);
-+ input_status = video->v4l2_input_status;
- aspeed_video_on(video);
-
- /* Exit early in case no clients remain */
-- if (test_bit(VIDEO_STOPPED, &video->flags))
-+ if (test_bit(VIDEO_STOPPED, &video->flags)) {
-+ spin_unlock_irqrestore(&video->lock, flags);
- goto done;
-+ }
-
- aspeed_video_init_regs(video);
--
-+ spin_unlock_irqrestore(&video->lock, flags);
- aspeed_video_get_resolution(video);
-
- if (video->detected_timings.width != video->active_timings.width ||
---
-2.7.4
-
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch
new file mode 100644
index 000000000..d66facdfa
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch
@@ -0,0 +1,35 @@
+From a2e0020ef6e03abde6819fb7fc328dcf23d0bd71 Mon Sep 17 00:00:00 2001
+From: "Hunt, Bryan" <bryan.hunt@intel.com>
+Date: Mon, 6 May 2019 10:02:14 -0700
+Subject: [PATCH] Add AST2500d JTAG driver
+
+Adding aspeed jtag device
+
+Signed-off-by: Hunt, Bryan <bryan.hunt@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g5.dtsi | 9 +
+ 1 files changed, 15 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index bf7ae631a458..2c9f287759ce 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -366,6 +366,15 @@
+ pinctrl-0 = <&pinctrl_espi_default>;
+ };
+
++ jtag: jtag@1e6e4000 {
++ compatible = "aspeed,ast2500-jtag";
++ reg = <0x1e6e4000 0x1c>;
++ clocks = <&syscon ASPEED_CLK_APB>;
++ resets = <&syscon ASPEED_RESET_JTAG_MASTER>;
++ interrupts = <43>;
++ status = "disabled";
++ };
++
+ lpc: lpc@1e789000 {
+ compatible = "aspeed,ast2500-lpc", "simple-mfd";
+ reg = <0x1e789000 0x1000>;
+--
+2.7.4
+
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
new file mode 100644
index 000000000..7ba94a7bc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch
@@ -0,0 +1,904 @@
+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
+Subject: [PATCH v29 1/6] drivers: jtag: Add JTAG core driver
+
+JTAG class driver provide infrastructure to support hardware/software
+JTAG platform drivers. It provide user layer API interface for flashing
+and debugging external devices which equipped with JTAG interface
+using standard transactions.
+
+Driver exposes set of IOCTL to user space for:
+- XFER:
+ SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan);
+ SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan);
+- GIOCSTATUS read the current TAPC state of the JTAG controller
+- SIOCSTATE Forces the JTAG TAPC to go into a particular state.
+- SIOCFREQ/GIOCFREQ for setting and reading JTAG frequency.
+- IOCBITBANG for low level control of JTAG signals.
+
+Driver core provides set of internal APIs for allocation and
+registration:
+- jtag_register;
+- jtag_unregister;
+- jtag_alloc;
+- jtag_free;
+
+Platform driver on registration with jtag-core creates the next
+entry in dev folder:
+/dev/jtagX
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Philippe Ombredanne <pombredanne@nexb.com>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: Paul Burton <paul.burton@mips.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Boris Brezillon <bbrezillon@kernel.org>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Johan Hovold <johan@kernel.org>
+Cc: Jens Axboe <axboe@kernel.dk>
+Cc: Joel Stanley <joel@jms.id.au>
+Cc: Palmer Dabbelt <palmer@sifive.com>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+v28->v29
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Expand bitbang function to accept multiples bitbang operations within a
+ single JTAG_IOCBITBANG call. It will receive a buffer with TDI and TMS
+ values and it is expected that driver fills TDO fields with its
+ corresponding output value for every transaction.
+- Always setup JTAG controller to master mode but disable JTAG output when
+ 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).
+
+v27->v28
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Replace JTAG_IOCRUNTEST with JTAG_SIOCSTATE adding support for all TAPC
+ end states in SW mode using a lookup table to navigate across states.
+- Add support for simultaneous READ/WRITE transfers(JTAG_READ_WRITE_XFER).
+- Support for switching JTAG controller mode between slave and master
+ mode.
+- Setup JTAG controller mode to master only when the driver is opened,
+ letting
+ other HW to own the JTAG bus when it isn't in use.
+- Include JTAG bit bang IOCTL for low level JTAG control usage
+ (JTAG_IOCBITBANG).
+
+v24->v25
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- set values to enums in jtag.h
+
+v23->v24
+Notifications from kbuild test robot <lkp@intel.com>
+- Add include types.h header to jtag.h
+- remove unecessary jtag_release
+
+v22->v23
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- remove restriction of allocated JTAG devs-
+- add validation fo idle values
+- remove unnecessary blank line
+- change retcode for xfer
+- remove unecessary jtag_release callback
+- remove unecessary defined fron jtag.h
+- align in one line define JTAG_IOCRUNTEST
+
+v21->v22
+Comments pointed by Andy Shevchenko <andy.shevchenko@gmail.com>
+- Fix 0x0f -> 0x0F in ioctl-number.txt
+- Add description to #define MAX_JTAG_NAME_LEN
+- Remove unnecessary entry *dev from struct jtag
+- Remove redundant parens
+- Described mandatory callbacks and removed unnecessary
+- Set JTAG_MAX_XFER_DATA_LEN to power of 2
+- rework driver alloc/register to devm_ variant
+- increasing line length up to 84 in order to improve readability.
+
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- fix spell in ABI doccumentation
+
+v20->v21
+ Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+ - Fix JTAG dirver help in Kconfig
+
+v19->v20
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- Fix JTAG dirver help in Kconfig
+
+Notifications from kbuild test robot <lkp@intel.com>
+- fix incompatible type casts
+
+v18->v19
+Comments pointed by Julia Cartwright <juliac@eso.teric.us>
+- Fix memory leak on jtag_alloc exit
+
+v17->v18
+Comments pointed by Julia Cartwright <juliac@eso.teric.us>
+- Change to return -EOPNOTSUPP in case of error in JTAG_GIOCFREQ
+- Add ops callbacks check to jtag_alloc
+- Add err check for copy_to_user
+- Move the kfree() above the if (err) in JTAG_IOCXFER
+- remove unnecessary check for error after put_user
+- add padding to struct jtag_xfer
+
+v16->v17
+Comments pointed by Julia Cartwright <juliac@eso.teric.us>
+- Fix memory allocation on jtag alloc
+- Move out unnecessary form lock on jtag open
+- Rework jtag register behavior
+
+v15->v16
+Comments pointed by Florian Fainelli <f.fainelli@gmail.com>
+- move check jtag->ops->* in ioctl before get_user()
+- change error type -EINVAL --> -EBUSY on open already opened jtag
+- remove unnecessary ARCH_DMA_MINALIGN flag from kzalloc
+- remove define ARCH_DMA_MINALIGN
+
+v14->v15
+v13->v14
+Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
+- Change style of head block comment from /**/ to //
+
+v12->v13
+Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
+- Change jtag.c licence type to
+ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ and reorder line with license in description
+
+v11->v12
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- Change jtag.h licence type to
+ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ and reorder line with license in description
+
+Comments pointed by Chip Bilbrey <chip@bilbrey.org>
+- Remove Apeed reference from uapi jtag.h header
+- Remove access mode from xfer and idle transactions
+- Add new ioctl JTAG_SIOCMODE for set hw mode
+- Add single open per device blocking
+
+v10->v11
+Notifications from kbuild test robot <lkp@intel.com>
+- Add include types.h header to jtag.h
+- fix incompatible type of xfer callback
+- remove rdundant class defination
+- Fix return order in case of xfer error
+
+V9->v10
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- remove unnecessary alignment for pirv data
+- move jtag_copy_to_user and jtag_copy_from_user code just to ioctl
+- move int jtag_run_test_idle_op and jtag_xfer_op code
+ just to ioctl
+- change return error codes to more applicable
+- add missing error checks
+- fix error check order in ioctl
+- remove unnecessary blank lines
+- add param validation to ioctl
+- remove compat_ioctl
+- remove only one open per JTAG port blocking.
+ User will care about this.
+- Fix idr memory leak on jtag_exit
+- change cdev device type to misc
+
+V8->v9
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- use get_user() instead of __get_user().
+- change jtag->open type from int to atomic_t
+- remove spinlock on jtg_open
+- remove mutex on jtag_register
+- add unregister_chrdev_region on jtag_init err
+- add unregister_chrdev_region on jtag_exit
+- remove unnecessary pointer casts
+- add *data parameter to xfer function prototype
+
+v7->v8
+Comments pointed by Moritz Fischer <moritz.fischer@ettus.com>
+- Fix misspelling s/friver/driver
+
+v6->v7
+Notifications from kbuild test robot <lkp@intel.com>
+- Remove include asm/types.h from jtag.h
+- Add include <linux/types.h> to jtag.c
+
+v5->v6
+v4->v5
+
+v3->v4
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- change transaction pointer tdio type to __u64
+- change internal status type from enum to __u32
+- reorder jtag_xfer members to avoid the implied padding
+- add __packed attribute to jtag_xfer and jtag_run_test_idle
+
+v2->v3
+Notifications from kbuild test robot <lkp@intel.com>
+- Change include path to <linux/types.h> in jtag.h
+
+v1->v2
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- Change license type from GPLv2/BSD to GPLv2
+- Change type of variables which crossed user/kernel to __type
+- Remove "default n" from Kconfig
+
+Comments pointed by Andrew Lunn <andrew@lunn.ch>
+- Change list_add_tail in jtag_unregister to list_del
+
+Comments pointed by Neil Armstrong <narmstrong@baylibre.com>
+- Add SPDX-License-Identifier instead of license text
+
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- Change __copy_to_user to memdup_user
+- Change __put_user to put_user
+- Change type of variables to __type for compatible 32 and 64-bit systems
+- Add check for maximum xfer data size
+- Change lookup data mechanism to get jtag data from inode
+- Add .compat_ioctl to file ops
+- Add mem alignment for jtag priv data
+
+Comments pointed by Tobias Klauser <tklauser@distanz.ch>
+- Change function names to avoid match with variable types
+- Fix description for jtag_ru_test_idle in uapi jtag.h
+- Fix misprints IDEL/IDLE, trough/through
+---
+ drivers/Kconfig | 1 +
+ drivers/Makefile | 1 +
+ drivers/jtag/Kconfig | 17 +++
+ drivers/jtag/Makefile | 1 +
+ drivers/jtag/jtag.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/jtag.h | 47 +++++++
+ include/uapi/linux/jtag.h | 208 ++++++++++++++++++++++++++++++
+ 7 files changed, 589 insertions(+)
+ create mode 100644 drivers/jtag/Kconfig
+ create mode 100644 drivers/jtag/Makefile
+ create mode 100644 drivers/jtag/jtag.c
+ create mode 100644 include/linux/jtag.h
+ create mode 100644 include/uapi/linux/jtag.h
+
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index 4f9f990..0102bae 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -228,4 +228,5 @@ source "drivers/siox/Kconfig"
+
+ source "drivers/slimbus/Kconfig"
+
++source "drivers/jtag/Kconfig"
+ endmenu
+diff --git a/drivers/Makefile b/drivers/Makefile
+index e1ce029..6d756c2 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -186,3 +186,4 @@ obj-$(CONFIG_MULTIPLEXER) += mux/
+ obj-$(CONFIG_SIOX) += siox/
+ obj-$(CONFIG_GNSS) += gnss/
+ obj-$(CONFIG_PECI) += peci/
++obj-$(CONFIG_JTAG) += jtag/
+diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
+new file mode 100644
+index 0000000..47771fc
+--- /dev/null
++++ b/drivers/jtag/Kconfig
+@@ -0,0 +1,17 @@
++menuconfig JTAG
++ tristate "JTAG support"
++ help
++ This provides basic core functionality support for JTAG class devices.
++ Hardware that is equipped with a JTAG microcontroller can be
++ supported by using this driver's interfaces.
++ This driver exposes a set of IOCTLs to the user space for
++ the following commands:
++ SDR: Performs an IEEE 1149.1 Data Register scan
++ SIR: Performs an IEEE 1149.1 Instruction Register scan.
++ RUNTEST: Forces the IEEE 1149.1 bus to a run state for a specified
++ number of clocks or a specified time period.
++
++ If you want this support, you should say Y here.
++
++ To compile this driver as a module, choose M here: the module will
++ be called jtag.
+diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile
+new file mode 100644
+index 0000000..af37493
+--- /dev/null
++++ b/drivers/jtag/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_JTAG) += jtag.o
+diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c
+new file mode 100644
+index 0000000..47503a1
+--- /dev/null
++++ b/drivers/jtag/jtag.c
+@@ -0,0 +1,314 @@
++// SPDX-License-Identifier: GPL-2.0-only
++// Copyright (c) 2018 Mellanox Technologies. All rights reserved.
++// Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com>
++// Copyright (c) 2019 Intel Corporation
++
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/jtag.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/rtnetlink.h>
++#include <linux/spinlock.h>
++#include <linux/types.h>
++#include <uapi/linux/jtag.h>
++
++struct jtag {
++ struct miscdevice miscdev;
++ const struct jtag_ops *ops;
++ int id;
++ unsigned long priv[0];
++};
++
++static DEFINE_IDA(jtag_ida);
++
++void *jtag_priv(struct jtag *jtag)
++{
++ return jtag->priv;
++}
++EXPORT_SYMBOL_GPL(jtag_priv);
++
++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_xfer xfer;
++ struct bitbang_packet bitbang;
++ struct tck_bitbang *bitbang_data;
++ struct jtag_mode mode;
++ u8 *xfer_data;
++ u32 data_size;
++ u32 value;
++ int err;
++
++ if (!arg)
++ return -EINVAL;
++
++ switch (cmd) {
++ case JTAG_GIOCFREQ:
++ if (!jtag->ops->freq_get)
++ return -EOPNOTSUPP;
++
++ err = jtag->ops->freq_get(jtag, &value);
++ if (err)
++ break;
++
++ if (put_user(value, (__u32 __user *)arg))
++ err = -EFAULT;
++ break;
++
++ case JTAG_SIOCFREQ:
++ if (!jtag->ops->freq_set)
++ return -EOPNOTSUPP;
++
++ if (get_user(value, (__u32 __user *)arg))
++ return -EFAULT;
++ if (value == 0)
++ return -EINVAL;
++
++ err = jtag->ops->freq_set(jtag, value);
++ break;
++
++ case JTAG_SIOCSTATE:
++ if (copy_from_user(&endstate, (const void __user *)arg,
++ sizeof(struct jtag_end_tap_state)))
++ return -EFAULT;
++
++ if (endstate.endstate > JTAG_STATE_UPDATEIR)
++ return -EINVAL;
++
++ if (endstate.reset > JTAG_FORCE_RESET)
++ return -EINVAL;
++
++ err = jtag->ops->status_set(jtag, &endstate);
++ break;
++
++ case JTAG_IOCXFER:
++ if (copy_from_user(&xfer, (const void __user *)arg,
++ sizeof(struct jtag_xfer)))
++ return -EFAULT;
++
++ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN)
++ return -EINVAL;
++
++ if (xfer.type > JTAG_SDR_XFER)
++ return -EINVAL;
++
++ if (xfer.direction > JTAG_READ_WRITE_XFER)
++ return -EINVAL;
++
++ if (xfer.endstate > JTAG_STATE_UPDATEIR)
++ return -EINVAL;
++
++ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE);
++ xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size);
++ if (IS_ERR(xfer_data))
++ return -EFAULT;
++
++ err = jtag->ops->xfer(jtag, &xfer, xfer_data);
++ if (err) {
++ kfree(xfer_data);
++ return err;
++ }
++
++ err = copy_to_user(u64_to_user_ptr(xfer.tdio),
++ (void *)xfer_data, data_size);
++ kfree(xfer_data);
++ if (err)
++ return -EFAULT;
++
++ if (copy_to_user((void __user *)arg, (void *)&xfer,
++ sizeof(struct jtag_xfer)))
++ return -EFAULT;
++ break;
++
++ case JTAG_GIOCSTATUS:
++ err = jtag->ops->status_get(jtag, &value);
++ if (err)
++ break;
++
++ err = put_user(value, (__u32 __user *)arg);
++ break;
++ case JTAG_IOCBITBANG:
++ if (copy_from_user(&bitbang, (const void __user *)arg,
++ sizeof(struct bitbang_packet)))
++ return -EFAULT;
++
++ if (bitbang.length >= JTAG_MAX_XFER_DATA_LEN)
++ return -EINVAL;
++
++ data_size = bitbang.length * sizeof(struct tck_bitbang);
++ bitbang_data = memdup_user((void __user *)bitbang.data,
++ data_size);
++ if (IS_ERR(bitbang_data))
++ return -EFAULT;
++
++ err = jtag->ops->bitbang(jtag, &bitbang, bitbang_data);
++ if (err) {
++ kfree(bitbang_data);
++ return err;
++ }
++ err = copy_to_user((void __user *)bitbang.data,
++ (void *)bitbang_data, data_size);
++ kfree(bitbang_data);
++ if (err)
++ return -EFAULT;
++ break;
++ case JTAG_SIOCMODE:
++ if (!jtag->ops->mode_set)
++ return -EOPNOTSUPP;
++
++ if (copy_from_user(&mode, (const void __user *)arg,
++ sizeof(struct jtag_mode)))
++ return -EFAULT;
++
++ err = jtag->ops->mode_set(jtag, &mode);
++ break;
++
++ default:
++ return -EINVAL;
++ }
++ return err;
++}
++
++static int jtag_open(struct inode *inode, struct file *file)
++{
++ struct jtag *jtag = container_of(file->private_data,
++ struct jtag,
++ miscdev);
++
++ file->private_data = jtag;
++ if (jtag->ops->enable(jtag))
++ return -EBUSY;
++ return nonseekable_open(inode, file);
++}
++
++static int jtag_release(struct inode *inode, struct file *file)
++{
++ struct jtag *jtag = file->private_data;
++
++ if (jtag->ops->disable(jtag))
++ return -EBUSY;
++ return 0;
++}
++
++static const struct file_operations jtag_fops = {
++ .owner = THIS_MODULE,
++ .open = jtag_open,
++ .llseek = noop_llseek,
++ .unlocked_ioctl = jtag_ioctl,
++ .release = jtag_release,
++};
++
++struct jtag *jtag_alloc(struct device *host, size_t priv_size,
++ const struct jtag_ops *ops)
++{
++ struct jtag *jtag;
++
++ if (!host)
++ return NULL;
++
++ if (!ops)
++ return NULL;
++
++ if (!ops->status_set || !ops->status_get || !ops->xfer)
++ return NULL;
++
++ jtag = kzalloc(sizeof(*jtag) + priv_size, GFP_KERNEL);
++ if (!jtag)
++ return NULL;
++
++ jtag->ops = ops;
++ jtag->miscdev.parent = host;
++
++ return jtag;
++}
++EXPORT_SYMBOL_GPL(jtag_alloc);
++
++void jtag_free(struct jtag *jtag)
++{
++ kfree(jtag);
++}
++EXPORT_SYMBOL_GPL(jtag_free);
++
++static int jtag_register(struct jtag *jtag)
++{
++ struct device *dev = jtag->miscdev.parent;
++ int err;
++ int id;
++
++ if (!dev)
++ return -ENODEV;
++
++ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL);
++ if (id < 0)
++ return id;
++
++ jtag->id = id;
++
++ jtag->miscdev.fops = &jtag_fops;
++ jtag->miscdev.minor = MISC_DYNAMIC_MINOR;
++ jtag->miscdev.name = kasprintf(GFP_KERNEL, "jtag%d", id);
++ if (!jtag->miscdev.name) {
++ err = -ENOMEM;
++ goto err_jtag_alloc;
++ }
++
++ err = misc_register(&jtag->miscdev);
++ if (err) {
++ dev_err(jtag->miscdev.parent, "Unable to register device\n");
++ goto err_jtag_name;
++ }
++ return 0;
++
++err_jtag_name:
++ kfree(jtag->miscdev.name);
++err_jtag_alloc:
++ ida_simple_remove(&jtag_ida, id);
++ return err;
++}
++
++static void jtag_unregister(struct jtag *jtag)
++{
++ misc_deregister(&jtag->miscdev);
++ kfree(jtag->miscdev.name);
++ ida_simple_remove(&jtag_ida, jtag->id);
++}
++
++static void devm_jtag_unregister(struct device *dev, void *res)
++{
++ jtag_unregister(*(struct jtag **)res);
++}
++
++int devm_jtag_register(struct device *dev, struct jtag *jtag)
++{
++ struct jtag **ptr;
++ int ret;
++
++ ptr = devres_alloc(devm_jtag_unregister, sizeof(*ptr), GFP_KERNEL);
++ if (!ptr)
++ return -ENOMEM;
++
++ ret = jtag_register(jtag);
++ if (!ret) {
++ *ptr = jtag;
++ devres_add(dev, ptr);
++ } else {
++ devres_free(ptr);
++ }
++ return ret;
++}
++EXPORT_SYMBOL_GPL(devm_jtag_register);
++
++static void __exit jtag_exit(void)
++{
++ ida_destroy(&jtag_ida);
++}
++
++module_exit(jtag_exit);
++
++MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>");
++MODULE_DESCRIPTION("Generic jtag support");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/jtag.h b/include/linux/jtag.h
+new file mode 100644
+index 0000000..4153c90
+--- /dev/null
++++ b/include/linux/jtag.h
+@@ -0,0 +1,47 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (c) 2018 Mellanox Technologies. All rights reserved. */
++/* Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> */
++/* Copyright (c) 2019 Intel Corporation */
++
++#ifndef __LINUX_JTAG_H
++#define __LINUX_JTAG_H
++
++#include <linux/types.h>
++#include <uapi/linux/jtag.h>
++
++#define JTAG_MAX_XFER_DATA_LEN 65535
++
++struct jtag;
++/**
++ * struct jtag_ops - callbacks for JTAG control functions:
++ *
++ * @freq_get: get frequency function. Filled by dev driver
++ * @freq_set: set frequency function. Filled by dev driver
++ * @status_get: get JTAG TAPC state function. Mandatory, Filled by dev driver
++ * @status_set: set JTAG TAPC state function. Mandatory, Filled by dev driver
++ * @xfer: send JTAG xfer function. Mandatory func. Filled by dev driver
++ * @mode_set: set specific work mode for JTAG. Filled by dev driver
++ * @bitbang: set low level bitbang operations. Filled by dev driver
++ * @enable: enables JTAG interface in master mode. Filled by dev driver
++ * @disable: disables JTAG interface master mode. Filled by dev driver
++ */
++struct jtag_ops {
++ 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 (*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,
++ struct tck_bitbang *bitbang_data);
++ int (*enable)(struct jtag *jtag);
++ int (*disable)(struct jtag *jtag);
++};
++
++void *jtag_priv(struct jtag *jtag);
++int devm_jtag_register(struct device *dev, struct jtag *jtag);
++struct jtag *jtag_alloc(struct device *host, size_t priv_size,
++ const struct jtag_ops *ops);
++void jtag_free(struct jtag *jtag);
++
++#endif /* __LINUX_JTAG_H */
+diff --git a/include/uapi/linux/jtag.h b/include/uapi/linux/jtag.h
+new file mode 100644
+index 0000000..3f9e195
+--- /dev/null
++++ b/include/uapi/linux/jtag.h
+@@ -0,0 +1,208 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (c) 2018 Mellanox Technologies. All rights reserved. */
++/* Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> */
++/* Copyright (c) 2019 Intel Corporation */
++
++#ifndef __UAPI_LINUX_JTAG_H
++#define __UAPI_LINUX_JTAG_H
++
++/*
++ * JTAG_XFER_MODE: JTAG transfer mode. Used to set JTAG controller transfer mode
++ * This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_XFER_MODE 0
++/*
++ * JTAG_CONTROL_MODE: JTAG controller mode. Used to set JTAG controller mode
++ * This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_CONTROL_MODE 1
++/*
++ * JTAG_MASTER_OUTPUT_DISABLE: JTAG master mode output disable, it is used to
++ * enable other devices to own the JTAG bus.
++ * This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_MASTER_OUTPUT_DISABLE 0
++/*
++ * JTAG_MASTER_MODE: JTAG master mode. Used to set JTAG controller master mode
++ * This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_MASTER_MODE 1
++/*
++ * JTAG_XFER_HW_MODE: JTAG hardware mode. Used to set HW drived or bitbang
++ * mode. This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_XFER_HW_MODE 1
++/*
++ * JTAG_XFER_SW_MODE: JTAG software mode. Used to set SW drived or bitbang
++ * mode. This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_XFER_SW_MODE 0
++
++/**
++ * enum jtag_endstate:
++ *
++ * @JTAG_STATE_TLRESET: JTAG state machine Test Logic Reset state
++ * @JTAG_STATE_IDLE: JTAG state machine IDLE state
++ * @JTAG_STATE_SELECTDR: JTAG state machine SELECT_DR state
++ * @JTAG_STATE_CAPTUREDR: JTAG state machine CAPTURE_DR state
++ * @JTAG_STATE_SHIFTDR: JTAG state machine SHIFT_DR state
++ * @JTAG_STATE_EXIT1DR: JTAG state machine EXIT-1 DR state
++ * @JTAG_STATE_PAUSEDR: JTAG state machine PAUSE_DR state
++ * @JTAG_STATE_EXIT2DR: JTAG state machine EXIT-2 DR state
++ * @JTAG_STATE_UPDATEDR: JTAG state machine UPDATE DR state
++ * @JTAG_STATE_SELECTIR: JTAG state machine SELECT_IR state
++ * @JTAG_STATE_CAPTUREIR: JTAG state machine CAPTURE_IR state
++ * @JTAG_STATE_SHIFTIR: JTAG state machine SHIFT_IR state
++ * @JTAG_STATE_EXIT1IR: JTAG state machine EXIT-1 IR state
++ * @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
++ */
++enum jtag_endstate {
++ JTAG_STATE_TLRESET,
++ JTAG_STATE_IDLE,
++ JTAG_STATE_SELECTDR,
++ JTAG_STATE_CAPTUREDR,
++ JTAG_STATE_SHIFTDR,
++ JTAG_STATE_EXIT1DR,
++ JTAG_STATE_PAUSEDR,
++ JTAG_STATE_EXIT2DR,
++ JTAG_STATE_UPDATEDR,
++ JTAG_STATE_SELECTIR,
++ JTAG_STATE_CAPTUREIR,
++ JTAG_STATE_SHIFTIR,
++ JTAG_STATE_EXIT1IR,
++ JTAG_STATE_PAUSEIR,
++ JTAG_STATE_EXIT2IR,
++ JTAG_STATE_UPDATEIR
++};
++
++/**
++ * enum jtag_reset:
++ *
++ * @JTAG_NO_RESET: JTAG run TAP from current state
++ * @JTAG_FORCE_RESET: JTAG force TAP to reset state
++ */
++enum jtag_reset {
++ JTAG_NO_RESET = 0,
++ JTAG_FORCE_RESET = 1,
++};
++
++/**
++ * enum jtag_xfer_type:
++ *
++ * @JTAG_SIR_XFER: SIR transfer
++ * @JTAG_SDR_XFER: SDR transfer
++ */
++enum jtag_xfer_type {
++ JTAG_SIR_XFER = 0,
++ JTAG_SDR_XFER = 1,
++};
++
++/**
++ * enum jtag_xfer_direction:
++ *
++ * @JTAG_READ_XFER: read transfer
++ * @JTAG_WRITE_XFER: write transfer
++ * @JTAG_READ_WRITE_XFER: read & write transfer
++ */
++enum jtag_xfer_direction {
++ JTAG_READ_XFER = 1,
++ JTAG_WRITE_XFER = 2,
++ JTAG_READ_WRITE_XFER = 3,
++};
++
++/**
++ * struct jtag_end_tap_state - forces JTAG state machine to go into a TAPC
++ * state
++ *
++ * @reset: 0 - run IDLE/PAUSE from current state
++ * 1 - go through TEST_LOGIC/RESET state before IDLE/PAUSE
++ * @end: completion flag
++ * @tck: clock counter
++ *
++ * Structure provide interface to JTAG device for JTAG set state execution.
++ */
++struct jtag_end_tap_state {
++ __u8 reset;
++ __u8 endstate;
++ __u8 tck;
++};
++
++/**
++ * struct jtag_xfer - jtag xfer:
++ *
++ * @type: transfer type
++ * @direction: xfer direction
++ * @length: xfer bits len
++ * @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 endstate;
++ __u8 padding;
++ __u32 length;
++ __u64 tdio;
++};
++
++/**
++ * struct bitbang_packet - jtag bitbang array packet:
++ *
++ * @data: JTAG Bitbang struct array pointer(input/output)
++ * @length: array size (input)
++ *
++ * Structure provide interface to JTAG device for JTAG bitbang bundle execution
++ */
++struct bitbang_packet {
++ struct tck_bitbang *data;
++ __u32 length;
++} __attribute__((__packed__));
++
++/**
++ * struct jtag_bitbang - jtag bitbang:
++ *
++ * @tms: JTAG TMS
++ * @tdi: JTAG TDI (input)
++ * @tdo: JTAG TDO (output)
++ *
++ * Structure provide interface to JTAG device for JTAG bitbang execution.
++ */
++struct tck_bitbang {
++ __u8 tms;
++ __u8 tdi;
++ __u8 tdo;
++} __attribute__((__packed__));
++
++/**
++ * struct jtag_mode - jtag mode:
++ *
++ * @feature: 0 - JTAG feature setting selector for JTAG controller HW/SW
++ * 1 - JTAG feature setting selector for controller bus master
++ * mode output (enable / disable).
++ * @mode: (0 - SW / 1 - HW) for JTAG_XFER_MODE feature(0)
++ * (0 - output disable / 1 - output enable) for JTAG_CONTROL_MODE
++ * feature(1)
++ *
++ * Structure provide configuration modes to JTAG device.
++ */
++struct jtag_mode {
++ __u32 feature;
++ __u32 mode;
++};
++
++/* ioctl interface */
++#define __JTAG_IOCTL_MAGIC 0xb2
++
++#define JTAG_SIOCSTATE _IOW(__JTAG_IOCTL_MAGIC, 0, struct jtag_end_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_SIOCMODE _IOW(__JTAG_IOCTL_MAGIC, 5, unsigned int)
++#define JTAG_IOCBITBANG _IOW(__JTAG_IOCTL_MAGIC, 6, unsigned int)
++
++#endif /* __UAPI_LINUX_JTAG_H */
+--
+2.7.4
+
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
new file mode 100644
index 000000000..d5d43f31b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch
@@ -0,0 +1,1282 @@
+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
+Subject: [PATCH v29 2/6] Add Aspeed SoC 24xx and 25xx families JTAG master
+ driver
+
+Driver adds support of Aspeed 2500/2400 series SOC JTAG master controller.
+
+Driver implements the following jtag ops:
+- freq_get;
+- freq_set;
+- status_get;
+- status_set
+- xfer;
+- mode_set;
+- bitbang;
+- enable;
+- disable;
+
+It has been tested on Mellanox system with BMC equipped with
+Aspeed 2520 SoC for programming CPLD devices.
+
+It has also been tested on Intel system using Aspeed 25xx SoC
+for JTAG communication.
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Acked-by: Philippe Ombredanne <pombredanne@nexb.com>
+Acked-by: Joel Stanley <joel@jms.id.au>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Andrew Jeffery <andrew@aj.id.au>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+v28->v29
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Expand bitbang function to accept multiples bitbang operations within a
+ single JTAG_IOCBITBANG call. It will receive a buffer with TDI and TMS
+ values and it is expected that driver fills TDO fields with its
+ corresponding output value for every transaction.
+- Always setup JTAG controller to master mode but disable JTAG output when
+ 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).
+- Encansulate dev_dgb message into DEBUG_JTAG macros to improve driver's JTAG
+ performace.
+
+v27->v28
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Replace JTAG_IOCRUNTEST with JTAG_SIOCSTATE adding support for all TAPC
+ end states in SW mode using a lookup table to navigate across states.
+- Add support for simultaneous READ/WRITE transfers(JTAG_READ_WRITE_XFER).
+- Support for switching JTAG controller mode between slave and master
+ mode.
+- Setup JTAG controller mode to master only when the driver is opened,
+ letting other HW to own the JTAG bus when it isn't in use.
+- Include JTAG bit bang IOCTL for low level JTAG control usage
+ (JTAG_IOCBITBANG).
+- Add debug traces.
+- Add support for register polling (default) due it is 3 times faster than
+ interrupt mode. Define USE_INTERRUPTS macro to enable interrupt usage.
+- Remove unnecessary delays for aspeed_jtag_status_set function. It makes
+ SW mode 4 times faster.
+- Clean data buffer on aspeed_jtag_xfer_sw before tdo writes to avoid data
+ output corruption for read operations in SW mode.
+- Correct register settings for HW mode transfer operations.
+- Propagate ret codes all the way from low level functions up to
+ JTAG_IOCXFER call.
+- Support for partitioned transfers. Single JTAG transfer through
+ multiples JTAG_IOCXFER calls. Now end transmission(scan_end) also
+ evaluates transfer end state.
+
+v26->v27
+Changes made by Oleksandr Shamray <oleksandrs@mellamnox.com>
+- change aspeed_jtag_sw_delay to udelay function in bit-bang operation
+
+v25->v26
+v24->v25
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- reduced debug printouts
+
+v23->v24
+v22->v23
+v21->v22
+Comments pointed by Andy Shevchenko <andy.shevchenko@gmail.com>
+- rearrange ASPEED register defines
+- simplified JTAG divider calculation formula
+- change delay function in bit-bang operation
+- add helper functions for TAP states switching
+- remove unnecessary comments
+- remove redundant debug messages
+- make dines for repetative register bit sets
+- fixed indentation
+- change checks from negative to positive
+- add error check for clk_prepare_enable
+- rework driver alloc/register to devm_ variant
+- Increasing line length up to 85 in order to improve readability
+
+v20->v21
+v19->v20
+Notifications from kbuild test robot <lkp@intel.com>
+- add static declaration to 'aspeed_jtag_init' and
+ 'aspeed_jtag_deinit' functions
+
+v18->v19
+v17->v18
+v16->v17
+v15->v16
+Comments pointed by Joel Stanley <joel.stan@gmail.com>
+- Add reset_control on Jtag init/deinit
+
+v14->v15
+Comments pointed by Joel Stanley <joel.stan@gmail.com>
+- Add ARCH_ASPEED || COMPILE_TEST to Kconfig
+- remove unused offset variable
+- remove "aspeed_jtag" from dev_err and dev_dbg messages
+- change clk_prepare_enable initialisation order
+
+v13->v14
+Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
+- Change style of head block comment from /**/ to //
+
+v12->v13
+Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
+- Change jtag-aspeed.c licence type to
+ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ and reorder line with license- add reset descriptions in bndings file
+ in description
+Comments pointed by Kun Yi <kunyi@google.com>
+- Changed capability check for aspeed,ast2400-jtag/ast200-jtag
+
+v11->v12
+Comments pointed by Chip Bilbrey <chip@bilbrey.org>
+- Remove access mode from xfer and idle transactions
+- Add new ioctl JTAG_SIOCMODE for set hw mode
+
+v10->v11
+v9->v10
+V8->v9
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- add *data parameter to xfer function prototype
+
+v7->v8
+Comments pointed by Joel Stanley <joel.stan@gmail.com>
+- aspeed_jtag_init replace goto to return;
+- change input variables type from __u32 to u32
+ in functios freq_get, freq_set, status_get
+- change sm_ variables type from char to u8
+- in jatg_init add disable clocks on error case
+- remove release_mem_region on error case
+- remove devm_free_irq on jtag_deinit
+- Fix misspelling Disabe/Disable
+- Change compatible string to ast2400 and ast2000
+
+v6->v7
+Notifications from kbuild test robot <lkp@intel.com>
+- Add include <linux/types.h> to jtag-asapeed.c
+
+v5->v6
+v4->v5
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- Added HAS_IOMEM dependence in Kconfig to avoid
+ "undefined reference to `devm_ioremap_resource'" error,
+ because in some arch this not supported
+
+v3->v4
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- change transaction pointer tdio type to __u64
+- change internal status type from enum to __u32
+
+v2->v3
+
+v1->v2
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- change license type from GPLv2/BSD to GPLv2
+
+Comments pointed by Neil Armstrong <narmstrong@baylibre.com>
+- Add clk_prepare_enable/clk_disable_unprepare in clock init/deinit
+- Change .compatible to soc-specific compatible names
+ aspeed,aspeed4000-jtag/aspeed5000-jtag
+- Added dt-bindings
+
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- Reorder functions and removed the forward declarations
+- Add static const qualifier to state machine states transitions
+- Change .compatible to soc-specific compatible names
+ aspeed,aspeed4000-jtag/aspeed5000-jtag
+- Add dt-bindings
+
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- Change module name jtag-aspeed in description in Kconfig
+
+Comments pointed by kbuild test robot <lkp@intel.com>
+- Remove invalid include <asm/mach-types.h>
+- add resource_size instead of calculation
+---
+ drivers/jtag/Kconfig | 14 +
+ drivers/jtag/Makefile | 1 +
+ drivers/jtag/jtag-aspeed.c | 1040 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1055 insertions(+)
+ create mode 100644 drivers/jtag/jtag-aspeed.c
+
+diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
+index 47771fc..0cc163f 100644
+--- a/drivers/jtag/Kconfig
++++ b/drivers/jtag/Kconfig
+@@ -15,3 +15,17 @@ menuconfig JTAG
+
+ To compile this driver as a module, choose M here: the module will
+ be called jtag.
++
++menuconfig JTAG_ASPEED
++ tristate "Aspeed SoC JTAG controller support"
++ depends on JTAG && HAS_IOMEM
++ depends on ARCH_ASPEED || COMPILE_TEST
++ help
++ This provides a support for Aspeed JTAG device, equipped on
++ Aspeed SoC 24xx and 25xx families. Drivers allows programming
++ of hardware devices, connected to SoC through the JTAG interface.
++
++ If you want this support, you should say Y here.
++
++ To compile this driver as a module, choose M here: the module will
++ be called jtag-aspeed.
+diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile
+index af37493..04a855e 100644
+--- a/drivers/jtag/Makefile
++++ b/drivers/jtag/Makefile
+@@ -1 +1,2 @@
+ obj-$(CONFIG_JTAG) += jtag.o
++obj-$(CONFIG_JTAG_ASPEED) += jtag-aspeed.o
+diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c
+new file mode 100644
+index 0000000..1d41a66
+--- /dev/null
++++ b/drivers/jtag/jtag-aspeed.c
+@@ -0,0 +1,1040 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018 Mellanox Technologies. All rights reserved.
++// Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com>
++// Copyright (c) 2019 Intel Corporation
++
++#include <linux/clk.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/jtag.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <uapi/linux/jtag.h>
++
++#define ASPEED_SCU_RESET_JTAG BIT(22)
++
++#define ASPEED_JTAG_DATA 0x00
++#define ASPEED_JTAG_INST 0x04
++#define ASPEED_JTAG_CTRL 0x08
++#define ASPEED_JTAG_ISR 0x0C
++#define ASPEED_JTAG_SW 0x10
++#define ASPEED_JTAG_TCK 0x14
++#define ASPEED_JTAG_EC 0x18
++
++#define ASPEED_JTAG_DATA_MSB 0x01
++#define ASPEED_JTAG_DATA_CHUNK_SIZE 0x20
++
++/* ASPEED_JTAG_CTRL: Engine Control */
++#define ASPEED_JTAG_CTL_ENG_EN BIT(31)
++#define ASPEED_JTAG_CTL_ENG_OUT_EN BIT(30)
++#define ASPEED_JTAG_CTL_FORCE_TMS BIT(29)
++#define ASPEED_JTAG_CTL_IR_UPDATE BIT(26)
++#define ASPEED_JTAG_CTL_INST_LEN(x) ((x) << 20)
++#define ASPEED_JTAG_CTL_LASPEED_INST BIT(17)
++#define ASPEED_JTAG_CTL_INST_EN BIT(16)
++#define ASPEED_JTAG_CTL_DR_UPDATE BIT(10)
++#define ASPEED_JTAG_CTL_DATA_LEN(x) ((x) << 4)
++#define ASPEED_JTAG_CTL_LASPEED_DATA BIT(1)
++#define ASPEED_JTAG_CTL_DATA_EN BIT(0)
++
++/* ASPEED_JTAG_ISR : Interrupt status and enable */
++#define ASPEED_JTAG_ISR_INST_PAUSE BIT(19)
++#define ASPEED_JTAG_ISR_INST_COMPLETE BIT(18)
++#define ASPEED_JTAG_ISR_DATA_PAUSE BIT(17)
++#define ASPEED_JTAG_ISR_DATA_COMPLETE BIT(16)
++#define ASPEED_JTAG_ISR_INST_PAUSE_EN BIT(3)
++#define ASPEED_JTAG_ISR_INST_COMPLETE_EN BIT(2)
++#define ASPEED_JTAG_ISR_DATA_PAUSE_EN BIT(1)
++#define ASPEED_JTAG_ISR_DATA_COMPLETE_EN BIT(0)
++#define ASPEED_JTAG_ISR_INT_EN_MASK GENMASK(3, 0)
++#define ASPEED_JTAG_ISR_INT_MASK GENMASK(19, 16)
++
++/* ASPEED_JTAG_SW : Software Mode and Status */
++#define ASPEED_JTAG_SW_MODE_EN BIT(19)
++#define ASPEED_JTAG_SW_MODE_TCK BIT(18)
++#define ASPEED_JTAG_SW_MODE_TMS BIT(17)
++#define ASPEED_JTAG_SW_MODE_TDIO BIT(16)
++
++/* ASPEED_JTAG_TCK : TCK Control */
++#define ASPEED_JTAG_TCK_DIVISOR_MASK GENMASK(10, 0)
++#define ASPEED_JTAG_TCK_GET_DIV(x) ((x) & ASPEED_JTAG_TCK_DIVISOR_MASK)
++
++/* ASPEED_JTAG_EC : Controller set for go to IDLE */
++#define ASPEED_JTAG_EC_GO_IDLE BIT(0)
++
++#define ASPEED_JTAG_IOUT_LEN(len) \
++ (ASPEED_JTAG_CTL_ENG_EN | \
++ ASPEED_JTAG_CTL_ENG_OUT_EN | \
++ ASPEED_JTAG_CTL_INST_LEN(len))
++
++#define ASPEED_JTAG_DOUT_LEN(len) \
++ (ASPEED_JTAG_CTL_ENG_EN | \
++ ASPEED_JTAG_CTL_ENG_OUT_EN | \
++ ASPEED_JTAG_CTL_DATA_LEN(len))
++
++#define ASPEED_JTAG_SW_TDIO (ASPEED_JTAG_SW_MODE_EN | ASPEED_JTAG_SW_MODE_TDIO)
++
++#define ASPEED_JTAG_GET_TDI(direction, byte) \
++ (((direction) & JTAG_WRITE_XFER) ? byte : UINT_MAX)
++
++#define ASPEED_JTAG_TCK_WAIT 10
++#define ASPEED_JTAG_RESET_CNTR 10
++#define WAIT_ITERATIONS 75
++
++/*#define USE_INTERRUPTS*/
++
++static const char * const regnames[] = {
++ [ASPEED_JTAG_DATA] = "ASPEED_JTAG_DATA",
++ [ASPEED_JTAG_INST] = "ASPEED_JTAG_INST",
++ [ASPEED_JTAG_CTRL] = "ASPEED_JTAG_CTRL",
++ [ASPEED_JTAG_ISR] = "ASPEED_JTAG_ISR",
++ [ASPEED_JTAG_SW] = "ASPEED_JTAG_SW",
++ [ASPEED_JTAG_TCK] = "ASPEED_JTAG_TCK",
++ [ASPEED_JTAG_EC] = "ASPEED_JTAG_EC",
++};
++
++#define ASPEED_JTAG_NAME "jtag-aspeed"
++
++struct aspeed_jtag {
++ void __iomem *reg_base;
++ struct device *dev;
++ struct clk *pclk;
++ enum jtag_endstate status;
++ int irq;
++ struct reset_control *rst;
++ u32 flag;
++ wait_queue_head_t jtag_wq;
++ u32 mode;
++};
++
++/*
++ * This structure represents a TMS cycle, as expressed in a set of bits and a
++ * count of bits (note: there are no start->end state transitions that require
++ * more than 1 byte of TMS cycles)
++ */
++struct tms_cycle {
++ unsigned char tmsbits;
++ unsigned char count;
++};
++
++/*
++ * This is the complete set TMS cycles for going from any TAP state to any
++ * other TAP state, following a "shortest path" rule.
++ */
++static const struct tms_cycle _tms_cycle_lookup[][16] = {
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* TLR */{{0x00, 0}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x02, 4}, {0x0a, 4},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x0a, 5}, {0x2a, 6}, {0x1a, 5}, {0x06, 3}, {0x06, 4}, {0x06, 5},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x16, 5}, {0x16, 6}, {0x56, 7}, {0x36, 6} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* RTI */{{0x07, 3}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, {0x03, 3}, {0x03, 4},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* SelDR*/{{0x03, 2}, {0x03, 3}, {0x00, 0}, {0x00, 1}, {0x00, 2}, {0x02, 2},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x02, 3}, {0x0a, 4}, {0x06, 3}, {0x01, 1}, {0x01, 2}, {0x01, 3},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* CapDR*/{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x00, 0}, {0x00, 1}, {0x01, 1},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* SDR */{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x00, 0}, {0x01, 1},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* Ex1DR*/{{0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x02, 3}, {0x00, 0},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x00, 1}, {0x02, 2}, {0x01, 1}, {0x07, 3}, {0x07, 4}, {0x07, 5},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* PDR */{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x01, 2}, {0x05, 3},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x00, 0}, {0x01, 1}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* Ex2DR*/{{0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x00, 1}, {0x02, 2},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x02, 3}, {0x00, 0}, {0x01, 1}, {0x07, 3}, {0x07, 4}, {0x07, 5},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* UpdDR*/{{0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x05, 4}, {0x15, 5}, {0x00, 0}, {0x03, 2}, {0x03, 3}, {0x03, 4},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* SelIR*/{{0x01, 1}, {0x01, 2}, {0x05, 3}, {0x05, 4}, {0x05, 5}, {0x15, 5},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x15, 6}, {0x55, 7}, {0x35, 6}, {0x00, 0}, {0x00, 1}, {0x00, 2},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x02, 2}, {0x02, 3}, {0x0a, 4}, {0x06, 3} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* CapIR*/{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x00, 0}, {0x00, 1},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* SIR */{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x0f, 5}, {0x00, 0},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* Ex1IR*/{{0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, {0x07, 4}, {0x02, 3},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x01, 1} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* PIR */{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x0f, 5}, {0x01, 2},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x05, 3}, {0x00, 0}, {0x01, 1}, {0x03, 2} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* Ex2IR*/{{0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, {0x07, 4}, {0x00, 1},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x02, 2}, {0x02, 3}, {0x00, 0}, {0x01, 1} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* UpdIR*/{{0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, {0x03, 3}, {0x03, 4},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x00, 0} },
++};
++
++static char *end_status_str[] = {
++ "tlr", "idle", "selDR", "capDR", "sDR", "ex1DR", "pDR", "ex2DR",
++ "updDR", "selIR", "capIR", "sIR", "ex1IR", "pIR", "ex2IR", "updIR"
++};
++
++static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg)
++{
++ u32 val = readl(aspeed_jtag->reg_base + reg);
++
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "read:%s val = 0x%08x\n", regnames[reg], val);
++#endif
++ return val;
++}
++
++static void
++aspeed_jtag_write(struct aspeed_jtag *aspeed_jtag, u32 val, u32 reg)
++{
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "write:%s val = 0x%08x\n",
++ regnames[reg], val);
++#endif
++ writel(val, aspeed_jtag->reg_base + reg);
++}
++
++static int aspeed_jtag_freq_set(struct jtag *jtag, u32 freq)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++ unsigned long apb_frq;
++ u32 tck_val;
++ u16 div;
++
++ apb_frq = clk_get_rate(aspeed_jtag->pclk);
++ if (!apb_frq)
++ return -ENOTSUPP;
++
++ div = (apb_frq - 1) / freq;
++ tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);
++ aspeed_jtag_write(aspeed_jtag,
++ (tck_val & ~ASPEED_JTAG_TCK_DIVISOR_MASK) | div,
++ ASPEED_JTAG_TCK);
++ return 0;
++}
++
++static int aspeed_jtag_freq_get(struct jtag *jtag, u32 *frq)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++ u32 pclk;
++ u32 tck;
++
++ pclk = clk_get_rate(aspeed_jtag->pclk);
++ tck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);
++ *frq = pclk / (ASPEED_JTAG_TCK_GET_DIV(tck) + 1);
++
++ return 0;
++}
++
++static inline void aspeed_jtag_output_disable(struct aspeed_jtag *aspeed_jtag)
++{
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL);
++}
++
++static inline void aspeed_jtag_master(struct aspeed_jtag *aspeed_jtag)
++{
++ aspeed_jtag_write(aspeed_jtag, (ASPEED_JTAG_CTL_ENG_EN |
++ ASPEED_JTAG_CTL_ENG_OUT_EN),
++ ASPEED_JTAG_CTRL);
++
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
++ ASPEED_JTAG_SW_MODE_TDIO,
++ ASPEED_JTAG_SW);
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_PAUSE |
++ ASPEED_JTAG_ISR_INST_COMPLETE |
++ ASPEED_JTAG_ISR_DATA_PAUSE |
++ ASPEED_JTAG_ISR_DATA_COMPLETE |
++ ASPEED_JTAG_ISR_INST_PAUSE_EN |
++ ASPEED_JTAG_ISR_INST_COMPLETE_EN |
++ ASPEED_JTAG_ISR_DATA_PAUSE_EN |
++ ASPEED_JTAG_ISR_DATA_COMPLETE_EN,
++ ASPEED_JTAG_ISR); /* Enable Interrupt */
++}
++
++static int aspeed_jtag_mode_set(struct jtag *jtag, struct jtag_mode *jtag_mode)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ switch (jtag_mode->feature) {
++ case JTAG_XFER_MODE:
++ aspeed_jtag->mode = jtag_mode->mode;
++ break;
++ case JTAG_CONTROL_MODE:
++ if (jtag_mode->mode == JTAG_MASTER_OUTPUT_DISABLE)
++ aspeed_jtag_output_disable(aspeed_jtag);
++ else if (jtag_mode->mode == JTAG_MASTER_MODE)
++ aspeed_jtag_master(aspeed_jtag);
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag,
++ u8 tms, u8 tdi)
++{
++ char tdo = 0;
++
++ /* TCK = 0 */
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
++ (tms * ASPEED_JTAG_SW_MODE_TMS) |
++ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
++
++ aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW);
++
++ /* TCK = 1 */
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
++ ASPEED_JTAG_SW_MODE_TCK |
++ (tms * ASPEED_JTAG_SW_MODE_TMS) |
++ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
++
++ if (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW) &
++ ASPEED_JTAG_SW_MODE_TDIO)
++ tdo = 1;
++
++ return tdo;
++}
++
++static int aspeed_jtag_bitbang(struct jtag *jtag,
++ struct bitbang_packet *bitbang,
++ struct tck_bitbang *bitbang_data)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++ int i = 0;
++
++ for (i = 0; i < bitbang->length; i++) {
++ bitbang_data[i].tdo =
++ aspeed_jtag_tck_cycle(aspeed_jtag, bitbang_data[i].tms,
++ bitbang_data[i].tdi);
++ }
++ return 0;
++}
++
++static int aspeed_jtag_wait_instruction_pause(struct aspeed_jtag *aspeed_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(aspeed_jtag->jtag_wq,
++ aspeed_jtag->flag &
++ ASPEED_JTAG_ISR_INST_PAUSE);
++ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_PAUSE;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & ASPEED_JTAG_ISR_INST_PAUSE) == 0) {
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, status);
++#endif
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(aspeed_jtag->dev,
++ "aspeed_jtag driver timed out waiting for instruction pause complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_PAUSE |
++ (status & 0xf),
++ ASPEED_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int
++aspeed_jtag_wait_instruction_complete(struct aspeed_jtag *aspeed_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(aspeed_jtag->jtag_wq,
++ aspeed_jtag->flag &
++ ASPEED_JTAG_ISR_INST_COMPLETE);
++ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_COMPLETE;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & ASPEED_JTAG_ISR_INST_COMPLETE) == 0) {
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, status);
++#endif
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(aspeed_jtag->dev,
++ "aspeed_jtag driver timed out waiting for instruction complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_COMPLETE |
++ (status & 0xf),
++ ASPEED_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int
++aspeed_jtag_wait_data_pause_complete(struct aspeed_jtag *aspeed_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(aspeed_jtag->jtag_wq,
++ aspeed_jtag->flag &
++ ASPEED_JTAG_ISR_DATA_PAUSE);
++ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_PAUSE;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & ASPEED_JTAG_ISR_DATA_PAUSE) == 0) {
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, status);
++#endif
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(aspeed_jtag->dev,
++ "aspeed_jtag driver timed out waiting for data pause complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_DATA_PAUSE |
++ (status & 0xf), ASPEED_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int aspeed_jtag_wait_data_complete(struct aspeed_jtag *aspeed_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(aspeed_jtag->jtag_wq,
++ aspeed_jtag->flag &
++ ASPEED_JTAG_ISR_DATA_COMPLETE);
++ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_COMPLETE;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, status);
++#endif
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(aspeed_jtag->dev,
++ "ast_jtag driver timed out waiting for data complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_ISR_DATA_COMPLETE | (status & 0xf),
++ ASPEED_JTAG_ISR);
++#endif
++ return res;
++}
++
++static void aspeed_jtag_set_tap_state(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_endstate endstate)
++{
++ int i = 0;
++ enum jtag_endstate from, to;
++
++ 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;
++}
++
++static void aspeed_jtag_end_tap_state_sw(struct aspeed_jtag *aspeed_jtag,
++ struct jtag_end_tap_state *endstate)
++{
++ /* SW mode from curent tap state -> to end_state */
++ if (endstate->reset) {
++ int i = 0;
++
++ for (i = 0; i < ASPEED_JTAG_RESET_CNTR; i++)
++ aspeed_jtag_tck_cycle(aspeed_jtag, 1, 0);
++ aspeed_jtag->status = JTAG_STATE_TLRESET;
++ }
++
++ aspeed_jtag_set_tap_state(aspeed_jtag, endstate->endstate);
++}
++
++static int aspeed_jtag_status_set(struct jtag *jtag,
++ struct jtag_end_tap_state *endstate)
++{
++ 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]);
++#endif
++
++ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
++ aspeed_jtag_end_tap_state_sw(aspeed_jtag, endstate);
++ return 0;
++ }
++
++ /* x TMS high + 1 TMS low */
++ if (endstate->reset) {
++ /* Disable sw mode */
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
++ mdelay(1);
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_CTL_ENG_EN |
++ ASPEED_JTAG_CTL_ENG_OUT_EN |
++ ASPEED_JTAG_CTL_FORCE_TMS, ASPEED_JTAG_CTRL);
++ mdelay(1);
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_SW_TDIO, ASPEED_JTAG_SW);
++ aspeed_jtag->status = JTAG_STATE_TLRESET;
++ }
++
++ return 0;
++}
++
++static void aspeed_jtag_xfer_sw(struct aspeed_jtag *aspeed_jtag,
++ struct jtag_xfer *xfer, u32 *data)
++{
++ unsigned long remain_xfer = xfer->length;
++ unsigned long shift_bits = 0;
++ unsigned long index = 0;
++ unsigned long tdi;
++ char tdo;
++
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "SW JTAG SHIFT %s, length = %d\n",
++ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length);
++#endif
++
++ if (xfer->type == JTAG_SIR_XFER)
++ aspeed_jtag_set_tap_state(aspeed_jtag, JTAG_STATE_SHIFTIR);
++ else
++ aspeed_jtag_set_tap_state(aspeed_jtag, JTAG_STATE_SHIFTDR);
++
++ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]);
++ data[index] = 0;
++ while (remain_xfer > 1) {
++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0,
++ tdi & ASPEED_JTAG_DATA_MSB);
++ data[index] |= tdo << (shift_bits %
++ ASPEED_JTAG_DATA_CHUNK_SIZE);
++ tdi >>= 1;
++ shift_bits++;
++ remain_xfer--;
++
++ if (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE == 0) {
++ tdo = 0;
++ index++;
++ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]);
++ data[index] = 0;
++ }
++ }
++
++ if ((xfer->endstate == (xfer->type == JTAG_SIR_XFER ?
++ JTAG_STATE_SHIFTIR : JTAG_STATE_SHIFTDR))) {
++ /* Stay in Shift IR/DR*/
++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0,
++ tdi & ASPEED_JTAG_DATA_MSB);
++ data[index] |= tdo << (shift_bits %
++ ASPEED_JTAG_DATA_CHUNK_SIZE);
++ } else {
++ /* Goto end state */
++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 1,
++ tdi & ASPEED_JTAG_DATA_MSB);
++ data[index] |= tdo << (shift_bits %
++ 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);
++ }
++}
++
++static int aspeed_jtag_xfer_push_data(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_xfer_type type, u32 bits_len)
++{
++ int res = 0;
++
++ if (type == JTAG_SIR_XFER) {
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len),
++ ASPEED_JTAG_CTRL);
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len) |
++ ASPEED_JTAG_CTL_INST_EN, ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_instruction_pause(aspeed_jtag);
++ } else {
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len),
++ ASPEED_JTAG_CTRL);
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len) |
++ ASPEED_JTAG_CTL_DATA_EN, ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_data_pause_complete(aspeed_jtag);
++ }
++ return res;
++}
++
++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)
++{
++ int res = 0;
++
++ if (type == JTAG_SIR_XFER) {
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_IOUT_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_LASPEED_INST,
++ ASPEED_JTAG_CTRL);
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_IOUT_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_LASPEED_INST |
++ ASPEED_JTAG_CTL_INST_EN,
++ ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_instruction_complete(aspeed_jtag);
++ } else {
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_DOUT_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_LASPEED_DATA,
++ ASPEED_JTAG_CTRL);
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_DOUT_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_LASPEED_DATA |
++ ASPEED_JTAG_CTL_DATA_EN,
++ ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_data_complete(aspeed_jtag);
++ }
++ return res;
++}
++
++static int aspeed_jtag_xfer_hw(struct aspeed_jtag *aspeed_jtag,
++ struct jtag_xfer *xfer, u32 *data)
++{
++ unsigned long remain_xfer = xfer->length;
++ unsigned long index = 0;
++ char shift_bits;
++ u32 data_reg;
++ u32 scan_end;
++
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "HW JTAG SHIFT %s, length = %d\n",
++ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length);
++#endif
++ data_reg = xfer->type == JTAG_SIR_XFER ?
++ ASPEED_JTAG_INST : ASPEED_JTAG_DATA;
++ if (xfer->endstate == JTAG_STATE_SHIFTIR ||
++ xfer->endstate == JTAG_STATE_SHIFTDR ||
++ xfer->endstate == JTAG_STATE_PAUSEIR ||
++ xfer->endstate == JTAG_STATE_PAUSEDR) {
++ scan_end = 0;
++ } else {
++ scan_end = 1;
++ }
++
++ while (remain_xfer) {
++ if (xfer->direction & JTAG_WRITE_XFER)
++ aspeed_jtag_write(aspeed_jtag, data[index], data_reg);
++ else
++ aspeed_jtag_write(aspeed_jtag, 0, data_reg);
++
++ if (remain_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) {
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev,
++ "Chunk len=%d chunk_size=%d remain_xfer=%lu\n",
++ xfer->length, ASPEED_JTAG_DATA_CHUNK_SIZE,
++ remain_xfer);
++#endif
++ shift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE;
++
++ /*
++ * Transmit bytes that were not equals to column length
++ * and after the transfer go to Pause IR/DR.
++ */
++ if (aspeed_jtag_xfer_push_data(aspeed_jtag, xfer->type,
++ shift_bits) != 0) {
++ return -EFAULT;
++ }
++ } else {
++ /*
++ * Read bytes equals to column length
++ */
++ shift_bits = remain_xfer;
++ if (scan_end) {
++ /*
++ * If this data is the end of the transmission
++ * send remaining bits and go to endstate
++ */
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev,
++ "Last len=%d chunk_size=%d remain_xfer=%lu\n",
++ xfer->length,
++ ASPEED_JTAG_DATA_CHUNK_SIZE,
++ remain_xfer);
++#endif
++ if (aspeed_jtag_xfer_push_data_last(
++ aspeed_jtag,
++ xfer->type,
++ shift_bits,
++ xfer->endstate) != 0) {
++ return -EFAULT;
++ }
++ } else {
++ /*
++ * If transmission is waiting for additional
++ * data send remaining bits and then go to
++ * Pause IR/DR.
++ */
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev,
++ "Tail len=%d chunk_size=%d remain_xfer=%lu\n",
++ xfer->length,
++ ASPEED_JTAG_DATA_CHUNK_SIZE,
++ remain_xfer);
++#endif
++ if (aspeed_jtag_xfer_push_data(aspeed_jtag,
++ xfer->type,
++ shift_bits)
++ != 0) {
++ return -EFAULT;
++ }
++ }
++ }
++
++ if (xfer->direction & JTAG_READ_XFER) {
++ if (shift_bits < ASPEED_JTAG_DATA_CHUNK_SIZE) {
++ data[index] = aspeed_jtag_read(aspeed_jtag,
++ data_reg);
++
++ data[index] >>= ASPEED_JTAG_DATA_CHUNK_SIZE -
++ shift_bits;
++ } else {
++ data[index] = aspeed_jtag_read(aspeed_jtag,
++ data_reg);
++ }
++ }
++
++ remain_xfer = remain_xfer - shift_bits;
++ index++;
++ }
++ return 0;
++}
++
++static int aspeed_jtag_xfer(struct jtag *jtag, struct jtag_xfer *xfer,
++ u8 *xfer_data)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
++ /* SW mode */
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_TDIO,
++ ASPEED_JTAG_SW);
++
++ aspeed_jtag_xfer_sw(aspeed_jtag, xfer, (u32 *)xfer_data);
++ } else {
++ /* HW mode */
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
++ if (aspeed_jtag_xfer_hw(aspeed_jtag, xfer,
++ (u32 *)xfer_data) != 0)
++ return -EFAULT;
++ }
++
++ aspeed_jtag->status = xfer->endstate;
++ return 0;
++}
++
++static int aspeed_jtag_status_get(struct jtag *jtag, u32 *status)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ *status = aspeed_jtag->status;
++ return 0;
++}
++
++#ifdef USE_INTERRUPTS
++static irqreturn_t aspeed_jtag_interrupt(s32 this_irq, void *dev_id)
++{
++ struct aspeed_jtag *aspeed_jtag = dev_id;
++ irqreturn_t ret = IRQ_HANDLED;
++ u32 status;
++
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++
++ if (status & ASPEED_JTAG_ISR_INT_MASK) {
++ aspeed_jtag_write(aspeed_jtag,
++ (status & ASPEED_JTAG_ISR_INT_MASK)
++ | (status & ASPEED_JTAG_ISR_INT_EN_MASK),
++ ASPEED_JTAG_ISR);
++ aspeed_jtag->flag |= status & ASPEED_JTAG_ISR_INT_MASK;
++ }
++
++ if (aspeed_jtag->flag) {
++ wake_up_interruptible(&aspeed_jtag->jtag_wq);
++ ret = IRQ_HANDLED;
++ } else {
++ dev_err(aspeed_jtag->dev, "irq status:%x\n",
++ status);
++ ret = IRQ_NONE;
++ }
++ return ret;
++}
++#endif
++
++static int aspeed_jtag_enable(struct jtag *jtag)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ aspeed_jtag_master(aspeed_jtag);
++ return 0;
++}
++
++static int aspeed_jtag_disable(struct jtag *jtag)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ aspeed_jtag_output_disable(aspeed_jtag);
++ return 0;
++}
++
++static int aspeed_jtag_init(struct platform_device *pdev,
++ struct aspeed_jtag *aspeed_jtag)
++{
++ struct resource *res;
++#ifdef USE_INTERRUPTS
++ int err;
++#endif
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ aspeed_jtag->reg_base = devm_ioremap_resource(aspeed_jtag->dev, res);
++ if (IS_ERR(aspeed_jtag->reg_base))
++ return -ENOMEM;
++
++ aspeed_jtag->pclk = devm_clk_get(aspeed_jtag->dev, NULL);
++ if (IS_ERR(aspeed_jtag->pclk)) {
++ dev_err(aspeed_jtag->dev, "devm_clk_get failed\n");
++ return PTR_ERR(aspeed_jtag->pclk);
++ }
++
++#ifdef USE_INTERRUPTS
++ aspeed_jtag->irq = platform_get_irq(pdev, 0);
++ if (aspeed_jtag->irq < 0) {
++ dev_err(aspeed_jtag->dev, "no irq specified\n");
++ return -ENOENT;
++ }
++#endif
++
++ if (clk_prepare_enable(aspeed_jtag->pclk)) {
++ dev_err(aspeed_jtag->dev, "no irq specified\n");
++ return -ENOENT;
++ }
++
++ aspeed_jtag->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
++ if (IS_ERR(aspeed_jtag->rst)) {
++ dev_err(aspeed_jtag->dev,
++ "missing or invalid reset controller device tree entry");
++ return PTR_ERR(aspeed_jtag->rst);
++ }
++ reset_control_deassert(aspeed_jtag->rst);
++
++#ifdef USE_INTERRUPTS
++ err = devm_request_irq(aspeed_jtag->dev, aspeed_jtag->irq,
++ aspeed_jtag_interrupt, 0,
++ "aspeed-jtag", aspeed_jtag);
++ if (err) {
++ dev_err(aspeed_jtag->dev, "unable to get IRQ");
++ clk_disable_unprepare(aspeed_jtag->pclk);
++ return err;
++ }
++#endif
++
++ aspeed_jtag_output_disable(aspeed_jtag);
++
++ aspeed_jtag->flag = 0;
++ aspeed_jtag->mode = 0;
++ init_waitqueue_head(&aspeed_jtag->jtag_wq);
++ return 0;
++}
++
++static int aspeed_jtag_deinit(struct platform_device *pdev,
++ struct aspeed_jtag *aspeed_jtag)
++{
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_ISR);
++ /* Disable clock */
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL);
++ reset_control_assert(aspeed_jtag->rst);
++ clk_disable_unprepare(aspeed_jtag->pclk);
++ return 0;
++}
++
++static const struct jtag_ops aspeed_jtag_ops = {
++ .freq_get = aspeed_jtag_freq_get,
++ .freq_set = aspeed_jtag_freq_set,
++ .status_get = aspeed_jtag_status_get,
++ .status_set = aspeed_jtag_status_set,
++ .xfer = aspeed_jtag_xfer,
++ .mode_set = aspeed_jtag_mode_set,
++ .bitbang = aspeed_jtag_bitbang,
++ .enable = aspeed_jtag_enable,
++ .disable = aspeed_jtag_disable
++};
++
++static int aspeed_jtag_probe(struct platform_device *pdev)
++{
++ struct aspeed_jtag *aspeed_jtag;
++ struct jtag *jtag;
++ int err;
++
++ jtag = jtag_alloc(&pdev->dev, sizeof(*aspeed_jtag), &aspeed_jtag_ops);
++ if (!jtag)
++ return -ENOMEM;
++
++ platform_set_drvdata(pdev, jtag);
++ aspeed_jtag = jtag_priv(jtag);
++ aspeed_jtag->dev = &pdev->dev;
++
++ /* Initialize device*/
++ err = aspeed_jtag_init(pdev, aspeed_jtag);
++ if (err)
++ goto err_jtag_init;
++
++ /* Initialize JTAG core structure*/
++ err = devm_jtag_register(aspeed_jtag->dev, jtag);
++ if (err)
++ goto err_jtag_register;
++
++ return 0;
++
++err_jtag_register:
++ aspeed_jtag_deinit(pdev, aspeed_jtag);
++err_jtag_init:
++ jtag_free(jtag);
++ return err;
++}
++
++static int aspeed_jtag_remove(struct platform_device *pdev)
++{
++ struct jtag *jtag = platform_get_drvdata(pdev);
++
++ aspeed_jtag_deinit(pdev, jtag_priv(jtag));
++ return 0;
++}
++
++static const struct of_device_id aspeed_jtag_of_match[] = {
++ { .compatible = "aspeed,ast2400-jtag", },
++ { .compatible = "aspeed,ast2500-jtag", },
++ {}
++};
++
++static struct platform_driver aspeed_jtag_driver = {
++ .probe = aspeed_jtag_probe,
++ .remove = aspeed_jtag_remove,
++ .driver = {
++ .name = ASPEED_JTAG_NAME,
++ .of_match_table = aspeed_jtag_of_match,
++ },
++};
++module_platform_driver(aspeed_jtag_driver);
++
++MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>");
++MODULE_DESCRIPTION("ASPEED JTAG driver");
++MODULE_LICENSE("GPL v2");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch
new file mode 100644
index 000000000..f17bdcd68
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch
@@ -0,0 +1,108 @@
+From 2a22feac440070b7feaf0a6fe7e7e555d57ca19b Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Wed, 10 Mar 2019 11:45:04 -0800
+Subject: [PATCH v29 3/6] Documentation: jtag: Add bindings for Aspeed SoC
+ 24xx and 25xx families JTAG master driver
+
+It has been tested on Mellanox system with BMC equipped with
+Aspeed 2520 SoC for programming CPLD devices.
+
+It also has been tested on Intel systems with BMC equipped with
+Aspeed 25x0 SoC for JTAG board communication.
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Joel Stanley <joel@jms.id.au>
+Cc: Andrew Jeffery <andrew@aj.id.au>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+v28->v29
+v27->v28
+v26->v27
+v25->v26
+v24->v25
+v23->v24
+v22->v23
+v21->v22
+v20->v21
+v19->v20
+v18->v19
+
+v17->v18
+v16->v17
+v15->v16
+Comments pointed by Joel Stanley <joel.stan@gmail.com>
+- change clocks = <&clk_apb> to proper clocks = <&syscon ASPEED_CLK_APB>
+- add reset descriptions in bindings file
+
+v14->v15
+v13->v14
+v12->v13
+v11->v12
+v10->v11
+v9->v10
+v8->v9
+v7->v8
+Comments pointed by pointed by Joel Stanley <joel.stan@gmail.com>
+- Change compatible string to ast2400 and ast2000
+
+V6->v7
+Comments pointed by Tobias Klauser <tklauser@distanz.ch>
+ - Fix spell "Doccumentation" -> "Documentation"
+
+v5->v6
+Comments pointed by Tobias Klauser <tklauser@distanz.ch>
+- Small nit: s/documentation/Documentation/
+
+v4->v5
+
+V3->v4
+Comments pointed by Rob Herring <robh@kernel.org>
+- delete unnecessary "status" and "reg-shift" descriptions in
+ bindings file
+
+v2->v3
+Comments pointed by Rob Herring <robh@kernel.org>
+- split Aspeed jtag driver and binding to separate patches
+- delete unnecessary "status" and "reg-shift" descriptions in
+ bindings file
+---
+ .../devicetree/bindings/jtag/aspeed-jtag.txt | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
+
+diff --git a/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt b/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
+new file mode 100644
+index 0000000..7c36eb6
+--- /dev/null
++++ b/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
+@@ -0,0 +1,22 @@
++Aspeed JTAG driver for ast2400 and ast2500 SoC
++
++Required properties:
++- compatible: Should be one of
++ - "aspeed,ast2400-jtag"
++ - "aspeed,ast2500-jtag"
++- reg contains the offset and length of the JTAG memory
++ region
++- clocks root clock of bus, should reference the APB
++ clock in the second cell
++- resets phandle to reset controller with the reset number in
++ the second cell
++- interrupts should contain JTAG controller interrupt
++
++Example:
++jtag: jtag@1e6e4000 {
++ compatible = "aspeed,ast2500-jtag";
++ reg = <0x1e6e4000 0x1c>;
++ clocks = <&syscon ASPEED_CLK_APB>;
++ resets = <&syscon ASPEED_RESET_JTAG_MASTER>;
++ interrupts = <43>;
++};
+--
+2.7.4
+
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
new file mode 100644
index 000000000..af641ffe2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch
@@ -0,0 +1,303 @@
+From c2d57900820475b50affd171f4dc423a278887ae Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Wed, 10 Mar 2019 11:47:40 -0800
+Subject: [PATCH v29 4/6] Documentation: jtag: Add ABI documentation
+
+Added document that describe the ABI for JTAG class driver
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Jiri Pirko <jiri@mellanox.com>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+v28->v29
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Expand bitbang function to accept multiples bitbang operations within a
+ single JTAG_IOCBITBANG call. It will receive a buffer with TDI and TMS
+ values and it is expected that driver fills TDO fields with its
+ corresponding output value for every transaction.
+
+v27->v28
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Replace JTAG_IOCRUNTEST with JTAG_SIOCSTATE adding support for all TAPC
+ end states in SW mode using a lookup table to navigate across states.
+- Add support for simultaneous READ/WRITE transfers(JTAG_READ_WRITE_XFER).
+- Support for switching JTAG controller mode between slave and master
+ mode.
+- Setup JTAG controller mode to master only when the driver is opened,
+ letting other HW to own the JTAG bus when it isn't in use.
+- Include JTAG bit bang IOCTL for low level JTAG control usage
+ (JTAG_IOCBITBANG).
+
+v26->v27
+v25->v26
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- fix spell in ABI documentation
+
+v24->v25
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- Fixed documentation according to new open() behavior
+
+v23->v24
+v22->v23
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- fix spell in ABI doccumentation
+
+v21->v22
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- fix spell in ABI doccumentation
+
+v20->v21
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- Fix JTAG dirver help in Kconfig
+
+v19->v20
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- Fix JTAG doccumentation
+
+v18->v19
+Pavel Machek <pavel@ucw.cz>
+- Added JTAG doccumentation to Documentation/jtag
+
+v17->v18
+v16->v17
+v15->v16
+v14->v15
+v13->v14
+v12->v13
+v11->v12 Tobias Klauser <tklauser@distanz.ch>
+Comments pointed by
+- rename /Documentation/ABI/testing/jatg-dev -> jtag-dev
+- Typo: s/interfase/interface
+v10->v11
+v9->v10
+Fixes added by Oleksandr:
+- change jtag-cdev to jtag-dev in documentation
+- update KernelVersion and Date in jtag-dev documentation;
+v8->v9
+v7->v8
+v6->v7
+Comments pointed by Pavel Machek <pavel@ucw.cz>
+- Added jtag-cdev documentation to Documentation/ABI/testing folder
+---
+ Documentation/ABI/testing/jtag-dev | 23 +++++++
+ Documentation/jtag/overview | 27 ++++++++
+ Documentation/jtag/transactions | 138 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 188 insertions(+)
+ create mode 100644 Documentation/ABI/testing/jtag-dev
+ create mode 100644 Documentation/jtag/overview
+ create mode 100644 Documentation/jtag/transactions
+
+diff --git a/Documentation/ABI/testing/jtag-dev b/Documentation/ABI/testing/jtag-dev
+new file mode 100644
+index 0000000..423baab
+--- /dev/null
++++ b/Documentation/ABI/testing/jtag-dev
+@@ -0,0 +1,23 @@
++What: /dev/jtag[0-9]+
++Date: July 2018
++KernelVersion: 4.20
++Contact: oleksandrs@mellanox.com
++Description:
++ The misc device files /dev/jtag* are the interface
++ between JTAG master interface and userspace.
++
++ The ioctl(2)-based ABI is defined and documented in
++ [include/uapi]<linux/jtag.h>.
++
++ The following file operations are supported:
++
++ open(2)
++ Opens and allocates file descriptor.
++
++ ioctl(2)
++ Initiate various actions.
++ See the inline documentation in [include/uapi]<linux/jtag.h>
++ for descriptions of all ioctls.
++
++Users:
++ userspace tools which wants to access to JTAG bus
+diff --git a/Documentation/jtag/overview b/Documentation/jtag/overview
+new file mode 100644
+index 0000000..6a5ec33
+--- /dev/null
++++ b/Documentation/jtag/overview
+@@ -0,0 +1,27 @@
++Linux kernel JTAG support
++=========================
++
++JTAG is an industry standard for verifying hardware. JTAG provides access to
++many logic signals of a complex integrated circuit, including the device pins.
++
++A JTAG interface is a special interface added to a chip.
++Depending on the version of JTAG, two, four, or five pins are added.
++
++The connector pins are:
++ TDI (Test Data In)
++ TDO (Test Data Out)
++ TCK (Test Clock)
++ TMS (Test Mode Select)
++ TRST (Test Reset) optional
++
++JTAG interface is designed to have two parts - basic core driver and
++hardware specific driver. The basic driver introduces a general interface
++which is not dependent of specific hardware. It provides communication
++between user space and hardware specific driver.
++Each JTAG device is represented as a char device from (jtag0, jtag1, ...).
++Access to a JTAG device is performed through IOCTL calls.
++
++Call flow example:
++User: open -> /dev/jatgX -> JTAG core driver -> JTAG hardware specific driver
++User: ioctl -> /dev/jtagX -> JTAG core driver -> JTAG hardware specific driver
++User: close -> /dev/jatgX -> JTAG core driver -> JTAG hardware specific driver
+diff --git a/Documentation/jtag/transactions b/Documentation/jtag/transactions
+new file mode 100644
+index 0000000..76fd0b1
+--- /dev/null
++++ b/Documentation/jtag/transactions
+@@ -0,0 +1,138 @@
++The JTAG API
++=============
++
++JTAG master devices can be accessed through a character misc-device.
++Each JTAG master interface can be accessed by using /dev/jtagN.
++
++JTAG system calls set:
++- SIR (Scan Instruction Register, IEEE 1149.1 Instruction Register scan);
++- SDR (Scan Data Register, IEEE 1149.1 Data Register scan);
++- RUNTEST (Forces the IEEE 1149.1 bus to a run state for a specified
++number of clocks.
++
++open(), close()
++-------
++open() opens JTAG device.
++
++Open/Close device:
++- jtag_fd = open("/dev/jtag0", O_RDWR);
++- close(jtag_fd);
++
++ioctl()
++-------
++All access operations to JTAG devices are performed through ioctl interface.
++The IOCTL interface supports these requests:
++ JTAG_SIOCSTATE - Force JTAG state machine to go into a TAPC state
++ JTAG_SIOCFREQ - Set JTAG TCK frequency
++ JTAG_GIOCFREQ - Get JTAG TCK frequency
++ JTAG_IOCXFER - send/receive JTAG data Xfer
++ JTAG_GIOCSTATUS - get current JTAG TAP state
++ JTAG_SIOCMODE - set JTAG mode flags.
++ JTAG_IOCBITBANG - JTAG bitbang low level control.
++
++JTAG_SIOCFREQ, JTAG_GIOCFREQ
++------
++Set/Get JTAG clock speed:
++
++ unsigned int jtag_fd;
++ ioctl(jtag_fd, JTAG_SIOCFREQ, &frq);
++ ioctl(jtag_fd, JTAG_GIOCFREQ, &frq);
++
++JTAG_SIOCSTATE
++------
++Force JTAG state machine to go into a TAPC state
++
++struct jtag_end_tap_state {
++ __u8 reset;
++ __u8 endstate;
++ __u8 tck;
++};
++
++reset:
++ JTAG_NO_RESET - go through selected endstate from current state
++ JTAG_FORCE_RESET - go through TEST_LOGIC/RESET state before selected endstate
++endstate: completion flag
++tck: clock counter
++
++Example:
++ struct jtag_end_tap_state end_state;
++
++ end_state.endstate = JTAG_STATE_IDLE;
++ end_state.reset = 0;
++ end_state.tck = data_p->tck;
++ usleep(25 * 1000);
++ ioctl(jtag_fd, JTAG_SIOCSTATE, &end_state);
++
++JTAG_GIOCSTATUS
++------
++Get JTAG TAPC machine state
++
++ unsigned int jtag_fd;
++ jtag_endstate endstate;
++ ioctl(jtag_fd, JTAG_GIOCSTATUS, &endstate);
++
++JTAG_IOCXFER
++------
++Send SDR/SIR transaction
++
++struct jtag_xfer {
++ __u8 type;
++ __u8 direction;
++ __u8 endstate;
++ __u8 padding;
++ __u32 length;
++ __u64 tdio;
++};
++
++type: transfer type - JTAG_SIR_XFER/JTAG_SDR_XFER
++direction: xfer direction - JTAG_READ_XFER/JTAG_WRITE_XFER/JTAG_READ_WRITE_XFER
++length: xfer data length in bits
++tdio : xfer data array
++endstate: xfer end state after transaction finish
++ can be: any state listed in jtag_endstate struct
++
++Example:
++ struct jtag_xfer xfer;
++ static char buf[64];
++ static unsigned int buf_len = 0;
++ [...]
++ xfer.type = JTAG_SDR_XFER;
++ xfer.tdio = (__u64)buf;
++ xfer.length = buf_len;
++ xfer.endstate = JTAG_STATE_IDLE;
++
++ if (is_read)
++ xfer.direction = JTAG_READ_XFER;
++ else if (is_write)
++ xfer.direction = JTAG_WRITE_XFER;
++ else
++ xfer.direction = JTAG_READ_WRITE_XFER;
++
++ ioctl(jtag_fd, JTAG_IOCXFER, &xfer);
++
++JTAG_SIOCMODE
++------
++If hardware driver can support different running modes you can change it.
++
++Example:
++ struct jtag_mode mode;
++ mode.feature = JTAG_XFER_MODE;
++ mode.mode = JTAG_XFER_HW_MODE;
++ ioctl(jtag_fd, JTAG_SIOCMODE, &mode);
++
++JTAG_IOCBITBANG
++------
++JTAG Bitbang low level operation.
++
++Example:
++ struct bitbang_packet bitbang;
++ struct tck_bitbang bitbang_data[2];
++ bitbang_data[0].tms = 0;
++ bitbang_data[0].tdi = 1;
++ bitbang_data[1].tms = 0;
++ bitbang_data[1].tdi = 1;
++ bitbang.data = bitbang_data;
++ bitbang.length = 2;
++ ioctl(jtag_fd, JTAG_IOCBITBANG, &bitbang);
++ tdo0 = bitbang_data[0].tdo;
++ tdo1 = bitbang_data[1].tdo;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch
new file mode 100644
index 000000000..a7dccc4b6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch
@@ -0,0 +1,57 @@
+From ba0c35ae070cffcb384fc76e23a38e00142b128d Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Wed, 10 Mar 2019 11:48:18 -0800
+Subject: [PATCH v29 5/6] Documentation jtag: Add JTAG core driver ioctl number
+
+JTAG class driver provide infrastructure to support hardware/software
+JTAG platform drivers. It provide user layer API interface for flashing
+and debugging external devices which equipped with JTAG interface
+using standard transactions.
+
+Driver exposes set of IOCTL to user space for:
+- XFER:
+ SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan);
+ SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan);
+- GIOCSTATUS read the current TAPC state of the JTAG controller
+- SIOCSTATE Forces the JTAG TAPC to go into a particular state.
+- SIOCFREQ/GIOCFREQ for setting and reading JTAG frequency.
+- IOCBITBANG for low level control of JTAG signals.
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Philippe Ombredanne <pombredanne@nexb.com>
+Cc: Jiri Pirko <jiri@mellanox.com>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Kishon Vijay Abraham I <kishon@ti.com>
+Cc: Darrick J. Wong <darrick.wong@oracle.com>
+Cc: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+Cc: Eric Sandeen <sandeen@redhat.com>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+ Documentation/ioctl/ioctl-number.txt | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
+index c955814..f732118 100644
+--- a/Documentation/ioctl/ioctl-number.txt
++++ b/Documentation/ioctl/ioctl-number.txt
+@@ -323,6 +323,8 @@ Code Seq#(hex) Include File Comments
+ 0xB0 all RATIO devices in development:
+ <mailto:vgo@ratio.de>
+ 0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
++0xB2 00-0F linux/jtag.h JTAG driver
++ <mailto:oleksandrs@mellanox.com>
+ 0xB3 00 linux/mmc/ioctl.h
+ 0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org>
+ 0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org>
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch
new file mode 100644
index 000000000..8ab4615f0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch
@@ -0,0 +1,50 @@
+From 0a563429bc3c34a951db92600681e799b606a01f Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Wed, 10 Mar 2019 11:49:37 -0800
+Subject: [PATCH v29 6/6] drivers: jtag: Add JTAG core driver Maintainers
+
+JTAG class driver provide infrastructure to support hardware/software
+JTAG platform drivers. It provide user layer API interface for flashing
+and debugging external devices which equipped with JTAG interface
+using standard transactions.
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Jiri Pirko <jiri@mellanox.com>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: David S. Miller <davem@davemloft.net>
+Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+ MAINTAINERS | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index dce5c09..eb710a6 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -8173,6 +8173,17 @@ L: linux-serial@vger.kernel.org
+ S: Orphan
+ F: drivers/tty/serial/jsm/
+
++JTAG SUBSYSTEM
++M: Oleksandr Shamray <oleksandrs@mellanox.com>
++M: Vadim Pasternak <vadimp@mellanox.com>
++M Ernesto Corona <ernesto.corona@intel.com>
++S: Maintained
++F: include/linux/jtag.h
++F: include/uapi/linux/jtag.h
++F: drivers/jtag/
++F: Documentation/devicetree/bindings/jtag/
++F: Documentation/ABI/testing/jtag-dev
++
+ K10TEMP HARDWARE MONITORING DRIVER
+ M: Clemens Ladisch <clemens@ladisch.de>
+ L: linux-hwmon@vger.kernel.org
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch
new file mode 100644
index 000000000..de8bf2355
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch
@@ -0,0 +1,182 @@
+From 551b5192b1074679ca9411cdedb9137d38f7de3d Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 1 May 2019 13:27:34 -0700
+Subject: [PATCH] i2c: aspeed: add general call support
+
+This commit adds general call support into Aspeed I2C driver.
+This is downstream only customization so it should not go into
+upstream.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ .../devicetree/bindings/i2c/i2c-aspeed.txt | 1 +
+ drivers/i2c/busses/i2c-aspeed.c | 39 ++++++++++++++++++++++
+ drivers/i2c/i2c-slave-mqueue.c | 4 ++-
+ include/linux/i2c.h | 1 +
+ 4 files changed, 44 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+index 7da7e813b2b0..724ee9f35c10 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+@@ -16,6 +16,7 @@ Optional Properties:
+ - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not
+ specified
+ - multi-master : states that there is another master active on this bus.
++- general-call : enables general call receiving.
+ - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not
+ specified.
+ - #retries : Number of retries for master transfer.
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index 0060193e1aa4..f96160e01a69 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -50,6 +50,7 @@
+ #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8)
+ #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7)
+ #define ASPEED_I2CD_M_HIGH_SPEED_EN BIT(6)
++#define ASPEED_I2CD_GCALL_EN BIT(2)
+ #define ASPEED_I2CD_SLAVE_EN BIT(1)
+ #define ASPEED_I2CD_MASTER_EN BIT(0)
+
+@@ -74,6 +75,7 @@
+ */
+ #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14)
+ #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13)
++#define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8)
+ #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7)
+ #define ASPEED_I2CD_INTR_SCL_TIMEOUT BIT(6)
+ #define ASPEED_I2CD_INTR_ABNORMAL BIT(5)
+@@ -133,6 +135,8 @@ enum aspeed_i2c_slave_state {
+ ASPEED_I2C_SLAVE_READ_PROCESSED,
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED,
+ ASPEED_I2C_SLAVE_WRITE_RECEIVED,
++ ASPEED_I2C_SLAVE_GCALL_START,
++ ASPEED_I2C_SLAVE_GCALL_REQUESTED,
+ ASPEED_I2C_SLAVE_STOP,
+ };
+
+@@ -163,6 +167,8 @@ struct aspeed_i2c_bus {
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+ struct i2c_client *slave;
+ enum aspeed_i2c_slave_state slave_state;
++ /* General call */
++ bool general_call;
+ #endif /* CONFIG_I2C_SLAVE */
+ };
+
+@@ -267,6 +273,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ bus->slave_state = ASPEED_I2C_SLAVE_START;
+ }
+
++ /* General call was requested, restart state machine. */
++ if (irq_status & ASPEED_I2CD_INTR_GCALL_ADDR) {
++ irq_handled |= ASPEED_I2CD_INTR_GCALL_ADDR;
++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_START;
++ }
++
+ /* Slave is not currently active, irq was for someone else. */
+ if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)
+ return irq_handled;
+@@ -285,6 +297,21 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ else
+ bus->slave_state =
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED;
++ } else if (bus->slave_state == ASPEED_I2C_SLAVE_GCALL_START) {
++ /*
++ * I2C spec defines the second byte meaning like below.
++ * 0x06 : Reset and write programmable part of slave
++ * address by hardware.
++ * 0x04 : Write programmable part of slave address by
++ * hardware.
++ * 0x00 : No allowed.
++ *
++ * But in OpenBMC, we are going to use this
++ * 'General call' feature for IPMB message broadcasting
++ * so it delivers all data as is without any specific
++ * handling of the second byte.
++ */
++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_REQUESTED;
+ }
+ irq_handled |= ASPEED_I2CD_INTR_RX_DONE;
+ }
+@@ -324,6 +351,10 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED;
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
+ break;
++ case ASPEED_I2C_SLAVE_GCALL_REQUESTED:
++ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED;
++ i2c_slave_event(slave, I2C_SLAVE_GCALL_REQUESTED, &value);
++ break;
+ case ASPEED_I2C_SLAVE_WRITE_RECEIVED:
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value);
+ break;
+@@ -332,6 +363,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
+ break;
+ case ASPEED_I2C_SLAVE_START:
++ case ASPEED_I2C_SLAVE_GCALL_START:
+ /* Slave was just started. Waiting for the next event. */;
+ break;
+ default:
+@@ -739,6 +771,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr)
+ /* Turn on slave mode. */
+ func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN;
++ if (bus->general_call)
++ func_ctrl_reg_val |= ASPEED_I2CD_GCALL_EN;
+ writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ }
+
+@@ -777,6 +811,8 @@ static int aspeed_i2c_unreg_slave(struct i2c_client *client)
+ /* Turn off slave mode. */
+ func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ func_ctrl_reg_val &= ~ASPEED_I2CD_SLAVE_EN;
++ if (bus->general_call)
++ func_ctrl_reg_val &= ~ASPEED_I2CD_GCALL_EN;
+ writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+ bus->slave = NULL;
+@@ -921,6 +957,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
+ bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
++ if (of_property_read_bool(pdev->dev.of_node, "general-call"))
++ bus->general_call = true;
++
+ /* If slave has already been registered, re-enable it. */
+ if (bus->slave)
+ __aspeed_i2c_reg_slave(bus, bus->slave->addr);
+diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c
+index 4548088e1922..a608846cb1db 100644
+--- a/drivers/i2c/i2c-slave-mqueue.c
++++ b/drivers/i2c/i2c-slave-mqueue.c
+@@ -53,10 +53,12 @@ static int i2c_slave_mqueue_callback(struct i2c_client *client,
+
+ switch (event) {
+ case I2C_SLAVE_WRITE_REQUESTED:
++ case I2C_SLAVE_GCALL_REQUESTED:
+ mq->truncated = 0;
+
+ msg->len = 1;
+- msg->buf[0] = client->addr << 1;
++ msg->buf[0] = event == I2C_SLAVE_GCALL_REQUESTED ?
++ 0 : client->addr << 1;
+ break;
+
+ case I2C_SLAVE_WRITE_RECEIVED:
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+index e1c6b78bdaf1..03ffb70d75f2 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -371,6 +371,7 @@ enum i2c_slave_event {
+ I2C_SLAVE_WRITE_REQUESTED,
+ I2C_SLAVE_READ_PROCESSED,
+ I2C_SLAVE_WRITE_RECEIVED,
++ I2C_SLAVE_GCALL_REQUESTED,
+ I2C_SLAVE_STOP,
+ };
+
+--
+2.7.4
+
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
new file mode 100644
index 000000000..e4161961e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0059-media-aspeed-remove-source-buffer-allocation-before-.patch
@@ -0,0 +1,49 @@
+From aa8f405609038693481bad4393d58f0c665569a6 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 1/4] 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 | 21 ---------------------
+ 1 file changed, 21 deletions(-)
+
+diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
+index 1bb863b32836..ee1f87a08c7c 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);
+--
+2.21.0
+
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
new file mode 100644
index 000000000..3e158c628
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-media-aspeed-use-different-delays-for-triggering-VE-.patch
@@ -0,0 +1,60 @@
+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/0061-media-aspeed-fix-an-incorrect-timeout-checking-in-mo.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-media-aspeed-fix-an-incorrect-timeout-checking-in-mo.patch
new file mode 100644
index 000000000..7739d5214
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-media-aspeed-fix-an-incorrect-timeout-checking-in-mo.patch
@@ -0,0 +1,30 @@
+From 294391f66df034de8dc63ac2e78f3a00d14075d9 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+Date: Thu, 23 May 2019 14:24:25 -0700
+Subject: [PATCH 3/4] media: aspeed: fix an incorrect timeout checking in mode
+ detection
+
+There is an incorrect timeout checking in mode detection logic so
+it misses resolution detecting chances. This commit fixes the bug.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ drivers/media/platform/aspeed-video.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
+index b8540cc7848d..da20e93f58d3 100644
+--- a/drivers/media/platform/aspeed-video.c
++++ b/drivers/media/platform/aspeed-video.c
+@@ -737,7 +737,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
+ do {
+ if (tries) {
+ set_current_state(TASK_INTERRUPTIBLE);
+- if (schedule_timeout(INVALID_RESOLUTION_DELAY))
++ if (!schedule_timeout(INVALID_RESOLUTION_DELAY))
+ return;
+ }
+
+--
+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
new file mode 100644
index 000000000..efa6f5023
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-media-aspeed-add-a-workaround-to-fix-a-silicon-bug.patch
@@ -0,0 +1,66 @@
+From 09ec380a1d6ae66b2a8124c8fdd984ff829b41d1 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 4/4] 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 | 26 +++++++++++++++++++-------
+ 1 file changed, 19 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
+index da20e93f58d3..c2d4a2e6f20f 100644
+--- a/drivers/media/platform/aspeed-video.c
++++ b/drivers/media/platform/aspeed-video.c
+@@ -826,8 +826,27 @@ 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 on A0
++ * revision, use it for all revisions without checking the
++ * revision ID.
++ */
++ 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 +863,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) {
+--
+2.21.0
+