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/conf/layer.conf20
-rw-r--r--meta-openbmc-mods/meta-ast2600/conf/machine/include/intel-ast2600.inc21
-rw-r--r--meta-openbmc-mods/meta-ast2600/conf/machine/include/obmc-bsp-si-common.inc45
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch1605
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0002-AST2600-Enable-host-searial-port-clock-configuration.patch71
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0003-ast2600-intel-layout-environment-addr.patch66
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch111
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch567
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0006-SPI-Quad-IO-Mode.patch102
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0007-ast2600-Override-OTP-strap-settings.patch57
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0008-AST2600-Add-TPM-pulse-trigger.patch50
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0009-AST2600-Disable-DMA-arbitration-options-on-MAC1-and-.patch57
-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.patch615
-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/0015-net-phy-realtek-Change-LED-configuration.patch40
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-LED-control-support.patch457
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-system-reset-status-support.patch154
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0017-Manufacturing-mode-physical-presence-detection.patch201
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0018-Add-a-workaround-to-cover-VGA-memory-size-bug-in-A0.patch52
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch105
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0022-Reboot-into-UBOOT-on-Watchdog-Failures.patch114
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0023-Add-WDT-to-u-boot-to-cover-booting-failures.patch317
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0024-fix-SUS_WARN-handling-logic.patch128
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0025-ast2600-PFR-platform-EXTRST-reset-mask-selection.patch50
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0026-Enable-PCIe-L1-support.patch40
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0027-ast2600-Add-Mailbox-init-function.patch127
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0028-Improve-randomness-of-mac-address-generation.patch53
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0029-Set-UART-routing-in-lowlevel_init.patch43
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch576
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0031-Add-a-workaround-to-fix-AST2600-A0-booting-issue.patch32
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0032-Disable-eSPI-initialization-in-u-boot-for-normal-boo.patch60
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0033-Disable-debug-interfaces.patch86
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0034-Implement-the-IPMI-commands-in-FFUJ-mode-in-u-boot.patch211
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0035-Remove-u-boot-delay-before-autoboot-in-release-image.patch34
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0036-Disable-BMC-MMIO-Decode-on-VGA-SCU-register-bit.patch62
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0037-Enable-I2C-clock-stretching-and-multi-master-support.patch143
-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.patch35
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-11059/0001-Fix-ext4-block-group-descriptor-sizing.patch62
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-11690/0001-lib-uuid-Fix-unseeded-PRNG-on-RANDOM_UUID-y.patch95
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13104/0001-CVE-2019-13104-ext4-check-for-underflow-in-ext4fs_re.patch41
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13105/0001-fs-ext4-cache-extent-data.patch409
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13105/0002-CVE-2019-13105-ext4-fix-double-free-in-ext4_cache_re.patch30
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13106/0001-CVE-2019-13106-ext4-fix-out-of-bounds-memset.patch49
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0001-image-Correct-comment-for-fit_conf_get_node.patch77
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0008-image-Load-the-correct-configuration-in-fit_check_si.patch51
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0009-fit_check_sign-Allow-selecting-the-configuration-to-.patch101
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0012-image-Use-constants-for-required-and-key-name-hint.patch152
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27097/0001-image-Adjust-the-workings-of-fit_check_format.patch397
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27097/0002-image-Add-an-option-to-do-a-full-check-of-the-FIT.patch212
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27138/0001-image-Check-for-unit-addresses-in-FITs.patch106
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/intel.cfg37
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend114
l---------meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-fw-utils-aspeed-sdk_%.bbappend1
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-graphics/obmc-ikvm/obmc-ikvm/0001-Enable-per-frame-CRC-calculation-option-to-save-netw.patch30
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0001-serial-8250-Add-Aspeed-UART-driver-with-DMA-supporte.patch1184
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0002-serial-8250-Fix-RX-DMA-time-out-property.patch29
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0003-serial-8250_aspeed-Make-port-type-fixed.patch57
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0004-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch269
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/intel-ast2600.cfg23
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed_%.bbappend10
-rw-r--r--meta-openbmc-mods/meta-ast2600/recipes.txt3
65 files changed, 10750 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-ast2600/conf/layer.conf b/meta-openbmc-mods/meta-ast2600/conf/layer.conf
new file mode 100644
index 000000000..72c40f6e1
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/conf/layer.conf
@@ -0,0 +1,20 @@
+LOCALCONF_VERSION = "3"
+# We have a conf and classes directory, add to BBPATH
+BBPATH .= ":${LAYERDIR}"
+
+# We have recipes-* directories, add to BBFILES
+BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "ast2600"
+BBFILE_PATTERN_ast2600 = "^${LAYERDIR}/"
+BBFILE_PRIORITY_ast2600 = "10"
+LAYERSERIES_COMPAT_ast2600 = "gatesgarth hardknott honister"
+
+INHERIT += "extrausers"
+#INHERIT += " cve-check"
+
+EXTRA_USERS_PARAMS:append:pn-intel-platforms = " \
+${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', "usermod -p '\$1\$UGMqyqdG\$FZiylVFmRRfl9Z0Ue8G7e/' root;", '', d)}"
+
+hostname:pn-base-files = "intel-obmc"
diff --git a/meta-openbmc-mods/meta-ast2600/conf/machine/include/intel-ast2600.inc b/meta-openbmc-mods/meta-ast2600/conf/machine/include/intel-ast2600.inc
new file mode 100644
index 000000000..a7146299c
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/conf/machine/include/intel-ast2600.inc
@@ -0,0 +1,21 @@
+COMPATIBLE_MACHINE:intel-ast2600 = "intel-ast2600"
+KMACHINE = "aspeed"
+KERNEL_DEVICETREE = " \
+ ${KMACHINE}-bmc-${COMPATIBLE_MACHINE}.dtb \
+ "
+#KERNEL_DEVICETREE = "${KMACHINE}-ast2600-evb.dtb"
+
+require conf/machine/include/ast2600.inc
+require conf/machine/include/obmc-bsp-si-common.inc
+require conf/machine/include/intel.inc
+
+TARGET_FPU = "hard"
+
+PREFERRED_PROVIDER_u-boot-fw-utils ?= "u-boot-fw-utils-aspeed-sdk"
+
+UBOOT_MACHINE = "ast2600_openbmc_defconfig"
+UBOOT_DEVICETREE = "ast2600-intel"
+
+VIRTUAL-RUNTIME_skeleton_workbook = "${MACHINE}-config"
+
+IMAGE_CLASSES += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'image_types_intel_pfr', '', d)}"
diff --git a/meta-openbmc-mods/meta-ast2600/conf/machine/include/obmc-bsp-si-common.inc b/meta-openbmc-mods/meta-ast2600/conf/machine/include/obmc-bsp-si-common.inc
new file mode 100644
index 000000000..59ec0c2a9
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/conf/machine/include/obmc-bsp-si-common.inc
@@ -0,0 +1,45 @@
+#@TYPE: Machine
+#@NAME: OpenBMC
+#@DESCRIPTION: Common machine configuration for OpenBMC chips
+
+MACHINE_EXTRA_RRECOMMENDS = " kernel-modules"
+EXTRA_IMAGEDEPENDS += "u-boot"
+
+IMAGE_FSTYPES += "squashfs-xz"
+IMAGE_FSTYPES += "mtd-auto"
+INITRAMFS_FSTYPES = "squashfs-xz"
+EXTRA_IMAGECMD:squashfs-xz:append = "-processors ${BB_NUMBER_THREADS} -b 262144 -Xdict-size 100% -Xbcj arm"
+
+KERNEL_CLASSES ?= "kernel-fitimage"
+KERNEL_IMAGETYPES ?= "fitImage"
+KERNEL_EXTRA_ARGS += "LOADADDR=${UBOOT_ENTRYPOINT}"
+
+UBOOT_SUFFIX ?= "bin"
+
+MACHINEOVERRIDES =. "openbmc:"
+
+OBMC_PHOSPHOR_IMAGE_OVERLAY= "1"
+OBMC_IMAGE_EXTRA_INSTALL:append = "u-boot-fw-utils-aspeed-sdk"
+
+IMAGE_CLASSES += "image_types image_types_phosphor_auto qemuboot"
+
+# do not generate an initramfs; use the above squashfs-xz as an initrd instead
+INITRAMFS_FSTYPES = ""
+INITRAMFS_CTYPE = ""
+INITRAMFS_IMAGE = ""
+
+MACHINE_FEATURES_BACKFILL_CONSIDERED = "qemu-usermode"
+
+KERNEL_IMAGETYPES += "zImage"
+
+# runqemu
+QB_SYSTEM_NAME = "qemu-system-arm"
+QB_DEFAULT_FSTYPE = "mtd"
+QB_ROOTFS_OPT = "-drive file=@ROOTFS@,format=raw,if=mtd"
+QB_MACHINE = "-M intel-ast2600"
+QB_OPT_APPEND += " -nographic -serial mon:stdio -serial none"
+QB_OPT_APPEND += " -global driver=aspeed.gpio-ast2600,property=gpioC0,value=true"
+QB_NETWORK_DEVICE = "-net nic,macaddr=C0:FF:EE:00:00:02,model=ftgmac100"
+QB_DEFAULT_KERNEL = "none"
+QB_RNG = ""
+QB_MEM = "1024"
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
new file mode 100644
index 000000000..a2981f822
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch
@@ -0,0 +1,1605 @@
+From 9c65cf5fa3cdbbdf1ac7f8269502ec6564703319 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: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Signed-off-by: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+---
+ arch/arm/dts/ast2600-intel.dts | 202 ++++---------
+ arch/arm/lib/interrupts.c | 5 +
+ arch/arm/mach-aspeed/ast2600/Kconfig | 4 +-
+ board/aspeed/ast2600_intel/Makefile | 3 +
+ 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 | 347 ++++++++++-----------
+ cmd/Kconfig | 2 +-
+ common/autoboot.c | 10 +
+ configs/ast2600_openbmc_defconfig | 2 +-
+ 12 files changed, 999 insertions(+), 334 deletions(-)
+ create mode 100644 board/aspeed/ast2600_intel/ast-espi.c
+ create mode 100644 board/aspeed/ast2600_intel/ast-irq.c
+ create mode 100644 board/aspeed/ast2600_intel/ast-irq.h
+ create mode 100644 board/aspeed/ast2600_intel/ast-timer.c
+
+diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts
+index c76547cd6352..e6197831cf02 100644
+--- a/arch/arm/dts/ast2600-intel.dts
++++ b/arch/arm/dts/ast2600-intel.dts
+@@ -1,10 +1,11 @@
+ // SPDX-License-Identifier: GPL-2.0+
++// Copyright (c) 2019-2021 Intel Corporation
+ /dts-v1/;
+
+ #include "ast2600-u-boot.dtsi"
+
+ / {
+- model = "AST2600 Intel EGS server board";
++ model = "Intel server board with AST2600 as the BMC";
+ compatible = "aspeed,ast2600-intel", "aspeed,ast2600";
+
+ memory {
+@@ -37,6 +38,42 @@
+ clock-frequency = <1200000000>;
+ };
+ };
++
++ system-leds {
++ compatible = "gpio-leds";
++ green-led {
++ label = "green";
++ gpios = <&gpio0 50 GPIO_ACTIVE_LOW>;
++ default-state = "blink";
++ };
++ amber-led {
++ label = "amber";
++ gpios = <&gpio0 51 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++ id-led {
++ label = "id";
++ gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
++ default-state = "blink";
++ };
++ hb-led {
++ label = "hb";
++ gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "heartbeat";
++ };
++ };
++};
++
++&gpio0 {
++ status = "okay";
++};
++
++&uart1 {
++ status = "okay";
++};
++
++&uart2 {
++ status = "okay";
+ };
+
+ &uart5 {
+@@ -49,22 +86,24 @@
+ };
+
+ &wdt1 {
++ u-boot,dm-pre-reloc;
+ status = "okay";
+ };
+
+ &wdt2 {
++ u-boot,dm-pre-reloc;
+ status = "okay";
+ };
+
+ &wdt3 {
++ u-boot,dm-pre-reloc;
+ status = "okay";
+ };
+
+ &mdio {
+ status = "okay";
+ pinctrl-names = "default";
+- pinctrl-0 = < &pinctrl_mdio1_default &pinctrl_mdio2_default
+- &pinctrl_mdio3_default &pinctrl_mdio4_default>;
++ pinctrl-0 = <&pinctrl_mdio2_default>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ethphy0: ethernet-phy@0 {
+@@ -84,14 +123,6 @@
+ };
+ };
+
+-&mac0 {
+- status = "okay";
+- phy-mode = "rgmii";
+- phy-handle = <&ethphy0>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_rgmii1_default>;
+-};
+-
+ &mac1 {
+ status = "okay";
+ phy-mode = "rgmii";
+@@ -100,146 +131,30 @@
+ pinctrl-0 = <&pinctrl_rgmii2_default>;
+ };
+
+-&mac2 {
+- status = "okay";
+- phy-mode = "rgmii";
+- phy-handle = <&ethphy2>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_rgmii3_default>;
+-};
+-
+-&mac3 {
+- status = "okay";
+- phy-mode = "rgmii";
+- phy-handle = <&ethphy3>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_rgmii4_default>;
+-};
+-
+ &fmc {
+ status = "okay";
+-
++#if 0
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fmcquad_default>;
+-
+- flash@0 {
+- compatible = "spi-flash", "sst,w25q256";
+- status = "okay";
+- spi-max-frequency = <50000000>;
+- spi-tx-bus-width = <4>;
+- spi-rx-bus-width = <4>;
+- };
+-
+- flash@1 {
+- compatible = "spi-flash", "sst,w25q256";
+- status = "okay";
+- spi-max-frequency = <50000000>;
+- spi-tx-bus-width = <4>;
+- spi-rx-bus-width = <4>;
+- };
+-
+- flash@2 {
+- compatible = "spi-flash", "sst,w25q256";
+- status = "okay";
+- spi-max-frequency = <50000000>;
+- spi-tx-bus-width = <4>;
+- spi-rx-bus-width = <4>;
+- };
+-};
+-
+-&spi1 {
+- status = "okay";
+-
+- pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1abr_default
+- &pinctrl_spi1cs1_default &pinctrl_spi1wp_default
+- &pinctrl_spi1wp_default &pinctrl_spi1quad_default>;
+-
+- flash@0 {
+- compatible = "spi-flash", "sst,w25q256";
+- status = "okay";
+- spi-max-frequency = <50000000>;
+- spi-tx-bus-width = <4>;
+- spi-rx-bus-width = <4>;
+- };
+-
+- flash@1 {
+- compatible = "spi-flash", "sst,w25q256";
+- status = "okay";
+- spi-max-frequency = <50000000>;
+- spi-tx-bus-width = <4>;
+- spi-rx-bus-width = <4>;
+- };
+-};
+-
+-&spi2 {
+- status = "okay";
+-
+- pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_spi2_default &pinctrl_spi2cs1_default
+- &pinctrl_spi2cs2_default &pinctrl_spi2quad_default>;
+-
++#endif
+ flash@0 {
+ compatible = "spi-flash", "sst,w25q256";
+ status = "okay";
+- spi-max-frequency = <50000000>;
+- spi-tx-bus-width = <4>;
+- spi-rx-bus-width = <4>;
+- };
+-
+- flash@1 {
+- compatible = "spi-flash", "sst,w25q256";
+- status = "okay";
+- spi-max-frequency = <50000000>;
+- spi-tx-bus-width = <4>;
+- spi-rx-bus-width = <4>;
+- };
+-
+- flash@2 {
+- compatible = "spi-flash", "sst,w25q256";
+- status = "okay";
+- spi-max-frequency = <50000000>;
+- spi-tx-bus-width = <4>;
+- spi-rx-bus-width = <4>;
++ spi-max-frequency = <40000000>;
++ spi-tx-bus-width = <2>;
++ spi-rx-bus-width = <2>;
+ };
+ };
+
+ &emmc {
+- u-boot,dm-pre-reloc;
+ timing-phase = <0x700ff>;
+ };
+
+ &emmc_slot0 {
+- u-boot,dm-pre-reloc;
+ status = "okay";
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_emmc_default>;
+- sdhci-drive-type = <1>;
+-};
+-
+-&sdhci {
+- timing-phase = <0xc6ffff>;
+-};
+-
+-&sdhci_slot0 {
+- status = "okay";
+- bus-width = <4>;
+- pwr-gpios = <&gpio0 ASPEED_GPIO(V, 0) GPIO_ACTIVE_HIGH>;
+- pwr-sw-gpios = <&gpio0 ASPEED_GPIO(V, 1) GPIO_ACTIVE_HIGH>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_sd1_default>;
+- sdhci-drive-type = <1>;
+-};
+-
+-&sdhci_slot1 {
+- status = "okay";
+- bus-width = <4>;
+- pwr-gpios = <&gpio0 ASPEED_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
+- pwr-sw-gpios = <&gpio0 ASPEED_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_sd2_default>;
+- sdhci-drive-type = <1>;
+ };
+
+ &i2c4 {
+@@ -277,29 +192,32 @@
+ pinctrl-0 = <&pinctrl_i2c9_default>;
+ };
+
+-&pcie_bridge1 {
++&i2c9 {
+ status = "okay";
+-};
+
+-&h2x {
+- status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c10_default>;
+ };
+
+-#if 0
+-&fsim0 {
++&i2c12 {
+ status = "okay";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c13_default>;
+ };
+
+-&fsim1 {
++&i2c13 {
+ status = "okay";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c14_default>;
+ };
+-#endif
+
+-&ehci1 {
++&pcie_bridge1 {
+ status = "okay";
+ };
+
+-&display_port {
++&h2x {
+ status = "okay";
+ };
+
+diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
+index ee775ce5d264..8c985532afb4 100644
+--- a/arch/arm/lib/interrupts.c
++++ b/arch/arm/lib/interrupts.c
+@@ -25,6 +25,7 @@
+
+ DECLARE_GLOBAL_DATA_PTR;
+
++int interrupt_init (void) __attribute__((weak));
+ int interrupt_init (void)
+ {
+ /*
+@@ -35,10 +36,13 @@ int interrupt_init (void)
+ return 0;
+ }
+
++void enable_interrupts (void) __attribute__((weak));
+ void enable_interrupts (void)
+ {
+ return;
+ }
++
++int disable_interrupts (void) __attribute__((weak));
+ int disable_interrupts (void)
+ {
+ return 0;
+@@ -189,6 +193,7 @@ void do_fiq (struct pt_regs *pt_regs)
+ bad_mode ();
+ }
+
++void do_irq (struct pt_regs *pt_regs) __attribute__((weak));
+ void do_irq (struct pt_regs *pt_regs)
+ {
+ efi_restore_gd();
+diff --git a/arch/arm/mach-aspeed/ast2600/Kconfig b/arch/arm/mach-aspeed/ast2600/Kconfig
+index fcdc425de59d..0900d22366d3 100644
+--- a/arch/arm/mach-aspeed/ast2600/Kconfig
++++ b/arch/arm/mach-aspeed/ast2600/Kconfig
+@@ -35,8 +35,8 @@ config TARGET_AST2600_INTEL
+ bool "AST2600-INTEL"
+ depends on ASPEED_AST2600
+ help
+- AST2600-INTEL is an Intel Eagle Stream CRB with
+- AST2600 as the BMC.
++ AST2600-INTEL is an Intel server board with the AST2600
++ as the BMC.
+
+ endchoice
+
+diff --git a/board/aspeed/ast2600_intel/Makefile b/board/aspeed/ast2600_intel/Makefile
+index 1f9fcc73c719..37d2f0064f38 100644
+--- a/board/aspeed/ast2600_intel/Makefile
++++ b/board/aspeed/ast2600_intel/Makefile
+@@ -1 +1,4 @@
+ obj-y += intel.o
++obj-y += ast-espi.o
++obj-y += ast-irq.o
++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..0fdbf089a450
+--- /dev/null
++++ b/board/aspeed/ast2600_intel/ast-espi.c
+@@ -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 0x1e789000
++#define AST_ESPI_BASE 0x1e6ee000
++#define AST_SCU_BASE 0x1e6e2000
++#define AST_SCU_HW_STRAP2 0x510
++#define SCU_HW_STRAP_ESPI_ENABLED 0x40
++
++#define USE_HW_HANDSHAKE 0
++#define DEBUG_ESPI_ENABLED 0
++#if DEBUG_ESPI_ENABLED
++#define DBG_ESPI printf
++#else
++#define DBG_ESPI(...)
++#endif
++
++/* eSPI controller registers */
++#define ESPI000 0x000 /* Engine Control. */
++#define ESPI004 0x004 /* Engine Status. */
++#define ESPI008 0x008 /* Interrupt Status. */
++#define ESPI00C 0x00C /* Interrupt Enable. */
++#define ESPI010 0x010 /* DMA Addr of Peripheral Channel Posted Rx pkt */
++#define ESPI014 0x014 /* Control of Peripheral Channel Posted Rx pkt. */
++#define ESPI018 0x018 /* Data port of Peripheral Channel Posted Rx pkt. */
++#define ESPI020 0x020 /* DMA Addr of Peripheral Channel Posted Tx pkt. */
++#define ESPI024 0x024 /* Control of Peripheral Channel Posted Tx pkt. */
++#define ESPI028 0x028 /* Data port of Peripheral Channel Posted Tx pkt. */
++#define ESPI030 0x030 /* DMA Addr of Peripheral Channel Non-Posted Tx pkt. */
++#define ESPI034 0x034 /* Control of Peripheral Channel Non-Posted Tx pkt. */
++#define ESPI038 0x038 /* Data port of Peripheral Channel Non-Posted Tx pkt. */
++#define ESPI040 0x040 /* DMA Addr of OOB Channel Rx pkt. */
++#define ESPI044 0x044 /* Control of OOB Channel Rx pkt. */
++#define ESPI048 0x048 /* Data port of OOB Channel Rx pkt. */
++#define ESPI050 0x050 /* DMA Addr of OOB Channel Tx pkt. */
++#define ESPI054 0x054 /* Control of OOB Channel Tx pkt. */
++#define ESPI058 0x058 /* Data port of OOB Channel Tx pkt. */
++#define ESPI060 0x060 /* DMA Addr of Flash Channel Rx pkt. */
++#define ESPI064 0x064 /* Control of Flash Channel Rx pkt. */
++#define ESPI068 0x068 /* Data port of Flash Channel Rx pkt. */
++#define ESPI070 0x070 /* DMA Addr of Flash Channel Tx pkt. */
++#define ESPI074 0x074 /* Control of Flash Channel Tx pkt. */
++#define ESPI078 0x078 /* Data port of Flash Channel Tx pkt. */
++#define ESPI080 0x080 /* Engine Control 2. */
++#define ESPI084 0x084 /* Mapping Src Addr of Peripheral Channel Rx pkt. */
++#define ESPI088 0x088 /* Mapping Tgt Addr of Peripheral Channel Rx pkt. */
++#define ESPI08C 0x08C /* Mapping Addr Mask of Peripheral Channel Rx pkt. */
++#define ESPI090 0x090 /* Mapping Target Addr and Mask of Flash Channel. */
++#define ESPI094 0x094 /* Interrupt enable of System Event from Master. */
++#define ESPI098 0x098 /* System Event from and to Master. */
++#define ESPI09C 0x09C /* GPIO through Virtual Wire Channel. */
++#define ESPI0A0 0x0A0 /* General Capabilities and Configurations. */
++#define ESPI0A4 0x0A4 /* Channel 0 Capabilities and Configurations. */
++#define ESPI0A8 0x0A8 /* Channel 1 Capabilities and Configurations. */
++#define ESPI0AC 0x0AC /* Channel 2 Capabilities and Configurations. */
++#define ESPI0B0 0x0B0 /* Channel 3 Capabilities and Configurations. */
++#define ESPI0B4 0x0B4 /* GPIO Direction of Virtual Wire Channel. */
++#define ESPI0B8 0x0B8 /* GPIO Selection of Virtual Wire Channel. */
++#define ESPI0BC 0x0BC /* GPIO Reset Selection of Virtual Wire Channel. */
++#define ESPI100 0x100 /* Interrupt enable of System Event 1 from Master. */
++#define ESPI104 0x104 /* System Event 1 from and to Master. */
++#define ESPI110 0x110 /* Interrupt type 0 of System Event from Master. */
++#define ESPI114 0x114 /* Interrupt type 1 of System Event from Master. */
++#define ESPI118 0x118 /* Interrupt type 2 of System Event from Master. */
++#define ESPI11C 0x11C /* Interrupt status of System Event from Master. */
++#define ESPI120 0x120 /* Interrupt type 0 of System Event 1 from Master. */
++#define ESPI124 0x124 /* Interrupt type 1 of System Event 1 from Master. */
++#define ESPI128 0x128 /* Interrupt type 2 of System Event 1 from Master. */
++#define ESPI12C 0x12C /* Interrupt status of System Event 1 from Master. */
++#define ESPICFG004 0x004 /* Device Identification. */
++#define ESPICFG008 0x008 /* General Capabilities and Configurations. */
++#define ESPICFG010 0x010 /* Channel 0 Capabilities and Configurations. */
++#define ESPICFG020 0x020 /* Channel 1 Capabilities and Configurations. */
++#define ESPICFG030 0x030 /* Channel 2 Capabilities and Configurations. */
++#define ESPICFG040 0x040 /* Channel 3 Capabilities and Configurations. */
++#define ESPICFG044 0x044 /* Channel 3 Capabilities and Configurations 2. */
++#define ESPICFG800 0x800 /* GPIO Direction of Virtual Wire Channel. */
++#define ESPICFG804 0x804 /* GPIO Selection of Virtual Wire Channel. */
++#define ESPICFG808 0x808 /* GPIO Reset Selection of Virtual Wire Channel. */
++#define ESPICFG810 0x810 /* Mapping Src Addr of Peripheral Channel Rx pkt */
++#define ESPICFG814 0x814 /* Mapping Tgt Addr of Peripheral Channel Rx pkt */
++#define ESPICFG818 0x818 /* Mapping Addr Mask of Peripheral Channel Rx pkt */
++
++/* ESPI000 bits */
++#define AST_ESPI_OOB_CHRDY BIT(4)
++#define AST_ESPI_FLASH_SW_CHRDY BIT(7)
++#define AST_ESPI_FLASH_SW_READ BIT(10)
++
++/* ESPI00C bits (Interrupt Enable) */
++#define AST_ESPI_IEN_HW_RST BIT(31)
++#define AST_ESPI_IEN_SYS1_EV BIT(22)
++#define AST_ESPI_IEN_SYS_EV BIT(8)
++#define AST_ESPI_IEN_GPIO_EV BIT(9)
++
++/* ESPI008 bits ISR */
++#define AST_ESPI_VW_SYS_EVT BIT(8)
++#define AST_ESPI_VW_GPIO_EVT BIT(9)
++#define AST_ESPI_VW_SYS_EV1 BIT(22)
++#define AST_ESPI_HW_RST BIT(31)
++
++/* ESPI080 bits */
++#define AST_ESPI_AUTO_ACK_HOST_RST_WARN BIT(2)
++#define AST_ESPI_AUTO_ACK_OOB_RST_WARN BIT(1)
++#define AST_ESPI_AUTO_ACK_SUS_WARN BIT(0)
++
++/* ESPI098 and ESPI11C bits */
++#define AST_ESPI_OOB_RST_WARN BIT(6)
++#define AST_ESPI_HOST_RST_WARN BIT(8)
++#define AST_ESPI_PLTRSTN BIT(5)
++#define AST_ESPI_OOB_RST_ACK BIT(16)
++#define AST_ESPI_SL_BT_DONE BIT(20)
++#define AST_ESPI_SL_BT_STATUS BIT(23)
++#define AST_ESPI_HOST_RST_ACK BIT(27)
++
++/* ESPI104 bits */
++#define AST_ESPI_SUS_WARN BIT(0)
++#define AST_ESPI_SUS_ACK BIT(20)
++
++/* LPC chip ID */
++#define SCR0SIO 0x170
++#define IRQ_SRC_ESPI 74 /* IRQ 74 */
++
++static void espi_handshake_ack(void)
++{
++ /* IRQ only serviced if strapped, so no strap check */
++ if (!(readl(AST_ESPI_BASE + ESPI098) & AST_ESPI_SL_BT_STATUS)) {
++ DBG_ESPI("Setting espi slave boot done\n");
++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) |
++ AST_ESPI_SL_BT_STATUS | AST_ESPI_SL_BT_DONE;
++ writel(v, AST_ESPI_BASE + ESPI098);
++ }
++
++ uint32_t sys1_event = readl(AST_ESPI_BASE + ESPI104);
++ if (sys1_event & AST_ESPI_SUS_WARN &&
++ !(sys1_event & AST_ESPI_SUS_ACK)) {
++ DBG_ESPI("Boot SUS_WARN, evt: 0x%08x\n", sys1_event);
++ writel(sys1_event | AST_ESPI_SUS_ACK, AST_ESPI_BASE + ESPI104);
++ DBG_ESPI("SUS_WARN sent ack\n");
++ }
++}
++
++int espi_irq_handler(struct pt_regs *regs)
++{
++ uint32_t irq_status = readl(AST_ESPI_BASE + ESPI008);
++
++ DBG_ESPI("espi_irq_handler, ESPI008=0X%x, ESPI00c=0X%x,\
++ ESPI100=0X%x, ESPI11c=0X%x, ESPI094=0X%x,\
++ ESPI12c=0X%x, irq_status=0x%x\n",
++ readl(AST_ESPI_BASE + ESPI008),
++ readl(AST_ESPI_BASE + ESPI00C),
++ readl(AST_ESPI_BASE + ESPI100),
++ readl(AST_ESPI_BASE + ESPI11C),
++ readl(AST_ESPI_BASE + ESPI094),
++ readl(AST_ESPI_BASE + ESPI12C), irq_status);
++
++ if (irq_status & AST_ESPI_VW_SYS_EVT) {
++ uint32_t sys_status = readl(AST_ESPI_BASE + ESPI11C);
++ uint32_t sys_event = readl(AST_ESPI_BASE + ESPI098);
++
++ DBG_ESPI("sys_status : 0x%08X\n", sys_status);
++ if (sys_status & AST_ESPI_HOST_RST_WARN) {
++ DBG_ESPI("HOST_RST_WARN evt: 0x%08X\n", sys_event);
++ if (sys_event & AST_ESPI_HOST_RST_WARN) {
++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) |
++ AST_ESPI_HOST_RST_ACK;
++ writel(v, AST_ESPI_BASE + ESPI098);
++ DBG_ESPI("HOST_RST_WARN sent ack\n");
++ }
++ }
++ if (sys_status & AST_ESPI_OOB_RST_WARN) {
++ DBG_ESPI("OOB_RST_WARN evt: 0x%08X\n", sys_event);
++ if (sys_event & AST_ESPI_OOB_RST_WARN) {
++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) |
++ AST_ESPI_OOB_RST_ACK;
++ writel(v, AST_ESPI_BASE + ESPI098);
++ DBG_ESPI("OOB_RST_WARN sent ack\n");
++ }
++ }
++ if (sys_status & AST_ESPI_PLTRSTN) {
++ DBG_ESPI("PLTRSTN: %c, evt: 0x%08X\n",
++ (sys_event & AST_ESPI_PLTRSTN) ? '1' : '0',
++ sys_event);
++ }
++ writel(sys_status, AST_ESPI_BASE + ESPI11C); /* clear status */
++ }
++
++ if (irq_status & AST_ESPI_VW_SYS_EV1) {
++ uint32_t sys1_status = readl(AST_ESPI_BASE + ESPI12C);
++ uint32_t sys1_event = readl(AST_ESPI_BASE + ESPI104);
++
++ DBG_ESPI("sys1_status : 0x%08X\n", sys1_status);
++ if (sys1_status & AST_ESPI_SUS_WARN) {
++ DBG_ESPI("SUS WARN evt: 0x%08X\n", sys1_event);
++ if (sys1_event & AST_ESPI_SUS_WARN) {
++ uint32_t v = readl(AST_ESPI_BASE + ESPI104) |
++ AST_ESPI_SUS_ACK;
++ writel(v, AST_ESPI_BASE + ESPI104);
++ DBG_ESPI("SUS_WARN sent ack\n");
++ }
++ }
++ writel(sys1_status, AST_ESPI_BASE + ESPI12C); /* clear status */
++ }
++
++ if (irq_status & AST_ESPI_HW_RST) {
++ uint32_t v = readl(AST_ESPI_BASE + ESPI000) & 0x00ffffffff;
++ writel(v, AST_ESPI_BASE + ESPI000);
++ v |= 0xff000000;
++ writel(v, AST_ESPI_BASE + ESPI000);
++
++ DBG_ESPI("HW_RESET\n");
++
++ espi_handshake_ack();
++ }
++
++ writel(irq_status, AST_ESPI_BASE + ESPI008); /* clear irq_status */
++
++ DBG_ESPI("end espi_irq_handler, ESPI008=0X%x, ESPI00c=0X%x,\
++ ESPI100=0X%x, ESPI11c=0X%x, ESPI094=0X%x,\
++ ESPI12c=0X%x, irq_status=0X%x\n",
++ readl(AST_ESPI_BASE + ESPI008),
++ readl(AST_ESPI_BASE + ESPI00C),
++ readl(AST_ESPI_BASE + ESPI100),
++ readl(AST_ESPI_BASE + ESPI11C),
++ readl(AST_ESPI_BASE + ESPI094),
++ readl(AST_ESPI_BASE + ESPI12C), irq_status);
++ return 0;
++}
++
++void espi_init(void)
++{
++ if (~readl(AST_SCU_BASE + AST_SCU_HW_STRAP2) &
++ SCU_HW_STRAP_ESPI_ENABLED) {
++ uint32_t v;
++
++ DBG_ESPI("espi init\n");
++
++ writel(0xff000000, AST_SCU_BASE + 0x454); /* driving strength */
++
++ /* Block flash access from Host */
++ v = readl(AST_ESPI_BASE + ESPI000) & ~AST_ESPI_FLASH_SW_CHRDY;
++ v |= AST_ESPI_FLASH_SW_READ | AST_ESPI_OOB_CHRDY;
++ writel(v, AST_ESPI_BASE + ESPI000);
++
++ /*
++ * Set SIO register 0x28 to 0xa8 as a faked ASPEED ChipID for
++ * BIOS using in eSPI mode.
++ */
++ v = readl(AST_LPC_BASE + SCR0SIO) & ~0x000000ff;
++ writel(v, AST_LPC_BASE + SCR0SIO);
++ v = readl(AST_LPC_BASE + SCR0SIO) | 0xa8;
++ writel(v, AST_LPC_BASE + SCR0SIO);
++
++#if USE_HW_HANDSHAKE
++ v = readl(AST_ESPI_BASE + ESPI098) |
++ AST_ESPI_SL_BT_STATUS | AST_ESPI_SL_BT_DONE;
++ writel(v, AST_ESPI_BASE + ESPI098);
++
++ return;
++#endif
++
++ v = readl(AST_ESPI_BASE + ESPI080);
++ v &= ~(AST_ESPI_AUTO_ACK_HOST_RST_WARN |
++ AST_ESPI_AUTO_ACK_OOB_RST_WARN |
++ 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);
++
++ irq_install_handler(IRQ_SRC_ESPI, espi_irq_handler, NULL);
++ } else {
++ DBG_ESPI("No espi strap\n");
++ }
++}
+diff --git a/board/aspeed/ast2600_intel/ast-irq.c b/board/aspeed/ast2600_intel/ast-irq.c
+new file mode 100644
+index 000000000000..f817f8cd7c81
+--- /dev/null
++++ b/board/aspeed/ast2600_intel/ast-irq.c
+@@ -0,0 +1,399 @@
++/*
++ * 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.
++ */
++
++#include <common.h>
++#include <netdev.h>
++#include <asm/io.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++#define GIC_DISTRIBUTOR_OFFSET 0x1000
++#define GIC_CPU_OFFSET 0x2000
++#define GIC_INTERFACE_OFFSET 0x4000
++#define GIC_VIRT_OFFSET 0x6000
++
++#define VIC_STATUS_L 0x80
++#define VIC_STATUS_H 0x84
++#define VIC_IRQ_SELECTION_L 0x98
++#define VIC_IRQ_SELECTION_H 0x9C
++#define VIC_ENABLE_L 0xA0
++#define VIC_ENABLE_H 0xA4
++#define VIC_ENABLE_CLEAR_L 0xA8
++#define VIC_ENABLE_CLEAR_H 0xAC
++#define VIC_INTERRUPT_CLEAR_L 0xD8
++#define VIC_INTERRUPT_CLEAR_H 0xDC
++
++#define VIC_CLEAR_ALL (~0)
++
++/* GIC_DISTRIBUTOR_OFFSET register offsets */
++#define GICD_CTLR 0x000
++#define GICD_TYPER 0x004
++#define GICD_IIDR 0x008
++#define GICD_IGROUPRn 0x080
++#define GICD_ISENABLERn 0x100
++#define GICD_ICENABLERn 0x180
++#define GICD_ISPENDRn 0x200
++#define GICD_ICPENDRn 0x280
++#define GICD_ISACTIVERn 0x300
++#define GICD_ICACTIVERn 0x380
++#define GICD_IPRIORITYRn 0x400
++#define GICD_ITARGETSRn 0x800
++#define GICD_ICFGRn 0xc00
++#define GICD_PPISR 0xd00
++#define GICD_SPISRn 0xd04
++#define GICD_SGIR 0xf00
++#define GICD_CPENDINGIRn 0xf10
++#define GICD_SPENDINGIRn 0xf10
++#define GICD_PIDR4 0xfd0
++#define GICD_PIDR5 0xfd4
++#define GICD_PIDR6 0xfd8
++#define GICD_PIDR7 0xfdc
++#define GICD_PIDR0 0xfe0
++#define GICD_PIDR1 0xfe4
++#define GICD_PIDR2 0xfe8
++#define GICD_PIDR3 0xfec
++#define GICD_CIDR0 0xff0
++#define GICD_CIDR1 0xff4
++#define GICD_CIDR2 0xff8
++#define GICD_CIDR3 0xffc
++
++#define GIC_DISTRIBUTOR_IMPLEMENTER_MAGIC 0x0100143b
++
++/* GIC_CPU_OFFSET register offsets */
++#define GICC_CTLR 0x0000
++#define GICC_PMRn 0x0004
++#define GICC_BPR 0x0008
++#define GICC_IAR 0x000c
++#define GICC_EOIR 0x0010
++#define GICC_RPR 0x0014
++#define GICC_HPPIR 0x0018
++#define GICC_ABPR 0x001c
++#define GICC_AIAR 0x0020
++#define GICC_AEOIR 0x0024
++#define GICC_AHPPIR 0x0028
++#define GICC_APR0 0x00d0
++#define GICC_NSAPR0 0x00e0
++#define GICC_IIDR 0x00fc
++#define GICC_DIR 0x1000
++
++#define GIC_CPU_IMPLEMENTER_MAGIC 0x0102143b
++
++/* GIC_INTERFACE_OFFSET register offsets */
++#define GICH_HCR 0x000
++#define GICH_VTR 0x004
++#define GICH_VMCR 0x008
++#define GICH_MISR 0x010
++#define GICH_EISR0 0x020
++#define GICH_ELSR0 0x020
++#define GICH_APR0 0x0f0
++#define GICH_LR0 0x100
++#define GICH_LR1 0x104
++#define GICH_LR2 0x108
++#define GICH_LR3 0x10c
++
++/* GIC_VIRT_OFFSET register offsets */
++#define GICV_CTLR 0x0000
++#define GICV_PMR 0x0004
++#define GICV_BPR 0x0008
++#define GICV_IAR 0x000c
++#define GICV_EOIR 0x0010
++#define GICV_RPR 0x0014
++#define GICV_HPPIR 0x0018
++#define GICV_ABPR 0x001c
++#define GICV_AIAR 0x0020
++#define GICV_AEOIR 0x0024
++#define GICV_AHPPIR 0x0028
++#define GICV_APR0 0x00d0
++#define GICV_NSAPR0 0x00e0
++#define GICV_IIDR 0x00fc
++#define GICV_DIR 0x1000
++
++#define GIC_VIRT_CPU_IMPLEMENTER_MAGIC 0x0102143b
++
++#define GICD_CTLR_ENABLE 0x03
++
++#define GICD_INT_DEF_PRI 0xa0
++#define GICD_INT_DEF_PRI_X4 (\
++ (GICD_INT_DEF_PRI << 24) |\
++ (GICD_INT_DEF_PRI << 16) |\
++ (GICD_INT_DEF_PRI << 8) |\
++ GICD_INT_DEF_PRI)
++
++#define GICD_INT_ACTLOW_LVLTRIG 0
++#define GICD_INT_EN_CLR_X32 0xffffffff
++#define GICD_INT_EN_CLR_PPI 0xffff0000
++#define GICD_INT_EN_SET_SGI 0x0000ffff
++
++#define gicd_readl(OFFSET) readl(gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET))
++#define gicd_writel(VALUE, OFFSET) \
++ writel((VALUE), gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET))
++#define gicc_readl(OFFSET) readl(gbase + GIC_CPU_OFFSET + (OFFSET))
++#define gich_readl(OFFSET) readl(gbase + GIC_INTERFACE_OFFSET + (OFFSET))
++#define gicv_readl(OFFSET) readl(gbase + GIC_VIRT_OFFSET + (OFFSET))
++
++static size_t max_irq = 0;
++
++#define ITLINES_MASK 0x1f
++#define ITLINES_SHIFT 5
++
++#define GIC_MAX_IRQ 1020
++static interrupt_handler_t *handlers[GIC_MAX_IRQ] = {NULL};
++static unsigned long irq_total = 0;
++static unsigned long irq_counts[GIC_MAX_IRQ] = {0};
++static uint32_t gbase = 0;
++
++/* TODO: This, hard-coded, or from dts? */
++static inline uint32_t gic_base(void)
++{
++ uint32_t base;
++ /* read the base address of the private peripheral space */
++ __asm__ __volatile__("mrc p15, 4, %r0, c15, c0, 0\n\t" : "=r"(base) : );
++ return base;
++}
++
++static void enable_gic(void)
++{
++ uint32_t gicd_ctlr;
++
++ /* add GIC offset ref table 1-3 for interrupt distributor address */
++ gicd_ctlr = gicd_readl(GICD_CTLR);
++ gicd_writel(gicd_ctlr | GICD_CTLR_ENABLE, GICD_CTLR);
++}
++
++static void disable_gic(void)
++{
++ uint32_t gicd_ctlr;
++
++ /* add GIC offset ref table 1-3 for interrupt distributor address */
++ gicd_ctlr = gicd_readl(GICD_CTLR);
++ gicd_writel(gicd_ctlr & ~GICD_CTLR_ENABLE, GICD_CTLR);
++}
++
++static void enable_irq_id(unsigned int id)
++{
++ uint32_t grp = id >> ITLINES_SHIFT;
++ uint32_t grp_bit = 1 << (id & ITLINES_MASK);
++ gicd_writel(grp_bit, GICD_ISENABLERn + grp * sizeof(uint32_t));
++}
++
++static void disable_irq_id(unsigned int id)
++{
++ uint32_t grp = id >> ITLINES_SHIFT;
++ uint32_t grp_bit = 1 << (id & ITLINES_MASK);
++ gicd_writel(grp_bit, GICD_ICENABLERn + grp * sizeof(uint32_t));
++}
++
++static int gic_probe(void)
++{
++ int i;
++ gbase = gic_base();
++ enable_gic();
++
++ if (gicd_readl(GICD_IIDR) != GIC_DISTRIBUTOR_IMPLEMENTER_MAGIC &&
++ gicc_readl(GICC_IIDR) != GIC_CPU_IMPLEMENTER_MAGIC &&
++ gicv_readl(GICV_IIDR) != GIC_VIRT_CPU_IMPLEMENTER_MAGIC)
++ {
++ return 0;
++ }
++ /* GIC supports up to 1020 lines */
++ max_irq = ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) << ITLINES_SHIFT;
++ 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_INT_DEF_PRI_X4, GICD_IPRIORITYRn + 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);
++ }
++ gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn);
++ gicd_writel(GICD_INT_EN_CLR_PPI, GICD_ICENABLERn);
++ gicd_writel(GICD_INT_EN_SET_SGI, GICD_ISENABLERn);
++
++ return 0;
++}
++
++void irq_free_handler (int irq);
++static void gic_shutdown(void)
++{
++ int i;
++ for (i = 0; i < max_irq; i++)
++ {
++ irq_free_handler(i);
++ }
++ disable_gic();
++}
++
++int arch_interrupt_init_early(void)
++{
++ return 0;
++}
++
++int arch_interrupt_init(void)
++{
++ int i;
++ for (i = 0; i < GIC_MAX_IRQ; i++)
++ {
++ handlers[i] = NULL;
++ irq_counts[i] = 0;
++ }
++ return gic_probe();
++}
++
++int arch_interrupt_fini(void)
++{
++ gic_shutdown();
++ return 0;
++}
++
++int interrupt_init (void)
++{
++ /*
++ * setup up stacks if necessary
++ */
++ IRQ_STACK_START_IN = gd->irq_sp + 8;
++
++ printf("%s()\n", __FUNCTION__);
++ return arch_interrupt_init();
++
++ return 0;
++}
++
++int global_interrupts_enabled (void)
++{
++ unsigned long cpsr;
++ __asm__ __volatile__("mrs %0, cpsr\n"
++ : "=r" (cpsr)
++ :
++ : "memory");
++
++ return (cpsr & 0x80) == 0;
++}
++
++void enable_interrupts (void)
++{
++ unsigned long cpsr;
++ __asm__ __volatile__("mrs %0, cpsr\n"
++ "bic %0, %0, #0x80\n"
++ "msr cpsr_c, %0"
++ : "=r" (cpsr)
++ :
++ : "memory");
++
++ return;
++}
++
++int disable_interrupts (void)
++{
++ unsigned long cpsr, temp;
++ __asm__ __volatile__("mrs %0, cpsr\n"
++ "orr %1, %0, #0xc0\n"
++ "msr cpsr_c, %1"
++ : "=r" (cpsr), "=r" (temp)
++ :
++ : "memory");
++ return (cpsr & 0x80) == 0;
++}
++
++void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx)
++{
++ if (irq > max_irq) {
++ printf("irq %d out of range\n", irq);
++ return;
++ }
++ if (handlers[irq]) {
++ printf("irq %d already in use (%p)\n", irq, handlers[irq]);
++ return;
++ }
++ printf("registering handler for irq %d\n", irq);
++ handlers[irq] = handler;
++ enable_irq_id(irq);
++}
++
++void irq_free_handler (int irq)
++{
++ if (irq >= max_irq) {
++ printf("irq %d out of range\n", irq);
++ return;
++ }
++ if (handlers[irq]) {
++ handlers[irq] = NULL;
++ disable_irq_id(irq);
++ }
++}
++
++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("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 +
++ (i >> ITLINES_SHIFT) * sizeof(uint32_t));
++ int irq_enabled = grp_en & (1 << (i & ITLINES_MASK));
++ if (!irq_enabled)
++ continue;
++ printf("% 2i (% 3s): %lu\n", i,
++ (irq_enabled ? "on" : "off"), irq_counts[i]);
++ }
++ printf("total: %lu\n", irq_total);
++ return 0;
++}
++
++void do_irq(struct pt_regs *pt_regs)
++{
++ int i;
++ if (!gbase) {
++ static int printed_msg = 0;
++ if (!printed_msg)
++ {
++ printed_msg = 1;
++ printf("interrupt before configured!\n");
++ }
++ return;
++ }
++ irq_total++;
++ uint32_t grp_pend = 0;
++ for (i = 0; i < max_irq; i++) {
++ /* limit reads of the pending register to once in 32 */
++ if ((i & ITLINES_MASK) == 0)
++ grp_pend = gicd_readl(GICD_ISPENDRn +
++ (i >> ITLINES_SHIFT) * sizeof(uint32_t));
++ uint32_t pending = grp_pend & (1 << (i & ITLINES_MASK));
++ if (pending) {
++ irq_counts[i]++;
++ /* mask via GICD_ICENABLERn */
++ gicd_writel(pending, GICD_ICENABLERn +
++ (i >> ITLINES_SHIFT) * sizeof(uint32_t));
++ if (handlers[i]) {
++ handlers[i](pt_regs);
++ /* unmask via GICD_ISENABLERn */
++ gicd_writel(pending, GICD_ISENABLERn +
++ (i >> ITLINES_SHIFT) * sizeof(uint32_t));
++ /* clear pending via GICD_ICPENDRn */
++ gicd_writel(pending, GICD_ICPENDRn +
++ (i >> ITLINES_SHIFT) * sizeof(uint32_t));
++ } else {
++ printf("unexpected interrupt %i; masking\n", i);
++ /* clear pending via GICD_ICPENDRn */
++ gicd_writel(pending, GICD_ISPENDRn +
++ (i >> ITLINES_SHIFT) * sizeof(uint32_t));
++ }
++ }
++ }
++}
+diff --git a/board/aspeed/ast2600_intel/ast-irq.h b/board/aspeed/ast2600_intel/ast-irq.h
+new file mode 100644
+index 000000000000..9957f2baa7ff
+--- /dev/null
++++ b/board/aspeed/ast2600_intel/ast-irq.h
+@@ -0,0 +1,8 @@
++#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/ast-timer.c b/board/aspeed/ast2600_intel/ast-timer.c
+new file mode 100644
+index 000000000000..cf8c69aba5d3
+--- /dev/null
++++ b/board/aspeed/ast2600_intel/ast-timer.c
+@@ -0,0 +1,59 @@
++/*
++ * 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.
++ */
++
++#include <common.h>
++#include <asm/io.h>
++
++static const int timer_irqs[] = {48, 49, 50, 51, 52, 53, 54, 55};
++#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
++#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_RELOAD 0x04
++#define TIMER_CONTROL_CLEAR 0x3c
++
++void timer_disable(int n)
++{
++ if (n < 0 || n > 7) {
++ return;
++ }
++ uint32_t tctrl = 0xf << (n * 4);
++ writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL_CLEAR);
++}
++
++void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler)
++{
++ if (n < 0 || n > 7) {
++ return;
++ }
++ if (!freq)
++ return;
++
++ timer_disable(n);
++
++ uint32_t v = TIMER_1MHZ_CLK_COUNT / freq;
++ writel(v, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD);
++
++ uint32_t tctrl = (
++ TIMER_ENABLE |
++ TIMER_1MHZ_CLK_SEL |
++ TIMER_RESET_BY_WDT) << (n * 4);
++
++ if (handler) {
++ irq_install_handler(timer_irqs[n], handler, NULL);
++ tctrl |= (TIMER_ENABLE_IRQ << (n * 4));
++ }
++ writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL);
++}
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index be6dc49a3bc7..fc0e41a47712 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -1,222 +1,193 @@
+-// SPDX-License-Identifier: GPL-2.0+
+-/*
+- * Copyright (C) ASPEED Technology Inc.
+- */
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2019-2021, Intel Corporation.
++
++/* Intel customizations of Das U-Boot */
+ #include <common.h>
++#include <asm/gpio.h>
+ #include <asm/io.h>
+
+-/* SCU registers */
+-#define SCU_BASE 0x1e6e2000
+-#define SCU_PINMUX4 (SCU_BASE + 0x410)
+-#define SCU_PINMUX4_RGMII3TXD1 BIT(19)
+-#define SCU_PINMUX5 (SCU_BASE + 0x414)
+-#define SCU_PINMUX5_SGPMI BIT(27)
+-#define SCU_PINMUX5_SGPMO BIT(26)
+-#define SCU_PINMUX5_SGPMLD BIT(25)
+-#define SCU_PINMUX5_SGPMCK BIT(24)
+-#define SCU_GPIO_PD0 (SCU_BASE + 0x610)
+-#define SCU_GPIO_PD0_B6 BIT(14)
+-#define SCU_PINMUX27 (SCU_BASE + 0x69c)
+-#define SCU_PINMUX27_HBLED_EN BIT(31)
+-
+-/* eSPI registers */
+-#define ESPI_BASE 0x1e6ee000
+-#define ESPI_CTRL (ESPI_BASE + 0x0)
+-#define ESPI_INT_EN (ESPI_BASE + 0xc)
+-#define ESPI_CTRL2 (ESPI_BASE + 0x80)
+-#define ESPI_SYSEVT_INT_EN (ESPI_BASE + 0x94)
+-#define ESPI_SYSEVT1_INT_EN (ESPI_BASE + 0x100)
+-#define ESPI_SYSEVT_INT_T0 (ESPI_BASE + 0x110)
+-#define ESPI_SYSEVT_INT_T1 (ESPI_BASE + 0x114)
+-#define ESPI_SYSEVT1_INT_T0 (ESPI_BASE + 0x120)
+-
+-/* LPC registers */
+-#define LPC_BASE 0x1e789000
+-#define LPC_HICR5 (LPC_BASE + 0x80)
+-#define LPC_HICR5_SIO80HGPIO_EN BIT(31)
+-#define LPC_HICR5_80HGPIO_EN BIT(30)
+-#define LPC_HICR5_80HGPIO_SEL_MASK GENMASK(28, 24)
+-#define LPC_HICR5_80HGPIO_SEL_SHIFT 24
+-#define LPC_HICR5_SNP0_INT_EN BIT(1)
+-#define LPC_HICR5_SNP0_EN BIT(0)
+-#define LPC_HICR6 (LPC_BASE + 0x84)
+-#define LPC_HICR6_STS_SNP1 BIT(1)
+-#define LPC_HICR6_STS_SNP0 BIT(0)
+-#define LPC_SNPWADR (LPC_BASE + 0x90)
+-#define LPC_SNPWADR_SNP0_MASK GENMASK(15, 0)
+-#define LPC_SNPWADR_SNP0_SHIFT 0
+-#define LPC_HICRB (LPC_BASE + 0x100)
+-#define LPC_HICRB_80HSGPIO_EN BIT(13)
+-
+-/* GPIO/SGPIO registers */
+-#define GPIO_BASE 0x1e780000
+-#define GPIO_ABCD_VAL (GPIO_BASE + 0x0)
+-#define GPIO_ABCD_VAL_D4 BIT(28)
+-#define GPIO_ABCD_VAL_C5 BIT(21)
+-#define GPIO_ABCD_VAL_C3 BIT(19)
+-#define GPIO_ABCD_DIR (GPIO_BASE + 0x4)
+-#define GPIO_ABCD_DIR_D4 BIT(28)
+-#define GPIO_ABCD_DIR_C5 BIT(21)
+-#define GPIO_ABCD_DIR_C3 BIT(19)
+-#define GPIO_EFGH_DIR (GPIO_BASE + 0x24)
+-#define GPIO_EFGH_DIR_G6 BIT(22)
+-#define SGPIO_M1_CONF (GPIO_BASE + 0x554)
+-#define SGPIO_M1_CONF_CLKDIV_MASK GENMASK(31, 16)
+-#define SGPIO_M1_CONF_CLKDIV_SHIFT 16
+-#define SGPIO_M1_PINS_MASK GENMASK(10, 6)
+-#define SGPIO_M1_PINS_SHIFT 6
+-#define SPGIO_M1_EN BIT(0)
+-
+-#define LPC_HICR5_UNKVAL_MASK 0x1FFF0000 /* bits with unknown values on reset */
+-
+-static void snoop_init(void)
++/* use GPIOC0 on intel boards */
++#define FFUJ_GPIO "gpio@1e78000016"
++
++int read_ffuj(void)
++{
++ struct gpio_desc desc;
++ int ret;
++
++ ret = dm_gpio_lookup_name(FFUJ_GPIO, &desc);
++ if (ret)
++ return ret;
++ ret = dm_gpio_request(&desc, "ffuj");
++ if (ret)
++ return ret;
++ ret = dm_gpio_set_dir_flags(&desc, GPIOD_ACTIVE_LOW);
++ if (ret)
++ return ret;
++ ret = dm_gpio_get_value(&desc);
++ dm_gpio_free(desc.dev, &desc);
++ return ret;
++}
++
++/* gpio_abort is a weak symbol in common/autoboot.c */
++int gpio_abort(void)
++{
++ int value;
++ /* check ffuj to abort the autoboot */
++ value = read_ffuj();
++ printf("FFUJ: %d\n", value);
++ return value <= 0 ? 0 : 1;
++}
++
++#define SCU_BASE 0x1E6E2000
++int misc_init_r(void)
++{
++ /* This is called near the end of the _r init sequence */
++
++ return 0;
++}
++
++#define SCU_418 0x418 /* Multi-function Pin Control #6 */
++#define SCU_418_PBIO_MASK GENMASK(6, 5)
++#define SCU_4bc 0x4bc /* Multi-function Pin Control #20 */
++#define SCU_4bc_PASSTHRU0_MASK GENMASK(25, 24)
++#define SCU_4bc_PASSTHRU1_MASK GENMASK(27, 26)
++#define SCU_4bc_PASSTHRU2_MASK GENMASK(29, 28)
++
++static void gpio_passthru_init(void)
+ {
+- u32 val;
++ writel(readl(SCU_BASE | SCU_4bc) |
++ SCU_4bc_PASSTHRU0_MASK | SCU_4bc_PASSTHRU1_MASK,
++ SCU_BASE | SCU_4bc);
++ writel(readl(SCU_BASE | SCU_418) | SCU_418_PBIO_MASK,
++ SCU_BASE | SCU_418);
++}
+
++#define AST_LPC_BASE 0x1e789000
++#define LPC_SNOOP_ADDR 0x80
++#define HICR5 0x080 /* Host Interface Control Register 5 */
++#define HICR6 0x084 /* Host Interface Control Register 6 */
++#define SNPWADR 0x090 /* LPC Snoop Address Register */
++#define HICRB 0x100 /* Host Interface Control Register B */
++
++/* HICR5 Bits */
++#define HICR5_EN_SIOGIO (1 << 31) /* Enable SIOGIO */
++#define HICR5_EN80HGIO (1 << 30) /* Enable 80hGIO */
++#define HICR5_SEL80HGIO (0x1f << 24) /* Select 80hGIO */
++#define SET_SEL80HGIO(x) ((x & 0x1f) << 24) /* Select 80hGIO Offset */
++#define HICR5_UNKVAL_MASK 0x1FFF0000 /* Bits with unknown values on reset */
++#define HICR5_ENINT_SNP0W (1 << 1) /* Enable Snooping address 0 */
++#define HICR5_EN_SNP0W (1 << 0) /* Enable Snooping address 0 */
++
++/* HRCR6 Bits */
++#define HICR6_STR_SNP0W (1 << 0) /* Interrupt Status Snoop address 0 */
++#define HICR6_STR_SNP1W (1 << 1) /* Interrupt Status Snoop address 1 */
++
++/* HICRB Bits */
++#define HICRB_EN80HSGIO (1 << 13) /* Enable 80hSGIO */
++#define HICRB_ENSNP0D (1 << 14) /* Enable ACCEPT response for snoop #0 */
++
++static void port80h_snoop_init(void)
++{
++ uint32_t value;
++ /* enable port80h snoop and sgpio */
+ /* set lpc snoop #0 to port 0x80 */
+- val = readl(LPC_SNPWADR) & 0xffff0000;
+- val |= ((0x80 << LPC_SNPWADR_SNP0_SHIFT) &
+- LPC_SNPWADR_SNP0_MASK);
+- writel(val, LPC_SNPWADR);
++ value = readl(AST_LPC_BASE + SNPWADR) & 0xffff0000;
++ writel(value | LPC_SNOOP_ADDR, AST_LPC_BASE + SNPWADR);
+
+ /* clear interrupt status */
+- val = readl(LPC_HICR6);
+- val |= (LPC_HICR6_STS_SNP0 |
+- LPC_HICR6_STS_SNP1);
+- writel(val, LPC_HICR6);
++ value = readl(AST_LPC_BASE + HICR6);
++ value |= HICR6_STR_SNP0W | HICR6_STR_SNP1W;
++ writel(value, AST_LPC_BASE + HICR6);
+
+ /* enable lpc snoop #0 and SIOGIO */
+- val = readl(LPC_HICR5);
+- val |= (LPC_HICR5_SIO80HGPIO_EN |
+- LPC_HICR5_SNP0_EN);
+- writel(val, LPC_HICR5);
++ value = readl(AST_LPC_BASE + HICR5) & ~(HICR5_UNKVAL_MASK);
++ value |= HICR5_EN_SIOGIO | HICR5_EN_SNP0W;
++ writel(value, AST_LPC_BASE + HICR5);
+
+ /* enable port80h snoop on SGPIO */
+- val = readl(LPC_HICRB);
+- val |= LPC_HICRB_80HSGPIO_EN;
+- writel(val, LPC_HICRB);
++ value = readl(AST_LPC_BASE + HICRB) | HICRB_EN80HSGIO | HICRB_ENSNP0D;
++ writel(value, AST_LPC_BASE + HICRB);
+ }
+
++#define AST_GPIO_BASE 0x1e780000
++
+ static void sgpio_init(void)
+ {
+ #define SGPIO_CLK_DIV(N) ((N) << 16)
+ #define SGPIO_BYTES(N) ((N) << 6)
+ #define SGPIO_ENABLE 1
++#define GPIO554 0x554
++#define SCU_414 0x414 /* Multi-function Pin Control #5 */
+ #define SCU_414_SGPM_MASK GENMASK(27, 24)
+
+- /* set the sgpio clock to pclk/(2*(5+1)) or ~2 MHz */
+- u32 val;
+-
+- val = ((256 << SGPIO_M1_CONF_CLKDIV_SHIFT) & SGPIO_M1_CONF_CLKDIV_MASK) |
+- ((10 << SGPIO_M1_PINS_SHIFT) & SGPIO_M1_PINS_MASK) |
+- SPGIO_M1_EN;
+- writel(val, SGPIO_M1_CONF);
++ uint32_t value;
++ /* set the sgpio clock to 2MHz */
++ value = SGPIO_CLK_DIV(24) | SGPIO_BYTES(10) | SGPIO_ENABLE;
++ writel(value, AST_GPIO_BASE + GPIO554);
++ writel(readl(SCU_BASE | SCU_414) | SCU_414_SGPM_MASK,
++ SCU_BASE | SCU_414);
++}
+
+- val = readl(SCU_PINMUX5);
+- val |= (SCU_PINMUX5_SGPMI |
+- SCU_PINMUX5_SGPMO |
+- SCU_PINMUX5_SGPMLD |
+- SCU_PINMUX5_SGPMCK);
+- writel(val, SCU_PINMUX5);
++static void timer_handler(void *regs)
++{
++ printf("+");
+ }
+
+-static void gpio_init(void)
++extern int arch_interrupt_init_early(void);
++int board_early_init_f(void)
+ {
+- /* Default setting of Y23 pad in AST2600 A1 is HBLED so disable it. */
+- writel(readl(SCU_PINMUX27) & ~SCU_PINMUX27_HBLED_EN,
+- SCU_PINMUX27);
+-
+- /*
+- * Set GPIOC3 as an output with value high explicitly since it doesn't
+- * have an external pull up. It uses direct register access because
+- * it's called from board_early_init_f().
+- */
+- writel(readl(SCU_PINMUX4) & ~SCU_PINMUX4_RGMII3TXD1,
+- SCU_PINMUX4);
+- writel(readl(GPIO_ABCD_DIR) | GPIO_ABCD_DIR_C3,
+- GPIO_ABCD_DIR);
+- writel(readl(GPIO_ABCD_VAL) | GPIO_ABCD_VAL_C3,
+- GPIO_ABCD_VAL);
+-
+- writel(readl(SCU_GPIO_PD0) | SCU_GPIO_PD0_B6, SCU_GPIO_PD0);
+-
+- /*
+- * 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.
+- */
+- writel(readl(GPIO_ABCD_DIR) & ~GPIO_ABCD_DIR_C5,
+- GPIO_ABCD_DIR);
+-
+- /*
+- * Set GPIOD4 as an output with value low explicitly to set the
+- * default SPD mux path to CPU and DIMMs.
+- */
+- writel(readl(GPIO_ABCD_DIR) | GPIO_ABCD_DIR_D4,
+- GPIO_ABCD_DIR);
+- writel(readl(GPIO_ABCD_VAL) & ~GPIO_ABCD_VAL_D4,
+- GPIO_ABCD_VAL);
+-
+- /* GPIO G6 is also an open-drain output so set it as an input. */
+- writel(readl(GPIO_EFGH_DIR) & ~GPIO_EFGH_DIR_G6,
+- GPIO_EFGH_DIR);
++ /* 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();
++
++ gpio_passthru_init();
++
++ port80h_snoop_init();
++
++ sgpio_init();
++
++ /* TODO: is it too late to enforce HW security registers? */
++ return 0;
+ }
+
+-static void espi_init(void)
++extern void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler);
++int board_early_init_r(void)
+ {
+- u32 reg;
+-
+- /*
+- * Aspeed STRONGLY NOT recommend to use eSPI early init.
+- *
+- * This eSPI early init sequence merely set OOB_FREE. It
+- * is NOT able to actually handle OOB requests from PCH.
+- *
+- * During the power on stage, PCH keep waiting OOB_FREE
+- * to continue its booting. In general, OOB_FREE is set
+- * when BMC firmware is ready. That is, the eSPI kernel
+- * driver is mounted and ready to serve eSPI. However,
+- * it means that PCH must wait until BMC kernel ready.
+- *
+- * For customers that request PCH booting as soon as
+- * possible. You may use this early init to set OOB_FREE
+- * to prevent PCH from blocking by OOB_FREE before BMC
+- * kernel ready.
+- *
+- * If you are not sure what you are doing, DO NOT use it.
+- */
+- reg = readl(ESPI_CTRL);
+- reg |= 0xef;
+- writel(reg, ESPI_CTRL);
+-
+- writel(0x0, ESPI_SYSEVT_INT_T0);
+- writel(0x0, ESPI_SYSEVT_INT_T1);
+-
+- reg = readl(ESPI_INT_EN);
+- reg |= 0x80000000;
+- writel(reg, ESPI_INT_EN);
+-
+- writel(0xffffffff, ESPI_SYSEVT_INT_EN);
+- writel(0x1, ESPI_SYSEVT1_INT_EN);
+- writel(0x1, ESPI_SYSEVT1_INT_T0);
+-
+- reg = readl(ESPI_CTRL2);
+- reg |= 0x50;
+- writel(reg, ESPI_CTRL2);
+-
+- reg = readl(ESPI_CTRL);
+- reg |= 0x10;
+- writel(reg, ESPI_CTRL);
++ debug("board_early_init_r\n");
++ /* timer_enable(0, 1, timer_handler); */
++
++ return 0;
+ }
+
+-int board_early_init_f(void)
++extern void espi_init(void);
++int board_late_init(void)
+ {
+- snoop_init();
+- gpio_init();
+- sgpio_init();
+ espi_init();
++
+ return 0;
+ }
++
++/* aspeed/board.c defines these functions
++int arch_early_init_r(void)
++{
++ return 0;
++}
++*/
++
++/*
++void board_init(void)
++{
++}
++*/
++
++#ifdef CONFIG_WATCHDOG
++/* watchdog stuff */
++void watchdog_init(void)
++{
++}
++
++void watchdog_reset(void)
++{
++}
++#endif
+diff --git a/cmd/Kconfig b/cmd/Kconfig
+index 1d2aa3a179a7..7599dd052df2 100644
+--- a/cmd/Kconfig
++++ b/cmd/Kconfig
+@@ -1888,7 +1888,7 @@ config CMD_DIAG
+
+ config CMD_IRQ
+ bool "irq - Show information about interrupts"
+- depends on !ARM && !MIPS && !SH
++ depends on !MIPS && !SH
+ help
+ This enables two commands:
+
+diff --git a/common/autoboot.c b/common/autoboot.c
+index 94133eaeda78..5e69000b848b 100644
+--- a/common/autoboot.c
++++ b/common/autoboot.c
+@@ -255,10 +255,20 @@ static int __abortboot(int bootdelay)
+ }
+ # endif /* CONFIG_AUTOBOOT_KEYED */
+
++int gpio_abort(void) __attribute__((weak));
++int gpio_abort(void)
++{
++ return 0;
++}
++
+ static int abortboot(int bootdelay)
+ {
+ int abort = 0;
+
++ abort = gpio_abort();
++ if (abort)
++ return abort;
++
+ if (bootdelay >= 0)
+ abort = __abortboot(bootdelay);
+
+diff --git a/configs/ast2600_openbmc_defconfig b/configs/ast2600_openbmc_defconfig
+index 179e3b005768..90735feec921 100644
+--- a/configs/ast2600_openbmc_defconfig
++++ b/configs/ast2600_openbmc_defconfig
+@@ -35,7 +35,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.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0002-AST2600-Enable-host-searial-port-clock-configuration.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0002-AST2600-Enable-host-searial-port-clock-configuration.patch
new file mode 100644
index 000000000..cd09ab4f0
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0002-AST2600-Enable-host-searial-port-clock-configuration.patch
@@ -0,0 +1,71 @@
+From 816ae827f387922e31281c8b10988870ce9e0294 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Tue, 10 Dec 2019 14:58:10 +0800
+Subject: [PATCH] AST2600: Enable host searial port clock configuration in
+ u-boot
+
+In u-boot could read env variable "hostsearialcfg" and set the corresponding
+clock for host searail port.
+
+Tested:
+setenv hostsearialcfg 1, speed is set to 192Mhz (baud rate 921600)
+other value, speed is set to 24Mhz(baud rate 115200)
+by default is 24Mhz.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ board/aspeed/ast2600_intel/intel.c | 35 ++++++++++++++++++++++++++++++
+ 1 file changed, 35 insertions(+)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 4a40a050c3da..d1ac8651ac6c 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -39,9 +39,44 @@ int gpio_abort(void)
+ }
+
+ #define SCU_BASE 0x1E6E2000
++#define SCU_338 0x338 //Generate UART 24 MHz Reference from UXCLK
++#define SCU_33C 0x33c //Generate UART 24 MHz Reference from HUXCLK
++#define SCU_338_R_VALUE_192MHZ 0x8e
++#define SCU_338_N_VALUE_192MHZ 0x3c3
++#define SCU_338_R_VALUE_24MHZ 0x06
++#define SCU_338_N_VALUE_24MHZ 0x145
++#define HOST_SERIAL_HIGH_SPEED_192MHZ 1
++#define R_VALUE_BITS 8
++#define V_VALUE_BITS 10
++#define R_V_VALUE_MASK (1 << (R_VALUE_BITS + V_VALUE_BITS))
++
+ int misc_init_r(void)
+ {
+ /* This is called near the end of the _r init sequence */
++ /* By default host serail is set 24Mhz */
++ uint32_t host_serial_cfg = 0;
++ char *host_serial_cfg_txt = NULL;
++
++ /* Config the uart clock source based on environment configuration */
++ host_serial_cfg_txt = env_get("hostserialcfg");
++
++ if (host_serial_cfg_txt != NULL)
++ host_serial_cfg = simple_strtoul(host_serial_cfg_txt, NULL, 16);
++
++ if (host_serial_cfg > HOST_SERIAL_HIGH_SPEED_192MHZ || host_serial_cfg < 0) {
++ printf("Invalid hostserialcfg %x, 24Mhz is set by default!\n", host_serial_cfg);
++ host_serial_cfg = 0;
++ }
++
++ if (host_serial_cfg & HOST_SERIAL_HIGH_SPEED_192MHZ) {
++ writel((readl(SCU_BASE | SCU_338) & R_V_VALUE_MASK) |
++ (SCU_338_N_VALUE_192MHZ << R_VALUE_BITS) | SCU_338_R_VALUE_192MHZ,
++ SCU_BASE | SCU_338);
++ } else {
++ writel((readl(SCU_BASE | SCU_338) & R_V_VALUE_MASK) |
++ (SCU_338_N_VALUE_24MHZ << R_VALUE_BITS) | SCU_338_R_VALUE_24MHZ,
++ SCU_BASE | SCU_338);
++ }
+
+ return 0;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0003-ast2600-intel-layout-environment-addr.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0003-ast2600-intel-layout-environment-addr.patch
new file mode 100644
index 000000000..c56fd872d
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0003-ast2600-intel-layout-environment-addr.patch
@@ -0,0 +1,66 @@
+From 665675336251d1daac56ce80d0490a8f71d13411 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Thu, 12 Dec 2019 12:54:18 +0800
+Subject: [PATCH] ast2600: intel-layout-environment-addr
+
+Tested:
+Both kernel and u-boot work at the area /dev/mtd/u-boot-env
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ common/board_r.c | 11 +++++++++--
+ include/configs/aspeed-common.h | 11 ++++++++++-
+ 2 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/common/board_r.c b/common/board_r.c
+index 472987d5d52f..434c0df45c85 100644
+--- a/common/board_r.c
++++ b/common/board_r.c
+@@ -433,10 +433,17 @@ static int should_load_env(void)
+ static int initr_env(void)
+ {
+ /* initialize environment */
+- if (should_load_env())
++ if (should_load_env()) {
++ /*
++ * try again, in case the environment failed to load the first
++ * time
++ */
++ if (!gd->env_valid)
++ env_init();
+ env_relocate();
+- else
++ } else {
+ set_default_env(NULL, 0);
++ }
+ #ifdef CONFIG_OF_CONTROL
+ env_set_hex("fdtcontroladdr",
+ (unsigned long)map_to_sysmem(gd->fdt_blob));
+diff --git a/include/configs/aspeed-common.h b/include/configs/aspeed-common.h
+index 8f404570b1fb..183a7a502e9c 100644
+--- a/include/configs/aspeed-common.h
++++ b/include/configs/aspeed-common.h
+@@ -67,9 +67,18 @@
+ #endif
+
+ #ifndef CONFIG_ENV_OFFSET
+-#define CONFIG_ENV_OFFSET 0xF0000
++#define CONFIG_ENV_OFFSET 0x2400000
+ #endif
+
++#define CONFIG_SYS_REDUNDAND_ENVIRONMENT
++#define CONFIG_ENV_OVERWRITE
++
++#define AST_FMC_CS0_BASE 0x20000000 /* CS0 */
++#define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET)
++#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)
++#define CONFIG_ENV_ADDR_REDUND (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET_REDUND)
++#define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE
++
+ #define CONFIG_ENV_SECT_SIZE (4 << 10)
+
+ /*
+--
+2.17.1
+
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
new file mode 100644
index 000000000..60929ccb0
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch
@@ -0,0 +1,111 @@
+From a7c85034b4a0a7e061930f27a6ec561d23d97cc6 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
+
+- Disabled GPIOC3 to prevent unexpected host failures.
+- Fixed GPIOC5, GPIOD4, GPIOG6, GPIOI0~7, GPIOL6~7 and GPIO_S3
+ directions and default values.
+- Disabled internal pull-down of GPIOB6.
+- Disabled HBLED.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/intel.c | 74 ++++++++++++++++++++++++++++++
+ 1 file changed, 74 insertions(+)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index d1ac8651ac6c..14a20b27e178 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -162,6 +162,78 @@ static void sgpio_init(void)
+ SCU_BASE | SCU_414);
+ }
+
++#define SCU_410 0x410 /* Multi-function Pin Control #4 */
++#define SCU_69C 0x69C /* Multi-function Pin Control #27 */
++#define SCU_69C_HBLED_EN BIT(31)
++#define GPIO_000 0x000 /* GPIO A/B/C/D Value */
++#define GPIO_004 0x004 /* GPIO A/B/C/D Direction */
++#define GPIO_020 0x020 /* GPIO E/F/G/H Value */
++#define GPIO_024 0x024 /* GPIO E/F/G/H Direction */
++#define GPIO_070 0x070 /* GPIO I/J/K/L Value */
++#define GPIO_074 0x074 /* GPIO I/J/K/L Direction */
++#define GPIO_080 0x080 /* GPIO Q/R/S/T Value */
++#define GPIO_084 0x084 /* GPIO Q/R/S/T Direction */
++
++static void set_gpio_default_state(void)
++{
++ /* Default setting of Y23 pad in AST2600 A1 is HBLED so disable it. */
++ writel(readl(SCU_BASE | SCU_69C) & ~SCU_69C_HBLED_EN,
++ SCU_BASE | SCU_69C);
++
++#define SCU_410_RGMII3TXD1 BIT(19)
++#define GPIO_C3 BIT(19)
++
++ /*
++ * Set GPIOC3 as an output with value high explicitly since it doesn't
++ * have an external pull up. It uses direct register access because
++ * it's called from board_early_init_f().
++ */
++ writel(readl(SCU_BASE | SCU_410) & ~SCU_410_RGMII3TXD1,
++ SCU_BASE | SCU_410);
++ writel(readl(AST_GPIO_BASE | GPIO_004) | GPIO_C3,
++ AST_GPIO_BASE | GPIO_004);
++ writel(readl(AST_GPIO_BASE | GPIO_000) | GPIO_C3,
++ AST_GPIO_BASE | GPIO_000);
++
++#define SCU_610 0x610 /* Disable internal pull-down #0 */
++#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,
++ AST_GPIO_BASE | GPIO_004);
++
++ /*
++ * Set GPIOD4 as an output with value low explicitly to set the
++ * default SPD mux path to CPU and DIMMs.
++ */
++#define GPIO_D4 BIT(28)
++ writel(readl(AST_GPIO_BASE | GPIO_004) | GPIO_D4,
++ AST_GPIO_BASE | GPIO_004);
++ writel(readl(AST_GPIO_BASE | GPIO_000) & ~GPIO_D4,
++ AST_GPIO_BASE | GPIO_000);
++
++ /* GPIO G6 is also an open-drain output so set it as an input. */
++#define GPIO_G6 BIT(22)
++ writel(readl(AST_GPIO_BASE | GPIO_024) & ~GPIO_G6,
++ AST_GPIO_BASE | GPIO_024);
++
++ /* Set GPIO S3 as push-pull output high */
++#define GPIO_S3 BIT(19)
++ writel(readl(AST_GPIO_BASE + GPIO_084) | GPIO_S3,
++ AST_GPIO_BASE + GPIO_084);
++ writel(readl(AST_GPIO_BASE + GPIO_080) | GPIO_S3,
++ AST_GPIO_BASE + GPIO_080);
++}
++
+ static void timer_handler(void *regs)
+ {
+ printf("+");
+@@ -175,6 +247,8 @@ int board_early_init_f(void)
+ * I am not sure if it actually does anything... */
+ arch_interrupt_init_early();
+
++ set_gpio_default_state();
++
+ gpio_passthru_init();
+
+ port80h_snoop_init();
+--
+2.17.1
+
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
new file mode 100644
index 000000000..ec4b6be09
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch
@@ -0,0 +1,567 @@
+From 0732dd21869418b4d437b8d1aef239d5348fc94d 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.
+
+Ast2600 is Cortex-A7
+GIC V2 is used as the interrupt controller
+GIC includes GICD and GICC
+
+Testedby:
+1. Enable interrupt based SW handshake for ESPI
+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>
+---
+ 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 c3dfa8de47c8..b62bcdbccf1e 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..5a5e60dbdde4 100644
+--- a/arch/arm/lib/vectors.S
++++ b/arch/arm/lib/vectors.S
+@@ -154,6 +154,17 @@ IRQ_STACK_START_IN:
+ .word 0x0badc0de
+ #endif
+
++#ifdef CONFIG_USE_IRQ
++/* IRQ stack memory (calculated at run-time) */
++.globl IRQ_STACK_START
++IRQ_STACK_START:
++ .word 0x0badc0de
++/* IRQ stack memory (calculated at run-time) */
++.globl FIQ_STACK_START
++FIQ_STACK_START:
++ .word 0x0badc0de
++#endif
++
+ @
+ @ IRQ stack frame.
+ @
+@@ -277,17 +288,30 @@ not_used:
+ bad_save_user_regs
+ bl do_not_used
+
+-
++#ifdef CONFIG_USE_IRQ
++ .align 5
++irq:
++ get_irq_stack
++ irq_save_user_regs
++ bl do_irq
++ irq_restore_user_regs
++ .align 5
++fiq:
++ get_fiq_stack
++ /* someone ought to write a more effective fiq_save_user_regs */
++ irq_save_user_regs
++ bl do_fiq
++ irq_restore_user_regs
++#else
+ .align 5
+ irq:
+ get_bad_stack
+ bad_save_user_regs
+ bl do_irq
+-
+ .align 5
+ fiq:
+ get_bad_stack
+ bad_save_user_regs
+ bl do_fiq
+-
++#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..106bb3b4ffb2 100644
+--- a/board/aspeed/ast2600_intel/ast-irq.c
++++ b/board/aspeed/ast2600_intel/ast-irq.c
+@@ -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
+
+-#define VIC_STATUS_L 0x80
+-#define VIC_STATUS_H 0x84
+-#define VIC_IRQ_SELECTION_L 0x98
+-#define VIC_IRQ_SELECTION_H 0x9C
+-#define VIC_ENABLE_L 0xA0
+-#define VIC_ENABLE_H 0xA4
+-#define VIC_ENABLE_CLEAR_L 0xA8
+-#define VIC_ENABLE_CLEAR_H 0xAC
+-#define VIC_INTERRUPT_CLEAR_L 0xD8
+-#define VIC_INTERRUPT_CLEAR_H 0xDC
+-
+-#define VIC_CLEAR_ALL (~0)
+-
+ /* GIC_DISTRIBUTOR_OFFSET register offsets */
+ #define GICD_CTLR 0x000
+ #define GICD_TYPER 0x004
+@@ -82,7 +62,9 @@ DECLARE_GLOBAL_DATA_PTR;
+ #define GICC_IIDR 0x00fc
+ #define GICC_DIR 0x1000
+
+-#define GIC_CPU_IMPLEMENTER_MAGIC 0x0102143b
++#define GIC_CPU_IMPLEMENTER_MAGIC 0x0102143b
++#define GICC_IAR_INT_ID_MASK 0x3ff
++#define GIC_CPU_DEACTIVATE 0x1000
+
+ /* GIC_INTERFACE_OFFSET register offsets */
+ #define GICH_HCR 0x000
+@@ -116,9 +98,10 @@ DECLARE_GLOBAL_DATA_PTR;
+
+ #define GIC_VIRT_CPU_IMPLEMENTER_MAGIC 0x0102143b
+
+-#define GICD_CTLR_ENABLE 0x03
+-
+-#define GICD_INT_DEF_PRI 0xa0
++#define GICD_CTLR_ENABLE 0x03 /*enable group 0 and 1*/
++#define GICC_CTLR_ENABLE 0x03
++#define GICD_ITARGET_ALL 0xffffffff
++#define GICD_INT_DEF_PRI 0xa0
+ #define GICD_INT_DEF_PRI_X4 (\
+ (GICD_INT_DEF_PRI << 24) |\
+ (GICD_INT_DEF_PRI << 16) |\
+@@ -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
++#define GICD_ICFG_LEVEL_TRIGGER 0x55555555
++#define GICC_UNMASK_ALL_PRIORITY 0xff
+
+ #define gicd_readl(OFFSET) readl(gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET))
+ #define gicd_writel(VALUE, OFFSET) \
+ writel((VALUE), gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET))
+ #define gicc_readl(OFFSET) readl(gbase + GIC_CPU_OFFSET + (OFFSET))
++#define gicc_writel(VALUE, OFFSET) \
++ writel((VALUE), gbase + GIC_CPU_OFFSET + (OFFSET))
+ #define gich_readl(OFFSET) readl(gbase + GIC_INTERFACE_OFFSET + (OFFSET))
+ #define gicv_readl(OFFSET) readl(gbase + GIC_VIRT_OFFSET + (OFFSET))
+-
+-static size_t max_irq = 0;
+-
+ #define ITLINES_MASK 0x1f
+ #define ITLINES_SHIFT 5
+-
+ #define GIC_MAX_IRQ 1020
++#define SPI_INT_NUM_MIN 32
++#define MAX_IRQ 0xfffffffe
++#define DEBUG_IRQ_ENABLED 0
++#if DEBUG_IRQ_ENABLED
++#define DBG_IRQ printf
++#else
++#define DBG_IRQ(...)
++#endif
++
++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};
+ static uint32_t gbase = 0;
+@@ -159,24 +153,31 @@ static inline uint32_t gic_base(void)
+
+ static void enable_gic(void)
+ {
+- uint32_t gicd_ctlr;
++ uint32_t gicd_ctlr, gicc_ctlr;
+
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ /* add GIC offset ref table 1-3 for interrupt distributor address */
+ gicd_ctlr = gicd_readl(GICD_CTLR);
++ gicc_ctlr = gicc_readl(GICC_CTLR);
+ gicd_writel(gicd_ctlr | GICD_CTLR_ENABLE, GICD_CTLR);
++ gicc_writel(gicc_ctlr | GICC_CTLR_ENABLE, GICC_CTLR);
+ }
+
+ static void disable_gic(void)
+ {
+- uint32_t gicd_ctlr;
+-
++ uint32_t gicd_ctlr, gicc_ctlr;
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ /* add GIC offset ref table 1-3 for interrupt distributor address */
+ gicd_ctlr = gicd_readl(GICD_CTLR);
+ gicd_writel(gicd_ctlr & ~GICD_CTLR_ENABLE, GICD_CTLR);
++ gicc_ctlr = gicc_readl(GICC_CTLR);
++ gicc_writel(gicc_ctlr & ~GICC_CTLR_ENABLE, GICC_CTLR);
+ }
+
+ static void enable_irq_id(unsigned int id)
+ {
++ DBG_IRQ(" %s()\n", __FUNCTION__);
++
+ uint32_t grp = id >> ITLINES_SHIFT;
+ uint32_t grp_bit = 1 << (id & ITLINES_MASK);
+ gicd_writel(grp_bit, GICD_ISENABLERn + grp * sizeof(uint32_t));
+@@ -184,6 +185,7 @@ static void enable_irq_id(unsigned int id)
+
+ static void disable_irq_id(unsigned int id)
+ {
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ 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,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));
+
+ if (gicd_readl(GICD_IIDR) != GIC_DISTRIBUTOR_IMPLEMENTER_MAGIC &&
+ gicc_readl(GICC_IIDR) != GIC_CPU_IMPLEMENTER_MAGIC &&
+ gicv_readl(GICV_IIDR) != GIC_VIRT_CPU_IMPLEMENTER_MAGIC)
+ {
++ 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;
+ 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 and target on all interrupts. */
++ for (i = 0; i < max_irq; i += 4) {
+ gicd_writel(GICD_INT_DEF_PRI_X4, GICD_IPRIORITYRn + i);
++ 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);
+ }
+- gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn);
+- gicd_writel(GICD_INT_EN_CLR_PPI, GICD_ICENABLERn);
++ gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn);
++ gicd_writel(GICD_INT_EN_CLR_PPI, GICD_ICENABLERn);
+ 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 +245,7 @@ static int gic_probe(void)
+ void irq_free_handler (int irq);
+ static void gic_shutdown(void)
+ {
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ int i;
+ for (i = 0; i < max_irq; i++)
+ {
+@@ -238,6 +256,7 @@ static void gic_shutdown(void)
+
+ int arch_interrupt_init_early(void)
+ {
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ return 0;
+ }
+
+@@ -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");
+ return gic_probe();
+ }
+
+ int arch_interrupt_fini(void)
+ {
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ gic_shutdown();
+ return 0;
+ }
+
+ int interrupt_init (void)
+ {
+- /*
+- * 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;
+
+- printf("%s()\n", __FUNCTION__);
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ return arch_interrupt_init();
+-
+- return 0;
+ }
+
+ int global_interrupts_enabled (void)
+@@ -286,12 +305,12 @@ void enable_interrupts (void)
+ {
+ unsigned long cpsr;
+ __asm__ __volatile__("mrs %0, cpsr\n"
+- "bic %0, %0, #0x80\n"
++ "bic %0, %0, #0x1c0\n"
+ "msr cpsr_c, %0"
+ : "=r" (cpsr)
+ :
+ : "memory");
+-
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ return;
+ }
+
+@@ -304,11 +323,13 @@ int disable_interrupts (void)
+ : "=r" (cpsr), "=r" (temp)
+ :
+ : "memory");
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ 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 *cookie)
+ {
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ if (irq > max_irq) {
+ printf("irq %d out of range\n", irq);
+ return;
+@@ -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);
+ }
+
+ void irq_free_handler (int irq)
+ {
++ DBG_IRQ(" %s()\n", __FUNCTION__);
+ if (irq >= max_irq) {
+ printf("irq %d out of range\n", irq);
+ return;
+ }
+ 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("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 +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,
++ printf("%2d (%3s): %lu\n", i,
+ (irq_enabled ? "on" : "off"), irq_counts[i]);
+ }
+- printf("total: %lu\n", irq_total);
++ printf("Total: %lu\n", irq_total);
++
+ return 0;
+ }
+
+ void do_irq(struct pt_regs *pt_regs)
+ {
+- int i;
+- if (!gbase) {
+- static int printed_msg = 0;
+- if (!printed_msg)
+- {
+- printed_msg = 1;
+- printf("interrupt before configured!\n");
+- }
+- return;
+- }
+- irq_total++;
+- uint32_t grp_pend = 0;
+- for (i = 0; i < max_irq; i++) {
+- /* limit reads of the pending register to once in 32 */
+- if ((i & ITLINES_MASK) == 0)
+- grp_pend = gicd_readl(GICD_ISPENDRn +
+- (i >> ITLINES_SHIFT) * sizeof(uint32_t));
+- uint32_t pending = grp_pend & (1 << (i & ITLINES_MASK));
+- if (pending) {
+- irq_counts[i]++;
+- /* mask via GICD_ICENABLERn */
+- gicd_writel(pending, GICD_ICENABLERn +
+- (i >> ITLINES_SHIFT) * sizeof(uint32_t));
+- if (handlers[i]) {
+- handlers[i](pt_regs);
+- /* unmask via GICD_ISENABLERn */
+- gicd_writel(pending, GICD_ISENABLERn +
+- (i >> ITLINES_SHIFT) * sizeof(uint32_t));
+- /* clear pending via GICD_ICPENDRn */
+- gicd_writel(pending, GICD_ICPENDRn +
+- (i >> ITLINES_SHIFT) * sizeof(uint32_t));
+- } else {
+- printf("unexpected interrupt %i; masking\n", i);
+- /* clear pending via GICD_ICPENDRn */
+- gicd_writel(pending, GICD_ISPENDRn +
+- (i >> ITLINES_SHIFT) * sizeof(uint32_t));
+- }
++ uint32_t irqstat, irqnr;
++
++ if (irq_total < MAX_IRQ)
++ irq_total++;
++ irqstat = gicc_readl(GICC_IAR);
++ irqnr = irqstat & GICC_IAR_INT_ID_MASK;
++
++ if (irqnr > SPI_INT_NUM_MIN && irqnr < GIC_MAX_IRQ) {
++ gicc_writel(irqnr, GICC_EOIR);
++ if (irq_counts[irqnr] < MAX_IRQ)
++ irq_counts[irqnr]++;
++ if (handlers[irqnr]) {
++ 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 14a20b27e178..d03a446846bc 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -239,7 +239,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.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0006-SPI-Quad-IO-Mode.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0006-SPI-Quad-IO-Mode.patch
new file mode 100644
index 000000000..6e44691f8
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0006-SPI-Quad-IO-Mode.patch
@@ -0,0 +1,102 @@
+From 6fe262f07e116ee185d3acf7967b2ea0d6cc3f3d Mon Sep 17 00:00:00 2001
+From: arun-pm <arun.p.m@linux.intel.com>
+Date: Fri, 29 Nov 2019 00:19:09 +0530
+Subject: [PATCH] SPI Quad IO Mode
+
+This commit adds quad IO mode in SPI driver for AST2600.
+
+Note:- Removed n25q00 Quad I/O support for the time being due to clock issue
+ with chip 'Micron 8UA15 - rw182 (128MB)' while enabling Quad I/O mode.
+---
+ arch/arm/dts/ast2600-intel.dts | 6 ++----
+ drivers/mtd/spi/spi-nor-ids.c | 7 ++++++-
+ drivers/spi/aspeed_spi.c | 18 +++++++++++++++++-
+ 3 files changed, 25 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts
+index e6197831cf02..c7970c16a474 100644
+--- a/arch/arm/dts/ast2600-intel.dts
++++ b/arch/arm/dts/ast2600-intel.dts
+@@ -133,16 +133,14 @@
+
+ &fmc {
+ status = "okay";
+-#if 0
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fmcquad_default>;
+-#endif
+ flash@0 {
+ compatible = "spi-flash", "sst,w25q256";
+ status = "okay";
+ spi-max-frequency = <40000000>;
+- spi-tx-bus-width = <2>;
+- spi-rx-bus-width = <2>;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
+ };
+ };
+
+diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
+index 5882eab2e3fc..42546f4d222a 100644
+--- a/drivers/mtd/spi/spi-nor-ids.c
++++ b/drivers/mtd/spi/spi-nor-ids.c
+@@ -189,7 +189,12 @@ const struct flash_info spi_nor_ids[] = {
+ { INFO("n25q256ax1", 0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+ { INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+ { INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+- { INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
++ /* Removed n25q00 Quad I/O support for the time being due to clock issue with chip 'Micron 8UA15 - rw182 (128MB)'
++ * while enabling Quad I/O mode. As this chip is default shipped in platforms, marking it
++ * as Not supported for the time being. Once all chips are replaced with the new model, this can be enabled
++ * back(Note:- Certain other chips having same name(n25q00) but different part number has no issues).
++ */
++ { INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | NO_CHIP_ERASE) },
+ { INFO("mt25ql02g", 0x20ba22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+ { INFO("n25q00a", 0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+ { INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+diff --git a/drivers/spi/aspeed_spi.c b/drivers/spi/aspeed_spi.c
+index f93200f8f67e..6db64079ae72 100644
+--- a/drivers/spi/aspeed_spi.c
++++ b/drivers/spi/aspeed_spi.c
+@@ -17,6 +17,9 @@
+
+ #define ASPEED_SPI_MAX_CS 3
+ #define FLASH_CALIBRATION_LEN 0x400
++#define AST2600A0 0x05000303
++#define AST2600A0_MAX_FREQ 40000000
++#define AST_MAX_FREQ 100000000
+
+ struct aspeed_spi_regs {
+ u32 conf; /* 0x00 CE Type Setting */
+@@ -1059,6 +1062,19 @@ static int aspeed_spi_bind(struct udevice *bus)
+ return 0;
+ }
+
++static int aspeed_get_max_freq(void)
++{
++ u32 rev_id = readl(ASPEED_REVISION_ID0);
++
++ /*Limit max spi frequency less than 50MHz on AST2600-A0 due
++ * to FWSPICLK signal quality issue.
++ */
++ if(rev_id == AST2600A0)
++ return AST2600A0_MAX_FREQ;
++ else
++ return AST_MAX_FREQ;
++}
++
+ static int aspeed_spi_probe(struct udevice *bus)
+ {
+ struct resource res_regs, res_ahb;
+@@ -1089,7 +1105,7 @@ static int aspeed_spi_probe(struct udevice *bus)
+ clk_free(&hclk);
+
+ priv->max_hz = dev_read_u32_default(bus, "spi-max-frequency",
+- 100000000);
++ aspeed_get_max_freq());
+
+ priv->num_cs = dev_read_u32_default(bus, "num-cs", ASPEED_SPI_MAX_CS);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0007-ast2600-Override-OTP-strap-settings.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0007-ast2600-Override-OTP-strap-settings.patch
new file mode 100644
index 000000000..bab279c40
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0007-ast2600-Override-OTP-strap-settings.patch
@@ -0,0 +1,57 @@
+From 053770be23c7826efefa9b7b087d8b285bf8bbcd Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 29 Jan 2020 14:55:44 -0800
+Subject: [PATCH] ast2600: Override OTP strap settings
+
+This commit adds settings to override OTP strap.
+Also, this commit disables SoC debug interface.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index 81520b0f036e..e479d0276d39 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -44,7 +44,9 @@
+ #define AST_SCU_HPLL_PARAM (AST_SCU_BASE + 0x200)
+ #define AST_SCU_HPLL_PARAM_EXT (AST_SCU_BASE + 0x204)
+ #define AST_SCU_HW_STRAP1 (AST_SCU_BASE + 0x500)
++#define AST_SCU_HW_STRAP1_CLR (AST_SCU_BASE + 0x504)
+ #define AST_SCU_HW_STRAP2 (AST_SCU_BASE + 0x510)
++#define AST_SCU_HW_STRAP2_CLR (AST_SCU_BASE + 0x514)
+ #define AST_SCU_HW_STRAP3 (AST_SCU_BASE + 0x51C)
+ #define AST_SCU_CA7_PARITY_CHK (AST_SCU_BASE + 0x820)
+ #define AST_SCU_CA7_PARITY_CLR (AST_SCU_BASE + 0x824)
+@@ -176,6 +178,26 @@ do_primary_core_setup:
+ /* unlock system control unit */
+ scu_unlock
+
++ /* disable CA7 CPU boot */
++ ldr r0, =AST_SCU_HW_STRAP1_CLR
++ movw r1, #0x0001 @; Disable ARM CA7 CPU boot
++ movt r1, #0x0000
++ str r1, [r0]
++
++ /* enable eSPI, debug interface and disable UART5 boot*/
++ ldr r0, =AST_SCU_HW_STRAP2_CLR
++ movw r1, #0x0040 @; Select eSPI
++ movt r1, #0x0000
++ orr r1, #0x0010 @; Enable debug interface
++ orr r1, #0x0100 @; Disable UART5 boot
++ str r1, [r0]
++
++ /* enable ACPI */
++ ldr r0, =AST_SCU_HW_STRAP2
++ ldr r1, [r0]
++ orr r1, #0x20 @; Enable ACPI
++ str r1, [r0]
++
+ /* identify AST2600 A0/A1 */
+ ldr r0, =AST_SCU_REV_ID
+ ldr r0, [r0]
+--
+2.17.1
+
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
new file mode 100644
index 000000000..f3cb01143
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0008-AST2600-Add-TPM-pulse-trigger.patch
@@ -0,0 +1,50 @@
+From a3b27074feba66aaf63930197b4aa507abdcc983 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
+
+This commit adds TPM pulse trigger into u-boot booting.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/intel.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 634b8ce20e7d..e8165694c312 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -234,6 +234,21 @@ static void set_gpio_default_state(void)
+ AST_GPIO_BASE + GPIO_080);
+ }
+
++void enable_onboard_tpm(void)
++{
++#define GPIO_C2 BIT(18)
++
++ writel(readl(AST_GPIO_BASE | GPIO_004) | GPIO_C2,
++ AST_GPIO_BASE | GPIO_004);
++ writel(readl(AST_GPIO_BASE | GPIO_000) | GPIO_C2,
++ AST_GPIO_BASE | GPIO_000);
++
++ mdelay(50);
++
++ writel(readl(AST_GPIO_BASE | GPIO_000) & ~GPIO_C2,
++ AST_GPIO_BASE | GPIO_000);
++}
++
+ static void timer_handler(void *regs)
+ {
+ printf("+");
+@@ -264,6 +279,8 @@ int board_early_init_r(void)
+ debug("board_early_init_r\n");
+ /* timer_enable(0, 1, timer_handler); */
+
++ enable_onboard_tpm();
++
+ return 0;
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0009-AST2600-Disable-DMA-arbitration-options-on-MAC1-and-.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0009-AST2600-Disable-DMA-arbitration-options-on-MAC1-and-.patch
new file mode 100644
index 000000000..6196551a2
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0009-AST2600-Disable-DMA-arbitration-options-on-MAC1-and-.patch
@@ -0,0 +1,57 @@
+From 970a7c3b21e7264bb6ada434652795b5ce947ac7 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 31 Mar 2020 13:28:31 -0700
+Subject: [PATCH] AST2600: Disable DMA arbitration options on MAC1 and MAC2
+
+Aspeed added 2 new options to DMA arbitration in AST2600A1 MAC1
+and MAC2 but it has a bug in A1 so it might cause the MAC hang if
+we enable these 2 new options.
+Option 1: Round Robin, register MAC58[27]
+Option 2: Tx Valid, register MAC58[28]
+
+So this commit disables options above.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index e479d0276d39..aaacb61a1f8b 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -58,6 +58,12 @@
+ #define AST_FMC_WDT1_CTRL_MODE (AST_FMC_BASE + 0x060)
+ #define AST_FMC_WDT2_CTRL_MODE (AST_FMC_BASE + 0x064)
+
++#define AST_MAC1_BASE (0x1E660000)
++#define AST_MAC1_CTRL2 (AST_MAC1_BASE + 0x058)
++
++#define AST_MAC2_BASE (0x1E680000)
++#define AST_MAC2_CTRL2 (AST_MAC2_BASE + 0x058)
++
+ #define AST_GPIO_BASE (0x1E780000)
+ #define AST_GPIOYZ_DATA_VALUE (AST_GPIO_BASE + 0x1E0)
+
+@@ -245,6 +251,18 @@ wait_lock:
+ bne 2f
+
+ 1:
++ /* disable DMA arbitration on MAC1 (A1 bug) */
++ ldr r0, =AST_MAC1_CTRL2
++ ldr r1, [r0]
++ orr r1, #0x18000000
++ str r1, [r0]
++
++ /* disable DMA arbitration on MAC2 (A1 bug) */
++ ldr r0, =AST_MAC2_CTRL2
++ ldr r1, [r0]
++ orr r1, #0x18000000
++ str r1, [r0]
++
+ /* LPC/eSPI mode selection by SW (AST2600/AST2620 A1 only) */
+ ldr r0, =AST_GPIOYZ_DATA_VALUE
+ ldr r0, [r0]
+--
+2.17.1
+
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..e998ae42f
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0010-Fix-timer-support.patch
@@ -0,0 +1,173 @@
+From 97fc99c77c68ec6b71354786f94a80a26adde389 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 ebf883144418..7c005fb323e6 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -249,16 +249,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();
+@@ -273,11 +271,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();
+
+@@ -285,8 +281,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.17.1
+
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..df10a9a0c
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0011-KCS-driver-support-in-uBoot.patch
@@ -0,0 +1,615 @@
+From b26b11483b006f603e0134551bfb1238e0980972 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.
+ - Get Device ID:
+ Req: ipmitool raw 6 1
+ Res: 23 00 12 03 02 BF 57 01 00 7B 00 00 00 00 00
+ - Get Self Test Results
+ Req: ipmitool raw 6 4
+ Res: 56 00
+ - All other commands
+ Req: ipmitool raw 6 2
+ Res: Unable to send RAW command (channel=0x0 netfn=0x6 lun=0x0
+cmd=0x2 rsp=0xc1): Invalid command
+
+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 7c005fb323e6..b3d2fb313561 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -281,6 +281,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)
+@@ -290,6 +291,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.17.1
+
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..67123645d
--- /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: ipmitool raw 6 1
+ Res: 00 23 00 82 03 02 00 57 01 00 7b 00 00 00 00 00
+- Get Self Test Results
+ Req: ipmitool raw 6 4
+ Res: 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..04baccf66
--- /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 e027384b44aff330375477556eed10c326ad1c48 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 b3d2fb313561..0d1ce69b6e53 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -251,7 +251,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)
+@@ -286,9 +298,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.17.1
+
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/0015-net-phy-realtek-Change-LED-configuration.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0015-net-phy-realtek-Change-LED-configuration.patch
new file mode 100644
index 000000000..e3b53f76a
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0015-net-phy-realtek-Change-LED-configuration.patch
@@ -0,0 +1,40 @@
+From cb1d9b2cb8a3afbbdcc0b5ee81f48c4b185da2bd Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 5 Jun 2020 14:08:20 -0700
+Subject: [PATCH] net: phy: realtek: Change LED configuration
+
+This commit changes Realtek NIC port LED configuration like below:
+LED0 (Right Green): Link 10/100/1000
+LED1 (Left Orange): Link 10/100 + Blink on Tx/Rx
+LED2 (Left Green): Link 1000 + Blink on Tx/Rx
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/net/phy/realtek.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
+index 6976ff7c0846..5bd620f67b6a 100644
+--- a/drivers/net/phy/realtek.c
++++ b/drivers/net/phy/realtek.c
+@@ -180,10 +180,15 @@ static int rtl8211f_config(struct phy_device *phydev)
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_RTL8211F_PAGE_SELECT, 0x0);
+
+- /* Set green LED for Link, yellow LED for Active */
++ /*
++ * Set LED configuration
++ * LED0 (Right Grean): Link 10/100/1000
++ * LED1 (Left Orange): Link 10/100 + Active
++ * LED2 (Left Green): Link 1000 + Active
++ */
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_RTL8211F_PAGE_SELECT, 0xd04);
+- phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x617f);
++ phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x626b);
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_RTL8211F_PAGE_SELECT, 0x0);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-LED-control-support.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-LED-control-support.patch
new file mode 100644
index 000000000..774767f97
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-LED-control-support.patch
@@ -0,0 +1,457 @@
+From d88bb32a5c33f356926a309289497f1b1e7c9aa1 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 2 Apr 2021 09:48:38 -0700
+Subject: [PATCH] Add LED control support
+
+This commit adds LED control support including customization and improvement
+on led-gpio and led-uclass driver to support 'blink' mode. LEDs will behave
+like below.
+
+Normal u-boot : Green LED blinks at 1Hz + ID LED blinks at 3Hz
+FFU u-boot : Amber LED solid on + ID LED solid on
+MFG detected : Green LED blinks at 3Hz + ID LED blinks at 3Hz
+Failure Recovery : Amber LED blinks at 3Hz + ID LED solid on
+Jumping to Kernel : Green LED solid on + ID LED solid on
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/dts/ast2600-intel.dts | 4 +-
+ board/aspeed/ast2600_intel/intel.c | 66 +++++++++++++++++++++++++++++-
+ cmd/net.c | 23 +++++++++--
+ drivers/led/led-uclass.c | 37 +++++++++++++++++
+ drivers/led/led_gpio.c | 62 ++++++++++++++++++++++++++++
+ include/led.h | 42 ++++++++++++++++++-
+ 6 files changed, 226 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts
+index c7970c16a474..7cae636554b6 100644
+--- a/arch/arm/dts/ast2600-intel.dts
++++ b/arch/arm/dts/ast2600-intel.dts
+@@ -58,8 +58,8 @@
+ };
+ hb-led {
+ label = "hb";
+- gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
+- linux,default-trigger = "heartbeat";
++ gpios = <&gpio0 173 GPIO_ACTIVE_LOW>;
++ default-state = "on";
+ };
+ };
+ };
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 6e442cf01472..46f169589915 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -5,6 +5,7 @@
+ #include <common.h>
+ #include <asm/gpio.h>
+ #include <asm/io.h>
++#include <led.h>
+ #include <malloc.h>
+
+ /* use GPIOC0 on intel boards */
+@@ -26,7 +27,27 @@ int read_ffuj(void)
+ return ret;
+ ret = dm_gpio_get_value(&desc);
+ dm_gpio_free(desc.dev, &desc);
+- return ret;
++
++ if (ret) {
++ struct udevice *dev;
++
++ /* FFU mode: ChassisID - Solid Blue, StatusLED - Solid Amber */
++ ret = led_get_by_label("green", &dev);
++ if (!ret)
++ led_set_state(dev, LEDST_OFF);
++
++ ret = led_get_by_label("amber", &dev);
++ if (!ret)
++ led_set_state(dev, LEDST_ON);
++
++ ret = led_get_by_label("id", &dev);
++ if (!ret)
++ led_set_state(dev, LEDST_ON);
++
++ return 1;
++ }
++
++ return 0;
+ }
+
+ /* gpio_abort is a weak symbol in common/autoboot.c */
+@@ -264,6 +285,11 @@ static void timer_callback(void *cookie)
+ dummy = readl(0x1e78e07c);
+ dummy = readl(0x1e78f07c);
+ break;
++#ifdef CONFIG_LED_BLINK
++ case 1:
++ led_blink_update();
++ break;
++#endif
+ }
+ }
+
+@@ -286,10 +312,20 @@ int board_early_init_f(void)
+
+ int board_early_init_r(void)
+ {
++ struct udevice *dev;
++ int ret;
++
+ debug("board_early_init_r\n");
+
+ enable_onboard_tpm();
+
++ led_default_state();
++#ifdef CONFIG_LED_BLINK
++ ret = led_get_by_label("id", &dev);
++ if (!ret)
++ led_set_period(dev, 160);
++#endif
++
+ return 0;
+ }
+
+@@ -366,6 +402,11 @@ int board_late_init(void)
+ if (readl(SCU_BASE | SCU_014) == REV_ID_AST2600A0)
+ timer_enable(0, ONE_MSEC_IN_USEC, timer_callback, (void *)0);
+
++#ifdef CONFIG_LED_BLINK
++ timer_enable(1, LED_BLINK_UPDATE_TICK_MS * ONE_MSEC_IN_USEC,
++ timer_callback, (void *)1);
++#endif
++
+ espi_init();
+
+ /* Add reset reason to bootargs */
+@@ -391,6 +432,29 @@ void board_init(void)
+ }
+ */
+
++void board_preboot_os(void)
++{
++ struct udevice *dev;
++ int ret;
++
++ /*
++ * last second before OS booting
++ * ChassisID - Solid Blue, StatusLED - Solid Green
++ */
++
++ ret = led_get_by_label("green", &dev);
++ if (!ret)
++ led_set_state(dev, LEDST_ON);
++
++ ret = led_get_by_label("amber", &dev);
++ if (!ret)
++ led_set_state(dev, LEDST_OFF);
++
++ ret = led_get_by_label("id", &dev);
++ if (!ret)
++ led_set_state(dev, LEDST_ON);
++}
++
+ #ifdef CONFIG_WATCHDOG
+ /* watchdog stuff */
+ void watchdog_init(void)
+diff --git a/cmd/net.c b/cmd/net.c
+index 7d2c21ba4d22..a6b03654cdbf 100644
+--- a/cmd/net.c
++++ b/cmd/net.c
+@@ -10,6 +10,7 @@
+ #include <common.h>
+ #include <command.h>
+ #include <net.h>
++#include <led.h>
+
+ static int netboot_common(enum proto_t, cmd_tbl_t *, int, char * const []);
+
+@@ -183,6 +184,10 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
+ int size;
+ ulong addr;
+
++#ifdef CONFIG_LED_BLINK
++ led_blink_disable();
++#endif
++
+ net_boot_file_name_explicit = false;
+
+ /* pre-set load_addr */
+@@ -229,7 +234,8 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
+ if (strict_strtoul(argv[1], 16, &save_addr) < 0 ||
+ strict_strtoul(argv[2], 16, &save_size) < 0) {
+ printf("Invalid address/size\n");
+- return CMD_RET_USAGE;
++ rcode = CMD_RET_USAGE;
++ goto exit;
+ }
+ net_boot_file_name_explicit = true;
+ copy_filename(net_boot_file_name, argv[3],
+@@ -238,14 +244,16 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
+ #endif
+ default:
+ bootstage_error(BOOTSTAGE_ID_NET_START);
+- return CMD_RET_USAGE;
++ rcode = CMD_RET_USAGE;
++ goto exit;
+ }
+ bootstage_mark(BOOTSTAGE_ID_NET_START);
+
+ size = net_loop(proto);
+ if (size < 0) {
+ bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
+- return CMD_RET_FAILURE;
++ rcode = CMD_RET_FAILURE;
++ goto exit;
+ }
+ bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
+
+@@ -255,7 +263,8 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
+ /* done if no file was loaded (no errors though) */
+ if (size == 0) {
+ bootstage_error(BOOTSTAGE_ID_NET_LOADED);
+- return CMD_RET_SUCCESS;
++ rcode = CMD_RET_SUCCESS;
++ goto exit;
+ }
+
+ bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
+@@ -266,6 +275,12 @@ static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
+ bootstage_mark(BOOTSTAGE_ID_NET_DONE);
+ else
+ bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
++
++exit:
++#ifdef CONFIG_LED_BLINK
++ led_blink_enable();
++#endif
++
+ return rcode;
+ }
+
+diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c
+index 2859475a6b8e..264e0735c815 100644
+--- a/drivers/led/led-uclass.c
++++ b/drivers/led/led-uclass.c
+@@ -62,6 +62,39 @@ int led_set_period(struct udevice *dev, int period_ms)
+
+ return ops->set_period(dev, period_ms);
+ }
++
++static bool blink_enable = true;
++
++void led_blink_enable(void)
++{
++ blink_enable = true;
++}
++
++void led_blink_disable(void)
++{
++ blink_enable = false;
++}
++
++int led_blink_update(void)
++{
++ struct udevice *dev;
++
++ if (!blink_enable)
++ return 0;
++
++ for (uclass_find_first_device(UCLASS_LED, &dev);
++ dev;
++ uclass_find_next_device(&dev)) {
++ if (device_active(dev) && led_get_state(dev) == LEDST_BLINK) {
++ struct led_ops *ops = led_get_ops(dev);
++
++ if (ops && ops->update_blink)
++ ops->update_blink(dev);
++ }
++ }
++
++ return 0;
++}
+ #endif
+
+ int led_default_state(void)
+@@ -87,6 +120,10 @@ int led_default_state(void)
+ led_set_state(dev, LEDST_ON);
+ else if (!strncmp(default_state, "off", 3))
+ led_set_state(dev, LEDST_OFF);
++#ifdef CONFIG_LED_BLINK
++ else if (!strncmp(default_state, "blink", 5))
++ led_set_state(dev, LEDST_BLINK);
++#endif
+ /* default-state = "keep" : device is only probed */
+ }
+
+diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c
+index 93f6b913c647..a88efde71a69 100644
+--- a/drivers/led/led_gpio.c
++++ b/drivers/led/led_gpio.c
+@@ -13,8 +13,45 @@
+
+ struct led_gpio_priv {
+ struct gpio_desc gpio;
++#ifdef CONFIG_LED_BLINK
++ int period;
++ int period_tick_count;
++ enum led_state_t state;
++#endif
+ };
+
++#ifdef CONFIG_LED_BLINK
++static int gpio_led_set_period(struct udevice *dev, int period_ms)
++{
++ struct led_gpio_priv *priv = dev_get_priv(dev);
++
++ if (period_ms < LED_BLINK_UPDATE_TICK_MS)
++ period_ms = LED_BLINK_PERIOD_DEFAULT_MS;
++
++ priv->period = period_ms / LED_BLINK_UPDATE_TICK_MS;
++ priv->period_tick_count = priv->period;
++
++ return 0;
++}
++
++static int gpio_led_update_blink(struct udevice *dev)
++{
++ struct led_gpio_priv *priv = dev_get_priv(dev);
++ int ret;
++
++ if (priv->period_tick_count) {
++ priv->period_tick_count--;
++ } else {
++ ret = dm_gpio_get_value(&priv->gpio);
++ if (ret >= 0)
++ dm_gpio_set_value(&priv->gpio, !ret);
++ priv->period_tick_count = priv->period;
++ }
++
++ return 0;
++}
++#endif
++
+ static int gpio_led_set_state(struct udevice *dev, enum led_state_t state)
+ {
+ struct led_gpio_priv *priv = dev_get_priv(dev);
+@@ -25,6 +62,9 @@ static int gpio_led_set_state(struct udevice *dev, enum led_state_t state)
+ switch (state) {
+ case LEDST_OFF:
+ case LEDST_ON:
++#ifdef CONFIG_LED_BLINK
++ case LEDST_BLINK:
++#endif
+ break;
+ case LEDST_TOGGLE:
+ ret = dm_gpio_get_value(&priv->gpio);
+@@ -36,6 +76,20 @@ static int gpio_led_set_state(struct udevice *dev, enum led_state_t state)
+ return -ENOSYS;
+ }
+
++#ifdef CONFIG_LED_BLINK
++ priv->state = state;
++
++ if (priv->state == LEDST_BLINK) {
++ if (priv->period < LED_BLINK_UPDATE_TICK_MS) {
++ priv->period = LED_BLINK_PERIOD_DEFAULT_MS /
++ LED_BLINK_UPDATE_TICK_MS;
++ priv->period_tick_count = priv->period;
++ }
++
++ return dm_gpio_set_value(&priv->gpio, LEDST_ON);
++ }
++#endif
++
+ return dm_gpio_set_value(&priv->gpio, state);
+ }
+
+@@ -46,6 +100,10 @@ static enum led_state_t gpio_led_get_state(struct udevice *dev)
+
+ if (!dm_gpio_is_valid(&priv->gpio))
+ return -EREMOTEIO;
++#ifdef CONFIG_LED_BLINK
++ if (priv->state == LEDST_BLINK)
++ return LEDST_BLINK;
++#endif
+ ret = dm_gpio_get_value(&priv->gpio);
+ if (ret < 0)
+ return ret;
+@@ -117,6 +175,10 @@ static int led_gpio_bind(struct udevice *parent)
+ static const struct led_ops gpio_led_ops = {
+ .set_state = gpio_led_set_state,
+ .get_state = gpio_led_get_state,
++#ifdef CONFIG_LED_BLINK
++ .set_period = gpio_led_set_period,
++ .update_blink = gpio_led_update_blink,
++#endif
+ };
+
+ static const struct udevice_id led_gpio_ids[] = {
+diff --git a/include/led.h b/include/led.h
+index 7bfdddfd6fab..583dbd2f8f0e 100644
+--- a/include/led.h
++++ b/include/led.h
+@@ -32,7 +32,6 @@ enum led_state_t {
+ #ifdef CONFIG_LED_BLINK
+ LEDST_BLINK,
+ #endif
+-
+ LEDST_COUNT,
+ };
+
+@@ -66,6 +65,17 @@ struct led_ops {
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_period)(struct udevice *dev, int period_ms);
++
++ /**
++ * update_blink() - update blink output of an LED
++ *
++ * This should be called in every tick for updating blink behavior of an
++ * LED.
++ *
++ * @dev: LED device to change
++ * @return 0 if OK, -ve on error
++ */
++ int (*update_blink)(struct udevice *dev);
+ #endif
+ };
+
+@@ -115,4 +125,34 @@ int led_set_period(struct udevice *dev, int period_ms);
+ */
+ int led_default_state(void);
+
++#ifdef CONFIG_LED_BLINK
++#define LED_BLINK_UPDATE_TICK_MS 10
++#define LED_BLINK_PERIOD_DEFAULT_MS 500
++
++/**
++ * led_blink_enable() - enable blinking for all LEDs that have the blink state
++ *
++ * This enables blinking for all LEDs that have the blink state.
++ *
++ */
++void led_blink_enable(void);
++
++/**
++ * led_blink_disable() - disable blinking for all LEDs that have the blink state
++ *
++ * This disables blinking for all LEDs that have the blink state.
++ *
++ */
++void led_blink_disable(void);
++
++/**
++ * led_blink_update() - timer tick callback for updating blink behavior
++ *
++ * This should be called on every LED_BLINK_UPDATE_TICK_MS for updating blink
++ * behavior of all LEDs that have the blink state.
++ *
++ */
++int led_blink_update(void);
++#endif
++
+ #endif
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-system-reset-status-support.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-system-reset-status-support.patch
new file mode 100644
index 000000000..1b0d4d95b
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-system-reset-status-support.patch
@@ -0,0 +1,154 @@
+From ea8f8aa37182b66893ac9afcbbb4d5043b3b4166 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Tue, 9 Apr 2019 14:42:05 +0800
+Subject: [PATCH] Add system reset status support
+
+Will display the reset reasons and other CPU information in u-boot,
+and save the reset reasons into kernel command line,
+for applications to query.
+
+Change-Id: I87ada3ecf14368519e4d09035bb1e09fdc05469b
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/scu_info.c | 4 ++
+ board/aspeed/ast2600_intel/intel.c | 65 +++++++++++++++++++++++++
+ include/asm-generic/global_data.h | 3 ++
+ 3 files changed, 72 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/scu_info.c b/arch/arm/mach-aspeed/ast2600/scu_info.c
+index fe26f743c0ca..18514c812018 100644
+--- a/arch/arm/mach-aspeed/ast2600/scu_info.c
++++ b/arch/arm/mach-aspeed/ast2600/scu_info.c
+@@ -9,6 +9,8 @@
+ #include <asm/io.h>
+ #include <asm/arch/aspeed_scu_info.h>
+
++DECLARE_GLOBAL_DATA_PTR;
++
+ /* SoC mapping Table */
+ #define SOC_ID(str, rev) { .name = str, .rev_id = rev, }
+
+@@ -263,6 +265,8 @@ void aspeed_print_sysrst_info(void)
+ writel(SYS_EXT_RESET, ASPEED_SYS_RESET_CTRL);
+ }
+ }
++
++ gd->reset_reason = rest;
+ }
+
+ #define SOC_FW_INIT_DRAM BIT(7)
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 0d1ce69b6e53..849e81ff3fef 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -5,6 +5,7 @@
+ #include <common.h>
+ #include <asm/gpio.h>
+ #include <asm/io.h>
++#include <malloc.h>
+
+ /* use GPIOC0 on intel boards */
+ #define FFUJ_GPIO "gpio@1e78000016"
+@@ -292,6 +293,65 @@ int board_early_init_r(void)
+ return 0;
+ }
+
++static void update_bootargs_cmd(const char *key, const char *value)
++{
++ int buf_len;
++ char *buf;
++ char *cmdline;
++ char comp_key[128];
++
++ if (!key || (key[0] == '\0')) {
++ printf("%s - Empty key not allowed\n", __func__);
++ return;
++ }
++
++ cmdline = env_get("bootargs");
++
++ /* Allocate space for maximum possible new command line */
++ if (value)
++ buf_len = strlen(cmdline) + strlen(key) + 3 + strlen(value);
++ else
++ buf_len = strlen(cmdline) + strlen(key) + 3;
++
++ buf = malloc(buf_len);
++ if (!buf) {
++ printf("%s: out of memory\n", __func__);
++ return;
++ }
++ memset(buf, 0, buf_len);
++
++ if (!cmdline) {
++ /* lets add key-value, though bootargs are empty */
++ snprintf(buf, buf_len, "%s=%s", key, (value ? value : ""));
++ env_set("bootargs", buf);
++ free(buf);
++ return;
++ }
++
++ snprintf(comp_key, sizeof(comp_key), "%s=", key);
++ char *start = strstr(cmdline, comp_key);
++
++ /* Check for full word match. Match should be start of cmdline
++ * or there should be space before match */
++ if (start && ((start == cmdline) || (*(start-1) == ' '))) {
++ char *end = strchr(start, ' ');
++ strncpy(buf, cmdline, (start - cmdline));
++
++ if (end)
++ snprintf(buf, buf_len, "%s%s=%s %s", buf, key,
++ (value ? value : ""), end+1);
++ else
++ snprintf(buf, buf_len, "%s%s=%s", buf, key,
++ (value ? value : ""));
++ } else {
++ snprintf(buf, buf_len, "%s %s=%s", cmdline, key,
++ (value ? value : ""));
++ }
++
++ env_set("bootargs", buf);
++ free(buf);
++}
++
+ extern void espi_init(void);
+ extern void kcs_init(void);
+ extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler,
+@@ -301,12 +361,17 @@ int board_late_init(void)
+ #define SCU_014 0x014 /* Silicon Revision ID */
+ #define REV_ID_AST2600A0 0x05000303 /* AST2600 A0 */
+ #define ONE_MSEC_IN_USEC 1000
++ char value[11];
+
+ if (readl(SCU_BASE | SCU_014) == REV_ID_AST2600A0)
+ timer_enable(0, ONE_MSEC_IN_USEC, timer_callback, (void *)0);
+
+ espi_init();
+
++ /* Add reset reason to bootargs */
++ snprintf(value, sizeof(value), "0x%x", gd->reset_reason);
++ update_bootargs_cmd("resetreason", value);
++
+ if (read_ffuj())
+ kcs_init();
+
+diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
+index 78dcf40bff48..fa51e384520f 100644
+--- a/include/asm-generic/global_data.h
++++ b/include/asm-generic/global_data.h
+@@ -133,6 +133,9 @@ typedef struct global_data {
+ struct spl_handoff *spl_handoff;
+ # endif
+ #endif
++#ifdef CONFIG_ARCH_ASPEED
++ u32 reset_reason;
++#endif
+ } gd_t;
+ #endif
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0017-Manufacturing-mode-physical-presence-detection.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0017-Manufacturing-mode-physical-presence-detection.patch
new file mode 100644
index 000000000..7df227c82
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0017-Manufacturing-mode-physical-presence-detection.patch
@@ -0,0 +1,201 @@
+From 3b08379cb6e841c934ded3db3c70a3d0906cea65 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Thu, 20 Jun 2019 18:11:43 +0530
+Subject: [PATCH] Manufacturing mode physical presence detection
+
+Support for physical presence of manufacturing mode added.
+Front panel power button press for 15 seconds will be detected
+and marked as special mode for manufacturing request.
+There will be Status LED blink for 10 seconds to do the physical
+indication to the user. This indicates the user that he has
+pressed power button long enough for manufacturing mode detection.
+
+Tested:
+1. Verified by holding the power button when u-boot boots for
+15 seconds, and confirmed that bootargs passed to linux has
+special=mfg string and status led blink physical indication
+has been provided
+2. Verified in normal condition special=mfg string is not passed
+and no physical indication has been provided
+
+Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+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/intel.c | 87 ++++++++++++++++++++++++++++--
+ common/autoboot.c | 12 ++++-
+ 2 files changed, 95 insertions(+), 4 deletions(-)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index f45b9d06a3f5..7664ac0ddfc6 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -8,6 +8,8 @@
+ #include <led.h>
+ #include <malloc.h>
+
++#define SYS_PWR_RESET_FLAG BIT(0) /* from scu_info.c */
++
+ /* use GPIOC0 on intel boards */
+ #define FFUJ_GPIO "gpio@1e78000016"
+
+@@ -60,6 +62,26 @@ int gpio_abort(void)
+ return value <= 0 ? 0 : 1;
+ }
+
++int read_frontpanel_power_button(void)
++{
++#define FP_PWRBTN_GPIO "gpio@1e780000122" /* GPIOP2 */
++ struct gpio_desc desc;
++ int ret;
++
++ ret = dm_gpio_lookup_name(FP_PWRBTN_GPIO, &desc);
++ if (ret)
++ return ret;
++ ret = dm_gpio_request(&desc, "fp_pwrbtn");
++ if (ret)
++ return ret;
++ ret = dm_gpio_set_dir_flags(&desc, GPIOD_ACTIVE_LOW);
++ if (ret)
++ return ret;
++ ret = dm_gpio_get_value(&desc);
++ dm_gpio_free(desc.dev, &desc);
++ return ret;
++}
++
+ #define SCU_BASE 0x1E6E2000
+ #define SCU_338 0x338 //Generate UART 24 MHz Reference from UXCLK
+ #define SCU_33C 0x33c //Generate UART 24 MHz Reference from HUXCLK
+@@ -119,6 +141,10 @@ static void gpio_passthru_init(void)
+ SCU_BASE | SCU_418);
+ }
+
++void board_pre_abort_autoboot(void)
++{
++}
++
+ #define AST_LPC_BASE 0x1e789000
+ #define LPC_SNOOP_ADDR 0x80
+ #define HICR5 0x080 /* Host Interface Control Register 5 */
+@@ -301,8 +327,6 @@ int board_early_init_f(void)
+
+ set_gpio_default_state();
+
+- gpio_passthru_init();
+-
+ port80h_snoop_init();
+
+ sgpio_init();
+@@ -389,6 +413,56 @@ static void update_bootargs_cmd(const char *key, const char *value)
+ free(buf);
+ }
+
++static bool is_mfg_mode_phy_req(void)
++{
++ /*
++ * Assume mfg mode physical request is made, if power button
++ * is pressed continously for 15 seconds, indicate the
++ * same in bootargs
++ */
++ const uint32_t delay_in_ms = 100;
++ const uint32_t read_count = ((15 * 1000) / delay_in_ms);
++ const uint32_t delay_for_indication = 2 * 1000;
++ uint32_t count;
++#ifdef CONFIG_LED_BLINK
++ struct udevice *dev;
++ int ret;
++#endif
++
++ for (count = 0; count < read_count; ++count) {
++ if (read_frontpanel_power_button() != 1)
++ return false;
++
++ mdelay(delay_in_ms);
++ }
++
++ printf("MFG mode is requested.\n");
++
++#ifdef CONFIG_LED_BLINK
++ ret = led_get_by_label("green", &dev);
++ if (!ret) {
++ led_set_period(dev, 160);
++ }
++#endif
++
++ /*
++ * Delay up to 15 seconds until the power button is released to prevent
++ * unintentional power button overriding to PCH through GPIO
++ * pass-through.
++ */
++ for (count = 0; count < read_count; ++count) {
++ if (read_frontpanel_power_button() != 1)
++ break;
++
++ mdelay(delay_in_ms);
++ }
++ /* Keep the indication at least for 2 seconds */
++ if (delay_in_ms * count < delay_for_indication)
++ mdelay(delay_for_indication - (delay_in_ms * count));
++
++ return true;
++}
++
+ extern void espi_init(void);
+ extern void kcs_init(void);
+ extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler,
+@@ -414,8 +488,15 @@ int board_late_init(void)
+ snprintf(value, sizeof(value), "0x%x", gd->reset_reason);
+ update_bootargs_cmd("resetreason", value);
+
+- if (read_ffuj())
++ /* Update the special mode in bootargs */
++ if (gd->reset_reason & SYS_PWR_RESET_FLAG && is_mfg_mode_phy_req())
++ update_bootargs_cmd("special", "mfg");
++
++ gpio_passthru_init();
++
++ if (read_ffuj()) {
+ kcs_init();
++ }
+
+ return 0;
+ }
+diff --git a/common/autoboot.c b/common/autoboot.c
+index 5e69000b848b..8a9978042386 100644
+--- a/common/autoboot.c
++++ b/common/autoboot.c
+@@ -261,13 +261,19 @@ int gpio_abort(void)
+ return 0;
+ }
+
++/* Allow for board specific config when we check abort condition */
++__weak void board_pre_abort_autoboot(void)
++{
++ /* please define board specific board_pre_abort_autoboot() */
++}
++
+ static int abortboot(int bootdelay)
+ {
+ int abort = 0;
+
+ abort = gpio_abort();
+ if (abort)
+- return abort;
++ goto exit;
+
+ if (bootdelay >= 0)
+ abort = __abortboot(bootdelay);
+@@ -277,6 +283,10 @@ static int abortboot(int bootdelay)
+ gd->flags &= ~GD_FLG_SILENT;
+ #endif
+
++exit:
++ if (abort)
++ board_pre_abort_autoboot();
++
+ return abort;
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0018-Add-a-workaround-to-cover-VGA-memory-size-bug-in-A0.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0018-Add-a-workaround-to-cover-VGA-memory-size-bug-in-A0.patch
new file mode 100644
index 000000000..250ca7f5c
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0018-Add-a-workaround-to-cover-VGA-memory-size-bug-in-A0.patch
@@ -0,0 +1,52 @@
+From d7cdcbd4222ef3ad6d532c1034f4649432b0a69d Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 18 Jun 2020 15:08:57 -0700
+Subject: [PATCH] Add a workaround to cover VGA memory size bug in A0
+
+AST2600 A0 has a silicon bug which requires setting of VGA memory
+size limit. This commit add VGA memory size setting of 8MB for A0
+and 16MB for A1.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index aaacb61a1f8b..7e6787e5c6db 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -213,6 +213,12 @@ do_primary_core_setup:
+
+ bne 0f
+
++ /* limit VGA memory size to 8MB (A0 bug) */
++ ldr r0, =AST_SCU_HW_STRAP1_CLR
++ movw r1, #0x6000
++ movt r1, #0x0000
++ str r1, [r0]
++
+ /* tune up CPU clocks (A0 only) */
+ ldr r0, =AST_SCU_HW_STRAP1
+ ldr r1, [r0]
+@@ -251,6 +257,17 @@ wait_lock:
+ bne 2f
+
+ 1:
++ /* set VGA memory size to 16MB (A1 only) */
++ ldr r0, =AST_SCU_HW_STRAP1_CLR
++ movw r1, #0x4000
++ movt r1, #0x0000
++ str r1, [r0]
++
++ ldr r0, =AST_SCU_HW_STRAP1
++ ldr r1, [r0]
++ orr r1, #0x2000
++ str r1, [r0]
++
+ /* disable DMA arbitration on MAC1 (A1 bug) */
+ ldr r0, =AST_MAC1_CTRL2
+ ldr r1, [r0]
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch
new file mode 100644
index 000000000..547264260
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch
@@ -0,0 +1,105 @@
+From f7671739c0d48994c3b6b90d08a75f0ba9e9a2ca Mon Sep 17 00:00:00 2001
+From: Suryakanth Sekar <suryakanth.sekar@linux.intel.com>
+Date: Thu, 18 Jun 2020 05:32:48 +0530
+Subject: [PATCH] Apply WDT1-2 reset mask to reset needed controller
+
+Issue:
+BMC reset during BIOS serial port access causes BIOS hang.
+
+Root caused:
+BMC resetting the LPC controller during BMC warm reset.
+Which cause BIOS hang as BIOS cannot dump the BIOS serial data.
+
+Fix:
+WDT reset mask has been updated from default to proper value,
+such that controllers interacting with host will not be reset
+during wdt reset operation.
+This was missed earlier, causing BIOS to hang whenever BMC resets,
+as BIOS was accessing the serial port (LPC controller).
+De-coupling LPC controller will make sure BIOS serial port access
+is not disturbed.
+And also Reset mask is updated not to reset the following
+additionally on the default mask setting.
+eSPI controller reset causes system console lost connection, when
+BMC reset.
+
+1. LPC controller
+2. PWM controller
+3. eSPI controller
+
+Quick Step to reproduce:
+ Stop the BMC in uboot and add below bootcmd command
+ setenv bootcmd "reset"
+ Do the System power ON or System warm reset.
+
+ For WDT2:
+ boot the BMC and ran the /usr/bin/watch_dog_reset.sh
+ Do the System Power ON or System warm reset.
+
+Tested:
+ 1. Ran overnight continous BIOS and BMC warm reset on two SUTs.
+
+ 2.Ran the TestApp which dump the BIOS serial port continously and
+ do the BMC reset.
+
+ 3.Stop the BMC in uboot and add below bootcmd command
+ setenv bootcmd "reset"
+ Do the System Power ON or System warm reset.
+
+ 4.Ran Over night AC cycle test. Completed +1000 in two systems.
+
+ 5.Stopped at u-boot.
+ Issue protect off all command
+ Issue erase all command.
+ BMC should not hang and able to complete the "erase all" command
+
+Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index 7e6787e5c6db..937ea0d7b9a0 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -64,6 +64,14 @@
+ #define AST_MAC2_BASE (0x1E680000)
+ #define AST_MAC2_CTRL2 (AST_MAC2_BASE + 0x058)
+
++#define AST_WDT1_BASE 0x1E785000
++#define AST_WDT1_RESET_MASK1 (AST_WDT1_BASE + 0x01C)
++#define AST_WDT1_RESET_MASK2 (AST_WDT1_BASE + 0x020)
++
++#define AST_WDT2_BASE 0x1E785040
++#define AST_WDT2_RESET_MASK1 (AST_WDT2_BASE + 0x01C)
++#define AST_WDT2_RESET_MASK2 (AST_WDT2_BASE + 0x020)
++
+ #define AST_GPIO_BASE (0x1E780000)
+ #define AST_GPIOYZ_DATA_VALUE (AST_GPIO_BASE + 0x1E0)
+
+@@ -293,6 +301,20 @@ wait_lock:
+ str r1, [r0]
+
+ 2:
++ /* disable eSPI, LPC and PWM resets on WDT1 reset */
++ ldr r0, =AST_WDT1_RESET_MASK2
++ ldr r1, [r0]
++ ldr r2, =0x04002800
++ bic r1, r2
++ str r1, [r0]
++
++ /* disable eSPI, LPC and PWM resets on WDT2 reset */
++ ldr r0, =AST_WDT2_RESET_MASK2
++ ldr r1, [r0]
++ ldr r2, =0x04002800
++ bic r1, r2
++ str r1, [r0]
++
+ /* PCIeRC/E2M8 power-on reset comes from SCU040
+ But SCU04018 default value is 0x0.
+ It should be 0x1 to reset PCIeRC/E2M8.*/
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0022-Reboot-into-UBOOT-on-Watchdog-Failures.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0022-Reboot-into-UBOOT-on-Watchdog-Failures.patch
new file mode 100644
index 000000000..9b87b5c57
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0022-Reboot-into-UBOOT-on-Watchdog-Failures.patch
@@ -0,0 +1,114 @@
+From 1c879ae1f822f59d74cec9dd7ed10790279ad65b Mon Sep 17 00:00:00 2001
+From: James Feist <james.feist@linux.intel.com>
+Date: Wed, 31 Jul 2019 16:01:49 -0700
+Subject: [PATCH] Reboot into UBOOT on Watchdog Failures
+
+We use watchdog1 to reboot when there is a watchdog
+error. Reboot into u-boot as we are using that as
+safe mode.
+
+Tested: watchdog -T 0 -F /dev/watchdog1 reboots into
+uboot after 3 times
+
+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/intel.c | 61 ++++++++++++++++++++++++++++++
+ 1 file changed, 61 insertions(+)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 7664ac0ddfc6..24ae48fc62e7 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -9,6 +9,55 @@
+ #include <malloc.h>
+
+ #define SYS_PWR_RESET_FLAG BIT(0) /* from scu_info.c */
++#define WATCHDOG_RESET_BIT BIT(20)
++#define BOOT_FAILURE_LIMIT 3
++
++static int get_boot_failures(void)
++{
++ return env_get_ulong("bootfailures", 10, 0);
++}
++
++static void set_boot_failures(u32 count)
++{
++ if (count > BOOT_FAILURE_LIMIT)
++ return;
++
++ env_set_ulong("bootfailures", count);
++ env_save();
++}
++
++int intel_failed_boot(void)
++{
++ struct udevice *dev;
++ int ret;
++
++ ret = get_boot_failures() >= BOOT_FAILURE_LIMIT;
++ if (ret) {
++ /*
++ * Failure Recovery state:
++ * ChassisID - Solid Blue, StatusLED - Blinking Amber at 3Hz
++ */
++ ret = led_get_by_label("green", &dev);
++ if (!ret)
++ led_set_state(dev, LEDST_OFF);
++
++#ifdef CONFIG_LED_BLINK
++ ret = led_get_by_label("amber", &dev);
++ if (!ret) {
++ led_set_period(dev, 160);
++ led_set_state(dev, LEDST_BLINK);
++ }
++#endif
++
++ ret = led_get_by_label("id", &dev);
++ if (!ret)
++ led_set_state(dev, LEDST_ON);
++
++ return 1;
++ }
++
++ return 0;
++}
+
+ /* use GPIOC0 on intel boards */
+ #define FFUJ_GPIO "gpio@1e78000016"
+@@ -56,6 +105,10 @@ int read_ffuj(void)
+ int gpio_abort(void)
+ {
+ int value;
++
++ if (intel_failed_boot())
++ return 1;
++
+ /* check ffuj to abort the autoboot */
+ value = read_ffuj();
+ printf("FFUJ: %d\n", value);
+@@ -473,6 +526,7 @@ int board_late_init(void)
+ #define REV_ID_AST2600A0 0x05000303 /* AST2600 A0 */
+ #define ONE_MSEC_IN_USEC 1000
+ char value[11];
++ u32 boot_failures;
+
+ if (readl(SCU_BASE | SCU_014) == REV_ID_AST2600A0)
+ timer_enable(0, ONE_MSEC_IN_USEC, timer_callback, (void *)0);
+@@ -488,6 +542,13 @@ int board_late_init(void)
+ snprintf(value, sizeof(value), "0x%x", gd->reset_reason);
+ update_bootargs_cmd("resetreason", value);
+
++ boot_failures = get_boot_failures();
++
++ if (gd->reset_reason & WATCHDOG_RESET_BIT)
++ set_boot_failures(boot_failures + 1);
++ else
++ set_boot_failures(0);
++
+ /* Update the special mode in bootargs */
+ if (gd->reset_reason & SYS_PWR_RESET_FLAG && is_mfg_mode_phy_req())
+ update_bootargs_cmd("special", "mfg");
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0023-Add-WDT-to-u-boot-to-cover-booting-failures.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0023-Add-WDT-to-u-boot-to-cover-booting-failures.patch
new file mode 100644
index 000000000..e143692a0
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0023-Add-WDT-to-u-boot-to-cover-booting-failures.patch
@@ -0,0 +1,317 @@
+From d1acf70afd376b45a73b325ee30c0532a142c4f2 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 16 Sep 2020 13:25:36 -0700
+Subject: [PATCH] Add WDT to u-boot to cover booting failures
+
+This commit enables WDT1 in early u-boot and before loading kernel
+image to make BMC reset to cover booting failures. If BMC meets any
+failure or if kernel can't initiate watchdog timer properly, BMC will
+be reset by this watchdog.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 15 +++++
+ board/aspeed/ast2600_intel/intel.c | 50 ++++++++++++++--
+ common/board_f.c | 1 +
+ common/image.c | 3 +-
+ drivers/mtd/spi/spi-nor-core.c | 5 ++
+ drivers/watchdog/ast_wdt.c | 78 ++++++++++++++-----------
+ include/configs/aspeed-common.h | 2 +
+ 7 files changed, 116 insertions(+), 38 deletions(-)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index 937ea0d7b9a0..c65adff0d69a 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -65,6 +65,9 @@
+ #define AST_MAC2_CTRL2 (AST_MAC2_BASE + 0x058)
+
+ #define AST_WDT1_BASE 0x1E785000
++#define AST_WDT1_RELOAD_VAL (AST_WDT1_BASE + 0x004)
++#define AST_WDT1_RESTART_CTRL (AST_WDT1_BASE + 0x008)
++#define AST_WDT1_CTRL (AST_WDT1_BASE + 0x00C)
+ #define AST_WDT1_RESET_MASK1 (AST_WDT1_BASE + 0x01C)
+ #define AST_WDT1_RESET_MASK2 (AST_WDT1_BASE + 0x020)
+
+@@ -348,6 +351,18 @@ wait_lock:
+ ldr r1, =AST_SCU_CA7_PARITY_CHK
+ str r0, [r1]
+
++#ifdef CONFIG_HW_WATCHDOG
++ /* Enable WDT1 to recover u-boot hang */
++ ldr r0, =AST_WDT1_RELOAD_VAL
++ ldr r1, =0x00500000 @ ~5 seconds
++ str r1, [r0]
++ ldr r0, =AST_WDT1_RESTART_CTRL
++ ldr r1, =0x00004755
++ str r1, [r0]
++ ldr r0, =AST_WDT1_CTRL
++ ldr r1, =0x00000013
++ str r1, [r0]
++#endif
+ #if 0
+ ldr r1, =AST_FMC_WDT2_CTRL_MODE
+ str r0, [r1]
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 03eff62ce04b..88d9384faf2d 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -7,6 +7,7 @@
+ #include <asm/io.h>
+ #include <led.h>
+ #include <malloc.h>
++#include <wdt.h>
+
+ #define SYS_PWR_RESET_FLAG BIT(0) /* from scu_info.c */
+ #define WATCHDOG_RESET_BIT BIT(20)
+@@ -584,13 +585,54 @@ void board_preboot_os(void)
+ led_set_state(dev, LEDST_ON);
+ }
+
+-#ifdef CONFIG_WATCHDOG
+-/* watchdog stuff */
+-void watchdog_init(void)
++#ifdef CONFIG_HW_WATCHDOG
++#define WDT_TIMEOUT_DEFAULT 0x6000000 /* ~100 seconds */
++
++void hw_watchdog_init(void)
++{
++ struct udevice *dev;
++ int ret;
++
++ ret = uclass_first_device(UCLASS_WDT, &dev);
++ if (ret) {
++ debug("Can't find a WDT: %d\n", ret);
++ return;
++ }
++
++ ret = wdt_start(dev, WDT_TIMEOUT_DEFAULT, 0);
++ if (ret)
++ debug("WDT start failed: %d\n", ret);
++}
++
++void hw_watchdog_reset(void)
+ {
++ struct udevice *dev;
++ int ret;
++
++ ret = uclass_first_device(UCLASS_WDT, &dev);
++ if (ret) {
++ debug("Can't find a WDT: %d\n", ret);
++ return;
++ }
++
++ ret = wdt_reset(dev);
++ if (ret)
++ debug("WDT reset failed: %d\n", ret);
+ }
+
+-void watchdog_reset(void)
++void hw_watchdog_disable(void)
+ {
++ struct udevice *dev;
++ int ret;
++
++ ret = uclass_first_device(UCLASS_WDT, &dev);
++ if (ret) {
++ debug("Can't find a WDT: %d\n", ret);
++ return;
++ }
++
++ ret = wdt_stop(dev);
++ if (ret)
++ debug("WDT stop failed: %d\n", ret);
+ }
+ #endif
+diff --git a/common/board_f.c b/common/board_f.c
+index 149a7229e8fa..fe3e8e59d93e 100644
+--- a/common/board_f.c
++++ b/common/board_f.c
+@@ -94,6 +94,7 @@ static int init_func_watchdog_init(void)
+ {
+ # if defined(CONFIG_HW_WATCHDOG) && \
+ (defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \
++ defined(CONFIG_ASPEED_AST2600) || \
+ defined(CONFIG_SH) || \
+ defined(CONFIG_DESIGNWARE_WATCHDOG) || \
+ defined(CONFIG_IMX_WATCHDOG))
+diff --git a/common/image.c b/common/image.c
+index 4d4248f234fb..90687092e1ae 100644
+--- a/common/image.c
++++ b/common/image.c
+@@ -528,7 +528,8 @@ void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
+ if (to == from)
+ return;
+
+-#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
++#if !defined(CONFIG_ASPEED_SPI_DMA) && \
++ (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG))
+ if (to > from) {
+ from += len;
+ to += len;
+diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
+index e1fe91712e24..13f499a90272 100644
+--- a/drivers/mtd/spi/spi-nor-core.c
++++ b/drivers/mtd/spi/spi-nor-core.c
+@@ -20,6 +20,7 @@
+ #include <linux/mtd/spi-nor.h>
+ #include <spi-mem.h>
+ #include <spi.h>
++#include <watchdog.h>
+
+ #include "sf_internal.h"
+
+@@ -429,6 +430,10 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
+ unsigned long timebase;
+ int ret;
+
++#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
++ WATCHDOG_RESET();
++#endif
++
+ timebase = get_timer(0);
+
+ while (get_timer(timebase) < timeout) {
+diff --git a/drivers/watchdog/ast_wdt.c b/drivers/watchdog/ast_wdt.c
+index c2dc3cf548d2..811ead41bb95 100644
+--- a/drivers/watchdog/ast_wdt.c
++++ b/drivers/watchdog/ast_wdt.c
+@@ -19,10 +19,11 @@
+ #define WDT_CTRL_RESET_MODE_SHIFT 5
+ #define WDT_CTRL_RESET_MODE_MASK 3
+
+-#define WDT_CTRL_EN (1 << 0)
+-#define WDT_CTRL_RESET (1 << 1)
+-#define WDT_CTRL_CLK1MHZ (1 << 4)
+-#define WDT_CTRL_2ND_BOOT (1 << 7)
++#define WDT_CTRL_EN BIT(0)
++#define WDT_CTRL_RESET BIT(1)
++#define WDT_CTRL_CLK1MHZ BIT(4) /* AST2400/2500 */
++#define WDT_CTRL_WDT_RST_BY_SOC_RST BIT(4) /* AST2600 */
++#define WDT_CTRL_2ND_BOOT BIT(7)
+
+ /* Values for Reset Mode */
+ #define WDT_CTRL_RESET_SOC 0
+@@ -31,32 +32,32 @@
+ #define WDT_CTRL_RESET_MASK 3
+
+ /* Reset Mask register */
+-#define WDT_RESET_ARM (1 << 0)
+-#define WDT_RESET_COPROC (1 << 1)
+-#define WDT_RESET_SDRAM (1 << 2)
+-#define WDT_RESET_AHB (1 << 3)
+-#define WDT_RESET_I2C (1 << 4)
+-#define WDT_RESET_MAC1 (1 << 5)
+-#define WDT_RESET_MAC2 (1 << 6)
+-#define WDT_RESET_GCRT (1 << 7)
+-#define WDT_RESET_USB20 (1 << 8)
+-#define WDT_RESET_USB11_HOST (1 << 9)
+-#define WDT_RESET_USB11_EHCI2 (1 << 10)
+-#define WDT_RESET_VIDEO (1 << 11)
+-#define WDT_RESET_HAC (1 << 12)
+-#define WDT_RESET_LPC (1 << 13)
+-#define WDT_RESET_SDSDIO (1 << 14)
+-#define WDT_RESET_MIC (1 << 15)
+-#define WDT_RESET_CRT2C (1 << 16)
+-#define WDT_RESET_PWM (1 << 17)
+-#define WDT_RESET_PECI (1 << 18)
+-#define WDT_RESET_JTAG (1 << 19)
+-#define WDT_RESET_ADC (1 << 20)
+-#define WDT_RESET_GPIO (1 << 21)
+-#define WDT_RESET_MCTP (1 << 22)
+-#define WDT_RESET_XDMA (1 << 23)
+-#define WDT_RESET_SPI (1 << 24)
+-#define WDT_RESET_MISC (1 << 25)
++#define WDT_RESET_ARM BIT(0)
++#define WDT_RESET_COPROC BIT(1)
++#define WDT_RESET_SDRAM BIT(2)
++#define WDT_RESET_AHB BIT(3)
++#define WDT_RESET_I2C BIT(4)
++#define WDT_RESET_MAC1 BIT(5)
++#define WDT_RESET_MAC2 BIT(6)
++#define WDT_RESET_GCRT BIT(7)
++#define WDT_RESET_USB20 BIT(8)
++#define WDT_RESET_USB11_HOST BIT(9)
++#define WDT_RESET_USB11_EHCI2 BIT(10)
++#define WDT_RESET_VIDEO BIT(11)
++#define WDT_RESET_HAC BIT(12)
++#define WDT_RESET_LPC BIT(13)
++#define WDT_RESET_SDSDIO BIT(14)
++#define WDT_RESET_MIC BIT(15)
++#define WDT_RESET_CRT2C BIT(16)
++#define WDT_RESET_PWM BIT(17)
++#define WDT_RESET_PECI BIT(18)
++#define WDT_RESET_JTAG BIT(19)
++#define WDT_RESET_ADC BIT(20)
++#define WDT_RESET_GPIO BIT(21)
++#define WDT_RESET_MCTP BIT(22)
++#define WDT_RESET_XDMA BIT(23)
++#define WDT_RESET_SPI BIT(24)
++#define WDT_RESET_MISC BIT(25)
+
+ #define WDT_RESET_DEFAULT \
+ (WDT_RESET_ARM | WDT_RESET_COPROC | WDT_RESET_I2C | \
+@@ -98,12 +99,18 @@ struct ast_wdt_priv {
+ static int ast_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+ {
+ struct ast_wdt_priv *priv = dev_get_priv(dev);
++ ulong driver_data = dev_get_driver_data(dev);
+
+ writel((u32) timeout, &priv->regs->counter_reload_val);
+
+ writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
+
+- writel(WDT_CTRL_EN | WDT_CTRL_RESET, &priv->regs->ctrl);
++ if (driver_data == WDT_AST2600) {
++ writel(WDT_CTRL_EN | WDT_CTRL_RESET |
++ WDT_CTRL_WDT_RST_BY_SOC_RST, &priv->regs->ctrl);
++ } else {
++ writel(WDT_CTRL_EN | WDT_CTRL_RESET, &priv->regs->ctrl);
++ }
+
+ return 0;
+ }
+@@ -115,12 +122,15 @@ static int ast_wdt_stop(struct udevice *dev)
+
+ clrbits_le32(&priv->regs->ctrl, WDT_CTRL_EN);
+
++#if !defined(CONFIG_TARGET_AST2600_INTEL)
+ if(driver_data == WDT_AST2600) {
+ writel(0x030f1ff1, &priv->regs->reset_mask1);
+ writel(0x3fffff1, &priv->regs->reset_mask2);
+- } else
++ } else {
+ writel(WDT_RESET_DEFAULT, &priv->regs->reset_mask1);
+-
++ }
++#endif
++
+ return 0;
+ }
+
+@@ -168,7 +178,9 @@ static const struct wdt_ops ast_wdt_ops = {
+ static int ast_wdt_probe(struct udevice *dev)
+ {
+ debug("%s() wdt%u\n", __func__, dev->seq);
++#if !defined(CONFIG_TARGET_AST2600_INTEL)
+ ast_wdt_stop(dev);
++#endif
+
+ return 0;
+ }
+diff --git a/include/configs/aspeed-common.h b/include/configs/aspeed-common.h
+index 183a7a502e9c..d5befb185b6a 100644
+--- a/include/configs/aspeed-common.h
++++ b/include/configs/aspeed-common.h
+@@ -20,6 +20,8 @@
+
+ #define CONFIG_STANDALONE_LOAD_ADDR 0x83000000
+
++#define CONFIG_HW_WATCHDOG
++
+ /* Misc CPU related */
+ #define CONFIG_CMDLINE_TAG
+ #define CONFIG_SETUP_MEMORY_TAGS
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0024-fix-SUS_WARN-handling-logic.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0024-fix-SUS_WARN-handling-logic.patch
new file mode 100644
index 000000000..e8562a184
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0024-fix-SUS_WARN-handling-logic.patch
@@ -0,0 +1,128 @@
+From e9a8a79453e23c86e7b086b1e752876c99bcf0b3 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+Date: Tue, 20 Oct 2020 15:49:26 -0700
+Subject: [PATCH] fix SUS_WARN handling logic
+
+This commit fixes SUS_WARN handling as dual-edge detection mode
+to support deepsx entry event properly.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ board/aspeed/ast2600_intel/ast-espi.c | 62 ++++++++++++++-------------
+ 1 file changed, 32 insertions(+), 30 deletions(-)
+
+diff --git a/board/aspeed/ast2600_intel/ast-espi.c b/board/aspeed/ast2600_intel/ast-espi.c
+index a8b389f159ef..51fcc836cc6a 100644
+--- a/board/aspeed/ast2600_intel/ast-espi.c
++++ b/board/aspeed/ast2600_intel/ast-espi.c
+@@ -148,9 +148,9 @@ static void espi_irq_handler(void *cookie)
+ {
+ uint32_t irq_status = readl(AST_ESPI_BASE + ESPI008);
+
+- DBG_ESPI("espi_irq_handler, ESPI008=0X%x, ESPI00c=0X%x,\
+- ESPI100=0X%x, ESPI11c=0X%x, ESPI094=0X%x,\
+- ESPI12c=0X%x, irq_status=0x%x\n",
++ DBG_ESPI("espi_irq_handler, ESPI008=0X%x, ESPI00c=0X%x, "
++ "ESPI100=0X%x, ESPI11c=0X%x, ESPI094=0X%x, "
++ "ESPI12c=0X%x, irq_status=0x%x\n",
+ readl(AST_ESPI_BASE + ESPI008),
+ readl(AST_ESPI_BASE + ESPI00C),
+ readl(AST_ESPI_BASE + ESPI100),
+@@ -165,21 +165,23 @@ static void espi_irq_handler(void *cookie)
+ DBG_ESPI("sys_status : 0x%08X\n", sys_status);
+ if (sys_status & AST_ESPI_HOST_RST_WARN) {
+ DBG_ESPI("HOST_RST_WARN evt: 0x%08X\n", sys_event);
+- if (sys_event & AST_ESPI_HOST_RST_WARN) {
+- uint32_t v = readl(AST_ESPI_BASE + ESPI098) |
+- AST_ESPI_HOST_RST_ACK;
+- writel(v, AST_ESPI_BASE + ESPI098);
+- DBG_ESPI("HOST_RST_WARN sent ack\n");
+- }
++ uint32_t v = readl(AST_ESPI_BASE + ESPI098);
++ if (sys_event & AST_ESPI_HOST_RST_WARN)
++ v |= AST_ESPI_HOST_RST_ACK;
++ else
++ v &= ~AST_ESPI_HOST_RST_ACK;
++ writel(v, AST_ESPI_BASE + ESPI098);
++ DBG_ESPI("HOST_RST_WARN sent ack\n");
+ }
+ if (sys_status & AST_ESPI_OOB_RST_WARN) {
+ DBG_ESPI("OOB_RST_WARN evt: 0x%08X\n", sys_event);
+- if (sys_event & AST_ESPI_OOB_RST_WARN) {
+- uint32_t v = readl(AST_ESPI_BASE + ESPI098) |
+- AST_ESPI_OOB_RST_ACK;
+- writel(v, AST_ESPI_BASE + ESPI098);
+- DBG_ESPI("OOB_RST_WARN sent ack\n");
+- }
++ uint32_t v = readl(AST_ESPI_BASE + ESPI098);
++ if (sys_event & AST_ESPI_OOB_RST_WARN)
++ v |= AST_ESPI_OOB_RST_ACK;
++ else
++ v &= ~AST_ESPI_OOB_RST_ACK;
++ writel(v, AST_ESPI_BASE + ESPI098);
++ DBG_ESPI("OOB_RST_WARN sent ack\n");
+ }
+ if (sys_status & AST_ESPI_PLTRSTN) {
+ DBG_ESPI("PLTRSTN: %c, evt: 0x%08X\n",
+@@ -196,12 +198,13 @@ static void espi_irq_handler(void *cookie)
+ DBG_ESPI("sys1_status : 0x%08X\n", sys1_status);
+ if (sys1_status & AST_ESPI_SUS_WARN) {
+ DBG_ESPI("SUS WARN evt: 0x%08X\n", sys1_event);
+- if (sys1_event & AST_ESPI_SUS_WARN) {
+- uint32_t v = readl(AST_ESPI_BASE + ESPI104) |
+- AST_ESPI_SUS_ACK;
+- writel(v, AST_ESPI_BASE + ESPI104);
+- DBG_ESPI("SUS_WARN sent ack\n");
+- }
++ uint32_t v = readl(AST_ESPI_BASE + ESPI104);
++ if (sys1_event & AST_ESPI_SUS_WARN)
++ v |= AST_ESPI_SUS_ACK;
++ else
++ v &= ~AST_ESPI_SUS_ACK;
++ writel(v, AST_ESPI_BASE + ESPI104);
++ DBG_ESPI("SUS_WARN sent ack\n");
+ }
+ writel(sys1_status, AST_ESPI_BASE + ESPI12C); /* clear status */
+ }
+@@ -219,9 +222,9 @@ static void espi_irq_handler(void *cookie)
+
+ writel(irq_status, AST_ESPI_BASE + ESPI008); /* clear irq_status */
+
+- DBG_ESPI("end espi_irq_handler, ESPI008=0X%x, ESPI00c=0X%x,\
+- ESPI100=0X%x, ESPI11c=0X%x, ESPI094=0X%x,\
+- ESPI12c=0X%x, irq_status=0X%x\n",
++ DBG_ESPI("end espi_irq_handler, ESPI008=0X%x, ESPI00c=0X%x, "
++ "ESPI100=0X%x, ESPI11c=0X%x, ESPI094=0X%x, "
++ "ESPI12c=0X%x, irq_status=0X%x\n",
+ readl(AST_ESPI_BASE + ESPI008),
+ readl(AST_ESPI_BASE + ESPI00C),
+ readl(AST_ESPI_BASE + ESPI100),
+@@ -232,6 +235,7 @@ static void espi_irq_handler(void *cookie)
+
+ static void espi_configure_irq(void)
+ {
++ /* Dual-edge setting for HOST_RST_WARN and OOB_RST_WARN */
+ writel(0, AST_ESPI_BASE + ESPI110);
+ writel(0, AST_ESPI_BASE + ESPI114);
+ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN |
+@@ -239,13 +243,11 @@ static void espi_configure_irq(void)
+ 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 */
++ /* Dual-edge setting for SUS_WARN */
++ writel(0, AST_ESPI_BASE + ESPI120);
+ 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_SUS_WARN, AST_ESPI_BASE + ESPI128);
++ writel(AST_ESPI_SUS_WARN, AST_ESPI_BASE + ESPI100);
+
+ writel(AST_ESPI_IEN_HW_RST | AST_ESPI_IEN_SYS1_EV |
+ AST_ESPI_IEN_SYS_EV, AST_ESPI_BASE + ESPI00C);
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0025-ast2600-PFR-platform-EXTRST-reset-mask-selection.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0025-ast2600-PFR-platform-EXTRST-reset-mask-selection.patch
new file mode 100644
index 000000000..e72679836
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0025-ast2600-PFR-platform-EXTRST-reset-mask-selection.patch
@@ -0,0 +1,50 @@
+From fc01155d6f78ab9940f1d1482b0df44addc5f313 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Mon, 22 Feb 2021 17:22:16 +0530
+Subject: [PATCH] ast2600-PFR-platform-EXTRST-reset-mask-selection
+
+This commit will enable specific reset mask for EXTRST# signal.
+On PFR platforms, EXTRST# signal is used by PFR CPLD to put BMC
+in reset during firmware authentications, recovery and firmware
+update flow, during which certain modules of BMC should be chosen
+to be reset so that Host functionality would be intact.
+
+Signed-off-by: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com>
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index c65adff0d69a..3db7d993d3ca 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -39,6 +39,8 @@
+ #define AST_SCU_REV_ID (AST_SCU_BASE + 0x014)
+ #define AST_SCU_SYSRST_CTRL (AST_SCU_BASE + 0x040)
+ #define AST_SCU_SYSRST_CTRL_CLR (AST_SCU_BASE + 0x044)
++#define AST_SCU_EXTRST_SEL1 (AST_SCU_BASE + 0x060)
++#define AST_SCU_EXTRST_SEL2 (AST_SCU_BASE + 0x070)
+ #define AST_SCU_DEBUG_CTRL (AST_SCU_BASE + 0x0C8)
+ #define AST_SCU_DEBUG_CTRL2 (AST_SCU_BASE + 0x0D8)
+ #define AST_SCU_HPLL_PARAM (AST_SCU_BASE + 0x200)
+@@ -304,6 +306,16 @@ wait_lock:
+ str r1, [r0]
+
+ 2:
++ /* SCU060:EXTRST1# reset mask selection */
++ ldr r0, =AST_SCU_EXTRST_SEL1
++ ldr r1, =0x6CF1FF1
++ str r1, [r0]
++
++ /* SCU070:EXTRST2# reset mask selection */
++ ldr r0, =AST_SCU_EXTRST_SEL2
++ ldr r1, =0x3FFFFF3
++ str r1, [r0]
++
+ /* disable eSPI, LPC and PWM resets on WDT1 reset */
+ ldr r0, =AST_WDT1_RESET_MASK2
+ ldr r1, [r0]
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0026-Enable-PCIe-L1-support.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0026-Enable-PCIe-L1-support.patch
new file mode 100644
index 000000000..ee1a8f7a4
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0026-Enable-PCIe-L1-support.patch
@@ -0,0 +1,40 @@
+From cd13ae4e64d57af84dc98ff6c8d5b31661bc450d Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 8 Jan 2019 13:33:15 -0800
+Subject: [PATCH] Enable PCIe L1 support
+
+This commit enables PCIe L1 support using magic registers.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index 3db7d993d3ca..e2fcb732b6a6 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -349,6 +349,20 @@ wait_lock:
+ movt r1, #0x0000
+ str r1, [r0]
+
++ /* enable PCIe L1 support */
++ ldr r0, =0x1e6ed07c
++ ldr r1, =0xa8
++ str r1, [r0]
++ ldr r0, =0x1e6ed010
++ ldr r1, =0x27040fe1
++ str r1, [r0]
++ ldr r0, =0x1e6ed068
++ ldr r1, =0xc81f0a
++ str r1, [r0]
++ ldr r0, =0x1e6ed07c
++ mov r1, #0
++ str r1, [r0]
++
+ /* MMIO decode setting */
+ ldr r0, =AST_SCU_MMIO_DEC_SET
+ mov r1, #0x2000
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0027-ast2600-Add-Mailbox-init-function.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0027-ast2600-Add-Mailbox-init-function.patch
new file mode 100644
index 000000000..8e3a17107
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0027-ast2600-Add-Mailbox-init-function.patch
@@ -0,0 +1,127 @@
+From b41a5d9eb94bcaf40bc960d82f13cf41cb83c34e Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Thu, 25 Feb 2021 14:45:12 +0800
+Subject: [PATCH] ast2600: Add Mailbox init function.
+
+Add Mailbox init function to make sure mailbox regs are reset
+to expected values at reset.
+
+At power-on reset, 0x0c=0, 0x0d=2, 0x0e=5e, 0x0f=31
+as per the handshake definition with BIOS.
+
+At all other resets, 0x0c is preserved, 0x0d, 0x0e, 0x0f
+are reset the same as power-on reset.
+
+Because the reset behavior depends on a flag set in the _f phase of
+booting, the mailbox_init function must be called from the _r phase.
+
+AST2600 A0 has 16 mailboxes.
+AST2600 A1 has 32 mailboxes.
+
+Tested:
+BMC could boot correctly and all the mailboxes clear
+ast# md 0x1e789200
+1e789200: 00000000 00000000 00000000 00000000 ................
+1e789210: 00000000 00000000 00000000 00000000 ................
+1e789220: 00000000 00000002 0000005e 00000031 .........^..1...
+1e789230: 00000000 00000000 00000000 00000000 ................
+1e789240: 00000000 00000000 00000000 00000000 ................
+
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/intel.c | 56 ++++++++++++++++++++++++++++--
+ 1 file changed, 54 insertions(+), 2 deletions(-)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 17f9d6c8fbf6..c8b3cef70dd7 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -13,6 +13,9 @@
+ #define WATCHDOG_RESET_BIT BIT(20)
+ #define BOOT_FAILURE_LIMIT 3
+
++#define SCU_014 0x014 /* Silicon Revision ID */
++#define REV_ID_AST2600A0 0x05000303 /* AST2600 A0 */
++
+ static int get_boot_failures(void)
+ {
+ return env_get_ulong("bootfailures", 10, 0);
+@@ -374,6 +377,55 @@ static void timer_callback(void *cookie)
+ }
+ }
+
++#define AST_MBX_BASE 0x1e789200
++#define AST_MBX_COUNT_A0 16
++#define AST_MBX_COUNT 32
++#define MAILBOX_INIT_D 0x02
++#define MAILBOX_INIT_E 0x5e
++#define MAILBOX_INIT_F 0x31
++static void mailbox_init(void)
++{
++ int i, mbx_count;
++
++ if (readl(SCU_BASE + SCU_014) == REV_ID_AST2600A0)
++ mbx_count = AST_MBX_COUNT_A0;
++ else
++ mbx_count = AST_MBX_COUNT;
++
++ if (gd->reset_reason & SYS_PWR_RESET_FLAG)
++ {
++ /* on AC-reset, clear all except special values to d/e/f */
++ for (i = 0; i < mbx_count; i++)
++ {
++ long v;
++ if (i == 0x0d)
++ v = MAILBOX_INIT_D;
++ else if (i == 0x0e)
++ v = MAILBOX_INIT_E;
++ else if (i == 0x0f)
++ v = MAILBOX_INIT_F;
++ else
++ v = 0;
++ writel(v, AST_MBX_BASE + 4 * i);
++ }
++ }
++ else
++ {
++ /* on other resets, clear all except c/d/e/f */
++ for (i = 0; i < mbx_count; i++)
++ {
++ long v;
++ if (i == 0x0d)
++ v = MAILBOX_INIT_D;
++ else if (i == 0x0c || i == 0x0e || i == 0x0f)
++ continue;
++ else
++ v = 0;
++ writel(v, AST_MBX_BASE + 4 * i);
++ }
++ }
++}
++
+ int board_early_init_f(void)
+ {
+ /* This is called before relocation; beware! */
+@@ -396,6 +448,8 @@ int board_early_init_r(void)
+
+ debug("board_early_init_r\n");
+
++ mailbox_init();
++
+ enable_onboard_tpm();
+
+ led_default_state();
+@@ -510,8 +564,6 @@ extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler,
+ void *cookie);
+ int board_late_init(void)
+ {
+-#define SCU_014 0x014 /* Silicon Revision ID */
+-#define REV_ID_AST2600A0 0x05000303 /* AST2600 A0 */
+ #define ONE_MSEC_IN_USEC 1000
+ char value[11];
+ u32 boot_failures;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0028-Improve-randomness-of-mac-address-generation.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0028-Improve-randomness-of-mac-address-generation.patch
new file mode 100644
index 000000000..337e9995b
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0028-Improve-randomness-of-mac-address-generation.patch
@@ -0,0 +1,53 @@
+From da155e990fe763d3a03bdac76054e1d5530b8c16 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 10 Mar 2021 20:15:10 -0800
+Subject: [PATCH] Improve randomness of mac address generation
+
+This commit improves randomness of mac address generation using
+AST2600's hardware random number generator.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ lib/rand.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/lib/rand.c b/lib/rand.c
+index af4cf3a0e8cf..0a12b0b82276 100644
+--- a/lib/rand.c
++++ b/lib/rand.c
+@@ -8,16 +8,32 @@
+ */
+
+ #include <common.h>
++#include <asm/io.h>
+
+ static unsigned int y = 1U;
+
+ unsigned int rand_r(unsigned int *seedp)
+ {
++#ifdef CONFIG_ASPEED_AST2600
++#define SCU_524 0x1e6e2524
++ int i;
++
++ /*
++ * Use hardware random number generator. It generates a new number on
++ * each 1us or on each 32 read command cycle so this code makes
++ * intentional dummy 32 reads.
++ */
++ for (i = 0; i < 32; i++)
++ *seedp ^= readl(SCU_524);
++
++ return readl(SCU_524);
++#else
+ *seedp ^= (*seedp << 13);
+ *seedp ^= (*seedp >> 17);
+ *seedp ^= (*seedp << 5);
+
+ return *seedp;
++#endif
+ }
+
+ unsigned int rand(void)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0029-Set-UART-routing-in-lowlevel_init.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0029-Set-UART-routing-in-lowlevel_init.patch
new file mode 100644
index 000000000..72be1a0b4
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0029-Set-UART-routing-in-lowlevel_init.patch
@@ -0,0 +1,43 @@
+From 44321f61f0b0edbde3300cc43b2f3e9f9fd93d44 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 26 Apr 2021 13:20:21 -0700
+Subject: [PATCH] Set UART routing in lowlevel_init
+
+This commit sets the UART routing back to default in lowlevel_init
+to prevent any data dropping from the physical host serial until
+SOL service is activated.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index e2fcb732b6a6..4cc22e31c604 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -80,6 +80,9 @@
+ #define AST_GPIO_BASE (0x1E780000)
+ #define AST_GPIOYZ_DATA_VALUE (AST_GPIO_BASE + 0x1E0)
+
++#define AST_LPC_BASE 0x1E789000
++#define AST_LPC_HICRA (AST_LPC_BASE + 0x09C)
++
+ /* Revision ID */
+ #define REV_ID_AST2600A0 0x05000303
+ #define REV_ID_AST2600A1 0x05010303
+@@ -433,6 +436,11 @@ skip_fill_wip_bit:
+ moveq r1, #0xff
+ str r1, [r0]
+
++ /* set UART routing back to default */
++ ldr r0, =AST_LPC_HICRA
++ ldr r1, =0x0
++ str r1, [r0]
++
+ /* relocate mailbox insn. for cpuN polling SMP go signal */
+ adrl r0, mailbox_insn
+ adrl r1, mailbox_insn_end
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch
new file mode 100644
index 000000000..176f9fa04
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch
@@ -0,0 +1,576 @@
+From a772d7bdde659d689fda47accc0f50bb6ce047d1 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 17 May 2021 13:11:24 -0700
+Subject: [PATCH] Add Aspeed PWM uclass driver
+
+This commit adds Aspeed PWM uclass driver to set default FAN speed
+in u-boot.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/dts/ast2600-intel.dts | 11 ++
+ arch/arm/dts/ast2600.dtsi | 88 ++++++++++++
+ board/aspeed/ast2600_intel/intel.c | 49 +++++++
+ drivers/pinctrl/aspeed/pinctrl_ast2600.c | 130 ++++++++++++++++-
+ drivers/pwm/Kconfig | 8 ++
+ drivers/pwm/Makefile | 1 +
+ drivers/pwm/aspeed_pwm.c | 172 +++++++++++++++++++++++
+ 7 files changed, 458 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/pwm/aspeed_pwm.c
+
+diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts
+index 7cae636554b6..a76193716d34 100644
+--- a/arch/arm/dts/ast2600-intel.dts
++++ b/arch/arm/dts/ast2600-intel.dts
+@@ -64,6 +64,17 @@
+ };
+ };
+
++&pwm {
++ status = "okay";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default
++ &pinctrl_pwm2_default &pinctrl_pwm3_default
++ &pinctrl_pwm4_default &pinctrl_pwm5_default
++ &pinctrl_pwm12g1_default &pinctrl_pwm13g1_default
++ &pinctrl_pwm14g1_default &pinctrl_pwm15g1_default>;
++};
++
+ &gpio0 {
+ status = "okay";
+ };
+diff --git a/arch/arm/dts/ast2600.dtsi b/arch/arm/dts/ast2600.dtsi
+index 9c4282515d55..3ff5bf2e16e1 100644
+--- a/arch/arm/dts/ast2600.dtsi
++++ b/arch/arm/dts/ast2600.dtsi
+@@ -265,6 +265,14 @@
+ #size-cells = <1>;
+ ranges;
+
++ pwm: pwm-controller@1e610000 {
++ compatible = "aspeed,ast2600-pwm";
++ reg = <0x1e610000 0x100>;
++ clocks = <&scu ASPEED_CLK_AHB>;
++ resets = <&rst ASPEED_RESET_PWM>;
++ status = "disabled";
++ };
++
+ syscon: syscon@1e6e2000 {
+ compatible = "aspeed,g6-scu", "syscon", "simple-mfd";
+ reg = <0x1e6e2000 0x1000>;
+@@ -1598,6 +1606,86 @@
+ groups = "PWM7";
+ };
+
++ pinctrl_pwm8g1_default: pwm8g1_default {
++ function = "PWM8G1";
++ groups = "PWM8G1";
++ };
++
++ pinctrl_pwm9g1_default: pwm9g1_default {
++ function = "PWM9G1";
++ groups = "PWM9G1";
++ };
++
++ pinctrl_pwm10g1_default: pwm10g1_default {
++ function = "PWM10G1";
++ groups = "PWM10G1";
++ };
++
++ pinctrl_pwm11g1_default: pwm11g1_default {
++ function = "PWM11G1";
++ groups = "PWM11G1";
++ };
++
++ pinctrl_pwm12g1_default: pwm12g1_default {
++ function = "PWM12G1";
++ groups = "PWM12G1";
++ };
++
++ pinctrl_pwm13g1_default: pwm13g1_default {
++ function = "PWM13G1";
++ groups = "PWM13G1";
++ };
++
++ pinctrl_pwm14g1_default: pwm14g1_default {
++ function = "PWM14G1";
++ groups = "PWM14G1";
++ };
++
++ pinctrl_pwm15g1_default: pwm15g1_default {
++ function = "PWM15G1";
++ groups = "PWM15G1";
++ };
++
++ pinctrl_pwm8g0_default: pwm8g0_default {
++ function = "PWM8G0";
++ groups = "PWM8G0";
++ };
++
++ pinctrl_pwm9g0_default: pwm9g0_default {
++ function = "PWM9G0";
++ groups = "PWM9G0";
++ };
++
++ pinctrl_pwm10g0_default: pwm10g0_default {
++ function = "PWM10G0";
++ groups = "PWM10G0";
++ };
++
++ pinctrl_pwm11g0_default: pwm11g0_default {
++ function = "PWM11G0";
++ groups = "PWM11G0";
++ };
++
++ pinctrl_pwm12g0_default: pwm12g0_default {
++ function = "PWM12G0";
++ groups = "PWM12G0";
++ };
++
++ pinctrl_pwm13g0_default: pwm13g0_default {
++ function = "PWM13G0";
++ groups = "PWM13G0";
++ };
++
++ pinctrl_pwm14g0_default: pwm14g0_default {
++ function = "PWM14G0";
++ groups = "PWM14G0";
++ };
++
++ pinctrl_pwm15g0_default: pwm15g0_default {
++ function = "PWM15G0";
++ groups = "PWM15G0";
++ };
++
+ pinctrl_rgmii1_default: rgmii1_default {
+ function = "RGMII1";
+ groups = "RGMII1";
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 82df0ac6137e..f1136eec9ab9 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -8,6 +8,7 @@
+ #include <led.h>
+ #include <malloc.h>
+ #include <wdt.h>
++#include <pwm.h>
+
+ #define SYS_PWR_RESET_FLAG BIT(0) /* from scu_info.c */
+ #define WATCHDOG_RESET_BIT BIT(20)
+@@ -426,6 +427,53 @@ static void mailbox_init(void)
+ }
+ }
+
++struct pwm_setting {
++ uint channel;
++ uint duty_pct;
++};
++
++static void pwm_init(void)
++{
++#define NSEC_PER_SEC 1000000000L
++#define PWM_TARGET_FREQ 25000
++#define PWM_TICK_NS (NSEC_PER_SEC / PWM_TARGET_FREQ)
++#define PWM_TICK_1PCT_NS (PWM_TICK_NS / 100)
++ const struct pwm_setting settings[] = {
++ {0, 65},
++ {1, 65},
++ {2, 65},
++ {3, 65},
++ {4, 65},
++ {5, 65},
++ {12, 65},
++ {13, 65},
++ {14, 65},
++ {15, 65},
++ };
++ struct udevice *dev;
++ int ret, setting_size, i;
++
++ ret = uclass_first_device(UCLASS_PWM, &dev);
++ if (ret) {
++ debug("Can't find PWM controller: %d\n", ret);
++ return;
++ }
++
++ setting_size = sizeof(settings) / sizeof(settings[0]);
++
++ for (i = 0; i < setting_size; i++) {
++ ret = pwm_set_config(dev, settings[i].channel, PWM_TICK_NS,
++ settings[i].duty_pct * PWM_TICK_1PCT_NS);
++ if (!ret) {
++ ret = pwm_set_enable(dev, settings[i].channel, true);
++ if (ret)
++ debug("PWM enabling failed: %d\n", ret);
++ } else {
++ debug("PWM configure failed: %d\n", ret);
++ }
++ }
++}
++
+ int board_early_init_f(void)
+ {
+ /* This is called before relocation; beware! */
+@@ -576,6 +624,7 @@ int board_late_init(void)
+ timer_callback, (void *)1);
+ #endif
+
++ pwm_init();
+ espi_init();
+
+ /* Add reset reason to bootargs */
+diff --git a/drivers/pinctrl/aspeed/pinctrl_ast2600.c b/drivers/pinctrl/aspeed/pinctrl_ast2600.c
+index 8a77a5d31556..980667f84e30 100644
+--- a/drivers/pinctrl/aspeed/pinctrl_ast2600.c
++++ b/drivers/pinctrl/aspeed/pinctrl_ast2600.c
+@@ -326,6 +326,110 @@ static struct aspeed_sig_desc pcie1rc_link[] = {
+ { 0x500, BIT(24), 0 }, //dedicate rc reset
+ };
+
++static struct aspeed_sig_desc pwm0[] = {
++ { 0x41C, BIT(16), 0 },
++};
++
++static struct aspeed_sig_desc pwm1[] = {
++ { 0x41C, BIT(17), 0 },
++};
++
++static struct aspeed_sig_desc pwm2[] = {
++ { 0x41C, BIT(18), 0 },
++};
++
++static struct aspeed_sig_desc pwm3[] = {
++ { 0x41C, BIT(19), 0 },
++};
++
++static struct aspeed_sig_desc pwm4[] = {
++ { 0x41C, BIT(20), 0 },
++};
++
++static struct aspeed_sig_desc pwm5[] = {
++ { 0x41C, BIT(21), 0 },
++};
++
++static struct aspeed_sig_desc pwm6[] = {
++ { 0x41C, BIT(22), 0 },
++};
++
++static struct aspeed_sig_desc pwm7[] = {
++ { 0x41C, BIT(23), 0 },
++};
++
++static struct aspeed_sig_desc pwm8g1[] = {
++ { 0x41C, BIT(24), 0 },
++};
++
++static struct aspeed_sig_desc pwm9g1[] = {
++ { 0x41C, BIT(25), 0 },
++};
++
++static struct aspeed_sig_desc pwm10g1[] = {
++ { 0x41C, BIT(26), 0 },
++};
++
++static struct aspeed_sig_desc pwm11g1[] = {
++ { 0x41C, BIT(27), 0 },
++};
++
++static struct aspeed_sig_desc pwm12g1[] = {
++ { 0x41C, BIT(28), 0 },
++};
++
++static struct aspeed_sig_desc pwm13g1[] = {
++ { 0x41C, BIT(29), 0 },
++};
++
++static struct aspeed_sig_desc pwm14g1[] = {
++ { 0x41C, BIT(30), 0 },
++};
++
++static struct aspeed_sig_desc pwm15g1[] = {
++ { 0x41C, BIT(31), 0 },
++};
++
++static struct aspeed_sig_desc pwm8g0[] = {
++ { 0x414, BIT(8), 1 },
++ { 0x4B4, BIT(8), 0 },
++};
++
++static struct aspeed_sig_desc pwm9g0[] = {
++ { 0x414, BIT(9), 1 },
++ { 0x4B4, BIT(9), 0 },
++};
++
++static struct aspeed_sig_desc pwm10g0[] = {
++ { 0x414, BIT(10), 1 },
++ { 0x4B4, BIT(10), 0 },
++};
++
++static struct aspeed_sig_desc pwm11g0[] = {
++ { 0x414, BIT(11), 1 },
++ { 0x4B4, BIT(11), 0 },
++};
++
++static struct aspeed_sig_desc pwm12g0[] = {
++ { 0x414, BIT(12), 1 },
++ { 0x4B4, BIT(12), 0 },
++};
++
++static struct aspeed_sig_desc pwm13g0[] = {
++ { 0x414, BIT(13), 1 },
++ { 0x4B4, BIT(13), 0 },
++};
++
++static struct aspeed_sig_desc pwm14g0[] = {
++ { 0x414, BIT(14), 1 },
++ { 0x4B4, BIT(14), 0 },
++};
++
++static struct aspeed_sig_desc pwm15g0[] = {
++ { 0x414, BIT(15), 1 },
++ { 0x4B4, BIT(15), 0 },
++};
++
+ static const struct aspeed_group_config ast2600_groups[] = {
+ { "MAC1LINK", ARRAY_SIZE(mac1_link), mac1_link },
+ { "MAC2LINK", ARRAY_SIZE(mac2_link), mac2_link },
+@@ -383,7 +487,31 @@ static const struct aspeed_group_config ast2600_groups[] = {
+ { "USB2AH", ARRAY_SIZE(usb2ah_link), usb2ah_link },
+ { "USB2BH", ARRAY_SIZE(usb2bh_link), usb2bh_link },
+ { "PCIE0RC", ARRAY_SIZE(pcie0rc_link), pcie0rc_link },
+- { "PCIE1RC", ARRAY_SIZE(pcie1rc_link), pcie1rc_link },
++ { "PCIE1RC", ARRAY_SIZE(pcie1rc_link), pcie1rc_link },
++ { "PWM0", ARRAY_SIZE(pwm0), pwm0 },
++ { "PWM1", ARRAY_SIZE(pwm1), pwm1 },
++ { "PWM2", ARRAY_SIZE(pwm2), pwm2 },
++ { "PWM3", ARRAY_SIZE(pwm3), pwm3 },
++ { "PWM4", ARRAY_SIZE(pwm4), pwm4 },
++ { "PWM5", ARRAY_SIZE(pwm5), pwm5 },
++ { "PWM6", ARRAY_SIZE(pwm6), pwm6 },
++ { "PWM7", ARRAY_SIZE(pwm7), pwm7 },
++ { "PWM8G1", ARRAY_SIZE(pwm8g1), pwm8g1 },
++ { "PWM9G1", ARRAY_SIZE(pwm9g1), pwm9g1 },
++ { "PWM10G1", ARRAY_SIZE(pwm10g1), pwm10g1 },
++ { "PWM11G1", ARRAY_SIZE(pwm11g1), pwm11g1 },
++ { "PWM12G1", ARRAY_SIZE(pwm12g1), pwm12g1 },
++ { "PWM13G1", ARRAY_SIZE(pwm13g1), pwm13g1 },
++ { "PWM14G1", ARRAY_SIZE(pwm14g1), pwm14g1 },
++ { "PWM15G1", ARRAY_SIZE(pwm15g1), pwm15g1 },
++ { "PWM8G0", ARRAY_SIZE(pwm8g0), pwm8g0 },
++ { "PWM9G0", ARRAY_SIZE(pwm9g0), pwm9g0 },
++ { "PWM10G0", ARRAY_SIZE(pwm10g0), pwm10g0 },
++ { "PWM11G0", ARRAY_SIZE(pwm11g0), pwm11g0 },
++ { "PWM12G0", ARRAY_SIZE(pwm12g0), pwm12g0 },
++ { "PWM13G0", ARRAY_SIZE(pwm13g0), pwm13g0 },
++ { "PWM14G0", ARRAY_SIZE(pwm14g0), pwm14g0 },
++ { "PWM15G0", ARRAY_SIZE(pwm15g0), pwm15g0 },
+ };
+
+ static int ast2600_pinctrl_get_groups_count(struct udevice *dev)
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index 2984b7976637..95e82ee5ddf6 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -50,3 +50,11 @@ config PWM_SUNXI
+ help
+ This PWM is found on H3, A64 and other Allwinner SoCs. It supports a
+ programmable period and duty cycle. A 16-bit counter is used.
++
++config PWM_ASPEED
++ bool "Enable support for the Aspeed AST2600 PWM"
++ depends on DM_PWM
++ depends on ASPEED_AST2600
++ help
++ This PWM is found on Aspeed AST2600 SoC. It supports a programmable
++ period and duty cycle. A 16-bit counter is used.
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index a837c35ed2e3..770b054c3f3b 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -16,3 +16,4 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o
+ obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o
+ obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o
+ obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o
++obj-$(CONFIG_PWM_ASPEED) += aspeed_pwm.o
+diff --git a/drivers/pwm/aspeed_pwm.c b/drivers/pwm/aspeed_pwm.c
+new file mode 100644
+index 000000000000..bd9a911b4fe2
+--- /dev/null
++++ b/drivers/pwm/aspeed_pwm.c
+@@ -0,0 +1,172 @@
++// SPDX-License-Identifier: GPL
++// Copyright (c) 2021 Intel Corporation
++
++#include <asm/io.h>
++#include <linux/bitfield.h>
++#include <clk.h>
++#include <common.h>
++#include <dm.h>
++#include <linux/ioport.h>
++#include <pwm.h>
++#include <reset.h>
++#include <asm/arch/scu_ast2600.h>
++
++#define NSEC_PER_SEC 1000000000L
++
++#define ASPEED_PWM_CTRL 0x00 /* PWM0 General Register */
++#define ASPEED_PWM_CTRL_CH(x) (((x) * 0x10) + ASPEED_PWM_CTRL)
++#define PWM_LOAD_AS_WDT BIT(19)
++#define PWM_DUTY_LOAD_AS_WDT_EN BIT(18)
++#define PWM_DUTY_SYNC_DIS BIT(17)
++#define PWM_CLK_ENABLE BIT(16)
++#define PWM_LEVEL_OUTPUT BIT(15)
++#define PWM_INVERSE BIT(14)
++#define PWM_OPEN_DRAIN_EN BIT(13)
++#define PWM_PIN_EN BIT(12)
++#define PWM_CLK_DIV_H_MASK GENMASK(11, 8)
++#define PWM_CLK_DIV_L_MASK GENMASK(7, 0)
++
++#define ASPEED_PWM_DUTY_CYCLE 0x04 /* PWM0 Duty Cycle Register */
++#define ASPEED_PWM_DUTY_CYCLE_CH(x) (((x) * 0x10) + ASPEED_PWM_DUTY_CYCLE)
++#define PWM_PERIOD_MASK GENMASK(31, 24)
++#define PWM_RISING_FALLING_AS_WDT_MASK GENMASK(23, 16)
++#define PWM_RISING_POINT_MASK GENMASK(15, 8)
++#define PWM_FALLING_POINT_MASK GENMASK(7, 0)
++
++#define PWM_PERIOD_MAX 255
++
++struct aspeed_pwm_priv {
++ void __iomem *base;
++ ulong clk_freq;
++ u32 clk_tick_ns;
++};
++
++static int aspeed_pwm_set_config(struct udevice *dev, uint channel,
++ uint period_ns, uint duty_ns)
++{
++ struct aspeed_pwm_priv *priv = dev_get_priv(dev);
++ u8 div_h, div_l, period_value, falling_point, rising_point;
++ u32 ctrl_value, duty_value, tick_ns;
++
++ /*
++ * We currently avoid using 64bit arithmetic by using the
++ * fact that anything faster than 1Hz is easily representable
++ * by 32bits.
++ */
++ if (period_ns > NSEC_PER_SEC)
++ return -ERANGE;
++
++ for (div_l = 0; div_l <= 0xff; div_l++) {
++ for (div_h = 0; div_h <= 0xf; div_h++) {
++ tick_ns = priv->clk_tick_ns * BIT(div_h) * (div_l + 1);
++ if (tick_ns * PWM_PERIOD_MAX >= period_ns)
++ break;
++ }
++ if (tick_ns * PWM_PERIOD_MAX >= period_ns)
++ break;
++ }
++
++ if (period_ns / tick_ns > PWM_PERIOD_MAX)
++ return -ERANGE;
++
++ ctrl_value = FIELD_PREP(PWM_CLK_DIV_H_MASK, div_h) |
++ FIELD_PREP(PWM_CLK_DIV_L_MASK, div_l);
++ period_value = period_ns / tick_ns;
++ falling_point = 0;
++ rising_point = duty_ns / tick_ns;
++ duty_value = FIELD_PREP(PWM_PERIOD_MASK, period_value) |
++ FIELD_PREP(PWM_RISING_POINT_MASK, rising_point) |
++ FIELD_PREP(PWM_FALLING_POINT_MASK, falling_point);
++
++ clrsetbits_le32(priv->base + ASPEED_PWM_DUTY_CYCLE_CH(channel),
++ PWM_PERIOD_MASK | PWM_RISING_POINT_MASK |
++ PWM_FALLING_POINT_MASK, duty_value);
++ clrsetbits_le32(priv->base + ASPEED_PWM_CTRL_CH(channel),
++ PWM_CLK_DIV_H_MASK | PWM_CLK_DIV_L_MASK, ctrl_value);
++
++ return 0;
++}
++
++static int aspeed_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
++{
++ struct aspeed_pwm_priv *priv = dev_get_priv(dev);
++
++ debug("%s: Enable '%s' channel %u\n", __func__, dev->name, channel);
++
++ clrsetbits_le32(priv->base + ASPEED_PWM_CTRL_CH(channel),
++ PWM_CLK_ENABLE | PWM_PIN_EN,
++ enable ? PWM_CLK_ENABLE | PWM_PIN_EN : 0);
++
++ return 0;
++}
++
++static int aspeed_pwm_ofdata_to_platdata(struct udevice *dev)
++{
++ struct aspeed_pwm_priv *priv = dev_get_priv(dev);
++ struct resource res_regs;
++ int ret;
++
++ ret = dev_read_resource(dev, 0, &res_regs);
++ if (ret < 0)
++ return ret;
++
++ priv->base = (void __iomem *)res_regs.start;
++
++ return 0;
++}
++
++static int aspeed_pwm_probe(struct udevice *dev)
++{
++ struct aspeed_pwm_priv *priv = dev_get_priv(dev);
++ struct reset_ctl reset_ctl;
++ struct clk hclk;
++ int ret;
++
++ ret = clk_get_by_index(dev, 0, &hclk);
++ if (ret) {
++ pr_err("%s: could not get clock: %d\n", dev->name, ret);
++ return ret;
++ }
++
++ priv->clk_freq = clk_get_rate(&hclk);
++ priv->clk_tick_ns = NSEC_PER_SEC / priv->clk_freq;
++ (void) clk_free(&hclk);
++
++ ret = reset_get_by_index(dev, 0, &reset_ctl);
++ if (ret) {
++ pr_err("%s: Failed to get reset signal: %d\n", dev->name, ret);
++ return ret;
++ }
++
++ ret = reset_assert(&reset_ctl);
++ if (!ret) {
++ mdelay(10);
++ ret = reset_deassert(&reset_ctl);
++ }
++
++ return ret;
++}
++
++static const struct pwm_ops aspeed_pwm_ops = {
++ .set_config = aspeed_pwm_set_config,
++ .set_enable = aspeed_pwm_set_enable,
++};
++
++static const struct udevice_id aspeed_pwm_ids[] = {
++ { .compatible = "aspeed,ast2600-pwm" },
++ { }
++};
++
++U_BOOT_DRIVER(aspeed_pwm) = {
++ .name = "aspeed_pwm",
++ .id = UCLASS_PWM,
++ .of_match = aspeed_pwm_ids,
++ .ops = &aspeed_pwm_ops,
++ .ofdata_to_platdata = aspeed_pwm_ofdata_to_platdata,
++ .priv_auto_alloc_size = sizeof(struct aspeed_pwm_priv),
++ .probe = aspeed_pwm_probe,
++};
++
++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Aspeed AST2600 PWM Driver");
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0031-Add-a-workaround-to-fix-AST2600-A0-booting-issue.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0031-Add-a-workaround-to-fix-AST2600-A0-booting-issue.patch
new file mode 100644
index 000000000..9444dde99
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0031-Add-a-workaround-to-fix-AST2600-A0-booting-issue.patch
@@ -0,0 +1,32 @@
+From 58ed1cb4ac3229b484c983a2e4982fad13da0e06 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 21 May 2021 17:24:13 -0700
+Subject: [PATCH] Add a workaround to fix AST2600 A0 booting issue
+
+AST2600 A0 doesn't boot with 88KB SRAM setting so this commit adds
+a workaround which pins SRAM size to 64KB to make A0 able to boot.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/include/asm/arch-aspeed/platform.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h
+index f016bdaba3e7..192e3b977a34 100644
+--- a/arch/arm/include/asm/arch-aspeed/platform.h
++++ b/arch/arm/include/asm/arch-aspeed/platform.h
+@@ -53,7 +53,11 @@
+ #define ASPEED_MAC_COUNT 4
+ #define ASPEED_DRAM_BASE 0x80000000
+ #define ASPEED_SRAM_BASE 0x10000000
++#if 1 /* AST2600 A0 doesn't boot with 88K setting so pin SRAM size to 64K */
++#define ASPEED_SRAM_SIZE 0x10000
++#else
+ #define ASPEED_SRAM_SIZE 0x16000
++#endif
+ #define ASPEED_FMC_CS0_BASE 0x20000000
+ #else
+ #err "No define for platform.h"
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0032-Disable-eSPI-initialization-in-u-boot-for-normal-boo.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0032-Disable-eSPI-initialization-in-u-boot-for-normal-boo.patch
new file mode 100644
index 000000000..018ab07cf
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0032-Disable-eSPI-initialization-in-u-boot-for-normal-boo.patch
@@ -0,0 +1,60 @@
+From 08f2b4f0464ef8abcf32511f8549233359d16eed Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 2 Jun 2021 13:03:47 -0700
+Subject: [PATCH] Disable eSPI initialization in u-boot for normal booting
+ cases
+
+Initializing eSPI in u-boot introduces a small blind window of
+handshaking when BMC jumps from boot loader to kernel and it causes
+an infinite PCH waiting issue in ME recovery mode. During the power
+on handshaking, PCH keeps waiting for OOB_FREE to continue its
+booting so the OOB_FREE actually means that BMC is fully ready for
+the power on handshake. To prevent the small blind window, this
+commit removes eSPI initialization in u-boot for normal booting
+cases and makes the kernel eSPI driver responsible for full
+eSPI initialization.
+
+eSPI will be initialized in u-boot only in these specific cases:
+1. When FFUJ (Force Firmware Update Jumper) is populated.
+2. When BMC booting is stopped at u-boot by typing a key.
+3. When BMC goes to u-boot due to the boot failure condition.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ board/aspeed/ast2600_intel/intel.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 54f53d77c476..f3f1d8114616 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -201,6 +201,10 @@ static void gpio_passthru_init(void)
+
+ void board_pre_abort_autoboot(void)
+ {
++ if (!read_ffuj()) {
++ espi_init();
++ kcs_init();
++ }
+ }
+
+ #define AST_LPC_BASE 0x1e789000
+@@ -625,7 +629,6 @@ int board_late_init(void)
+ #endif
+
+ pwm_init();
+- espi_init();
+
+ /* Add reset reason to bootargs */
+ snprintf(value, sizeof(value), "0x%x", gd->reset_reason);
+@@ -645,6 +648,7 @@ int board_late_init(void)
+ gpio_passthru_init();
+
+ if (read_ffuj()) {
++ espi_init();
+ kcs_init();
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0033-Disable-debug-interfaces.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0033-Disable-debug-interfaces.patch
new file mode 100644
index 000000000..9a7541eed
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0033-Disable-debug-interfaces.patch
@@ -0,0 +1,86 @@
+From 7a0f0e0915c7d9260a3d067746157112f85822db Mon Sep 17 00:00:00 2001
+From: Chen Yugang <yugang.chen@linux.intel.com>
+Date: Fri, 11 Jun 2021 12:44:25 +0800
+Subject: [PATCH] Disable debug interfaces
+
+1.Disable ARM Core CA7 debug features in
+SCU800: CA7 processor Control
+2.Disable Mailbox Write/Disable in PDSEF0: PCIe
+Device Security Enhancement Control Register F0
+3.Disable target AHB to PCIE RC bridge controller
+in AHBC88: AHB Bus Target Disable Control Register
+
+Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com>
+---
+ arch/arm/mach-aspeed/ast2600/platform.S | 34 +++++++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S
+index 4cc22e31c6..636bccad32 100644
+--- a/arch/arm/mach-aspeed/ast2600/platform.S
++++ b/arch/arm/mach-aspeed/ast2600/platform.S
+@@ -26,6 +26,9 @@
+ * +----------------------+ AST_SMP_MAILBOX_BASE
+ */
+
++#define AST_AHBC_BASE 0x1E600000
++#define AST_AHBC_BUS_TARGET_CTRL (AST_AHBC_BASE + 0x088)
++
+ #define AST_SMP_MAILBOX_BASE (0x1E6E2180)
+ #define AST_SMP_MBOX_FIELD_ENTRY (AST_SMP_MAILBOX_BASE + 0x0)
+ #define AST_SMP_MBOX_FIELD_GOSIGN (AST_SMP_MAILBOX_BASE + 0x4)
+@@ -50,6 +53,7 @@
+ #define AST_SCU_HW_STRAP2 (AST_SCU_BASE + 0x510)
+ #define AST_SCU_HW_STRAP2_CLR (AST_SCU_BASE + 0x514)
+ #define AST_SCU_HW_STRAP3 (AST_SCU_BASE + 0x51C)
++#define AST_SCU_CA7_PROCESSOR_CTRL (AST_SCU_BASE + 0x800)
+ #define AST_SCU_CA7_PARITY_CHK (AST_SCU_BASE + 0x820)
+ #define AST_SCU_CA7_PARITY_CLR (AST_SCU_BASE + 0x824)
+ #define AST_SCU_MMIO_DEC_SET (AST_SCU_BASE + 0xC24)
+@@ -83,6 +87,9 @@
+ #define AST_LPC_BASE 0x1E789000
+ #define AST_LPC_HICRA (AST_LPC_BASE + 0x09C)
+
++#define AST_PCIEATH_BASE 0x1E7F2000
++#define AST_PCIEATH_SECURITY_CTRL (AST_PCIEATH_BASE + 0x0F0)
++
+ /* Revision ID */
+ #define REV_ID_AST2600A0 0x05000303
+ #define REV_ID_AST2600A1 0x05010303
+@@ -436,6 +443,33 @@ skip_fill_wip_bit:
+ moveq r1, #0xff
+ str r1, [r0]
+
++ /* disable debug interfaces */
++ /* SCU_800 */
++ ldr r0, =AST_SCU_CA7_PROCESSOR_CTRL
++ ldr r1, [r0]
++ ldr r2, =0x0c03f
++ and r1, r1, r2
++ str r1, [r0]
++
++ /* PCIEATH_F0 */
++ ldr r0, =AST_PCIEATH_SECURITY_CTRL
++ ldr r1, [r0]
++ orr r1, #0x50000
++ str r1, [r0]
++
++ /* AHBC_088 */
++ ldr r0, =AST_AHBC_BASE
++ movw r1, #0x1a03
++ movt r1, #0xaeed
++ str r1, [r0]
++ ldr r0, =AST_AHBC_BUS_TARGET_CTRL
++ ldr r1, [r0]
++ orr r1, #0xc0000
++ str r1, [r0]
++ ldr r0, =AST_AHBC_BASE
++ movw r1, #0
++ str r1, [r0]
++
+ /* set UART routing back to default */
+ ldr r0, =AST_LPC_HICRA
+ ldr r1, =0x0
+--
+2.27.0
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0034-Implement-the-IPMI-commands-in-FFUJ-mode-in-u-boot.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0034-Implement-the-IPMI-commands-in-FFUJ-mode-in-u-boot.patch
new file mode 100644
index 000000000..0d27f9d70
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0034-Implement-the-IPMI-commands-in-FFUJ-mode-in-u-boot.patch
@@ -0,0 +1,211 @@
+From 8b0d9f83aeb6e58c271ffe2d07c79397fe813a78 Mon Sep 17 00:00:00 2001
+From: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+Date: Wed, 23 Jun 2021 18:10:08 +0000
+Subject: [PATCH] Implement the IPMI commands in FFUJ mode in u-boot
+
+Implemented the following IPMI commands in force firmware update
+jumper (FFUJ) mode in u-boot.
+
+1. Get BMC execution context (0x23)
+2. Get Security mode (0xb3)
+3. Set security mode (0xb4)
+4. Get buffer size (0x66)
+
+Tested:
+Used ipmitool from Host OS to verify each individual commands
+
+Positive test cases:
+
+get execution context
+ipmitool raw 8 0x23
+11 01
+get buffer size
+ipmitool raw 0x30 0x66
+ff ff
+set security mode
+ipmitool raw 0x30 0xb4 5
+get security mode
+ipmitool raw 0x30 0xb3
+05 00
+set security mode
+ipmitool raw 0x30 0xb4 4
+get security mode
+ipmitool raw 0x30 0xb3
+04 00
+set security mode
+ipmitool raw 0x30 0xb4 3
+get security mode
+ipmitool raw 0x30 0xb3
+03 00
+
+Negative test cases:
+
+set security mode
+ipmitool raw 0x30 0xb4 1
+Unable to send RAW command: Invalid data field in request
+ipmitool raw 0x30 0xb4 2
+Unable to send RAW command: Invalid data field in request
+ipmitool raw 0x30 0xb4 6
+Unable to send RAW command: Invalid data field in request
+ipmitool raw 0x30 0xb4 7
+Unable to send RAW command: Invalid data field in request
+
+Change-Id: I515cec5ff6019aa3ea30a9a38886130e354252a8
+Signed-off-by: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+---
+ board/aspeed/ast2600_intel/ipmi-handler.c | 120 +++++++++++++++++++++-
+ 1 file changed, 117 insertions(+), 3 deletions(-)
+
+diff --git a/board/aspeed/ast2600_intel/ipmi-handler.c b/board/aspeed/ast2600_intel/ipmi-handler.c
+index 04732846ac..5319f986a7 100644
+--- a/board/aspeed/ast2600_intel/ipmi-handler.c
++++ b/board/aspeed/ast2600_intel/ipmi-handler.c
+@@ -4,11 +4,28 @@
+ #include "ipmi-handler.h"
+
+ /* IPMI network function codes */
+-#define NETFN_APP 0x06
++#define NETFN_APP 0x06
++#define NETFN_FIRMWARE 0x08
++#define NETFN_INTEL_OEM 0x30
+
+ /* IPMI command codes */
+ #define CMD_GET_DEV_ID 0x01
+ #define CMD_GET_SELF_TEST_RESULTS 0x04
++#define CMD_FWUPD_GET_EXECUTION_CTX 0x23
++#define CMD_INTL_OEM_GET_BUFFER_SIZE 0x66
++#define CMD_INTL_OEM_GET_SEC_MODE 0xB3
++#define CMD_INTL_OEM_SET_SEC_MODE 0xB4
++
++#define MAX_KCS_BUF_SIZE 1020 /* (0xFF * 4) */
++#define MAX_IPMB_BUF_SIZE 1020 /* (0xFF * 4) */
++
++/* Restriction mode values */
++#define RESTRICTION_MODE_MIN_VALUE 3 /*Provisioning*/
++#define RESTRICION_MODE_MAX_VALUE 5 /*Provisioned host disabled */
++
++#define STR_ENV_PROVISION "provision"
++
++#define PRIMARY_IMAGE 0x01
+
+ typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res);
+
+@@ -28,6 +45,21 @@ struct self_test_res {
+ u8 completion_code;
+ u8 res_byte[2];
+ };
++struct fwupd_get_exe_ctx_res {
++ u8 completion_code;
++ u8 execution_ctx;
++ u8 partition_ptr;
++};
++struct intc_get_buf_size_res {
++ u8 completion_code;
++ u8 kcs_size;
++ u8 ipmb_size;
++};
++struct intc_get_secuirty_mode_res {
++ u8 completion_code;
++ u8 restriction_mode;
++ u8 special_mode;
++};
+
+ struct ipmi_cmd_table {
+ u8 net_fun;
+@@ -84,9 +116,91 @@ static u16 get_self_test_result(u8 *req, u16 req_len, u8 *res)
+ return sizeof(struct self_test_res);
+ }
+
++u16 fwupd_get_execution_ctx(u8 *req, u16 req_len, u8 *res) {
++
++ /* Get firmware update execution context */
++ struct fwupd_get_exe_ctx_res *result = (struct fwupd_get_exe_ctx_res *)res;
++
++ /* For PFR platforms, only primary/active image always */
++ result->partition_ptr = PRIMARY_IMAGE;
++ result->execution_ctx = 0x11; /* Forced Firmware Update mode */
++ result->completion_code = IPMI_CC_OK;
++
++ return sizeof(struct fwupd_get_exe_ctx_res);
++}
++
++static u16 intel_get_buffer_size(u8 *req, u16 req_len, u8 *res) {
++
++ /* Get buffer size */
++ struct intc_get_buf_size_res *result = (struct intc_get_buf_size_res *)res;
++
++ if (req_len != 0) {
++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH;
++ return sizeof(result->completion_code);
++ }
++
++ /* Size is multiples of four bytes */
++ result->completion_code = IPMI_CC_OK;
++ result->kcs_size = MAX_KCS_BUF_SIZE / 4;
++ result->ipmb_size = MAX_IPMB_BUF_SIZE / 4;
++
++ return sizeof(struct intc_get_buf_size_res);
++}
++
++static u16 intel_get_security_mode(u8 *req, u16 req_len, u8 *res) {
++
++ char *cmdline = NULL;
++ /* Get security mode */
++ struct intc_get_secuirty_mode_res *result =
++ (struct intc_get_secuirty_mode_res *)res;
++
++ if (req_len != 0) {
++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH;
++ return sizeof(result->completion_code);
++ }
++
++ cmdline = env_get(STR_ENV_PROVISION);
++
++ if (!cmdline) {
++ /* Default provision must be set only by linux */
++ result->completion_code = IPMI_CC_UNSPECIFIED;
++ return sizeof(result->completion_code);
++ }
++
++ result->restriction_mode = simple_strtol(cmdline, NULL, 10);
++ /* special mode is non-volatile and not applicable in U-Boot */
++ result->special_mode = 0;
++ result->completion_code = IPMI_CC_OK;
++
++ return sizeof(*result);
++}
++
++static u16 intel_set_security_mode(u8 *req, u16 req_len, u8 *res) {
++
++ if (req_len != sizeof(*req)) {
++ *res = IPMI_CC_INVALID_DATA_LENGTH;
++ return sizeof(*res);
++ }
++
++ if (*req > RESTRICION_MODE_MAX_VALUE || *req < RESTRICTION_MODE_MIN_VALUE) {
++ *res = IPMI_CC_INVALID_DATA_FIELD;
++ return sizeof(*res);
++ }
++
++ env_set_ulong(STR_ENV_PROVISION, *req);
++ env_save();
++ *res = IPMI_CC_OK;
++
++ return sizeof(*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 }
++ { NETFN_APP, CMD_GET_DEV_ID, get_device_id},
++ { NETFN_APP, CMD_GET_SELF_TEST_RESULTS, get_self_test_result},
++ { NETFN_FIRMWARE, CMD_FWUPD_GET_EXECUTION_CTX, fwupd_get_execution_ctx},
++ { NETFN_INTEL_OEM, CMD_INTL_OEM_GET_BUFFER_SIZE, intel_get_buffer_size},
++ { NETFN_INTEL_OEM, CMD_INTL_OEM_GET_SEC_MODE, intel_get_security_mode},
++ { NETFN_INTEL_OEM, CMD_INTL_OEM_SET_SEC_MODE, intel_set_security_mode}
+ };
+
+ #define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0035-Remove-u-boot-delay-before-autoboot-in-release-image.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0035-Remove-u-boot-delay-before-autoboot-in-release-image.patch
new file mode 100644
index 000000000..17ef21308
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0035-Remove-u-boot-delay-before-autoboot-in-release-image.patch
@@ -0,0 +1,34 @@
+From 7aeedcb63c6d83e7ad61b55a7098c2e6381a917c Mon Sep 17 00:00:00 2001
+From: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+Date: Sun, 12 Sep 2021 19:16:59 +0000
+Subject: [PATCH] Remove u-boot delay before autoboot in release image
+
+Removed the delay in u-boot which allowed the user to stop
+automatically booting to kernel in release image by changing
+the delay value to negative.
+
+Tested:
+After the fix, unable to stop the release image at u-boot
+and prevent autoboot.
+
+Signed-off-by: AKSHAY RAVEENDRAN K <akshay.raveendran.k@intel.com>
+---
+ include/configs/aspeed-common.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/configs/aspeed-common.h b/include/configs/aspeed-common.h
+index 2be63a5c66..9707a49f90 100644
+--- a/include/configs/aspeed-common.h
++++ b/include/configs/aspeed-common.h
+@@ -85,6 +85,8 @@
+
+ #define CONFIG_ENV_SECT_SIZE (4 << 10)
+
++#define CONFIG_BOOTDELAY -2
++
+ /*
+ * Ethernet related
+ */
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0036-Disable-BMC-MMIO-Decode-on-VGA-SCU-register-bit.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0036-Disable-BMC-MMIO-Decode-on-VGA-SCU-register-bit.patch
new file mode 100644
index 000000000..f48532102
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0036-Disable-BMC-MMIO-Decode-on-VGA-SCU-register-bit.patch
@@ -0,0 +1,62 @@
+From 700d71d2c9ef669583acb6900a913620bbb68ce0 Mon Sep 17 00:00:00 2001
+From: sureshv1 <suresh.vijayakumar@intel.com>
+Date: Mon, 20 Sep 2021 11:27:46 +0530
+Subject: [PATCH] Disable BMC MMIO Decode on VGA SCU register bit
+
+This patch is required to avoid un-necessary logging of
+redfish log(P2A Bridge Enabled) as the default value of
+SCUC20 has this bit set causing the default/init value
+to be taken into consideration and logging the event.
+
+Tested:
+Flashed the image and performed AC Power cycle multiple
+times also to check whether any critical events related
+to P2A Bridge enabled log, this redfish log is not being
+logged after this changes.
+
+Change-Id: If24fbea338ce17e3b4f1ba93b4d11c7843ddb952
+Signed-off-by: sureshv1 <suresh.vijayakumar@intel.com>
+---
+ board/aspeed/ast2600_intel/intel.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c
+index 1791045ee8..103bf538b5 100644
+--- a/board/aspeed/ast2600_intel/intel.c
++++ b/board/aspeed/ast2600_intel/intel.c
+@@ -478,6 +478,23 @@ static void pwm_init(void)
+ }
+ }
+
++/*
++ * Description: Disable BMC MMIO Decode on VGA
++ * which is not being used.
++ */
++void disable_bmc_mmio_decode_vga()
++{
++#define AST_SCU_BASE 0x1E6E2000
++#define AST_PCI_CONFIG_REG 0xC20
++
++ u32 pcie_config_val = readl(AST_SCU_BASE + AST_PCI_CONFIG_REG);
++
++ if (pcie_config_val & BIT(1)) {
++ writel(pcie_config_val & ~BIT(1),
++ AST_SCU_BASE + AST_PCI_CONFIG_REG);
++ }
++}
++
+ int board_early_init_f(void)
+ {
+ /* This is called before relocation; beware! */
+@@ -680,6 +697,8 @@ int board_late_init(void)
+
+ pwm_init();
+
++ disable_bmc_mmio_decode_vga();
++
+ /* Add reset reason to bootargs */
+ snprintf(value, sizeof(value), "0x%x", gd->reset_reason);
+ update_bootargs_cmd("resetreason", value);
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0037-Enable-I2C-clock-stretching-and-multi-master-support.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0037-Enable-I2C-clock-stretching-and-multi-master-support.patch
new file mode 100644
index 000000000..014915772
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0037-Enable-I2C-clock-stretching-and-multi-master-support.patch
@@ -0,0 +1,143 @@
+From 292700faccff983b60a6bf210af36d9bf7a0ac1a Mon Sep 17 00:00:00 2001
+From: Jan Sowinski <jan.sowinski@intel.com>
+Date: Fri, 15 Oct 2021 23:34:10 +0200
+Subject: [PATCH] Enable I2C clock stretching and multi-master support for
+ AST2600
+
+Enabled I2C clock stretching by default to
+improve general compatibility with various devices.
+
+Added support for multi-master mode enabled with
+"multi-master" property set in DTS for every i2c node.
+
+Signed-off-by: Jan Sowinski <jan.sowinski@intel.com>
+---
+ arch/arm/dts/ast2600-intel.dts | 8 ++++++++
+ drivers/i2c/ast_i2c.c | 19 ++++++++++++-------
+ 2 files changed, 20 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts
+index a76193716d..dba62fd254 100644
+--- a/arch/arm/dts/ast2600-intel.dts
++++ b/arch/arm/dts/ast2600-intel.dts
+@@ -168,6 +168,7 @@
+
+ &i2c4 {
+ status = "okay";
++ multi-master;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c5_default>;
+@@ -175,6 +176,7 @@
+
+ &i2c5 {
+ status = "okay";
++ multi-master;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c6_default>;
+@@ -182,6 +184,7 @@
+
+ &i2c6 {
+ status = "okay";
++ multi-master;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c7_default>;
+@@ -189,6 +192,7 @@
+
+ &i2c7 {
+ status = "okay";
++ multi-master;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c8_default>;
+@@ -196,6 +200,7 @@
+
+ &i2c8 {
+ status = "okay";
++ multi-master;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c9_default>;
+@@ -203,6 +208,7 @@
+
+ &i2c9 {
+ status = "okay";
++ multi-master;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c10_default>;
+@@ -210,6 +216,7 @@
+
+ &i2c12 {
+ status = "okay";
++ multi-master;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c13_default>;
+@@ -217,6 +224,7 @@
+
+ &i2c13 {
+ status = "okay";
++ multi-master;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c14_default>;
+diff --git a/drivers/i2c/ast_i2c.c b/drivers/i2c/ast_i2c.c
+index bbc32d6cdb..974641220b 100644
+--- a/drivers/i2c/ast_i2c.c
++++ b/drivers/i2c/ast_i2c.c
+@@ -31,6 +31,8 @@ struct ast_i2c_priv {
+ struct ast_i2c_regs *regs;
+ /* I2C speed in Hz */
+ int speed;
++ /* Multi-master mode */
++ bool multi_master;
+ };
+
+ /*
+@@ -67,14 +69,14 @@ static void ast_i2c_clear_interrupts(struct udevice *dev)
+ static void ast_i2c_init_bus(struct udevice *dev)
+ {
+ struct ast_i2c_priv *priv = dev_get_priv(dev);
++ u32 fun_ctrl_reg = I2CD_MASTER_EN;
+
+ /* Reset device */
+ writel(0, &priv->regs->fcr);
+- /* Enable Master Mode. Assuming single-master */
+- writel(I2CD_MASTER_EN
+- | I2CD_M_SDA_LOCK_EN
+- | I2CD_MULTI_MASTER_DIS | I2CD_M_SCL_DRIVE_EN,
+- &priv->regs->fcr);
++ /* Enable Single-Master or Multi-Master Mode. */
++ if (!priv->multi_master)
++ fun_ctrl_reg |= I2CD_MULTI_MASTER_DIS;
++ writel(fun_ctrl_reg, &priv->regs->fcr);
+ /* Enable Interrupts */
+ writel(I2CD_INTR_TX_ACK
+ | I2CD_INTR_TX_NAK
+@@ -100,6 +102,9 @@ static int ast_i2c_ofdata_to_platdata(struct udevice *dev)
+ return ret;
+ }
+
++ if (dev_read_bool(dev, "multi-master"))
++ priv->multi_master = true;
++
+ return 0;
+ }
+
+@@ -246,8 +251,8 @@ static int ast_i2c_deblock(struct udevice *dev)
+ bool scl_high = csr & I2CD_SCL_LINE_STS;
+ int ret = 0;
+
+- if (sda_high && scl_high) {
+- /* Bus is idle, no deblocking needed. */
++ if ((sda_high && scl_high) || priv->multi_master) {
++ /* Bus is idle or multi-master mode enabled, no deblocking needed. */
+ return 0;
+ } else if (sda_high) {
+ /* Send stop command */
+--
+2.25.1
+
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
new file mode 100644
index 000000000..df26cb5a9
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0043-AST2600-PFR-u-boot-env-changes-as-per-PFR-BMC-image.patch
@@ -0,0 +1,35 @@
+From 0b1cf63187baba9016fa01df7e58989c80d57465 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+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: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ 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 d5befb185b6a..2be63a5c662b 100644
+--- a/include/configs/aspeed-common.h
++++ b/include/configs/aspeed-common.h
+@@ -68,9 +68,11 @@
+ #define CONFIG_ENV_SIZE 0x10000
+ #endif
+
+-#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_SYS_REDUNDAND_ENVIRONMENT
+ #define CONFIG_ENV_OVERWRITE
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-11059/0001-Fix-ext4-block-group-descriptor-sizing.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-11059/0001-Fix-ext4-block-group-descriptor-sizing.patch
new file mode 100644
index 000000000..d35ee0ac1
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-11059/0001-Fix-ext4-block-group-descriptor-sizing.patch
@@ -0,0 +1,62 @@
+From febbc583319b567fe3d83e521cc2ace9be8d1501 Mon Sep 17 00:00:00 2001
+From: Benjamin Lim <jarsp.ctf@gmail.com>
+Date: Fri, 29 Mar 2019 07:29:45 -0400
+Subject: [PATCH] Fix ext4 block group descriptor sizing
+
+Ext4 allows for arbitrarily sized block group descriptors when 64-bit
+addressing is enabled, which was previously not properly supported. This
+patch dynamically allocates a chunk of memory of the correct size.
+
+Signed-off-by: Benjamin Lim <jarsp.ctf@gmail.com>
+---
+ fs/ext4/ext4_common.c | 19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
+index feffbfa9a9eb..464c33d0d74c 100644
+--- a/fs/ext4/ext4_common.c
++++ b/fs/ext4/ext4_common.c
+@@ -1587,7 +1587,7 @@ static int ext4fs_blockgroup
+
+ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
+ {
+- struct ext2_block_group blkgrp;
++ struct ext2_block_group *blkgrp;
+ struct ext2_sblock *sblock = &data->sblock;
+ struct ext_filesystem *fs = get_fs();
+ int log2blksz = get_fs()->dev_desc->log2blksz;
+@@ -1595,17 +1595,28 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
+ long int blkno;
+ unsigned int blkoff;
+
++ /* Allocate blkgrp based on gdsize (for 64-bit support). */
++ blkgrp = zalloc(get_fs()->gdsize);
++ if (!blkgrp)
++ return 0;
++
+ /* It is easier to calculate if the first inode is 0. */
+ ino--;
+ status = ext4fs_blockgroup(data, ino / le32_to_cpu
+- (sblock->inodes_per_group), &blkgrp);
+- if (status == 0)
++ (sblock->inodes_per_group), blkgrp);
++ if (status == 0) {
++ free(blkgrp);
+ return 0;
++ }
+
+ inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
+- blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) +
++ blkno = ext4fs_bg_get_inode_table_id(blkgrp, fs) +
+ (ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
+ blkoff = (ino % inodes_per_block) * fs->inodesz;
++
++ /* Free blkgrp as it is no longer required. */
++ free(blkgrp);
++
+ /* Read the inode. */
+ status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) -
+ log2blksz), blkoff,
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-11690/0001-lib-uuid-Fix-unseeded-PRNG-on-RANDOM_UUID-y.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-11690/0001-lib-uuid-Fix-unseeded-PRNG-on-RANDOM_UUID-y.patch
new file mode 100644
index 000000000..c793df2f4
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-11690/0001-lib-uuid-Fix-unseeded-PRNG-on-RANDOM_UUID-y.patch
@@ -0,0 +1,95 @@
+From 4ccf678f37731d8ec09eae8dca5f4cbe84132a52 Mon Sep 17 00:00:00 2001
+From: Eugeniu Rosca <erosca@de.adit-jv.com>
+Date: Thu, 2 May 2019 14:27:06 +0200
+Subject: [PATCH] lib: uuid: Fix unseeded PRNG on RANDOM_UUID=y
+
+The random uuid values (enabled via CONFIG_RANDOM_UUID=y) on our
+platform are always the same. Below is consistent on each cold boot:
+
+ => ### interrupt autoboot
+ => env default -a; gpt write mmc 1 $partitions; print uuid_gpt_misc
+ ...
+ uuid_gpt_misc=d117f98e-6f2c-d04b-a5b2-331a19f91cb2
+ => env default -a; gpt write mmc 1 $partitions; print uuid_gpt_misc
+ ...
+ uuid_gpt_misc=ad5ec4b6-2d9f-8544-9417-fe3bd1c9b1b3
+ => env default -a; gpt write mmc 1 $partitions; print uuid_gpt_misc
+ ...
+ uuid_gpt_misc=cceb0b18-39cb-d547-9db7-03b405fa77d4
+ => env default -a; gpt write mmc 1 $partitions; print uuid_gpt_misc
+ ...
+ uuid_gpt_misc=d4981a2b-0478-544e-9607-7fd3c651068d
+ => env default -a; gpt write mmc 1 $partitions; print uuid_gpt_misc
+ ...
+ uuid_gpt_misc=6d6c9a36-e919-264d-a9ee-bd00379686c7
+
+While the uuids do change on every 'gpt write' command, the values
+appear to be taken from the same pool, in the same order.
+
+Assuming U-Boot with RANDOM_UUID=y is deployed on a large number of
+devices, all those devices would essentially expose the same UUID,
+breaking the assumption of system/RFS/application designers who rely
+on UUID as being globally unique (e.g. a database using UUID as key
+would alias/mix up entries/records due to duplicated UUID).
+
+The root cause seems to be simply _not_ seeding PRNG before generating
+a random value. It turns out this belongs to an established class of
+PRNG-specific problems, commonly known as "unseeded randomness", for
+which I am able to find below bugs/CVE/CWE:
+ - https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2015-0285
+ ("CVE-2015-0285 openssl: handshake with unseeded PRNG")
+ - https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2015-9019
+ ("CVE-2015-9019 libxslt: math.random() in xslt uses unseeded
+ randomness")
+ - https://cwe.mitre.org/data/definitions/336.html
+ ("CWE-336: Same Seed in Pseudo-Random Number Generator (PRNG)")
+
+The first revision [1] of this patch updated the seed based on the
+output of get_timer(), similar to [4].
+
+There are two problems with this approach:
+ - get_timer() has a poor _ms_ resolution
+ - when gen_rand_uuid() is called in a loop, get_timer() returns the
+ same result, leading to the same seed being passed to srand(),
+ leading to the same uuid being generated for several partitions
+ with different names
+
+The above drawbacks have been addressed in the second version [2].
+In its third revision (current), the patch reworded the description
+and summary line to emphasize it is a *fix* rather than an improvement.
+
+Testing [3] consisted of running 'gpt write mmc 1 $partitions' in a
+loop on R-Car3 for several minutes, collecting 8844 randomly generated
+UUIDS. Two consecutive cold boots are concatenated in the log.
+As a result, all uuid values are unique (scripted check).
+
+Thanks to Roman, who reported the issue and provided support in fixing.
+
+[1] https://patchwork.ozlabs.org/patch/1091802/
+[2] https://patchwork.ozlabs.org/patch/1092945/
+[3] https://gist.github.com/erosca/2820be9d554f76b982edd48474d0e7ca
+[4] commit da384a9d7628 ("net: rename and refactor eth_rand_ethaddr() function")
+
+Reported-by: Roman Stratiienko <roman.stratiienko@globallogic.com>
+Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
+Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
+---
+ lib/uuid.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/lib/uuid.c b/lib/uuid.c
+index fa20ee39fc32..2d4d6ef7e461 100644
+--- a/lib/uuid.c
++++ b/lib/uuid.c
+@@ -238,6 +238,8 @@ void gen_rand_uuid(unsigned char *uuid_bin)
+ unsigned int *ptr = (unsigned int *)&uuid;
+ int i;
+
++ srand(get_ticks() + rand());
++
+ /* Set all fields randomly */
+ for (i = 0; i < sizeof(struct uuid) / sizeof(*ptr); i++)
+ *(ptr + i) = cpu_to_be32(rand());
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13104/0001-CVE-2019-13104-ext4-check-for-underflow-in-ext4fs_re.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13104/0001-CVE-2019-13104-ext4-check-for-underflow-in-ext4fs_re.patch
new file mode 100644
index 000000000..fbb9098fe
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13104/0001-CVE-2019-13104-ext4-check-for-underflow-in-ext4fs_re.patch
@@ -0,0 +1,41 @@
+From 878269dbe74229005dd7f27aca66c554e31dad8e Mon Sep 17 00:00:00 2001
+From: Paul Emge <paulemge@forallsecure.com>
+Date: Mon, 8 Jul 2019 16:37:05 -0700
+Subject: [PATCH] CVE-2019-13104: ext4: check for underflow in ext4fs_read_file
+
+in ext4fs_read_file, it is possible for a broken/malicious file
+system to cause a memcpy of a negative number of bytes, which
+overflows all memory. This patch fixes the issue by checking for
+a negative length.
+
+Signed-off-by: Paul Emge <paulemge@forallsecure.com>
+---
+ fs/ext4/ext4fs.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
+index 85dc122f3003..e2b740cac405 100644
+--- a/fs/ext4/ext4fs.c
++++ b/fs/ext4/ext4fs.c
+@@ -66,13 +66,15 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+
+ ext_cache_init(&cache);
+
+- if (blocksize <= 0)
+- return -1;
+-
+ /* Adjust len so it we can't read past the end of the file. */
+ if (len + pos > filesize)
+ len = (filesize - pos);
+
++ if (blocksize <= 0 || len <= 0) {
++ ext_cache_fini(&cache);
++ return -1;
++ }
++
+ blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
+
+ for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13105/0001-fs-ext4-cache-extent-data.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13105/0001-fs-ext4-cache-extent-data.patch
new file mode 100644
index 000000000..4daf1649e
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13105/0001-fs-ext4-cache-extent-data.patch
@@ -0,0 +1,409 @@
+From c7422737dc7c2ecd7c2118540fbc0dad48affaf5 Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Wed, 30 Jan 2019 12:58:05 -0700
+Subject: [PATCH] fs: ext4: cache extent data
+
+When a file contains extents, U-Boot currently reads extent-related data
+for each block in the file, even if that data is located in the same
+block each time. This significantly slows down loading of files that use
+extents. Implement a very dumb cache to prevent repeatedly reading the
+same block. Files with extents now load as fast as files without.
+
+Note: There are many cases where read_allocated_block() is called. This
+patch only addresses one of those places; all others still read redundant
+data in any case they did before. This is a minimal patch to fix the
+load command; other cases aren't fixed.
+
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+---
+ fs/ext4/ext4_common.c | 45 ++++++++++++++++++++++---------------
+ fs/ext4/ext4_journal.c | 22 +++++++++---------
+ fs/ext4/ext4_write.c | 6 ++---
+ fs/ext4/ext4fs.c | 51 +++++++++++++++++++++++++++++++++++++-----
+ include/ext4fs.h | 12 +++++++++-
+ 5 files changed, 99 insertions(+), 37 deletions(-)
+
+diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
+index 67e2471bd388..29308e3b4474 100644
+--- a/fs/ext4/ext4_common.c
++++ b/fs/ext4/ext4_common.c
+@@ -510,7 +510,8 @@ restart:
+
+ restart_read:
+ /* read the block no allocated to a file */
+- first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx);
++ first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx,
++ NULL);
+ if (first_block_no_of_root <= 0)
+ goto fail;
+
+@@ -646,7 +647,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname)
+
+ /* get the block no allocated to a file */
+ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
+- blknr = read_allocated_block(parent_inode, blk_idx);
++ blknr = read_allocated_block(parent_inode, blk_idx, NULL);
+ if (blknr <= 0)
+ goto fail;
+
+@@ -943,7 +944,7 @@ int ext4fs_filename_unlink(char *filename)
+
+ /* read the block no allocated to a file */
+ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
+- blknr = read_allocated_block(g_parent_inode, blk_idx);
++ blknr = read_allocated_block(g_parent_inode, blk_idx, NULL);
+ if (blknr <= 0)
+ break;
+ inodeno = unlink_filename(filename, blknr);
+@@ -1522,7 +1523,7 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
+ #endif
+
+ static struct ext4_extent_header *ext4fs_get_extent_block
+- (struct ext2_data *data, char *buf,
++ (struct ext2_data *data, struct ext_block_cache *cache,
+ struct ext4_extent_header *ext_block,
+ uint32_t fileblock, int log2_blksz)
+ {
+@@ -1551,12 +1552,10 @@ static struct ext4_extent_header *ext4fs_get_extent_block
+
+ block = le16_to_cpu(index[i].ei_leaf_hi);
+ block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
+-
+- if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
+- buf))
+- ext_block = (struct ext4_extent_header *)buf;
+- else
++ block <<= log2_blksz;
++ if (!ext_cache_read(cache, (lbaint_t)block, blksz))
+ return NULL;
++ ext_block = (struct ext4_extent_header *)cache->buf;
+ }
+ }
+
+@@ -1613,7 +1612,8 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
+ return 1;
+ }
+
+-long int read_allocated_block(struct ext2_inode *inode, int fileblock)
++long int read_allocated_block(struct ext2_inode *inode, int fileblock,
++ struct ext_block_cache *cache)
+ {
+ long int blknr;
+ int blksz;
+@@ -1630,20 +1630,26 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
+
+ if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
+ long int startblock, endblock;
+- char *buf = zalloc(blksz);
+- if (!buf)
+- return -ENOMEM;
++ struct ext_block_cache *c, cd;
+ struct ext4_extent_header *ext_block;
+ struct ext4_extent *extent;
+ int i;
++
++ if (cache) {
++ c = cache;
++ } else {
++ c = &cd;
++ ext_cache_init(c);
++ }
+ ext_block =
+- ext4fs_get_extent_block(ext4fs_root, buf,
++ ext4fs_get_extent_block(ext4fs_root, c,
+ (struct ext4_extent_header *)
+ inode->b.blocks.dir_blocks,
+ fileblock, log2_blksz);
+ if (!ext_block) {
+ printf("invalid extent block\n");
+- free(buf);
++ if (!cache)
++ ext_cache_fini(c);
+ return -EINVAL;
+ }
+
+@@ -1655,19 +1661,22 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
+
+ if (startblock > fileblock) {
+ /* Sparse file */
+- free(buf);
++ if (!cache)
++ ext_cache_fini(c);
+ return 0;
+
+ } else if (fileblock < endblock) {
+ start = le16_to_cpu(extent[i].ee_start_hi);
+ start = (start << 32) +
+ le32_to_cpu(extent[i].ee_start_lo);
+- free(buf);
++ if (!cache)
++ ext_cache_fini(c);
+ return (fileblock - startblock) + start;
+ }
+ }
+
+- free(buf);
++ if (!cache)
++ ext_cache_fini(c);
+ return 0;
+ }
+
+diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
+index 148593da7fef..6adbab93a68f 100644
+--- a/fs/ext4/ext4_journal.c
++++ b/fs/ext4/ext4_journal.c
+@@ -347,7 +347,7 @@ void recover_transaction(int prev_desc_logical_no)
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+ (struct ext2_inode *)&inode_journal);
+ blknr = read_allocated_block((struct ext2_inode *)
+- &inode_journal, i);
++ &inode_journal, i, NULL);
+ ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
+ temp_buff);
+ p_jdb = (char *)temp_buff;
+@@ -372,7 +372,7 @@ void recover_transaction(int prev_desc_logical_no)
+ be32_to_cpu(jdb->h_sequence)) == 0)
+ continue;
+ }
+- blknr = read_allocated_block(&inode_journal, i);
++ blknr = read_allocated_block(&inode_journal, i, NULL);
+ ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
+ fs->blksz, metadata_buff);
+ put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
+@@ -419,7 +419,8 @@ int ext4fs_check_journal_state(int recovery_flag)
+ }
+
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+- blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
++ blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
++ NULL);
+ ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
+ temp_buff);
+ jsb = (struct journal_superblock_t *) temp_buff;
+@@ -443,7 +444,7 @@ int ext4fs_check_journal_state(int recovery_flag)
+
+ i = be32_to_cpu(jsb->s_first);
+ while (1) {
+- blknr = read_allocated_block(&inode_journal, i);
++ blknr = read_allocated_block(&inode_journal, i, NULL);
+ memset(temp_buff1, '\0', fs->blksz);
+ ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
+ 0, fs->blksz, temp_buff1);
+@@ -537,7 +538,7 @@ end:
+ ext4_read_superblock((char *)fs->sb);
+
+ blknr = read_allocated_block(&inode_journal,
+- EXT2_JOURNAL_SUPERBLOCK);
++ EXT2_JOURNAL_SUPERBLOCK, NULL);
+ put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
+ (struct journal_superblock_t *)temp_buff,
+ (uint32_t) fs->blksz);
+@@ -566,7 +567,7 @@ static void update_descriptor_block(long int blknr)
+
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+ jsb_blknr = read_allocated_block(&inode_journal,
+- EXT2_JOURNAL_SUPERBLOCK);
++ EXT2_JOURNAL_SUPERBLOCK, NULL);
+ ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
+ temp_buff);
+ jsb = (struct journal_superblock_t *) temp_buff;
+@@ -618,7 +619,7 @@ static void update_commit_block(long int blknr)
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+ &inode_journal);
+ jsb_blknr = read_allocated_block(&inode_journal,
+- EXT2_JOURNAL_SUPERBLOCK);
++ EXT2_JOURNAL_SUPERBLOCK, NULL);
+ ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
+ temp_buff);
+ jsb = (struct journal_superblock_t *) temp_buff;
+@@ -645,16 +646,17 @@ void ext4fs_update_journal(void)
+ long int blknr;
+ int i;
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+- blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
++ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
+ update_descriptor_block(blknr);
+ for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+ if (journal_ptr[i]->blknr == -1)
+ break;
+- blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
++ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++,
++ NULL);
+ put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
+ journal_ptr[i]->buf, fs->blksz);
+ }
+- blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
++ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
+ update_commit_block(blknr);
+ printf("update journal finished\n");
+ }
+diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
+index 4eb77c327ef3..95ffa3dfad51 100644
+--- a/fs/ext4/ext4_write.c
++++ b/fs/ext4/ext4_write.c
+@@ -479,7 +479,7 @@ static int ext4fs_delete_file(int inodeno)
+
+ /* release data blocks */
+ for (i = 0; i < no_blocks; i++) {
+- blknr = read_allocated_block(&inode, i);
++ blknr = read_allocated_block(&inode, i, NULL);
+ if (blknr == 0)
+ continue;
+ if (blknr < 0)
+@@ -695,7 +695,7 @@ void ext4fs_deinit(void)
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+ &inode_journal);
+ blknr = read_allocated_block(&inode_journal,
+- EXT2_JOURNAL_SUPERBLOCK);
++ EXT2_JOURNAL_SUPERBLOCK, NULL);
+ ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
+ temp_buff);
+ jsb = (struct journal_superblock_t *)temp_buff;
+@@ -776,7 +776,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
+ long int blknr;
+ int blockend = fs->blksz;
+ int skipfirst = 0;
+- blknr = read_allocated_block(file_inode, i);
++ blknr = read_allocated_block(file_inode, i, NULL);
+ if (blknr <= 0)
+ return -1;
+
+diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
+index 2a28031d14ca..26db677a1f17 100644
+--- a/fs/ext4/ext4fs.c
++++ b/fs/ext4/ext4fs.c
+@@ -62,6 +62,9 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+ lbaint_t delayed_next = 0;
+ char *delayed_buf = NULL;
+ short status;
++ struct ext_block_cache cache;
++
++ ext_cache_init(&cache);
+
+ if (blocksize <= 0)
+ return -1;
+@@ -77,9 +80,11 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+ int blockoff = pos - (blocksize * i);
+ int blockend = blocksize;
+ int skipfirst = 0;
+- blknr = read_allocated_block(&(node->inode), i);
+- if (blknr < 0)
++ blknr = read_allocated_block(&node->inode, i, &cache);
++ if (blknr < 0) {
++ ext_cache_fini(&cache);
+ return -1;
++ }
+
+ blknr = blknr << log2_fs_blocksize;
+
+@@ -109,8 +114,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+ delayed_skipfirst,
+ delayed_extent,
+ delayed_buf);
+- if (status == 0)
++ if (status == 0) {
++ ext_cache_fini(&cache);
+ return -1;
++ }
+ previous_block_number = blknr;
+ delayed_start = blknr;
+ delayed_extent = blockend;
+@@ -136,8 +143,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+ delayed_skipfirst,
+ delayed_extent,
+ delayed_buf);
+- if (status == 0)
++ if (status == 0) {
++ ext_cache_fini(&cache);
+ return -1;
++ }
+ previous_block_number = -1;
+ }
+ /* Zero no more than `len' bytes. */
+@@ -153,12 +162,15 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+ status = ext4fs_devread(delayed_start,
+ delayed_skipfirst, delayed_extent,
+ delayed_buf);
+- if (status == 0)
++ if (status == 0) {
++ ext_cache_fini(&cache);
+ return -1;
++ }
+ previous_block_number = -1;
+ }
+
+ *actread = len;
++ ext_cache_fini(&cache);
+ return 0;
+ }
+
+@@ -252,3 +264,32 @@ int ext4fs_uuid(char *uuid_str)
+ return -ENOSYS;
+ #endif
+ }
++
++void ext_cache_init(struct ext_block_cache *cache)
++{
++ memset(cache, 0, sizeof(*cache));
++}
++
++void ext_cache_fini(struct ext_block_cache *cache)
++{
++ free(cache->buf);
++ ext_cache_init(cache);
++}
++
++int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size)
++{
++ /* This could be more lenient, but this is simple and enough for now */
++ if (cache->buf && cache->block == block && cache->size == size)
++ return 1;
++ ext_cache_fini(cache);
++ cache->buf = malloc(size);
++ if (!cache->buf)
++ return 0;
++ if (!ext4fs_devread(block, 0, size, cache->buf)) {
++ free(cache->buf);
++ return 0;
++ }
++ cache->block = block;
++ cache->size = size;
++ return 1;
++}
+diff --git a/include/ext4fs.h b/include/ext4fs.h
+index 24210113411a..4b5de6e7b636 100644
+--- a/include/ext4fs.h
++++ b/include/ext4fs.h
+@@ -117,6 +117,12 @@ struct ext_filesystem {
+ struct blk_desc *dev_desc;
+ };
+
++struct ext_block_cache {
++ char *buf;
++ lbaint_t block;
++ int size;
++};
++
+ extern struct ext2_data *ext4fs_root;
+ extern struct ext2fs_node *ext4fs_file;
+
+@@ -146,11 +152,15 @@ int ext4fs_size(const char *filename, loff_t *size);
+ void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot);
+ int ext4fs_devread(lbaint_t sector, int byte_offset, int byte_len, char *buf);
+ void ext4fs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info);
+-long int read_allocated_block(struct ext2_inode *inode, int fileblock);
++long int read_allocated_block(struct ext2_inode *inode, int fileblock,
++ struct ext_block_cache *cache);
+ int ext4fs_probe(struct blk_desc *fs_dev_desc,
+ disk_partition_t *fs_partition);
+ int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
+ loff_t *actread);
+ int ext4_read_superblock(char *buffer);
+ int ext4fs_uuid(char *uuid_str);
++void ext_cache_init(struct ext_block_cache *cache);
++void ext_cache_fini(struct ext_block_cache *cache);
++int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size);
+ #endif
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13105/0002-CVE-2019-13105-ext4-fix-double-free-in-ext4_cache_re.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13105/0002-CVE-2019-13105-ext4-fix-double-free-in-ext4_cache_re.patch
new file mode 100644
index 000000000..f7ccb41f4
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13105/0002-CVE-2019-13105-ext4-fix-double-free-in-ext4_cache_re.patch
@@ -0,0 +1,30 @@
+From 6e5a79de658cb1c8012c86e0837379aa6eabd024 Mon Sep 17 00:00:00 2001
+From: Paul Emge <paulemge@forallsecure.com>
+Date: Mon, 8 Jul 2019 16:37:04 -0700
+Subject: [PATCH] CVE-2019-13105: ext4: fix double-free in ext4_cache_read
+
+ext_cache_read doesn't null cache->buf, after freeing, which results
+in a later function double-freeing it. This patch fixes
+ext_cache_read to call ext_cache_fini instead of free.
+
+Signed-off-by: Paul Emge <paulemge@forallsecure.com>
+---
+ fs/ext4/ext4fs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
+index 26db677a1f17..85dc122f3003 100644
+--- a/fs/ext4/ext4fs.c
++++ b/fs/ext4/ext4fs.c
+@@ -286,7 +286,7 @@ int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size)
+ if (!cache->buf)
+ return 0;
+ if (!ext4fs_devread(block, 0, size, cache->buf)) {
+- free(cache->buf);
++ ext_cache_fini(cache);
+ return 0;
+ }
+ cache->block = block;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13106/0001-CVE-2019-13106-ext4-fix-out-of-bounds-memset.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13106/0001-CVE-2019-13106-ext4-fix-out-of-bounds-memset.patch
new file mode 100644
index 000000000..9bd0b27a8
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2019-13106/0001-CVE-2019-13106-ext4-fix-out-of-bounds-memset.patch
@@ -0,0 +1,49 @@
+From e205896c5383c938274262524adceb2775fb03ba Mon Sep 17 00:00:00 2001
+From: Paul Emge <paulemge@forallsecure.com>
+Date: Mon, 8 Jul 2019 16:37:07 -0700
+Subject: [PATCH] CVE-2019-13106: ext4: fix out-of-bounds memset
+
+In ext4fs_read_file in ext4fs.c, a memset can overwrite the bounds of
+the destination memory region. This patch adds a check to disallow
+this.
+
+Signed-off-by: Paul Emge <paulemge@forallsecure.com>
+---
+ fs/ext4/ext4fs.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
+index e2b740cac405..37b31d9f0fcc 100644
+--- a/fs/ext4/ext4fs.c
++++ b/fs/ext4/ext4fs.c
+@@ -61,6 +61,7 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+ lbaint_t delayed_skipfirst = 0;
+ lbaint_t delayed_next = 0;
+ char *delayed_buf = NULL;
++ char *start_buf = buf;
+ short status;
+ struct ext_block_cache cache;
+
+@@ -139,6 +140,7 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+ }
+ } else {
+ int n;
++ int n_left;
+ if (previous_block_number != -1) {
+ /* spill */
+ status = ext4fs_devread(delayed_start,
+@@ -153,8 +155,9 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
+ }
+ /* Zero no more than `len' bytes. */
+ n = blocksize - skipfirst;
+- if (n > len)
+- n = len;
++ n_left = len - ( buf - start_buf );
++ if (n > n_left)
++ n = n_left;
+ memset(buf, 0, n);
+ }
+ buf += blocksize - skipfirst;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0001-image-Correct-comment-for-fit_conf_get_node.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0001-image-Correct-comment-for-fit_conf_get_node.patch
new file mode 100644
index 000000000..8c922f5e8
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0001-image-Correct-comment-for-fit_conf_get_node.patch
@@ -0,0 +1,77 @@
+From 211549e16fa6601f9783e6e3802db9aaa3f4922e Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Tue, 31 Mar 2020 18:43:55 +0200
+Subject: [PATCH] image: Correct comment for fit_conf_get_node()
+
+This should mention that conf_uname can be NULL and should be in the
+header file. Fix this.
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ common/image-fit.c | 18 ------------------
+ include/image.h | 19 +++++++++++++++++++
+ 2 files changed, 19 insertions(+), 18 deletions(-)
+
+diff --git a/common/image-fit.c b/common/image-fit.c
+index ac901e131ca1..06f3358c931c 100644
+--- a/common/image-fit.c
++++ b/common/image-fit.c
+@@ -1612,24 +1612,6 @@ int fit_conf_find_compat(const void *fit, const void *fdt)
+ return best_match_offset;
+ }
+
+-/**
+- * fit_conf_get_node - get node offset for configuration of a given unit name
+- * @fit: pointer to the FIT format image header
+- * @conf_uname: configuration node unit name
+- *
+- * fit_conf_get_node() finds a configuration (within the '/configurations'
+- * parent node) of a provided unit name. If configuration is found its node
+- * offset is returned to the caller.
+- *
+- * When NULL is provided in second argument fit_conf_get_node() will search
+- * for a default configuration node instead. Default configuration node unit
+- * name is retrieved from FIT_DEFAULT_PROP property of the '/configurations'
+- * node.
+- *
+- * returns:
+- * configuration node offset when found (>=0)
+- * negative number on failure (FDT_ERR_* code)
+- */
+ int fit_conf_get_node(const void *fit, const char *conf_uname)
+ {
+ int noffset, confs_noffset;
+diff --git a/include/image.h b/include/image.h
+index 765ffecee0a7..4b764d11c70d 100644
+--- a/include/image.h
++++ b/include/image.h
+@@ -1045,6 +1045,25 @@ int fit_image_check_comp(const void *fit, int noffset, uint8_t comp);
+ int fit_check_format(const void *fit);
+
+ int fit_conf_find_compat(const void *fit, const void *fdt);
++
++/**
++ * fit_conf_get_node - get node offset for configuration of a given unit name
++ * @fit: pointer to the FIT format image header
++ * @conf_uname: configuration node unit name (NULL to use default)
++ *
++ * fit_conf_get_node() finds a configuration (within the '/configurations'
++ * parent node) of a provided unit name. If configuration is found its node
++ * offset is returned to the caller.
++ *
++ * When NULL is provided in second argument fit_conf_get_node() will search
++ * for a default configuration node instead. Default configuration node unit
++ * name is retrieved from FIT_DEFAULT_PROP property of the '/configurations'
++ * node.
++ *
++ * returns:
++ * configuration node offset when found (>=0)
++ * negative number on failure (FDT_ERR_* code)
++ */
+ int fit_conf_get_node(const void *fit, const char *conf_uname);
+
+ /**
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0008-image-Load-the-correct-configuration-in-fit_check_si.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0008-image-Load-the-correct-configuration-in-fit_check_si.patch
new file mode 100644
index 000000000..9a6b64b06
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0008-image-Load-the-correct-configuration-in-fit_check_si.patch
@@ -0,0 +1,51 @@
+From 0b274994cc0fe1631c27837a4e4c546b37d7dc77 Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Tue, 31 Mar 2020 18:43:55 +0200
+Subject: [PATCH] image: Load the correct configuration in fit_check_sign
+
+At present bootm_host_load_images() is passed the configuration that has
+been verified, but ignores it and just uses the default configuration.
+This may not be the same.
+
+Update this function to use the selected configuration.
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ common/bootm.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/common/bootm.c b/common/bootm.c
+index 3adbceaa38e3..29091be0a1c8 100644
+--- a/common/bootm.c
++++ b/common/bootm.c
+@@ -929,7 +929,8 @@ void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
+ memmove(to, from, len);
+ }
+
+-static int bootm_host_load_image(const void *fit, int req_image_type)
++static int bootm_host_load_image(const void *fit, int req_image_type,
++ int cfg_noffset)
+ {
+ const char *fit_uname_config = NULL;
+ ulong data, len;
+@@ -941,6 +942,7 @@ static int bootm_host_load_image(const void *fit, int req_image_type)
+ void *load_buf;
+ int ret;
+
++ fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
+ memset(&images, '\0', sizeof(images));
+ images.verify = 1;
+ noffset = fit_image_load(&images, (ulong)fit,
+@@ -985,7 +987,7 @@ int bootm_host_load_images(const void *fit, int cfg_noffset)
+ for (i = 0; i < ARRAY_SIZE(image_types); i++) {
+ int ret;
+
+- ret = bootm_host_load_image(fit, image_types[i]);
++ ret = bootm_host_load_image(fit, image_types[i], cfg_noffset);
+ if (!err && ret && ret != -ENOENT)
+ err = ret;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0009-fit_check_sign-Allow-selecting-the-configuration-to-.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0009-fit_check_sign-Allow-selecting-the-configuration-to-.patch
new file mode 100644
index 000000000..3094e7ecc
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0009-fit_check_sign-Allow-selecting-the-configuration-to-.patch
@@ -0,0 +1,101 @@
+From 77b652268cacc0f114ba9e92b79e7ff372ec62ee Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Tue, 31 Mar 2020 18:43:55 +0200
+Subject: [PATCH] fit_check_sign: Allow selecting the configuration to verify
+
+This tool always verifies the default configuration. It is useful to be
+able to verify a specific one. Add a command-line flag for this and plumb
+the logic through.
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ tools/fdt_host.h | 3 ++-
+ tools/fit_check_sign.c | 8 ++++++--
+ tools/image-host.c | 6 ++++--
+ 3 files changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/tools/fdt_host.h b/tools/fdt_host.h
+index 99b009b22109..15c07c7a96ed 100644
+--- a/tools/fdt_host.h
++++ b/tools/fdt_host.h
+@@ -27,6 +27,7 @@
+ */
+ int fdt_remove_unused_strings(const void *old, void *new);
+
+-int fit_check_sign(const void *working_fdt, const void *key);
++int fit_check_sign(const void *fit, const void *key,
++ const char *fit_uname_config);
+
+ #endif /* __FDT_HOST_H__ */
+diff --git a/tools/fit_check_sign.c b/tools/fit_check_sign.c
+index 62adc751cbce..303e878ddb4d 100644
+--- a/tools/fit_check_sign.c
++++ b/tools/fit_check_sign.c
+@@ -41,6 +41,7 @@ int main(int argc, char **argv)
+ void *fit_blob;
+ char *fdtfile = NULL;
+ char *keyfile = NULL;
++ char *config_name = NULL;
+ char cmdname[256];
+ int ret;
+ void *key_blob;
+@@ -48,7 +49,7 @@ int main(int argc, char **argv)
+
+ strncpy(cmdname, *argv, sizeof(cmdname) - 1);
+ cmdname[sizeof(cmdname) - 1] = '\0';
+- while ((c = getopt(argc, argv, "f:k:")) != -1)
++ while ((c = getopt(argc, argv, "f:k:c:")) != -1)
+ switch (c) {
+ case 'f':
+ fdtfile = optarg;
+@@ -56,6 +57,9 @@ int main(int argc, char **argv)
+ case 'k':
+ keyfile = optarg;
+ break;
++ case 'c':
++ config_name = optarg;
++ break;
+ default:
+ usage(cmdname);
+ break;
+@@ -78,7 +82,7 @@ int main(int argc, char **argv)
+ return EXIT_FAILURE;
+
+ image_set_host_blob(key_blob);
+- ret = fit_check_sign(fit_blob, key_blob);
++ ret = fit_check_sign(fit_blob, key_blob, config_name);
+ if (!ret) {
+ ret = EXIT_SUCCESS;
+ fprintf(stderr, "Signature check OK\n");
+diff --git a/tools/image-host.c b/tools/image-host.c
+index 8e94ee8f3e31..28474bc7fc8b 100644
+--- a/tools/image-host.c
++++ b/tools/image-host.c
+@@ -734,12 +734,13 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
+ }
+
+ #ifdef CONFIG_FIT_SIGNATURE
+-int fit_check_sign(const void *fit, const void *key)
++int fit_check_sign(const void *fit, const void *key,
++ const char *fit_uname_config)
+ {
+ int cfg_noffset;
+ int ret;
+
+- cfg_noffset = fit_conf_get_node(fit, NULL);
++ cfg_noffset = fit_conf_get_node(fit, fit_uname_config);
+ if (!cfg_noffset)
+ return -1;
+
+@@ -748,6 +749,7 @@ int fit_check_sign(const void *fit, const void *key)
+ ret = fit_config_verify(fit, cfg_noffset);
+ if (ret)
+ return ret;
++ printf("Verified OK, loading images\n");
+ ret = bootm_host_load_images(fit, cfg_noffset);
+
+ return ret;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0012-image-Use-constants-for-required-and-key-name-hint.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0012-image-Use-constants-for-required-and-key-name-hint.patch
new file mode 100644
index 000000000..6cdaaa656
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2020-10648/0012-image-Use-constants-for-required-and-key-name-hint.patch
@@ -0,0 +1,152 @@
+From b7249b8a036200cd461d0676a330b865f7309231 Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Tue, 31 Mar 2020 18:43:55 +0200
+Subject: [PATCH] image: Use constants for 'required' and 'key-name-hint'
+
+These are used in multiple places so update them to use a shared #define.
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ common/image-fit.c | 6 +++---
+ common/image-sig.c | 8 +++++---
+ include/image.h | 4 +++-
+ lib/rsa/rsa-sign.c | 6 +++---
+ tools/image-host.c | 6 +++---
+ 5 files changed, 17 insertions(+), 13 deletions(-)
+
+diff --git a/common/image-fit.c b/common/image-fit.c
+index 58923cbc9371..b2f41ba408be 100644
+--- a/common/image-fit.c
++++ b/common/image-fit.c
+@@ -166,7 +166,7 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p,
+ int value_len;
+ char *algo;
+ const char *padding;
+- int required;
++ bool required;
+ int ret, i;
+
+ debug("%s %s node: '%s'\n", p, type,
+@@ -177,8 +177,8 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p,
+ return;
+ }
+ printf("%s", algo);
+- keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+- required = fdt_getprop(fit, noffset, "required", NULL) != NULL;
++ keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
++ required = fdt_getprop(fit, noffset, FIT_KEY_REQUIRED, NULL) != NULL;
+ if (keyname)
+ printf(":%s", keyname);
+ if (required)
+diff --git a/common/image-sig.c b/common/image-sig.c
+index 4526c82acf75..e0987af4f5e8 100644
+--- a/common/image-sig.c
++++ b/common/image-sig.c
+@@ -200,7 +200,7 @@ static int fit_image_setup_verify(struct image_sign_info *info,
+ padding_name = RSA_DEFAULT_PADDING_NAME;
+
+ memset(info, '\0', sizeof(*info));
+- info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
++ info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
+ info->fit = (void *)fit;
+ info->node_offset = noffset;
+ info->name = algo_name;
+@@ -311,7 +311,8 @@ int fit_image_verify_required_sigs(const void *fit, int image_noffset,
+ const char *required;
+ int ret;
+
+- required = fdt_getprop(sig_blob, noffset, "required", NULL);
++ required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
++ NULL);
+ if (!required || strcmp(required, "image"))
+ continue;
+ ret = fit_image_verify_sig(fit, image_noffset, data, size,
+@@ -528,7 +529,8 @@ int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
+ const char *required;
+ int ret;
+
+- required = fdt_getprop(sig_blob, noffset, "required", NULL);
++ required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
++ NULL);
+ if (!required || strcmp(required, "conf"))
+ continue;
+ ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
+diff --git a/include/image.h b/include/image.h
+index 4b764d11c70d..afb9bea17c34 100644
+--- a/include/image.h
++++ b/include/image.h
+@@ -903,12 +903,14 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
+ #define FIT_IMAGES_PATH "/images"
+ #define FIT_CONFS_PATH "/configurations"
+
+-/* hash/signature node */
++/* hash/signature/key node */
+ #define FIT_HASH_NODENAME "hash"
+ #define FIT_ALGO_PROP "algo"
+ #define FIT_VALUE_PROP "value"
+ #define FIT_IGNORE_PROP "uboot-ignore"
+ #define FIT_SIG_NODENAME "signature"
++#define FIT_KEY_REQUIRED "required"
++#define FIT_KEY_HINT "key-name-hint"
+
+ /* image node */
+ #define FIT_DATA_PROP "data"
+diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
+index fb5e07b56d8a..5f0f27d2f6f9 100644
+--- a/lib/rsa/rsa-sign.c
++++ b/lib/rsa/rsa-sign.c
+@@ -773,8 +773,8 @@ int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
+ }
+
+ if (!ret) {
+- ret = fdt_setprop_string(keydest, node, "key-name-hint",
+- info->keyname);
++ ret = fdt_setprop_string(keydest, node, FIT_KEY_HINT,
++ info->keyname);
+ }
+ if (!ret)
+ ret = fdt_setprop_u32(keydest, node, "rsa,num-bits", bits);
+@@ -796,7 +796,7 @@ int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
+ info->name);
+ }
+ if (!ret && info->require_keys) {
+- ret = fdt_setprop_string(keydest, node, "required",
++ ret = fdt_setprop_string(keydest, node, FIT_KEY_REQUIRED,
+ info->require_keys);
+ }
+ done:
+diff --git a/tools/image-host.c b/tools/image-host.c
+index 28474bc7fc8b..3396d8234e52 100644
+--- a/tools/image-host.c
++++ b/tools/image-host.c
+@@ -170,7 +170,7 @@ static int fit_image_setup_sig(struct image_sign_info *info,
+
+ memset(info, '\0', sizeof(*info));
+ info->keydir = keydir;
+- info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
++ info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
+ info->fit = fit;
+ info->node_offset = noffset;
+ info->name = strdup(algo_name);
+@@ -249,7 +249,7 @@ static int fit_image_process_sig(const char *keydir, void *keydest,
+ free(value);
+
+ /* Get keyname again, as FDT has changed and invalidated our pointer */
+- info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
++ info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
+
+ /*
+ * Write the public key into the supplied FDT file; this might fail
+@@ -630,7 +630,7 @@ static int fit_config_process_sig(const char *keydir, void *keydest,
+ free(region_prop);
+
+ /* Get keyname again, as FDT has changed and invalidated our pointer */
+- info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
++ info.keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
+
+ /* Write the public key into the supplied FDT file */
+ if (keydest) {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27097/0001-image-Adjust-the-workings-of-fit_check_format.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27097/0001-image-Adjust-the-workings-of-fit_check_format.patch
new file mode 100644
index 000000000..97814024f
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27097/0001-image-Adjust-the-workings-of-fit_check_format.patch
@@ -0,0 +1,397 @@
+From d676a491fb465f11271c47185f1eb3e479c5c738 Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Mon, 15 Feb 2021 17:08:09 -0700
+Subject: [PATCH] image: Adjust the workings of fit_check_format()
+
+At present this function does not accept a size for the FIT. This means
+that it must be read from the FIT itself, introducing potential security
+risk. Update the function to include a size parameter, which can be
+invalid, in which case fit_check_format() calculates it.
+
+For now no callers pass the size, but this can be updated later.
+
+Also adjust the return value to an error code so that all the different
+types of problems can be distinguished by the user.
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+Reported-by: Bruce Monroe <bruce.monroe@intel.com>
+Reported-by: Arie Haenel <arie.haenel@intel.com>
+Reported-by: Julien Lenoir <julien.lenoir@intel.com>
+---
+ arch/arm/cpu/armv8/sec_firmware.c | 2 +-
+ cmd/bootm.c | 6 ++--
+ cmd/disk.c | 2 +-
+ cmd/fdc.c | 2 +-
+ cmd/fpga.c | 2 +-
+ cmd/nand.c | 2 +-
+ cmd/source.c | 2 +-
+ cmd/ximg.c | 2 +-
+ common/image-fdt.c | 2 +-
+ common/image-fit.c | 45 +++++++++++++-----------------
+ common/splash_source.c | 4 +--
+ common/update.c | 2 +-
+ drivers/net/fsl-mc/mc.c | 2 +-
+ drivers/net/pfe_eth/pfe_firmware.c | 2 +-
+ include/image.h | 21 +++++++++++++-
+ tools/fit_common.c | 3 +-
+ tools/fit_image.c | 2 +-
+ tools/mkimage.h | 2 ++
+ 18 files changed, 61 insertions(+), 44 deletions(-)
+
+diff --git a/arch/arm/cpu/armv8/sec_firmware.c b/arch/arm/cpu/armv8/sec_firmware.c
+index 8dc0ac92668f..3c5249541222 100644
+--- a/arch/arm/cpu/armv8/sec_firmware.c
++++ b/arch/arm/cpu/armv8/sec_firmware.c
+@@ -310,7 +310,7 @@ __weak bool sec_firmware_is_valid(const void *sec_firmware_img)
+ return false;
+ }
+
+- if (!fit_check_format(sec_firmware_img)) {
++ if (fit_check_format(sec_firmware_img, IMAGE_SIZE_INVAL)) {
+ printf("SEC Firmware: Bad firmware image (bad FIT header)\n");
+ return false;
+ }
+diff --git a/cmd/bootm.c b/cmd/bootm.c
+index c3a063474ac6..1d6ec0d4cacc 100644
+--- a/cmd/bootm.c
++++ b/cmd/bootm.c
+@@ -282,7 +282,7 @@ static int image_info(ulong addr)
+ case IMAGE_FORMAT_FIT:
+ puts(" FIT image found\n");
+
+- if (!fit_check_format(hdr)) {
++ if (fit_check_format(hdr, IMAGE_SIZE_INVAL)) {
+ puts("Bad FIT image format!\n");
+ return 1;
+ }
+@@ -355,7 +355,7 @@ static int do_imls_nor(void)
+ #endif
+ #if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+- if (!fit_check_format(hdr))
++ if (fit_check_format(hdr), IMAGE_SIZE_INVAL)
+ goto next_sector;
+
+ printf("FIT Image at %08lX:\n", (ulong)hdr);
+@@ -435,7 +435,7 @@ static int nand_imls_fitimage(struct mtd_info *mtd, int nand_dev, loff_t off,
+ return ret;
+ }
+
+- if (!fit_check_format(imgdata)) {
++ if (fit_check_format(imgdata), IMAGE_SIZE_INVAL) {
+ free(imgdata);
+ return 0;
+ }
+diff --git a/cmd/disk.c b/cmd/disk.c
+index dcc36a6c2cb7..294fc111023a 100644
+--- a/cmd/disk.c
++++ b/cmd/disk.c
+@@ -110,7 +110,7 @@ int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
+ /* This cannot be done earlier,
+ * we need complete FIT image in RAM first */
+ if (genimg_get_format((void *) addr) == IMAGE_FORMAT_FIT) {
+- if (!fit_check_format(fit_hdr)) {
++ if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) {
+ bootstage_error(BOOTSTAGE_ID_IDE_FIT_READ);
+ puts("** Bad FIT image format\n");
+ return 1;
+diff --git a/cmd/fdc.c b/cmd/fdc.c
+index 906845d4049b..37e557a1e7d7 100644
+--- a/cmd/fdc.c
++++ b/cmd/fdc.c
+@@ -730,7 +730,7 @@ int do_fdcboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ #if defined(CONFIG_FIT)
+ /* This cannot be done earlier, we need complete FIT image in RAM first */
+ if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
+- if (!fit_check_format (fit_hdr)) {
++ if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) {
+ puts ("** Bad FIT image format\n");
+ return 1;
+ }
+diff --git a/cmd/fpga.c b/cmd/fpga.c
+index 88a8e3f3186b..9093026ff6ce 100644
+--- a/cmd/fpga.c
++++ b/cmd/fpga.c
+@@ -325,7 +325,7 @@ static int do_fpga_loadmk(cmd_tbl_t *cmdtp, int flag, int argc,
+ return CMD_RET_FAILURE;
+ }
+
+- if (!fit_check_format(fit_hdr)) {
++ if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) {
+ puts("Bad FIT image format\n");
+ return CMD_RET_FAILURE;
+ }
+diff --git a/cmd/nand.c b/cmd/nand.c
+index a22945d144b3..536a11be9605 100644
+--- a/cmd/nand.c
++++ b/cmd/nand.c
+@@ -911,7 +911,7 @@ static int nand_load_image(cmd_tbl_t *cmdtp, struct mtd_info *mtd,
+ #if defined(CONFIG_FIT)
+ /* This cannot be done earlier, we need complete FIT image in RAM first */
+ if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
+- if (!fit_check_format (fit_hdr)) {
++ if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) {
+ bootstage_error(BOOTSTAGE_ID_NAND_FIT_READ);
+ puts ("** Bad FIT image format\n");
+ return 1;
+diff --git a/cmd/source.c b/cmd/source.c
+index 6d98a1cfd32b..897b97057d85 100644
+--- a/cmd/source.c
++++ b/cmd/source.c
+@@ -106,7 +106,7 @@ source (ulong addr, const char *fit_uname)
+ #if defined(CONFIG_FIT)
+ case IMAGE_FORMAT_FIT:
+ fit_hdr = buf;
+- if (!fit_check_format (fit_hdr)) {
++ if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) {
+ puts ("Bad FIT image format\n");
+ return 1;
+ }
+diff --git a/cmd/ximg.c b/cmd/ximg.c
+index 8572a67a0063..51af741c827b 100644
+--- a/cmd/ximg.c
++++ b/cmd/ximg.c
+@@ -131,7 +131,7 @@ do_imgextract(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+ "at %08lx ...\n", uname, addr);
+
+ fit_hdr = (const void *)addr;
+- if (!fit_check_format(fit_hdr)) {
++ if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) {
+ puts("Bad FIT image format\n");
+ return 1;
+ }
+diff --git a/common/image-fdt.c b/common/image-fdt.c
+index 52ada56fc17b..3aa6c427362c 100644
+--- a/common/image-fdt.c
++++ b/common/image-fdt.c
+@@ -394,7 +394,7 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,
+ */
+ #if CONFIG_IS_ENABLED(FIT)
+ /* check FDT blob vs FIT blob */
+- if (fit_check_format(buf)) {
++ if (!fit_check_format(buf, IMAGE_SIZE_INVAL)) {
+ ulong load, len;
+
+ fdt_noffset = boot_get_fdt_fit(images,
+diff --git a/common/image-fit.c b/common/image-fit.c
+index 6894384b47b9..124d8895cffd 100644
+--- a/common/image-fit.c
++++ b/common/image-fit.c
+@@ -8,6 +8,8 @@
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
++#define LOG_CATEGORY LOGC_BOOT
++
+ #ifdef USE_HOSTCC
+ #include "mkimage.h"
+ #include <time.h>
+@@ -1460,46 +1462,39 @@ int fit_image_check_comp(const void *fit, int noffset, uint8_t comp)
+ return (comp == image_comp);
+ }
+
+-/**
+- * fit_check_format - sanity check FIT image format
+- * @fit: pointer to the FIT format image header
+- *
+- * fit_check_format() runs a basic sanity FIT image verification.
+- * Routine checks for mandatory properties, nodes, etc.
+- *
+- * returns:
+- * 1, on success
+- * 0, on failure
+- */
+-int fit_check_format(const void *fit)
++int fit_check_format(const void *fit, ulong size)
+ {
++ int ret;
++
+ /* A FIT image must be a valid FDT */
+- if (fdt_check_header(fit)) {
+- debug("Wrong FIT format: not a flattened device tree\n");
+- return 0;
++ ret = fdt_check_header(fit);
++ if (ret) {
++ log_debug("Wrong FIT format: not a flattened device tree (err=%d)\n",
++ ret);
++ return -ENOEXEC;
+ }
+
+ /* mandatory / node 'description' property */
+- if (fdt_getprop(fit, 0, FIT_DESC_PROP, NULL) == NULL) {
+- debug("Wrong FIT format: no description\n");
+- return 0;
++ if (!fdt_getprop(fit, 0, FIT_DESC_PROP, NULL)) {
++ log_debug("Wrong FIT format: no description\n");
++ return -ENOMSG;
+ }
+
+ if (IMAGE_ENABLE_TIMESTAMP) {
+ /* mandatory / node 'timestamp' property */
+- if (fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL) == NULL) {
+- debug("Wrong FIT format: no timestamp\n");
+- return 0;
++ if (!fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL)) {
++ log_debug("Wrong FIT format: no timestamp\n");
++ return -ENODATA;
+ }
+ }
+
+ /* mandatory subimages parent '/images' node */
+ if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) {
+- debug("Wrong FIT format: no images parent node\n");
+- return 0;
++ log_debug("Wrong FIT format: no images parent node\n");
++ return -ENOENT;
+ }
+
+- return 1;
++ return 0;
+ }
+
+
+@@ -1813,7 +1808,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
+ printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
+
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT);
+- if (!fit_check_format(fit)) {
++ if (fit_check_format(fit, IMAGE_SIZE_INVAL)) {
+ printf("Bad FIT %s image format!\n", prop_name);
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT);
+ return -ENOEXEC;
+diff --git a/common/splash_source.c b/common/splash_source.c
+index 62763b9ebd56..d43dd0b2cd98 100644
+--- a/common/splash_source.c
++++ b/common/splash_source.c
+@@ -329,8 +329,8 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
+ if (res < 0)
+ return res;
+
+- res = fit_check_format(fit_header);
+- if (!res) {
++ res = fit_check_format(fit_header, IMAGE_SIZE_INVAL);
++ if (res) {
+ debug("Could not find valid FIT image\n");
+ return -EINVAL;
+ }
+diff --git a/common/update.c b/common/update.c
+index f237ea53bb2a..42950edbbf22 100644
+--- a/common/update.c
++++ b/common/update.c
+@@ -280,7 +280,7 @@ int update_tftp(ulong addr, char *interface, char *devstring)
+ got_update_file:
+ fit = (void *)addr;
+
+- if (!fit_check_format((void *)fit)) {
++ if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
+ printf("Bad FIT format of the update file, aborting "
+ "auto-update\n");
+ return 1;
+diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c
+index cc59b21f9f48..c4f35e7325b2 100644
+--- a/drivers/net/fsl-mc/mc.c
++++ b/drivers/net/fsl-mc/mc.c
+@@ -130,7 +130,7 @@ int parse_mc_firmware_fit_image(u64 mc_fw_addr,
+ return -EINVAL;
+ }
+
+- if (!fit_check_format(fit_hdr)) {
++ if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) {
+ printf("fsl-mc: ERR: Bad firmware image (bad FIT header)\n");
+ return -EINVAL;
+ }
+diff --git a/drivers/net/pfe_eth/pfe_firmware.c b/drivers/net/pfe_eth/pfe_firmware.c
+index adb2d06010ce..7b930ecc2a02 100644
+--- a/drivers/net/pfe_eth/pfe_firmware.c
++++ b/drivers/net/pfe_eth/pfe_firmware.c
+@@ -150,7 +150,7 @@ static int pfe_fit_check(void)
+ return ret;
+ }
+
+- if (!fit_check_format(pfe_fit_addr)) {
++ if (fit_check_format(pfe_fit_addr, IMAGE_SIZE_INVAL)) {
+ printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
+ ret = -1;
+ return ret;
+diff --git a/include/image.h b/include/image.h
+index ea4c05ca2586..b73f739c1585 100644
+--- a/include/image.h
++++ b/include/image.h
+@@ -453,6 +453,9 @@ extern bootm_headers_t images;
+ #define uimage_to_cpu(x) be32_to_cpu(x)
+ #define cpu_to_uimage(x) cpu_to_be32(x)
+
++/* An invalid size, meaning that the image size is not known */
++#define IMAGE_SIZE_INVAL (-1UL)
++
+ /*
+ * Translation table for entries of a specific type; used by
+ * get_table_entry_id() and get_table_entry_name().
+@@ -1062,7 +1065,23 @@ int fit_image_check_os(const void *fit, int noffset, uint8_t os);
+ int fit_image_check_arch(const void *fit, int noffset, uint8_t arch);
+ int fit_image_check_type(const void *fit, int noffset, uint8_t type);
+ int fit_image_check_comp(const void *fit, int noffset, uint8_t comp);
+-int fit_check_format(const void *fit);
++
++/**
++ * fit_check_format() - Check that the FIT is valid
++ *
++ * This performs various checks on the FIT to make sure it is suitable for
++ * use, looking for mandatory properties, nodes, etc.
++ *
++ * If FIT_FULL_CHECK is enabled, it also runs it through libfdt to make
++ * sure that there are no strange tags or broken nodes in the FIT.
++ *
++ * @fit: pointer to the FIT format image header
++ * @return 0 if OK, -ENOEXEC if not an FDT file, -EINVAL if the full FDT check
++ * failed (e.g. due to bad structure), -ENOMSG if the description is
++ * missing, -ENODATA if the timestamp is missing, -ENOENT if the /images
++ * path is missing
++ */
++int fit_check_format(const void *fit, ulong size);
+
+ int fit_conf_find_compat(const void *fit, const void *fdt);
+
+diff --git a/tools/fit_common.c b/tools/fit_common.c
+index 9506390214ce..5e85ca221ac9 100644
+--- a/tools/fit_common.c
++++ b/tools/fit_common.c
+@@ -26,7 +26,8 @@
+ int fit_verify_header(unsigned char *ptr, int image_size,
+ struct image_tool_params *params)
+ {
+- if (fdt_check_header(ptr) != EXIT_SUCCESS || !fit_check_format(ptr))
++ if (fdt_check_header(ptr) != EXIT_SUCCESS ||
++ fit_check_format(ptr, IMAGE_SIZE_INVAL))
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+diff --git a/tools/fit_image.c b/tools/fit_image.c
+index 3b867e06564e..21fc11c084c9 100644
+--- a/tools/fit_image.c
++++ b/tools/fit_image.c
+@@ -764,7 +764,7 @@ static int fit_extract_contents(void *ptr, struct image_tool_params *params)
+ /* Indent string is defined in header image.h */
+ p = IMAGE_INDENT_STRING;
+
+- if (!fit_check_format(fit)) {
++ if (fit_check_format(fit, IMAGE_SIZE_INVAL)) {
+ printf("Bad FIT image format\n");
+ return -1;
+ }
+diff --git a/tools/mkimage.h b/tools/mkimage.h
+index 0254af59fbed..d32625f0a234 100644
+--- a/tools/mkimage.h
++++ b/tools/mkimage.h
+@@ -29,6 +29,8 @@
+ #define debug(fmt,args...)
+ #endif /* MKIMAGE_DEBUG */
+
++#define log_debug(fmt, args...) debug(fmt, ##args)
++
+ static inline void *map_sysmem(ulong paddr, unsigned long len)
+ {
+ return (void *)(uintptr_t)paddr;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27097/0002-image-Add-an-option-to-do-a-full-check-of-the-FIT.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27097/0002-image-Add-an-option-to-do-a-full-check-of-the-FIT.patch
new file mode 100644
index 000000000..51d858470
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27097/0002-image-Add-an-option-to-do-a-full-check-of-the-FIT.patch
@@ -0,0 +1,212 @@
+From cf469ab0783da6783f89a8e31c213f19fdf38dba Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Mon, 15 Feb 2021 17:08:10 -0700
+Subject: [PATCH] image: Add an option to do a full check of the FIT
+
+Some strange modifications of the FIT can introduce security risks. Add an
+option to check it thoroughly, using libfdt's fdt_check_full() function.
+
+Enable this by default if signature verification is enabled.
+
+CVE-2021-27097
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+Reported-by: Bruce Monroe <bruce.monroe@intel.com>
+Reported-by: Arie Haenel <arie.haenel@intel.com>
+Reported-by: Julien Lenoir <julien.lenoir@intel.com>
+---
+ Kconfig | 19 ++++++++++++
+ common/image-fit.c | 20 ++++++++++++-
+ include/linux/libfdt.h | 2 ++
+ lib/libfdt/fdt_ro.c | 65 ++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 105 insertions(+), 1 deletion(-)
+
+diff --git a/Kconfig b/Kconfig
+index b62bcdbccf1e..0165ca33c5d1 100644
+--- a/Kconfig
++++ b/Kconfig
+@@ -318,11 +318,21 @@ config FIT_ENABLE_SHA512_SUPPORT
+ SHA512 checksum is a 512-bit (64-byte) hash value used to check that
+ the image contents have not been corrupted.
+
++config FIT_FULL_CHECK
++ bool "Do a full check of the FIT before using it"
++ default y
++ help
++ Enable this do a full check of the FIT to make sure it is valid. This
++ helps to protect against carefully crafted FITs which take advantage
++ of bugs or omissions in the code. This includes a bad structure,
++ multiple root nodes and the like.
++
+ config FIT_SIGNATURE
+ bool "Enable signature verification of FIT uImages"
+ depends on DM
+ select HASH
+ select RSA
++ select FIT_FULL_CHECK
+ help
+ This option enables signature verification of FIT uImages,
+ using a hash signed and verified using RSA. If
+@@ -398,6 +408,14 @@ config SPL_FIT_PRINT
+ help
+ Support printing the content of the fitImage in a verbose manner in SPL.
+
++config SPL_FIT_FULL_CHECK
++ bool "Do a full check of the FIT before using it"
++ help
++ Enable this do a full check of the FIT to make sure it is valid. This
++ helps to protect against carefully crafted FITs which take advantage
++ of bugs or omissions in the code. This includes a bad structure,
++ multiple root nodes and the like.
++
+ config SPL_FIT_SIGNATURE
+ bool "Enable signature verification of FIT firmware within SPL"
+ depends on SPL_DM
+@@ -405,6 +423,7 @@ config SPL_FIT_SIGNATURE
+ select SPL_CRYPTO_SUPPORT
+ select SPL_HASH_SUPPORT
+ select SPL_RSA
++ select SPL_FIT_FULL_CHECK
+
+ config SPL_LOAD_FIT
+ bool "Enable SPL loading U-Boot as a FIT"
+diff --git a/common/image-fit.c b/common/image-fit.c
+index 124d8895cffd..b1926d8b53f8 100644
+--- a/common/image-fit.c
++++ b/common/image-fit.c
+@@ -15,7 +15,6 @@
+ #include <time.h>
+ #else
+ #include <linux/compiler.h>
+-#include <linux/kconfig.h>
+ #include <common.h>
+ #include <errno.h>
+ #include <mapmem.h>
+@@ -26,12 +25,15 @@ DECLARE_GLOBAL_DATA_PTR;
+
+ #include <image.h>
+ #include <bootstage.h>
++#include <linux/kconfig.h>
+ #include <u-boot/crc.h>
+ #include <u-boot/md5.h>
+ #include <u-boot/sha1.h>
+ #include <u-boot/sha256.h>
+ #include <u-boot/sha512.h>
+
++#define log_debug(fmt, args...) debug(fmt, ##args)
++
+ /*****************************************************************************/
+ /* New uImage format routines */
+ /*****************************************************************************/
+@@ -1487,6 +1489,22 @@ int fit_check_format(const void *fit, ulong size)
+ return -ENODATA;
+ }
+ }
++
++ if (CONFIG_IS_ENABLED(FIT_FULL_CHECK)) {
++ /*
++ * If we are not given the size, make do wtih calculating it.
++ * This is not as secure, so we should consider a flag to
++ * control this.
++ */
++ if (size == IMAGE_SIZE_INVAL)
++ size = fdt_totalsize(fit);
++ ret = fdt_check_full(fit, size);
++
++ if (ret) {
++ log_debug("FIT check error %d\n", ret);
++ return -EINVAL;
++ }
++ }
+
+ /* mandatory subimages parent '/images' node */
+ if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) {
+diff --git a/include/linux/libfdt.h b/include/linux/libfdt.h
+index eeb2344971f3..29c997ada398 100644
+--- a/include/linux/libfdt.h
++++ b/include/linux/libfdt.h
+@@ -305,6 +305,8 @@ int fdt_next_region(const void *fdt,
+ */
+ int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+ int max_regions, struct fdt_region_state *info);
++
++int fdt_check_full(const void *fdt, size_t bufsize);
+ #endif /* SWIG */
+
+ extern struct fdt_header *working_fdt; /* Pointer to the working fdt */
+diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c
+index b6ca4e0b0c30..dfbeb2c21a85 100644
+--- a/lib/libfdt/fdt_ro.c
++++ b/lib/libfdt/fdt_ro.c
+@@ -680,3 +680,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+
+ return offset; /* error from fdt_next_node() */
+ }
++
++#define INT_MAX ((int)(~0U>>1))
++
++int fdt_check_full(const void *fdt, size_t bufsize)
++{
++ int err;
++ int num_memrsv;
++ int offset, nextoffset = 0;
++ uint32_t tag;
++ unsigned depth = 0;
++ const void *prop;
++ const char *propname;
++
++ if (bufsize < FDT_V1_SIZE)
++ return -FDT_ERR_TRUNCATED;
++ err = fdt_check_header(fdt);
++ if (err != 0)
++ return err;
++ if (bufsize < fdt_totalsize(fdt))
++ return -FDT_ERR_TRUNCATED;
++
++ num_memrsv = fdt_num_mem_rsv(fdt);
++ if (num_memrsv < 0)
++ return num_memrsv;
++
++ while (1) {
++ offset = nextoffset;
++ tag = fdt_next_tag(fdt, offset, &nextoffset);
++
++ if (nextoffset < 0)
++ return nextoffset;
++
++ switch (tag) {
++ case FDT_NOP:
++ break;
++
++ case FDT_END:
++ if (depth != 0)
++ return -FDT_ERR_BADSTRUCTURE;
++ return 0;
++
++ case FDT_BEGIN_NODE:
++ depth++;
++ if (depth > INT_MAX)
++ return -FDT_ERR_BADSTRUCTURE;
++ break;
++
++ case FDT_END_NODE:
++ if (depth == 0)
++ return -FDT_ERR_BADSTRUCTURE;
++ depth--;
++ break;
++
++ case FDT_PROP:
++ prop = fdt_getprop_by_offset(fdt, offset, &propname,
++ &err);
++ if (!prop)
++ return err;
++ break;
++
++ default:
++ return -FDT_ERR_INTERNAL;
++ }
++ }
++}
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27138/0001-image-Check-for-unit-addresses-in-FITs.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27138/0001-image-Check-for-unit-addresses-in-FITs.patch
new file mode 100644
index 000000000..33dbf15be
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/CVE-2021-27138/0001-image-Check-for-unit-addresses-in-FITs.patch
@@ -0,0 +1,106 @@
+From dbfcf0735d5f4d27445176f72e6174edf064c118 Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Mon, 15 Feb 2021 17:08:12 -0700
+Subject: [PATCH] image: Check for unit addresses in FITs
+
+Using unit addresses in a FIT is a security risk. Add a check for this
+and disallow it.
+
+CVE-2021-27138
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+Reported-by: Bruce Monroe <bruce.monroe@intel.com>
+Reported-by: Arie Haenel <arie.haenel@intel.com>
+Reported-by: Julien Lenoir <julien.lenoir@intel.com>
+---
+ common/image-fit.c | 56 ++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 52 insertions(+), 4 deletions(-)
+
+diff --git a/common/image-fit.c b/common/image-fit.c
+index 78db32e89f6f..6c495ffa4349 100644
+--- a/common/image-fit.c
++++ b/common/image-fit.c
+@@ -1217,6 +1217,34 @@ int fit_image_check_comp(const void *fit, int noffset, uint8_t comp)
+ return (comp == image_comp);
+ }
+
++/**
++ * fdt_check_no_at() - Check for nodes whose names contain '@'
++ *
++ * This checks the parent node and all subnodes recursively
++ *
++ * @fit: FIT to check
++ * @parent: Parent node to check
++ * @return 0 if OK, -EADDRNOTAVAIL is a node has a name containing '@'
++ */
++static int fdt_check_no_at(const void *fit, int parent)
++{
++ const char *name;
++ int node;
++ int ret;
++
++ name = fdt_get_name(fit, parent, NULL);
++ if (!name || strchr(name, '@'))
++ return -EADDRNOTAVAIL;
++
++ fdt_for_each_subnode(node, fit, parent) {
++ ret = fdt_check_no_at(fit, node);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
+ int fit_check_format(const void *fit, ulong size)
+ {
+ int ret;
+@@ -1251,10 +1279,27 @@ int fit_check_format(const void *fit, ulong size)
+ if (size == IMAGE_SIZE_INVAL)
+ size = fdt_totalsize(fit);
+ ret = fdt_check_full(fit, size);
++ if (ret)
++ ret = -EINVAL;
++
++ /*
++ * U-Boot stopped using unit addressed in 2017. Since libfdt
++ * can match nodes ignoring any unit address, signature
++ * verification can see the wrong node if one is inserted with
++ * the same name as a valid node but with a unit address
++ * attached. Protect against this by disallowing unit addresses.
++ */
++ if (!ret && CONFIG_IS_ENABLED(FIT_SIGNATURE)) {
++ ret = fdt_check_no_at(fit, 0);
+
++ if (ret) {
++ log_debug("FIT check error %d\n", ret);
++ return ret;
++ }
++ }
+ if (ret) {
+ log_debug("FIT check error %d\n", ret);
+- return -EINVAL;
++ return ret;
+ }
+ }
+
+@@ -1604,10 +1649,13 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
+ printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
+
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT);
+- if (fit_check_format(fit, IMAGE_SIZE_INVAL)) {
+- printf("Bad FIT %s image format!\n", prop_name);
++ ret = fit_check_format(fit, IMAGE_SIZE_INVAL);
++ if (ret) {
++ printf("Bad FIT %s image format! (err=%d)\n", prop_name, ret);
++ if (CONFIG_IS_ENABLED(FIT_SIGNATURE) && ret == -EADDRNOTAVAIL)
++ printf("Signature checking prevents use of unit addresses (@) in nodes\n");
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT);
+- return -ENOEXEC;
++ return ret;
+ }
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK);
+ if (fit_uname) {
+--
+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
new file mode 100644
index 000000000..7d64f1584
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/intel.cfg
@@ -0,0 +1,37 @@
+CONFIG_MISC_INIT_R=y
+CONFIG_LED=y
+CONFIG_LED_BLINK=y
+CONFIG_LED_GPIO=y
+CONFIG_CMD_LED=y
+CONFIG_TARGET_AST2600_INTEL=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_BOARD_EARLY_INIT_R=y
+CONFIG_SYS_ARCH_TIMER=y
+CONFIG_USE_IRQ=y
+CONFIG_CMD_IRQ=y
+CONFIG_ENV_SIZE=0x10000
+CONFIG_ENV_OFFSET=0x2400000
+CONFIG_BOARD_LATE_INIT=y
+CONFIG_DM_PWM=y
+CONFIG_PWM_ASPEED=y
+CONFIG_TARGET_EVB_AST2600A1=n
+CONFIG_PHY_NCSI=n
+CONFIG_CMD_USB=n
+CONFIG_CMD_EXT4=n
+CONFIG_CMD_EXT4_WRITE=n
+CONFIG_CMD_FAT=n
+CONFIG_CMD_FS_GENERIC=n
+CONFIG_CMD_MTDPARTS=n
+CONFIG_EFI_PARTITION=n
+CONFIG_EFI_LOADER=n
+CONFIG_USB=n
+CONFIG_DM_USB=n
+CONFIG_USB_EHCI_HCD=n
+CONFIG_USB_STORAGE=n
+CONFIG_NETCONSOLE=n
+CONFIG_CMD_NFS=n
+CONFIG_POSITION_INDEPENDENT=n
+CONFIG_SYS_TEXT_BASE=0x0
+CONFIG_SPL=n
+CONFIG_ASPEED_DP=n
+CONFIG_PHY_BROADCOM=n \ No newline at end of file
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
new file mode 100644
index 000000000..1e20585bc
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend
@@ -0,0 +1,114 @@
+COMPATIBLE_MACHINE = "intel-ast2600"
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files:"
+
+# the meta-phosphor layer adds this patch, which conflicts
+# with the intel layout for environment
+
+SRC_URI:append:intel-ast2600 = " \
+ file://intel.cfg \
+ file://0001-Add-ast2600-intel-as-a-new-board.patch \
+ file://0002-AST2600-Enable-host-searial-port-clock-configuration.patch \
+ file://0003-ast2600-intel-layout-environment-addr.patch \
+ file://0004-AST2600-Adjust-default-GPIO-settings.patch \
+ file://0005-Ast2600-Enable-interrupt-in-u-boot.patch \
+ file://0006-SPI-Quad-IO-Mode.patch \
+ 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 \
+ file://0015-net-phy-realtek-Change-LED-configuration.patch \
+ file://0016-Add-system-reset-status-support.patch \
+ file://0016-Add-LED-control-support.patch \
+ file://0017-Manufacturing-mode-physical-presence-detection.patch \
+ file://0018-Add-a-workaround-to-cover-VGA-memory-size-bug-in-A0.patch \
+ file://0019-Apply-WDT1-2-reset-mask-to-reset-needed-controller.patch \
+ file://0022-Reboot-into-UBOOT-on-Watchdog-Failures.patch \
+ file://0023-Add-WDT-to-u-boot-to-cover-booting-failures.patch \
+ file://0024-fix-SUS_WARN-handling-logic.patch \
+ file://0025-ast2600-PFR-platform-EXTRST-reset-mask-selection.patch \
+ file://0026-Enable-PCIe-L1-support.patch \
+ file://0027-ast2600-Add-Mailbox-init-function.patch \
+ file://0028-Improve-randomness-of-mac-address-generation.patch \
+ file://0029-Set-UART-routing-in-lowlevel_init.patch \
+ file://0030-Add-Aspeed-PWM-uclass-driver.patch \
+ file://0031-Add-a-workaround-to-fix-AST2600-A0-booting-issue.patch \
+ file://0032-Disable-eSPI-initialization-in-u-boot-for-normal-boo.patch \
+ file://0033-Disable-debug-interfaces.patch \
+ file://0034-Implement-the-IPMI-commands-in-FFUJ-mode-in-u-boot.patch \
+ file://0036-Disable-BMC-MMIO-Decode-on-VGA-SCU-register-bit.patch \
+ file://0037-Enable-I2C-clock-stretching-and-multi-master-support.patch \
+ "
+
+# CVE-2020-10648 vulnerability fix
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files/CVE-2020-10648:"
+SRC_URI:append:intel-ast2600 = " \
+ file://0001-image-Correct-comment-for-fit_conf_get_node.patch \
+ file://0008-image-Load-the-correct-configuration-in-fit_check_si.patch \
+ file://0009-fit_check_sign-Allow-selecting-the-configuration-to-.patch \
+ file://0012-image-Use-constants-for-required-and-key-name-hint.patch \
+ "
+
+# CVE-2019-11059 vulnerability fix
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files/CVE-2019-11059:"
+SRC_URI:append:intel-ast2600 = " \
+ file://0001-Fix-ext4-block-group-descriptor-sizing.patch \
+ "
+
+# CVE-2019-11690 vulnerability fix
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files/CVE-2019-11690:"
+SRC_URI:append:intel-ast2600 = " \
+ file://0001-lib-uuid-Fix-unseeded-PRNG-on-RANDOM_UUID-y.patch \
+ "
+
+# CVE-2019-13105 vulnerability fix
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files/CVE-2019-13105:"
+SRC_URI:append:intel-ast2600 = " \
+ file://0001-fs-ext4-cache-extent-data.patch \
+ file://0002-CVE-2019-13105-ext4-fix-double-free-in-ext4_cache_re.patch \
+ "
+
+# CVE-2019-13104 vulnerability fix
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files/CVE-2019-13104:"
+SRC_URI:append:intel-ast2600 = " \
+ file://0001-CVE-2019-13104-ext4-check-for-underflow-in-ext4fs_re.patch \
+ "
+
+# CVE-2019-13106 vulnerability fix
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files/CVE-2019-13106:"
+SRC_URI:append:intel-ast2600 = " \
+ file://0001-CVE-2019-13106-ext4-fix-out-of-bounds-memset.patch \
+ "
+
+# CVE-2021-27097 vulnerability fix
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files/CVE-2021-27097:"
+SRC_URI:append:intel-ast2600 = " \
+ file://0001-image-Adjust-the-workings-of-fit_check_format.patch \
+ file://0002-image-Add-an-option-to-do-a-full-check-of-the-FIT.patch \
+ "
+
+# CVE-2021-27138 vulnerability fix
+FILESEXTRAPATHS:append:intel-ast2600:= "${THISDIR}/files/CVE-2021-27138:"
+SRC_URI:append:intel-ast2600 = " \
+ file://0001-image-Check-for-unit-addresses-in-FITs.patch \
+ "
+
+PFR_SRC_URI = " \
+ file://0043-AST2600-PFR-u-boot-env-changes-as-per-PFR-BMC-image.patch \
+ "
+
+AUTOBOOT_SRC_URI = " \
+ file://0035-Remove-u-boot-delay-before-autoboot-in-release-image.patch \
+ "
+
+SRC_URI:append:intel-ast2600 += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', PFR_SRC_URI, '', d)}"
+SRC_URI:append:intel-ast2600 += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', AUTOBOOT_SRC_URI, d)}"
+
+do_install:append () {
+ install -m 0644 ${WORKDIR}/fw_env.config ${D}${sysconfdir}/fw_env.config
+ install -m 0644 ${WORKDIR}/fw_env.config ${S}/tools/env/fw_env.config
+}
+RDEPENDS:${PN} = "udev-aspeed-mtd-partitions"
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-fw-utils-aspeed-sdk_%.bbappend b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-fw-utils-aspeed-sdk_%.bbappend
new file mode 120000
index 000000000..c73fd75cc
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/u-boot-fw-utils-aspeed-sdk_%.bbappend
@@ -0,0 +1 @@
+u-boot-aspeed-sdk_%.bbappend \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-graphics/obmc-ikvm/obmc-ikvm/0001-Enable-per-frame-CRC-calculation-option-to-save-netw.patch b/meta-openbmc-mods/meta-ast2600/recipes-graphics/obmc-ikvm/obmc-ikvm/0001-Enable-per-frame-CRC-calculation-option-to-save-netw.patch
new file mode 100644
index 000000000..459d0dddc
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-graphics/obmc-ikvm/obmc-ikvm/0001-Enable-per-frame-CRC-calculation-option-to-save-netw.patch
@@ -0,0 +1,30 @@
+From fa81ec28629d59b8bad623ff8d3285162671d45a Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 21 Jul 2021 13:03:22 -0700
+Subject: [PATCH] Enable per-frame CRC calculation option to save network
+ bandwidth
+
+This commit enables per-frame CRC calculation option to save network
+bandwidth by dropping off frames that don't have changes.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ start-ipkvm.service | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/start-ipkvm.service b/start-ipkvm.service
+index 60234b231da3..10e424845599 100644
+--- a/start-ipkvm.service
++++ b/start-ipkvm.service
+@@ -5,7 +5,7 @@ ConditionPathIsMountPoint=/sys/kernel/config
+ [Service]
+ Restart=always
+ ExecStartPre=/usr/bin/create_usbhid.sh disconnect
+-ExecStart=/usr/bin/obmc-ikvm -v /dev/video0 -k /dev/hidg0 -p /dev/hidg1
++ExecStart=/usr/bin/obmc-ikvm -c -v /dev/video0 -k /dev/hidg0 -p /dev/hidg1
+
+ [Install]
+ WantedBy=multi-user.target
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend b/meta-openbmc-mods/meta-ast2600/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend
new file mode 100644
index 000000000..85e3ffc26
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS:append := ":${THISDIR}/${PN}"
+
+SRC_URI += " \
+ file://0001-Enable-per-frame-CRC-calculation-option-to-save-netw.patch \
+ "
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0001-serial-8250-Add-Aspeed-UART-driver-with-DMA-supporte.patch b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0001-serial-8250-Add-Aspeed-UART-driver-with-DMA-supporte.patch
new file mode 100644
index 000000000..525b910d0
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0001-serial-8250-Add-Aspeed-UART-driver-with-DMA-supporte.patch
@@ -0,0 +1,1184 @@
+From a4897aed25195742ec9fd992a52a6e7bf872f318 Mon Sep 17 00:00:00 2001
+From: "Chia-Wei, Wang" <chiawei_wang@aspeedtech.com>
+Date: Wed, 22 Jul 2020 13:46:21 +0800
+Subject: [PATCH] serial: 8250: Add Aspeed UART driver with DMA supported
+
+This patch adds drivers for Aspeed UARTs, which are 16550A compatible.
+The drivers includes an wrapper to support the extended DMA feature of
+UART devices and another UDMA driver to control the UART DMA engine.
+
+Signed-off-by: Chia-Wei, Wang <chiawei_wang@aspeedtech.com>
+---
+ arch/arm/boot/dts/aspeed-ast2600-evb.dts | 5 -
+ .../arm/boot/dts/aspeed-bmc-intel-ast2600.dts | 2 -
+ arch/arm/boot/dts/aspeed-g6.dtsi | 28 +-
+ drivers/soc/aspeed/Kconfig | 8 +
+ drivers/soc/aspeed/Makefile | 1 +
+ drivers/soc/aspeed/aspeed-udma.c | 441 ++++++++++++++++
+ drivers/tty/serial/8250/8250_aspeed.c | 494 ++++++++++++++++++
+ drivers/tty/serial/8250/Kconfig | 8 +
+ drivers/tty/serial/8250/Makefile | 1 +
+ include/linux/soc/aspeed/aspeed-udma.h | 30 ++
+ 10 files changed, 997 insertions(+), 21 deletions(-)
+ create mode 100644 drivers/soc/aspeed/aspeed-udma.c
+ create mode 100644 drivers/tty/serial/8250/8250_aspeed.c
+ create mode 100644 include/linux/soc/aspeed/aspeed-udma.h
+
+diff --git a/arch/arm/boot/dts/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed-ast2600-evb.dts
+index acbd1c947465..913749205c1d 100644
+--- a/arch/arm/boot/dts/aspeed-ast2600-evb.dts
++++ b/arch/arm/boot/dts/aspeed-ast2600-evb.dts
+@@ -180,11 +180,6 @@
+ };
+ };
+
+-&uart5 {
+- // Workaround for A0
+- compatible = "snps,dw-apb-uart";
+-};
+-
+ &i2c0 {
+ status = "okay";
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
+index 02c837c3e2c4..210d2bbdf836 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
+@@ -427,8 +427,6 @@
+
+ &uart5 {
+ status = "okay";
+- // Workaround for A0
+- compatible = "snps,dw-apb-uart";
+ };
+
+ &uart_routing {
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index e76dfb73430e..001ecf9ad33c 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -524,23 +524,22 @@
+ };
+
+ uart1: serial@1e783000 {
+- compatible = "ns16550a";
++ compatible = "aspeed,ast2600-uart";
+ reg = <0x1e783000 0x20>;
+- reg-shift = <2>;
+- reg-io-width = <4>;
+ interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>;
+ resets = <&lpc_reset 4>;
+ no-loopback-test;
++ dma-mode;
++ dma-channel = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd1_default &pinctrl_rxd1_default>;
+ status = "disabled";
+ };
+
+ uart5: serial@1e784000 {
+- compatible = "ns16550a";
++ compatible = "aspeed,ast2600-uart";
+ reg = <0x1e784000 0x1000>;
+- reg-shift = <2>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART5CLK>;
+ no-loopback-test;
+@@ -754,10 +753,8 @@
+ };
+
+ uart2: serial@1e78d000 {
+- compatible = "ns16550a";
++ compatible = "aspeed,ast2600-uart";
+ reg = <0x1e78d000 0x20>;
+- reg-shift = <2>;
+- reg-io-width = <4>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART2CLK>;
+ resets = <&lpc_reset 5>;
+@@ -768,10 +765,8 @@
+ };
+
+ uart3: serial@1e78e000 {
+- compatible = "ns16550a";
++ compatible = "aspeed,ast2600-uart";
+ reg = <0x1e78e000 0x20>;
+- reg-shift = <2>;
+- reg-io-width = <4>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART3CLK>;
+ resets = <&lpc_reset 6>;
+@@ -782,10 +777,8 @@
+ };
+
+ uart4: serial@1e78f000 {
+- compatible = "ns16550a";
++ compatible = "aspeed,ast2600-uart";
+ reg = <0x1e78f000 0x20>;
+- reg-shift = <2>;
+- reg-io-width = <4>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART4CLK>;
+ resets = <&lpc_reset 7>;
+@@ -834,6 +827,13 @@
+ clocks = <&syscon ASPEED_CLK_GATE_FSICLK>;
+ status = "disabled";
+ };
++
++ udma: uart-dma@1e79e000 {
++ compatible = "aspeed,ast2600-udma";
++ reg = <0x1e79e000 0x400>;
++ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
+ };
+ };
+ };
+diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
+index d36ee43451a5..ca284ac2f0ab 100644
+--- a/drivers/soc/aspeed/Kconfig
++++ b/drivers/soc/aspeed/Kconfig
+@@ -90,6 +90,14 @@ config ASPEED_XDMA
+ SoCs. The XDMA engine can perform PCIe DMA operations between the BMC
+ and a host processor.
+
++config ASPEED_UDMA
++ tristate "Aspeed UDMA Engine Driver"
++ depends on SOC_ASPEED && REGMAP && MFD_SYSCON && HAS_DMA
++ help
++ Enable support for the Aspeed UDMA Engine found on the Aspeed AST2XXX
++ SOCs. The UDMA engine can perform UART DMA operations between the memory
++ buffer and the UART/VUART devices.
++
+ config ASPEED_VGA_SHAREDMEM
+ tristate "Aspeed VGA Shared memory"
+ help
+diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
+index f3afc32b58b9..e6248ecdeee3 100644
+--- a/drivers/soc/aspeed/Makefile
++++ b/drivers/soc/aspeed/Makefile
+@@ -8,5 +8,6 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+ obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
+ obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o
+ obj-$(CONFIG_ASPEED_XDMA) += aspeed-xdma.o
++obj-$(CONFIG_ASPEED_UDMA) += aspeed-udma.o
+ obj-$(CONFIG_ASPEED_VGA_SHAREDMEM) += aspeed-vga-sharedmem.o
+ obj-$(CONFIG_ASPEED_MCTP) += aspeed-mctp.o
+diff --git a/drivers/soc/aspeed/aspeed-udma.c b/drivers/soc/aspeed/aspeed-udma.c
+new file mode 100644
+index 000000000000..01b73ebe1880
+--- /dev/null
++++ b/drivers/soc/aspeed/aspeed-udma.c
+@@ -0,0 +1,441 @@
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/spinlock.h>
++#include <linux/soc/aspeed/aspeed-udma.h>
++
++#define DEVICE_NAME "aspeed-udma"
++
++/* UART DMA registers offset */
++#define UDMA_TX_DMA_EN 0x000
++#define UDMA_RX_DMA_EN 0x004
++#define UDMA_TIMEOUT_TIMER 0x00c
++#define UDMA_TX_DMA_RST 0x020
++#define UDMA_RX_DMA_RST 0x024
++#define UDMA_TX_DMA_INT_EN 0x030
++#define UDMA_TX_DMA_INT_STAT 0x034
++#define UDMA_RX_DMA_INT_EN 0x038
++#define UDMA_RX_DMA_INT_STAT 0x03c
++
++#define UDMA_CHX_OFF(x) ((x) * 0x20)
++#define UDMA_CHX_TX_RD_PTR(x) (0x040 + UDMA_CHX_OFF(x))
++#define UDMA_CHX_TX_WR_PTR(x) (0x044 + UDMA_CHX_OFF(x))
++#define UDMA_CHX_TX_BUF_BASE(x) (0x048 + UDMA_CHX_OFF(x))
++#define UDMA_CHX_TX_CTRL(x) (0x04c + UDMA_CHX_OFF(x))
++#define UDMA_TX_CTRL_TMOUT_DISABLE BIT(4)
++#define UDMA_TX_CTRL_BUFSZ_MASK GENMASK(3, 0)
++#define UDMA_TX_CTRL_BUFSZ_SHIFT 0
++#define UDMA_CHX_RX_RD_PTR(x) (0x050 + UDMA_CHX_OFF(x))
++#define UDMA_CHX_RX_WR_PTR(x) (0x054 + UDMA_CHX_OFF(x))
++#define UDMA_CHX_RX_BUF_BASE(x) (0x058 + UDMA_CHX_OFF(x))
++#define UDMA_CHX_RX_CTRL(x) (0x05c + UDMA_CHX_OFF(x))
++#define UDMA_RX_CTRL_TMOUT_DISABLE BIT(4)
++#define UDMA_RX_CTRL_BUFSZ_MASK GENMASK(3, 0)
++#define UDMA_RX_CTRL_BUFSZ_SHIFT 0
++
++#define UDMA_MAX_CHANNEL 14
++#define UDMA_TIMEOUT 0x200
++
++enum aspeed_udma_bufsz_code {
++ UDMA_BUFSZ_CODE_1KB,
++ UDMA_BUFSZ_CODE_4KB,
++ UDMA_BUFSZ_CODE_16KB,
++ UDMA_BUFSZ_CODE_64KB,
++
++ /*
++ * 128KB and above are supported ONLY for
++ * virtual UARTs. For physical UARTs, the
++ * size code is wrapped around at the 64K
++ * boundary.
++ */
++ UDMA_BUFSZ_CODE_128KB,
++ UDMA_BUFSZ_CODE_256KB,
++ UDMA_BUFSZ_CODE_512KB,
++ UDMA_BUFSZ_CODE_1024KB,
++ UDMA_BUFSZ_CODE_2048KB,
++ UDMA_BUFSZ_CODE_4096KB,
++ UDMA_BUFSZ_CODE_8192KB,
++ UDMA_BUFSZ_CODE_16384KB,
++};
++
++struct aspeed_udma_chan {
++ dma_addr_t dma_addr;
++
++ struct circ_buf *rb;
++ u32 rb_sz;
++
++ aspeed_udma_cb_t cb;
++ void *cb_arg;
++
++ bool dis_tmout;
++};
++
++struct aspeed_udma {
++ struct device *dev;
++ u8 __iomem *regs;
++ u32 irq;
++ struct aspeed_udma_chan tx_chs[UDMA_MAX_CHANNEL];
++ struct aspeed_udma_chan rx_chs[UDMA_MAX_CHANNEL];
++ spinlock_t lock;
++};
++
++struct aspeed_udma udma[1];
++
++static int aspeed_udma_get_bufsz_code(u32 buf_sz)
++{
++ switch (buf_sz) {
++ case 0x400:
++ return UDMA_BUFSZ_CODE_1KB;
++ case 0x1000:
++ return UDMA_BUFSZ_CODE_4KB;
++ case 0x4000:
++ return UDMA_BUFSZ_CODE_16KB;
++ case 0x10000:
++ return UDMA_BUFSZ_CODE_64KB;
++ case 0x20000:
++ return UDMA_BUFSZ_CODE_128KB;
++ case 0x40000:
++ return UDMA_BUFSZ_CODE_256KB;
++ case 0x80000:
++ return UDMA_BUFSZ_CODE_512KB;
++ case 0x100000:
++ return UDMA_BUFSZ_CODE_1024KB;
++ case 0x200000:
++ return UDMA_BUFSZ_CODE_2048KB;
++ case 0x400000:
++ return UDMA_BUFSZ_CODE_4096KB;
++ case 0x800000:
++ return UDMA_BUFSZ_CODE_8192KB;
++ case 0x1000000:
++ return UDMA_BUFSZ_CODE_16384KB;
++ default:
++ return -1;
++ }
++
++ return -1;
++}
++
++static u32 aspeed_udma_get_tx_rptr(u32 ch_no)
++{
++ return readl(udma->regs + UDMA_CHX_TX_RD_PTR(ch_no));
++}
++
++static u32 aspeed_udma_get_rx_wptr(u32 ch_no)
++{
++ return readl(udma->regs + UDMA_CHX_RX_WR_PTR(ch_no));
++}
++
++static void aspeed_udma_set_ptr(u32 ch_no, u32 ptr, bool is_tx)
++{
++ writel(ptr, udma->regs +
++ ((is_tx) ?
++ UDMA_CHX_TX_WR_PTR(ch_no) :
++ UDMA_CHX_RX_RD_PTR(ch_no)));
++}
++
++void aspeed_udma_set_tx_wptr(u32 ch_no, u32 wptr)
++{
++ aspeed_udma_set_ptr(ch_no, wptr, true);
++}
++EXPORT_SYMBOL(aspeed_udma_set_tx_wptr);
++
++void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr)
++{
++ aspeed_udma_set_ptr(ch_no, rptr, false);
++}
++EXPORT_SYMBOL(aspeed_udma_set_rx_rptr);
++
++static int aspeed_udma_free_chan(u32 ch_no, bool is_tx)
++{
++ u32 reg;
++ unsigned long flags;
++
++ if (ch_no > UDMA_MAX_CHANNEL)
++ return -EINVAL;
++
++ spin_lock_irqsave(&udma->lock, flags);
++
++ reg = readl(udma->regs +
++ ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN));
++ reg &= ~(0x1 << ch_no);
++
++ writel(reg, udma->regs +
++ ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN));
++
++ spin_unlock_irqrestore(&udma->lock, flags);
++
++ return 0;
++}
++
++int aspeed_udma_free_tx_chan(u32 ch_no)
++{
++ return aspeed_udma_free_chan(ch_no, true);
++}
++EXPORT_SYMBOL(aspeed_udma_free_tx_chan);
++
++int aspeed_udma_free_rx_chan(u32 ch_no)
++{
++ return aspeed_udma_free_chan(ch_no, false);
++}
++EXPORT_SYMBOL(aspeed_udma_free_rx_chan);
++
++static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr,
++ struct circ_buf *rb, u32 rb_sz,
++ aspeed_udma_cb_t cb, void *id, bool dis_tmout, bool is_tx)
++{
++ int retval = 0;
++ int rbsz_code;
++
++ u32 reg;
++ unsigned long flags;
++ struct aspeed_udma_chan *ch;
++
++ if (ch_no > UDMA_MAX_CHANNEL) {
++ retval = -EINVAL;
++ goto out;
++ }
++
++ if (IS_ERR_OR_NULL(rb) || IS_ERR_OR_NULL(rb->buf)) {
++ retval = -EINVAL;
++ goto out;
++ }
++
++ rbsz_code = aspeed_udma_get_bufsz_code(rb_sz);
++ if (rbsz_code < 0) {
++ retval = -EINVAL;
++ goto out;
++ }
++
++ spin_lock_irqsave(&udma->lock, flags);
++
++ if (is_tx) {
++ reg = readl(udma->regs + UDMA_TX_DMA_INT_EN);
++ if (reg & (0x1 << ch_no)) {
++ retval = -EBUSY;
++ goto unlock_n_out;
++ }
++
++ reg |= (0x1 << ch_no);
++ writel(reg, udma->regs + UDMA_TX_DMA_INT_EN);
++
++ reg = readl(udma->regs + UDMA_CHX_TX_CTRL(ch_no));
++ reg |= (dis_tmout) ? UDMA_TX_CTRL_TMOUT_DISABLE : 0;
++ reg |= (rbsz_code << UDMA_TX_CTRL_BUFSZ_SHIFT) & UDMA_TX_CTRL_BUFSZ_MASK;
++ writel(reg, udma->regs + UDMA_CHX_TX_CTRL(ch_no));
++
++ writel(addr, udma->regs + UDMA_CHX_TX_BUF_BASE(ch_no));
++ }
++ else {
++ reg = readl(udma->regs + UDMA_RX_DMA_INT_EN);
++ if (reg & (0x1 << ch_no)) {
++ retval = -EBUSY;
++ goto unlock_n_out;
++ }
++
++ reg |= (0x1 << ch_no);
++ writel(reg, udma->regs + UDMA_RX_DMA_INT_EN);
++
++ reg = readl(udma->regs + UDMA_CHX_RX_CTRL(ch_no));
++ reg |= (dis_tmout) ? UDMA_RX_CTRL_TMOUT_DISABLE : 0;
++ reg |= (rbsz_code << UDMA_RX_CTRL_BUFSZ_SHIFT) & UDMA_RX_CTRL_BUFSZ_MASK;
++ writel(reg, udma->regs + UDMA_CHX_RX_CTRL(ch_no));
++
++ writel(addr, udma->regs + UDMA_CHX_RX_BUF_BASE(ch_no));
++ }
++
++ ch = (is_tx) ? &udma->tx_chs[ch_no] : &udma->rx_chs[ch_no];
++ ch->rb = rb;
++ ch->rb_sz = rb_sz;
++ ch->cb = cb;
++ ch->cb_arg = id;
++ ch->dma_addr = addr;
++ ch->dis_tmout = dis_tmout;
++
++unlock_n_out:
++ spin_unlock_irqrestore(&udma->lock, flags);
++out:
++ return 0;
++}
++
++int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr,
++ struct circ_buf *rb, u32 rb_sz,
++ aspeed_udma_cb_t cb, void *id, bool dis_tmout)
++{
++ return aspeed_udma_request_chan(ch_no, addr, rb, rb_sz, cb, id,
++ dis_tmout, true);
++}
++EXPORT_SYMBOL(aspeed_udma_request_tx_chan);
++
++int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr,
++ struct circ_buf *rb, u32 rb_sz,
++ aspeed_udma_cb_t cb, void *id, bool dis_tmout)
++{
++ return aspeed_udma_request_chan(ch_no, addr, rb, rb_sz, cb, id,
++ dis_tmout, false);
++}
++EXPORT_SYMBOL(aspeed_udma_request_rx_chan);
++
++static void aspeed_udma_chan_ctrl(u32 ch_no, u32 op, bool is_tx)
++{
++ unsigned long flags;
++ u32 reg_en, reg_rst;
++ u32 reg_en_off = (is_tx) ? UDMA_TX_DMA_EN : UDMA_RX_DMA_EN;
++ u32 reg_rst_off = (is_tx) ? UDMA_TX_DMA_RST : UDMA_TX_DMA_RST;
++
++ if (ch_no > UDMA_MAX_CHANNEL)
++ return;
++
++ spin_lock_irqsave(&udma->lock, flags);
++
++ reg_en = readl(udma->regs + reg_en_off);
++ reg_rst = readl(udma->regs + reg_rst_off);
++
++ switch (op) {
++ case ASPEED_UDMA_OP_ENABLE:
++ reg_en |= (0x1 << ch_no);
++ writel(reg_en, udma->regs + reg_en_off);
++ break;
++ case ASPEED_UDMA_OP_DISABLE:
++ reg_en &= ~(0x1 << ch_no);
++ writel(reg_en, udma->regs + reg_en_off);
++ break;
++ case ASPEED_UDMA_OP_RESET:
++ reg_en &= ~(0x1 << ch_no);
++ writel(reg_en, udma->regs + reg_en_off);
++ reg_rst |= (0x1 << ch_no);
++ writel(reg_rst, udma->regs + reg_rst_off);
++ reg_rst &= ~(0x1 << ch_no);
++ writel(reg_rst, udma->regs + reg_rst_off);
++ break;
++ default:
++ break;
++ }
++
++ spin_unlock_irqrestore(&udma->lock, flags);
++}
++
++void aspeed_udma_tx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op)
++{
++ aspeed_udma_chan_ctrl(ch_no, op, true);
++}
++EXPORT_SYMBOL(aspeed_udma_tx_chan_ctrl);
++
++void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op)
++{
++ aspeed_udma_chan_ctrl(ch_no, op, false);
++}
++EXPORT_SYMBOL(aspeed_udma_rx_chan_ctrl);
++
++static irqreturn_t aspeed_udma_isr(int irq, void *arg)
++{
++ u32 bit;
++ unsigned long tx_stat = readl(udma->regs + UDMA_TX_DMA_INT_STAT);
++ unsigned long rx_stat = readl(udma->regs + UDMA_RX_DMA_INT_STAT);
++
++ if (udma != (struct aspeed_udma *)arg)
++ return IRQ_NONE;
++
++ if (tx_stat == 0 && rx_stat == 0)
++ return IRQ_NONE;
++
++ for_each_set_bit(bit, &tx_stat, UDMA_MAX_CHANNEL) {
++ writel((0x1 << bit), udma->regs + UDMA_TX_DMA_INT_STAT);
++ if (udma->tx_chs[bit].cb)
++ udma->tx_chs[bit].cb(aspeed_udma_get_tx_rptr(bit),
++ udma->tx_chs[bit].cb_arg);
++ }
++
++ for_each_set_bit(bit, &rx_stat, UDMA_MAX_CHANNEL) {
++ writel((0x1 << bit), udma->regs + UDMA_RX_DMA_INT_STAT);
++ if (udma->rx_chs[bit].cb)
++ udma->rx_chs[bit].cb(aspeed_udma_get_rx_wptr(bit),
++ udma->rx_chs[bit].cb_arg);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int aspeed_udma_probe(struct platform_device *pdev)
++{
++ int i, rc;
++ struct resource *res;
++ struct device *dev = &pdev->dev;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (IS_ERR_OR_NULL(res)) {
++ dev_err(dev, "failed to get register base\n");
++ return -ENODEV;
++ }
++
++ udma->regs = devm_ioremap_resource(dev, res);
++ if (IS_ERR_OR_NULL(udma->regs)) {
++ dev_err(dev, "failed to map registers\n");
++ return PTR_ERR(udma->regs);
++ }
++
++ /* disable for safety */
++ writel(0x0, udma->regs + UDMA_TX_DMA_EN);
++ writel(0x0, udma->regs + UDMA_RX_DMA_EN);
++
++ udma->irq = platform_get_irq(pdev, 0);
++ if (udma->irq < 0) {
++ dev_err(dev, "failed to get IRQ number\n");
++ return -ENODEV;
++ }
++
++ rc = devm_request_irq(dev, udma->irq, aspeed_udma_isr,
++ IRQF_SHARED, DEVICE_NAME, udma);
++ if (rc) {
++ dev_err(dev, "failed to request IRQ handler\n");
++ return rc;
++ }
++
++ for (i = 0; i < UDMA_MAX_CHANNEL; ++i) {
++ writel(0, udma->regs + UDMA_CHX_TX_WR_PTR(i));
++ writel(0, udma->regs + UDMA_CHX_RX_RD_PTR(i));
++ }
++
++ writel(0xffffffff, udma->regs + UDMA_TX_DMA_RST);
++ writel(0x0, udma->regs + UDMA_TX_DMA_RST);
++
++ writel(0xffffffff, udma->regs + UDMA_RX_DMA_RST);
++ writel(0x0, udma->regs + UDMA_RX_DMA_RST);
++
++ writel(0x0, udma->regs + UDMA_TX_DMA_INT_EN);
++ writel(0xffffffff, udma->regs + UDMA_TX_DMA_INT_STAT);
++ writel(0x0, udma->regs + UDMA_RX_DMA_INT_EN);
++ writel(0xffffffff, udma->regs + UDMA_RX_DMA_INT_STAT);
++
++ writel(UDMA_TIMEOUT, udma->regs + UDMA_TIMEOUT_TIMER);
++
++ spin_lock_init(&udma->lock);
++
++ dev_set_drvdata(dev, udma);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_udma_match[] = {
++ { .compatible = "aspeed,ast2500-udma" },
++ { .compatible = "aspeed,ast2600-udma" },
++};
++
++static struct platform_driver aspeed_udma_driver = {
++ .driver = {
++ .name = DEVICE_NAME,
++ .of_match_table = aspeed_udma_match,
++
++ },
++ .probe = aspeed_udma_probe,
++};
++
++module_platform_driver(aspeed_udma_driver);
++
++MODULE_AUTHOR("Chia-Wei Wang <chiawei_wang@aspeedtech.com>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Aspeed UDMA Engine Driver");
+diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/8250_aspeed.c
+new file mode 100644
+index 000000000000..1dc798298fca
+--- /dev/null
++++ b/drivers/tty/serial/8250/8250_aspeed.c
+@@ -0,0 +1,494 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) ASPEED Technology Inc.
++ */
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/serial_8250.h>
++#include <linux/serial_reg.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <linux/dma-mapping.h>
++#include <linux/circ_buf.h>
++#include <linux/tty_flip.h>
++#include <linux/pm_runtime.h>
++#include <linux/soc/aspeed/aspeed-udma.h>
++
++#include "8250.h"
++
++#define DEVICE_NAME "aspeed-uart"
++
++/* offsets for the aspeed virtual uart registers */
++#define VUART_GCRA 0x20
++#define VUART_GCRA_VUART_EN BIT(0)
++#define VUART_GCRA_SIRQ_POLARITY BIT(1)
++#define VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
++#define VUART_GCRB 0x24
++#define VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4)
++#define VUART_GCRB_HOST_SIRQ_SHIFT 4
++#define VUART_ADDRL 0x28
++#define VUART_ADDRH 0x2c
++
++#define DMA_TX_BUFSZ PAGE_SIZE
++#define DMA_RX_BUFSZ (64 * 1024)
++
++struct uart_ops ast8250_pops;
++
++struct ast8250_vuart {
++ u32 port;
++ u32 sirq;
++ u32 sirq_pol;
++};
++
++struct ast8250_udma {
++ u32 ch;
++
++ u32 tx_rbsz;
++ u32 rx_rbsz;
++
++ dma_addr_t tx_addr;
++ dma_addr_t rx_addr;
++
++ struct circ_buf *tx_rb;
++ struct circ_buf *rx_rb;
++
++ bool tx_tmout_dis;
++ bool rx_tmout_dis;
++};
++
++struct ast8250_data {
++ int line;
++
++ u8 __iomem *regs;
++
++ bool is_vuart;
++ bool use_dma;
++
++ struct reset_control *rst;
++ struct clk *clk;
++
++ struct ast8250_vuart vuart;
++ struct ast8250_udma dma;
++};
++
++static void ast8250_dma_tx_complete(int tx_rb_rptr, void *id)
++{
++ u32 count;
++ unsigned long flags;
++ struct uart_port *port = (struct uart_port*)id;
++ struct ast8250_data *data = port->private_data;
++
++ spin_lock_irqsave(&port->lock, flags);
++
++ count = CIRC_CNT(tx_rb_rptr, port->state->xmit.tail, data->dma.tx_rbsz);
++ port->state->xmit.tail = tx_rb_rptr;
++ port->icount.tx += count;
++
++ if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(port);
++
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void ast8250_dma_rx_complete(int rx_rb_wptr, void *id)
++{
++ unsigned long flags;
++ struct uart_port *up = (struct uart_port*)id;
++ struct tty_port *tp = &up->state->port;
++ struct ast8250_data *data = up->private_data;
++ struct ast8250_udma *dma = &data->dma;
++ struct circ_buf *rx_rb = dma->rx_rb;
++ u32 rx_rbsz = dma->rx_rbsz;
++ u32 count = 0;
++
++ spin_lock_irqsave(&up->lock, flags);
++
++ rx_rb->head = rx_rb_wptr;
++
++ dma_sync_single_for_cpu(up->dev,
++ dma->rx_addr, dma->rx_rbsz, DMA_FROM_DEVICE);
++
++ while (CIRC_CNT(rx_rb->head, rx_rb->tail, rx_rbsz)) {
++ count = CIRC_CNT_TO_END(rx_rb->head, rx_rb->tail, rx_rbsz);
++
++ tty_insert_flip_string(tp, rx_rb->buf + rx_rb->tail, count);
++
++ rx_rb->tail += count;
++ rx_rb->tail %= rx_rbsz;
++
++ up->icount.rx += count;
++ }
++
++ if (count) {
++ aspeed_udma_set_rx_rptr(data->dma.ch, rx_rb->tail);
++ tty_flip_buffer_push(tp);
++ }
++
++ spin_unlock_irqrestore(&up->lock, flags);
++}
++
++static void ast8250_dma_start_tx(struct uart_port *port)
++{
++ struct ast8250_data *data = port->private_data;
++ struct ast8250_udma *dma = &data->dma;
++ struct circ_buf *tx_rb = dma->tx_rb;
++
++ dma_sync_single_for_device(port->dev,
++ dma->tx_addr, dma->tx_rbsz, DMA_TO_DEVICE);
++
++ aspeed_udma_set_tx_wptr(dma->ch, tx_rb->head);
++}
++
++static void ast8250_dma_pops_hook(struct uart_port *port)
++{
++ static int first = 1;
++
++ if (first) {
++ ast8250_pops = *port->ops;
++ ast8250_pops.start_tx = ast8250_dma_start_tx;
++ }
++
++ first = 0;
++ port->ops = &ast8250_pops;
++}
++
++static void ast8250_vuart_init(struct ast8250_data *data)
++{
++ u8 reg;
++ struct ast8250_vuart *vuart = &data->vuart;
++
++ /* IO port address */
++ writeb((u8)(vuart->port >> 0), data->regs + VUART_ADDRL);
++ writeb((u8)(vuart->port >> 8), data->regs + VUART_ADDRH);
++
++ /* SIRQ number */
++ reg = readb(data->regs + VUART_GCRB);
++ reg &= ~VUART_GCRB_HOST_SIRQ_MASK;
++ reg |= ((vuart->sirq << VUART_GCRB_HOST_SIRQ_SHIFT) & VUART_GCRB_HOST_SIRQ_MASK);
++ writeb(reg, data->regs + VUART_GCRB);
++
++ /* SIRQ polarity */
++ reg = readb(data->regs + VUART_GCRA);
++ if (vuart->sirq_pol)
++ reg |= VUART_GCRA_SIRQ_POLARITY;
++ else
++ reg &= ~VUART_GCRA_SIRQ_POLARITY;
++ writeb(reg, data->regs + VUART_GCRA);
++}
++
++static void ast8250_vuart_set_host_tx_discard(struct ast8250_data *data, bool discard)
++{
++ u8 reg;
++
++ reg = readb(data->regs + VUART_GCRA);
++ if (discard)
++ reg &= ~VUART_GCRA_DISABLE_HOST_TX_DISCARD;
++ else
++ reg |= VUART_GCRA_DISABLE_HOST_TX_DISCARD;
++ writeb(reg, data->regs + VUART_GCRA);
++}
++
++static void ast8250_vuart_set_enable(struct ast8250_data *data, bool enable)
++{
++ u8 reg;
++
++ reg = readb(data->regs + VUART_GCRA);
++ if (enable)
++ reg |= VUART_GCRA_VUART_EN;
++ else
++ reg &= ~VUART_GCRA_VUART_EN;
++ writeb(reg, data->regs + VUART_GCRA);
++}
++
++static int ast8250_handle_irq(struct uart_port *port)
++{
++ u32 iir = port->serial_in(port, UART_IIR);
++ return serial8250_handle_irq(port, iir);
++}
++
++static int ast8250_startup(struct uart_port *port)
++{
++ int rc = 0;
++ struct ast8250_data *data = port->private_data;
++ struct ast8250_udma *dma;
++
++ if (data->is_vuart)
++ ast8250_vuart_set_host_tx_discard(data, false);
++
++ if (data->use_dma) {
++ dma = &data->dma;
++
++ dma->tx_rbsz = DMA_TX_BUFSZ;
++ dma->rx_rbsz = DMA_RX_BUFSZ;
++
++ /*
++ * We take the xmit buffer passed from upper layers as
++ * the DMA TX buffer and allocate a new buffer for the
++ * RX use.
++ *
++ * To keep the TX/RX operation consistency, we use the
++ * streaming DMA interface instead of the coherent one
++ */
++ dma->tx_rb = &port->state->xmit;
++ dma->rx_rb->buf = kzalloc(data->dma.rx_rbsz, GFP_KERNEL);
++ if (IS_ERR_OR_NULL(dma->rx_rb->buf)) {
++ dev_err(port->dev, "failed to allcoate RX DMA buffer\n");
++ rc = -ENOMEM;
++ goto out;
++ }
++
++ dma->tx_addr = dma_map_single(port->dev, dma->tx_rb->buf,
++ dma->tx_rbsz, DMA_TO_DEVICE);
++ if (dma_mapping_error(port->dev, dma->tx_addr)) {
++ dev_err(port->dev, "failed to map streaming TX DMA region\n");
++ rc = -ENOMEM;
++ goto free_dma_n_out;
++ }
++
++ dma->rx_addr = dma_map_single(port->dev, dma->rx_rb->buf,
++ dma->rx_rbsz, DMA_FROM_DEVICE);
++ if (dma_mapping_error(port->dev, dma->rx_addr)) {
++ dev_err(port->dev, "failed to map streaming RX DMA region\n");
++ rc = -ENOMEM;
++ goto free_dma_n_out;
++ }
++
++ rc = aspeed_udma_request_tx_chan(dma->ch, dma->tx_addr,
++ dma->tx_rb, dma->tx_rbsz, ast8250_dma_tx_complete, port, dma->tx_tmout_dis);
++ if (rc) {
++ dev_err(port->dev, "failed to request DMA TX channel\n");
++ goto free_dma_n_out;
++ }
++
++ rc = aspeed_udma_request_rx_chan(dma->ch, dma->rx_addr,
++ dma->rx_rb, dma->rx_rbsz, ast8250_dma_rx_complete, port, dma->tx_tmout_dis);
++ if (rc) {
++ dev_err(port->dev, "failed to request DMA RX channel\n");
++ goto free_dma_n_out;
++ }
++
++ ast8250_dma_pops_hook(port);
++
++ aspeed_udma_tx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_ENABLE);
++ aspeed_udma_rx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_ENABLE);
++ }
++
++ memset(&port->icount, 0, sizeof(port->icount));
++ return serial8250_do_startup(port);
++
++free_dma_n_out:
++ kfree(dma->rx_rb->buf);
++out:
++ return rc;
++}
++
++static void ast8250_shutdown(struct uart_port *port)
++{
++ int rc;
++ struct ast8250_data *data = port->private_data;
++ struct ast8250_udma *dma;
++
++ if (data->use_dma) {
++ dma = &data->dma;
++
++ aspeed_udma_tx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_DISABLE);
++ aspeed_udma_rx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_DISABLE);
++
++ rc = aspeed_udma_free_tx_chan(dma->ch);
++ if (rc)
++ dev_err(port->dev, "failed to free DMA TX channel, rc=%d\n", rc);
++
++ rc = aspeed_udma_free_rx_chan(dma->ch);
++ if (rc)
++ dev_err(port->dev, "failed to free DMA TX channel, rc=%d\n", rc);
++
++ dma_unmap_single(port->dev, dma->tx_addr,
++ dma->tx_rbsz, DMA_TO_DEVICE);
++ dma_unmap_single(port->dev, dma->rx_addr,
++ dma->rx_rbsz, DMA_FROM_DEVICE);
++
++ if (dma->rx_rb->buf)
++ kfree(dma->rx_rb->buf);
++ }
++
++ if (data->is_vuart)
++ ast8250_vuart_set_host_tx_discard(data, true);
++
++ serial8250_do_shutdown(port);
++}
++
++static int __maybe_unused ast8250_suspend(struct device *dev)
++{
++ struct ast8250_data *data = dev_get_drvdata(dev);
++ serial8250_suspend_port(data->line);
++ return 0;
++}
++
++static int __maybe_unused ast8250_resume(struct device *dev)
++{
++ struct ast8250_data *data = dev_get_drvdata(dev);
++ serial8250_resume_port(data->line);
++ return 0;
++}
++
++static int ast8250_probe(struct platform_device *pdev)
++{
++ int rc;
++ struct uart_8250_port uart = {};
++ struct uart_port *port = &uart.port;
++ struct device *dev = &pdev->dev;
++ struct ast8250_data *data;
++
++ struct resource *res;
++ u32 irq;
++
++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
++ if (data == NULL)
++ return -ENOMEM;
++
++ data->dma.rx_rb = devm_kzalloc(dev, sizeof(data->dma.rx_rb), GFP_KERNEL);
++ if (data->dma.rx_rb == NULL)
++ return -ENOMEM;
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ if (irq != -EPROBE_DEFER)
++ dev_err(dev, "failed to get IRQ number\n");
++ return irq;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res == NULL) {
++ dev_err(dev, "failed to get register base\n");
++ return -ENODEV;
++ }
++
++ data->regs = devm_ioremap(dev, res->start, resource_size(res));
++ if (IS_ERR(data->regs)) {
++ dev_err(dev, "failed to map registers\n");
++ return PTR_ERR(data->regs);
++ }
++
++ data->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(data->clk)) {
++ dev_err(dev, "failed to get clocks\n");
++ return -ENODEV;
++ }
++
++ rc = clk_prepare_enable(data->clk);
++ if (rc) {
++ dev_err(dev, "failed to enable clock\n");
++ return rc;
++ }
++
++ data->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
++ if (!IS_ERR(data->rst))
++ reset_control_deassert(data->rst);
++
++ data->is_vuart = of_property_read_bool(dev->of_node, "virtual");
++ if (data->is_vuart) {
++ rc = of_property_read_u32(dev->of_node, "port", &data->vuart.port);
++ if (rc) {
++ dev_err(dev, "failed to get VUART port address\n");
++ return -ENODEV;
++ }
++
++ rc = of_property_read_u32(dev->of_node, "sirq", &data->vuart.sirq);
++ if (rc) {
++ dev_err(dev, "failed to get VUART SIRQ number\n");
++ return -ENODEV;
++ }
++
++ rc = of_property_read_u32(dev->of_node, "sirq-polarity", &data->vuart.sirq_pol);
++ if (rc) {
++ dev_err(dev, "failed to get VUART SIRQ polarity\n");
++ return -ENODEV;
++ }
++
++ ast8250_vuart_init(data);
++ ast8250_vuart_set_host_tx_discard(data, true);
++ ast8250_vuart_set_enable(data, true);
++ }
++
++ data->use_dma = of_property_read_bool(dev->of_node, "dma-mode");
++ if (data->use_dma) {
++ rc = of_property_read_u32(dev->of_node, "dma-channel", &data->dma.ch);
++ if (rc) {
++ dev_err(dev, "failed to get DMA channel\n");
++ return -ENODEV;
++ }
++
++ data->dma.tx_tmout_dis = of_property_read_bool(dev->of_node, "dma-tx-timeout-disable");
++ data->dma.rx_tmout_dis = of_property_read_bool(dev->of_node, "dma-rx-timeout-disable");
++ }
++
++ spin_lock_init(&port->lock);
++ port->dev = dev;
++ port->type = PORT_16550;
++ port->irq = irq;
++ port->line = of_alias_get_id(dev->of_node, "serial");
++ port->handle_irq = ast8250_handle_irq;
++ port->mapbase = res->start;
++ port->mapsize = resource_size(res);
++ port->membase = data->regs;
++ port->uartclk = clk_get_rate(data->clk);
++ port->regshift = 2;
++ port->iotype = UPIO_MEM32;
++ port->flags = UPF_FIXED_PORT | UPF_SHARE_IRQ;
++ port->startup = ast8250_startup;
++ port->shutdown = ast8250_shutdown;
++ port->private_data = data;
++
++ data->line = serial8250_register_8250_port(&uart);
++ if (data->line < 0) {
++ dev_err(dev, "failed to register 8250 port\n");
++ return data->line;
++ }
++
++ pm_runtime_set_active(&pdev->dev);
++ pm_runtime_enable(&pdev->dev);
++
++ platform_set_drvdata(pdev, data);
++ return 0;
++}
++
++static int ast8250_remove(struct platform_device *pdev)
++{
++ struct ast8250_data *data = platform_get_drvdata(pdev);
++
++ if (data->is_vuart)
++ ast8250_vuart_set_enable(data, false);
++
++ serial8250_unregister_port(data->line);
++ return 0;
++}
++
++static const struct dev_pm_ops ast8250_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(ast8250_suspend, ast8250_resume)
++};
++
++static const struct of_device_id ast8250_of_match[] = {
++ { .compatible = "aspeed,ast2500-uart" },
++ { .compatible = "aspeed,ast2600-uart" },
++};
++
++static struct platform_driver ast8250_platform_driver = {
++ .driver = {
++ .name = DEVICE_NAME,
++ .pm = &ast8250_pm_ops,
++ .of_match_table = ast8250_of_match,
++ },
++ .probe = ast8250_probe,
++ .remove = ast8250_remove,
++};
++
++module_platform_driver(ast8250_platform_driver);
++
++MODULE_AUTHOR("Chia-Wei Wang <chiawei_wang@aspeedtech.com>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Aspeed UART Driver");
+diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
+index d1b3c2373fa4..b62a972c9c97 100644
+--- a/drivers/tty/serial/8250/Kconfig
++++ b/drivers/tty/serial/8250/Kconfig
+@@ -249,6 +249,14 @@ config SERIAL_8250_ACCENT
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_accent.
+
++config SERIAL_8250_ASPEED
++ tristate "Aspeed serial port support"
++ depends on SERIAL_8250 && ARCH_ASPEED
++ select ASPEED_UDMA
++ help
++ If you have a system using an Aspeed ASTXXXX SoCs and wish to make use
++ of its UARTs, say Y to this option. If unsure, say N.
++
+ config SERIAL_8250_ASPEED_VUART
+ tristate "Aspeed Virtual UART"
+ depends on SERIAL_8250
+diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
+index b9bcd73c8997..310375fe8d7e 100644
+--- a/drivers/tty/serial/8250/Makefile
++++ b/drivers/tty/serial/8250/Makefile
+@@ -16,6 +16,7 @@ obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o
+ obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
+ obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
+ obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
++obj-$(CONFIG_SERIAL_8250_ASPEED) += 8250_aspeed.o
+ obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o
+ obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
+ obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
+diff --git a/include/linux/soc/aspeed/aspeed-udma.h b/include/linux/soc/aspeed/aspeed-udma.h
+new file mode 100644
+index 000000000000..33acea745f1c
+--- /dev/null
++++ b/include/linux/soc/aspeed/aspeed-udma.h
+@@ -0,0 +1,30 @@
++#ifndef __ASPEED_UDMA_H__
++#define __ASPEED_UDMA_H__
++
++#include <linux/circ_buf.h>
++
++typedef void (*aspeed_udma_cb_t)(int rb_rwptr, void *id);
++
++enum aspeed_udma_ops {
++ ASPEED_UDMA_OP_ENABLE,
++ ASPEED_UDMA_OP_DISABLE,
++ ASPEED_UDMA_OP_RESET,
++};
++
++void aspeed_udma_set_tx_wptr(u32 ch_no, u32 wptr);
++void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr);
++
++void aspeed_udma_tx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op);
++void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op);
++
++int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr,
++ struct circ_buf *rb, u32 rb_sz,
++ aspeed_udma_cb_t cb, void *id, bool en_tmout);
++int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr,
++ struct circ_buf *rb, u32 rb_sz,
++ aspeed_udma_cb_t cb, void *id, bool en_tmout);
++
++int aspeed_udma_free_tx_chan(u32 ch_no);
++int aspeed_udma_free_rx_chan(u32 ch_no);
++
++#endif
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0002-serial-8250-Fix-RX-DMA-time-out-property.patch b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0002-serial-8250-Fix-RX-DMA-time-out-property.patch
new file mode 100644
index 000000000..bbadb8b01
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0002-serial-8250-Fix-RX-DMA-time-out-property.patch
@@ -0,0 +1,29 @@
+From 64897e97edeefc7fbc89b07aaece760009ba76a0 Mon Sep 17 00:00:00 2001
+From: "Chia-Wei, Wang" <chiawei_wang@aspeedtech.com>
+Date: Mon, 21 Dec 2020 16:27:20 +0800
+Subject: [PATCH] serial: 8250: Fix RX DMA time out property
+
+Fix the typo that passing the TX DMA time out property
+to the RX configuration.
+
+Signed-off-by: Chia-Wei, Wang <chiawei_wang@aspeedtech.com>
+---
+ drivers/tty/serial/8250/8250_aspeed.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/8250_aspeed.c
+index 1dc798298fca..fc14c86d3761 100644
+--- a/drivers/tty/serial/8250/8250_aspeed.c
++++ b/drivers/tty/serial/8250/8250_aspeed.c
+@@ -266,7 +266,7 @@ static int ast8250_startup(struct uart_port *port)
+ }
+
+ rc = aspeed_udma_request_rx_chan(dma->ch, dma->rx_addr,
+- dma->rx_rb, dma->rx_rbsz, ast8250_dma_rx_complete, port, dma->tx_tmout_dis);
++ dma->rx_rb, dma->rx_rbsz, ast8250_dma_rx_complete, port, dma->rx_tmout_dis);
+ if (rc) {
+ dev_err(port->dev, "failed to request DMA RX channel\n");
+ goto free_dma_n_out;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0003-serial-8250_aspeed-Make-port-type-fixed.patch b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0003-serial-8250_aspeed-Make-port-type-fixed.patch
new file mode 100644
index 000000000..4a0e221b6
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0003-serial-8250_aspeed-Make-port-type-fixed.patch
@@ -0,0 +1,57 @@
+From a7a8bf2f7df17f69a407abe21a14b3f0f2c7338c Mon Sep 17 00:00:00 2001
+From: Chia-Wei Wang <chiawei_wang@aspeedtech.com>
+Date: Mon, 31 May 2021 15:39:59 +0800
+Subject: [PATCH] serial/8250_aspeed: Make port type fixed
+
+Make the UART port type fixed to 16550A to
+avoid redundant probing.
+
+Signed-off-by: Chia-Wei Wang <chiawei_wang@aspeedtech.com>
+Change-Id: Id179725b1cd475cd52c18c43b6c312dcd912fc20
+---
+ drivers/tty/serial/8250/8250_aspeed.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/8250_aspeed.c
+index fc14c86d3761..bb3955bb8c24 100644
+--- a/drivers/tty/serial/8250/8250_aspeed.c
++++ b/drivers/tty/serial/8250/8250_aspeed.c
+@@ -25,12 +25,12 @@
+
+ /* offsets for the aspeed virtual uart registers */
+ #define VUART_GCRA 0x20
+-#define VUART_GCRA_VUART_EN BIT(0)
+-#define VUART_GCRA_SIRQ_POLARITY BIT(1)
+-#define VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
++#define VUART_GCRA_VUART_EN BIT(0)
++#define VUART_GCRA_SIRQ_POLARITY BIT(1)
++#define VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
+ #define VUART_GCRB 0x24
+-#define VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4)
+-#define VUART_GCRB_HOST_SIRQ_SHIFT 4
++#define VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4)
++#define VUART_GCRB_HOST_SIRQ_SHIFT 4
+ #define VUART_ADDRL 0x28
+ #define VUART_ADDRH 0x2c
+
+@@ -429,7 +429,7 @@ static int ast8250_probe(struct platform_device *pdev)
+
+ spin_lock_init(&port->lock);
+ port->dev = dev;
+- port->type = PORT_16550;
++ port->type = PORT_16550A;
+ port->irq = irq;
+ port->line = of_alias_get_id(dev->of_node, "serial");
+ port->handle_irq = ast8250_handle_irq;
+@@ -439,7 +439,7 @@ static int ast8250_probe(struct platform_device *pdev)
+ port->uartclk = clk_get_rate(data->clk);
+ port->regshift = 2;
+ port->iotype = UPIO_MEM32;
+- port->flags = UPF_FIXED_PORT | UPF_SHARE_IRQ;
++ port->flags = UPF_FIXED_TYPE | UPF_FIXED_PORT | UPF_SHARE_IRQ;
+ port->startup = ast8250_startup;
+ port->shutdown = ast8250_shutdown;
+ port->private_data = data;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0004-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0004-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch
new file mode 100644
index 000000000..757b00a25
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/0004-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch
@@ -0,0 +1,269 @@
+From a9b43dbf68a4b5650dd98332243d4a2951717eb5 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>
+---
+ .../arm/boot/dts/aspeed-bmc-intel-ast2600.dts | 4 ++
+ drivers/tty/serial/8250/8250_aspeed.c | 56 ++++++++++++++++-
+ drivers/tty/serial/8250/8250_early.c | 1 +
+ drivers/tty/serial/8250/8250_of.c | 63 +++++++++++++++++++
+ 4 files changed, 123 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
+index c648c123c315..bf375634082c 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
+@@ -392,6 +392,7 @@
+ };
+
+ &uart1 {
++ reg = <0x1e783000 0x20>, <0x1e6e2014 0x4>, <0x1e78307c 0x4>;
+ status = "okay";
+ pinctrl-0 = <&pinctrl_txd1_default
+ &pinctrl_rxd1_default
+@@ -404,6 +405,7 @@
+ };
+
+ &uart2 {
++ reg = <0x1e78d000 0x20>, <0x1e6e2014 0x4>, <0x1e78d07c 0x4>;
+ status = "okay";
+ pinctrl-0 = <&pinctrl_txd2_default
+ &pinctrl_rxd2_default
+@@ -416,11 +418,13 @@
+ };
+
+ &uart3 {
++ reg = <0x1e78e000 0x20>, <0x1e6e2014 0x4>, <0x1e78e07c 0x4>;
+ status = "okay";
+ pinctrl-0 = <>;
+ };
+
+ &uart4 {
++ reg = <0x1e78f000 0x20>, <0x1e6e2014 0x4>, <0x1e78f07c 0x4>;
+ status = "okay";
+ pinctrl-0 = <>;
+ };
+diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/8250_aspeed.c
+index bb3955bb8c24..1ba4423d5e2f 100644
+--- a/drivers/tty/serial/8250/8250_aspeed.c
++++ b/drivers/tty/serial/8250/8250_aspeed.c
+@@ -74,6 +74,10 @@ struct ast8250_data {
+
+ struct ast8250_vuart vuart;
+ struct ast8250_udma dma;
++
++ struct workqueue_struct *work_queue;
++ struct delayed_work work_handler;
++ void __iomem *wa_base;
+ };
+
+ static void ast8250_dma_tx_complete(int tx_rb_rptr, void *id)
+@@ -336,12 +340,25 @@ static int __maybe_unused ast8250_resume(struct device *dev)
+ return 0;
+ }
+
++#define WA_DELAY_JIFFIES msecs_to_jiffies(1)
++static void ast8250_clear_abnormal_int_flags(struct work_struct *work)
++{
++ struct delayed_work *dwork = to_delayed_work(work);
++ struct ast8250_data *data = container_of(dwork, struct ast8250_data,
++ work_handler);
++
++ (void) readl(data->wa_base);
++ queue_delayed_work(data->work_queue, &data->work_handler,
++ WA_DELAY_JIFFIES);
++}
++
+ static int ast8250_probe(struct platform_device *pdev)
+ {
+ int rc;
+ struct uart_8250_port uart = {};
+ struct uart_port *port = &uart.port;
+ struct device *dev = &pdev->dev;
++ void __iomem *chip_id_base;
+ struct ast8250_data *data;
+
+ struct resource *res;
+@@ -454,6 +471,37 @@ static int ast8250_probe(struct platform_device *pdev)
+ pm_runtime_enable(&pdev->dev);
+
+ platform_set_drvdata(pdev, data);
++
++ #define REV_ID_AST2600A0 0x05000303
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!res || resource_size(res) < 2)
++ return 0;
++
++ data->wa_base = devm_platform_ioremap_resource(pdev, 2);
++ if (IS_ERR(data->wa_base))
++ return 0;
++
++ chip_id_base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(chip_id_base))
++ return 0;
++
++ if (readl(chip_id_base) == REV_ID_AST2600A0) {
++ data->work_queue = alloc_ordered_workqueue(pdev->name, 0);
++ if (data->work_queue) {
++ INIT_DELAYED_WORK(&data->work_handler,
++ ast8250_clear_abnormal_int_flags);
++ queue_delayed_work(data->work_queue,
++ &data->work_handler,
++ WA_DELAY_JIFFIES);
++ dev_info(dev, "AST2600 A0 WA initiated\n");
++ } else {
++ dev_err(dev, "Can't enable AST2600 A0 UART WA\n");
++ }
++ }
++
++ devm_iounmap(dev, chip_id_base);
++ devm_release_mem_region(dev, res->start, resource_size(res));
++
+ return 0;
+ }
+
+@@ -464,7 +512,13 @@ static int ast8250_remove(struct platform_device *pdev)
+ if (data->is_vuart)
+ ast8250_vuart_set_enable(data, false);
+
+- serial8250_unregister_port(data->line);
++ if (data->work_queue) {
++ cancel_delayed_work_sync(&data->work_handler);
++ destroy_workqueue(data->work_queue);
++ }
++
++ serial8250_unregister_port(data->line);
++
+ return 0;
+ }
+
+diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
+index c171ce6db691..6d7bb63fe0c6 100644
+--- a/drivers/tty/serial/8250/8250_early.c
++++ b/drivers/tty/serial/8250/8250_early.c
+@@ -180,6 +180,7 @@ OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
+ OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
+ OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
+ OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
++OF_EARLYCON_DECLARE(uart, "aspeed,ast2600-uart", early_serial8250_setup);
+
+ #ifdef CONFIG_SERIAL_8250_OMAP
+
+diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
+index bce28729dd7b..6159d8af6fef 100644
+--- a/drivers/tty/serial/8250/8250_of.c
++++ b/drivers/tty/serial/8250/8250_of.c
+@@ -15,6 +15,7 @@
+ #include <linux/pm_runtime.h>
+ #include <linux/clk.h>
+ #include <linux/reset.h>
++#include <linux/workqueue.h>
+
+ #include "8250.h"
+
+@@ -23,6 +24,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;
+ };
+
+ /*
+@@ -181,6 +185,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
+ */
+@@ -233,6 +249,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);
+@@ -254,6 +311,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);
+@@ -324,6 +386,7 @@ static const struct of_device_id of_platform_serial_table[] = {
+ { .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, },
+ { .compatible = "nuvoton,wpcm450-uart", .data = (void *)PORT_NPCM, },
+ { .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.17.1
+
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/intel-ast2600.cfg b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/intel-ast2600.cfg
new file mode 100644
index 000000000..9bd1535be
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed/intel-ast2600.cfg
@@ -0,0 +1,23 @@
+CONFIG_SENSORS_ASPEED=n
+CONFIG_SENSORS_ASPEED_G6=y
+CONFIG_SPI_ASPEED_SMC=y
+CONFIG_SPI_FMC=y
+CONFIG_I3C=y
+CONFIG_DW_I3C_MASTER=y
+CONFIG_I3CDEV=y
+CONFIG_U_SERIAL_CONSOLE=n
+CONFIG_HIGHMEM=n
+CONFIG_I2C_SLAVE_MQUEUE=y
+CONFIG_PINCTRL_ASPEED_G6=y
+CONFIG_DEBUG_LL=n
+CONFIG_DEBUG_LL_UART_8250=n
+CONFIG_EARLY_PRINTK=n
+CONFIG_LOG_BUF_SHIFT=21
+CONFIG_DEBUG_PINCTRL=n
+CONFIG_SUSPEND=n
+CONFIG_ASPEED_MCTP=y
+CONFIG_KERNEL_LZO=n
+CONFIG_KERNEL_XZ=y
+CONFIG_SERIAL_8250_DW=n
+CONFIG_SERIAL_8250_ASPEED=y
+CONFIG_ASPEED_UDMA=y
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
new file mode 100644
index 000000000..df3901d77
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes-kernel/linux/linux-aspeed_%.bbappend
@@ -0,0 +1,10 @@
+COMPATIBLE_MACHINE = "intel-ast2600"
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " \
+ file://intel-ast2600.cfg \
+ file://0001-serial-8250-Add-Aspeed-UART-driver-with-DMA-supporte.patch \
+ file://0002-serial-8250-Fix-RX-DMA-time-out-property.patch \
+ file://0003-serial-8250_aspeed-Make-port-type-fixed.patch \
+ file://0004-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch \
+ "
diff --git a/meta-openbmc-mods/meta-ast2600/recipes.txt b/meta-openbmc-mods/meta-ast2600/recipes.txt
new file mode 100644
index 000000000..2f89155c3
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2600/recipes.txt
@@ -0,0 +1,3 @@
+recipes-bsp - Anything with links to specific hardware or hardware configuration information
+recipes-kernel - The kernel and generic applications/libraries with strong kernel dependencies
+recipes-phosphor - Phosphor OpenBMC applications and configuration