summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-ast2600
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-ast2600')
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch61
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch30
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch250
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0008-AST2600-Add-TPM-pulse-trigger.patch18
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0010-Fix-timer-support.patch173
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0011-KCS-driver-support-in-uBoot.patch614
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0012-IPMI-command-handler-implementation-in-uboot.patch330
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0013-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch58
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0014-Add-a-workaround-to-cover-eSPI-OOB-free-bug-in-AST26.patch138
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0043-AST2600-PFR-u-boot-env-changes-as-per-PFR-BMC-image.patch41
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/intel.cfg2
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0001-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch186
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed_%.bbappend6
14 files changed, 1785 insertions, 127 deletions
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch
index 7accd788c..1fbb464b8 100644
--- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch
@@ -1,11 +1,11 @@
-From a40cea99245e624e8fb2e39e26c7e76f1aee67fe Mon Sep 17 00:00:00 2001
+From 2cec5042f3b33c6762073deb9275a66875538d82 Mon Sep 17 00:00:00 2001
From: Vernon Mauery <vernon.mauery@intel.com>
Date: Thu, 24 Oct 2019 14:06:33 -0700
Subject: [PATCH] Add ast2600-intel as a new board
Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
arch/arm/dts/Makefile | 3 +-
arch/arm/dts/ast2600-intel.dts | 197 ++++++++++++++++
@@ -13,14 +13,15 @@ Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
arch/arm/mach-aspeed/ast2600/Kconfig | 8 +
board/aspeed/ast2600_intel/Kconfig | 13 ++
board/aspeed/ast2600_intel/Makefile | 4 +
- board/aspeed/ast2600_intel/ast-espi.c | 298 ++++++++++++++++++++++++
+ board/aspeed/ast2600_intel/ast-espi.c | 292 ++++++++++++++++++++++++
board/aspeed/ast2600_intel/ast-irq.c | 399 +++++++++++++++++++++++++++++++++
board/aspeed/ast2600_intel/ast-irq.h | 8 +
board/aspeed/ast2600_intel/ast-timer.c | 59 +++++
- board/aspeed/ast2600_intel/intel.c | 185 +++++++++++++++
+ board/aspeed/ast2600_intel/intel.c | 192 ++++++++++++++++
cmd/Kconfig | 2 +-
common/autoboot.c | 10 +
- 13 files changed, 1189 insertions(+), 2 deletions(-)
+ configs/ast2600_openbmc_defconfig | 2 +-
+ 14 files changed, 1191 insertions(+), 3 deletions(-)
create mode 100644 arch/arm/dts/ast2600-intel.dts
create mode 100644 board/aspeed/ast2600_intel/Kconfig
create mode 100644 board/aspeed/ast2600_intel/Makefile
@@ -338,23 +339,17 @@ index 000000000000..37d2f0064f38
+obj-y += ast-timer.o
diff --git a/board/aspeed/ast2600_intel/ast-espi.c b/board/aspeed/ast2600_intel/ast-espi.c
new file mode 100644
-index 000000000000..1852dd3d86e2
+index 000000000000..0fdbf089a450
--- /dev/null
+++ b/board/aspeed/ast2600_intel/ast-espi.c
-@@ -0,0 +1,298 @@
-+/*
-+ * Copyright 2018 Intel Corporation
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version
-+ * 2 of the License, or (at your option) any later version.
-+ */
+@@ -0,0 +1,292 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018-2020, Intel Corporation.
+
+#include <common.h>
+#include <asm/io.h>
+
-+#define AST_LPC_BASE 0x1e6e9000
++#define AST_LPC_BASE 0x1e789000
+#define AST_ESPI_BASE 0x1e6ee000
+#define AST_SCU_BASE 0x1e6e2000
+#define AST_SCU_HW_STRAP2 0x510
@@ -581,7 +576,7 @@ index 000000000000..1852dd3d86e2
+
+void espi_init(void)
+{
-+ if (!readl(AST_SCU_BASE + AST_SCU_HW_STRAP2) &
++ if (~readl(AST_SCU_BASE + AST_SCU_HW_STRAP2) &
+ SCU_HW_STRAP_ESPI_ENABLED) {
+ uint32_t v;
+
@@ -1126,10 +1121,13 @@ index 000000000000..cf8c69aba5d3
+}
diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
new file mode 100644
-index 000000000000..03363b80b4f5
+index 000000000000..4a40a050c3da
--- /dev/null
+++ b/board/aspeed/ast2600_intel/intel.c
-@@ -0,0 +1,185 @@
+@@ -0,0 +1,192 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2019-2020, Intel Corporation.
++
+/* Intel customizations of Das U-Boot */
+#include <common.h>
+#include <asm/gpio.h>
@@ -1256,15 +1254,12 @@ index 000000000000..03363b80b4f5
+ SCU_BASE | SCU_414);
+}
+
-+void espi_init(void);
-+int arch_interrupt_init_early(void);
-+
+static void timer_handler(void *regs)
+{
+ printf("+");
+}
+
-+void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler);
++extern int arch_interrupt_init_early(void);
+int board_early_init_f(void)
+{
+ /* This is called before relocation; beware! */
@@ -1282,11 +1277,18 @@ index 000000000000..03363b80b4f5
+ return 0;
+}
+
++extern void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler);
+int board_early_init_r(void)
+{
+ debug("board_early_init_r\n");
+ /* timer_enable(0, 1, timer_handler); */
+
++ return 0;
++}
++
++extern void espi_init(void);
++int board_late_init(void)
++{
+ espi_init();
+
+ return 0;
@@ -1353,6 +1355,19 @@ index 94133eaeda78..5e69000b848b 100644
if (bootdelay >= 0)
abort = __abortboot(bootdelay);
+diff --git a/configs/ast2600_openbmc_defconfig b/configs/ast2600_openbmc_defconfig
+index 2e2df2e3a235..77c39d848312 100644
+--- a/configs/ast2600_openbmc_defconfig
++++ b/configs/ast2600_openbmc_defconfig
+@@ -13,7 +13,7 @@ CONFIG_FIT=y
+ CONFIG_USE_BOOTARGS=y
+ CONFIG_BOOTARGS="console=ttyS4,115200n8 root=/dev/ram rw"
+ CONFIG_USE_BOOTCOMMAND=y
+-CONFIG_BOOTCOMMAND="bootm 20100000"
++CONFIG_BOOTCOMMAND="bootm 20080000"
+ CONFIG_SYS_CONSOLE_ENV_OVERWRITE=y
+ CONFIG_DISPLAY_BOARDINFO_LATE=y
+ CONFIG_ARCH_EARLY_INIT_R=y
--
2.7.4
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch
index 7868c03d6..1b2cc83a1 100644
--- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch
@@ -1,4 +1,4 @@
-From 2e848b74af709f84d1e9fe27a58a74bfc686bfff Mon Sep 17 00:00:00 2001
+From b6bce26bf19e74863e145e6e6e1f6e458077a31a Mon Sep 17 00:00:00 2001
From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Date: Fri, 3 Jan 2020 15:14:09 -0800
Subject: [PATCH] AST2600: Adjust default GPIO settings
@@ -10,14 +10,14 @@ Subject: [PATCH] AST2600: Adjust default GPIO settings
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
- board/aspeed/ast2600_intel/intel.c | 44 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 44 insertions(+)
+ board/aspeed/ast2600_intel/intel.c | 50 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 50 insertions(+)
diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
-index eb9b3959625e..25c61d1a806c 100644
+index d1ac8651ac6c..b1a08db91bec 100644
--- a/board/aspeed/ast2600_intel/intel.c
+++ b/board/aspeed/ast2600_intel/intel.c
-@@ -151,6 +151,48 @@ static void sgpio_init(void)
+@@ -162,6 +162,54 @@ static void sgpio_init(void)
SCU_BASE | SCU_414);
}
@@ -50,11 +50,17 @@ index eb9b3959625e..25c61d1a806c 100644
+#define SCU_610_GPIOB6 BIT(14)
+ writel(readl(SCU_BASE | SCU_610) | SCU_610_GPIOB6, SCU_BASE | SCU_610);
+
++ /*
++ * GPIO C5 has a connection between BMC(3.3v) and CPU(1.0v) so if we
++ * set it as an logic high output, it will be clipped by a protection
++ * circuit in the CPU and eventually the signal will be detected as
++ * logic low. So we leave this GPIO as an input so that the signal
++ * can be pulled up by a CPU internal resister. The signal will be
++ * 1.0v logic high resultingy.
++ */
+#define GPIO_C5 BIT(21)
-+ writel(readl(AST_GPIO_BASE | GPIO_004) | GPIO_C5,
++ writel(readl(AST_GPIO_BASE | GPIO_004) & ~GPIO_C5,
+ AST_GPIO_BASE | GPIO_004);
-+ writel(readl(AST_GPIO_BASE | GPIO_000) | GPIO_C5,
-+ AST_GPIO_BASE | GPIO_000);
+
+#define GPIO_G6 BIT(22)
+ writel(readl(AST_GPIO_BASE | GPIO_024) | GPIO_G6,
@@ -63,10 +69,10 @@ index eb9b3959625e..25c61d1a806c 100644
+ AST_GPIO_BASE | GPIO_020);
+}
+
- void espi_init(void);
- int arch_interrupt_init_early(void);
-
-@@ -167,6 +209,8 @@ int board_early_init_f(void)
+ static void timer_handler(void *regs)
+ {
+ printf("+");
+@@ -175,6 +223,8 @@ int board_early_init_f(void)
* I am not sure if it actually does anything... */
arch_interrupt_init_early();
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch
index 66f3d3b12..d5bd4a2b1 100644
--- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch
@@ -1,4 +1,4 @@
-From 143fb89b03af61bd807b0d6f9f11d6801cf8fe69 Mon Sep 17 00:00:00 2001
+From c1561193296d04dd8bd06adca43edac814058367 Mon Sep 17 00:00:00 2001
From: Kuiying Wang <kuiying.wang@intel.com>
Date: Fri, 3 Jan 2020 12:52:29 +0800
Subject: [PATCH] Enable interrupt in u-boot.
@@ -12,27 +12,70 @@ Testedby:
2. Both ArcherCity and Ast2600 EVB are working well.
Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
- arch/arm/lib/vectors.S | 31 ++++++-
- board/aspeed/ast2600_intel/ast-irq.c | 154 +++++++++++++++++------------------
- 2 files changed, 105 insertions(+), 80 deletions(-)
+ Kconfig | 14 +++
+ arch/arm/lib/stack.c | 9 ++
+ arch/arm/lib/vectors.S | 30 +++++-
+ board/aspeed/ast2600_intel/ast-espi.c | 3 +-
+ board/aspeed/ast2600_intel/ast-irq.c | 185 +++++++++++++++++-----------------
+ board/aspeed/ast2600_intel/ast-irq.h | 8 --
+ board/aspeed/ast2600_intel/intel.c | 1 -
+ 7 files changed, 145 insertions(+), 105 deletions(-)
+ delete mode 100644 board/aspeed/ast2600_intel/ast-irq.h
+diff --git a/Kconfig b/Kconfig
+index 305b265ed713..a6f68cd13d54 100644
+--- a/Kconfig
++++ b/Kconfig
+@@ -239,6 +239,20 @@ config BUILD_TARGET
+ special image will be automatically built upon calling
+ make / buildman.
+
++config USE_IRQ
++ bool "Use interrupts"
++ default n
++
++config STACKSIZE_IRQ
++ depends on USE_IRQ
++ int "Size for IRQ stack (only if USE_IRQ enabled)"
++ default 16384
++
++config STACKSIZE_FIQ
++ depends on USE_IRQ
++ int "Size for FIQ stack (only if USE_IRQ enabled)"
++ default 16384
++
+ endmenu # General setup
+
+ menu "Boot images"
+diff --git a/arch/arm/lib/stack.c b/arch/arm/lib/stack.c
+index c89a219dd26d..d9a7f49c5623 100644
+--- a/arch/arm/lib/stack.c
++++ b/arch/arm/lib/stack.c
+@@ -24,6 +24,15 @@ int arch_reserve_stacks(void)
+ gd->irq_sp = gd->start_addr_sp;
+
+ # if !defined(CONFIG_ARM64)
++# ifdef CONFIG_USE_IRQ
++ gd->start_addr_sp -= (CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ);
++ printf("Reserving %zu Bytes for IRQ stack at: %08lx\n",
++ CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ, gd->start_addr_sp);
++
++ /* 8-byte alignment for ARM ABI compliance */
++ gd->start_addr_sp &= ~0x07;
++# endif
++
+ /* leave 3 words for abort-stack, plus 1 for alignment */
+ gd->start_addr_sp -= 16;
+ # endif
diff --git a/arch/arm/lib/vectors.S b/arch/arm/lib/vectors.S
-index 2ca6e2494a7a..e2ed04a204de 100644
+index 2ca6e2494a7a..5a5e60dbdde4 100644
--- a/arch/arm/lib/vectors.S
+++ b/arch/arm/lib/vectors.S
-@@ -13,7 +13,7 @@
- */
-
- #include <config.h>
--
-+#define CONFIG_USE_IRQ
- /*
- * A macro to allow insertion of an ARM exception vector either
- * for the non-boot0 case or by a boot0-header.
-@@ -145,6 +145,17 @@ fiq:
-
- #else /* !CONFIG_SPL_BUILD */
+@@ -154,6 +154,17 @@ IRQ_STACK_START_IN:
+ .word 0x0badc0de
+ #endif
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
@@ -45,15 +88,16 @@ index 2ca6e2494a7a..e2ed04a204de 100644
+ .word 0x0badc0de
+#endif
+
- /* IRQ stack memory (calculated at run-time) + 8 bytes */
- .globl IRQ_STACK_START_IN
- IRQ_STACK_START_IN:
-@@ -277,17 +288,31 @@ not_used:
+ @
+ @ IRQ stack frame.
+ @
+@@ -277,17 +288,30 @@ not_used:
bad_save_user_regs
bl do_not_used
-+ .align 5
+-
+#ifdef CONFIG_USE_IRQ
++ .align 5
+irq:
+ get_irq_stack
+ irq_save_user_regs
@@ -66,9 +110,8 @@ index 2ca6e2494a7a..e2ed04a204de 100644
+ irq_save_user_regs
+ bl do_fiq
+ irq_restore_user_regs
-
- .align 5
+#else
+ .align 5
irq:
get_bad_stack
bad_save_user_regs
@@ -82,11 +125,49 @@ index 2ca6e2494a7a..e2ed04a204de 100644
-
+#endif /* CONFIG_USE_IRQ */
#endif /* CONFIG_SPL_BUILD */
+diff --git a/board/aspeed/ast2600_intel/ast-espi.c b/board/aspeed/ast2600_intel/ast-espi.c
+index 0fdbf089a450..1d7ae529612d 100644
+--- a/board/aspeed/ast2600_intel/ast-espi.c
++++ b/board/aspeed/ast2600_intel/ast-espi.c
+@@ -142,7 +142,7 @@ static void espi_handshake_ack(void)
+ }
+ }
+
+-int espi_irq_handler(struct pt_regs *regs)
++static void espi_irq_handler(void *cookie)
+ {
+ uint32_t irq_status = readl(AST_ESPI_BASE + ESPI008);
+
+@@ -226,7 +226,6 @@ int espi_irq_handler(struct pt_regs *regs)
+ readl(AST_ESPI_BASE + ESPI11C),
+ readl(AST_ESPI_BASE + ESPI094),
+ readl(AST_ESPI_BASE + ESPI12C), irq_status);
+- return 0;
+ }
+
+ void espi_init(void)
diff --git a/board/aspeed/ast2600_intel/ast-irq.c b/board/aspeed/ast2600_intel/ast-irq.c
-index f817f8cd7c81..6e91b17ab186 100644
+index f817f8cd7c81..106bb3b4ffb2 100644
--- a/board/aspeed/ast2600_intel/ast-irq.c
+++ b/board/aspeed/ast2600_intel/ast-irq.c
-@@ -18,19 +18,6 @@ DECLARE_GLOBAL_DATA_PTR;
+@@ -1,14 +1,7 @@
+-/*
+- * Copyright 2018 Intel Corporation
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * as published by the Free Software Foundation; either version
+- * 2 of the License, or (at your option) any later version.
+- */
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018-2020, Intel Corporation.
+
+ #include <common.h>
+-#include <netdev.h>
+ #include <asm/io.h>
+
+ DECLARE_GLOBAL_DATA_PTR;
+@@ -18,19 +11,6 @@ DECLARE_GLOBAL_DATA_PTR;
#define GIC_INTERFACE_OFFSET 0x4000
#define GIC_VIRT_OFFSET 0x6000
@@ -106,7 +187,7 @@ index f817f8cd7c81..6e91b17ab186 100644
/* GIC_DISTRIBUTOR_OFFSET register offsets */
#define GICD_CTLR 0x000
#define GICD_TYPER 0x004
-@@ -82,7 +69,9 @@ DECLARE_GLOBAL_DATA_PTR;
+@@ -82,7 +62,9 @@ DECLARE_GLOBAL_DATA_PTR;
#define GICC_IIDR 0x00fc
#define GICC_DIR 0x1000
@@ -117,7 +198,7 @@ index f817f8cd7c81..6e91b17ab186 100644
/* GIC_INTERFACE_OFFSET register offsets */
#define GICH_HCR 0x000
-@@ -116,9 +105,10 @@ DECLARE_GLOBAL_DATA_PTR;
+@@ -116,9 +98,10 @@ DECLARE_GLOBAL_DATA_PTR;
#define GIC_VIRT_CPU_IMPLEMENTER_MAGIC 0x0102143b
@@ -131,7 +212,7 @@ index f817f8cd7c81..6e91b17ab186 100644
#define GICD_INT_DEF_PRI_X4 (\
(GICD_INT_DEF_PRI << 24) |\
(GICD_INT_DEF_PRI << 16) |\
-@@ -129,20 +119,30 @@ DECLARE_GLOBAL_DATA_PTR;
+@@ -129,21 +112,32 @@ DECLARE_GLOBAL_DATA_PTR;
#define GICD_INT_EN_CLR_X32 0xffffffff
#define GICD_INT_EN_CLR_PPI 0xffff0000
#define GICD_INT_EN_SET_SGI 0x0000ffff
@@ -164,9 +245,11 @@ index f817f8cd7c81..6e91b17ab186 100644
+
+static size_t max_irq = 0;
static interrupt_handler_t *handlers[GIC_MAX_IRQ] = {NULL};
++static void *cookies[GIC_MAX_IRQ] = {NULL};
static unsigned long irq_total = 0;
static unsigned long irq_counts[GIC_MAX_IRQ] = {0};
-@@ -159,31 +159,40 @@ static inline uint32_t gic_base(void)
+ static uint32_t gbase = 0;
+@@ -159,24 +153,31 @@ static inline uint32_t gic_base(void)
static void enable_gic(void)
{
@@ -201,8 +284,7 @@ index f817f8cd7c81..6e91b17ab186 100644
uint32_t grp = id >> ITLINES_SHIFT;
uint32_t grp_bit = 1 << (id & ITLINES_MASK);
gicd_writel(grp_bit, GICD_ISENABLERn + grp * sizeof(uint32_t));
-+ gicd_writel(GICD_ITARGET_ALL, GICD_ITARGETSRn + id / 4 * 4);
- }
+@@ -184,6 +185,7 @@ static void enable_irq_id(unsigned int id)
static void disable_irq_id(unsigned int id)
{
@@ -210,13 +292,13 @@ index f817f8cd7c81..6e91b17ab186 100644
uint32_t grp = id >> ITLINES_SHIFT;
uint32_t grp_bit = 1 << (id & ITLINES_MASK);
gicd_writel(grp_bit, GICD_ICENABLERn + grp * sizeof(uint32_t));
-@@ -193,22 +202,29 @@ static int gic_probe(void)
+@@ -193,34 +195,49 @@ static int gic_probe(void)
{
int i;
gbase = gic_base();
+- enable_gic();
+ DBG_IRQ("gic_probe GIC base = 0x%x, magicd=0x%x\n",
+ gbase, gicd_readl(GICD_IIDR));
- enable_gic();
if (gicd_readl(GICD_IIDR) != GIC_DISTRIBUTOR_IMPLEMENTER_MAGIC &&
gicc_readl(GICC_IIDR) != GIC_CPU_IMPLEMENTER_MAGIC &&
@@ -225,24 +307,34 @@ index f817f8cd7c81..6e91b17ab186 100644
+ printf("error: magic check \n");
return 0;
}
++
++ disable_gic();
++
/* GIC supports up to 1020 lines */
- max_irq = ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) << ITLINES_SHIFT;
-+ max_irq = (((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) * 32) - 1;
++ max_irq = ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) * 32;
if (max_irq > GIC_MAX_IRQ)
max_irq = GIC_MAX_IRQ;
/* set all lines to be level triggered N-N */
for (i = 32; i < max_irq; i += 16)
- gicd_writel(0, GICD_ICFGRn + i / 4);
+-
+- /* Set priority on all interrupts. */
+- for (i = 0; i < max_irq; i += 4)
+ gicd_writel(GICD_ICFG_LEVEL_TRIGGER, GICD_ICFGRn + i / 4);
-
++
+ DBG_IRQ("max_irq = 0x%x, typer=0x%x, config=0x%x, maxirq=0x%x\n", max_irq,
+ (gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1,
+ gicd_readl(GICD_ICFGRn + 0x8),
+ ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) * 0x20);
- /* Set priority on all interrupts. */
- for (i = 0; i < max_irq; i += 4)
++ /* Set priority and target on all interrupts. */
++ for (i = 0; i < max_irq; i += 4) {
gicd_writel(GICD_INT_DEF_PRI_X4, GICD_IPRIORITYRn + i);
-@@ -218,9 +234,11 @@ static int gic_probe(void)
++ gicd_writel(GICD_ITARGET_ALL, GICD_ITARGETSRn + i);
++ }
+
+ /* Deactivate and disable all SPIs. */
+ for (i = 32; i < max_irq; i += 32) {
gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn + i / 8);
gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICENABLERn + i / 8);
}
@@ -253,10 +345,12 @@ index f817f8cd7c81..6e91b17ab186 100644
gicd_writel(GICD_INT_EN_SET_SGI, GICD_ISENABLERn);
+ /* unmask all priority */
+ gicc_writel(GICC_UNMASK_ALL_PRIORITY, GICC_PMRn);
++
++ enable_gic();
return 0;
}
-@@ -228,6 +246,7 @@ static int gic_probe(void)
+@@ -228,6 +245,7 @@ static int gic_probe(void)
void irq_free_handler (int irq);
static void gic_shutdown(void)
{
@@ -264,7 +358,7 @@ index f817f8cd7c81..6e91b17ab186 100644
int i;
for (i = 0; i < max_irq; i++)
{
-@@ -238,6 +257,7 @@ static void gic_shutdown(void)
+@@ -238,6 +256,7 @@ static void gic_shutdown(void)
int arch_interrupt_init_early(void)
{
@@ -272,8 +366,11 @@ index f817f8cd7c81..6e91b17ab186 100644
return 0;
}
-@@ -249,11 +269,13 @@ int arch_interrupt_init(void)
+@@ -247,28 +266,28 @@ int arch_interrupt_init(void)
+ for (i = 0; i < GIC_MAX_IRQ; i++)
+ {
handlers[i] = NULL;
++ cookies[i] = NULL;
irq_counts[i] = 0;
}
+ DBG_IRQ("arch_interrupt_init\n");
@@ -286,13 +383,13 @@ index f817f8cd7c81..6e91b17ab186 100644
gic_shutdown();
return 0;
}
-@@ -261,14 +283,12 @@ int arch_interrupt_fini(void)
+
int interrupt_init (void)
{
- /*
+- /*
- * setup up stacks if necessary
- */
-+ * setup up stacks if necessary*/
++ /* setup up stacks if necessary */
+ IRQ_STACK_START = gd->irq_sp + 8;
IRQ_STACK_START_IN = gd->irq_sp + 8;
@@ -304,7 +401,7 @@ index f817f8cd7c81..6e91b17ab186 100644
}
int global_interrupts_enabled (void)
-@@ -286,12 +306,12 @@ void enable_interrupts (void)
+@@ -286,12 +305,12 @@ void enable_interrupts (void)
{
unsigned long cpsr;
__asm__ __volatile__("mrs %0, cpsr\n"
@@ -319,7 +416,7 @@ index f817f8cd7c81..6e91b17ab186 100644
return;
}
-@@ -304,11 +324,13 @@ int disable_interrupts (void)
+@@ -304,11 +323,13 @@ int disable_interrupts (void)
: "=r" (cpsr), "=r" (temp)
:
: "memory");
@@ -327,19 +424,21 @@ index f817f8cd7c81..6e91b17ab186 100644
return (cpsr & 0x80) == 0;
}
- void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx)
+-void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx)
++void irq_install_handler(int irq, interrupt_handler_t *handler, void *cookie)
{
+ DBG_IRQ(" %s()\n", __FUNCTION__);
if (irq > max_irq) {
printf("irq %d out of range\n", irq);
return;
-@@ -317,13 +339,14 @@ void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx)
+@@ -317,19 +338,22 @@ void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx)
printf("irq %d already in use (%p)\n", irq, handlers[irq]);
return;
}
- printf("registering handler for irq %d\n", irq);
+ DBG_IRQ("registering handler for irq %d\n", irq);
handlers[irq] = handler;
++ cookies[irq] = cookie;
enable_irq_id(irq);
}
@@ -349,29 +448,36 @@ index f817f8cd7c81..6e91b17ab186 100644
if (irq >= max_irq) {
printf("irq %d out of range\n", irq);
return;
-@@ -338,9 +361,10 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
- {
+ }
+ if (handlers[irq]) {
+ handlers[irq] = NULL;
++ cookies[irq] = NULL;
+ disable_irq_id(irq);
+ }
+ }
+@@ -339,8 +363,10 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
int i;
int enabled = global_interrupts_enabled();
-- printf("GIC base = 0x%x\n", gbase);
+ printf("GIC base = 0x%x\n", gbase);
- printf("interrupts %sabled\n", (enabled ? "en" : "dis"));
-+ DBG_IRQ("GIC base = 0x%x\n", gbase);
-+ DBG_IRQ("interrupts %sabled\n", (enabled ? "en" : "dis"));
++ printf("Number of interrupt sources = %d\n", max_irq);
++ printf("Interrupts %sabled\n", (enabled ? "en" : "dis"));
uint32_t grp_en = 0;
+
for (i = 0; i < max_irq; i++) {
if ((i & ITLINES_MASK) == 0)
grp_en = gicd_readl(GICD_ISENABLERn +
-@@ -348,52 +372,28 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+@@ -348,52 +374,29 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
int irq_enabled = grp_en & (1 << (i & ITLINES_MASK));
if (!irq_enabled)
continue;
- printf("% 2i (% 3s): %lu\n", i,
-+ DBG_IRQ("%2d (%3s): %lu\n", i,
++ printf("%2d (%3s): %lu\n", i,
(irq_enabled ? "on" : "off"), irq_counts[i]);
}
- printf("total: %lu\n", irq_total);
-+ DBG_IRQ("total: %lu\n", irq_total);
++ printf("Total: %lu\n", irq_total);
++
return 0;
}
@@ -414,7 +520,7 @@ index f817f8cd7c81..6e91b17ab186 100644
- gicd_writel(pending, GICD_ISPENDRn +
- (i >> ITLINES_SHIFT) * sizeof(uint32_t));
- }
-+ uint32_t irqstat = 0, irqnr = 0;
++ uint32_t irqstat, irqnr;
+
+ if (irq_total < MAX_IRQ)
+ irq_total++;
@@ -426,10 +532,36 @@ index f817f8cd7c81..6e91b17ab186 100644
+ if (irq_counts[irqnr] < MAX_IRQ)
+ irq_counts[irqnr]++;
+ if (handlers[irqnr]) {
-+ handlers[irqnr](NULL);
++ handlers[irqnr](cookies[irqnr]);
}
}
}
+diff --git a/board/aspeed/ast2600_intel/ast-irq.h b/board/aspeed/ast2600_intel/ast-irq.h
+deleted file mode 100644
+index 9957f2baa7ff..000000000000
+--- a/board/aspeed/ast2600_intel/ast-irq.h
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#ifndef _AST_IRQ_H_
+-#define _AST_IRQ_H_
+-
+-int request_irq(int irq, interrupt_handler_t *handler);
+-int release_irq(int irq);
+-int arch_interrupt_init_early(void);
+-
+-#endif
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index ac108c3a066c..22a377d2cb77 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -209,7 +209,6 @@ static void timer_handler(void *regs)
+ printf("+");
+ }
+
+-extern int arch_interrupt_init_early(void);
+ int board_early_init_f(void)
+ {
+ /* This is called before relocation; beware! */
--
2.7.4
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0008-AST2600-Add-TPM-pulse-trigger.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0008-AST2600-Add-TPM-pulse-trigger.patch
index c737d4f95..19606ee38 100644
--- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0008-AST2600-Add-TPM-pulse-trigger.patch
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0008-AST2600-Add-TPM-pulse-trigger.patch
@@ -1,4 +1,4 @@
-From 7903cb8540f83e9beca9386681ab6232eb288527 Mon Sep 17 00:00:00 2001
+From b7f02c074c0dee6b5d6d1c1f632993f7b0e3e952 Mon Sep 17 00:00:00 2001
From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Date: Wed, 25 Mar 2020 15:04:26 -0700
Subject: [PATCH] AST2600: Add TPM pulse trigger
@@ -11,10 +11,10 @@ Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
1 file changed, 17 insertions(+)
diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
-index 25c61d1a806c..cd90597221ea 100644
+index 22a377d2cb77..47e5ad21d66d 100644
--- a/board/aspeed/ast2600_intel/intel.c
+++ b/board/aspeed/ast2600_intel/intel.c
-@@ -193,6 +193,21 @@ static void set_gpio_default_state(void)
+@@ -204,6 +204,21 @@ static void set_gpio_default_state(void)
AST_GPIO_BASE | GPIO_020);
}
@@ -33,12 +33,12 @@ index 25c61d1a806c..cd90597221ea 100644
+ AST_GPIO_BASE | GPIO_000);
+}
+
- void espi_init(void);
- int arch_interrupt_init_early(void);
-
-@@ -228,6 +243,8 @@ int board_early_init_r(void)
-
- espi_init();
+ static void timer_handler(void *regs)
+ {
+ printf("+");
+@@ -234,6 +249,8 @@ int board_early_init_r(void)
+ debug("board_early_init_r\n");
+ /* timer_enable(0, 1, timer_handler); */
+ enable_onboard_tpm();
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0010-Fix-timer-support.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0010-Fix-timer-support.patch
new file mode 100644
index 000000000..cf13a17f2
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0010-Fix-timer-support.patch
@@ -0,0 +1,173 @@
+From bd4eb78dc71529342e5d0b784731c412cf747acc Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 20 Apr 2020 10:42:05 -0700
+Subject: [PATCH] Fix timer support
+
+Timer interrupt flag should be cleared just after it gets an
+interrupt otherwise the interrupt will be called infinitely and
+main context will starve resultingly. To fix this issue, this
+commit adds the timer interrupt flag clearing logic.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/ast-timer.c | 69 ++++++++++++++++++++--------------
+ board/aspeed/ast2600_intel/intel.c | 13 ++++---
+ 2 files changed, 48 insertions(+), 34 deletions(-)
+
+diff --git a/board/aspeed/ast2600_intel/ast-timer.c b/board/aspeed/ast2600_intel/ast-timer.c
+index cf8c69aba5d3..d98ec9238e15 100644
+--- a/board/aspeed/ast2600_intel/ast-timer.c
++++ b/board/aspeed/ast2600_intel/ast-timer.c
+@@ -1,59 +1,72 @@
+-/*
+- * Copyright 2019 Intel Corporation
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License
+- * as published by the Free Software Foundation; either version
+- * 2 of the License, or (at your option) any later version.
+- */
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2019-2020, Intel Corporation.
+
+ #include <common.h>
+ #include <asm/io.h>
+
+ static const int timer_irqs[] = {48, 49, 50, 51, 52, 53, 54, 55};
++static void (*timer_callback[ARRAY_SIZE(timer_irqs)]) (void *) = {NULL};
++static void *cb_cookie[ARRAY_SIZE(timer_irqs)] = {NULL};
++
+ #define AST_TIMER_BASE 0x1e782000
+ /* offsets from AST_TIMER_BASE for each timer */
+-static const uint32_t timer_bases[] = {0, 0x10, 0x20, 0x40,
+- 0x50, 0x60, 0x70, 0x80};
+-#define TIMER_1MHZ_CLK_COUNT 1000000u
++static const u32 timer_bases[] = {0, 0x10, 0x20, 0x40, 0x50, 0x60, 0x70, 0x80};
+ #define TIMER_ENABLE 1
+ #define TIMER_1MHZ_CLK_SEL 2
+ #define TIMER_ENABLE_IRQ 4
+ #define TIMER_RESET_BY_WDT 8
+ #define TIMER_CONTROL 0x30
++#define TIMER_INT_CLR 0x34
+ #define TIMER_RELOAD 0x04
+ #define TIMER_CONTROL_CLEAR 0x3c
+
++static void timer_irq_handler(void *cookie)
++{
++ int timer_nr = (int)cookie;
++
++ writel(1 << timer_nr, AST_TIMER_BASE + TIMER_INT_CLR);
++
++ if (timer_callback[timer_nr])
++ timer_callback[timer_nr](cb_cookie[timer_nr]);
++}
++
+ void timer_disable(int n)
+ {
+- if (n < 0 || n > 7) {
++ u32 tctrl;
++
++ if (n < 0 || n > 7)
+ return;
+- }
+- uint32_t tctrl = 0xf << (n * 4);
++
++ irq_free_handler(timer_irqs[n]);
++ timer_callback[n] = NULL;
++ cb_cookie[n] = NULL;
++
++ tctrl = 0xf << (n * 4);
+ writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL_CLEAR);
+ }
+
+-void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler)
++void timer_enable(uint n, u32 interval_us, interrupt_handler_t *handler,
++ void *cookie)
+ {
+- if (n < 0 || n > 7) {
+- return;
+- }
+- if (!freq)
++ u32 tctrl;
++
++ if (n < 0 || n > 7 || !interval_us)
+ return;
+
+ timer_disable(n);
+
+- uint32_t v = TIMER_1MHZ_CLK_COUNT / freq;
+- writel(v, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD);
++ writel(interval_us, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD);
+
+- uint32_t tctrl = (
+- TIMER_ENABLE |
+- TIMER_1MHZ_CLK_SEL |
+- TIMER_RESET_BY_WDT) << (n * 4);
++ tctrl = (TIMER_ENABLE | TIMER_1MHZ_CLK_SEL |
++ TIMER_RESET_BY_WDT) << (n * 4) | TIMER_ENABLE_IRQ << (n * 4);
+
+ if (handler) {
+- irq_install_handler(timer_irqs[n], handler, NULL);
+- tctrl |= (TIMER_ENABLE_IRQ << (n * 4));
++ timer_callback[n] = handler;
++ cb_cookie[n] = cookie;
+ }
+- writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL);
++
++ irq_install_handler(timer_irqs[n], timer_irq_handler, (void *)n);
++
++ writel(readl(AST_TIMER_BASE + TIMER_CONTROL) | tctrl,
++ AST_TIMER_BASE + TIMER_CONTROL);
+ }
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 47e5ad21d66d..befeaff0a953 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -219,16 +219,14 @@ void enable_onboard_tpm(void)
+ AST_GPIO_BASE | GPIO_000);
+ }
+
+-static void timer_handler(void *regs)
++static void timer_callback(void *cookie)
+ {
+- printf("+");
++ debug("+");
+ }
+
+ int board_early_init_f(void)
+ {
+ /* This is called before relocation; beware! */
+- /* initialize running timer? timer_init is next in the list but
+- * I am not sure if it actually does anything... */
+ arch_interrupt_init_early();
+
+ set_gpio_default_state();
+@@ -243,11 +241,9 @@ int board_early_init_f(void)
+ return 0;
+ }
+
+-extern void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler);
+ int board_early_init_r(void)
+ {
+ debug("board_early_init_r\n");
+- /* timer_enable(0, 1, timer_handler); */
+
+ enable_onboard_tpm();
+
+@@ -255,8 +251,13 @@ int board_early_init_r(void)
+ }
+
+ extern void espi_init(void);
++extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler,
++ void *cookie);
+ int board_late_init(void)
+ {
++#define ONE_SEC_IN_USEC 1000000
++
++ timer_enable(0, ONE_SEC_IN_USEC, timer_callback, (void *)0);
+ espi_init();
+
+ return 0;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0011-KCS-driver-support-in-uBoot.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0011-KCS-driver-support-in-uBoot.patch
new file mode 100644
index 000000000..f446d797a
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0011-KCS-driver-support-in-uBoot.patch
@@ -0,0 +1,614 @@
+From 1fbd857e2ff5396ea057f686cbd01c6db4328316 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Mon, 20 Apr 2020 11:08:22 -0700
+Subject: [PATCH] KCS driver support in uBoot
+
+Added KCS support in uBoot. This will enable
+KCS channels and set the specified registers
+to do KCS communication in uBoot. It also
+consist of read and write KCS message transations
+work flow implementation( As specified in IPMI
+specification Section 9.15). It is enabled
+only when Force Firmware Update Jumper is ON.
+
+Tested:
+Stopped booting in uBoot and sent IPMI commands
+via KCS interfaces using cmdtool.efi.
+ - Get Device ID:
+ Req: cmdtool.efi 20 18 1
+ Res: 00 23 00 12 03 02 BF 57 01 00 7B 00 00 00 00 00
+ - Get Self Test Results
+ Req: cmdtool.efi 20 18 4
+ Res: 00 56 00
+ - All other commands
+ Req: cmdtool.efi 20 18 2
+ Res: C1 (Invalid).
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/Makefile | 1 +
+ board/aspeed/ast2600_intel/ast-kcs.c | 418 +++++++++++++++++++++++++++++++++++
+ board/aspeed/ast2600_intel/ast-kcs.h | 112 ++++++++++
+ board/aspeed/ast2600_intel/intel.c | 4 +
+ 4 files changed, 535 insertions(+)
+ create mode 100644 board/aspeed/ast2600_intel/ast-kcs.c
+ create mode 100644 board/aspeed/ast2600_intel/ast-kcs.h
+
+diff --git a/board/aspeed/ast2600_intel/Makefile b/board/aspeed/ast2600_intel/Makefile
+index 37d2f0064f38..d049922719f3 100644
+--- a/board/aspeed/ast2600_intel/Makefile
++++ b/board/aspeed/ast2600_intel/Makefile
+@@ -2,3 +2,4 @@ obj-y += intel.o
+ obj-y += ast-espi.o
+ obj-y += ast-irq.o
+ obj-y += ast-timer.o
++obj-y += ast-kcs.o
+diff --git a/board/aspeed/ast2600_intel/ast-kcs.c b/board/aspeed/ast2600_intel/ast-kcs.c
+new file mode 100644
+index 000000000000..a03b7e725370
+--- /dev/null
++++ b/board/aspeed/ast2600_intel/ast-kcs.c
+@@ -0,0 +1,418 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018-2020 Intel Corporation
++
++#include "ast-kcs.h"
++
++#ifdef DEBUG_KCS_ENABLED
++#define DBG_KCS printf
++#else
++#define DBG_KCS(...)
++#endif
++
++/* TODO: Move to IPMI file. */
++#define IPMI_CC_OK 0x00
++#define IPMI_CC_INVALID 0xC1
++#define IPMI_CC_UNSPECIFIED 0xFF
++
++#define KCS_CHANNEL_NO_3 3
++
++static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 };
++
++static const struct kcs_io_reg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
++ { .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 },
++ { .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 },
++ { .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 },
++ { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 }
++};
++
++#define NO_OF_ENABLED_KCS_CHANNELS ARRAY_SIZE(enabled_kcs_channel)
++
++static struct kcs_packet m_kcs_pkt[NO_OF_ENABLED_KCS_CHANNELS];
++
++static u16 read_status(u16 channel_num)
++{
++ return readl(AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].str);
++}
++
++static void write_status(u16 channel_num, u16 value)
++{
++ writel(value, AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].str);
++}
++
++static u16 read_data(u16 channel_num)
++{
++ return readl(AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].idr);
++}
++
++static void write_data(u16 channel_num, u16 value)
++{
++ writel(value, AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].odr);
++}
++
++static void set_kcs_state(u16 channel_num, u16 state)
++{
++ u16 status = read_status(channel_num);
++
++ status &= ~KCS_STATE_MASK;
++ status |= KCS_STATE(state) & KCS_STATE_MASK;
++ write_status(channel_num, status);
++}
++
++static struct kcs_packet *get_kcs_packet(u16 channel_num)
++{
++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) {
++ if (channel_num == enabled_kcs_channel[idx])
++ return &m_kcs_pkt[idx];
++ }
++
++ /* very unlike code hits here. */
++ DBG_KCS("ERROR: %s error. ChannelNo: %d\n", __func__, channel_num);
++ BUG();
++}
++
++static void kcs_force_abort(u16 channel_num)
++{
++ struct kcs_packet *kcs_pkt = NULL;
++
++ kcs_pkt = get_kcs_packet(channel_num);
++ DBG_KCS("ERROR: KCS communication aborted (Channel:%d, Error:%d)\n",
++ channel_num, kcs_pkt->error);
++ set_kcs_state(channel_num, KCS_STATE_ERROR);
++ read_data(channel_num);
++ write_data(channel_num, ZERO_DATA);
++
++ kcs_pkt->phase = KCS_PHASE_ERROR;
++ kcs_pkt->read_req_done = false;
++ kcs_pkt->data_in_idx = 0;
++}
++
++static void init_kcs_packet(u16 channel_num)
++{
++ struct kcs_packet *kcs_pkt = NULL;
++
++ kcs_pkt = get_kcs_packet(channel_num);
++ kcs_pkt->channel = channel_num;
++ kcs_pkt->read_req_done = false;
++ kcs_pkt->phase = KCS_PHASE_IDLE;
++ kcs_pkt->error = KCS_NO_ERROR;
++ kcs_pkt->data_in_idx = 0;
++ kcs_pkt->data_out_idx = 0;
++ kcs_pkt->data_out_len = 0;
++}
++
++static void process_kcs_request(u16 channel_num)
++{
++ struct kcs_packet *kcs_pkt = NULL;
++ int i;
++
++ kcs_pkt = get_kcs_packet(channel_num);
++ if (!kcs_pkt->read_req_done)
++ return;
++
++ DBG_KCS("%s:- chan:%d\n", __func__, channel_num);
++
++#ifdef DEBUG_KCS_ENABLED
++ DBG_KCS("Request data(Len:%d): ", kcs_pkt->data_in_idx);
++ for (i = 0; i < kcs_pkt->data_in_idx; i++)
++ DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]);
++ DBG_KCS("\n");
++#endif
++
++ /*
++ * TODO: Move it to IPMI Command Handler
++ * Below code is added for timebeing till
++ * we implement the IPMI command handler.
++ */
++ kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */
++ kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */
++ kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */
++
++ if (((kcs_pkt->data_in[0] >> 2) == 0x06) &&
++ (kcs_pkt->data_in[1] == 0x01)) {
++ /* Get Device ID */
++ u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02,
++ 0xBF, 0x57, 0x01, 0x00, 0x7B,
++ 0x00, 0x00, 0x00, 0x00, 0x00 };
++ for (i = 0; i < 15; i++)
++ kcs_pkt->data_out[i + 3] = device_id[i];
++ kcs_pkt->data_out_len = 18;
++ } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) &&
++ (kcs_pkt->data_in[1] == 0x04)) {
++ /* Get Self Test Results */
++ kcs_pkt->data_out[3] = 0x56;
++ kcs_pkt->data_out[4] = 0x00;
++ kcs_pkt->data_out_len = 5;
++ } else {
++ kcs_pkt->data_out[2] =
++ IPMI_CC_INVALID; /* Invalid or not supported. */
++ kcs_pkt->data_out_len = 3;
++ }
++ /* END: TODO */
++
++#ifdef DEBUG_KCS_ENABLED
++ DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len);
++ for (i = 0; i < kcs_pkt->data_out_len; i++)
++ DBG_KCS(" 0x%02x", kcs_pkt->data_out[i]);
++ DBG_KCS("\n");
++#endif
++
++ kcs_pkt->phase = KCS_PHASE_READ;
++ write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]);
++ kcs_pkt->read_req_done = false;
++}
++
++static void read_kcs_data(u16 channel_num)
++{
++ struct kcs_packet *kcs_pkt = NULL;
++
++ kcs_pkt = get_kcs_packet(channel_num);
++
++ switch (kcs_pkt->phase) {
++ case KCS_PHASE_WRITE_START:
++ kcs_pkt->phase = KCS_PHASE_WRITE_DATA;
++ /* fall through */
++
++ case KCS_PHASE_WRITE_DATA:
++ if (kcs_pkt->data_in_idx >= MAX_KCS_PKT_SIZE) {
++ kcs_pkt->error = KCS_LENGTH_ERROR;
++ kcs_force_abort(channel_num);
++ return;
++ }
++ set_kcs_state(channel_num, KCS_STATE_WRITE);
++ write_data(channel_num, ZERO_DATA);
++ kcs_pkt->data_in[kcs_pkt->data_in_idx++] =
++ read_data(channel_num);
++ break;
++
++ case KCS_PHASE_WRITE_END:
++ if (kcs_pkt->data_in_idx >= MAX_KCS_PKT_SIZE) {
++ kcs_pkt->error = KCS_LENGTH_ERROR;
++ kcs_force_abort(channel_num);
++ return;
++ }
++ set_kcs_state(channel_num, KCS_STATE_READ);
++ kcs_pkt->data_in[kcs_pkt->data_in_idx++] =
++ read_data(channel_num);
++ kcs_pkt->phase = KCS_PHASE_READ_WAIT;
++ kcs_pkt->read_req_done = true;
++
++ process_kcs_request(channel_num);
++ break;
++
++ case KCS_PHASE_READ:
++ if (kcs_pkt->data_out_idx == kcs_pkt->data_out_len)
++ set_kcs_state(channel_num, KCS_STATE_IDLE);
++
++ u8 data = read_data(channel_num);
++ if (data != KCS_CTRL_CODE_READ) {
++ DBG_KCS("Invalid Read data. Phase:%d, Data:0x%02x\n",
++ kcs_pkt->phase, data);
++ set_kcs_state(channel_num, KCS_STATE_ERROR);
++ write_data(channel_num, ZERO_DATA);
++ break;
++ }
++
++ if (kcs_pkt->data_out_idx == kcs_pkt->data_out_len) {
++ write_data(channel_num, ZERO_DATA);
++ kcs_pkt->phase = KCS_PHASE_IDLE;
++ break;
++ }
++ write_data(channel_num,
++ kcs_pkt->data_out[kcs_pkt->data_out_idx++]);
++ break;
++
++ case KCS_PHASE_ABORT_1:
++ set_kcs_state(channel_num, KCS_STATE_READ);
++ read_data(channel_num);
++ write_data(channel_num, kcs_pkt->error);
++ kcs_pkt->phase = KCS_PHASE_ABORT_2;
++ break;
++
++ case KCS_PHASE_ABORT_2:
++ set_kcs_state(channel_num, KCS_STATE_IDLE);
++ read_data(channel_num);
++ write_data(channel_num, ZERO_DATA);
++ kcs_pkt->phase = KCS_PHASE_IDLE;
++ break;
++
++ default:
++ kcs_force_abort(channel_num);
++ }
++}
++
++static void read_kcs_cmd(u16 channel_num)
++{
++ struct kcs_packet *kcs_pkt = NULL;
++
++ kcs_pkt = get_kcs_packet(channel_num);
++
++ set_kcs_state(channel_num, KCS_STATE_WRITE);
++ write_data(channel_num, ZERO_DATA);
++
++ u16 cmd = read_data(channel_num);
++ switch (cmd) {
++ case KCS_CTRL_CODE_WRITE_START:
++ init_kcs_packet(channel_num);
++ kcs_pkt->phase = KCS_PHASE_WRITE_START;
++ break;
++
++ case KCS_CTRL_CODE_WRITE_END:
++ if (kcs_pkt->error != KCS_NO_ERROR) {
++ kcs_force_abort(channel_num);
++ return;
++ }
++
++ kcs_pkt->phase = KCS_PHASE_WRITE_END;
++ break;
++
++ case KCS_CTRL_CODE_GET_STATUS_ABORT:
++ kcs_pkt->phase = KCS_PHASE_ABORT_1;
++ kcs_pkt->error = KCS_ABORT_BY_CMD;
++ break;
++
++ default:
++ kcs_pkt->error = KCS_ILLEGAL_CTRL_CMD;
++ kcs_force_abort(channel_num);
++ }
++}
++
++static void kcs_irq_handler(void *cookie)
++{
++ u32 channel_num = (u32)cookie;
++ /* Look-up the interrupted KCS channel */
++ u16 status = read_status(channel_num);
++ if (status & BIT_STATUS_IBF) {
++ if (status & BIT_STATUS_COD)
++ read_kcs_cmd(channel_num);
++ else
++ read_kcs_data(channel_num);
++ }
++
++ DBG_KCS("%s: chan_no: %d\n", __FUNC__, channel_num);
++}
++
++static void set_kcs_channel_addr(u16 channel_num)
++{
++ u32 val;
++
++ switch (channel_num) {
++ case 1:
++ val = readl(AST_LPC_BASE + LPC_HICR4) & ~BIT_LADR12AS;
++ writel(val, AST_LPC_BASE + LPC_HICR4);
++ val = (KCS_CHANNEL1_ADDR >> 8);
++ writel(val, AST_LPC_BASE + LPC_LADR12H);
++ val = (KCS_CHANNEL1_ADDR & 0xFF);
++ writel(val, AST_LPC_BASE + LPC_LADR12L);
++ break;
++
++ case 2:
++ val = readl(AST_LPC_BASE + LPC_HICR4) | BIT_LADR12AS;
++ writel(val, AST_LPC_BASE + LPC_HICR4);
++ val = (KCS_CHANNEL2_ADDR >> 8);
++ writel(val, AST_LPC_BASE + LPC_LADR12H);
++ val = (KCS_CHANNEL2_ADDR & 0xFF);
++ writel(val, AST_LPC_BASE + LPC_LADR12L);
++ break;
++
++ case 3:
++ val = (KCS_CHANNEL3_ADDR >> 8);
++ writel(val, AST_LPC_BASE + LPC_LADR3H);
++ val = (KCS_CHANNEL3_ADDR & 0xFF);
++ writel(val, AST_LPC_BASE + LPC_LADR3L);
++ break;
++
++ case 4:
++ val = (((KCS_CHANNEL4_ADDR + 1) << 16) | KCS_CHANNEL4_ADDR);
++ writel(val, AST_LPC_BASE + LPC_LADR4);
++ break;
++
++ default:
++ DBG_KCS("Invalid channel (%d) specified\n", channel_num);
++ break;
++ }
++}
++
++static void enable_kcs_channel(u16 channel_num, u16 enable)
++{
++ u32 val;
++
++ switch (channel_num) {
++ case 1:
++ if (enable) {
++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE1;
++ writel(val, AST_LPC_BASE + LPC_HICR2);
++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC1E;
++ writel(val, AST_LPC_BASE + LPC_HICR0);
++ } else {
++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC1E;
++ writel(val, AST_LPC_BASE + LPC_HICR0);
++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE1;
++ writel(val, AST_LPC_BASE + LPC_HICR2);
++ }
++ break;
++
++ case 2:
++ if (enable) {
++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE2;
++ writel(val, AST_LPC_BASE + LPC_HICR2);
++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC2E;
++ writel(val, AST_LPC_BASE + LPC_HICR0);
++ } else {
++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC2E;
++ writel(val, AST_LPC_BASE + LPC_HICR0);
++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE2;
++ writel(val, AST_LPC_BASE + LPC_HICR2);
++ }
++ break;
++
++ case 3:
++ if (enable) {
++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE3;
++ writel(val, AST_LPC_BASE + LPC_HICR2);
++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC3E;
++ writel(val, AST_LPC_BASE + LPC_HICR0);
++ val = readl(AST_LPC_BASE + LPC_HICR4) | BIT_KCSENBL;
++ writel(val, AST_LPC_BASE + LPC_HICR4);
++ } else {
++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC3E;
++ writel(val, AST_LPC_BASE + LPC_HICR0);
++ val = readl(AST_LPC_BASE + LPC_HICR4) & ~BIT_KCSENBL;
++ writel(val, AST_LPC_BASE + LPC_HICR4);
++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE3;
++ writel(val, AST_LPC_BASE + LPC_HICR2);
++ }
++ break;
++
++ case 4:
++ if (enable) {
++ val = readl(AST_LPC_BASE + LPC_HICRB) | BIT_IBFIE4 |
++ BIT_LPC4E;
++ writel(val, AST_LPC_BASE + LPC_HICRB);
++ } else {
++ val = readl(AST_LPC_BASE + LPC_HICRB) &
++ ~(BIT_IBFIE4 | BIT_LPC4E);
++ writel(val, AST_LPC_BASE + LPC_HICRB);
++ }
++ break;
++
++ default:
++ DBG_KCS("Invalid channel (%d) specified\n", channel_num);
++ }
++}
++
++void kcs_init(void)
++{
++ /* Initialize the KCS channels. */
++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) {
++ uint channel_num = (uint)enabled_kcs_channel[idx];
++ DBG_KCS("%s Channel: %d\n", __func__, channel_num);
++ set_kcs_channel_addr(channel_num);
++ enable_kcs_channel(channel_num, 1);
++
++ /* Set KCS channel state to idle */
++ set_kcs_state(channel_num, KCS_STATE_IDLE);
++ /* KCS interrupt */
++ irq_install_handler(IRQ_SRC_KCS_BASE + channel_num - 1,
++ kcs_irq_handler, (void *)channel_num);
++ }
++}
+diff --git a/board/aspeed/ast2600_intel/ast-kcs.h b/board/aspeed/ast2600_intel/ast-kcs.h
+new file mode 100644
+index 000000000000..e9b949eccf69
+--- /dev/null
++++ b/board/aspeed/ast2600_intel/ast-kcs.h
+@@ -0,0 +1,112 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (c) 2018-2020 Intel Corporation */
++
++#include <asm/io.h>
++#include <common.h>
++
++#define KCS_CHANNEL_MAX 4
++#define IRQ_SRC_KCS_BASE 170 /* IRQ 170 */
++#define MAX_KCS_PKT_SIZE (64 * 1024)
++/* KCS channel addresses */
++#define KCS_CHANNEL1_ADDR 0xCA0
++#define KCS_CHANNEL2_ADDR 0xCA8
++#define KCS_CHANNEL3_ADDR 0xCA2 /* KCS SMS */
++#define KCS_CHANNEL4_ADDR 0xCA4 /* KCS SMM */
++
++#define ZERO_DATA 0x00
++
++#define AST_LPC_BASE 0x1e789000
++
++/* Aspeed KCS control registers */
++#define LPC_HICR0 0x00 /* Host Interface Control Register 0 */
++#define LPC_HICR1 0x04 /* Host Interface Control Register 1 */
++#define LPC_HICR2 0x08 /* Host Interface Control Register 2 */
++#define LPC_HICR3 0x0C /* Host Interface Control Register 3 */
++#define LPC_HICR4 0x10 /* Host Interface Control Register 4 */
++#define LPC_LADR3H 0x14 /* LPC channel #3 Address Register H */
++#define LPC_LADR3L 0x18 /* LPC channel #3 Address Register H */
++#define LPC_LADR12H 0x1C /* LPC channel #1#2 Address Register H */
++#define LPC_LADR12L 0x20 /* LPC channel #1#2 Address Register L */
++#define LPC_IDR1 0x24 /* Input Data Register 1 */
++#define LPC_IDR2 0x28 /* Input Data Register 2 */
++#define LPC_IDR3 0x2C /* Input Data Register 3 */
++#define LPC_ODR1 0x30 /* Output Data Register 1 */
++#define LPC_ODR2 0x34 /* Output Data Register 2 */
++#define LPC_ODR3 0x38 /* Output Data Register 3 */
++#define LPC_STR1 0x3C /* Status Register 1 */
++#define LPC_STR2 0x40 /* Status Register 2 */
++#define LPC_STR3 0x44 /* Status Register 3 */
++#define LPC_HICRB 0x100 /* Host Interface Control Register B */
++#define LPC_LADR4 0x110 /* LPC channel #4 Address Register */
++#define LPC_IDR4 0x114 /* Input Data Register 4 */
++#define LPC_ODR4 0x118 /* Output Data Register 4 */
++#define LPC_STR4 0x11C /* Status Data Register 4 */
++
++/* LPC Bits */
++#define BIT_LADR12AS BIT(7) /* Channel Address selection */
++#define BIT_IBFIE1 BIT(1) /* Enable IDR1 Recv completion interrupt */
++#define BIT_IBFIE2 BIT(2) /* Enable IDR2 Recv completion interrupt */
++#define BIT_IBFIE3 BIT(3) /* Enable IBF13 interrupt */
++#define BIT_LPC1E BIT(5) /* Enable LPC channel #1 */
++#define BIT_LPC2E BIT(6) /* Enable LPC channel #2 */
++#define BIT_LPC3E BIT(7) /* Enable LPC channel #2 */
++#define BIT_KCSENBL BIT(2) /* Enable KCS interface in Channel #3 */
++#define BIT_IBFIE4 BIT(1)
++#define BIT_LPC4E BIT(0)
++
++#define BIT_STATUS_OBF BIT(0) /* Output Data Register full #1/#2/#3 */
++#define BIT_STATUS_IBF BIT(1) /* Input Data Register full #1/#2/#3 */
++#define BIT_STATUS_COD BIT(3) /* Command/Data - (1=command,0=data) */
++
++#define KCS_STATE_MASK 0xC0 /* BIT[6:7] of status register */
++#define KCS_STATE(state) ((state) << 6)
++
++/* IPMI2.0(section 9.7) - KCS interface State Bits */
++#define KCS_STATE_IDLE 0x00
++#define KCS_STATE_READ 0x01
++#define KCS_STATE_WRITE 0x02
++#define KCS_STATE_ERROR 0x03
++
++/* IPMI2.0(section 9.10) - KCS interface control codes */
++#define KCS_CTRL_CODE_GET_STATUS_ABORT 0x60
++#define KCS_CTRL_CODE_WRITE_START 0x61
++#define KCS_CTRL_CODE_WRITE_END 0x62
++#define KCS_CTRL_CODE_READ 0x68
++
++struct kcs_io_reg {
++ u32 idr;
++ u32 odr;
++ u32 str;
++};
++
++enum kcs_phase {
++ KCS_PHASE_IDLE = 0,
++ KCS_PHASE_WRITE_START = 1,
++ KCS_PHASE_WRITE_DATA = 2,
++ KCS_PHASE_WRITE_END = 3,
++ KCS_PHASE_READ_WAIT = 4,
++ KCS_PHASE_READ = 5,
++ KCS_PHASE_ABORT_1 = 6,
++ KCS_PHASE_ABORT_2 = 7,
++ KCS_PHASE_ERROR = 8
++};
++
++enum kcs_error {
++ KCS_NO_ERROR = 0x00,
++ KCS_ABORT_BY_CMD = 0x01,
++ KCS_ILLEGAL_CTRL_CMD = 0x02,
++ KCS_LENGTH_ERROR = 0x06,
++ KCS_UNSPECIFIED_ERROR = 0xFF,
++};
++
++struct kcs_packet {
++ enum kcs_phase phase;
++ enum kcs_error error;
++ u16 channel;
++ bool read_req_done;
++ u16 data_in_idx;
++ u8 data_in[MAX_KCS_PKT_SIZE];
++ u16 data_out_len;
++ u16 data_out_idx;
++ u8 data_out[MAX_KCS_PKT_SIZE];
++};
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index befeaff0a953..6ac24beb930b 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -251,6 +251,7 @@ int board_early_init_r(void)
+ }
+
+ extern void espi_init(void);
++extern void kcs_init(void);
+ extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler,
+ void *cookie);
+ int board_late_init(void)
+@@ -260,6 +261,9 @@ int board_late_init(void)
+ timer_enable(0, ONE_SEC_IN_USEC, timer_callback, (void *)0);
+ espi_init();
+
++ if (read_ffuj())
++ kcs_init();
++
+ return 0;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0012-IPMI-command-handler-implementation-in-uboot.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0012-IPMI-command-handler-implementation-in-uboot.patch
new file mode 100644
index 000000000..a4a574424
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0012-IPMI-command-handler-implementation-in-uboot.patch
@@ -0,0 +1,330 @@
+From 19bbdf59f39d295ad3e698b121a0b447b77b927c Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Mon, 20 Apr 2020 16:13:09 -0700
+Subject: [PATCH] IPMI command handler implementation in uboot
+
+IPMI command handler implementation in uBoot.
+Implemented IPMI commands:
+ 1) Get Device ID
+ 2) Get Self Test Result
+
+Tested By:
+Ran the above IPMI command Via KCS channel
+and got proper response.
+- Get Device ID
+ Req: cmdtool.efi 20 18 1
+ Res: 0x00 0x23 0x00 0x82 0x03 0x02 0x00 0x57 0x01 0x00 0x7b 0x00 0x00 0x00 0x00 0x00
+- Get Self Test Results
+ Req: cmdtool.efi 20 18 4
+ Res: 00 56 00
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/Makefile | 1 +
+ board/aspeed/ast2600_intel/ast-kcs.c | 77 +++++++++++---------
+ board/aspeed/ast2600_intel/ipmi-handler.c | 117 ++++++++++++++++++++++++++++++
+ board/aspeed/ast2600_intel/ipmi-handler.h | 39 ++++++++++
+ 4 files changed, 200 insertions(+), 34 deletions(-)
+ create mode 100644 board/aspeed/ast2600_intel/ipmi-handler.c
+ create mode 100644 board/aspeed/ast2600_intel/ipmi-handler.h
+
+diff --git a/board/aspeed/ast2600_intel/Makefile b/board/aspeed/ast2600_intel/Makefile
+index d049922719f3..a0587323afe0 100644
+--- a/board/aspeed/ast2600_intel/Makefile
++++ b/board/aspeed/ast2600_intel/Makefile
+@@ -3,3 +3,4 @@ obj-y += ast-espi.o
+ obj-y += ast-irq.o
+ obj-y += ast-timer.o
+ obj-y += ast-kcs.o
++obj-y += ipmi-handler.o
+diff --git a/board/aspeed/ast2600_intel/ast-kcs.c b/board/aspeed/ast2600_intel/ast-kcs.c
+index a03b7e725370..3889cd9222a4 100644
+--- a/board/aspeed/ast2600_intel/ast-kcs.c
++++ b/board/aspeed/ast2600_intel/ast-kcs.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0
+ // Copyright (c) 2018-2020 Intel Corporation
+
+-#include "ast-kcs.h"
++#include "ipmi-handler.h"
+
+ #ifdef DEBUG_KCS_ENABLED
+ #define DBG_KCS printf
+@@ -9,11 +9,6 @@
+ #define DBG_KCS(...)
+ #endif
+
+-/* TODO: Move to IPMI file. */
+-#define IPMI_CC_OK 0x00
+-#define IPMI_CC_INVALID 0xC1
+-#define IPMI_CC_UNSPECIFIED 0xFF
+-
+ #define KCS_CHANNEL_NO_3 3
+
+ static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 };
+@@ -103,6 +98,7 @@ static void init_kcs_packet(u16 channel_num)
+ static void process_kcs_request(u16 channel_num)
+ {
+ struct kcs_packet *kcs_pkt = NULL;
++ struct ipmi_cmd_data ipmi_data;
+ int i;
+
+ kcs_pkt = get_kcs_packet(channel_num);
+@@ -117,37 +113,49 @@ static void process_kcs_request(u16 channel_num)
+ DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]);
+ DBG_KCS("\n");
+ #endif
++ u8 req_lun = kcs_pkt->data_in[0] & 0x03; /* LUN[1:0] */
++ ipmi_data.net_fun = (kcs_pkt->data_in[0] >> 2); /* netfn[7:2] */
++ ipmi_data.cmd = kcs_pkt->data_in[1]; /* cmd */
++ /* We support only BMC LUN 00h */
++ if (req_lun != LUN_BMC) {
++ kcs_pkt->data_out[0] =
++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun);
++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */
++ kcs_pkt->data_out[2] = IPMI_CC_INVALID_CMD_LUN; /* CC code */
++ kcs_pkt->data_out_len = 3;
++ goto done;
++ }
+
+- /*
+- * TODO: Move it to IPMI Command Handler
+- * Below code is added for timebeing till
+- * we implement the IPMI command handler.
+- */
+- kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */
+- kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */
+- kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */
+-
+- if (((kcs_pkt->data_in[0] >> 2) == 0x06) &&
+- (kcs_pkt->data_in[1] == 0x01)) {
+- /* Get Device ID */
+- u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02,
+- 0xBF, 0x57, 0x01, 0x00, 0x7B,
+- 0x00, 0x00, 0x00, 0x00, 0x00 };
+- for (i = 0; i < 15; i++)
+- kcs_pkt->data_out[i + 3] = device_id[i];
+- kcs_pkt->data_out_len = 18;
+- } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) &&
+- (kcs_pkt->data_in[1] == 0x04)) {
+- /* Get Self Test Results */
+- kcs_pkt->data_out[3] = 0x56;
+- kcs_pkt->data_out[4] = 0x00;
+- kcs_pkt->data_out_len = 5;
+- } else {
+- kcs_pkt->data_out[2] =
+- IPMI_CC_INVALID; /* Invalid or not supported. */
++ /* Boundary check */
++ if ((kcs_pkt->data_in_idx - 2) > sizeof(ipmi_data.req_data)) {
++ kcs_pkt->data_out[0] =
++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun);
++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */
++ kcs_pkt->data_out[2] = IPMI_CC_OUT_OF_SPACE; /* CC code */
+ kcs_pkt->data_out_len = 3;
++ goto done;
+ }
+- /* END: TODO */
++ /* Fill in IPMI request data */
++ ipmi_data.req_len = kcs_pkt->data_in_idx - 2;
++ for (i = 0; i < kcs_pkt->data_in_idx - 2; i++)
++ ipmi_data.req_data[i] = kcs_pkt->data_in[i + 2];
++
++ /* Call IPMI command handler */
++ ipmi_cmd_handler(&ipmi_data);
++
++ /* Get IPMI response and fill KCS out data */
++ /* First 2 bytes in KCS response are netFn, Cmd */
++ kcs_pkt->data_out[0] = GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun);
++ kcs_pkt->data_out[1] = ipmi_data.cmd;
++ if ((ipmi_data.res_len + 2) > sizeof(kcs_pkt->data_out)) {
++ kcs_pkt->data_out[2] = IPMI_CC_UNSPECIFIED; /* CC code */
++ kcs_pkt->data_out_len = 3;
++ goto done;
++ }
++ for (i = 0; i < ipmi_data.res_len; i++)
++ kcs_pkt->data_out[i + 2] = ipmi_data.res_data[i];
++
++ kcs_pkt->data_out_len = ipmi_data.res_len + 2;
+
+ #ifdef DEBUG_KCS_ENABLED
+ DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len);
+@@ -156,6 +164,7 @@ static void process_kcs_request(u16 channel_num)
+ DBG_KCS("\n");
+ #endif
+
++done:
+ kcs_pkt->phase = KCS_PHASE_READ;
+ write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]);
+ kcs_pkt->read_req_done = false;
+diff --git a/board/aspeed/ast2600_intel/ipmi-handler.c b/board/aspeed/ast2600_intel/ipmi-handler.c
+new file mode 100644
+index 000000000000..04732846ac28
+--- /dev/null
++++ b/board/aspeed/ast2600_intel/ipmi-handler.c
+@@ -0,0 +1,117 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018-2020 Intel Corporation
++
++#include "ipmi-handler.h"
++
++/* IPMI network function codes */
++#define NETFN_APP 0x06
++
++/* IPMI command codes */
++#define CMD_GET_DEV_ID 0x01
++#define CMD_GET_SELF_TEST_RESULTS 0x04
++
++typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res);
++
++struct get_dev_id {
++ u8 completion_code;
++ u8 dev_id;
++ u8 dev_rev;
++ u8 fw_rev1;
++ u8 fw_rev2;
++ u8 ipmi_ver;
++ u8 dev_support;
++ u8 mfg_id[3];
++ u8 product_id[2];
++ u8 aux_fw_rev[4];
++};
++struct self_test_res {
++ u8 completion_code;
++ u8 res_byte[2];
++};
++
++struct ipmi_cmd_table {
++ u8 net_fun;
++ u8 cmd;
++ fun_handler process_cmd;
++};
++
++static u16 get_device_id(u8 *req, u16 req_len, u8 *res)
++{
++ /* Get Device ID */
++ bool operation = 1; /* Firmware operation */
++ u8 intel_mfg_id[3] = { 0x57, 0x01, 0x00 };
++ u8 platform_id[2] = { 0x7B, 0x00 };
++ u8 aux_fw_rev[4] = { 0x00, 0x00, 0x00, 0x00 };
++ struct get_dev_id *result = (struct get_dev_id *)res;
++
++ if (req_len != 0) {
++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH;
++ return sizeof(result->completion_code);
++ }
++
++ result->completion_code = IPMI_CC_OK;
++ result->dev_id = 0x23;
++ result->dev_rev = 0x00; /* Not provides dev SDR */
++
++ result->ipmi_ver = 0x02; /* IPMI 2.0 */
++ result->dev_support = 0x00; /* No dev support in this mode */
++ memcpy(result->mfg_id, intel_mfg_id, sizeof(result->mfg_id));
++ memcpy(result->aux_fw_rev, aux_fw_rev, sizeof(result->aux_fw_rev));
++
++ /* TODO: Get Firmware version from flash(PFM Header) */
++ result->fw_rev1 = ((operation << 7) | (0x02 & 0x7F));
++ result->fw_rev2 = 0x03;
++ /* TODO: Read Platform ID from GPIO */
++ memcpy(result->product_id, platform_id, sizeof(result->product_id));
++
++ return sizeof(struct get_dev_id);
++}
++
++static u16 get_self_test_result(u8 *req, u16 req_len, u8 *res)
++{
++ /* Get Self Test Results */
++ struct self_test_res *result = (struct self_test_res *)res;
++
++ if (req_len != 0) {
++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH;
++ return sizeof(result->completion_code);
++ }
++
++ result->completion_code = IPMI_CC_OK;
++ result->res_byte[0] = 0x56; /* Self test function not implemented. */
++ result->res_byte[1] = 0x00;
++
++ return sizeof(struct self_test_res);
++}
++
++const struct ipmi_cmd_table cmd_info[] = {
++ { NETFN_APP, CMD_GET_DEV_ID, get_device_id },
++ { NETFN_APP, CMD_GET_SELF_TEST_RESULTS, get_self_test_result }
++};
++
++#define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info)
++
++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data)
++{
++ int i = 0;
++ for (i = 0; i < CMD_TABLE_SIZE; i++) {
++ if ((cmd_info[i].net_fun == ipmi_data->net_fun) &&
++ (cmd_info[i].cmd == ipmi_data->cmd)) {
++ break;
++ }
++ }
++
++ if (i == CMD_TABLE_SIZE) {
++ /* Invalid or not supported. */
++ ipmi_data->res_data[0] = IPMI_CC_INVALID_CMD;
++ ipmi_data->res_len = 1;
++ return;
++ }
++
++ /* Call the appropriate function handler */
++ ipmi_data->res_len =
++ cmd_info[i].process_cmd(ipmi_data->req_data, ipmi_data->req_len,
++ &ipmi_data->res_data[0]);
++
++ return;
++}
+diff --git a/board/aspeed/ast2600_intel/ipmi-handler.h b/board/aspeed/ast2600_intel/ipmi-handler.h
+new file mode 100644
+index 000000000000..11a2e91fe2c2
+--- /dev/null
++++ b/board/aspeed/ast2600_intel/ipmi-handler.h
+@@ -0,0 +1,39 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (c) 2018-2020 Intel Corporation */
++
++#include "ast-kcs.h"
++
++/* IPMI completion codes */
++#define IPMI_CC_OK 0x00
++#define IPMI_CC_NODE_BUSY 0xC0
++#define IPMI_CC_INVALID_CMD 0xC1
++#define IPMI_CC_INVALID_CMD_LUN 0xC2
++#define IPMI_CC_OUT_OF_SPACE 0xC4
++#define IPMI_CC_INVALID_DATA_LENGTH 0xC7
++#define IPMI_CC_INVALID_DATA_FIELD 0xCC
++#define IPMI_CC_UNSPECIFIED 0xFF
++
++/* BMC IPMB LUNs */
++#define LUN_BMC 0x00
++#define LUN_OEM1 0x01
++#define LUN_SMS 0x02
++#define LUN_OEM2 0x01
++
++
++#define MAX_IPMI_REQ_DATA_SIZE MAX_KCS_PKT_SIZE
++#define MAX_IPMI_RES_DATA_SIZE 64
++
++/* Response netFn[7:2], Lun[1:0] */
++#define GET_RESP_NETFN_LUN(lun, netfn) \
++ ((lun & 0x03) | (((netfn + 1) << 2) & 0xFD))
++
++struct ipmi_cmd_data {
++ u8 net_fun;
++ u8 cmd;
++ u16 req_len;
++ u16 res_len;
++ u8 req_data[MAX_IPMI_REQ_DATA_SIZE];
++ u8 res_data[MAX_IPMI_RES_DATA_SIZE];
++};
++
++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0013-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0013-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch
new file mode 100644
index 000000000..7d7b450a8
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0013-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch
@@ -0,0 +1,58 @@
+From 2d0a3aff4c4aa3a764958579ed10a3aab43a7d8a Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 27 Apr 2020 12:40:01 -0700
+Subject: [PATCH] Add a workaround to cover UART interrupt bug in AST2600 A0
+
+This commit adds a workaround to cover UART interrupt bug in
+AST2600 A0 revision. It makes infinite reading on the UART +0x7c
+register for clearing abnormal interrupts in every milli-second.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/intel.c | 22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 6ac24beb930b..ad5ab7632447 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -221,7 +221,19 @@ void enable_onboard_tpm(void)
+
+ static void timer_callback(void *cookie)
+ {
+- debug("+");
++ uint timer_nr = (uint)cookie;
++ u32 dummy;
++
++ switch (timer_nr) {
++ case 0:
++ /* WA for UART interrupt bug in A0 */
++ dummy = readl(0x1e78307c);
++ dummy = readl(0x1e78407c);
++ dummy = readl(0x1e78d07c);
++ dummy = readl(0x1e78e07c);
++ dummy = readl(0x1e78f07c);
++ break;
++ }
+ }
+
+ int board_early_init_f(void)
+@@ -256,9 +268,13 @@ extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler,
+ void *cookie);
+ int board_late_init(void)
+ {
+-#define ONE_SEC_IN_USEC 1000000
++#define SCU_014 0x014 /* Silicon Revision ID */
++#define REV_ID_AST2600A0 0x05000303 /* AST2600 A0 */
++#define ONE_MSEC_IN_USEC 1000
++
++ if (readl(SCU_BASE | SCU_014) == REV_ID_AST2600A0)
++ timer_enable(0, ONE_MSEC_IN_USEC, timer_callback, (void *)0);
+
+- timer_enable(0, ONE_SEC_IN_USEC, timer_callback, (void *)0);
+ espi_init();
+
+ if (read_ffuj())
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0014-Add-a-workaround-to-cover-eSPI-OOB-free-bug-in-AST26.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0014-Add-a-workaround-to-cover-eSPI-OOB-free-bug-in-AST26.patch
new file mode 100644
index 000000000..0a8333e7d
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0014-Add-a-workaround-to-cover-eSPI-OOB-free-bug-in-AST26.patch
@@ -0,0 +1,138 @@
+From 40ab08221b6f8d67d154d8f91b8e55a11d412120 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 27 Apr 2020 17:05:09 -0700
+Subject: [PATCH] Add a workaround to cover eSPI OOB free bug in AST2600 A0
+
+This commit adds a workaround to cover eSPI OOB free bug in AST2600
+A0 revision. It enables GPIO W7 interrupt to catch eSPI reset signal
+and it sets when the reset signal is deasserted to manually set the
+OOB free bit in eSPI protocol.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/ast-espi.c | 79 ++++++++++++++++++++++++++---------
+ 1 file changed, 59 insertions(+), 20 deletions(-)
+
+diff --git a/board/aspeed/ast2600_intel/ast-espi.c b/board/aspeed/ast2600_intel/ast-espi.c
+index 1d7ae529612d..a8b389f159ef 100644
+--- a/board/aspeed/ast2600_intel/ast-espi.c
++++ b/board/aspeed/ast2600_intel/ast-espi.c
+@@ -88,6 +88,7 @@
+ #define AST_ESPI_OOB_CHRDY BIT(4)
+ #define AST_ESPI_FLASH_SW_CHRDY BIT(7)
+ #define AST_ESPI_FLASH_SW_READ BIT(10)
++#define AST_ESPI_SW_RESET GENMASK(31, 24)
+
+ /* ESPI00C bits (Interrupt Enable) */
+ #define AST_ESPI_IEN_HW_RST BIT(31)
+@@ -122,6 +123,7 @@
+ /* LPC chip ID */
+ #define SCR0SIO 0x170
+ #define IRQ_SRC_ESPI 74 /* IRQ 74 */
++#define IRQ_SRC_GPIO 72 /* IRQ 72 */
+
+ static void espi_handshake_ack(void)
+ {
+@@ -205,9 +207,9 @@ static void espi_irq_handler(void *cookie)
+ }
+
+ if (irq_status & AST_ESPI_HW_RST) {
+- uint32_t v = readl(AST_ESPI_BASE + ESPI000) & 0x00ffffffff;
+- writel(v, AST_ESPI_BASE + ESPI000);
+- v |= 0xff000000;
++ uint32_t v;
++
++ v = readl(AST_ESPI_BASE + ESPI000) | AST_ESPI_OOB_CHRDY;
+ writel(v, AST_ESPI_BASE + ESPI000);
+
+ DBG_ESPI("HW_RESET\n");
+@@ -228,6 +230,56 @@ static void espi_irq_handler(void *cookie)
+ readl(AST_ESPI_BASE + ESPI12C), irq_status);
+ }
+
++static void espi_configure_irq(void)
++{
++ writel(0, AST_ESPI_BASE + ESPI110);
++ writel(0, AST_ESPI_BASE + ESPI114);
++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN |
++ AST_ESPI_PLTRSTN, AST_ESPI_BASE + ESPI118);
++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN |
++ AST_ESPI_PLTRSTN, AST_ESPI_BASE + ESPI094);
++
++ writel(AST_ESPI_SUS_WARN,
++ AST_ESPI_BASE + ESPI120); /* int type 0 susp warn */
++ writel(0, AST_ESPI_BASE + ESPI124);
++ writel(0, AST_ESPI_BASE + ESPI128);
++ writel(AST_ESPI_SUS_WARN,
++ AST_ESPI_BASE +
++ ESPI100); /* Enable sysev1 ints for susp warn */
++
++ writel(AST_ESPI_IEN_HW_RST | AST_ESPI_IEN_SYS1_EV |
++ AST_ESPI_IEN_SYS_EV, AST_ESPI_BASE + ESPI00C);
++}
++
++#define AST_GPIO_BASE 0x1e780000
++#define GPIO_148 0x148 /* GPIO U/V/W/X Interrupt Enable */
++#define GPIO_W7 BIT(23)
++#define GPIO_14C 0x14c /* GPIO U/V/W/X Sensitivity Type 0 */
++#define GPIO_150 0x150 /* GPIO U/V/W/X Sensitivity Type 1 */
++#define GPIO_154 0x154 /* GPIO U/V/W/X Sensitivity Type 2 */
++#define GPIO_158 0x158 /* GPIO U/V/W/X Interrupt Status */
++
++static void espi_reset_handler(void *cookie)
++{
++ if (readl(AST_GPIO_BASE + GPIO_158) & GPIO_W7) {
++ uint32_t v;
++
++ writel(GPIO_W7, AST_GPIO_BASE + GPIO_158);
++
++ v = readl(AST_ESPI_BASE + ESPI000) & ~AST_ESPI_SW_RESET;
++ writel(v, AST_ESPI_BASE + ESPI000);
++ v |= AST_ESPI_SW_RESET;
++ writel(v, AST_ESPI_BASE + ESPI000);
++
++ v = readl(AST_ESPI_BASE + ESPI000) & ~AST_ESPI_OOB_CHRDY;
++ writel(v, AST_ESPI_BASE + ESPI000);
++
++ espi_configure_irq();
++
++ DBG_ESPI("eSPI Reset\n");
++ }
++}
++
+ void espi_init(void)
+ {
+ if (~readl(AST_SCU_BASE + AST_SCU_HW_STRAP2) &
+@@ -266,25 +318,12 @@ void espi_init(void)
+ AST_ESPI_AUTO_ACK_SUS_WARN);
+ writel(v, AST_ESPI_BASE + ESPI080); /* Disable auto H/W ack */
+
+- writel(0, AST_ESPI_BASE + ESPI110);
+- writel(0, AST_ESPI_BASE + ESPI114);
+- writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN |
+- AST_ESPI_PLTRSTN, AST_ESPI_BASE + ESPI118);
+- writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN |
+- AST_ESPI_PLTRSTN, AST_ESPI_BASE + ESPI094);
+-
+- writel(AST_ESPI_SUS_WARN,
+- AST_ESPI_BASE + ESPI120); /* int type 0 susp warn */
+- writel(0, AST_ESPI_BASE + ESPI124);
+- writel(0, AST_ESPI_BASE + ESPI128);
+- writel(AST_ESPI_SUS_WARN,
+- AST_ESPI_BASE +
+- ESPI100); /* Enable sysev1 ints for susp warn */
+-
+- writel(AST_ESPI_IEN_HW_RST | AST_ESPI_IEN_SYS1_EV |
+- AST_ESPI_IEN_SYS_EV, AST_ESPI_BASE + ESPI00C);
++ espi_configure_irq();
+
+ irq_install_handler(IRQ_SRC_ESPI, espi_irq_handler, NULL);
++
++ irq_install_handler(IRQ_SRC_GPIO, espi_reset_handler, NULL);
++ writel(GPIO_W7, AST_GPIO_BASE + GPIO_148);
+ } else {
+ DBG_ESPI("No espi strap\n");
+ }
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0043-AST2600-PFR-u-boot-env-changes-as-per-PFR-BMC-image.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0043-AST2600-PFR-u-boot-env-changes-as-per-PFR-BMC-image.patch
index 1b4201f5e..3d9d50c8d 100644
--- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0043-AST2600-PFR-u-boot-env-changes-as-per-PFR-BMC-image.patch
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0043-AST2600-PFR-u-boot-env-changes-as-per-PFR-BMC-image.patch
@@ -1,36 +1,35 @@
-From 23e29ce85056f2b296d938e1244b5b2f2160069e Mon Sep 17 00:00:00 2001
+From 948a92b3000120f902292b661a544e35d796784a Mon Sep 17 00:00:00 2001
From: Kuiying Wang <kuiying.wang@intel.com>
-Date: Wed, 4 Mar 2020 13:21:12 +0800
-Subject: [PATCH] AST2600: PFR u-boot env changes as per PFR BMC image
+Date: Mon, 13 Apr 2020 09:30:14 +0800
+Subject: [PATCH] PFR u-boot env changes as per PFR BMC image
u-boot env changes as per PFR BMC flash layout.
-Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
---
- include/configs/aspeed-common.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
+ include/configs/aspeed-common.h | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/include/configs/aspeed-common.h b/include/configs/aspeed-common.h
-index 0ece4a1b94..6291e0e7d9 100644
+index 6065ec58db..b13dbd02f3 100644
--- a/include/configs/aspeed-common.h
+++ b/include/configs/aspeed-common.h
-@@ -53,13 +53,13 @@
- * Miscellaneous configurable options
- */
- #ifndef CONFIG_BOOTCOMMAND
--#define CONFIG_BOOTCOMMAND "bootm 20080000"
-+#define CONFIG_BOOTCOMMAND "bootm 20b00000"
+@@ -64,9 +64,11 @@
+ #define CONFIG_ENV_SIZE 0x10000
#endif
- #define CONFIG_SYS_REDUNDAND_ENVIRONMENT
- #define CONFIG_ENV_ADDR_REDUND
- #define CONFIG_ENV_OVERWRITE
- #define AST_FMC_CS0_BASE 0x20000000 /* CS0 */
+
+-#ifndef CONFIG_ENV_OFFSET
-#define CONFIG_ENV_OFFSET 0x2400000
+-#endif
++#undef CONFIG_BOOTCOMMAND
++#define CONFIG_BOOTCOMMAND "bootm 20b00000"
++
++#undef CONFIG_ENV_OFFSET
+#define CONFIG_ENV_OFFSET 0xa0000
- #define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET)
- #define CONFIG_ENV_SIZE 0x10000
- #define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)
+
+ #define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+ #define CONFIG_ENV_OVERWRITE
--
-2.20.1
+2.17.1
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/intel.cfg b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/intel.cfg
index 99ac5a220..ceaf62800 100644
--- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/intel.cfg
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/intel.cfg
@@ -11,7 +11,7 @@ CONFIG_USE_IRQ=y
CONFIG_CMD_IRQ=y
CONFIG_ENV_SIZE=0x10000
CONFIG_ENV_OFFSET=0x2400000
-CONFIG_BOOTCOMMAND="bootm 20080000"
+CONFIG_BOARD_LATE_INIT=y
CONFIG_TARGET_EVB_AST2600A1=n
CONFIG_PHY_NCSI=n
CONFIG_CMD_USB=n
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend
index ff1aa58e3..ae56f11eb 100644
--- a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend
@@ -15,6 +15,11 @@ SRC_URI_append_intel-ast2600 = " \
file://0007-ast2600-Override-OTP-strap-settings.patch \
file://0008-AST2600-Add-TPM-pulse-trigger.patch \
file://0009-AST2600-Disable-DMA-arbitration-options-on-MAC1-and-.patch \
+ file://0010-Fix-timer-support.patch \
+ file://0011-KCS-driver-support-in-uBoot.patch \
+ file://0012-IPMI-command-handler-implementation-in-uboot.patch \
+ file://0013-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch \
+ file://0014-Add-a-workaround-to-cover-eSPI-OOB-free-bug-in-AST26.patch \
"
PFR_SRC_URI = " \
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0001-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0001-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch
new file mode 100644
index 000000000..81e742412
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0001-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch
@@ -0,0 +1,186 @@
+From 0177d25a23d56bca91fa7938d786b709fd7fba3e Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 27 Apr 2020 12:11:06 -0700
+Subject: [PATCH] Add a workaround to cover UART interrupt bug in AST2600 A0
+
+This commit adds a workaround to cover UART interrupt bug in
+AST2600 A0 revision. It makes infinite reading on the UART +0x7c
+register for clearing abnormal interrupts in every milli-second.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g6.dtsi | 20 ++++++-------
+ drivers/tty/serial/8250/8250_of.c | 63 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 73 insertions(+), 10 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 656053386fe8..91f431e419d9 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -502,8 +502,8 @@
+ };
+
+ uart1: serial@1e783000 {
+- compatible = "ns16550a";
+- reg = <0x1e783000 0x20>;
++ compatible = "aspeed,ast2600-uart";
++ reg = <0x1e783000 0x20>, <0x1e6e2014 0x4>, <0x1e78307c 0x4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+@@ -516,8 +516,8 @@
+ };
+
+ uart5: serial@1e784000 {
+- compatible = "ns16550a";
+- reg = <0x1e784000 0x1000>;
++ compatible = "aspeed,ast2600-uart";
++ reg = <0x1e784000 0x20>, <0x1e6e2014 0x4>, <0x1e78407c 0x4>;
+ reg-shift = <2>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART5CLK>;
+@@ -744,8 +744,8 @@
+ };
+
+ uart2: serial@1e78d000 {
+- compatible = "ns16550a";
+- reg = <0x1e78d000 0x20>;
++ compatible = "aspeed,ast2600-uart";
++ reg = <0x1e78d000 0x20>, <0x1e6e2014 0x4>, <0x1e78d07c 0x4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+@@ -758,8 +758,8 @@
+ };
+
+ uart3: serial@1e78e000 {
+- compatible = "ns16550a";
+- reg = <0x1e78e000 0x20>;
++ compatible = "aspeed,ast2600-uart";
++ reg = <0x1e78e000 0x20>, <0x1e6e2014 0x4>, <0x1e78e07c 0x4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+@@ -772,8 +772,8 @@
+ };
+
+ uart4: serial@1e78f000 {
+- compatible = "ns16550a";
+- reg = <0x1e78f000 0x20>;
++ compatible = "aspeed,ast2600-uart";
++ reg = <0x1e78f000 0x20>, <0x1e6e2014 0x4>, <0x1e78f07c 0x4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
+index 9ba31701a372..53850f859424 100644
+--- a/drivers/tty/serial/8250/8250_of.c
++++ b/drivers/tty/serial/8250/8250_of.c
+@@ -16,6 +16,7 @@
+ #include <linux/pm_runtime.h>
+ #include <linux/clk.h>
+ #include <linux/reset.h>
++#include <linux/workqueue.h>
+
+ #include "8250.h"
+
+@@ -24,6 +25,9 @@ struct of_serial_info {
+ struct reset_control *rst;
+ int type;
+ int line;
++ struct workqueue_struct *work_queue;
++ struct delayed_work work_handler;
++ void __iomem *wa_base;
+ };
+
+ #ifdef CONFIG_ARCH_TEGRA
+@@ -202,6 +206,18 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
+ return ret;
+ }
+
++#define WA_DELAY_JIFFIES msecs_to_jiffies(1)
++static void clear_abnormal_int_flags(struct work_struct *work)
++{
++ struct delayed_work *dwork = to_delayed_work(work);
++ struct of_serial_info *info = container_of(dwork, struct of_serial_info,
++ work_handler);
++
++ (void) readl(info->wa_base);
++ queue_delayed_work(info->work_queue, &info->work_handler,
++ WA_DELAY_JIFFIES);
++}
++
+ /*
+ * Try to register a serial port
+ */
+@@ -250,6 +266,47 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
+ if (ret < 0)
+ goto err_dispose;
+
++ if (of_device_is_compatible(ofdev->dev.of_node,
++ "aspeed,ast2600-uart")) {
++ #define REV_ID_AST2600A0 0x05000303
++ void __iomem *chip_id_base;
++ struct resource *res = platform_get_resource(ofdev,
++ IORESOURCE_MEM, 1);
++
++ if (!res || resource_size(res) < 2)
++ goto skip_wa;
++
++ info->wa_base = devm_platform_ioremap_resource(ofdev, 2);
++ if (IS_ERR(info->wa_base))
++ goto skip_wa;
++
++ chip_id_base = devm_ioremap_resource(&ofdev->dev, res);
++ if (IS_ERR(chip_id_base))
++ goto skip_wa;
++
++ if (readl(chip_id_base) == REV_ID_AST2600A0) {
++ info->work_queue = alloc_ordered_workqueue(ofdev->name,
++ 0);
++ if (info->work_queue) {
++ INIT_DELAYED_WORK(&info->work_handler,
++ clear_abnormal_int_flags);
++ queue_delayed_work(info->work_queue,
++ &info->work_handler,
++ WA_DELAY_JIFFIES);
++ dev_info(&ofdev->dev,
++ "AST2600 A0 WA initiated\n");
++ } else {
++ dev_err(&ofdev->dev,
++ "Can't enable AST2600 A0 UART WA\n");
++ }
++ }
++
++ devm_iounmap(&ofdev->dev, chip_id_base);
++ devm_release_mem_region(&ofdev->dev, res->start,
++ resource_size(res));
++ }
++
++skip_wa:
+ info->type = port_type;
+ info->line = ret;
+ platform_set_drvdata(ofdev, info);
+@@ -271,6 +328,11 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
+ {
+ struct of_serial_info *info = platform_get_drvdata(ofdev);
+
++ if (info->work_queue) {
++ cancel_delayed_work_sync(&info->work_handler);
++ destroy_workqueue(info->work_queue);
++ }
++
+ serial8250_unregister_port(info->line);
+
+ reset_control_assert(info->rst);
+@@ -341,6 +403,7 @@ static const struct of_device_id of_platform_serial_table[] = {
+ .data = (void *)PORT_XSCALE, },
+ { .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, },
+ { .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, },
++ { .compatible = "aspeed,ast2600-uart", .data = (void *)PORT_16550A, },
+ { /* end of list */ },
+ };
+ MODULE_DEVICE_TABLE(of, of_platform_serial_table);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed_%.bbappend
index ca534560b..d32f38611 100644
--- a/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed_%.bbappend
+++ b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed_%.bbappend
@@ -4,5 +4,7 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/linux-aspeed:"
#LINUX_VERSION="5.2.11"
# TODO: the base kernel dtsi fixups patch should be pushed upstream
-SRC_URI += "file://intel-ast2600.cfg \
- "
+SRC_URI += " \
+ file://intel-ast2600.cfg \
+ file://0001-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch \
+ "