diff options
Diffstat (limited to 'meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files')
43 files changed, 7509 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch new file mode 100644 index 000000000..dfb11d89a --- /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,1379 @@ +From ada80beb48d974f101201745657d10e72fe30b9c 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> +--- + arch/arm/dts/Makefile | 3 +- + arch/arm/dts/ast2600-intel.dts | 197 ++++++++++++ + arch/arm/lib/interrupts.c | 5 + + arch/arm/mach-aspeed/ast2600/Kconfig | 8 + + board/aspeed/ast2600_intel/Kconfig | 13 + + board/aspeed/ast2600_intel/Makefile | 4 + + board/aspeed/ast2600_intel/ast-espi.c | 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 | 192 ++++++++++++ + cmd/Kconfig | 2 +- + common/autoboot.c | 10 + + configs/ast2600_openbmc_defconfig | 2 +- + 14 files changed, 1191 insertions(+), 3 deletions(-) + mode change 100755 => 100644 arch/arm/dts/Makefile + create mode 100644 arch/arm/dts/ast2600-intel.dts + create mode 100644 board/aspeed/ast2600_intel/Kconfig + create mode 100644 board/aspeed/ast2600_intel/Makefile + 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 + create mode 100644 board/aspeed/ast2600_intel/intel.c + mode change 100755 => 100644 configs/ast2600_openbmc_defconfig + +diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile +old mode 100755 +new mode 100644 +index e9d994737949..d2ad5968775e +--- a/arch/arm/dts/Makefile ++++ b/arch/arm/dts/Makefile +@@ -684,7 +684,8 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ + ast2600-fpga.dtb \ + ast2600-rainier.dtb \ + ast2600-slt.dtb \ +- ast2600-tacoma.dtb ++ ast2600-tacoma.dtb \ ++ ast2600-intel.dtb + + dtb-$(CONFIG_ARCH_STI) += stih410-b2260.dtb + +diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts +new file mode 100644 +index 000000000000..9a15e204f83b +--- /dev/null ++++ b/arch/arm/dts/ast2600-intel.dts +@@ -0,0 +1,197 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2019-2020 Intel Corporation ++/dts-v1/; ++ ++#include "ast2600-u-boot.dtsi" ++ ++/ { ++ memory { ++ device_type = "memory"; ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ chosen { ++ stdout-path = &uart5; ++ }; ++ ++ aliases { ++ spi0 = &fmc; ++ ethernet1 = &mac1; ++ }; ++ ++ cpus { ++ cpu@0 { ++ clock-frequency = <800000000>; ++ }; ++ cpu@1 { ++ clock-frequency = <800000000>; ++ }; ++ }; ++ ++ 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 { ++ u-boot,dm-pre-reloc; ++ status = "okay"; ++}; ++ ++&sdrammc { ++ clock-frequency = <400000000>; ++}; ++ ++&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"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ethphy1: ethernet-phy@1 { ++ reg = <0>; ++ }; ++ ++ ethphy2: ethernet-phy@2 { ++ reg = <0>; ++ }; ++ ++ ethphy3: ethernet-phy@3 { ++ reg = <0>; ++ }; ++ ++ ethphy4: ethernet-phy@4 { ++ reg = <0>; ++ }; ++}; ++ ++&mac1 { ++ status = "okay"; ++ phy-mode = "rgmii"; ++ phy-handle = <ðphy2>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mac2link_default &pinctrl_mdio2_default>; ++}; ++ ++&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>; ++ }; ++}; ++ ++&emmc_slot0 { ++ status = "okay"; ++ bus-width = <4>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_emmc_default>; ++}; ++ ++&i2c4 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c5_default>; ++}; ++ ++&i2c5 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c6_default>; ++}; ++ ++&i2c6 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c7_default>; ++}; ++ ++&i2c7 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c8_default>; ++}; ++ ++&i2c8 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c9_default>; ++}; ++ ++&i2c9 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c10_default>; ++}; ++ ++&i2c12 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c13_default>; ++}; ++ ++&i2c13 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c14_default>; ++}; +\ No newline at end of file +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 518f41b558d3..8023397cff58 100644 +--- a/arch/arm/mach-aspeed/ast2600/Kconfig ++++ b/arch/arm/mach-aspeed/ast2600/Kconfig +@@ -51,6 +51,13 @@ config TARGET_SLT_AST2600 + help + SLT-AST2600 is Aspeed SLT board for AST2600 chip. + ++config TARGET_AST2600_INTEL ++ bool "AST2600-INTEL" ++ depends on ASPEED_AST2600 ++ help ++ AST2600-INTEL is an Intel server board with the AST2600 ++ as the BMC. ++ + endchoice + + config ASPEED_SECBOOT_BL2 +@@ -71,5 +78,6 @@ source "board/aspeed/ncsi_ast2600a0/Kconfig" + source "board/aspeed/ncsi_ast2600a1/Kconfig" + source "board/aspeed/fpga_ast2600/Kconfig" + source "board/aspeed/slt_ast2600/Kconfig" ++source "board/aspeed/ast2600_intel/Kconfig" + + endif +diff --git a/board/aspeed/ast2600_intel/Kconfig b/board/aspeed/ast2600_intel/Kconfig +new file mode 100644 +index 000000000000..b841dab60c76 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/Kconfig +@@ -0,0 +1,13 @@ ++if TARGET_AST2600_INTEL ++ ++config SYS_BOARD ++ default "ast2600_intel" ++ ++config SYS_VENDOR ++ default "aspeed" ++ ++config SYS_CONFIG_NAME ++ string "board configuration name" ++ default "ast2600_intel" ++ ++endif +diff --git a/board/aspeed/ast2600_intel/Makefile b/board/aspeed/ast2600_intel/Makefile +new file mode 100644 +index 000000000000..37d2f0064f38 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/Makefile +@@ -0,0 +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 +new file mode 100644 +index 000000000000..4a40a050c3da +--- /dev/null ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -0,0 +1,192 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2019-2020, Intel Corporation. ++ ++/* Intel customizations of Das U-Boot */ ++#include <common.h> ++#include <asm/gpio.h> ++#include <asm/io.h> ++ ++/* 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) ++{ ++ 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 */ ++ ++static void port80h_snoop_init(void) ++{ ++ uint32_t value; ++ /* enable port80h snoop and sgpio */ ++ /* set lpc snoop #0 to port 0x80 */ ++ value = readl(AST_LPC_BASE + SNPWADR) & 0xffff0000; ++ writel(value | LPC_SNOOP_ADDR, AST_LPC_BASE + SNPWADR); ++ ++ /* clear interrupt status */ ++ 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 */ ++ 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 */ ++ value = readl(AST_LPC_BASE + HICRB) | HICRB_EN80HSGIO; ++ 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) ++ ++ uint32_t value; ++ /* set the sgpio clock to pclk/(2*(5+1)) or ~2 MHz */ ++ value = SGPIO_CLK_DIV(256) | 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); ++} ++ ++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! */ ++ /* 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; ++} ++ ++extern void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler); ++int board_early_init_r(void) ++{ ++ debug("board_early_init_r\n"); ++ /* timer_enable(0, 1, timer_handler); */ ++ ++ return 0; ++} ++ ++extern void espi_init(void); ++int board_late_init(void) ++{ ++ espi_init(); ++ ++ return 0; ++} ++ ++/* 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 +old mode 100755 +new mode 100644 +index 2e2df2e3a235..77c39d848312 +--- a/configs/ast2600_openbmc_defconfig ++++ b/configs/ast2600_openbmc_defconfig +@@ -13,7 +13,7 @@ CONFIG_FIT=y + CONFIG_USE_BOOTARGS=y + CONFIG_BOOTARGS="console=ttyS4,115200n8 root=/dev/ram rw" + CONFIG_USE_BOOTCOMMAND=y +-CONFIG_BOOTCOMMAND="bootm 20100000" ++CONFIG_BOOTCOMMAND="bootm 20080000" + CONFIG_SYS_CONSOLE_ENV_OVERWRITE=y + CONFIG_DISPLAY_BOARDINFO_LATE=y + CONFIG_ARCH_EARLY_INIT_R=y +-- +2.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..326f36df1 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0003-ast2600-intel-layout-environment-addr.patch @@ -0,0 +1,67 @@ +From 3195e1ec2d772d5e4c16ae5b60c294086cfc17be 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 | 13 ++++++++++--- + include/configs/aspeed-common.h | 11 ++++++++++- + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/common/board_r.c b/common/board_r.c +index 472987d5d52f..b665d0e30262 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()) +- env_relocate(); +- else ++ 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 { + 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 cdbffc97a223..6065ec58db0a 100644 +--- a/include/configs/aspeed-common.h ++++ b/include/configs/aspeed-common.h +@@ -65,9 +65,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.7.4 + diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0004-AST2600-Adjust-default-GPIO-settings.patch 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..d5bd4a2b1 --- /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 c1561193296d04dd8bd06adca43edac814058367 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 3 Jan 2020 12:52:29 +0800 +Subject: [PATCH] Enable interrupt in u-boot. + +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 305b265ed713..a6f68cd13d54 100644 +--- a/Kconfig ++++ b/Kconfig +@@ -239,6 +239,20 @@ config BUILD_TARGET + special image will be automatically built upon calling + make / buildman. + ++config USE_IRQ ++ bool "Use interrupts" ++ default n ++ ++config STACKSIZE_IRQ ++ depends on USE_IRQ ++ int "Size for IRQ stack (only if USE_IRQ enabled)" ++ default 16384 ++ ++config STACKSIZE_FIQ ++ depends on USE_IRQ ++ int "Size for FIQ stack (only if USE_IRQ enabled)" ++ default 16384 ++ + endmenu # General setup + + menu "Boot images" +diff --git a/arch/arm/lib/stack.c b/arch/arm/lib/stack.c +index c89a219dd26d..d9a7f49c5623 100644 +--- a/arch/arm/lib/stack.c ++++ b/arch/arm/lib/stack.c +@@ -24,6 +24,15 @@ int arch_reserve_stacks(void) + gd->irq_sp = gd->start_addr_sp; + + # if !defined(CONFIG_ARM64) ++# ifdef CONFIG_USE_IRQ ++ gd->start_addr_sp -= (CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ); ++ printf("Reserving %zu Bytes for IRQ stack at: %08lx\n", ++ CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ, gd->start_addr_sp); ++ ++ /* 8-byte alignment for ARM ABI compliance */ ++ gd->start_addr_sp &= ~0x07; ++# endif ++ + /* leave 3 words for abort-stack, plus 1 for alignment */ + gd->start_addr_sp -= 16; + # endif +diff --git a/arch/arm/lib/vectors.S b/arch/arm/lib/vectors.S +index 2ca6e2494a7a..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 ac108c3a066c..22a377d2cb77 100644 +--- a/board/aspeed/ast2600_intel/intel.c ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -209,7 +209,6 @@ static void timer_handler(void *regs) + printf("+"); + } + +-extern int arch_interrupt_init_early(void); + int board_early_init_f(void) + { + /* This is called before relocation; beware! */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/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..720d165c5 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0006-SPI-Quad-IO-Mode.patch @@ -0,0 +1,102 @@ +From fd0768e6a63a25fdc87596036a5cbf82a88a1eb6 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 9a15e204f83b..1f14753056ee 100644 +--- a/arch/arm/dts/ast2600-intel.dts ++++ b/arch/arm/dts/ast2600-intel.dts +@@ -120,16 +120,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 3b0a910d3fca..d6b949170570 100644 +--- a/drivers/mtd/spi/spi-nor-ids.c ++++ b/drivers/mtd/spi/spi-nor-ids.c +@@ -164,7 +164,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("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) }, + #endif +diff --git a/drivers/spi/aspeed_spi.c b/drivers/spi/aspeed_spi.c +index 18d4c2fa098e..6efb8c4e3c65 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 */ +@@ -1037,6 +1040,19 @@ static int aspeed_spi_bind(struct udevice *bus) + return 0; + } + ++static int aspeed_get_max_freq(void) ++{ ++ u32 rev_id = readl(ASPEED_REVISION_ID); ++ ++ /*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; +@@ -1067,7 +1083,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..2a2d1054a --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0007-ast2600-Override-OTP-strap-settings.patch @@ -0,0 +1,78 @@ +From 6f9d529b616ce84271ccd2584b9bcd8d13ab57de 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 | 26 ++++++++++++++++++++++--- + 1 file changed, 23 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S +index f193c66cd04b..997670b66bdc 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_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) +@@ -173,6 +175,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] +@@ -262,19 +284,17 @@ skip_fill_wip_bit: + ldr r1, =AST_FMC_WDT1_CTRL_MODE + str r0, [r1] + +-#if 0 + /* disable UART-based SoC Debug Interface UART5 and P2A bridge*/ + ldr r0, =AST_SCU_DEBUG_CTRL + ldr r1, [r0] + orr r1, #0x03 + str r1, [r0] +- ++ + /* disable UART-based SoC Debug Interface UART1 and LPC2AHB bridge */ + ldr r0, =AST_SCU_DEBUG_CTRL2 + ldr r1, [r0] + orr r1, #0x0A + str r1, [r0] +-#endif + + /* relocate mailbox insn. for cpuN polling SMP go signal */ + adrl r0, mailbox_insn +-- +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..6b417fae9 --- /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 ec8377bb77dd560b3f03f02361d268b362e28e7f 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 d03a446846bc..ebf883144418 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..f47092eaa --- /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 f1bfa10fefa992c7032e0c32647543bb2a8dc90f 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 997670b66bdc..6b447845fe26 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -57,6 +57,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) + +@@ -229,6 +235,18 @@ wait_lock: + b 1f + + 0: ++ /* 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 (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..cf13a17f2 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0010-Fix-timer-support.patch @@ -0,0 +1,173 @@ +From bd4eb78dc71529342e5d0b784731c412cf747acc Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 20 Apr 2020 10:42:05 -0700 +Subject: [PATCH] Fix timer support + +Timer interrupt flag should be cleared just after it gets an +interrupt otherwise the interrupt will be called infinitely and +main context will starve resultingly. To fix this issue, this +commit adds the timer interrupt flag clearing logic. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + board/aspeed/ast2600_intel/ast-timer.c | 69 ++++++++++++++++++++-------------- + board/aspeed/ast2600_intel/intel.c | 13 ++++--- + 2 files changed, 48 insertions(+), 34 deletions(-) + +diff --git a/board/aspeed/ast2600_intel/ast-timer.c b/board/aspeed/ast2600_intel/ast-timer.c +index cf8c69aba5d3..d98ec9238e15 100644 +--- a/board/aspeed/ast2600_intel/ast-timer.c ++++ b/board/aspeed/ast2600_intel/ast-timer.c +@@ -1,59 +1,72 @@ +-/* +- * Copyright 2019 Intel Corporation +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License +- * as published by the Free Software Foundation; either version +- * 2 of the License, or (at your option) any later version. +- */ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2019-2020, Intel Corporation. + + #include <common.h> + #include <asm/io.h> + + static const int timer_irqs[] = {48, 49, 50, 51, 52, 53, 54, 55}; ++static void (*timer_callback[ARRAY_SIZE(timer_irqs)]) (void *) = {NULL}; ++static void *cb_cookie[ARRAY_SIZE(timer_irqs)] = {NULL}; ++ + #define AST_TIMER_BASE 0x1e782000 + /* offsets from AST_TIMER_BASE for each timer */ +-static const uint32_t timer_bases[] = {0, 0x10, 0x20, 0x40, +- 0x50, 0x60, 0x70, 0x80}; +-#define TIMER_1MHZ_CLK_COUNT 1000000u ++static const u32 timer_bases[] = {0, 0x10, 0x20, 0x40, 0x50, 0x60, 0x70, 0x80}; + #define TIMER_ENABLE 1 + #define TIMER_1MHZ_CLK_SEL 2 + #define TIMER_ENABLE_IRQ 4 + #define TIMER_RESET_BY_WDT 8 + #define TIMER_CONTROL 0x30 ++#define TIMER_INT_CLR 0x34 + #define TIMER_RELOAD 0x04 + #define TIMER_CONTROL_CLEAR 0x3c + ++static void timer_irq_handler(void *cookie) ++{ ++ int timer_nr = (int)cookie; ++ ++ writel(1 << timer_nr, AST_TIMER_BASE + TIMER_INT_CLR); ++ ++ if (timer_callback[timer_nr]) ++ timer_callback[timer_nr](cb_cookie[timer_nr]); ++} ++ + void timer_disable(int n) + { +- if (n < 0 || n > 7) { ++ u32 tctrl; ++ ++ if (n < 0 || n > 7) + return; +- } +- uint32_t tctrl = 0xf << (n * 4); ++ ++ irq_free_handler(timer_irqs[n]); ++ timer_callback[n] = NULL; ++ cb_cookie[n] = NULL; ++ ++ tctrl = 0xf << (n * 4); + writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL_CLEAR); + } + +-void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler) ++void timer_enable(uint n, u32 interval_us, interrupt_handler_t *handler, ++ void *cookie) + { +- if (n < 0 || n > 7) { +- return; +- } +- if (!freq) ++ u32 tctrl; ++ ++ if (n < 0 || n > 7 || !interval_us) + return; + + timer_disable(n); + +- uint32_t v = TIMER_1MHZ_CLK_COUNT / freq; +- writel(v, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD); ++ writel(interval_us, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD); + +- uint32_t tctrl = ( +- TIMER_ENABLE | +- TIMER_1MHZ_CLK_SEL | +- TIMER_RESET_BY_WDT) << (n * 4); ++ tctrl = (TIMER_ENABLE | TIMER_1MHZ_CLK_SEL | ++ TIMER_RESET_BY_WDT) << (n * 4) | TIMER_ENABLE_IRQ << (n * 4); + + if (handler) { +- irq_install_handler(timer_irqs[n], handler, NULL); +- tctrl |= (TIMER_ENABLE_IRQ << (n * 4)); ++ timer_callback[n] = handler; ++ cb_cookie[n] = cookie; + } +- writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL); ++ ++ irq_install_handler(timer_irqs[n], timer_irq_handler, (void *)n); ++ ++ writel(readl(AST_TIMER_BASE + TIMER_CONTROL) | tctrl, ++ AST_TIMER_BASE + TIMER_CONTROL); + } +diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c +index 47e5ad21d66d..befeaff0a953 100644 +--- a/board/aspeed/ast2600_intel/intel.c ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -219,16 +219,14 @@ void enable_onboard_tpm(void) + AST_GPIO_BASE | GPIO_000); + } + +-static void timer_handler(void *regs) ++static void timer_callback(void *cookie) + { +- printf("+"); ++ debug("+"); + } + + int board_early_init_f(void) + { + /* This is called before relocation; beware! */ +- /* initialize running timer? timer_init is next in the list but +- * I am not sure if it actually does anything... */ + arch_interrupt_init_early(); + + set_gpio_default_state(); +@@ -243,11 +241,9 @@ int board_early_init_f(void) + return 0; + } + +-extern void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler); + int board_early_init_r(void) + { + debug("board_early_init_r\n"); +- /* timer_enable(0, 1, timer_handler); */ + + enable_onboard_tpm(); + +@@ -255,8 +251,13 @@ int board_early_init_r(void) + } + + extern void espi_init(void); ++extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler, ++ void *cookie); + int board_late_init(void) + { ++#define ONE_SEC_IN_USEC 1000000 ++ ++ timer_enable(0, ONE_SEC_IN_USEC, timer_callback, (void *)0); + espi_init(); + + return 0; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0011-KCS-driver-support-in-uBoot.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0011-KCS-driver-support-in-uBoot.patch new file mode 100644 index 000000000..f446d797a --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0011-KCS-driver-support-in-uBoot.patch @@ -0,0 +1,614 @@ +From 1fbd857e2ff5396ea057f686cbd01c6db4328316 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 20 Apr 2020 11:08:22 -0700 +Subject: [PATCH] KCS driver support in uBoot + +Added KCS support in uBoot. This will enable +KCS channels and set the specified registers +to do KCS communication in uBoot. It also +consist of read and write KCS message transations +work flow implementation( As specified in IPMI +specification Section 9.15). It is enabled +only when Force Firmware Update Jumper is ON. + +Tested: +Stopped booting in uBoot and sent IPMI commands +via KCS interfaces using cmdtool.efi. + - Get Device ID: + Req: cmdtool.efi 20 18 1 + Res: 00 23 00 12 03 02 BF 57 01 00 7B 00 00 00 00 00 + - Get Self Test Results + Req: cmdtool.efi 20 18 4 + Res: 00 56 00 + - All other commands + Req: cmdtool.efi 20 18 2 + Res: C1 (Invalid). + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + board/aspeed/ast2600_intel/Makefile | 1 + + board/aspeed/ast2600_intel/ast-kcs.c | 418 +++++++++++++++++++++++++++++++++++ + board/aspeed/ast2600_intel/ast-kcs.h | 112 ++++++++++ + board/aspeed/ast2600_intel/intel.c | 4 + + 4 files changed, 535 insertions(+) + create mode 100644 board/aspeed/ast2600_intel/ast-kcs.c + create mode 100644 board/aspeed/ast2600_intel/ast-kcs.h + +diff --git a/board/aspeed/ast2600_intel/Makefile b/board/aspeed/ast2600_intel/Makefile +index 37d2f0064f38..d049922719f3 100644 +--- a/board/aspeed/ast2600_intel/Makefile ++++ b/board/aspeed/ast2600_intel/Makefile +@@ -2,3 +2,4 @@ obj-y += intel.o + obj-y += ast-espi.o + obj-y += ast-irq.o + obj-y += ast-timer.o ++obj-y += ast-kcs.o +diff --git a/board/aspeed/ast2600_intel/ast-kcs.c b/board/aspeed/ast2600_intel/ast-kcs.c +new file mode 100644 +index 000000000000..a03b7e725370 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/ast-kcs.c +@@ -0,0 +1,418 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2020 Intel Corporation ++ ++#include "ast-kcs.h" ++ ++#ifdef DEBUG_KCS_ENABLED ++#define DBG_KCS printf ++#else ++#define DBG_KCS(...) ++#endif ++ ++/* TODO: Move to IPMI file. */ ++#define IPMI_CC_OK 0x00 ++#define IPMI_CC_INVALID 0xC1 ++#define IPMI_CC_UNSPECIFIED 0xFF ++ ++#define KCS_CHANNEL_NO_3 3 ++ ++static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 }; ++ ++static const struct kcs_io_reg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = { ++ { .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 }, ++ { .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 }, ++ { .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 }, ++ { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 } ++}; ++ ++#define NO_OF_ENABLED_KCS_CHANNELS ARRAY_SIZE(enabled_kcs_channel) ++ ++static struct kcs_packet m_kcs_pkt[NO_OF_ENABLED_KCS_CHANNELS]; ++ ++static u16 read_status(u16 channel_num) ++{ ++ return readl(AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].str); ++} ++ ++static void write_status(u16 channel_num, u16 value) ++{ ++ writel(value, AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].str); ++} ++ ++static u16 read_data(u16 channel_num) ++{ ++ return readl(AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].idr); ++} ++ ++static void write_data(u16 channel_num, u16 value) ++{ ++ writel(value, AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].odr); ++} ++ ++static void set_kcs_state(u16 channel_num, u16 state) ++{ ++ u16 status = read_status(channel_num); ++ ++ status &= ~KCS_STATE_MASK; ++ status |= KCS_STATE(state) & KCS_STATE_MASK; ++ write_status(channel_num, status); ++} ++ ++static struct kcs_packet *get_kcs_packet(u16 channel_num) ++{ ++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) { ++ if (channel_num == enabled_kcs_channel[idx]) ++ return &m_kcs_pkt[idx]; ++ } ++ ++ /* very unlike code hits here. */ ++ DBG_KCS("ERROR: %s error. ChannelNo: %d\n", __func__, channel_num); ++ BUG(); ++} ++ ++static void kcs_force_abort(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ DBG_KCS("ERROR: KCS communication aborted (Channel:%d, Error:%d)\n", ++ channel_num, kcs_pkt->error); ++ set_kcs_state(channel_num, KCS_STATE_ERROR); ++ read_data(channel_num); ++ write_data(channel_num, ZERO_DATA); ++ ++ kcs_pkt->phase = KCS_PHASE_ERROR; ++ kcs_pkt->read_req_done = false; ++ kcs_pkt->data_in_idx = 0; ++} ++ ++static void init_kcs_packet(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ kcs_pkt->channel = channel_num; ++ kcs_pkt->read_req_done = false; ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ kcs_pkt->error = KCS_NO_ERROR; ++ kcs_pkt->data_in_idx = 0; ++ kcs_pkt->data_out_idx = 0; ++ kcs_pkt->data_out_len = 0; ++} ++ ++static void process_kcs_request(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ int i; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ if (!kcs_pkt->read_req_done) ++ return; ++ ++ DBG_KCS("%s:- chan:%d\n", __func__, channel_num); ++ ++#ifdef DEBUG_KCS_ENABLED ++ DBG_KCS("Request data(Len:%d): ", kcs_pkt->data_in_idx); ++ for (i = 0; i < kcs_pkt->data_in_idx; i++) ++ DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]); ++ DBG_KCS("\n"); ++#endif ++ ++ /* ++ * TODO: Move it to IPMI Command Handler ++ * Below code is added for timebeing till ++ * we implement the IPMI command handler. ++ */ ++ kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */ ++ kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */ ++ ++ if (((kcs_pkt->data_in[0] >> 2) == 0x06) && ++ (kcs_pkt->data_in[1] == 0x01)) { ++ /* Get Device ID */ ++ u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02, ++ 0xBF, 0x57, 0x01, 0x00, 0x7B, ++ 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ for (i = 0; i < 15; i++) ++ kcs_pkt->data_out[i + 3] = device_id[i]; ++ kcs_pkt->data_out_len = 18; ++ } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) && ++ (kcs_pkt->data_in[1] == 0x04)) { ++ /* Get Self Test Results */ ++ kcs_pkt->data_out[3] = 0x56; ++ kcs_pkt->data_out[4] = 0x00; ++ kcs_pkt->data_out_len = 5; ++ } else { ++ kcs_pkt->data_out[2] = ++ IPMI_CC_INVALID; /* Invalid or not supported. */ ++ kcs_pkt->data_out_len = 3; ++ } ++ /* END: TODO */ ++ ++#ifdef DEBUG_KCS_ENABLED ++ DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len); ++ for (i = 0; i < kcs_pkt->data_out_len; i++) ++ DBG_KCS(" 0x%02x", kcs_pkt->data_out[i]); ++ DBG_KCS("\n"); ++#endif ++ ++ kcs_pkt->phase = KCS_PHASE_READ; ++ write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]); ++ kcs_pkt->read_req_done = false; ++} ++ ++static void read_kcs_data(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ ++ switch (kcs_pkt->phase) { ++ case KCS_PHASE_WRITE_START: ++ kcs_pkt->phase = KCS_PHASE_WRITE_DATA; ++ /* fall through */ ++ ++ case KCS_PHASE_WRITE_DATA: ++ if (kcs_pkt->data_in_idx >= MAX_KCS_PKT_SIZE) { ++ kcs_pkt->error = KCS_LENGTH_ERROR; ++ kcs_force_abort(channel_num); ++ return; ++ } ++ set_kcs_state(channel_num, KCS_STATE_WRITE); ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->data_in[kcs_pkt->data_in_idx++] = ++ read_data(channel_num); ++ break; ++ ++ case KCS_PHASE_WRITE_END: ++ if (kcs_pkt->data_in_idx >= MAX_KCS_PKT_SIZE) { ++ kcs_pkt->error = KCS_LENGTH_ERROR; ++ kcs_force_abort(channel_num); ++ return; ++ } ++ set_kcs_state(channel_num, KCS_STATE_READ); ++ kcs_pkt->data_in[kcs_pkt->data_in_idx++] = ++ read_data(channel_num); ++ kcs_pkt->phase = KCS_PHASE_READ_WAIT; ++ kcs_pkt->read_req_done = true; ++ ++ process_kcs_request(channel_num); ++ break; ++ ++ case KCS_PHASE_READ: ++ if (kcs_pkt->data_out_idx == kcs_pkt->data_out_len) ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ ++ u8 data = read_data(channel_num); ++ if (data != KCS_CTRL_CODE_READ) { ++ DBG_KCS("Invalid Read data. Phase:%d, Data:0x%02x\n", ++ kcs_pkt->phase, data); ++ set_kcs_state(channel_num, KCS_STATE_ERROR); ++ write_data(channel_num, ZERO_DATA); ++ break; ++ } ++ ++ if (kcs_pkt->data_out_idx == kcs_pkt->data_out_len) { ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ break; ++ } ++ write_data(channel_num, ++ kcs_pkt->data_out[kcs_pkt->data_out_idx++]); ++ break; ++ ++ case KCS_PHASE_ABORT_1: ++ set_kcs_state(channel_num, KCS_STATE_READ); ++ read_data(channel_num); ++ write_data(channel_num, kcs_pkt->error); ++ kcs_pkt->phase = KCS_PHASE_ABORT_2; ++ break; ++ ++ case KCS_PHASE_ABORT_2: ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ read_data(channel_num); ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ break; ++ ++ default: ++ kcs_force_abort(channel_num); ++ } ++} ++ ++static void read_kcs_cmd(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ ++ set_kcs_state(channel_num, KCS_STATE_WRITE); ++ write_data(channel_num, ZERO_DATA); ++ ++ u16 cmd = read_data(channel_num); ++ switch (cmd) { ++ case KCS_CTRL_CODE_WRITE_START: ++ init_kcs_packet(channel_num); ++ kcs_pkt->phase = KCS_PHASE_WRITE_START; ++ break; ++ ++ case KCS_CTRL_CODE_WRITE_END: ++ if (kcs_pkt->error != KCS_NO_ERROR) { ++ kcs_force_abort(channel_num); ++ return; ++ } ++ ++ kcs_pkt->phase = KCS_PHASE_WRITE_END; ++ break; ++ ++ case KCS_CTRL_CODE_GET_STATUS_ABORT: ++ kcs_pkt->phase = KCS_PHASE_ABORT_1; ++ kcs_pkt->error = KCS_ABORT_BY_CMD; ++ break; ++ ++ default: ++ kcs_pkt->error = KCS_ILLEGAL_CTRL_CMD; ++ kcs_force_abort(channel_num); ++ } ++} ++ ++static void kcs_irq_handler(void *cookie) ++{ ++ u32 channel_num = (u32)cookie; ++ /* Look-up the interrupted KCS channel */ ++ u16 status = read_status(channel_num); ++ if (status & BIT_STATUS_IBF) { ++ if (status & BIT_STATUS_COD) ++ read_kcs_cmd(channel_num); ++ else ++ read_kcs_data(channel_num); ++ } ++ ++ DBG_KCS("%s: chan_no: %d\n", __FUNC__, channel_num); ++} ++ ++static void set_kcs_channel_addr(u16 channel_num) ++{ ++ u32 val; ++ ++ switch (channel_num) { ++ case 1: ++ val = readl(AST_LPC_BASE + LPC_HICR4) & ~BIT_LADR12AS; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = (KCS_CHANNEL1_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR12H); ++ val = (KCS_CHANNEL1_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR12L); ++ break; ++ ++ case 2: ++ val = readl(AST_LPC_BASE + LPC_HICR4) | BIT_LADR12AS; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = (KCS_CHANNEL2_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR12H); ++ val = (KCS_CHANNEL2_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR12L); ++ break; ++ ++ case 3: ++ val = (KCS_CHANNEL3_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR3H); ++ val = (KCS_CHANNEL3_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR3L); ++ break; ++ ++ case 4: ++ val = (((KCS_CHANNEL4_ADDR + 1) << 16) | KCS_CHANNEL4_ADDR); ++ writel(val, AST_LPC_BASE + LPC_LADR4); ++ break; ++ ++ default: ++ DBG_KCS("Invalid channel (%d) specified\n", channel_num); ++ break; ++ } ++} ++ ++static void enable_kcs_channel(u16 channel_num, u16 enable) ++{ ++ u32 val; ++ ++ switch (channel_num) { ++ case 1: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE1; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC1E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC1E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE1; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 2: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE2; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC2E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC2E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE2; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 3: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE3; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC3E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR4) | BIT_KCSENBL; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC3E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR4) & ~BIT_KCSENBL; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE3; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 4: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICRB) | BIT_IBFIE4 | ++ BIT_LPC4E; ++ writel(val, AST_LPC_BASE + LPC_HICRB); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICRB) & ++ ~(BIT_IBFIE4 | BIT_LPC4E); ++ writel(val, AST_LPC_BASE + LPC_HICRB); ++ } ++ break; ++ ++ default: ++ DBG_KCS("Invalid channel (%d) specified\n", channel_num); ++ } ++} ++ ++void kcs_init(void) ++{ ++ /* Initialize the KCS channels. */ ++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) { ++ uint channel_num = (uint)enabled_kcs_channel[idx]; ++ DBG_KCS("%s Channel: %d\n", __func__, channel_num); ++ set_kcs_channel_addr(channel_num); ++ enable_kcs_channel(channel_num, 1); ++ ++ /* Set KCS channel state to idle */ ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ /* KCS interrupt */ ++ irq_install_handler(IRQ_SRC_KCS_BASE + channel_num - 1, ++ kcs_irq_handler, (void *)channel_num); ++ } ++} +diff --git a/board/aspeed/ast2600_intel/ast-kcs.h b/board/aspeed/ast2600_intel/ast-kcs.h +new file mode 100644 +index 000000000000..e9b949eccf69 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/ast-kcs.h +@@ -0,0 +1,112 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2018-2020 Intel Corporation */ ++ ++#include <asm/io.h> ++#include <common.h> ++ ++#define KCS_CHANNEL_MAX 4 ++#define IRQ_SRC_KCS_BASE 170 /* IRQ 170 */ ++#define MAX_KCS_PKT_SIZE (64 * 1024) ++/* KCS channel addresses */ ++#define KCS_CHANNEL1_ADDR 0xCA0 ++#define KCS_CHANNEL2_ADDR 0xCA8 ++#define KCS_CHANNEL3_ADDR 0xCA2 /* KCS SMS */ ++#define KCS_CHANNEL4_ADDR 0xCA4 /* KCS SMM */ ++ ++#define ZERO_DATA 0x00 ++ ++#define AST_LPC_BASE 0x1e789000 ++ ++/* Aspeed KCS control registers */ ++#define LPC_HICR0 0x00 /* Host Interface Control Register 0 */ ++#define LPC_HICR1 0x04 /* Host Interface Control Register 1 */ ++#define LPC_HICR2 0x08 /* Host Interface Control Register 2 */ ++#define LPC_HICR3 0x0C /* Host Interface Control Register 3 */ ++#define LPC_HICR4 0x10 /* Host Interface Control Register 4 */ ++#define LPC_LADR3H 0x14 /* LPC channel #3 Address Register H */ ++#define LPC_LADR3L 0x18 /* LPC channel #3 Address Register H */ ++#define LPC_LADR12H 0x1C /* LPC channel #1#2 Address Register H */ ++#define LPC_LADR12L 0x20 /* LPC channel #1#2 Address Register L */ ++#define LPC_IDR1 0x24 /* Input Data Register 1 */ ++#define LPC_IDR2 0x28 /* Input Data Register 2 */ ++#define LPC_IDR3 0x2C /* Input Data Register 3 */ ++#define LPC_ODR1 0x30 /* Output Data Register 1 */ ++#define LPC_ODR2 0x34 /* Output Data Register 2 */ ++#define LPC_ODR3 0x38 /* Output Data Register 3 */ ++#define LPC_STR1 0x3C /* Status Register 1 */ ++#define LPC_STR2 0x40 /* Status Register 2 */ ++#define LPC_STR3 0x44 /* Status Register 3 */ ++#define LPC_HICRB 0x100 /* Host Interface Control Register B */ ++#define LPC_LADR4 0x110 /* LPC channel #4 Address Register */ ++#define LPC_IDR4 0x114 /* Input Data Register 4 */ ++#define LPC_ODR4 0x118 /* Output Data Register 4 */ ++#define LPC_STR4 0x11C /* Status Data Register 4 */ ++ ++/* LPC Bits */ ++#define BIT_LADR12AS BIT(7) /* Channel Address selection */ ++#define BIT_IBFIE1 BIT(1) /* Enable IDR1 Recv completion interrupt */ ++#define BIT_IBFIE2 BIT(2) /* Enable IDR2 Recv completion interrupt */ ++#define BIT_IBFIE3 BIT(3) /* Enable IBF13 interrupt */ ++#define BIT_LPC1E BIT(5) /* Enable LPC channel #1 */ ++#define BIT_LPC2E BIT(6) /* Enable LPC channel #2 */ ++#define BIT_LPC3E BIT(7) /* Enable LPC channel #2 */ ++#define BIT_KCSENBL BIT(2) /* Enable KCS interface in Channel #3 */ ++#define BIT_IBFIE4 BIT(1) ++#define BIT_LPC4E BIT(0) ++ ++#define BIT_STATUS_OBF BIT(0) /* Output Data Register full #1/#2/#3 */ ++#define BIT_STATUS_IBF BIT(1) /* Input Data Register full #1/#2/#3 */ ++#define BIT_STATUS_COD BIT(3) /* Command/Data - (1=command,0=data) */ ++ ++#define KCS_STATE_MASK 0xC0 /* BIT[6:7] of status register */ ++#define KCS_STATE(state) ((state) << 6) ++ ++/* IPMI2.0(section 9.7) - KCS interface State Bits */ ++#define KCS_STATE_IDLE 0x00 ++#define KCS_STATE_READ 0x01 ++#define KCS_STATE_WRITE 0x02 ++#define KCS_STATE_ERROR 0x03 ++ ++/* IPMI2.0(section 9.10) - KCS interface control codes */ ++#define KCS_CTRL_CODE_GET_STATUS_ABORT 0x60 ++#define KCS_CTRL_CODE_WRITE_START 0x61 ++#define KCS_CTRL_CODE_WRITE_END 0x62 ++#define KCS_CTRL_CODE_READ 0x68 ++ ++struct kcs_io_reg { ++ u32 idr; ++ u32 odr; ++ u32 str; ++}; ++ ++enum kcs_phase { ++ KCS_PHASE_IDLE = 0, ++ KCS_PHASE_WRITE_START = 1, ++ KCS_PHASE_WRITE_DATA = 2, ++ KCS_PHASE_WRITE_END = 3, ++ KCS_PHASE_READ_WAIT = 4, ++ KCS_PHASE_READ = 5, ++ KCS_PHASE_ABORT_1 = 6, ++ KCS_PHASE_ABORT_2 = 7, ++ KCS_PHASE_ERROR = 8 ++}; ++ ++enum kcs_error { ++ KCS_NO_ERROR = 0x00, ++ KCS_ABORT_BY_CMD = 0x01, ++ KCS_ILLEGAL_CTRL_CMD = 0x02, ++ KCS_LENGTH_ERROR = 0x06, ++ KCS_UNSPECIFIED_ERROR = 0xFF, ++}; ++ ++struct kcs_packet { ++ enum kcs_phase phase; ++ enum kcs_error error; ++ u16 channel; ++ bool read_req_done; ++ u16 data_in_idx; ++ u8 data_in[MAX_KCS_PKT_SIZE]; ++ u16 data_out_len; ++ u16 data_out_idx; ++ u8 data_out[MAX_KCS_PKT_SIZE]; ++}; +diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c +index befeaff0a953..6ac24beb930b 100644 +--- a/board/aspeed/ast2600_intel/intel.c ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -251,6 +251,7 @@ int board_early_init_r(void) + } + + extern void espi_init(void); ++extern void kcs_init(void); + extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler, + void *cookie); + int board_late_init(void) +@@ -260,6 +261,9 @@ int board_late_init(void) + timer_enable(0, ONE_SEC_IN_USEC, timer_callback, (void *)0); + espi_init(); + ++ if (read_ffuj()) ++ kcs_init(); ++ + return 0; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0012-IPMI-command-handler-implementation-in-uboot.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0012-IPMI-command-handler-implementation-in-uboot.patch new file mode 100644 index 000000000..a4a574424 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0012-IPMI-command-handler-implementation-in-uboot.patch @@ -0,0 +1,330 @@ +From 19bbdf59f39d295ad3e698b121a0b447b77b927c Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 20 Apr 2020 16:13:09 -0700 +Subject: [PATCH] IPMI command handler implementation in uboot + +IPMI command handler implementation in uBoot. +Implemented IPMI commands: + 1) Get Device ID + 2) Get Self Test Result + +Tested By: +Ran the above IPMI command Via KCS channel +and got proper response. +- Get Device ID + Req: cmdtool.efi 20 18 1 + Res: 0x00 0x23 0x00 0x82 0x03 0x02 0x00 0x57 0x01 0x00 0x7b 0x00 0x00 0x00 0x00 0x00 +- Get Self Test Results + Req: cmdtool.efi 20 18 4 + Res: 00 56 00 + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + board/aspeed/ast2600_intel/Makefile | 1 + + board/aspeed/ast2600_intel/ast-kcs.c | 77 +++++++++++--------- + board/aspeed/ast2600_intel/ipmi-handler.c | 117 ++++++++++++++++++++++++++++++ + board/aspeed/ast2600_intel/ipmi-handler.h | 39 ++++++++++ + 4 files changed, 200 insertions(+), 34 deletions(-) + create mode 100644 board/aspeed/ast2600_intel/ipmi-handler.c + create mode 100644 board/aspeed/ast2600_intel/ipmi-handler.h + +diff --git a/board/aspeed/ast2600_intel/Makefile b/board/aspeed/ast2600_intel/Makefile +index d049922719f3..a0587323afe0 100644 +--- a/board/aspeed/ast2600_intel/Makefile ++++ b/board/aspeed/ast2600_intel/Makefile +@@ -3,3 +3,4 @@ obj-y += ast-espi.o + obj-y += ast-irq.o + obj-y += ast-timer.o + obj-y += ast-kcs.o ++obj-y += ipmi-handler.o +diff --git a/board/aspeed/ast2600_intel/ast-kcs.c b/board/aspeed/ast2600_intel/ast-kcs.c +index a03b7e725370..3889cd9222a4 100644 +--- a/board/aspeed/ast2600_intel/ast-kcs.c ++++ b/board/aspeed/ast2600_intel/ast-kcs.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + // Copyright (c) 2018-2020 Intel Corporation + +-#include "ast-kcs.h" ++#include "ipmi-handler.h" + + #ifdef DEBUG_KCS_ENABLED + #define DBG_KCS printf +@@ -9,11 +9,6 @@ + #define DBG_KCS(...) + #endif + +-/* TODO: Move to IPMI file. */ +-#define IPMI_CC_OK 0x00 +-#define IPMI_CC_INVALID 0xC1 +-#define IPMI_CC_UNSPECIFIED 0xFF +- + #define KCS_CHANNEL_NO_3 3 + + static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 }; +@@ -103,6 +98,7 @@ static void init_kcs_packet(u16 channel_num) + static void process_kcs_request(u16 channel_num) + { + struct kcs_packet *kcs_pkt = NULL; ++ struct ipmi_cmd_data ipmi_data; + int i; + + kcs_pkt = get_kcs_packet(channel_num); +@@ -117,37 +113,49 @@ static void process_kcs_request(u16 channel_num) + DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]); + DBG_KCS("\n"); + #endif ++ u8 req_lun = kcs_pkt->data_in[0] & 0x03; /* LUN[1:0] */ ++ ipmi_data.net_fun = (kcs_pkt->data_in[0] >> 2); /* netfn[7:2] */ ++ ipmi_data.cmd = kcs_pkt->data_in[1]; /* cmd */ ++ /* We support only BMC LUN 00h */ ++ if (req_lun != LUN_BMC) { ++ kcs_pkt->data_out[0] = ++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_INVALID_CMD_LUN; /* CC code */ ++ kcs_pkt->data_out_len = 3; ++ goto done; ++ } + +- /* +- * TODO: Move it to IPMI Command Handler +- * Below code is added for timebeing till +- * we implement the IPMI command handler. +- */ +- kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */ +- kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */ +- kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */ +- +- if (((kcs_pkt->data_in[0] >> 2) == 0x06) && +- (kcs_pkt->data_in[1] == 0x01)) { +- /* Get Device ID */ +- u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02, +- 0xBF, 0x57, 0x01, 0x00, 0x7B, +- 0x00, 0x00, 0x00, 0x00, 0x00 }; +- for (i = 0; i < 15; i++) +- kcs_pkt->data_out[i + 3] = device_id[i]; +- kcs_pkt->data_out_len = 18; +- } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) && +- (kcs_pkt->data_in[1] == 0x04)) { +- /* Get Self Test Results */ +- kcs_pkt->data_out[3] = 0x56; +- kcs_pkt->data_out[4] = 0x00; +- kcs_pkt->data_out_len = 5; +- } else { +- kcs_pkt->data_out[2] = +- IPMI_CC_INVALID; /* Invalid or not supported. */ ++ /* Boundary check */ ++ if ((kcs_pkt->data_in_idx - 2) > sizeof(ipmi_data.req_data)) { ++ kcs_pkt->data_out[0] = ++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_OUT_OF_SPACE; /* CC code */ + kcs_pkt->data_out_len = 3; ++ goto done; + } +- /* END: TODO */ ++ /* Fill in IPMI request data */ ++ ipmi_data.req_len = kcs_pkt->data_in_idx - 2; ++ for (i = 0; i < kcs_pkt->data_in_idx - 2; i++) ++ ipmi_data.req_data[i] = kcs_pkt->data_in[i + 2]; ++ ++ /* Call IPMI command handler */ ++ ipmi_cmd_handler(&ipmi_data); ++ ++ /* Get IPMI response and fill KCS out data */ ++ /* First 2 bytes in KCS response are netFn, Cmd */ ++ kcs_pkt->data_out[0] = GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; ++ if ((ipmi_data.res_len + 2) > sizeof(kcs_pkt->data_out)) { ++ kcs_pkt->data_out[2] = IPMI_CC_UNSPECIFIED; /* CC code */ ++ kcs_pkt->data_out_len = 3; ++ goto done; ++ } ++ for (i = 0; i < ipmi_data.res_len; i++) ++ kcs_pkt->data_out[i + 2] = ipmi_data.res_data[i]; ++ ++ kcs_pkt->data_out_len = ipmi_data.res_len + 2; + + #ifdef DEBUG_KCS_ENABLED + DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len); +@@ -156,6 +164,7 @@ static void process_kcs_request(u16 channel_num) + DBG_KCS("\n"); + #endif + ++done: + kcs_pkt->phase = KCS_PHASE_READ; + write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]); + kcs_pkt->read_req_done = false; +diff --git a/board/aspeed/ast2600_intel/ipmi-handler.c b/board/aspeed/ast2600_intel/ipmi-handler.c +new file mode 100644 +index 000000000000..04732846ac28 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/ipmi-handler.c +@@ -0,0 +1,117 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2020 Intel Corporation ++ ++#include "ipmi-handler.h" ++ ++/* IPMI network function codes */ ++#define NETFN_APP 0x06 ++ ++/* IPMI command codes */ ++#define CMD_GET_DEV_ID 0x01 ++#define CMD_GET_SELF_TEST_RESULTS 0x04 ++ ++typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res); ++ ++struct get_dev_id { ++ u8 completion_code; ++ u8 dev_id; ++ u8 dev_rev; ++ u8 fw_rev1; ++ u8 fw_rev2; ++ u8 ipmi_ver; ++ u8 dev_support; ++ u8 mfg_id[3]; ++ u8 product_id[2]; ++ u8 aux_fw_rev[4]; ++}; ++struct self_test_res { ++ u8 completion_code; ++ u8 res_byte[2]; ++}; ++ ++struct ipmi_cmd_table { ++ u8 net_fun; ++ u8 cmd; ++ fun_handler process_cmd; ++}; ++ ++static u16 get_device_id(u8 *req, u16 req_len, u8 *res) ++{ ++ /* Get Device ID */ ++ bool operation = 1; /* Firmware operation */ ++ u8 intel_mfg_id[3] = { 0x57, 0x01, 0x00 }; ++ u8 platform_id[2] = { 0x7B, 0x00 }; ++ u8 aux_fw_rev[4] = { 0x00, 0x00, 0x00, 0x00 }; ++ struct get_dev_id *result = (struct get_dev_id *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ result->dev_id = 0x23; ++ result->dev_rev = 0x00; /* Not provides dev SDR */ ++ ++ result->ipmi_ver = 0x02; /* IPMI 2.0 */ ++ result->dev_support = 0x00; /* No dev support in this mode */ ++ memcpy(result->mfg_id, intel_mfg_id, sizeof(result->mfg_id)); ++ memcpy(result->aux_fw_rev, aux_fw_rev, sizeof(result->aux_fw_rev)); ++ ++ /* TODO: Get Firmware version from flash(PFM Header) */ ++ result->fw_rev1 = ((operation << 7) | (0x02 & 0x7F)); ++ result->fw_rev2 = 0x03; ++ /* TODO: Read Platform ID from GPIO */ ++ memcpy(result->product_id, platform_id, sizeof(result->product_id)); ++ ++ return sizeof(struct get_dev_id); ++} ++ ++static u16 get_self_test_result(u8 *req, u16 req_len, u8 *res) ++{ ++ /* Get Self Test Results */ ++ struct self_test_res *result = (struct self_test_res *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ result->res_byte[0] = 0x56; /* Self test function not implemented. */ ++ result->res_byte[1] = 0x00; ++ ++ return sizeof(struct self_test_res); ++} ++ ++const struct ipmi_cmd_table cmd_info[] = { ++ { NETFN_APP, CMD_GET_DEV_ID, get_device_id }, ++ { NETFN_APP, CMD_GET_SELF_TEST_RESULTS, get_self_test_result } ++}; ++ ++#define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info) ++ ++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data) ++{ ++ int i = 0; ++ for (i = 0; i < CMD_TABLE_SIZE; i++) { ++ if ((cmd_info[i].net_fun == ipmi_data->net_fun) && ++ (cmd_info[i].cmd == ipmi_data->cmd)) { ++ break; ++ } ++ } ++ ++ if (i == CMD_TABLE_SIZE) { ++ /* Invalid or not supported. */ ++ ipmi_data->res_data[0] = IPMI_CC_INVALID_CMD; ++ ipmi_data->res_len = 1; ++ return; ++ } ++ ++ /* Call the appropriate function handler */ ++ ipmi_data->res_len = ++ cmd_info[i].process_cmd(ipmi_data->req_data, ipmi_data->req_len, ++ &ipmi_data->res_data[0]); ++ ++ return; ++} +diff --git a/board/aspeed/ast2600_intel/ipmi-handler.h b/board/aspeed/ast2600_intel/ipmi-handler.h +new file mode 100644 +index 000000000000..11a2e91fe2c2 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/ipmi-handler.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2018-2020 Intel Corporation */ ++ ++#include "ast-kcs.h" ++ ++/* IPMI completion codes */ ++#define IPMI_CC_OK 0x00 ++#define IPMI_CC_NODE_BUSY 0xC0 ++#define IPMI_CC_INVALID_CMD 0xC1 ++#define IPMI_CC_INVALID_CMD_LUN 0xC2 ++#define IPMI_CC_OUT_OF_SPACE 0xC4 ++#define IPMI_CC_INVALID_DATA_LENGTH 0xC7 ++#define IPMI_CC_INVALID_DATA_FIELD 0xCC ++#define IPMI_CC_UNSPECIFIED 0xFF ++ ++/* BMC IPMB LUNs */ ++#define LUN_BMC 0x00 ++#define LUN_OEM1 0x01 ++#define LUN_SMS 0x02 ++#define LUN_OEM2 0x01 ++ ++ ++#define MAX_IPMI_REQ_DATA_SIZE MAX_KCS_PKT_SIZE ++#define MAX_IPMI_RES_DATA_SIZE 64 ++ ++/* Response netFn[7:2], Lun[1:0] */ ++#define GET_RESP_NETFN_LUN(lun, netfn) \ ++ ((lun & 0x03) | (((netfn + 1) << 2) & 0xFD)) ++ ++struct ipmi_cmd_data { ++ u8 net_fun; ++ u8 cmd; ++ u16 req_len; ++ u16 res_len; ++ u8 req_data[MAX_IPMI_REQ_DATA_SIZE]; ++ u8 res_data[MAX_IPMI_RES_DATA_SIZE]; ++}; ++ ++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0013-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0013-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch new file mode 100644 index 000000000..7d7b450a8 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0013-Add-a-workaround-to-cover-UART-interrupt-bug-in-AST2.patch @@ -0,0 +1,58 @@ +From 2d0a3aff4c4aa3a764958579ed10a3aab43a7d8a Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 27 Apr 2020 12:40:01 -0700 +Subject: [PATCH] Add a workaround to cover UART interrupt bug in AST2600 A0 + +This commit adds a workaround to cover UART interrupt bug in +AST2600 A0 revision. It makes infinite reading on the UART +0x7c +register for clearing abnormal interrupts in every milli-second. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + board/aspeed/ast2600_intel/intel.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c +index 6ac24beb930b..ad5ab7632447 100644 +--- a/board/aspeed/ast2600_intel/intel.c ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -221,7 +221,19 @@ void enable_onboard_tpm(void) + + static void timer_callback(void *cookie) + { +- debug("+"); ++ uint timer_nr = (uint)cookie; ++ u32 dummy; ++ ++ switch (timer_nr) { ++ case 0: ++ /* WA for UART interrupt bug in A0 */ ++ dummy = readl(0x1e78307c); ++ dummy = readl(0x1e78407c); ++ dummy = readl(0x1e78d07c); ++ dummy = readl(0x1e78e07c); ++ dummy = readl(0x1e78f07c); ++ break; ++ } + } + + int board_early_init_f(void) +@@ -256,9 +268,13 @@ extern void timer_enable(int n, u32 interval_us, interrupt_handler_t *handler, + void *cookie); + int board_late_init(void) + { +-#define ONE_SEC_IN_USEC 1000000 ++#define SCU_014 0x014 /* Silicon Revision ID */ ++#define REV_ID_AST2600A0 0x05000303 /* AST2600 A0 */ ++#define ONE_MSEC_IN_USEC 1000 ++ ++ if (readl(SCU_BASE | SCU_014) == REV_ID_AST2600A0) ++ timer_enable(0, ONE_MSEC_IN_USEC, timer_callback, (void *)0); + +- timer_enable(0, ONE_SEC_IN_USEC, timer_callback, (void *)0); + espi_init(); + + if (read_ffuj()) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0014-Add-a-workaround-to-cover-eSPI-OOB-free-bug-in-AST26.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0014-Add-a-workaround-to-cover-eSPI-OOB-free-bug-in-AST26.patch new file mode 100644 index 000000000..0a8333e7d --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0014-Add-a-workaround-to-cover-eSPI-OOB-free-bug-in-AST26.patch @@ -0,0 +1,138 @@ +From 40ab08221b6f8d67d154d8f91b8e55a11d412120 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 27 Apr 2020 17:05:09 -0700 +Subject: [PATCH] Add a workaround to cover eSPI OOB free bug in AST2600 A0 + +This commit adds a workaround to cover eSPI OOB free bug in AST2600 +A0 revision. It enables GPIO W7 interrupt to catch eSPI reset signal +and it sets when the reset signal is deasserted to manually set the +OOB free bit in eSPI protocol. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + board/aspeed/ast2600_intel/ast-espi.c | 79 ++++++++++++++++++++++++++--------- + 1 file changed, 59 insertions(+), 20 deletions(-) + +diff --git a/board/aspeed/ast2600_intel/ast-espi.c b/board/aspeed/ast2600_intel/ast-espi.c +index 1d7ae529612d..a8b389f159ef 100644 +--- a/board/aspeed/ast2600_intel/ast-espi.c ++++ b/board/aspeed/ast2600_intel/ast-espi.c +@@ -88,6 +88,7 @@ + #define AST_ESPI_OOB_CHRDY BIT(4) + #define AST_ESPI_FLASH_SW_CHRDY BIT(7) + #define AST_ESPI_FLASH_SW_READ BIT(10) ++#define AST_ESPI_SW_RESET GENMASK(31, 24) + + /* ESPI00C bits (Interrupt Enable) */ + #define AST_ESPI_IEN_HW_RST BIT(31) +@@ -122,6 +123,7 @@ + /* LPC chip ID */ + #define SCR0SIO 0x170 + #define IRQ_SRC_ESPI 74 /* IRQ 74 */ ++#define IRQ_SRC_GPIO 72 /* IRQ 72 */ + + static void espi_handshake_ack(void) + { +@@ -205,9 +207,9 @@ static void espi_irq_handler(void *cookie) + } + + if (irq_status & AST_ESPI_HW_RST) { +- uint32_t v = readl(AST_ESPI_BASE + ESPI000) & 0x00ffffffff; +- writel(v, AST_ESPI_BASE + ESPI000); +- v |= 0xff000000; ++ uint32_t v; ++ ++ v = readl(AST_ESPI_BASE + ESPI000) | AST_ESPI_OOB_CHRDY; + writel(v, AST_ESPI_BASE + ESPI000); + + DBG_ESPI("HW_RESET\n"); +@@ -228,6 +230,56 @@ static void espi_irq_handler(void *cookie) + readl(AST_ESPI_BASE + ESPI12C), irq_status); + } + ++static void espi_configure_irq(void) ++{ ++ writel(0, AST_ESPI_BASE + ESPI110); ++ writel(0, AST_ESPI_BASE + ESPI114); ++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN | ++ AST_ESPI_PLTRSTN, AST_ESPI_BASE + ESPI118); ++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN | ++ AST_ESPI_PLTRSTN, AST_ESPI_BASE + ESPI094); ++ ++ writel(AST_ESPI_SUS_WARN, ++ AST_ESPI_BASE + ESPI120); /* int type 0 susp warn */ ++ writel(0, AST_ESPI_BASE + ESPI124); ++ writel(0, AST_ESPI_BASE + ESPI128); ++ writel(AST_ESPI_SUS_WARN, ++ AST_ESPI_BASE + ++ ESPI100); /* Enable sysev1 ints for susp warn */ ++ ++ writel(AST_ESPI_IEN_HW_RST | AST_ESPI_IEN_SYS1_EV | ++ AST_ESPI_IEN_SYS_EV, AST_ESPI_BASE + ESPI00C); ++} ++ ++#define AST_GPIO_BASE 0x1e780000 ++#define GPIO_148 0x148 /* GPIO U/V/W/X Interrupt Enable */ ++#define GPIO_W7 BIT(23) ++#define GPIO_14C 0x14c /* GPIO U/V/W/X Sensitivity Type 0 */ ++#define GPIO_150 0x150 /* GPIO U/V/W/X Sensitivity Type 1 */ ++#define GPIO_154 0x154 /* GPIO U/V/W/X Sensitivity Type 2 */ ++#define GPIO_158 0x158 /* GPIO U/V/W/X Interrupt Status */ ++ ++static void espi_reset_handler(void *cookie) ++{ ++ if (readl(AST_GPIO_BASE + GPIO_158) & GPIO_W7) { ++ uint32_t v; ++ ++ writel(GPIO_W7, AST_GPIO_BASE + GPIO_158); ++ ++ v = readl(AST_ESPI_BASE + ESPI000) & ~AST_ESPI_SW_RESET; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ v |= AST_ESPI_SW_RESET; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ ++ v = readl(AST_ESPI_BASE + ESPI000) & ~AST_ESPI_OOB_CHRDY; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ ++ espi_configure_irq(); ++ ++ DBG_ESPI("eSPI Reset\n"); ++ } ++} ++ + void espi_init(void) + { + if (~readl(AST_SCU_BASE + AST_SCU_HW_STRAP2) & +@@ -266,25 +318,12 @@ void espi_init(void) + AST_ESPI_AUTO_ACK_SUS_WARN); + writel(v, AST_ESPI_BASE + ESPI080); /* Disable auto H/W ack */ + +- writel(0, AST_ESPI_BASE + ESPI110); +- writel(0, AST_ESPI_BASE + ESPI114); +- writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN | +- AST_ESPI_PLTRSTN, AST_ESPI_BASE + ESPI118); +- writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN | +- AST_ESPI_PLTRSTN, AST_ESPI_BASE + ESPI094); +- +- writel(AST_ESPI_SUS_WARN, +- AST_ESPI_BASE + ESPI120); /* int type 0 susp warn */ +- writel(0, AST_ESPI_BASE + ESPI124); +- writel(0, AST_ESPI_BASE + ESPI128); +- writel(AST_ESPI_SUS_WARN, +- AST_ESPI_BASE + +- ESPI100); /* Enable sysev1 ints for susp warn */ +- +- writel(AST_ESPI_IEN_HW_RST | AST_ESPI_IEN_SYS1_EV | +- AST_ESPI_IEN_SYS_EV, AST_ESPI_BASE + ESPI00C); ++ espi_configure_irq(); + + irq_install_handler(IRQ_SRC_ESPI, espi_irq_handler, NULL); ++ ++ irq_install_handler(IRQ_SRC_GPIO, espi_reset_handler, NULL); ++ writel(GPIO_W7, AST_GPIO_BASE + GPIO_148); + } else { + DBG_ESPI("No espi strap\n"); + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/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..d701d5a27 --- /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 144b845cd597cb93e4a6143a194e5018f2176f23 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 dd45e11b3ad9..167b34b2b2c9 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -169,10 +169,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.7.4 + 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..bc2007288 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0016-Add-LED-control-support.patch @@ -0,0 +1,457 @@ +From d7befc37ba40a248899b5dc8e99bef2746a957d2 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 1f14753056ee..5243d1a0afc3 100644 +--- a/arch/arm/dts/ast2600-intel.dts ++++ b/arch/arm/dts/ast2600-intel.dts +@@ -47,8 +47,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 849e81ff3fef..fb9075f93945 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..fb072c8b9f1a 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..89a8808eb --- /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 0a2511d407ad9294b8c08f5228d85e042c104aaa 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 2ee88b4dd39b..2cc6c3652bab 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, } + +@@ -237,6 +239,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 05872b439361..95e5492009d7 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" +@@ -274,6 +275,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, +@@ -283,12 +343,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.7.4 + 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..c0d409592 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0017-Manufacturing-mode-physical-presence-detection.patch @@ -0,0 +1,188 @@ +From 5d3f9d42ba9b1f634a65ae52f6263b1c4a95b947 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 | 74 ++++++++++++++++++++++++++++-- + common/autoboot.c | 12 ++++- + 2 files changed, 82 insertions(+), 4 deletions(-) + +diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c +index fb9075f93945..a644010dd339 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,11 @@ static void gpio_passthru_init(void) + SCU_BASE | SCU_418); + } + ++void board_pre_abort_autoboot(void) ++{ ++ gpio_passthru_init(); ++} ++ + #define AST_LPC_BASE 0x1e789000 + #define LPC_SNOOP_ADDR 0x80 + #define HICR5 0x080 /* Host Interface Control Register 5 */ +@@ -300,8 +327,6 @@ int board_early_init_f(void) + + set_gpio_default_state(); + +- gpio_passthru_init(); +- + port80h_snoop_init(); + + sgpio_init(); +@@ -388,6 +413,43 @@ 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 = 10 * 1000; ++#ifdef CONFIG_LED_BLINK ++ struct udevice *dev; ++ int ret; ++#endif ++ ++ for (uint32_t 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 the boot to do physical indication for mfg mode */ ++ mdelay(delay_for_indication); ++ ++ 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, +@@ -413,8 +475,14 @@ 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"); ++ ++ if (read_ffuj()) { ++ gpio_passthru_init(); + 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..da69791ea --- /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 1333a1ff082cbaec4a44cefaf84d1bcc03ba1510 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 6b447845fe26..55b867ff1b17 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -210,6 +210,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] +@@ -235,6 +241,17 @@ wait_lock: + b 1f + + 0: ++ /* 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..ea7650f8b --- /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 a56e138569ce7b37285d4c2f2b4ef4082ab2a283 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 55b867ff1b17..cd8a57edd76b 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -63,6 +63,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) + +@@ -277,6 +285,20 @@ wait_lock: + str r1, [r0] + + 1: ++ /* 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] ++ + /* 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/0021-AST2600-Enable-host-searial-port-clock-configuration.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0021-AST2600-Enable-host-searial-port-clock-configuration.patch new file mode 100644 index 000000000..915b0197f --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0021-AST2600-Enable-host-searial-port-clock-configuration.patch @@ -0,0 +1,71 @@ +From c2e2496dfd8cde56e32274b11968185a77f40736 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 a02e246d0d81..eb9b3959625e 100644 +--- a/board/aspeed/ast2600_intel/intel.c ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -36,9 +36,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.7.4 + 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..d1cb523e5 --- /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 56a1cafcf68c624ca9ea9de6c38080603e80ea0d 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 a644010dd339..2db162bc9d4c 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); +@@ -460,6 +513,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); +@@ -475,6 +529,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..da7889be6 --- /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 473b1990ecb578b6dc5d3347dc0ab8f7d5609137 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 cd8a57edd76b..08f33a9f1a17 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -64,6 +64,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) + +@@ -313,6 +316,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 948f8a01f868..1a95893631c8 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 1793a9e1f560..2ba5e5d65f4a 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" + +@@ -425,6 +426,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 255901ff0ea8..0797cd4febed 100755 +--- a/include/configs/aspeed-common.h ++++ b/include/configs/aspeed-common.h +@@ -18,6 +18,8 @@ + #define CONFIG_IPADDR 192.168.0.45 + #define CONFIG_SERVERIP 192.168.0.81 + ++#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-Enable-PCIe-L1-support.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0025-Enable-PCIe-L1-support.patch new file mode 100644 index 000000000..8cc95174f --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0025-Enable-PCIe-L1-support.patch @@ -0,0 +1,40 @@ +From 1f95d121b4a11444bffd0494bcfff1986e0905b6 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 cd8a57edd76b..ecc9fd33d125 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -299,6 +299,20 @@ wait_lock: + bic r1, r2 + 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/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..23fc22ea7 --- /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,49 @@ +From 5ca28a9259d084440879be48ef4b4d6716794281 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 | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S +index ecc9fd33d1..8c40515b76 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) +@@ -285,6 +287,15 @@ wait_lock: + str r1, [r0] + + 1: ++ /* SCU060:EXTRST1# reset mask selection */ ++ ldr r0, =AST_SCU_EXTRST_SEL1 ++ ldr r1, =0x6FF1FF5 ++ str r1, [r0] ++ /* SCU070:EXTRST2# reset mask selection */ ++ ldr r0, =AST_SCU_EXTRST_SEL2 ++ ldr r1, =0x3FFFFF7 ++ 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/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..4d8d97d10 --- /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 b6f6c6fe9b92e3b1bbed12e27a65e822a44da528 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 0d038920b150..dce15c83a093 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -79,6 +79,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 +@@ -409,6 +412,11 @@ skip_fill_wip_bit: + orr r1, #0x0A + 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/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..3d9d50c8d --- /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 948a92b3000120f902292b661a544e35d796784a 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 6065ec58db..b13dbd02f3 100644 +--- a/include/configs/aspeed-common.h ++++ b/include/configs/aspeed-common.h +@@ -64,9 +64,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..1ac02608b --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/intel.cfg @@ -0,0 +1,30 @@ +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_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 |