diff options
Diffstat (limited to 'arch')
119 files changed, 7858 insertions, 315 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 141e48bc43..ae9c93ed7b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -133,6 +133,9 @@ config SANDBOX imply PHYLIB imply DM_MDIO imply DM_MDIO_MUX + imply ACPI_PMC + imply ACPI_PMC_SANDBOX + imply CMD_PMC config SH bool "SuperH architecture" @@ -183,12 +186,14 @@ config X86 imply USB_HOST_ETHER imply PCH imply RTC_MC146818 + imply IRQ # Thing to enable for when SPL/TPL are enabled: SPL imply SPL_DM imply SPL_OF_LIBFDT imply SPL_DRIVERS_MISC_SUPPORT imply SPL_GPIO_SUPPORT + imply SPL_PINCTRL imply SPL_LIBCOMMON_SUPPORT imply SPL_LIBGENERIC_SUPPORT imply SPL_SERIAL_SUPPORT @@ -200,14 +205,12 @@ config X86 imply SPL_SYSCON # TPL imply TPL_DM - imply TPL_OF_LIBFDT imply TPL_DRIVERS_MISC_SUPPORT imply TPL_GPIO_SUPPORT + imply TPL_PINCTRL imply TPL_LIBCOMMON_SUPPORT imply TPL_LIBGENERIC_SUPPORT imply TPL_SERIAL_SUPPORT - imply TPL_SPI_FLASH_SUPPORT - imply TPL_SPI_SUPPORT imply TPL_OF_CONTROL imply TPL_TIMER imply TPL_REGMAP diff --git a/arch/arm/cpu/armv7/ls102xa/Kconfig b/arch/arm/cpu/armv7/ls102xa/Kconfig index b9511da3f3..57d7fd9e55 100644 --- a/arch/arm/cpu/armv7/ls102xa/Kconfig +++ b/arch/arm/cpu/armv7/ls102xa/Kconfig @@ -27,14 +27,6 @@ config ARCH_LS1021A menu "LS102xA architecture" depends on ARCH_LS1021A -config FSL_PCIE_COMPAT - string "PCIe compatible of Kernel DT" - depends on PCIE_LAYERSCAPE - default "fsl,ls1021a-pcie" if ARCH_LS1021A - help - This compatible is used to find pci controller node in Kernel DT - to complete fixup. - config LS1_DEEP_SLEEP bool "Deep sleep" depends on ARCH_LS1021A diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig index f1578b10bc..ed478ddd48 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -219,6 +219,7 @@ config ARCH_LX2160A select SYS_FSL_DDR_VER_50 select SYS_FSL_EC1 select SYS_FSL_EC2 + select SYS_FSL_ERRATUM_A050106 select SYS_FSL_HAS_RGMII select SYS_FSL_HAS_SEC select SYS_FSL_HAS_CCN508 @@ -252,20 +253,6 @@ menu "Layerscape architecture" config FSL_LAYERSCAPE bool -config FSL_PCIE_COMPAT - string "PCIe compatible of Kernel DT" - depends on PCIE_LAYERSCAPE || PCIE_LAYERSCAPE_GEN4 - default "fsl,ls1012a-pcie" if ARCH_LS1012A - default "fsl,ls1028a-pcie" if ARCH_LS1028A - default "fsl,ls1043a-pcie" if ARCH_LS1043A - default "fsl,ls1046a-pcie" if ARCH_LS1046A - default "fsl,ls2080a-pcie" if ARCH_LS2080A - default "fsl,ls1088a-pcie" if ARCH_LS1088A - default "fsl,lx2160a-pcie" if ARCH_LX2160A - help - This compatible is used to find pci controller node in Kernel DT - to complete fixup. - config HAS_FEATURE_GIC64K_ALIGN bool default y if ARCH_LS1043A @@ -348,6 +335,14 @@ config SYS_FSL_ERRATUM_A009008 config SYS_FSL_ERRATUM_A009798 bool "Workaround for USB PHY erratum A009798" +config SYS_FSL_ERRATUM_A050106 + bool "Workaround for USB PHY erratum A050106" + help + USB3.0 Receiver needs to enable fixed equalization + for each of PHY instances in an SOC. This is similar + to erratum A-009007, but this one is for LX2160A, + and the register value is different. + config SYS_FSL_ERRATUM_A010315 bool "Workaround for PCIe erratum A010315" @@ -388,6 +383,15 @@ config QSPI_AHB_INIT But some QSPI flash size up to 64MBytes, so initialize the QSPI AHB bus for those flashes to support the full QSPI flash size. +config FSPI_AHB_EN_4BYTE + bool "Enable 4-byte Fast Read command for AHB mode" + default n + help + The default setting for FlexSPI AHB bus just supports 3-byte addressing. + But some FlexSPI flash sizes are up to 64MBytes. + This flag enables fast read command for AHB mode and modifies required + LUT to support full FlexSPI flash. + config SYS_CCI400_OFFSET hex "Offset for CCI400 base" depends on SYS_FSL_HAS_CCI400 diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c index 6c87c1b11a..639f531649 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -1101,6 +1101,12 @@ static void config_core_prefetch(void) } } +#ifdef CONFIG_PCIE_ECAM_GENERIC +__weak void set_ecam_icids(void) +{ +} +#endif + int arch_early_init_r(void) { #ifdef CONFIG_SYS_FSL_ERRATUM_A009635 @@ -1153,6 +1159,9 @@ int arch_early_init_r(void) #ifdef CONFIG_SYS_DPAA_QBMAN setup_qbman_portals(); #endif +#ifdef CONFIG_PCIE_ECAM_GENERIC + set_ecam_icids(); +#endif return 0; } diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c index e993209593..1e7e46e88a 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c @@ -421,6 +421,12 @@ static void fdt_disable_multimedia(void *blob, unsigned int svr) } #endif +#ifdef CONFIG_PCIE_ECAM_GENERIC +__weak void fdt_fixup_ecam(void *blob) +{ +} +#endif + void ft_cpu_setup(void *blob, bd_t *bd) { struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); @@ -485,4 +491,7 @@ void ft_cpu_setup(void *blob, bd_t *bd) #ifdef CONFIG_ARCH_LS1028A fdt_disable_multimedia(blob, svr); #endif +#ifdef CONFIG_PCIE_ECAM_GENERIC + fdt_fixup_ecam(blob); +#endif } diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ls1028_ids.c b/arch/arm/cpu/armv8/fsl-layerscape/ls1028_ids.c index 9462298fbf..8110412da6 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/ls1028_ids.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/ls1028_ids.c @@ -33,3 +33,96 @@ struct icid_id_table icid_tbl[] = { }; int icid_tbl_sz = ARRAY_SIZE(icid_tbl); + +/* integrated PCI is handled separately as it's not part of CCSR/SCFG */ +#ifdef CONFIG_PCIE_ECAM_GENERIC + +#define ECAM_IERB_BASE 0x1f0800000ULL +#define ECAM_IERB_OFFSET_NA -1 +#define ECAM_IERB_FUNC_CNT ARRAY_SIZE(ierb_offset) +/* cache related transaction attributes for PCIe functions */ +#define ECAM_IERB_MSICAR (ECAM_IERB_BASE + 0xa400) +#define ECAM_IERB_MSICAR_VALUE 0x30 + +/* offset of IERB config register per PCI function */ +static int ierb_offset[] = { + 0x0800, + 0x1800, + 0x2800, + 0x3800, + 0x4800, + 0x5800, + 0x6800, + ECAM_IERB_OFFSET_NA, + 0x0804, + 0x0808, + 0x1804, + 0x1808, +}; + +/* + * Use a custom function for LS1028A, for now this is the only SoC with IERB + * and we're currently considering reorganizing IERB for future SoCs. + */ +void set_ecam_icids(void) +{ + int i; + + out_le32(ECAM_IERB_MSICAR, ECAM_IERB_MSICAR_VALUE); + + for (i = 0; i < ECAM_IERB_FUNC_CNT; i++) { + if (ierb_offset[i] == ECAM_IERB_OFFSET_NA) + continue; + + out_le32(ECAM_IERB_BASE + ierb_offset[i], + FSL_ECAM_STREAM_ID_START + i); + } +} + +static int fdt_setprop_inplace_idx_u32(void *fdt, int nodeoffset, + const char *name, uint32_t idx, u32 val) +{ + val = cpu_to_be32(val); + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), + idx * sizeof(val), &val, + sizeof(val)); +} + +static int fdt_getprop_len(void *fdt, int nodeoffset, const char *name) +{ + int len; + + if (fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), &len)) + return len; + + return 0; +} + +void fdt_fixup_ecam(void *blob) +{ + int off; + + off = fdt_node_offset_by_compatible(blob, 0, "pci-host-ecam-generic"); + if (off < 0) { + debug("ECAM node not found\n"); + return; + } + + if (fdt_getprop_len(blob, off, "msi-map") != 16 || + fdt_getprop_len(blob, off, "iommu-map") != 16) { + log_err("invalid msi/iommu-map propertly size in ECAM node\n"); + return; + } + + fdt_setprop_inplace_idx_u32(blob, off, "msi-map", 2, + FSL_ECAM_STREAM_ID_START); + fdt_setprop_inplace_idx_u32(blob, off, "msi-map", 3, + ECAM_IERB_FUNC_CNT); + + fdt_setprop_inplace_idx_u32(blob, off, "iommu-map", 2, + FSL_ECAM_STREAM_ID_START); + fdt_setprop_inplace_idx_u32(blob, off, "iommu-map", 3, + ECAM_IERB_FUNC_CNT); +} +#endif /* CONFIG_PCIE_ECAM_GENERIC */ diff --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c b/arch/arm/cpu/armv8/fsl-layerscape/soc.c index 70933a2e03..578f8d12de 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c @@ -147,7 +147,7 @@ static void erratum_a008997(void) out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_4) #elif defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1088A) || \ - defined(CONFIG_ARCH_LS1028A) + defined(CONFIG_ARCH_LS1028A) || defined(CONFIG_ARCH_LX2160A) #define PROGRAM_USB_PHY_RX_OVRD_IN_HI(phy) \ out_le16((phy) + DCSR_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_1); \ @@ -181,6 +181,15 @@ static void erratum_a009007(void) } #if defined(CONFIG_FSL_LSCH3) +static void erratum_a050106(void) +{ +#if defined(CONFIG_ARCH_LX2160A) + void __iomem *dcsr = (void __iomem *)DCSR_BASE; + + PROGRAM_USB_PHY_RX_OVRD_IN_HI(dcsr + DCSR_USB_PHY1); + PROGRAM_USB_PHY_RX_OVRD_IN_HI(dcsr + DCSR_USB_PHY2); +#endif +} /* * This erratum requires setting a value to eddrtqcr1 to * optimal the DDR performance. @@ -332,6 +341,7 @@ void fsl_lsch3_early_init_f(void) erratum_a009798(); erratum_a008997(); erratum_a009007(); + erratum_a050106(); #ifdef CONFIG_CHAIN_OF_TRUST /* In case of Secure Boot, the IBR configures the SMMU * to allow only Secure transactions. @@ -676,6 +686,47 @@ void fsl_lsch2_early_init_f(void) } #endif +#ifdef CONFIG_FSPI_AHB_EN_4BYTE +int fspi_ahb_init(void) +{ + /* Enable 4bytes address support and fast read */ + u32 *fspi_lut, lut_key, *fspi_key; + + fspi_key = (void *)SYS_NXP_FSPI_ADDR + SYS_NXP_FSPI_LUTKEY_BASE_ADDR; + fspi_lut = (void *)SYS_NXP_FSPI_ADDR + SYS_NXP_FSPI_LUT_BASE_ADDR; + + lut_key = in_be32(fspi_key); + + if (lut_key == SYS_NXP_FSPI_LUTKEY) { + /* That means the register is BE */ + out_be32(fspi_key, SYS_NXP_FSPI_LUTKEY); + /* Unlock the lut table */ + out_be32(fspi_key + 1, SYS_NXP_FSPI_LUTCR_UNLOCK); + /* Create READ LUT */ + out_be32(fspi_lut, 0x0820040c); + out_be32(fspi_lut + 1, 0x24003008); + out_be32(fspi_lut + 2, 0x00000000); + /* Lock the lut table */ + out_be32(fspi_key, SYS_NXP_FSPI_LUTKEY); + out_be32(fspi_key + 1, SYS_NXP_FSPI_LUTCR_LOCK); + } else { + /* That means the register is LE */ + out_le32(fspi_key, SYS_NXP_FSPI_LUTKEY); + /* Unlock the lut table */ + out_le32(fspi_key + 1, SYS_NXP_FSPI_LUTCR_UNLOCK); + /* Create READ LUT */ + out_le32(fspi_lut, 0x0820040c); + out_le32(fspi_lut + 1, 0x24003008); + out_le32(fspi_lut + 2, 0x00000000); + /* Lock the lut table */ + out_le32(fspi_key, SYS_NXP_FSPI_LUTKEY); + out_le32(fspi_key + 1, SYS_NXP_FSPI_LUTCR_LOCK); + } + + return 0; +} +#endif + #ifdef CONFIG_QSPI_AHB_INIT /* Enable 4bytes address support and fast read */ int qspi_ahb_init(void) @@ -868,6 +919,9 @@ int board_late_init(void) #ifdef CONFIG_QSPI_AHB_INIT qspi_ahb_init(); #endif +#ifdef CONFIG_FSPI_AHB_EN_4BYTE + fspi_ahb_init(); +#endif return fsl_board_late_init(); } diff --git a/arch/arm/cpu/armv8/fsl-layerscape/spl.c b/arch/arm/cpu/armv8/fsl-layerscape/spl.c index 58a39e1123..ed3a605663 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/spl.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/spl.c @@ -129,7 +129,7 @@ int spl_start_uboot(void) } #endif /* CONFIG_SPL_OS_BOOT */ #ifdef CONFIG_SPL_LOAD_FIT -int board_fit_config_name_match(const char *name) +__weak int board_fit_config_name_match(const char *name) { /* Just empty function now - can't decide what to choose */ debug("%s: %s\n", __func__, name); diff --git a/arch/arm/dts/fsl-lx2160a.dtsi b/arch/arm/dts/fsl-lx2160a.dtsi index a189333e40..9d018cad1c 100644 --- a/arch/arm/dts/fsl-lx2160a.dtsi +++ b/arch/arm/dts/fsl-lx2160a.dtsi @@ -127,12 +127,14 @@ compatible = "arm,pl011"; reg = <0x0 0x21c0000 0x0 0x1000>; clocks = <&clockgen 4 0>; + status = "disabled"; }; uart1: serial@21d0000 { compatible = "arm,pl011"; reg = <0x0 0x21d0000 0x0 0x1000>; clocks = <&clockgen 4 0>; + status = "disabled"; }; uart2: serial@21e0000 { diff --git a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h index d46477d96e..299201b157 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h @@ -23,7 +23,13 @@ #define CONFIG_SYS_FSL_CH3_CLK_GRPA_ADDR (CONFIG_SYS_IMMR + 0x00300000) #define CONFIG_SYS_FSL_CH3_CLK_GRPB_ADDR (CONFIG_SYS_IMMR + 0x00310000) #define CONFIG_SYS_FSL_CH3_CLK_CTRL_ADDR (CONFIG_SYS_IMMR + 0x00370000) +#ifndef CONFIG_NXP_LSCH3_2 #define SYS_FSL_QSPI_ADDR (CONFIG_SYS_IMMR + 0x010c0000) +#else +#define SYS_NXP_FSPI_ADDR (CONFIG_SYS_IMMR + 0x010c0000) +#define SYS_NXP_FSPI_LUTKEY_BASE_ADDR 0x18 +#define SYS_NXP_FSPI_LUT_BASE_ADDR 0x200 +#endif #define CONFIG_SYS_FSL_ESDHC_ADDR (CONFIG_SYS_IMMR + 0x01140000) #define FSL_ESDHC1_BASE_ADDR CONFIG_SYS_FSL_ESDHC_ADDR #define FSL_ESDHC2_BASE_ADDR (CONFIG_SYS_IMMR + 0x01150000) @@ -252,8 +258,14 @@ #define DCSR_USB_PHY_RX_OVRD_IN_HI 0x200C #define USB_PHY_RX_EQ_VAL_1 0x0000 #define USB_PHY_RX_EQ_VAL_2 0x0080 +#if defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1088A) || \ + defined(CONFIG_ARCH_LS1028A) #define USB_PHY_RX_EQ_VAL_3 0x0380 #define USB_PHY_RX_EQ_VAL_4 0x0b80 +#elif defined(CONFIG_ARCH_LX2160A) +#define USB_PHY_RX_EQ_VAL_3 0x0080 +#define USB_PHY_RX_EQ_VAL_4 0x0880 +#endif #define DCSR_USB_IOCR1 0x108004 #define DCSR_USB_PCSTXSWINGFULL 0x71 diff --git a/arch/arm/include/asm/arch-fsl-layerscape/soc.h b/arch/arm/include/asm/arch-fsl-layerscape/soc.h index 35719d747b..c62d414aac 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/soc.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/soc.h @@ -140,6 +140,13 @@ void init_pfe_scfg_dcfg_regs(void); int qspi_ahb_init(void); #endif +#ifdef CONFIG_FSPI_AHB_EN_4BYTE +#define SYS_NXP_FSPI_LUTCR_LOCK 0x00000001 +#define SYS_NXP_FSPI_LUTCR_UNLOCK 0x00000002 +#define SYS_NXP_FSPI_LUTKEY 0x5AF05AF0 +int fspi_ahb_init(void); +#endif + void cpu_name(char *name); #ifdef CONFIG_SYS_FSL_ERRATUM_A009635 void erratum_a009635(void); diff --git a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h index 94ea99a349..4c54e3d3d5 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Copyright 2015-2018 NXP + * Copyright 2015-2019 NXP * Copyright 2014 Freescale Semiconductor, Inc. * */ @@ -42,6 +42,10 @@ * -the MC is responsible for allocating and setting up 'isolation context * IDs (ICIDs) based on the allocated stream IDs for all DPAA2 devices. * + * - ECAM (integrated PCI) + * - U-Boot applies the value here to HW and does DT fix-up for both + * 'iommu-map' and 'msi-map' + * * On Chasis-3 SoCs stream IDs are programmed in AMQ registers (32-bits) for * each of the different bus masters. The relationship between * the AMQ registers and stream IDs is defined in the table below: @@ -83,14 +87,12 @@ /* PCI - programmed in PEXn_LUT */ #define FSL_PEX_STREAM_ID_START 7 -#ifdef CONFIG_ARCH_LX2160A -#define FSL_PEX_STREAM_ID_NUM (0x100) -#endif - #if defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1028A) #define FSL_PEX_STREAM_ID_END 22 #elif defined(CONFIG_ARCH_LS1088A) #define FSL_PEX_STREAM_ID_END 18 +#elif defined(CONFIG_ARCH_LX2160A) +#define FSL_PEX_STREAM_ID_END (0x100) #endif @@ -98,6 +100,10 @@ #define FSL_DPAA2_STREAM_ID_START 23 #define FSL_DPAA2_STREAM_ID_END 63 +/* PCI IEPs, this overlaps DPAA2 but these two are exclusive at least for now */ +#define FSL_ECAM_STREAM_ID_START 32 +#define FSL_ECAM_STREAM_ID_END 63 + #define FSL_SEC_STREAM_ID 64 #define FSL_SEC_JR1_STREAM_ID 65 #define FSL_SEC_JR2_STREAM_ID 66 diff --git a/arch/arm/include/asm/omap_gpio.h b/arch/arm/include/asm/omap_gpio.h index 20268fa084..151afa8f44 100644 --- a/arch/arm/include/asm/omap_gpio.h +++ b/arch/arm/include/asm/omap_gpio.h @@ -22,7 +22,7 @@ #include <asm/arch/cpu.h> -#ifdef CONFIG_DM_GPIO +#if CONFIG_IS_ENABLED(DM_GPIO) /* Information about a GPIO bank */ struct omap_gpio_platdata { diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h index 91faf729ae..2daeb4fef8 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9260.h +++ b/arch/arm/mach-at91/include/mach/at91sam9260.h @@ -133,7 +133,7 @@ /* * Other misc defines */ -#ifndef CONFIG_DM_GPIO +#if !CONFIG_IS_ENABLED(DM_GPIO) #define ATMEL_PIO_PORTS 3 /* these SoCs have 3 PIO */ #define ATMEL_BASE_PIO ATMEL_BASE_PIOA #endif diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h index c150240962..e5a4053414 100644 --- a/arch/arm/mach-davinci/include/mach/gpio.h +++ b/arch/arm/mach-davinci/include/mach/gpio.h @@ -18,7 +18,7 @@ #define davinci_gpio_bank67 ((struct davinci_gpio *)DAVINCI_GPIO_BANK67) #define davinci_gpio_bank8 ((struct davinci_gpio *)DAVINCI_GPIO_BANK8) -#ifndef CONFIG_DM_GPIO +#if !CONFIG_IS_ENABLED(DM_GPIO) #define gpio_status() gpio_info() #endif #define GPIO_NAME_SIZE 20 diff --git a/arch/arm/mach-omap2/am33xx/board.c b/arch/arm/mach-omap2/am33xx/board.c index 03460c3eb7..e64942b716 100644 --- a/arch/arm/mach-omap2/am33xx/board.c +++ b/arch/arm/mach-omap2/am33xx/board.c @@ -116,7 +116,7 @@ U_BOOT_DEVICES(am33xx_i2c) = { }; #endif -#ifdef CONFIG_DM_GPIO +#if CONFIG_IS_ENABLED(DM_GPIO) static const struct omap_gpio_platdata am33xx_gpio[] = { { 0, AM33XX_GPIO0_BASE }, { 1, AM33XX_GPIO1_BASE }, @@ -141,7 +141,7 @@ U_BOOT_DEVICES(am33xx_gpios) = { #endif #endif -#ifndef CONFIG_DM_GPIO +#if !CONFIG_IS_ENABLED(DM_GPIO) static const struct gpio_bank gpio_bank_am33xx[] = { { (void *)AM33XX_GPIO0_BASE }, { (void *)AM33XX_GPIO1_BASE }, diff --git a/arch/arm/mach-omap2/omap3/board.c b/arch/arm/mach-omap2/omap3/board.c index 658ef8c1f1..60de0d6052 100644 --- a/arch/arm/mach-omap2/omap3/board.c +++ b/arch/arm/mach-omap2/omap3/board.c @@ -33,7 +33,7 @@ extern omap3_sysinfo sysinfo; static void omap3_invalidate_l2_cache_secure(void); #endif -#ifdef CONFIG_DM_GPIO +#if CONFIG_IS_ENABLED(DM_GPIO) #if !CONFIG_IS_ENABLED(OF_CONTROL) /* Manually initialize GPIO banks when OF_CONTROL doesn't */ static const struct omap_gpio_platdata omap34xx_gpio[] = { diff --git a/arch/arm/mach-omap2/omap5/hwinit.c b/arch/arm/mach-omap2/omap5/hwinit.c index eba21647d9..56458ce495 100644 --- a/arch/arm/mach-omap2/omap5/hwinit.c +++ b/arch/arm/mach-omap2/omap5/hwinit.c @@ -25,7 +25,7 @@ u32 *const omap_si_rev = (u32 *)OMAP_SRAM_SCRATCH_OMAP_REV; -#ifndef CONFIG_DM_GPIO +#if !CONFIG_IS_ENABLED(DM_GPIO) static struct gpio_bank gpio_bank_54xx[8] = { { (void *)OMAP54XX_GPIO1_BASE }, { (void *)OMAP54XX_GPIO2_BASE }, diff --git a/arch/powerpc/dts/p1020-post.dtsi b/arch/powerpc/dts/p1020-post.dtsi index fb3b203a24..1c77702f01 100644 --- a/arch/powerpc/dts/p1020-post.dtsi +++ b/arch/powerpc/dts/p1020-post.dtsi @@ -13,6 +13,18 @@ compatible = "fsl,p1020-immr", "simple-bus"; bus-frequency = <0x0>; + usb@22000 { + compatible = "fsl-usb2-dr"; + reg = <0x22000 0x1000>; + phy_type = "ulpi"; + }; + + usb@23000 { + compatible = "fsl-usb2-dr"; + reg = <0x23000 0x1000>; + phy_type = "ulpi"; + }; + mpic: pic@40000 { interrupt-controller; #address-cells = <0>; @@ -31,6 +43,7 @@ /* Filled in by U-Boot */ clock-frequency = <0>; }; + }; /* PCIe controller base address 0x9000 */ diff --git a/arch/powerpc/dts/p2020-post.dtsi b/arch/powerpc/dts/p2020-post.dtsi index c07ed66726..5bbd5c5468 100644 --- a/arch/powerpc/dts/p2020-post.dtsi +++ b/arch/powerpc/dts/p2020-post.dtsi @@ -13,6 +13,12 @@ compatible = "fsl,p2020-immr", "simple-bus"; bus-frequency = <0x0>; + usb@22000 { + compatible = "fsl-usb2-dr"; + reg = <0x22000 0x1000>; + phy_type = "ulpi"; + }; + mpic: pic@40000 { interrupt-controller; #address-cells = <0>; diff --git a/arch/powerpc/dts/p2041.dtsi b/arch/powerpc/dts/p2041.dtsi index 223052ac1c..0f5e7dbdc8 100644 --- a/arch/powerpc/dts/p2041.dtsi +++ b/arch/powerpc/dts/p2041.dtsi @@ -60,6 +60,18 @@ clock-frequency = <0x0>; }; + usb0: usb@210000 { + compatible = "fsl-usb2-mph"; + reg = <0x210000 0x1000>; + phy_type = "utmi"; + }; + + usb1: usb@211000 { + compatible = "fsl-usb2-mph"; + reg = <0x210000 0x1000>; + phy_type = "utmi"; + }; + sata: sata@220000 { compatible = "fsl,pq-sata-v2"; reg = <0x220000 0x1000>; diff --git a/arch/powerpc/dts/p3041.dtsi b/arch/powerpc/dts/p3041.dtsi index e873db2a36..6736d00035 100644 --- a/arch/powerpc/dts/p3041.dtsi +++ b/arch/powerpc/dts/p3041.dtsi @@ -60,6 +60,18 @@ clock-frequency = <0x0>; }; + usb0: usb@fe210000 { + compatible = "fsl-usb2-mph"; + reg = <0x210000 0x1000>; + phy_type = "utmi"; + }; + + usb1: usb@fe211000 { + compatible = "fsl-usb2-dr"; + reg = <0x211000 0x1000>; + phy_type = "utmi"; + }; + sata: sata@220000 { compatible = "fsl,pq-sata-v2"; reg = <0x220000 0x1000>; diff --git a/arch/powerpc/dts/p4080.dtsi b/arch/powerpc/dts/p4080.dtsi index 08ac26df67..02f39fbfcb 100644 --- a/arch/powerpc/dts/p4080.dtsi +++ b/arch/powerpc/dts/p4080.dtsi @@ -85,6 +85,18 @@ reg = <0x114000 0x1000>; clock-frequency = <0>; }; + + usb0@210000 { + compatible = "fsl-usb2-mph"; + reg = <0x210000 0x1000>; + phy_type = "ulpi"; + }; + + usb1@211000 { + compatible = "fsl-usb2-dr"; + reg = <0x211000 0x1000>; + phy_type = "ulpi"; + }; }; pcie@ffe200000 { diff --git a/arch/powerpc/dts/p5040.dtsi b/arch/powerpc/dts/p5040.dtsi index 71019245f0..67a62a7725 100644 --- a/arch/powerpc/dts/p5040.dtsi +++ b/arch/powerpc/dts/p5040.dtsi @@ -59,6 +59,18 @@ clock-frequency = <0x0>; }; + usb@210000 { + compatible = "fsl-usb2-mph"; + reg = <0x210000 0x1000>; + phy_type = "utmi"; + }; + + usb@211000 { + compatible = "fsl-usb2-dr"; + reg = <0x211000 0x1000>; + phy_type = "utmi"; + }; + sata: sata@220000 { compatible = "fsl,pq-sata-v2"; reg = <0x220000 0x1000>; diff --git a/arch/powerpc/dts/t102x.dtsi b/arch/powerpc/dts/t102x.dtsi index 0bc1d809a4..a6b821a76a 100644 --- a/arch/powerpc/dts/t102x.dtsi +++ b/arch/powerpc/dts/t102x.dtsi @@ -49,6 +49,18 @@ clock-frequency = <0x0>; }; + usb0@210000 { + compatible = "fsl-usb2-mph"; + reg = <0x210000 0x1000>; + phy_type = "utmi"; + }; + + usb1@211000 { + compatible = "fsl-usb2-dr"; + reg = <0x211000 0x1000>; + phy_type = "utmi"; + }; + sata: sata@220000 { compatible = "fsl,pq-sata-v2"; reg = <0x220000 0x1000>; diff --git a/arch/powerpc/dts/t104x.dtsi b/arch/powerpc/dts/t104x.dtsi index 0828f73b93..093aaab834 100644 --- a/arch/powerpc/dts/t104x.dtsi +++ b/arch/powerpc/dts/t104x.dtsi @@ -59,6 +59,18 @@ clock-frequency = <0x0>; }; + usb0@210000 { + compatible = "fsl-usb2-mph"; + reg = <0x210000 0x1000>; + phy_type = "utmi"; + }; + + usb1@211000 { + compatible = "fsl-usb2-dr"; + reg = <0x211000 0x1000>; + phy_type = "utmi"; + }; + sata: sata@220000 { compatible = "fsl,pq-sata-v2"; reg = <0x220000 0x1000>; diff --git a/arch/powerpc/dts/t4240.dtsi b/arch/powerpc/dts/t4240.dtsi index 5170083b5b..43f98cd9e1 100644 --- a/arch/powerpc/dts/t4240.dtsi +++ b/arch/powerpc/dts/t4240.dtsi @@ -99,6 +99,18 @@ clock-frequency = <0x0>; }; + usb@210000 { + compatible = "fsl-usb2-mph"; + reg = <0x210000 0x1000>; + phy_type = "utmi"; + }; + + usb@211000 { + compatible = "fsl-usb2-dr"; + reg = <0x211000 0x1000>; + phy_type = "utmi"; + }; + sata: sata@220000 { compatible = "fsl,pq-sata-v2"; reg = <0x220000 0x1000>; diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c index dee5fde4f7..cd46e000f5 100644 --- a/arch/sandbox/cpu/state.c +++ b/arch/sandbox/cpu/state.c @@ -356,6 +356,7 @@ void state_reset_for_test(struct sandbox_state *state) /* No reset yet, so mark it as such. Always allow power reset */ state->last_sysreset = SYSRESET_COUNT; state->sysreset_allowed[SYSRESET_POWER_OFF] = true; + state->allow_memio = false; memset(&state->wdt, '\0', sizeof(state->wdt)); memset(state->spi, '\0', sizeof(state->spi)); diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index f1637c80f6..4dd82f6a32 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -6,6 +6,7 @@ #address-cells = <1>; #size-cells = <1>; model = "sandbox"; + compatible = "sandbox"; aliases { i2c0 = &i2c_0; diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index f09bc70b0d..7bf144f532 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -100,6 +100,17 @@ }; pci-controller { + pci@1e,0 { + compatible = "sandbox,pmc"; + reg = <0xf000 0 0 0 0>; + sandbox,emul = <&pmc_emul>; + gpe0-dwx-mask = <0xf>; + gpe0-dwx-shift-base = <4>; + gpe0-dw = <6 7 9>; + gpe0-sts = <0x20>; + gpe0-en = <0x30>; + }; + pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; @@ -109,6 +120,9 @@ emul { compatible = "sandbox,pci-emul-parent"; + pmc_emul: emul@1e,0 { + compatible = "sandbox,pmc-emul"; + }; swap_case_emul: emul@1f,0 { compatible = "sandbox,swap-case"; }; diff --git a/arch/sandbox/dts/sandbox64.dts b/arch/sandbox/dts/sandbox64.dts index 37a5539ff4..5c95cee9d7 100644 --- a/arch/sandbox/dts/sandbox64.dts +++ b/arch/sandbox/dts/sandbox64.dts @@ -6,6 +6,7 @@ #address-cells = <2>; #size-cells = <2>; model = "sandbox"; + compatible = "sandbox"; aliases { i2c0 = &i2c_0; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index fdb08f2111..57513a449f 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -353,6 +353,10 @@ vss-microvolts = <0>; }; + irq { + compatible = "sandbox,irq"; + }; + lcd { u-boot,dm-pre-reloc; compatible = "sandbox,lcd-sdl"; @@ -471,6 +475,27 @@ 0x01000810 0 0 0 0>; sandbox,emul = <&swap_case_emul0_1>; }; + p2sb-pci@2,0 { + compatible = "sandbox,p2sb"; + reg = <0x02001010 0 0 0 0>; + sandbox,emul = <&p2sb_emul>; + + adder { + intel,p2sb-port-id = <3>; + compatible = "sandbox,adder"; + }; + }; + pci@1e,0 { + compatible = "sandbox,pmc"; + reg = <0xf000 0 0 0 0>; + sandbox,emul = <&pmc_emul1e>; + acpi-base = <0x400>; + gpe0-dwx-mask = <0xf>; + gpe0-dwx-shift-base = <4>; + gpe0-dw = <6 7 9>; + gpe0-sts = <0x20>; + gpe0-en = <0x30>; + }; pci@1f,0 { compatible = "pci-generic"; /* reg 0 is at 0x10, using FDT_PCI_SPACE_IO */ @@ -491,6 +516,12 @@ swap_case_emul0_1f: emul0@1f,0 { compatible = "sandbox,swap-case"; }; + p2sb_emul: emul@2,0 { + compatible = "sandbox,p2sb-emul"; + }; + pmc_emul1e: emul@1e,0 { + compatible = "sandbox,pmc-emul"; + }; }; pci1: pci-controller1 { diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index b885e1a14f..2421922c9e 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -13,6 +13,8 @@ #define SANDBOX_PCI_VENDOR_ID 0x1234 #define SANDBOX_PCI_SWAP_CASE_EMUL_ID 0x5678 +#define SANDBOX_PCI_PMC_EMUL_ID 0x5677 +#define SANDBOX_PCI_P2SB_EMUL_ID 0x5676 #define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM #define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL @@ -72,6 +74,13 @@ void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len); +void sandbox_i2c_eeprom_set_chip_addr_offset_mask(struct udevice *dev, + uint mask); + +uint sanbox_i2c_eeprom_get_prev_addr(struct udevice *dev); + +uint sanbox_i2c_eeprom_get_prev_offset(struct udevice *dev); + /** * sandbox_i2c_rtc_set_offset() - set the time offset from system/base time * diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 17a6fe6d3d..89b93e5de2 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -106,6 +106,7 @@ source "board/google/Kconfig" source "board/intel/Kconfig" # platform-specific options below +source "arch/x86/cpu/apollolake/Kconfig" source "arch/x86/cpu/baytrail/Kconfig" source "arch/x86/cpu/braswell/Kconfig" source "arch/x86/cpu/broadwell/Kconfig" @@ -217,6 +218,14 @@ config SYS_X86_START16 depends on X86_RESET_VECTOR default 0xfffff800 +config HAVE_X86_FIT + bool + help + Enable inclusion of an Intel Firmware Interface Table (FIT) into the + image. This table is supposed to point to microcode and the like. So + far it is just a fixed table with the minimum set of headers, so that + it is actually present. + config X86_LOAD_FROM_32_BIT bool "Boot from a 32-bit program" help @@ -326,7 +335,7 @@ config X86_RAMTEST config FLASH_DESCRIPTOR_FILE string "Flash descriptor binary filename" - depends on HAVE_INTEL_ME + depends on HAVE_INTEL_ME || FSP_VERSION2 default "descriptor.bin" help The filename of the file to use as flash descriptor in the @@ -411,6 +420,54 @@ config FSP_ADDR The default base address of 0xfffc0000 indicates that the binary must be located at offset 0xc0000 from the beginning of a 1MB flash device. +if FSP_VERSION2 + +config FSP_FILE_T + string "Firmware Support Package binary filename (Temp RAM)" + default "fsp_t.bin" + help + The filename of the file to use for the temporary-RAM init phase from + the Firmware Support Package binary. Put this in the board directory. + It is used to set up an initial area of RAM which can be used for the + stack and other purposes, while bringing up the main system DRAM. + +config FSP_ADDR_T + hex "Firmware Support Package binary location (Temp RAM)" + default 0xffff8000 + help + FSP is not Position-Independent Code (PIC) and FSP components have to + be rebased if placed at a location which is different from the + perferred base address specified during the FSP build. Use Intel's + Binary Configuration Tool (BCT) to do the rebase. + +config FSP_FILE_M + string "Firmware Support Package binary filename (Memory Init)" + default "fsp_m.bin" + help + The filename of the file to use for the RAM init phase from the + Firmware Support Package binary. Put this in the board directory. + It is used to set up the main system DRAM and runs in SPL, once + temporary RAM (CAR) is working. + +config FSP_FILE_S + string "Firmware Support Package binary filename (Silicon Init)" + default "fsp_s.bin" + help + The filename of the file to use for the Silicon init phase from the + Firmware Support Package binary. Put this in the board directory. + It is used to set up the silicon to work correctly and must be + executed after DRAM is running. + +config IFWI_INPUT_FILE + string "Filename containing FIT (Firmware Interface Table) with IFWI" + default "fitimage.bin" + help + The IFWI is obtained by running a tool on this file to extract the + IFWI. Put this in the board directory. The IFWI contains U-Boot TPL, + microcode and other internal items. + +endif + config FSP_TEMP_RAM_ADDR hex depends on FSP_VERSION1 @@ -532,6 +589,10 @@ config HAVE_REFCODE broadwell) U-Boot will be missing some critical setup steps. Various peripherals may fail to work. +config HAVE_MICROCODE + bool + default y if !FSP_VERSION2 + config SMP bool "Enable Symmetric Multiprocessing" default n @@ -595,7 +656,7 @@ config VGA_BIOS_ADDR config HAVE_VBT bool "Add a Video BIOS Table (VBT) image" - depends on FSP_VERSION1 + depends on HAVE_FSP help Select this option if you have a Video BIOS Table (VBT) image that you would like to add to your ROM. This is normally required if you @@ -823,4 +884,30 @@ config HIGH_TABLE_SIZE Increse it if the default size does not fit the board's needs. This is most likely due to a large ACPI DSDT table is used. +config INTEL_CAR_CQOS + bool "Support Intel Cache Quality of Service" + help + Cache Quality of Service allows more fine-grained control of cache + usage. As result, it is possible to set up a portion of L2 cache for + CAR and use the remainder for actual caching. + +# +# Each bit in QOS mask controls this many bytes. This is calculated as: +# (CACHE_WAYS / CACHE_BITS_PER_MASK) * CACHE_LINE_SIZE * CACHE_SETS +# +config CACHE_QOS_SIZE_PER_BIT + hex + depends on INTEL_CAR_CQOS + default 0x20000 # 128 KB + +config X86_OFFSET_U_BOOT + hex "Offset of U-Boot in ROM image" + depends on HAVE_SYS_TEXT_BASE + default SYS_TEXT_BASE + +config X86_OFFSET_SPL + hex "Offset of SPL in ROM image" + depends on SPL && X86 + default SPL_TEXT_BASE + endmenu diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 6296b55ff8..5b40838e60 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -41,6 +41,7 @@ extra-y += call32.o endif obj-y += intel_common/ +obj-$(CONFIG_INTEL_APOLLOLAKE) += apollolake/ obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_INTEL_BRASWELL) += braswell/ obj-$(CONFIG_INTEL_BROADWELL) += broadwell/ @@ -53,7 +54,8 @@ obj-$(CONFIG_INTEL_QUARK) += quark/ obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/ obj-$(CONFIG_INTEL_TANGIER) += tangier/ obj-$(CONFIG_APIC) += lapic.o ioapic.o -obj-y += irq.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += irq.o +obj-$(CONFIG_QFW) += qfw_cpu.o ifndef CONFIG_$(SPL_)X86_64 obj-$(CONFIG_SMP) += mp_init.o endif diff --git a/arch/x86/cpu/apollolake/Kconfig b/arch/x86/cpu/apollolake/Kconfig new file mode 100644 index 0000000000..fcff176c27 --- /dev/null +++ b/arch/x86/cpu/apollolake/Kconfig @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2019 Google LLC +# + +config INTEL_APOLLOLAKE + bool + select FSP_VERSION2 + select HAVE_FSP + select ARCH_MISC_INIT + select USE_CAR + select INTEL_PMC + select TPL_X86_TSC_TIMER_NATIVE + select SPL_PCH_SUPPORT + select TPL_PCH_SUPPORT + select PCH_SUPPORT + select P2SB + imply ENABLE_MRC_CACHE + imply AHCI_PCI + imply SCSI + imply SCSI_AHCI + imply SPI_FLASH + imply USB + imply USB_EHCI_HCD + imply TPL + imply SPL + imply TPL_X86_16BIT_INIT + imply TPL_OF_PLATDATA + imply ACPI_PMC + imply MMC + imply DM_MMC + imply MMC_PCI + imply MMC_SDHCI + imply CMD_MMC + imply VIDEO_FSP + imply PINCTRL_INTEL + imply PINCTRL_INTEL_APL + imply HAVE_VBT + imply HAVE_X86_FIT + imply INTEL_GPIO + imply SMP + +if INTEL_APOLLOLAKE + +config DCACHE_RAM_BASE + default 0xfef00000 + +config DCACHE_RAM_SIZE + default 0xc0000 + +config DCACHE_RAM_MRC_VAR_SIZE + default 0xb0000 + +config CPU_SPECIFIC_OPTIONS + def_bool y + select SMM_TSEG + select X86_RAMTEST + +config SMM_TSEG_SIZE + hex + default 0x800000 + +config MMCONF_BASE_ADDRESS + hex + default 0xe0000000 + +config TPL_SIZE_LIMIT + default 0x7800 + +config CPU_ADDR_BITS + default 39 + +config APL_SPI_FLASH_BOOT + bool "Support booting with SPI-flash driver instead memory-mapped SPI" + select TPL_SPI_FLASH_SUPPORT + select TPL_SPI_SUPPORT + help + This enables SPI and SPI flash in TPL. Without the this only + available boot method is to use memory-mapped SPI. Since this is + actually fast and produces a TPL which is 7KB smaller, memory-mapped + SPI is the default. + +config APL_BOOT_FROM_FAST_SPI_FLASH + bool "Boot using SPI flash driver" + select APL_SPI_FLASH_BOOT + help + This option is separate from APL_SPI_FLASH_BOOT since it is useful to + be able to compare booting speed with the same build. Enable this to + use the SPI-flash driver to load SPL, U-Boot and FSP-M. For technical + reasons FSP-S is currently always loaded from memory-mapped SPI. See + Apollo Lake's arch_fsp_init_r() for details about that. + +config VBT_ADDR + default 0xff3f1000 + +endif diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile new file mode 100644 index 0000000000..1760df54d8 --- /dev/null +++ b/arch/x86/cpu/apollolake/Makefile @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2019 Google LLC + +obj-$(CONFIG_SPL_BUILD) += cpu_spl.o +obj-$(CONFIG_SPL_BUILD) += spl.o +obj-$(CONFIG_SPL_BUILD) += systemagent.o +obj-y += cpu_common.o + +ifndef CONFIG_TPL_BUILD +obj-y += cpu.o +obj-y += punit.o +ifdef CONFIG_SPL_BUILD +obj-y += fsp_m.o +endif +endif +ifndef CONFIG_SPL_BUILD +obj-y += fsp_s.o +endif + +obj-y += hostbridge.o +obj-y += itss.o +obj-y += lpc.o +obj-y += p2sb.o +obj-y += pch.o +obj-y += pmc.o +obj-y += uart.o diff --git a/arch/x86/cpu/apollolake/cpu.c b/arch/x86/cpu/apollolake/cpu.c new file mode 100644 index 0000000000..3d05c82a5c --- /dev/null +++ b/arch/x86/cpu/apollolake/cpu.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <asm/cpu_common.h> +#include <asm/cpu_x86.h> + +static int apl_get_info(struct udevice *dev, struct cpu_info *info) +{ + return cpu_intel_get_info(info, INTEL_BCLK_MHZ); +} + +static int apl_get_count(struct udevice *dev) +{ + return 4; +} + +static const struct cpu_ops cpu_x86_apl_ops = { + .get_desc = cpu_x86_get_desc, + .get_info = apl_get_info, + .get_count = apl_get_count, + .get_vendor = cpu_x86_get_vendor, +}; + +static const struct udevice_id cpu_x86_apl_ids[] = { + { .compatible = "intel,apl-cpu" }, + { } +}; + +U_BOOT_DRIVER(cpu_x86_apl_drv) = { + .name = "cpu_x86_apl", + .id = UCLASS_CPU, + .of_match = cpu_x86_apl_ids, + .bind = cpu_x86_bind, + .ops = &cpu_x86_apl_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/arch/x86/cpu/apollolake/cpu_common.c b/arch/x86/cpu/apollolake/cpu_common.c new file mode 100644 index 0000000000..ba6bda37bc --- /dev/null +++ b/arch/x86/cpu/apollolake/cpu_common.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <asm/cpu_common.h> +#include <asm/msr.h> + +void cpu_flush_l1d_to_l2(void) +{ + struct msr_t msr; + + msr = msr_read(MSR_POWER_MISC); + msr.lo |= FLUSH_DL1_L2; + msr_write(MSR_POWER_MISC, msr); +} diff --git a/arch/x86/cpu/apollolake/cpu_spl.c b/arch/x86/cpu/apollolake/cpu_spl.c new file mode 100644 index 0000000000..8a39c3128e --- /dev/null +++ b/arch/x86/cpu/apollolake/cpu_spl.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + * + * Portions taken from coreboot + */ + +#include <common.h> +#include <acpi_s3.h> +#include <dm.h> +#include <ec_commands.h> +#include <log.h> +#include <spi_flash.h> +#include <spl.h> +#include <syscon.h> +#include <asm/cpu.h> +#include <asm/cpu_common.h> +#include <asm/cpu_x86.h> +#include <asm/fast_spi.h> +#include <asm/intel_pinctrl.h> +#include <asm/intel_regs.h> +#include <asm/io.h> +#include <asm/msr.h> +#include <asm/mtrr.h> +#include <asm/pci.h> +#include <asm/arch/cpu.h> +#include <asm/arch/gpio.h> +#include <asm/arch/iomap.h> +#include <asm/arch/lpc.h> +#include <asm/arch/pch.h> +#include <asm/arch/systemagent.h> +#include <asm/arch/uart.h> +#include <asm/fsp2/fsp_api.h> +#include <linux/sizes.h> +#include <power/acpi_pmc.h> + +/* Define this here to avoid referencing any drivers for the debug UART 1 */ +#define PCH_DEV_P2SB PCI_BDF(0, 0x0d, 0) + +static void pch_uart_init(void) +{ + /* + * Set up the pinmux so that the UART rx/tx signals are connected + * outside the SoC. + * + * There are about 500 lines of code required to program the GPIO + * configuration for the UARTs. But it boils down to four writes, and + * for the debug UART we want the minimum possible amount of code before + * the UART is running. So just add the magic writes here. See + * apl_hostbridge_early_init_pinctrl() for the full horror. + */ + if (PCI_FUNC(PCH_DEV_UART) == 1) { + writel(0x40000402, 0xd0c50650); + writel(0x3c47, 0xd0c50654); + writel(0x40000400, 0xd0c50658); + writel(0x3c48, 0xd0c5065c); + } else { /* UART2 */ + writel(0x40000402, 0xd0c50670); + writel(0x3c4b, 0xd0c50674); + writel(0x40000400, 0xd0c50678); + writel(0x3c4c, 0xd0c5067c); + } + +#ifdef CONFIG_DEBUG_UART + apl_uart_init(PCH_DEV_UART, CONFIG_DEBUG_UART_BASE); +#endif +} + +static void p2sb_enable_bar(ulong bar) +{ + /* Enable PCR Base address in PCH */ + pci_x86_write_config(PCH_DEV_P2SB, PCI_BASE_ADDRESS_0, bar, + PCI_SIZE_32); + pci_x86_write_config(PCH_DEV_P2SB, PCI_BASE_ADDRESS_1, 0, PCI_SIZE_32); + + /* Enable P2SB MSE */ + pci_x86_write_config(PCH_DEV_P2SB, PCI_COMMAND, + PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, + PCI_SIZE_8); +} + +/* + * board_debug_uart_init() - Init the debug UART ready for use + * + * This is the minimum init needed to get the UART running. It avoids any + * drivers or complex code, so that the UART is running as soon as possible. + */ +void board_debug_uart_init(void) +{ + p2sb_enable_bar(IOMAP_P2SB_BAR); + pch_uart_init(); +} + +static int fast_spi_cache_bios_region(void) +{ + uint map_size, offset; + ulong map_base, base; + int ret; + + ret = fast_spi_early_init(PCH_DEV_SPI, IOMAP_SPI_BASE); + if (ret) + return log_msg_ret("early_init", ret); + + ret = fast_spi_get_bios_mmap(PCH_DEV_SPI, &map_base, &map_size, + &offset); + if (ret) + return log_msg_ret("get_mmap", ret); + + base = SZ_4G - map_size; + mtrr_set_next_var(MTRR_TYPE_WRPROT, base, map_size); + log_debug("BIOS cache base=%lx, size=%x\n", base, (uint)map_size); + + return 0; +} + +static void enable_pm_timer_emulation(struct udevice *pmc) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(pmc); + msr_t msr; + + /* + * The derived frequency is calculated as follows: + * (CTC_FREQ * msr[63:32]) >> 32 = target frequency. + * + * Back-solve the multiplier so the 3.579545MHz ACPI timer frequency is + * used. + */ + msr.hi = (3579545ULL << 32) / CTC_FREQ; + + /* Set PM1 timer IO port and enable */ + msr.lo = EMULATE_PM_TMR_EN | (upriv->acpi_base + R_ACPI_PM1_TMR); + debug("PM timer %x %x\n", msr.hi, msr.lo); + msr_write(MSR_EMULATE_PM_TIMER, msr); +} + +static void google_chromeec_ioport_range(uint *out_basep, uint *out_sizep) +{ + uint base; + uint size; + + if (IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_MEC)) { + base = MEC_EMI_BASE; + size = MEC_EMI_SIZE; + } else { + base = EC_HOST_CMD_REGION0; + size = 2 * EC_HOST_CMD_REGION_SIZE; + /* Make sure MEMMAP region follows host cmd region */ + assert(base + size == EC_LPC_ADDR_MEMMAP); + size += EC_MEMMAP_SIZE; + } + + *out_basep = base; + *out_sizep = size; +} + +static void early_ec_init(void) +{ + uint base, size; + + /* + * Set up LPC decoding for the Chrome OS EC I/O port ranges: + * - Ports 62/66, 60/64, and 200->208 + * - Chrome OS EC communication I/O ports + */ + lpc_enable_fixed_io_ranges(LPC_IOE_EC_62_66 | LPC_IOE_KBC_60_64 | + LPC_IOE_LGE_200); + google_chromeec_ioport_range(&base, &size); + lpc_open_pmio_window(base, size); +} + +static int arch_cpu_init_tpl(void) +{ + struct udevice *pmc, *sa, *p2sb, *serial, *spi, *lpc; + int ret; + + ret = uclass_first_device_err(UCLASS_ACPI_PMC, &pmc); + if (ret) + return log_msg_ret("PMC", ret); + + /* Clear global reset promotion bit */ + ret = pmc_global_reset_set_enable(pmc, false); + if (ret) + return log_msg_ret("disable global reset", ret); + + enable_pm_timer_emulation(pmc); + + ret = uclass_first_device_err(UCLASS_P2SB, &p2sb); + if (ret) + return log_msg_ret("p2sb", ret); + ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &sa); + if (ret) + return log_msg_ret("northbridge", ret); + gd->baudrate = CONFIG_BAUDRATE; + ret = uclass_first_device_err(UCLASS_SERIAL, &serial); + if (ret) + return log_msg_ret("serial", ret); + if (CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT)) { + ret = uclass_first_device_err(UCLASS_SPI, &spi); + if (ret) + return log_msg_ret("SPI", ret); + } else { + /* Alternative code if we don't have SPI in TPL */ + if (IS_ENABLED(CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH)) + printf("Warning: Enable APL_SPI_FLASHBOOT to use SPI-flash driver in TPL"); + ret = fast_spi_cache_bios_region(); + if (ret) + return log_msg_ret("BIOS cache", ret); + } + ret = pmc_disable_tco(pmc); + if (ret) + return log_msg_ret("disable TCO", ret); + ret = pmc_gpe_init(pmc); + if (ret) + return log_msg_ret("pmc_gpe", ret); + ret = uclass_first_device_err(UCLASS_LPC, &lpc); + if (ret) + return log_msg_ret("lpc", ret); + + early_ec_init(); + + return 0; +} + +/* + * Enables several BARs and devices which are needed for memory init + * - MCH_BASE_ADDR is needed in order to talk to the memory controller + * - HPET is enabled because FSP wants to store a pointer to global data in the + * HPET comparator register + */ +static int arch_cpu_init_spl(void) +{ + struct udevice *pmc, *p2sb; + int ret; + + ret = uclass_first_device_err(UCLASS_ACPI_PMC, &pmc); + if (ret) + return log_msg_ret("Could not probe PMC", ret); + ret = uclass_first_device_err(UCLASS_P2SB, &p2sb); + if (ret) + return log_msg_ret("Cannot set up p2sb", ret); + + lpc_io_setup_comm_a_b(); + + /* TODO(sjg@chromium.org): Enable upper RTC bank here */ + + ret = pmc_init(pmc); + if (ret < 0) + return log_msg_ret("Could not init PMC", ret); +#ifdef CONFIG_HAVE_ACPI_RESUME + ret = pmc_prev_sleep_state(pmc); + if (ret < 0) + return log_msg_ret("Could not get PMC sleep state", ret); + gd->arch.prev_sleep_state = ret; +#endif + + return 0; +} + +int arch_cpu_init(void) +{ + int ret = 0; + + if (spl_phase() == PHASE_TPL) + ret = arch_cpu_init_tpl(); + else if (spl_phase() == PHASE_SPL) + ret = arch_cpu_init_spl(); + if (ret) + printf("%s: Error %d\n", __func__, ret); + + return ret; +} diff --git a/arch/x86/cpu/apollolake/fsp_m.c b/arch/x86/cpu/apollolake/fsp_m.c new file mode 100644 index 0000000000..5308af8ed4 --- /dev/null +++ b/arch/x86/cpu/apollolake/fsp_m.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <asm/arch/iomap.h> +#include <asm/arch/fsp/fsp_configs.h> +#include <asm/arch/fsp/fsp_m_upd.h> +#include <asm/fsp2/fsp_internal.h> +#include <dm/uclass-internal.h> + +/* + * ODT settings: + * If ODT PIN to LP4 DRAM is pulled HIGH for ODT_A and HIGH for ODT_B, + * choose ODT_A_B_HIGH_HIGH. If ODT PIN to LP4 DRAM is pulled HIGH for ODT_A + * and LOW for ODT_B, choose ODT_A_B_HIGH_LOW. + * + * Note that the enum values correspond to the interpreted UPD fields + * within Ch[3:0]_OdtConfig parameters. + */ +enum { + ODT_A_B_HIGH_LOW = 0 << 1, + ODT_A_B_HIGH_HIGH = 1 << 1, + N_WR_24 = 1 << 5, +}; + +/* + * LPDDR4 helper routines for configuring the memory UPD for LPDDR4 operation. + * There are four physical LPDDR4 channels, each 32-bits wide. There are two + * logical channels using two physical channels together to form a 64-bit + * interface to memory for each logical channel. + */ + +enum { + LP4_PHYS_CH0A, + LP4_PHYS_CH0B, + LP4_PHYS_CH1A, + LP4_PHYS_CH1B, + + LP4_NUM_PHYS_CHANNELS, +}; + +/* + * The DQs within a physical channel can be bit-swizzled within each byte. + * Within a channel the bytes can be swapped, but the DQs need to be routed + * with the corresponding DQS (strobe). + */ +enum { + LP4_DQS0, + LP4_DQS1, + LP4_DQS2, + LP4_DQS3, + + LP4_NUM_BYTE_LANES, + DQ_BITS_PER_DQS = 8, +}; + +/* Provide bit swizzling per DQS and byte swapping within a channel */ +struct lpddr4_chan_swizzle_cfg { + u8 dqs[LP4_NUM_BYTE_LANES][DQ_BITS_PER_DQS]; +}; + +struct lpddr4_swizzle_cfg { + struct lpddr4_chan_swizzle_cfg phys[LP4_NUM_PHYS_CHANNELS]; +}; + +static void setup_sdram(struct fsp_m_config *cfg, + const struct lpddr4_swizzle_cfg *swizzle_cfg) +{ + const struct lpddr4_chan_swizzle_cfg *sch; + /* Number of bytes to copy per DQS */ + const size_t sz = DQ_BITS_PER_DQS; + int chan; + + cfg->memory_down = 1; + cfg->scrambler_support = 1; + cfg->channel_hash_mask = 0x36; + cfg->slice_hash_mask = 9; + cfg->interleaved_mode = 2; + cfg->channels_slices_enable = 0; + cfg->min_ref_rate2x_enable = 0; + cfg->dual_rank_support_enable = 1; + + /* LPDDR4 is memory down so no SPD addresses */ + cfg->dimm0_spd_address = 0; + cfg->dimm1_spd_address = 0; + + for (chan = 0; chan < 4; chan++) { + struct fsp_ram_channel *ch = &cfg->chan[chan]; + + ch->rank_enable = 1; + ch->device_width = 1; + ch->dram_density = 2; + ch->option = 3; + ch->odt_config = ODT_A_B_HIGH_HIGH; + } + + /* + * CH0_DQB byte lanes in the bit swizzle configuration field are + * not 1:1. The mapping within the swizzling field is: + * indices [0:7] - byte lane 1 (DQS1) DQ[8:15] + * indices [8:15] - byte lane 0 (DQS0) DQ[0:7] + * indices [16:23] - byte lane 3 (DQS3) DQ[24:31] + * indices [24:31] - byte lane 2 (DQS2) DQ[16:23] + */ + sch = &swizzle_cfg->phys[LP4_PHYS_CH0B]; + memcpy(&cfg->ch_bit_swizzling[0][0], &sch->dqs[LP4_DQS1], sz); + memcpy(&cfg->ch_bit_swizzling[0][8], &sch->dqs[LP4_DQS0], sz); + memcpy(&cfg->ch_bit_swizzling[0][16], &sch->dqs[LP4_DQS3], sz); + memcpy(&cfg->ch_bit_swizzling[0][24], &sch->dqs[LP4_DQS2], sz); + + /* + * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1. + */ + sch = &swizzle_cfg->phys[LP4_PHYS_CH0A]; + memcpy(&cfg->ch_bit_swizzling[1][0], &sch->dqs[LP4_DQS0], sz); + memcpy(&cfg->ch_bit_swizzling[1][8], &sch->dqs[LP4_DQS1], sz); + memcpy(&cfg->ch_bit_swizzling[1][16], &sch->dqs[LP4_DQS2], sz); + memcpy(&cfg->ch_bit_swizzling[1][24], &sch->dqs[LP4_DQS3], sz); + + sch = &swizzle_cfg->phys[LP4_PHYS_CH1B]; + memcpy(&cfg->ch_bit_swizzling[2][0], &sch->dqs[LP4_DQS1], sz); + memcpy(&cfg->ch_bit_swizzling[2][8], &sch->dqs[LP4_DQS0], sz); + memcpy(&cfg->ch_bit_swizzling[2][16], &sch->dqs[LP4_DQS3], sz); + memcpy(&cfg->ch_bit_swizzling[2][24], &sch->dqs[LP4_DQS2], sz); + + /* + * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1. + */ + sch = &swizzle_cfg->phys[LP4_PHYS_CH1A]; + memcpy(&cfg->ch_bit_swizzling[3][0], &sch->dqs[LP4_DQS0], sz); + memcpy(&cfg->ch_bit_swizzling[3][8], &sch->dqs[LP4_DQS1], sz); + memcpy(&cfg->ch_bit_swizzling[3][16], &sch->dqs[LP4_DQS2], sz); + memcpy(&cfg->ch_bit_swizzling[3][24], &sch->dqs[LP4_DQS3], sz); +} + +int fspm_update_config(struct udevice *dev, struct fspm_upd *upd) +{ + struct fsp_m_config *cfg = &upd->config; + struct fspm_arch_upd *arch = &upd->arch; + + arch->nvs_buffer_ptr = NULL; + prepare_mrc_cache(upd); + arch->stack_base = (void *)0xfef96000; + arch->boot_loader_tolum_size = 0; + + arch->boot_mode = FSP_BOOT_WITH_FULL_CONFIGURATION; + cfg->serial_debug_port_type = 2; + cfg->serial_debug_port_device = 2; + cfg->serial_debug_port_stride_size = 2; + cfg->serial_debug_port_address = 0; + + cfg->package = 1; + /* Don't enforce a memory size limit */ + cfg->memory_size_limit = 0; + cfg->low_memory_max_value = 2048; /* 2 GB */ + /* No restrictions on memory above 4GiB */ + cfg->high_memory_max_value = 0; + + /* Always default to attempt to use saved training data */ + cfg->disable_fast_boot = 0; + + const u8 *swizzle_data; + + swizzle_data = dev_read_u8_array_ptr(dev, "lpddr4-swizzle", + LP4_NUM_BYTE_LANES * + DQ_BITS_PER_DQS * + LP4_NUM_PHYS_CHANNELS); + if (!swizzle_data) + return log_msg_ret("Cannot read swizzel data", -EINVAL); + + setup_sdram(cfg, (struct lpddr4_swizzle_cfg *)swizzle_data); + + cfg->pre_mem_gpio_table_ptr = 0; + + cfg->profile = 0xb; + cfg->msg_level_mask = 0; + + /* other */ + cfg->skip_cse_rbp = 1; + cfg->periodic_retraining_disable = 0; + cfg->enable_s3_heci2 = 0; + + return 0; +} + +/* + * The FSP-M binary appears to break the SPI controller. It can be fixed by + * writing the BAR again, so do that here + */ +int fspm_done(struct udevice *dev) +{ + struct udevice *spi; + int ret; + + /* Don't probe the device, since that reads the BAR */ + ret = uclass_find_first_device(UCLASS_SPI, &spi); + if (ret) + return log_msg_ret("SPI", ret); + if (!spi) + return log_msg_ret("no SPI", -ENODEV); + + dm_pci_write_config32(spi, PCI_BASE_ADDRESS_0, + IOMAP_SPI_BASE | PCI_BASE_ADDRESS_SPACE_MEMORY); + + return 0; +} diff --git a/arch/x86/cpu/apollolake/fsp_s.c b/arch/x86/cpu/apollolake/fsp_s.c new file mode 100644 index 0000000000..9804227f80 --- /dev/null +++ b/arch/x86/cpu/apollolake/fsp_s.c @@ -0,0 +1,661 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <acpi_s3.h> +#include <binman.h> +#include <dm.h> +#include <irq.h> +#include <asm/intel_pinctrl.h> +#include <asm/io.h> +#include <asm/intel_regs.h> +#include <asm/msr.h> +#include <asm/msr-index.h> +#include <asm/pci.h> +#include <asm/arch/cpu.h> +#include <asm/arch/systemagent.h> +#include <asm/arch/fsp/fsp_configs.h> +#include <asm/arch/fsp/fsp_s_upd.h> + +#define PCH_P2SB_E0 0xe0 +#define HIDE_BIT BIT(0) + +#define INTEL_GSPI_MAX 3 +#define INTEL_I2C_DEV_MAX 8 +#define MAX_USB2_PORTS 8 + +enum { + CHIPSET_LOCKDOWN_FSP = 0, /* FSP handles locking per UPDs */ + CHIPSET_LOCKDOWN_COREBOOT, /* coreboot handles locking */ +}; + +enum i2c_speed { + I2C_SPEED_STANDARD = 100000, + I2C_SPEED_FAST = 400000, + I2C_SPEED_FAST_PLUS = 1000000, + I2C_SPEED_HIGH = 3400000, + I2C_SPEED_FAST_ULTRA = 5000000, +}; + +/* + * Timing values are in units of clock period, with the clock speed + * provided by the SOC + * + * TODO(sjg@chromium.org): Connect this up to the I2C driver + */ +struct dw_i2c_speed_config { + enum i2c_speed speed; + /* SCL high and low period count */ + u16 scl_lcnt; + u16 scl_hcnt; + /* + * SDA hold time should be 300ns in standard and fast modes + * and long enough for deterministic logic level change in + * fast-plus and high speed modes. + * + * [15:0] SDA TX Hold Time + * [23:16] SDA RX Hold Time + */ + u32 sda_hold; +}; + +/* Serial IRQ control. SERIRQ_QUIET is the default (0) */ +enum serirq_mode { + SERIRQ_QUIET, + SERIRQ_CONTINUOUS, + SERIRQ_OFF, +}; + +/* + * This I2C controller has support for 3 independent speed configs but can + * support both FAST_PLUS and HIGH speeds through the same set of speed + * config registers. These are treated separately so the speed config values + * can be provided via ACPI to the OS. + */ +#define DW_I2C_SPEED_CONFIG_COUNT 4 + +struct dw_i2c_bus_config { + /* Bus should be enabled in TPL with temporary base */ + int early_init; + /* Bus speed in Hz, default is I2C_SPEED_FAST (400 KHz) */ + enum i2c_speed speed; + /* + * If rise_time_ns is non-zero the calculations for lcnt and hcnt + * registers take into account the times of the bus. However, if + * there is a match in speed_config those register values take + * precedence + */ + int rise_time_ns; + int fall_time_ns; + int data_hold_time_ns; + /* Specific bus speed configuration */ + struct dw_i2c_speed_config speed_config[DW_I2C_SPEED_CONFIG_COUNT]; +}; + +struct gspi_cfg { + /* Bus speed in MHz */ + u32 speed_mhz; + /* Bus should be enabled prior to ramstage with temporary base */ + u8 early_init; +}; + +/* + * This structure will hold data required by common blocks. + * These are soc specific configurations which will be filled by soc. + * We'll fill this structure once during init and use the data in common block. + */ +struct soc_intel_common_config { + int chipset_lockdown; + struct gspi_cfg gspi[INTEL_GSPI_MAX]; + struct dw_i2c_bus_config i2c[INTEL_I2C_DEV_MAX]; +}; + +enum pnp_settings { + PNP_PERF, + PNP_POWER, + PNP_PERF_POWER, +}; + +struct usb2_eye_per_port { + u8 per_port_tx_pe_half; + u8 per_port_pe_txi_set; + u8 per_port_txi_set; + u8 hs_skew_sel; + u8 usb_tx_emphasis_en; + u8 per_port_rxi_set; + u8 hs_npre_drv_sel; + u8 override_en; +}; + +struct apl_config { + /* Common structure containing soc config data required by common code*/ + struct soc_intel_common_config common_soc_config; + + /* + * Mapping from PCIe root port to CLKREQ input on the SOC. The SOC has + * four CLKREQ inputs, but six root ports. Root ports without an + * associated CLKREQ signal must be marked with "CLKREQ_DISABLED" + */ + u8 pcie_rp_clkreq_pin[MAX_PCIE_PORTS]; + + /* Enable/disable hot-plug for root ports (0 = disable, 1 = enable) */ + u8 pcie_rp_hotplug_enable[MAX_PCIE_PORTS]; + + /* De-emphasis enable configuration for each PCIe root port */ + u8 pcie_rp_deemphasis_enable[MAX_PCIE_PORTS]; + + /* + * [14:8] DDR mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR mode Number of dealy elements.Each = 125pSec. + */ + u32 emmc_tx_cmd_cntl; + + /* + * [14:8] HS400 mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR104/HS200 mode Number of dealy elements.Each = 125pSec. + */ + u32 emmc_tx_data_cntl1; + + /* + * [30:24] SDR50 mode Number of dealy elements.Each = 125pSec. + * [22:16] DDR50 mode Number of dealy elements.Each = 125pSec. + * [14:8] SDR25/HS50 mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR12/Compatibility mode Number of dealy elements. + * Each = 125pSec. + */ + u32 emmc_tx_data_cntl2; + + /* + * [30:24] SDR50 mode Number of dealy elements.Each = 125pSec. + * [22:16] DDR50 mode Number of dealy elements.Each = 125pSec. + * [14:8] SDR25/HS50 mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR12/Compatibility mode Number of dealy elements. + * Each = 125pSec. + */ + u32 emmc_rx_cmd_data_cntl1; + + /* + * [14:8] HS400 mode 1 Number of dealy elements.Each = 125pSec. + * [6:0] HS400 mode 2 Number of dealy elements.Each = 125pSec. + */ + u32 emmc_rx_strobe_cntl; + + /* + * [13:8] Auto Tuning mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR104/HS200 Number of dealy elements.Each = 125pSec. + */ + u32 emmc_rx_cmd_data_cntl2; + + /* Select the eMMC max speed allowed */ + u32 emmc_host_max_speed; + + /* Specifies on which IRQ the SCI will internally appear */ + u32 sci_irq; + + /* Configure serial IRQ (SERIRQ) line */ + enum serirq_mode serirq_mode; + + /* Configure LPSS S0ix Enable */ + bool lpss_s0ix_enable; + + /* Enable DPTF support */ + bool dptf_enable; + + /* TCC activation offset value in degrees Celsius */ + int tcc_offset; + + /* + * Configure Audio clk gate and power gate + * IOSF-SB port ID 92 offset 0x530 [5] and [3] + */ + bool hdaudio_clk_gate_enable; + bool hdaudio_pwr_gate_enable; + bool hdaudio_bios_config_lockdown; + + /* SLP S3 minimum assertion width */ + int slp_s3_assertion_width_usecs; + + /* GPIO pin for PERST_0 */ + u32 prt0_gpio; + + /* USB2 eye diagram settings per port */ + struct usb2_eye_per_port usb2eye[MAX_USB2_PORTS]; + + /* GPIO SD card detect pin */ + unsigned int sdcard_cd_gpio; + + /* + * PRMRR size setting with three options + * 0x02000000 - 32MiB + * 0x04000000 - 64MiB + * 0x08000000 - 128MiB + */ + u32 PrmrrSize; + + /* + * Enable SGX feature. + * Enabling SGX feature is 2 step process, + * (1) set sgx_enable = 1 + * (2) set PrmrrSize to supported size + */ + bool sgx_enable; + + /* + * Select PNP Settings. + * (0) Performance, + * (1) Power + * (2) Power & Performance + */ + enum pnp_settings pnp_settings; + + /* + * PMIC PCH_PWROK delay configuration - IPC Configuration + * Upd for changing PCH_PWROK delay configuration : I2C_Slave_Address + * (31:24) + Register_Offset (23:16) + OR Value (15:8) + AND Value (7:0) + */ + u32 pmic_pmc_ipc_ctrl; + + /* + * Options to disable XHCI Link Compliance Mode. Default is FALSE to not + * disable Compliance Mode. Set TRUE to disable Compliance Mode. + * 0:FALSE(Default), 1:True. + */ + bool disable_compliance_mode; + + /* + * Options to change USB3 ModPhy setting for the Integrated Filter (IF) + * value. Default is 0 to not changing default IF value (0x12). Set + * value with the range from 0x01 to 0xff to change IF value. + */ + u32 mod_phy_if_value; + + /* + * Options to bump USB3 LDO voltage. Default is FALSE to not increasing + * LDO voltage. Set TRUE to increase LDO voltage with 40mV. + * 0:FALSE (default), 1:True. + */ + bool mod_phy_voltage_bump; + + /* + * Options to adjust PMIC Vdd2 voltage. Default is 0 to not adjusting + * the PMIC Vdd2 default voltage 1.20v. Upd for changing Vdd2 Voltage + * configuration: I2C_Slave_Address (31:23) + Register_Offset (23:16) + * + OR Value (15:8) + AND Value (7:0) through BUCK5_VID[3:2]: + * 00=1.10v, 01=1.15v, 10=1.24v, 11=1.20v (default). + */ + u32 pmic_vdd2_voltage; + + /* Option to enable VTD feature */ + bool enable_vtd; +}; + +static int get_config(struct udevice *dev, struct apl_config *apl) +{ + const u8 *ptr; + ofnode node; + u32 emmc[4]; + int ret; + + memset(apl, '\0', sizeof(*apl)); + + node = dev_read_subnode(dev, "fsp-s"); + if (!ofnode_valid(node)) + return log_msg_ret("fsp-s settings", -ENOENT); + + ptr = ofnode_read_u8_array_ptr(node, "pcie-rp-clkreq-pin", + MAX_PCIE_PORTS); + if (!ptr) + return log_msg_ret("pcie-rp-clkreq-pin", -EINVAL); + memcpy(apl->pcie_rp_clkreq_pin, ptr, MAX_PCIE_PORTS); + + ret = ofnode_read_u32(node, "prt0-gpio", &apl->prt0_gpio); + if (ret) + return log_msg_ret("prt0-gpio", ret); + ret = ofnode_read_u32(node, "sdcard-cd-gpio", &apl->sdcard_cd_gpio); + if (ret) + return log_msg_ret("sdcard-cd-gpio", ret); + + ret = ofnode_read_u32_array(node, "emmc", emmc, ARRAY_SIZE(emmc)); + if (ret) + return log_msg_ret("emmc", ret); + apl->emmc_tx_data_cntl1 = emmc[0]; + apl->emmc_tx_data_cntl2 = emmc[1]; + apl->emmc_rx_cmd_data_cntl1 = emmc[2]; + apl->emmc_rx_cmd_data_cntl2 = emmc[3]; + + apl->dptf_enable = ofnode_read_bool(node, "dptf-enable"); + + apl->hdaudio_clk_gate_enable = ofnode_read_bool(node, + "hdaudio-clk-gate-enable"); + apl->hdaudio_pwr_gate_enable = ofnode_read_bool(node, + "hdaudio-pwr-gate-enable"); + apl->hdaudio_bios_config_lockdown = ofnode_read_bool(node, + "hdaudio-bios-config-lockdown"); + apl->lpss_s0ix_enable = ofnode_read_bool(node, "lpss-s0ix-enable"); + + /* Santa */ + apl->usb2eye[1].per_port_pe_txi_set = 7; + apl->usb2eye[1].per_port_txi_set = 2; + + return 0; +} + +static void apl_fsp_silicon_init_params_cb(struct apl_config *apl, + struct fsp_s_config *cfg) +{ + u8 port; + + for (port = 0; port < MAX_USB2_PORTS; port++) { + if (apl->usb2eye[port].per_port_tx_pe_half) + cfg->port_usb20_per_port_tx_pe_half[port] = + apl->usb2eye[port].per_port_tx_pe_half; + + if (apl->usb2eye[port].per_port_pe_txi_set) + cfg->port_usb20_per_port_pe_txi_set[port] = + apl->usb2eye[port].per_port_pe_txi_set; + + if (apl->usb2eye[port].per_port_txi_set) + cfg->port_usb20_per_port_txi_set[port] = + apl->usb2eye[port].per_port_txi_set; + + if (apl->usb2eye[port].hs_skew_sel) + cfg->port_usb20_hs_skew_sel[port] = + apl->usb2eye[port].hs_skew_sel; + + if (apl->usb2eye[port].usb_tx_emphasis_en) + cfg->port_usb20_i_usb_tx_emphasis_en[port] = + apl->usb2eye[port].usb_tx_emphasis_en; + + if (apl->usb2eye[port].per_port_rxi_set) + cfg->port_usb20_per_port_rxi_set[port] = + apl->usb2eye[port].per_port_rxi_set; + + if (apl->usb2eye[port].hs_npre_drv_sel) + cfg->port_usb20_hs_npre_drv_sel[port] = + apl->usb2eye[port].hs_npre_drv_sel; + } +} + +int fsps_update_config(struct udevice *dev, ulong rom_offset, + struct fsps_upd *upd) +{ + struct fsp_s_config *cfg = &upd->config; + struct apl_config *apl; + struct binman_entry vbt; + void *buf; + int ret; + + ret = binman_entry_find("intel-vbt", &vbt); + if (ret) + return log_msg_ret("Cannot find VBT", ret); + vbt.image_pos += rom_offset; + buf = malloc(vbt.size); + if (!buf) + return log_msg_ret("Alloc VBT", -ENOMEM); + + /* + * Load VBT before devicetree-specific config. This only supports + * memory-mapped SPI at present. + */ + bootstage_start(BOOTSTAGE_ID_ACCUM_MMAP_SPI, "mmap_spi"); + memcpy(buf, (void *)vbt.image_pos, vbt.size); + bootstage_accum(BOOTSTAGE_ID_ACCUM_MMAP_SPI); + if (*(u32 *)buf != VBT_SIGNATURE) + return log_msg_ret("VBT signature", -EINVAL); + cfg->graphics_config_ptr = (ulong)buf; + + apl = malloc(sizeof(*apl)); + if (!apl) + return log_msg_ret("config", -ENOMEM); + get_config(dev, apl); + + cfg->ish_enable = 0; + cfg->enable_sata = 0; + cfg->pcie_root_port_en[2] = 0; + cfg->pcie_rp_hot_plug[2] = 0; + cfg->pcie_root_port_en[3] = 0; + cfg->pcie_rp_hot_plug[3] = 0; + cfg->pcie_root_port_en[4] = 0; + cfg->pcie_rp_hot_plug[4] = 0; + cfg->pcie_root_port_en[5] = 0; + cfg->pcie_rp_hot_plug[5] = 0; + cfg->pcie_root_port_en[1] = 0; + cfg->pcie_rp_hot_plug[1] = 0; + cfg->usb_otg = 0; + cfg->i2c6_enable = 0; + cfg->i2c7_enable = 0; + cfg->hsuart3_enable = 0; + cfg->spi1_enable = 0; + cfg->spi2_enable = 0; + cfg->sdio_enabled = 0; + + memcpy(cfg->pcie_rp_clk_req_number, apl->pcie_rp_clkreq_pin, + sizeof(cfg->pcie_rp_clk_req_number)); + + memcpy(cfg->pcie_rp_hot_plug, apl->pcie_rp_hotplug_enable, + sizeof(cfg->pcie_rp_hot_plug)); + + switch (apl->serirq_mode) { + case SERIRQ_QUIET: + cfg->sirq_enable = 1; + cfg->sirq_mode = 0; + break; + case SERIRQ_CONTINUOUS: + cfg->sirq_enable = 1; + cfg->sirq_mode = 1; + break; + case SERIRQ_OFF: + default: + cfg->sirq_enable = 0; + break; + } + + if (apl->emmc_tx_cmd_cntl) + cfg->emmc_tx_cmd_cntl = apl->emmc_tx_cmd_cntl; + if (apl->emmc_tx_data_cntl1) + cfg->emmc_tx_data_cntl1 = apl->emmc_tx_data_cntl1; + if (apl->emmc_tx_data_cntl2) + cfg->emmc_tx_data_cntl2 = apl->emmc_tx_data_cntl2; + if (apl->emmc_rx_cmd_data_cntl1) + cfg->emmc_rx_cmd_data_cntl1 = apl->emmc_rx_cmd_data_cntl1; + if (apl->emmc_rx_strobe_cntl) + cfg->emmc_rx_strobe_cntl = apl->emmc_rx_strobe_cntl; + if (apl->emmc_rx_cmd_data_cntl2) + cfg->emmc_rx_cmd_data_cntl2 = apl->emmc_rx_cmd_data_cntl2; + if (apl->emmc_host_max_speed) + cfg->e_mmc_host_max_speed = apl->emmc_host_max_speed; + + cfg->lpss_s0ix_enable = apl->lpss_s0ix_enable; + + cfg->skip_mp_init = true; + + /* Disable setting of EISS bit in FSP */ + cfg->spi_eiss = 0; + + /* Disable FSP from locking access to the RTC NVRAM */ + cfg->rtc_lock = 0; + + /* Enable Audio clk gate and power gate */ + cfg->hd_audio_clk_gate = apl->hdaudio_clk_gate_enable; + cfg->hd_audio_pwr_gate = apl->hdaudio_pwr_gate_enable; + /* Bios config lockdown Audio clk and power gate */ + cfg->bios_cfg_lock_down = apl->hdaudio_bios_config_lockdown; + apl_fsp_silicon_init_params_cb(apl, cfg); + + cfg->usb_otg = true; + cfg->vtd_enable = apl->enable_vtd; + + return 0; +} + +static void p2sb_set_hide_bit(pci_dev_t dev, int hide) +{ + pci_x86_clrset_config(dev, PCH_P2SB_E0 + 1, HIDE_BIT, + hide ? HIDE_BIT : 0, PCI_SIZE_8); +} + +/* Configure package power limits */ +static int set_power_limits(struct udevice *dev) +{ + msr_t rapl_msr_reg, limit; + u32 power_unit; + u32 tdp, min_power, max_power; + u32 pl2_val; + u32 override_tdp[2]; + int ret; + + /* Get units */ + rapl_msr_reg = msr_read(MSR_PKG_POWER_SKU_UNIT); + power_unit = 1 << (rapl_msr_reg.lo & 0xf); + + /* Get power defaults for this SKU */ + rapl_msr_reg = msr_read(MSR_PKG_POWER_SKU); + tdp = rapl_msr_reg.lo & PKG_POWER_LIMIT_MASK; + pl2_val = rapl_msr_reg.hi & PKG_POWER_LIMIT_MASK; + min_power = (rapl_msr_reg.lo >> 16) & PKG_POWER_LIMIT_MASK; + max_power = rapl_msr_reg.hi & PKG_POWER_LIMIT_MASK; + + if (min_power > 0 && tdp < min_power) + tdp = min_power; + + if (max_power > 0 && tdp > max_power) + tdp = max_power; + + ret = dev_read_u32_array(dev, "tdp-pl-override-mw", override_tdp, + ARRAY_SIZE(override_tdp)); + if (ret) + return log_msg_ret("tdp-pl-override-mw", ret); + + /* Set PL1 override value */ + if (override_tdp[0]) + tdp = override_tdp[0] * power_unit / 1000; + + /* Set PL2 override value */ + if (override_tdp[1]) + pl2_val = override_tdp[1] * power_unit / 1000; + + /* Set long term power limit to TDP */ + limit.lo = tdp & PKG_POWER_LIMIT_MASK; + /* Set PL1 Pkg Power clamp bit */ + limit.lo |= PKG_POWER_LIMIT_CLAMP; + + limit.lo |= PKG_POWER_LIMIT_EN; + limit.lo |= (MB_POWER_LIMIT1_TIME_DEFAULT & + PKG_POWER_LIMIT_TIME_MASK) << PKG_POWER_LIMIT_TIME_SHIFT; + + /* Set short term power limit PL2 */ + limit.hi = pl2_val & PKG_POWER_LIMIT_MASK; + limit.hi |= PKG_POWER_LIMIT_EN; + + /* Program package power limits in RAPL MSR */ + msr_write(MSR_PKG_POWER_LIMIT, limit); + log_info("RAPL PL1 %d.%dW\n", tdp / power_unit, + 100 * (tdp % power_unit) / power_unit); + log_info("RAPL PL2 %d.%dW\n", pl2_val / power_unit, + 100 * (pl2_val % power_unit) / power_unit); + + /* + * Sett RAPL MMIO register for Power limits. RAPL driver is using MSR + * instead of MMIO, so disable LIMIT_EN bit for MMIO + */ + writel(limit.lo & ~PKG_POWER_LIMIT_EN, MCHBAR_REG(MCHBAR_RAPL_PPL)); + writel(limit.hi & ~PKG_POWER_LIMIT_EN, MCHBAR_REG(MCHBAR_RAPL_PPL + 4)); + + return 0; +} + +int p2sb_unhide(void) +{ + pci_dev_t dev = PCI_BDF(0, 0xd, 0); + ulong val; + + p2sb_set_hide_bit(dev, 0); + + pci_x86_read_config(dev, PCI_VENDOR_ID, &val, PCI_SIZE_16); + + if (val != PCI_VENDOR_ID_INTEL) + return log_msg_ret("p2sb unhide", -EIO); + + return 0; +} + +/* Overwrites the SCI IRQ if another IRQ number is given by device tree */ +static void set_sci_irq(void) +{ + /* Skip this for now */ +} + +int arch_fsps_preinit(void) +{ + struct udevice *itss; + int ret; + + ret = uclass_first_device_err(UCLASS_IRQ, &itss); + if (ret) + return log_msg_ret("no itss", ret); + /* + * Snapshot the current GPIO IRQ polarities. FSP is setting a default + * policy that doesn't honour boards' requirements + */ + irq_snapshot_polarities(itss); + + /* + * Clear the GPI interrupt status and enable registers. These + * registers do not get reset to default state when booting from S5. + */ + ret = pinctrl_gpi_clear_int_cfg(); + if (ret) + return log_msg_ret("gpi_clear", ret); + + return 0; +} + +int arch_fsp_init_r(void) +{ +#ifdef CONFIG_HAVE_ACPI_RESUME + bool s3wake = gd->arch.prev_sleep_state == ACPI_S3; +#else + bool s3wake = false; +#endif + struct udevice *dev, *itss; + int ret; + + /* + * This must be called before any devices are probed. Put any probing + * into arch_fsps_preinit() above. + * + * We don't use CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH here since it will + * force PCI to be probed. + */ + ret = fsp_silicon_init(s3wake, false); + if (ret) + return ret; + + ret = uclass_first_device_err(UCLASS_IRQ, &itss); + if (ret) + return log_msg_ret("no itss", ret); + /* Restore GPIO IRQ polarities back to previous settings */ + irq_restore_polarities(itss); + + /* soc_init() */ + ret = p2sb_unhide(); + if (ret) + return log_msg_ret("unhide p2sb", ret); + + /* Set RAPL MSR for Package power limits*/ + ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev); + if (ret) + return log_msg_ret("Cannot get northbridge", ret); + set_power_limits(dev); + + /* + * FSP-S routes SCI to IRQ 9. With the help of this function you can + * select another IRQ for SCI. + */ + set_sci_irq(); + + return 0; +} diff --git a/arch/x86/cpu/apollolake/hostbridge.c b/arch/x86/cpu/apollolake/hostbridge.c new file mode 100644 index 0000000000..793853d5b5 --- /dev/null +++ b/arch/x86/cpu/apollolake/hostbridge.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <dt-structs.h> +#include <spl.h> +#include <asm/intel_pinctrl.h> +#include <asm/intel_regs.h> +#include <asm/pci.h> +#include <asm/arch/systemagent.h> + +/** + * struct apl_hostbridge_platdata - platform data for hostbridge + * + * @dtplat: Platform data for of-platdata + * @early_pads: Early pad data to set up, each (pad, cfg0, cfg1) + * @early_pads_count: Number of pads to process + * @pciex_region_size: BAR length in bytes + * @bdf: Bus/device/function of hostbridge + */ +struct apl_hostbridge_platdata { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_intel_apl_hostbridge dtplat; +#endif + u32 *early_pads; + int early_pads_count; + uint pciex_region_size; + pci_dev_t bdf; +}; + +enum { + PCIEXBAR = 0x60, + PCIEXBAR_LENGTH_256MB = 0, + PCIEXBAR_LENGTH_128MB, + PCIEXBAR_LENGTH_64MB, + + PCIEXBAR_PCIEXBAREN = 1 << 0, + + TSEG = 0xb8, /* TSEG base */ +}; + +static int apl_hostbridge_early_init_pinctrl(struct udevice *dev) +{ + struct apl_hostbridge_platdata *plat = dev_get_platdata(dev); + struct udevice *pinctrl; + int ret; + + ret = uclass_first_device_err(UCLASS_PINCTRL, &pinctrl); + if (ret) + return log_msg_ret("no hostbridge pinctrl", ret); + + return pinctrl_config_pads(pinctrl, plat->early_pads, + plat->early_pads_count); +} + +static int apl_hostbridge_early_init(struct udevice *dev) +{ + struct apl_hostbridge_platdata *plat = dev_get_platdata(dev); + u32 region_size; + ulong base; + u32 reg; + int ret; + + /* Set up the MCHBAR */ + pci_x86_read_config(plat->bdf, MCHBAR, &base, PCI_SIZE_32); + base = MCH_BASE_ADDRESS; + pci_x86_write_config(plat->bdf, MCHBAR, base | 1, PCI_SIZE_32); + + /* + * The PCIEXBAR is assumed to live in the memory mapped IO space under + * 4GiB + */ + pci_x86_write_config(plat->bdf, PCIEXBAR + 4, 0, PCI_SIZE_32); + + switch (plat->pciex_region_size >> 20) { + default: + case 256: + region_size = PCIEXBAR_LENGTH_256MB; + break; + case 128: + region_size = PCIEXBAR_LENGTH_128MB; + break; + case 64: + region_size = PCIEXBAR_LENGTH_64MB; + break; + } + + reg = CONFIG_MMCONF_BASE_ADDRESS | (region_size << 1) + | PCIEXBAR_PCIEXBAREN; + pci_x86_write_config(plat->bdf, PCIEXBAR, reg, PCI_SIZE_32); + + /* + * TSEG defines the base of SMM range. BIOS determines the base + * of TSEG memory which must be at or below Graphics base of GTT + * Stolen memory, hence its better to clear TSEG register early + * to avoid power on default non-zero value (if any). + */ + pci_x86_write_config(plat->bdf, TSEG, 0, PCI_SIZE_32); + + ret = apl_hostbridge_early_init_pinctrl(dev); + if (ret) + return log_msg_ret("pinctrl", ret); + + return 0; +} + +static int apl_hostbridge_ofdata_to_platdata(struct udevice *dev) +{ + struct apl_hostbridge_platdata *plat = dev_get_platdata(dev); + struct udevice *pinctrl; + int ret; + + /* + * The host bridge holds the early pad data needed to get through TPL. + * This is a small amount of data, enough to fit in TPL, so we keep it + * separate from the full pad data, stored in the fsp-s subnode. That + * subnode is not present in TPL, to save space. + */ + ret = uclass_first_device_err(UCLASS_PINCTRL, &pinctrl); + if (ret) + return log_msg_ret("no hostbridge PINCTRL", ret); +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + int root; + + /* Get length of PCI Express Region */ + plat->pciex_region_size = dev_read_u32_default(dev, "pciex-region-size", + 256 << 20); + + root = pci_get_devfn(dev); + if (root < 0) + return log_msg_ret("Cannot get host-bridge PCI address", root); + plat->bdf = root; + + ret = pinctrl_read_pads(pinctrl, dev_ofnode(dev), "early-pads", + &plat->early_pads, &plat->early_pads_count); + if (ret) + return log_msg_ret("early-pads", ret); +#else + struct dtd_intel_apl_hostbridge *dtplat = &plat->dtplat; + int size; + + plat->pciex_region_size = dtplat->pciex_region_size; + plat->bdf = pci_ofplat_get_devfn(dtplat->reg[0]); + + /* Assume that if everything is 0, it is empty */ + plat->early_pads = dtplat->early_pads; + size = ARRAY_SIZE(dtplat->early_pads); + plat->early_pads_count = pinctrl_count_pads(pinctrl, plat->early_pads, + size); + +#endif + + return 0; +} + +static int apl_hostbridge_probe(struct udevice *dev) +{ + if (spl_phase() == PHASE_TPL) + return apl_hostbridge_early_init(dev); + + return 0; +} + +static const struct udevice_id apl_hostbridge_ids[] = { + { .compatible = "intel,apl-hostbridge" }, + { } +}; + +U_BOOT_DRIVER(apl_hostbridge_drv) = { + .name = "intel_apl_hostbridge", + .id = UCLASS_NORTHBRIDGE, + .of_match = apl_hostbridge_ids, + .ofdata_to_platdata = apl_hostbridge_ofdata_to_platdata, + .probe = apl_hostbridge_probe, + .platdata_auto_alloc_size = sizeof(struct apl_hostbridge_platdata), +}; diff --git a/arch/x86/cpu/apollolake/itss.c b/arch/x86/cpu/apollolake/itss.c new file mode 100644 index 0000000000..8789f8e6bb --- /dev/null +++ b/arch/x86/cpu/apollolake/itss.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Something to do with Interrupts, but I don't know what ITSS stands for + * + * Copyright (C) 2017 Intel Corporation. + * Copyright (C) 2017 Siemens AG + * Copyright 2019 Google LLC + * + * Taken from coreboot itss.c + */ + +#include <common.h> +#include <dm.h> +#include <dt-structs.h> +#include <irq.h> +#include <p2sb.h> +#include <spl.h> +#include <asm/arch/itss.h> + +struct apl_itss_platdata { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + /* Put this first since driver model will copy the data here */ + struct dtd_intel_apl_itss dtplat; +#endif +}; + +/* struct pmc_route - Routing for PMC to GPIO */ +struct pmc_route { + u32 pmc; + u32 gpio; +}; + +struct apl_itss_priv { + struct pmc_route *route; + uint route_count; + u32 irq_snapshot[NUM_IPC_REGS]; +}; + +static int apl_set_polarity(struct udevice *dev, uint irq, bool active_low) +{ + u32 mask; + uint reg; + + if (irq > ITSS_MAX_IRQ) + return -EINVAL; + + reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * (irq / IRQS_PER_IPC); + mask = 1 << (irq % IRQS_PER_IPC); + + pcr_clrsetbits32(dev, reg, mask, active_low ? mask : 0); + + return 0; +} + +#ifndef CONFIG_TPL_BUILD +static int apl_snapshot_polarities(struct udevice *dev) +{ + struct apl_itss_priv *priv = dev_get_priv(dev); + const int start = GPIO_IRQ_START; + const int end = GPIO_IRQ_END; + int reg_start; + int reg_end; + int i; + + reg_start = start / IRQS_PER_IPC; + reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC; + + for (i = reg_start; i < reg_end; i++) { + uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; + + priv->irq_snapshot[i] = pcr_read32(dev, reg); + } + + return 0; +} + +static void show_polarities(struct udevice *dev, const char *msg) +{ + int i; + + log_info("ITSS IRQ Polarities %s:\n", msg); + for (i = 0; i < NUM_IPC_REGS; i++) { + uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; + + log_info("IPC%d: 0x%08x\n", i, pcr_read32(dev, reg)); + } +} + +static int apl_restore_polarities(struct udevice *dev) +{ + struct apl_itss_priv *priv = dev_get_priv(dev); + const int start = GPIO_IRQ_START; + const int end = GPIO_IRQ_END; + int reg_start; + int reg_end; + int i; + + show_polarities(dev, "Before"); + + reg_start = start / IRQS_PER_IPC; + reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC; + + for (i = reg_start; i < reg_end; i++) { + u32 mask; + u16 reg; + int irq_start; + int irq_end; + + irq_start = i * IRQS_PER_IPC; + irq_end = min(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ); + + if (start > irq_end) + continue; + if (end < irq_start) + break; + + /* Track bits within the bounds of of the register */ + irq_start = max(start, irq_start) % IRQS_PER_IPC; + irq_end = min(end, irq_end) % IRQS_PER_IPC; + + /* Create bitmask of the inclusive range of start and end */ + mask = (((1U << irq_end) - 1) | (1U << irq_end)); + mask &= ~((1U << irq_start) - 1); + + reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; + pcr_clrsetbits32(dev, reg, mask, mask & priv->irq_snapshot[i]); + } + + show_polarities(dev, "After"); + + return 0; +} +#endif + +static int apl_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) +{ + struct apl_itss_priv *priv = dev_get_priv(dev); + struct pmc_route *route; + int i; + + for (i = 0, route = priv->route; i < priv->route_count; i++, route++) { + if (pmc_gpe_num == route->pmc) + return route->gpio; + } + + return -ENOENT; +} + +static int apl_itss_ofdata_to_platdata(struct udevice *dev) +{ + struct apl_itss_priv *priv = dev_get_priv(dev); + int ret; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct apl_itss_platdata *plat = dev_get_platdata(dev); + struct dtd_intel_apl_itss *dtplat = &plat->dtplat; + + /* + * It would be nice to do this in the bind() method, but with + * of-platdata binding happens in the order that DM finds things in the + * linker list (i.e. alphabetical order by driver name). So the GPIO + * device may well be bound before its parent (p2sb), and this call + * will fail if p2sb is not bound yet. + * + * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc + */ + ret = p2sb_set_port_id(dev, dtplat->intel_p2sb_port_id); + if (ret) + return log_msg_ret("Could not set port id", ret); + priv->route = (struct pmc_route *)dtplat->intel_pmc_routes; + priv->route_count = ARRAY_SIZE(dtplat->intel_pmc_routes) / + sizeof(struct pmc_route); +#else + int size; + + size = dev_read_size(dev, "intel,pmc-routes"); + if (size < 0) + return size; + priv->route = malloc(size); + if (!priv->route) + return -ENOMEM; + ret = dev_read_u32_array(dev, "intel,pmc-routes", (u32 *)priv->route, + size / sizeof(fdt32_t)); + if (ret) + return log_msg_ret("Cannot read pmc-routes", ret); + priv->route_count = size / sizeof(struct pmc_route); +#endif + + return 0; +} + +static const struct irq_ops apl_itss_ops = { + .route_pmc_gpio_gpe = apl_route_pmc_gpio_gpe, + .set_polarity = apl_set_polarity, +#ifndef CONFIG_TPL_BUILD + .snapshot_polarities = apl_snapshot_polarities, + .restore_polarities = apl_restore_polarities, +#endif +}; + +static const struct udevice_id apl_itss_ids[] = { + { .compatible = "intel,apl-itss"}, + { } +}; + +U_BOOT_DRIVER(apl_itss_drv) = { + .name = "intel_apl_itss", + .id = UCLASS_IRQ, + .of_match = apl_itss_ids, + .ops = &apl_itss_ops, + .ofdata_to_platdata = apl_itss_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct apl_itss_platdata), + .priv_auto_alloc_size = sizeof(struct apl_itss_priv), +}; diff --git a/arch/x86/cpu/apollolake/lpc.c b/arch/x86/cpu/apollolake/lpc.c new file mode 100644 index 0000000000..45b2144fc6 --- /dev/null +++ b/arch/x86/cpu/apollolake/lpc.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + * + * From coreboot Apollo Lake support lpc.c + */ + +#include <common.h> +#include <dm.h> +#include <spl.h> +#include <asm/lpc_common.h> +#include <asm/pci.h> +#include <asm/arch/iomap.h> +#include <asm/arch/lpc.h> +#include <linux/log2.h> + +void lpc_enable_fixed_io_ranges(uint io_enables) +{ + pci_x86_clrset_config(PCH_DEV_LPC, LPC_IO_ENABLES, 0, io_enables, + PCI_SIZE_16); +} + +/* + * Find the first unused IO window. + * Returns -1 if not found, 0 for reg 0x84, 1 for reg 0x88 ... + */ +static int find_unused_pmio_window(void) +{ + int i; + ulong lgir; + + for (i = 0; i < LPC_NUM_GENERIC_IO_RANGES; i++) { + pci_x86_read_config(PCH_DEV_LPC, LPC_GENERIC_IO_RANGE(i), + &lgir, PCI_SIZE_32); + + if (!(lgir & LPC_LGIR_EN)) + return i; + } + + return -1; +} + +int lpc_open_pmio_window(uint base, uint size) +{ + int i, lgir_reg_num; + u32 lgir_reg_offset, lgir, window_size, alignment; + ulong bridged_size, bridge_base; + ulong reg; + + log_debug("LPC: Trying to open IO window from %x size %x\n", base, + size); + + bridged_size = 0; + bridge_base = base; + + while (bridged_size < size) { + /* Each IO range register can only open a 256-byte window */ + window_size = min(size, (uint)LPC_LGIR_MAX_WINDOW_SIZE); + + /* Window size must be a power of two for the AMASK to work */ + alignment = 1UL << (order_base_2(window_size)); + window_size = ALIGN(window_size, alignment); + + /* Address[15:2] in LGIR[15:12] and Mask[7:2] in LGIR[23:18] */ + lgir = (bridge_base & LPC_LGIR_ADDR_MASK) | LPC_LGIR_EN; + lgir |= ((window_size - 1) << 16) & LPC_LGIR_AMASK_MASK; + + /* Skip programming if same range already programmed */ + for (i = 0; i < LPC_NUM_GENERIC_IO_RANGES; i++) { + pci_x86_read_config(PCH_DEV_LPC, + LPC_GENERIC_IO_RANGE(i), ®, + PCI_SIZE_32); + if (lgir == reg) + return -EALREADY; + } + + lgir_reg_num = find_unused_pmio_window(); + if (lgir_reg_num < 0) { + log_err("LPC: Cannot open IO window: %lx size %lx\n", + bridge_base, size - bridged_size); + log_err("No more IO windows\n"); + + return -ENOSPC; + } + lgir_reg_offset = LPC_GENERIC_IO_RANGE(lgir_reg_num); + + pci_x86_write_config(PCH_DEV_LPC, lgir_reg_offset, lgir, + PCI_SIZE_32); + + log_debug("LPC: Opened IO window LGIR%d: base %lx size %x\n", + lgir_reg_num, bridge_base, window_size); + + bridged_size += window_size; + bridge_base += window_size; + } + + return 0; +} + +void lpc_io_setup_comm_a_b(void) +{ + /* ComA Range 3F8h-3FFh [2:0] */ + u16 com_ranges = LPC_IOD_COMA_RANGE; + u16 com_enable = LPC_IOE_COMA_EN; + + /* Setup I/O Decode Range Register for LPC */ + pci_write_config16(PCH_DEV_LPC, LPC_IO_DECODE, com_ranges); + /* Enable ComA and ComB Port */ + lpc_enable_fixed_io_ranges(com_enable); +} + +static const struct udevice_id apl_lpc_ids[] = { + { .compatible = "intel,apl-lpc" }, + { } +}; + +/* All pads are LPC already configured by the hostbridge, so no probing here */ +U_BOOT_DRIVER(apl_lpc_drv) = { + .name = "intel_apl_lpc", + .id = UCLASS_LPC, + .of_match = apl_lpc_ids, +}; diff --git a/arch/x86/cpu/apollolake/p2sb.c b/arch/x86/cpu/apollolake/p2sb.c new file mode 100644 index 0000000000..eb27861b7a --- /dev/null +++ b/arch/x86/cpu/apollolake/p2sb.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Primary-to-Sideband Bridge + * + * Copyright 2019 Google LLC + */ + +#define LOG_CATEGORY UCLASS_P2SB + +#include <common.h> +#include <dm.h> +#include <dt-structs.h> +#include <p2sb.h> +#include <spl.h> +#include <asm/pci.h> + +struct p2sb_platdata { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_intel_apl_p2sb dtplat; +#endif + ulong mmio_base; + pci_dev_t bdf; +}; + +/* PCI config space registers */ +#define HPTC_OFFSET 0x60 +#define HPTC_ADDR_ENABLE_BIT BIT(7) + +/* High Performance Event Timer Configuration */ +#define P2SB_HPTC 0x60 +#define P2SB_HPTC_ADDRESS_ENABLE BIT(7) + +/* + * ADDRESS_SELECT ENCODING_RANGE + * 0 0xfed0 0000 - 0xfed0 03ff + * 1 0xfed0 1000 - 0xfed0 13ff + * 2 0xfed0 2000 - 0xfed0 23ff + * 3 0xfed0 3000 - 0xfed0 33ff + */ +#define P2SB_HPTC_ADDRESS_SELECT_0 (0 << 0) +#define P2SB_HPTC_ADDRESS_SELECT_1 (1 << 0) +#define P2SB_HPTC_ADDRESS_SELECT_2 (2 << 0) +#define P2SB_HPTC_ADDRESS_SELECT_3 (3 << 0) + +/* + * apl_p2sb_early_init() - Enable decoding for HPET range + * + * This is needed by FSP-M which uses the High Precision Event Timer. + * + * @dev: P2SB device + * @return 0 if OK, -ve on error + */ +static int apl_p2sb_early_init(struct udevice *dev) +{ + struct p2sb_platdata *plat = dev_get_platdata(dev); + pci_dev_t pdev = plat->bdf; + + /* + * Enable decoding for HPET memory address range. + * HPTC_OFFSET(0x60) bit 7, when set the P2SB will decode + * the High Performance Timer memory address range + * selected by bits 1:0 + */ + pci_x86_write_config(pdev, HPTC_OFFSET, HPTC_ADDR_ENABLE_BIT, + PCI_SIZE_8); + + /* Enable PCR Base address in PCH */ + pci_x86_write_config(pdev, PCI_BASE_ADDRESS_0, plat->mmio_base, + PCI_SIZE_32); + pci_x86_write_config(pdev, PCI_BASE_ADDRESS_1, 0, PCI_SIZE_32); + + /* Enable P2SB MSE */ + pci_x86_write_config(pdev, PCI_COMMAND, PCI_COMMAND_MASTER | + PCI_COMMAND_MEMORY, PCI_SIZE_8); + + return 0; +} + +static int apl_p2sb_spl_init(struct udevice *dev) +{ + /* Enable decoding for HPET. Needed for FSP global pointer storage */ + dm_pci_write_config(dev, P2SB_HPTC, P2SB_HPTC_ADDRESS_SELECT_0 | + P2SB_HPTC_ADDRESS_ENABLE, PCI_SIZE_8); + + return 0; +} + +int apl_p2sb_ofdata_to_platdata(struct udevice *dev) +{ + struct p2sb_uc_priv *upriv = dev_get_uclass_priv(dev); + struct p2sb_platdata *plat = dev_get_platdata(dev); + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + int ret; + + if (spl_phase() == PHASE_TPL) { + u32 base[2]; + + /* TPL sets up the initial BAR */ + ret = dev_read_u32_array(dev, "early-regs", base, + ARRAY_SIZE(base)); + if (ret) + return log_msg_ret("Missing/short early-regs", ret); + plat->mmio_base = base[0]; + plat->bdf = pci_get_devfn(dev); + if (plat->bdf < 0) + return log_msg_ret("Cannot get p2sb PCI address", + plat->bdf); + } else { + plat->mmio_base = dev_read_addr_pci(dev); + /* Don't set BDF since it should not be used */ + if (!plat->mmio_base || plat->mmio_base == FDT_ADDR_T_NONE) + return -EINVAL; + } +#else + plat->mmio_base = plat->dtplat.early_regs[0]; + plat->bdf = pci_ofplat_get_devfn(plat->dtplat.reg[0]); +#endif + upriv->mmio_base = plat->mmio_base; + debug("p2sb: mmio_base=%x\n", (uint)plat->mmio_base); + + return 0; +} + +static int apl_p2sb_probe(struct udevice *dev) +{ + if (spl_phase() == PHASE_TPL) + return apl_p2sb_early_init(dev); + else if (spl_phase() == PHASE_SPL) + return apl_p2sb_spl_init(dev); + + return 0; +} + +static int p2sb_child_post_bind(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev); + int ret; + u32 pid; + + ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid); + if (ret) + return ret; + pplat->pid = pid; +#endif + + return 0; +} + +static const struct udevice_id apl_p2sb_ids[] = { + { .compatible = "intel,apl-p2sb" }, + { } +}; + +U_BOOT_DRIVER(apl_p2sb_drv) = { + .name = "intel_apl_p2sb", + .id = UCLASS_P2SB, + .of_match = apl_p2sb_ids, + .probe = apl_p2sb_probe, + .ofdata_to_platdata = apl_p2sb_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct p2sb_platdata), + .per_child_platdata_auto_alloc_size = + sizeof(struct p2sb_child_platdata), + .child_post_bind = p2sb_child_post_bind, +}; diff --git a/arch/x86/cpu/apollolake/pch.c b/arch/x86/cpu/apollolake/pch.c new file mode 100644 index 0000000000..1a5a985221 --- /dev/null +++ b/arch/x86/cpu/apollolake/pch.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <pch.h> +#include <spl.h> +#include <asm/lpc_common.h> + +#define BIOS_CTRL 0xdc + +static int apl_set_spi_protect(struct udevice *dev, bool protect) +{ + if (spl_phase() == PHASE_SPL) + return lpc_set_spi_protect(dev, BIOS_CTRL, protect); + + return 0; +} + +static const struct pch_ops apl_pch_ops = { + .set_spi_protect = apl_set_spi_protect, +}; + +static const struct udevice_id apl_pch_ids[] = { + { .compatible = "intel,apl-pch" }, + { } +}; + +U_BOOT_DRIVER(apl_pch) = { + .name = "apl_pch", + .id = UCLASS_PCH, + .of_match = apl_pch_ids, + .ops = &apl_pch_ops, +}; diff --git a/arch/x86/cpu/apollolake/pmc.c b/arch/x86/cpu/apollolake/pmc.c new file mode 100644 index 0000000000..683c6082f2 --- /dev/null +++ b/arch/x86/cpu/apollolake/pmc.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Intel Corporation. + * Copyright 2019 Google LLC + * + * Modified from coreboot pmclib.c, pmc.c and pmutil.c + */ + +#define LOG_CATEGORY UCLASS_ACPI_PMC + +#include <common.h> +#include <acpi_s3.h> +#include <dt-structs.h> +#include <dm.h> +#include <spl.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <power/acpi_pmc.h> + +#define GPIO_GPE_CFG 0x1050 + +/* Memory mapped IO registers behind PMC_BASE_ADDRESS */ +#define PRSTS 0x1000 +#define GEN_PMCON1 0x1020 +#define COLD_BOOT_STS BIT(27) +#define COLD_RESET_STS BIT(26) +#define WARM_RESET_STS BIT(25) +#define GLOBAL_RESET_STS BIT(24) +#define SRS BIT(20) +#define MS4V BIT(18) +#define RPS BIT(2) +#define GEN_PMCON1_CLR1_BITS (COLD_BOOT_STS | COLD_RESET_STS | \ + WARM_RESET_STS | GLOBAL_RESET_STS | \ + SRS | MS4V) +#define GEN_PMCON2 0x1024 +#define GEN_PMCON3 0x1028 + +/* Offset of TCO registers from ACPI base I/O address */ +#define TCO_REG_OFFSET 0x60 +#define TCO1_STS 0x64 +#define DMISCI_STS BIT(9) +#define BOOT_STS BIT(18) +#define TCO2_STS 0x66 +#define TCO1_CNT 0x68 +#define TCO_LOCK BIT(12) +#define TCO2_CNT 0x6a + +enum { + ETR = 0x1048, + CF9_LOCK = 1UL << 31, + CF9_GLB_RST = 1 << 20, +}; + +struct apl_pmc_platdata { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_intel_apl_pmc dtplat; +#endif + pci_dev_t bdf; +}; + +static int apl_pmc_fill_power_state(struct udevice *dev) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); + + upriv->tco1_sts = inw(upriv->acpi_base + TCO1_STS); + upriv->tco2_sts = inw(upriv->acpi_base + TCO2_STS); + + upriv->prsts = readl(upriv->pmc_bar0 + PRSTS); + upriv->gen_pmcon1 = readl(upriv->pmc_bar0 + GEN_PMCON1); + upriv->gen_pmcon2 = readl(upriv->pmc_bar0 + GEN_PMCON2); + upriv->gen_pmcon3 = readl(upriv->pmc_bar0 + GEN_PMCON3); + + return 0; +} + +static int apl_prev_sleep_state(struct udevice *dev, int prev_sleep_state) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); + + /* WAK_STS bit will not be set when waking from G3 state */ + if (!(upriv->pm1_sts & WAK_STS) && + (upriv->gen_pmcon1 & COLD_BOOT_STS)) + prev_sleep_state = ACPI_S5; + + return prev_sleep_state; +} + +static int apl_disable_tco(struct udevice *dev) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); + + pmc_disable_tco_base(upriv->acpi_base + TCO_REG_OFFSET); + + return 0; +} + +static int apl_global_reset_set_enable(struct udevice *dev, bool enable) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); + + if (enable) + setbits_le32(upriv->pmc_bar0 + ETR, CF9_GLB_RST); + else + clrbits_le32(upriv->pmc_bar0 + ETR, CF9_GLB_RST); + + return 0; +} + +int apl_pmc_ofdata_to_uc_platdata(struct udevice *dev) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); + struct apl_pmc_platdata *plat = dev_get_platdata(dev); + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + u32 base[6]; + int size; + int ret; + + ret = dev_read_u32_array(dev, "early-regs", base, ARRAY_SIZE(base)); + if (ret) + return log_msg_ret("Missing/short early-regs", ret); + upriv->pmc_bar0 = (void *)base[0]; + upriv->pmc_bar2 = (void *)base[2]; + upriv->acpi_base = base[4]; + + /* Since PCI is not enabled, we must get the BDF manually */ + plat->bdf = pci_get_devfn(dev); + if (plat->bdf < 0) + return log_msg_ret("Cannot get PMC PCI address", plat->bdf); + + /* Get the dwX values for pmc gpe settings */ + size = dev_read_size(dev, "gpe0-dw"); + if (size < 0) + return log_msg_ret("Cannot read gpe0-dm", size); + upriv->gpe0_count = size / sizeof(u32); + ret = dev_read_u32_array(dev, "gpe0-dw", upriv->gpe0_dw, + upriv->gpe0_count); + if (ret) + return log_msg_ret("Bad gpe0-dw", ret); + + return pmc_ofdata_to_uc_platdata(dev); +#else + struct dtd_intel_apl_pmc *dtplat = &plat->dtplat; + + plat->bdf = pci_ofplat_get_devfn(dtplat->reg[0]); + upriv->pmc_bar0 = (void *)dtplat->early_regs[0]; + upriv->pmc_bar2 = (void *)dtplat->early_regs[2]; + upriv->acpi_base = dtplat->early_regs[4]; + upriv->gpe0_dwx_mask = dtplat->gpe0_dwx_mask; + upriv->gpe0_dwx_shift_base = dtplat->gpe0_dwx_shift_base; + upriv->gpe0_sts_reg = dtplat->gpe0_sts; + upriv->gpe0_sts_reg += upriv->acpi_base; + upriv->gpe0_en_reg = dtplat->gpe0_en; + upriv->gpe0_en_reg += upriv->acpi_base; + upriv->gpe0_count = min((int)ARRAY_SIZE(dtplat->gpe0_dw), GPE0_REG_MAX); + memcpy(upriv->gpe0_dw, dtplat->gpe0_dw, sizeof(dtplat->gpe0_dw)); +#endif + upriv->gpe_cfg = (u32 *)(upriv->pmc_bar0 + GPIO_GPE_CFG); + + return 0; +} + +static int enable_pmcbar(struct udevice *dev) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); + struct apl_pmc_platdata *priv = dev_get_platdata(dev); + pci_dev_t pmc = priv->bdf; + + /* + * Set PMC base addresses and enable decoding. BARs 1 and 3 are 64-bit + * BARs. + */ + pci_x86_write_config(pmc, PCI_BASE_ADDRESS_0, (ulong)upriv->pmc_bar0, + PCI_SIZE_32); + pci_x86_write_config(pmc, PCI_BASE_ADDRESS_1, 0, PCI_SIZE_32); + pci_x86_write_config(pmc, PCI_BASE_ADDRESS_2, (ulong)upriv->pmc_bar2, + PCI_SIZE_32); + pci_x86_write_config(pmc, PCI_BASE_ADDRESS_3, 0, PCI_SIZE_32); + pci_x86_write_config(pmc, PCI_BASE_ADDRESS_4, upriv->acpi_base, + PCI_SIZE_16); + pci_x86_write_config(pmc, PCI_COMMAND, PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + PCI_SIZE_16); + + return 0; +} + +static int apl_pmc_probe(struct udevice *dev) +{ + if (spl_phase() == PHASE_TPL) + return enable_pmcbar(dev); + + return 0; +} + +static struct acpi_pmc_ops apl_pmc_ops = { + .init = apl_pmc_fill_power_state, + .prev_sleep_state = apl_prev_sleep_state, + .disable_tco = apl_disable_tco, + .global_reset_set_enable = apl_global_reset_set_enable, +}; + +static const struct udevice_id apl_pmc_ids[] = { + { .compatible = "intel,apl-pmc" }, + { } +}; + +U_BOOT_DRIVER(apl_pmc) = { + .name = "intel_apl_pmc", + .id = UCLASS_ACPI_PMC, + .of_match = apl_pmc_ids, + .ofdata_to_platdata = apl_pmc_ofdata_to_uc_platdata, + .probe = apl_pmc_probe, + .ops = &apl_pmc_ops, + .platdata_auto_alloc_size = sizeof(struct apl_pmc_platdata), +}; diff --git a/arch/x86/cpu/apollolake/punit.c b/arch/x86/cpu/apollolake/punit.c new file mode 100644 index 0000000000..1a131fb0b1 --- /dev/null +++ b/arch/x86/cpu/apollolake/punit.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <spl.h> +#include <asm/cpu.h> +#include <asm/cpu_common.h> +#include <asm/intel_regs.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <asm/arch/systemagent.h> + +/* + * Punit Initialisation code. This all isn't documented, but + * this is the recipe. + */ +static int punit_init(struct udevice *dev) +{ + struct udevice *cpu; + u32 reg; + ulong start; + int ret; + + /* Thermal throttle activation offset */ + ret = uclass_first_device_err(UCLASS_CPU, &cpu); + if (ret) + return log_msg_ret("Cannot find CPU", ret); + cpu_configure_thermal_target(cpu); + + /* + * Software Core Disable Mask (P_CR_CORE_DISABLE_MASK_0_0_0_MCHBAR). + * Enable all cores here. + */ + writel(0, MCHBAR_REG(CORE_DISABLE_MASK)); + + /* P-Unit bring up */ + reg = readl(MCHBAR_REG(BIOS_RESET_CPL)); + if (reg == 0xffffffff) { + /* P-unit not found */ + debug("Punit MMIO not available\n"); + return -ENOENT; + } + + /* Set Punit interrupt pin IPIN offset 3D */ + dm_pci_write_config8(dev, PCI_INTERRUPT_PIN, 0x2); + + /* Set PUINT IRQ to 24 and INTPIN LOCK */ + writel(PUINT_THERMAL_DEVICE_IRQ_VEC_NUMBER | + PUINT_THERMAL_DEVICE_IRQ_LOCK, + MCHBAR_REG(PUNIT_THERMAL_DEVICE_IRQ)); + + /* Stage0 BIOS Reset Complete (RST_CPL) */ + enable_bios_reset_cpl(); + + /* + * Poll for bit 8 to check if PCODE has completed its action in response + * to BIOS Reset complete. We wait here till 1 ms for the bit to get + * set. + */ + start = get_timer(0); + while (!(readl(MCHBAR_REG(BIOS_RESET_CPL)) & PCODE_INIT_DONE)) { + if (get_timer(start) > 1) { + debug("PCODE Init Done timeout\n"); + return -ETIMEDOUT; + } + udelay(100); + } + debug("PUNIT init complete\n"); + + return 0; +} + +static int apl_punit_probe(struct udevice *dev) +{ + if (spl_phase() == PHASE_SPL) + return punit_init(dev); + + return 0; +} + +static const struct udevice_id apl_syscon_ids[] = { + { .compatible = "intel,apl-punit", .data = X86_SYSCON_PUNIT }, + { } +}; + +U_BOOT_DRIVER(syscon_intel_punit) = { + .name = "intel_punit_syscon", + .id = UCLASS_SYSCON, + .of_match = apl_syscon_ids, + .probe = apl_punit_probe, +}; diff --git a/arch/x86/cpu/apollolake/spl.c b/arch/x86/cpu/apollolake/spl.c new file mode 100644 index 0000000000..7ab7243311 --- /dev/null +++ b/arch/x86/cpu/apollolake/spl.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <binman_sym.h> +#include <dm.h> +#include <spi.h> +#include <spl.h> +#include <spi_flash.h> +#include <asm/fast_spi.h> +#include <asm/spl.h> +#include <asm/arch/cpu.h> +#include <asm/arch/iomap.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> + +/* This reads the next phase from mapped SPI flash */ +static int rom_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) +{ + ulong spl_pos = spl_get_image_pos(); + ulong spl_size = spl_get_image_size(); + struct udevice *dev; + ulong map_base; + size_t map_size; + uint offset; + int ret; + + spl_image->size = CONFIG_SYS_MONITOR_LEN; /* We don't know SPL size */ + spl_image->entry_point = spl_phase() == PHASE_TPL ? + CONFIG_SPL_TEXT_BASE : CONFIG_SYS_TEXT_BASE; + spl_image->load_addr = spl_image->entry_point; + spl_image->os = IH_OS_U_BOOT; + spl_image->name = "U-Boot"; + debug("Reading from mapped SPI %lx, size %lx", spl_pos, spl_size); + + if (CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT)) { + ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev); + if (ret) + return log_msg_ret("spi_flash", ret); + if (!dev) + return log_msg_ret("spi_flash dev", -ENODEV); + ret = dm_spi_get_mmap(dev, &map_base, &map_size, &offset); + if (ret) + return log_msg_ret("mmap", ret); + } else { + ret = fast_spi_get_bios_mmap(PCH_DEV_SPI, &map_base, &map_size, + &offset); + if (ret) + return ret; + } + spl_pos += map_base & ~0xff000000; + debug(", base %lx, pos %lx\n", map_base, spl_pos); + bootstage_start(BOOTSTAGE_ID_ACCUM_MMAP_SPI, "mmap_spi"); + memcpy((void *)spl_image->load_addr, (void *)spl_pos, spl_size); + cpu_flush_l1d_to_l2(); + bootstage_accum(BOOTSTAGE_ID_ACCUM_MMAP_SPI); + + return 0; +} +SPL_LOAD_IMAGE_METHOD("Mapped SPI", 2, BOOT_DEVICE_SPI_MMAP, rom_load_image); + +#if CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT) + +static int apl_flash_std_read(struct udevice *dev, u32 offset, size_t len, + void *buf) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + struct mtd_info *mtd = &flash->mtd; + size_t retlen; + + return log_ret(mtd->_read(mtd, offset, len, &retlen, buf)); +} + +static int apl_flash_probe(struct udevice *dev) +{ + return spi_flash_std_probe(dev); +} + +/* + * Manually set the parent of the SPI flash to SPI, since dtoc doesn't. We also + * need to allocate the parent_platdata since by the time this function is + * called device_bind() has already gone past that step. + */ +static int apl_flash_bind(struct udevice *dev) +{ + if (CONFIG_IS_ENABLED(OF_PLATDATA)) { + struct dm_spi_slave_platdata *plat; + struct udevice *spi; + int ret; + + ret = uclass_first_device_err(UCLASS_SPI, &spi); + if (ret) + return ret; + dev->parent = spi; + + plat = calloc(sizeof(*plat), 1); + if (!plat) + return -ENOMEM; + dev->parent_platdata = plat; + } + + return 0; +} + +static const struct dm_spi_flash_ops apl_flash_ops = { + .read = apl_flash_std_read, +}; + +static const struct udevice_id apl_flash_ids[] = { + { .compatible = "jedec,spi-nor" }, + { } +}; + +U_BOOT_DRIVER(winbond_w25q128fw) = { + .name = "winbond_w25q128fw", + .id = UCLASS_SPI_FLASH, + .of_match = apl_flash_ids, + .bind = apl_flash_bind, + .probe = apl_flash_probe, + .priv_auto_alloc_size = sizeof(struct spi_flash), + .ops = &apl_flash_ops, +}; + +/* This uses a SPI flash device to read the next phase */ +static int spl_fast_spi_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) +{ + ulong spl_pos = spl_get_image_pos(); + ulong spl_size = spl_get_image_size(); + struct udevice *dev; + int ret; + + ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev); + if (ret) + return ret; + + spl_image->size = CONFIG_SYS_MONITOR_LEN; /* We don't know SPL size */ + spl_image->entry_point = spl_phase() == PHASE_TPL ? + CONFIG_SPL_TEXT_BASE : CONFIG_SYS_TEXT_BASE; + spl_image->load_addr = spl_image->entry_point; + spl_image->os = IH_OS_U_BOOT; + spl_image->name = "U-Boot"; + spl_pos &= ~0xff000000; + debug("Reading from flash %lx, size %lx\n", spl_pos, spl_size); + ret = spi_flash_read_dm(dev, spl_pos, spl_size, + (void *)spl_image->load_addr); + cpu_flush_l1d_to_l2(); + if (ret) + return ret; + + return 0; +} +SPL_LOAD_IMAGE_METHOD("Fast SPI", 1, BOOT_DEVICE_FAST_SPI, + spl_fast_spi_load_image); + +void board_boot_order(u32 *spl_boot_list) +{ + bool use_spi_flash = IS_ENABLED(CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH); + + if (use_spi_flash) { + spl_boot_list[0] = BOOT_DEVICE_FAST_SPI; + spl_boot_list[1] = BOOT_DEVICE_SPI_MMAP; + } else { + spl_boot_list[0] = BOOT_DEVICE_SPI_MMAP; + spl_boot_list[1] = BOOT_DEVICE_FAST_SPI; + } +} + +#else + +void board_boot_order(u32 *spl_boot_list) +{ + spl_boot_list[0] = BOOT_DEVICE_SPI_MMAP; +} +#endif diff --git a/arch/x86/cpu/apollolake/systemagent.c b/arch/x86/cpu/apollolake/systemagent.c new file mode 100644 index 0000000000..b6bc2ba14f --- /dev/null +++ b/arch/x86/cpu/apollolake/systemagent.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Intel Corporation. + * Take from coreboot project file of the same name + */ + +#include <common.h> +#include <asm/intel_regs.h> +#include <asm/io.h> +#include <asm/arch/systemagent.h> + +void enable_bios_reset_cpl(void) +{ + /* + * Set bits 0+1 of BIOS_RESET_CPL to indicate to the CPU + * that BIOS has initialised memory and power management + * + * The FSP-S does not do this. If we leave this as zero then I believe + * the power-aware interrupts don't work in Linux, and CPU 0 always gets + * the interrupt. + */ + setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 3); +} diff --git a/arch/x86/cpu/apollolake/uart.c b/arch/x86/cpu/apollolake/uart.c new file mode 100644 index 0000000000..f2b356eb44 --- /dev/null +++ b/arch/x86/cpu/apollolake/uart.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Special driver to handle of-platdata + * + * Copyright 2019 Google LLC + * + * Some code from coreboot lpss.c + */ + +#include <common.h> +#include <dm.h> +#include <dt-structs.h> +#include <ns16550.h> +#include <spl.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <asm/lpss.h> + +/* Low-power Subsystem (LPSS) clock register */ +enum { + LPSS_CLOCK_CTL_REG = 0x200, + LPSS_CNT_CLOCK_EN = 1, + LPSS_CNT_CLK_UPDATE = 1U << 31, + LPSS_CLOCK_DIV_N_SHIFT = 16, + LPSS_CLOCK_DIV_N_MASK = 0x7fff << LPSS_CLOCK_DIV_N_SHIFT, + LPSS_CLOCK_DIV_M_SHIFT = 1, + LPSS_CLOCK_DIV_M_MASK = 0x7fff << LPSS_CLOCK_DIV_M_SHIFT, + + /* These set the UART input clock speed */ + LPSS_UART_CLK_M_VAL = 0x25a, + LPSS_UART_CLK_N_VAL = 0x7fff, +}; + +static void lpss_clk_update(void *regs, u32 clk_m_val, u32 clk_n_val) +{ + u32 clk_sel; + + clk_sel = clk_n_val << LPSS_CLOCK_DIV_N_SHIFT | + clk_m_val << LPSS_CLOCK_DIV_M_SHIFT; + clk_sel |= LPSS_CNT_CLK_UPDATE | LPSS_CNT_CLOCK_EN; + + writel(clk_sel, regs + LPSS_CLOCK_CTL_REG); +} + +static void uart_lpss_init(void *regs) +{ + /* Take UART out of reset */ + lpss_reset_release(regs); + + /* Set M and N divisor inputs and enable clock */ + lpss_clk_update(regs, LPSS_UART_CLK_M_VAL, LPSS_UART_CLK_N_VAL); +} + +void apl_uart_init(pci_dev_t bdf, ulong base) +{ + /* Set UART base address */ + pci_x86_write_config(bdf, PCI_BASE_ADDRESS_0, base, PCI_SIZE_32); + + /* Enable memory access and bus master */ + pci_x86_write_config(bdf, PCI_COMMAND, PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER, PCI_SIZE_32); + + uart_lpss_init((void *)base); +} + +/* + * This driver uses its own compatible string but almost everything else from + * the standard ns16550 driver. This allows us to provide an of-platdata + * implementation, since the platdata produced by of-platdata does not match + * struct ns16550_platdata. + * + * When running with of-platdata (generally TPL), the platdata is converted to + * something that ns16550 expects. When running withoutof-platdata (SPL, U-Boot + * proper), we use ns16550's ofdata_to_platdata routine. + */ + +static int apl_ns16550_probe(struct udevice *dev) +{ + struct ns16550_platdata *plat = dev_get_platdata(dev); + + if (!CONFIG_IS_ENABLED(PCI)) + apl_uart_init(plat->bdf, plat->base); + + return ns16550_serial_probe(dev); +} + +static int apl_ns16550_ofdata_to_platdata(struct udevice *dev) +{ +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_intel_apl_ns16550 *dtplat = dev_get_platdata(dev); + struct ns16550_platdata *plat; + + /* + * Convert our platdata to the ns16550's platdata, so we can just use + * that driver + */ + plat = malloc(sizeof(*plat)); + if (!plat) + return -ENOMEM; + plat->base = dtplat->early_regs[0]; + plat->reg_width = 1; + plat->reg_shift = dtplat->reg_shift; + plat->reg_offset = 0; + plat->clock = dtplat->clock_frequency; + plat->fcr = UART_FCR_DEFVAL; + plat->bdf = pci_ofplat_get_devfn(dtplat->reg[0]); + dev->platdata = plat; +#else + int ret; + + ret = ns16550_serial_ofdata_to_platdata(dev); + if (ret) + return ret; +#endif /* OF_PLATDATA */ + + return 0; +} + +static const struct udevice_id apl_ns16550_serial_ids[] = { + { .compatible = "intel,apl-ns16550" }, + { }, +}; + +U_BOOT_DRIVER(apl_ns16550) = { + .name = "intel_apl_ns16550", + .id = UCLASS_SERIAL, + .of_match = apl_ns16550_serial_ids, + .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), + .priv_auto_alloc_size = sizeof(struct NS16550), + .ops = &ns16550_serial_ops, + .ofdata_to_platdata = apl_ns16550_ofdata_to_platdata, + .probe = apl_ns16550_probe, +}; diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c index dfd8afc35f..15bfc5811c 100644 --- a/arch/x86/cpu/broadwell/sdram.c +++ b/arch/x86/cpu/broadwell/sdram.c @@ -83,7 +83,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data) struct mrc_region entry; int ret; - ret = mrccache_get_region(NULL, &entry); + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret; mrc_cache = mrccache_find_current(&entry); @@ -169,12 +169,14 @@ int dram_init(void) pei_data->data_to_save); /* S3 resume: don't save scrambler seed or MRC data */ if (pei_data->boot_mode != SLEEP_STATE_S3) { + struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL]; + /* * This will be copied to SDRAM in reserve_arch(), then written * to SPI flash in mrccache_save() */ - gd->arch.mrc_output = (char *)pei_data->data_to_save; - gd->arch.mrc_output_len = pei_data->data_to_save_size; + mrc->buf = (char *)pei_data->data_to_save; + mrc->len = pei_data->data_to_save_size; } gd->arch.pei_meminfo = pei_data->meminfo; diff --git a/arch/x86/cpu/coreboot/Kconfig b/arch/x86/cpu/coreboot/Kconfig index 93f61f2fa4..c8e6a889d0 100644 --- a/arch/x86/cpu/coreboot/Kconfig +++ b/arch/x86/cpu/coreboot/Kconfig @@ -24,5 +24,6 @@ config SYS_COREBOOT imply CMD_CBFS imply FS_CBFS imply CBMEM_CONSOLE + imply X86_TSC_READ_BASE endif diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 4e59476fc9..d626e38fd1 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -46,6 +46,7 @@ DECLARE_GLOBAL_DATA_PTR; +#ifndef CONFIG_TPL_BUILD static const char *const x86_vendor_name[] = { [X86_VENDOR_INTEL] = "Intel", [X86_VENDOR_CYRIX] = "Cyrix", @@ -58,6 +59,7 @@ static const char *const x86_vendor_name[] = { [X86_VENDOR_NSC] = "NSC", [X86_VENDOR_SIS] = "SiS", }; +#endif int __weak x86_cleanup_before_linux(void) { @@ -114,6 +116,7 @@ int icache_status(void) return 1; } +#ifndef CONFIG_TPL_BUILD const char *cpu_vendor_name(int vendor) { const char *name; @@ -124,6 +127,7 @@ const char *cpu_vendor_name(int vendor) return name; } +#endif char *cpu_get_name(char *name) { diff --git a/arch/x86/cpu/i386/Makefile b/arch/x86/cpu/i386/Makefile index 0c47252610..18e152074a 100644 --- a/arch/x86/cpu/i386/Makefile +++ b/arch/x86/cpu/i386/Makefile @@ -5,5 +5,7 @@ obj-y += call64.o obj-y += cpu.o +ifndef CONFIG_TPL_BUILD obj-y += interrupt.o +endif obj-y += setjmp.o diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index c66382bdd2..2b27617ca3 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -21,6 +21,7 @@ #include <common.h> #include <cpu_func.h> #include <malloc.h> +#include <spl.h> #include <asm/control_regs.h> #include <asm/cpu.h> #include <asm/mp.h> @@ -58,6 +59,8 @@ struct cpuinfo_x86 { uint8_t x86_mask; }; +/* gcc 7.3 does not wwant to drop x86_vendors, so use #ifdef */ +#ifndef CONFIG_TPL_BUILD /* * List of cpu vendor strings along with their normalized * id values. @@ -78,6 +81,7 @@ static const struct { { X86_VENDOR_NSC, "Geode by NSC", }, { X86_VENDOR_SIS, "SiS SiS SiS ", }, }; +#endif static void load_ds(u32 segment) { @@ -199,6 +203,7 @@ static inline int test_cyrix_52div(void) return (unsigned char) (test >> 8) == 0x02; } +#ifndef CONFIG_TPL_BUILD /* * Detect a NexGen CPU running without BIOS hypercode new enough * to have CPUID. (Thanks to Herbert Oppmann) @@ -219,6 +224,7 @@ static int deep_magic_nexgen_probe(void) : "=a" (ret) : : "cx", "dx"); return ret; } +#endif static bool has_cpuid(void) { @@ -230,6 +236,7 @@ static bool has_mtrr(void) return cpuid_edx(0x00000001) & (1 << 12) ? true : false; } +#ifndef CONFIG_TPL_BUILD static int build_vendor_name(char *vendor_name) { struct cpuid_result result; @@ -242,14 +249,40 @@ static int build_vendor_name(char *vendor_name) return result.eax; } +#endif static void identify_cpu(struct cpu_device_id *cpu) { + cpu->device = 0; /* fix gcc 4.4.4 warning */ + + /* + * Do a quick and dirty check to save space - Intel and AMD only and + * just the vendor. This is enough for most TPL code. + */ + if (spl_phase() == PHASE_TPL) { + struct cpuid_result result; + + result = cpuid(0x00000000); + switch (result.ecx >> 24) { + case 'l': /* GenuineIntel */ + cpu->vendor = X86_VENDOR_INTEL; + break; + case 'D': /* AuthenticAMD */ + cpu->vendor = X86_VENDOR_AMD; + break; + default: + cpu->vendor = X86_VENDOR_ANY; + break; + } + return; + } + +/* gcc 7.3 does not want to drop x86_vendors, so use #ifdef */ +#ifndef CONFIG_TPL_BUILD char vendor_name[16]; int i; vendor_name[0] = '\0'; /* Unset */ - cpu->device = 0; /* fix gcc 4.4.4 warning */ /* Find the id and vendor_name */ if (!has_cpuid()) { @@ -265,9 +298,8 @@ static void identify_cpu(struct cpu_device_id *cpu) /* Detect NexGen with old hypercode */ else if (deep_magic_nexgen_probe()) memcpy(vendor_name, "NexGenDriven", 13); - } - if (has_cpuid()) { - int cpuid_level; + } else { + int cpuid_level; cpuid_level = build_vendor_name(vendor_name); vendor_name[12] = '\0'; @@ -287,6 +319,7 @@ static void identify_cpu(struct cpu_device_id *cpu) break; } } +#endif } static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms) diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 07f27c29ec..cc4e1c962b 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -8,8 +8,18 @@ obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += me_status.o obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += report_platform.o obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += mrc.o endif + +ifdef CONFIG_INTEL_CAR_CQOS +obj-$(CONFIG_TPL_BUILD) += car2.o +ifndef CONFIG_SPL_BUILD +obj-y += car2_uninit.o +endif +endif + obj-y += cpu.o +obj-y += fast_spi.o obj-y += lpc.o +obj-y += lpss.o ifndef CONFIG_TARGET_EFI_APP obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o ifndef CONFIG_$(SPL_)X86_64 diff --git a/arch/x86/cpu/intel_common/car2.S b/arch/x86/cpu/intel_common/car2.S new file mode 100644 index 0000000000..086f987477 --- /dev/null +++ b/arch/x86/cpu/intel_common/car2.S @@ -0,0 +1,448 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file was modified from the coreboot version. + * + * Copyright (C) 2015-2016 Intel Corp. + */ + +#include <config.h> +#include <asm/msr-index.h> +#include <asm/mtrr.h> +#include <asm/post.h> +#include <asm/processor.h> +#include <asm/processor-flags.h> + +#define KiB 1024 + +#define IS_POWER_OF_2(x) (!((x) & ((x) - 1))) + +.global car_init +car_init: + post_code(POST_CAR_START) + + /* + * Use the MTRR default type MSR as a proxy for detecting INIT#. + * Reset the system if any known bits are set in that MSR. That is + * an indication of the CPU not being properly reset. + */ +check_for_clean_reset: + mov $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + and $(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN), %eax + cmp $0, %eax + jz no_reset + /* perform warm reset */ + movw $IO_PORT_RESET, %dx + movb $(SYS_RST | RST_CPU), %al + outb %al, %dx + +no_reset: + post_code(POST_CAR_SIPI) + + /* Clear/disable fixed MTRRs */ + mov $fixed_mtrr_list_size, %ebx + xor %eax, %eax + xor %edx, %edx + +clear_fixed_mtrr: + add $-2, %ebx + movzwl fixed_mtrr_list(%ebx), %ecx + wrmsr + jnz clear_fixed_mtrr + + post_code(POST_CAR_MTRR) + + /* Figure put how many MTRRs we have, and clear them out */ + mov $MTRR_CAP_MSR, %ecx + rdmsr + movzb %al, %ebx /* Number of variable MTRRs */ + mov $MTRR_PHYS_BASE_MSR(0), %ecx + xor %eax, %eax + xor %edx, %edx + +clear_var_mtrr: + wrmsr + inc %ecx + wrmsr + inc %ecx + dec %ebx + jnz clear_var_mtrr + + post_code(POST_CAR_UNCACHEABLE) + + /* Configure default memory type to uncacheable (UC) */ + mov $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + /* Clear enable bits and set default type to UC */ + and $~(MTRR_DEF_TYPE_MASK | MTRR_DEF_TYPE_EN | \ + MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* + * Configure MTRR_PHYS_MASK_HIGH for proper addressing above 4GB + * based on the physical address size supported for this processor + * This is based on read from CPUID EAX = 080000008h, EAX bits [7:0] + * + * Examples: + * MTRR_PHYS_MASK_HIGH = 00000000Fh For 36 bit addressing + * MTRR_PHYS_MASK_HIGH = 0000000FFh For 40 bit addressing + */ + + movl $0x80000008, %eax /* Address sizes leaf */ + cpuid + sub $32, %al + movzx %al, %eax + xorl %esi, %esi + bts %eax, %esi + dec %esi /* esi <- MTRR_PHYS_MASK_HIGH */ + + post_code(POST_CAR_BASE_ADDRESS) + +#if IS_POWER_OF_2(CONFIG_DCACHE_RAM_SIZE) + /* Configure CAR region as write-back (WB) */ + mov $MTRR_PHYS_BASE_MSR(0), %ecx + mov $CONFIG_DCACHE_RAM_BASE, %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + /* Configure the MTRR mask for the size region */ + mov $MTRR_PHYS_MASK(0), %ecx + mov $CONFIG_DCACHE_RAM_SIZE, %eax /* size mask */ + dec %eax + not %eax + or $MTRR_PHYS_MASK_VALID, %eax + movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */ + wrmsr +#elif (CONFIG_DCACHE_RAM_SIZE == 768 * KiB) /* 768 KiB */ + /* Configure CAR region as write-back (WB) */ + mov $MTRR_PHYS_BASE_MSR(0), %ecx + mov $CONFIG_DCACHE_RAM_BASE, %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + mov $MTRR_PHYS_MASK_MSR(0), %ecx + mov $(512 * KiB), %eax /* size mask */ + dec %eax + not %eax + or $MTRR_PHYS_MASK_VALID, %eax + movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */ + wrmsr + + mov $MTRR_PHYS_BASE_MSR(1), %ecx + mov $(CONFIG_DCACHE_RAM_BASE + 512 * KiB), %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + mov $MTRR_PHYS_MASK_MSR(1), %ecx + mov $(256 * KiB), %eax /* size mask */ + dec %eax + not %eax + or $MTRR_PHYS_MASK_VALID, %eax + movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */ + wrmsr +#else +#error "DCACHE_RAM_SIZE is not a power of 2 and setup code is missing" +#endif + post_code(POST_CAR_FILL) + + /* Enable variable MTRRs */ + mov $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + or $MTRR_DEF_TYPE_EN, %eax + wrmsr + + /* Enable caching */ + mov %cr0, %eax + and $~(X86_CR0_CD | X86_CR0_NW), %eax + invd + mov %eax, %cr0 + +#if IS_ENABLED(CONFIG_INTEL_CAR_NEM) + jmp car_nem +#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS) + jmp car_cqos +#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED) + jmp car_nem_enhanced +#else +#error "No CAR mechanism selected: +#endif + jmp car_init_ret + +fixed_mtrr_list: + .word MTRR_FIX_64K_00000_MSR + .word MTRR_FIX_16K_80000_MSR + .word MTRR_FIX_16K_A0000_MSR + .word MTRR_FIX_4K_C0000_MSR + .word MTRR_FIX_4K_C8000_MSR + .word MTRR_FIX_4K_D0000_MSR + .word MTRR_FIX_4K_D8000_MSR + .word MTRR_FIX_4K_E0000_MSR + .word MTRR_FIX_4K_E8000_MSR + .word MTRR_FIX_4K_F0000_MSR + .word MTRR_FIX_4K_F8000_MSR +fixed_mtrr_list_size = . - fixed_mtrr_list + +#if IS_ENABLED(CONFIG_INTEL_CAR_NEM) +.global car_nem +car_nem: + /* Disable cache eviction (setup stage) */ + mov $MSR_EVICT_CTL, %ecx + rdmsr + or $0x1, %eax + wrmsr + + post_code(0x26) + + /* Clear the cache memory region. This will also fill up the cache */ + movl $CONFIG_DCACHE_RAM_BASE, %edi + movl $CONFIG_DCACHE_RAM_SIZE, %ecx + shr $0x02, %ecx + xor %eax, %eax + cld + rep stosl + + post_code(0x27) + + /* Disable cache eviction (run stage) */ + mov $MSR_EVICT_CTL, %ecx + rdmsr + or $0x2, %eax + wrmsr + + post_code(0x28) + + jmp car_init_ret + +#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS) +.global car_cqos +car_cqos: + /* + * Create CBM_LEN_MASK based on CBM_LEN + * Get CPUID.(EAX=10H, ECX=2H):EAX.CBM_LEN[bits 4:0] + */ + mov $0x10, %eax + mov $0x2, %ecx + cpuid + and $0x1f, %eax + add $1, %al + + mov $1, %ebx + mov %al, %cl + shl %cl, %ebx + sub $1, %ebx + + /* Store the CBM_LEN_MASK in mm3 for later use */ + movd %ebx, %mm3 + + /* + * Disable both L1 and L2 prefetcher. For yet-to-understood reason, + * prefetchers slow down filling cache with rep stos in CQOS mode. + */ + mov $MSR_PREFETCH_CTL, %ecx + rdmsr + or $(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax + wrmsr + +#if (CONFIG_DCACHE_RAM_SIZE == CONFIG_L2_CACHE_SIZE) +/* + * If CAR size is set to full L2 size, mask is calculated as all-zeros. + * This is not supported by the CPU/uCode. + */ +#error "CQOS CAR may not use whole L2 cache area" +#endif + + /* Calculate how many bits to be used for CAR */ + xor %edx, %edx + mov $CONFIG_DCACHE_RAM_SIZE, %eax /* dividend */ + mov $CONFIG_CACHE_QOS_SIZE_PER_BIT, %ecx /* divisor */ + div %ecx /* result is in eax */ + mov %eax, %ecx /* save to ecx */ + mov $1, %ebx + shl %cl, %ebx + sub $1, %ebx /* resulting mask is is in ebx */ + + /* Set this mask for initial cache fill */ + mov $MSR_L2_QOS_MASK(0), %ecx + rdmsr + mov %ebx, %eax + wrmsr + + /* Set CLOS selector to 0 */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~MSR_IA32_PQR_ASSOC_MASK, %edx /* select mask 0 */ + wrmsr + + /* We will need to block CAR region from evicts */ + mov $MSR_L2_QOS_MASK(1), %ecx + rdmsr + /* Invert bits that are to be used for cache */ + mov %ebx, %eax + xor $~0, %eax /* invert 32 bits */ + + /* + * Use CBM_LEN_MASK stored in mm3 to set bits based on Capacity Bit + * Mask Length. + */ + movd %mm3, %ebx + and %ebx, %eax + wrmsr + + post_code(0x26) + + /* Clear the cache memory region. This will also fill up the cache */ + movl $CONFIG_DCACHE_RAM_BASE, %edi + movl $CONFIG_DCACHE_RAM_SIZE, %ecx + shr $0x02, %ecx + xor %eax, %eax + cld + rep stosl + + post_code(0x27) + + /* Cache is populated. Use mask 1 that will block evicts */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~MSR_IA32_PQR_ASSOC_MASK, %edx /* clear index bits first */ + or $1, %edx /* select mask 1 */ + wrmsr + + /* Enable prefetchers */ + mov $MSR_PREFETCH_CTL, %ecx + rdmsr + and $~(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax + wrmsr + + post_code(0x28) + + jmp car_init_ret + +#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED) +.global car_nem_enhanced +car_nem_enhanced: + /* Disable cache eviction (setup stage) */ + mov $MSR_EVICT_CTL, %ecx + rdmsr + or $0x1, %eax + wrmsr + post_code(0x26) + + /* Create n-way set associativity of cache */ + xorl %edi, %edi +find_llc_subleaf: + movl %edi, %ecx + movl $0x04, %eax + cpuid + inc %edi + and $0xe0, %al /* EAX[7:5] = Cache Level */ + cmp $0x60, %al /* Check to see if it is LLC */ + jnz find_llc_subleaf + + /* + * Set MSR 0xC91 IA32_L3_MASK_! = 0xE/0xFE/0xFFE/0xFFFE + * for 4/8/16 way of LLC + */ + shr $22, %ebx + inc %ebx + /* Calculate n-way associativity of LLC */ + mov %bl, %cl + + /* + * Maximizing RO cacheability while locking in the CAR to a + * single way since that particular way won't be victim candidate + * for evictions. + * This has been done after programing LLC_WAY_MASK_1 MSR + * with desired LLC way as mentioned below. + * + * Hence create Code and Data Size as per request + * Code Size (RO) : Up to 16M + * Data Size (RW) : Up to 256K + */ + movl $0x01, %eax + /* + * LLC Ways -> LLC_WAY_MASK_1: + * 4: 0x000E + * 8: 0x00FE + * 12: 0x0FFE + * 16: 0xFFFE + * + * These MSRs contain one bit per each way of LLC + * - If this bit is '0' - the way is protected from eviction + * - If this bit is '1' - the way is not protected from eviction + */ + shl %cl, %eax + subl $0x02, %eax + movl $MSR_IA32_L3_MASK_1, %ecx + xorl %edx, %edx + wrmsr + /* + * Set MSR 0xC92 IA32_L3_MASK_2 = 0x1 + * + * For SKL SOC, data size remains 256K consistently. + * Hence, creating 1-way associative cache for Data + */ + mov $MSR_IA32_L3_MASK_2, %ecx + mov $0x01, %eax + xorl %edx, %edx + wrmsr + /* + * Set MSR_IA32_PQR_ASSOC = 0x02 + * + * Possible values: + * 0: Default value, no way mask should be applied + * 1: Apply way mask 1 to LLC + * 2: Apply way mask 2 to LLC + * 3: Shouldn't be use in NEM Mode + */ + movl $MSR_IA32_PQR_ASSOC, %ecx + movl $0x02, %eax + xorl %edx, %edx + wrmsr + + movl $CONFIG_DCACHE_RAM_BASE, %edi + movl $CONFIG_DCACHE_RAM_SIZE, %ecx + shr $0x02, %ecx + xor %eax, %eax + cld + rep stosl + /* + * Set MSR_IA32_PQR_ASSOC = 0x01 + * At this stage we apply LLC_WAY_MASK_1 to the cache. + * i.e. way 0 is protected from eviction. + */ + movl $MSR_IA32_PQR_ASSOC, %ecx + movl $0x01, %eax + xorl %edx, %edx + wrmsr + + post_code(0x27) + /* + * Enable No-Eviction Mode Run State by setting + * NO_EVICT_MODE MSR 2E0h bit [1] = '1'. + */ + + movl $MSR_EVICT_CTL, %ecx + rdmsr + orl $0x02, %eax + wrmsr + + post_code(0x28) + + jmp car_init_ret +#endif + +#if CONFIG_IS_ENABLED(X86_16BIT_INIT) +_dt_ucode_base_size: + /* These next two fields are filled in by binman */ +.globl ucode_base +ucode_base: /* Declared in microcode.h */ + .long 0 /* microcode base */ +.globl ucode_size +ucode_size: /* Declared in microcode.h */ + .long 0 /* microcode size */ + .long CONFIG_SYS_MONITOR_BASE /* code region base */ + .long CONFIG_SYS_MONITOR_LEN /* code region size */ +#endif diff --git a/arch/x86/cpu/intel_common/car2_uninit.S b/arch/x86/cpu/intel_common/car2_uninit.S new file mode 100644 index 0000000000..aba3a5381e --- /dev/null +++ b/arch/x86/cpu/intel_common/car2_uninit.S @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017 Intel Corp. + * Copyright 2019 Google LLC + * Taken from coreboot file exit_car.S + */ + +#include <config.h> +#include <asm/msr-index.h> +#include <asm/mtrr.h> + +.text +.global car_uninit +car_uninit: + + /* + * Retrieve return address from stack as it will get trashed below if + * execution is utilizing the cache-as-ram stack. + */ + pop %ebx + + /* Disable MTRRs */ + mov $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + and $(~(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN)), %eax + wrmsr + +#ifdef CONFIG_INTEL_CAR_NEM +.global car_nem_teardown +car_nem_teardown: + + /* invalidate cache contents */ + invd + + /* Knock down bit 1 then bit 0 of NEM control not combining steps */ + mov $(MSR_EVICT_CTL), %ecx + rdmsr + and $(~(1 << 1)), %eax + wrmsr + and $(~(1 << 0)), %eax + wrmsr + +#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS) +.global car_cqos_teardown +car_cqos_teardown: + + /* Go back to all-evicting mode, set both masks to all-1s */ + mov $MSR_L2_QOS_MASK(0), %ecx + rdmsr + mov $~0, %al + wrmsr + + mov $MSR_L2_QOS_MASK(1), %ecx + rdmsr + mov $~0, %al + wrmsr + + /* Reset CLOS selector to 0 */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~MSR_IA32_PQR_ASSOC_MASK, %edx + wrmsr + +#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED) +.global car_nem_enhanced_teardown +car_nem_enhanced_teardown: + + /* invalidate cache contents */ + invd + + /* Knock down bit 1 then bit 0 of NEM control not combining steps */ + mov $(MSR_EVICT_CTL), %ecx + rdmsr + and $(~(1 << 1)), %eax + wrmsr + and $(~(1 << 0)), %eax + wrmsr + + /* Reset CLOS selector to 0 */ + mov $IA32_PQR_ASSOC, %ecx + rdmsr + and $~IA32_PQR_ASSOC_MASK, %edx + wrmsr +#endif + + /* Return to caller */ + jmp *%ebx diff --git a/arch/x86/cpu/intel_common/fast_spi.c b/arch/x86/cpu/intel_common/fast_spi.c new file mode 100644 index 0000000000..a6e3d0a5bf --- /dev/null +++ b/arch/x86/cpu/intel_common/fast_spi.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/cpu_common.h> +#include <asm/fast_spi.h> +#include <asm/pci.h> + +/* + * Returns bios_start and fills in size of the BIOS region. + */ +static ulong fast_spi_get_bios_region(struct fast_spi_regs *regs, + uint *bios_size) +{ + ulong bios_start, bios_end; + + /* + * BIOS_BFPREG provides info about BIOS-Flash Primary Region Base and + * Limit. Base and Limit fields are in units of 4K. + */ + u32 val = readl(®s->bfp); + + bios_start = (val & SPIBAR_BFPREG_PRB_MASK) << 12; + bios_end = (((val & SPIBAR_BFPREG_PRL_MASK) >> + SPIBAR_BFPREG_PRL_SHIFT) + 1) << 12; + *bios_size = bios_end - bios_start; + + return bios_start; +} + +int fast_spi_get_bios_mmap(pci_dev_t pdev, ulong *map_basep, uint *map_sizep, + uint *offsetp) +{ + struct fast_spi_regs *regs; + ulong bar, base, mmio_base; + + /* Special case to find mapping without probing the device */ + pci_x86_read_config(pdev, PCI_BASE_ADDRESS_0, &bar, PCI_SIZE_32); + mmio_base = bar & PCI_BASE_ADDRESS_MEM_MASK; + regs = (struct fast_spi_regs *)mmio_base; + base = fast_spi_get_bios_region(regs, map_sizep); + *map_basep = (u32)-*map_sizep - base; + *offsetp = base; + + return 0; +} + +int fast_spi_early_init(pci_dev_t pdev, ulong mmio_base) +{ + /* Program Temporary BAR for SPI */ + pci_x86_write_config(pdev, PCI_BASE_ADDRESS_0, + mmio_base | PCI_BASE_ADDRESS_SPACE_MEMORY, + PCI_SIZE_32); + + /* Enable Bus Master and MMIO Space */ + pci_x86_clrset_config(pdev, PCI_COMMAND, 0, PCI_COMMAND_MASTER | + PCI_COMMAND_MEMORY, PCI_SIZE_8); + + /* + * Disable the BIOS write protect so write commands are allowed. + * Enable Prefetching and caching. + */ + pci_x86_clrset_config(pdev, SPIBAR_BIOS_CONTROL, + SPIBAR_BIOS_CONTROL_EISS | + SPIBAR_BIOS_CONTROL_CACHE_DISABLE, + SPIBAR_BIOS_CONTROL_WPD | + SPIBAR_BIOS_CONTROL_PREFETCH_ENABLE, PCI_SIZE_8); + + return 0; +} diff --git a/arch/x86/cpu/intel_common/lpss.c b/arch/x86/cpu/intel_common/lpss.c new file mode 100644 index 0000000000..26a2d2d1e3 --- /dev/null +++ b/arch/x86/cpu/intel_common/lpss.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Special driver to handle of-platdata + * + * Copyright 2019 Google LLC + * + * Some code from coreboot lpss.c + */ + +#include <common.h> +#include <dm.h> +#include <pci.h> +#include <asm/io.h> +#include <asm/lpss.h> + +enum { + LPSS_RESET_CTL_REG = 0x204, + + /* + * Bit 1:0 controls LPSS controller reset. + * + * 00 ->LPSS Host Controller is in reset (Reset Asserted) + * 01/10 ->Reserved + * 11 ->LPSS Host Controller is NOT at reset (Reset Released) + */ + LPSS_CNT_RST_RELEASE = 3, + + /* Power management control and status register */ + PME_CTRL_STATUS = 0x84, + + /* Bit 1:0 Powerstate, controls D0 and D3 state */ + POWER_STATE_MASK = 3, +}; + +/* Take controller out of reset */ +void lpss_reset_release(void *regs) +{ + writel(LPSS_CNT_RST_RELEASE, regs + LPSS_RESET_CTL_REG); +} + +void lpss_set_power_state(struct udevice *dev, enum lpss_pwr_state state) +{ + dm_pci_clrset_config8(dev, PME_CTRL_STATUS, POWER_STATE_MASK, state); +} diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 3adc155818..ed9938f7f7 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -350,14 +350,6 @@ int irq_router_probe(struct udevice *dev) return 0; } -ulong write_pirq_routing_table(ulong addr) -{ - if (!gd->arch.pirq_routing_table) - return addr; - - return copy_pirq_routing_table(addr, gd->arch.pirq_routing_table); -} - static const struct udevice_id irq_router_ids[] = { { .compatible = "intel,irq-router" }, { } @@ -370,8 +362,3 @@ U_BOOT_DRIVER(irq_router_drv) = { .probe = irq_router_probe, .priv_auto_alloc_size = sizeof(struct irq_router), }; - -UCLASS_DRIVER(irq) = { - .id = UCLASS_IRQ, - .name = "irq", -}; diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c index 51ca4ad301..cf34f94a91 100644 --- a/arch/x86/cpu/ivybridge/sdram.c +++ b/arch/x86/cpu/ivybridge/sdram.c @@ -116,7 +116,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data) ret = read_seed_from_cmos(pei_data); if (ret) return ret; - ret = mrccache_get_region(NULL, &entry); + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret; mrc_cache = mrccache_find_current(&entry); @@ -538,12 +538,14 @@ int dram_init(void) /* S3 resume: don't save scrambler seed or MRC data */ if (pei_data->boot_mode != PEI_BOOT_RESUME) { + struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL]; + /* * This will be copied to SDRAM in reserve_arch(), then written * to SPI flash in mrccache_save() */ - gd->arch.mrc_output = (char *)pei_data->mrc_output; - gd->arch.mrc_output_len = pei_data->mrc_output_len; + mrc->buf = (char *)pei_data->mrc_output; + mrc->len = pei_data->mrc_output_len; ret = write_seeds_to_cmos(pei_data); if (ret) debug("Failed to write seeds to CMOS: %d\n", ret); diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index fefbf8f728..7b09f90cd5 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -418,69 +418,6 @@ static int init_bsp(struct udevice **devp) return 0; } -#ifdef CONFIG_QFW -static int qemu_cpu_fixup(void) -{ - int ret; - int cpu_num; - int cpu_online; - struct udevice *dev, *pdev; - struct cpu_platdata *plat; - char *cpu; - - /* first we need to find '/cpus' */ - for (device_find_first_child(dm_root(), &pdev); - pdev; - device_find_next_child(&pdev)) { - if (!strcmp(pdev->name, "cpus")) - break; - } - if (!pdev) { - printf("unable to find cpus device\n"); - return -ENODEV; - } - - /* calculate cpus that are already bound */ - cpu_num = 0; - for (uclass_find_first_device(UCLASS_CPU, &dev); - dev; - uclass_find_next_device(&dev)) { - cpu_num++; - } - - /* get actual cpu number */ - cpu_online = qemu_fwcfg_online_cpus(); - if (cpu_online < 0) { - printf("unable to get online cpu number: %d\n", cpu_online); - return cpu_online; - } - - /* bind addtional cpus */ - dev = NULL; - for (; cpu_num < cpu_online; cpu_num++) { - /* - * allocate device name here as device_bind_driver() does - * not copy device name, 8 bytes are enough for - * sizeof("cpu@") + 3 digits cpu number + '\0' - */ - cpu = malloc(8); - if (!cpu) { - printf("unable to allocate device name\n"); - return -ENOMEM; - } - sprintf(cpu, "cpu@%d", cpu_num); - ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev); - if (ret) { - printf("binding cpu@%d failed: %d\n", cpu_num, ret); - return ret; - } - plat = dev_get_parent_platdata(dev); - plat->cpu_id = cpu_num; - } - return 0; -} -#endif - int mp_init(struct mp_params *p) { int num_aps; @@ -494,11 +431,11 @@ int mp_init(struct mp_params *p) if (ret) return ret; -#ifdef CONFIG_QFW - ret = qemu_cpu_fixup(); - if (ret) - return ret; -#endif + if (IS_ENABLED(CONFIG_QFW)) { + ret = qemu_cpu_fixup(); + if (ret) + return ret; + } ret = init_bsp(&cpu); if (ret) { diff --git a/arch/x86/cpu/qfw_cpu.c b/arch/x86/cpu/qfw_cpu.c new file mode 100644 index 0000000000..49e9dfcf69 --- /dev/null +++ b/arch/x86/cpu/qfw_cpu.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Google, Inc + */ + +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <qfw.h> +#include <dm/lists.h> +#include <dm/uclass-internal.h> +#include <dm/root.h> + +int qemu_cpu_fixup(void) +{ + int ret; + int cpu_num; + int cpu_online; + struct udevice *dev, *pdev; + struct cpu_platdata *plat; + char *cpu; + + /* first we need to find '/cpus' */ + for (device_find_first_child(dm_root(), &pdev); + pdev; + device_find_next_child(&pdev)) { + if (!strcmp(pdev->name, "cpus")) + break; + } + if (!pdev) { + printf("unable to find cpus device\n"); + return -ENODEV; + } + + /* calculate cpus that are already bound */ + cpu_num = 0; + for (uclass_find_first_device(UCLASS_CPU, &dev); + dev; + uclass_find_next_device(&dev)) { + cpu_num++; + } + + /* get actual cpu number */ + cpu_online = qemu_fwcfg_online_cpus(); + if (cpu_online < 0) { + printf("unable to get online cpu number: %d\n", cpu_online); + return cpu_online; + } + + /* bind addtional cpus */ + dev = NULL; + for (; cpu_num < cpu_online; cpu_num++) { + /* + * allocate device name here as device_bind_driver() does + * not copy device name, 8 bytes are enough for + * sizeof("cpu@") + 3 digits cpu number + '\0' + */ + cpu = malloc(8); + if (!cpu) { + printf("unable to allocate device name\n"); + return -ENOMEM; + } + sprintf(cpu, "cpu@%d", cpu_num); + ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev); + if (ret) { + printf("binding cpu@%d failed: %d\n", cpu_num, ret); + return ret; + } + plat = dev_get_parent_platdata(dev); + plat->cpu_id = cpu_num; + } + return 0; +} diff --git a/arch/x86/cpu/quark/dram.c b/arch/x86/cpu/quark/dram.c index 995e119fb6..2bf90dcfc6 100644 --- a/arch/x86/cpu/quark/dram.c +++ b/arch/x86/cpu/quark/dram.c @@ -24,7 +24,7 @@ static __maybe_unused int prepare_mrc_cache(struct mrc_params *mrc_params) struct mrc_region entry; int ret; - ret = mrccache_get_region(NULL, &entry); + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret; @@ -154,9 +154,11 @@ int dram_init(void) #ifdef CONFIG_ENABLE_MRC_CACHE cache = malloc(sizeof(struct mrc_timings)); if (cache) { + struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL]; + memcpy(cache, &mrc_params.timings, sizeof(struct mrc_timings)); - gd->arch.mrc_output = cache; - gd->arch.mrc_output_len = sizeof(struct mrc_timings); + mrc->buf = cache; + mrc->len = sizeof(struct mrc_timings); } #endif diff --git a/arch/x86/cpu/slimbootloader/Kconfig b/arch/x86/cpu/slimbootloader/Kconfig index 3ea4c9958c..58a9ca01a9 100644 --- a/arch/x86/cpu/slimbootloader/Kconfig +++ b/arch/x86/cpu/slimbootloader/Kconfig @@ -17,3 +17,4 @@ config SYS_SLIMBOOTLOADER imply USB_EHCI_HCD imply USB_XHCI_HCD imply E1000 + imply X86_TSC_READ_BASE diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index c1e9bfbf66..e6c22895b3 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -17,7 +17,10 @@ SECTIONS . = IMAGE_TEXT_BASE; /* Location of bootcode in flash */ __text_start = .; - .text : { *(.text*); } + .text : { + __image_copy_start = .; + *(.text*); + } . = ALIGN(4); diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile index d4bdf62be6..be209aaaf8 100644 --- a/arch/x86/dts/Makefile +++ b/arch/x86/dts/Makefile @@ -2,6 +2,7 @@ dtb-y += bayleybay.dtb \ cherryhill.dtb \ + chromebook_coral.dtb \ chromebook_link.dtb \ chromebox_panther.dtb \ chromebook_samus.dtb \ diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts new file mode 100644 index 0000000000..24fcbb5063 --- /dev/null +++ b/arch/x86/dts/chromebook_coral.dts @@ -0,0 +1,831 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/dts-v1/; + +#include <dt-bindings/gpio/x86-gpio.h> + +/include/ "skeleton.dtsi" +/include/ "keyboard.dtsi" +/include/ "reset.dtsi" +/include/ "rtc.dtsi" +/include/ "tsc_timer.dtsi" + +#ifdef CONFIG_CHROMEOS +#include "chromeos-x86.dtsi" +#include "flashmap-x86-ro.dtsi" +#include "flashmap-16mb-rw.dtsi" +#endif + +#include <asm/intel_pinctrl_defs.h> +#include <asm/arch-apollolake/cpu.h> +#include <asm/arch-apollolake/gpio.h> +#include <asm/arch-apollolake/iomap.h> +#include <asm/arch-apollolake/pm.h> + +/ { + model = "Google Coral"; + compatible = "google,coral", "intel,apollolake"; + + aliases { + cros-ec0 = &cros_ec; + fsp = &fsp_s; + spi0 = &spi; + }; + + config { + silent_console = <0>; + }; + + chosen { + stdout-path = &serial; + }; + + cpus { + u-boot,dm-pre-reloc; + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + u-boot,dm-pre-reloc; + device_type = "cpu"; + compatible = "intel,apl-cpu"; + reg = <0>; + intel,apic-id = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "intel,apl-cpu"; + reg = <1>; + intel,apic-id = <2>; + }; + + cpu@2 { + device_type = "cpu"; + compatible = "intel,apl-cpu"; + reg = <2>; + intel,apic-id = <4>; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "intel,apl-cpu"; + reg = <3>; + intel,apic-id = <6>; + }; + + }; + + keyboard { + intel,duplicate-por; + }; + + pci { + compatible = "pci-x86"; + #address-cells = <3>; + #size-cells = <2>; + u-boot,dm-pre-reloc; + ranges = <0x02000000 0x0 0xc0000000 0xc0000000 0 0x10000000 + 0x42000000 0x0 0xb0000000 0xb0000000 0 0x10000000 + 0x01000000 0x0 0x1000 0x1000 0 0xefff>; + u-boot,skip-auto-config-until-reloc; + + host_bridge: host-bridge@0,0 { + u-boot,dm-pre-reloc; + reg = <0x00000000 0 0 0 0>; + compatible = "intel,apl-hostbridge"; + pciex-region-size = <0x10000000>; + /* + * Parameters used by the FSP-S binary blob. This is + * really unfortunate since these parameters mostly + * relate to drivers but we need them in one place. We + * could put them in the driver nodes easily, but then + * would have to scan each node to find them. So just + * dump them here for now. + */ + fsp_s: fsp-s { + }; + }; + + punit@0,1 { + u-boot,dm-pre-reloc; + reg = <0x00000800 0 0 0 0>; + compatible = "intel,apl-punit"; + }; + + p2sb: p2sb@d,0 { + u-boot,dm-pre-reloc; + reg = <0x02006810 0 0 0 0>; + compatible = "intel,apl-p2sb"; + early-regs = <IOMAP_P2SB_BAR 0x100000>; + + n { + compatible = "intel,apl-pinctrl"; + u-boot,dm-pre-reloc; + intel,p2sb-port-id = <PID_GPIO_N>; + gpio_n: gpio-n { + compatible = "intel,gpio"; + u-boot,dm-pre-reloc; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + nw { + u-boot,dm-pre-reloc; + compatible = "intel,apl-pinctrl"; + intel,p2sb-port-id = <PID_GPIO_NW>; + #gpio-cells = <2>; + gpio_nw: gpio-nw { + compatible = "intel,gpio"; + u-boot,dm-pre-reloc; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + w { + u-boot,dm-pre-reloc; + compatible = "intel,apl-pinctrl"; + intel,p2sb-port-id = <PID_GPIO_W>; + #gpio-cells = <2>; + gpio_w: gpio-w { + compatible = "intel,gpio"; + u-boot,dm-pre-reloc; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + sw { + u-boot,dm-pre-reloc; + compatible = "intel,apl-pinctrl"; + intel,p2sb-port-id = <PID_GPIO_SW>; + #gpio-cells = <2>; + gpio_sw: gpio-sw { + compatible = "intel,gpio"; + u-boot,dm-pre-reloc; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + itss { + u-boot,dm-pre-reloc; + compatible = "intel,apl-itss"; + intel,p2sb-port-id = <PID_ITSS>; + intel,pmc-routes = < + PMC_GPE_SW_31_0 GPIO_GPE_SW_31_0 + PMC_GPE_SW_63_32 GPIO_GPE_SW_63_32 + PMC_GPE_NW_31_0 GPIO_GPE_NW_31_0 + PMC_GPE_NW_63_32 GPIO_GPE_NW_63_32 + PMC_GPE_NW_95_64 GPIO_GPE_NW_95_64 + PMC_GPE_N_31_0 GPIO_GPE_N_31_0 + PMC_GPE_N_63_32 GPIO_GPE_N_63_32 + PMC_GPE_W_31_0 GPIO_GPE_W_31_0>; + }; + }; + + pmc@d,1 { + u-boot,dm-pre-reloc; + reg = <0x6900 0 0 0 0>; + + /* + * Values for BAR0, BAR2 and ACPI_BASE for when PCI + * auto-configure is not available + */ + early-regs = <0xfe042000 0x2000 + 0xfe044000 0x2000 + IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>; + compatible = "intel,apl-pmc"; + gpe0-dwx-mask = <0xf>; + gpe0-dwx-shift-base = <4>; + + /* + * GPE configuration + * Note that GPE events called out in ASL code rely on + * this route, i.e., if this route changes then the + * affected GPE * offset bits also need to be changed. + * This sets the PMC register GPE_CFG fields. + */ + gpe0-dw = <PMC_GPE_N_31_0 + PMC_GPE_N_63_32 + PMC_GPE_SW_31_0>; + gpe0-sts = <0x20>; + gpe0-en = <0x30>; + }; + + spi: fast-spi@d,2 { + u-boot,dm-pre-reloc; + reg = <0x02006a10 0 0 0 0>; + #address-cells = <1>; + #size-cells = <0>; + compatible = "intel,fast-spi"; + early-regs = <IOMAP_SPI_BASE 0x1000>; + intel,hardware-seq = <1>; + + fwstore_spi: spi-flash@0 { + #size-cells = <1>; + #address-cells = <1>; + u-boot,dm-pre-reloc; + reg = <0>; + compatible = "winbond,w25q128fw", + "jedec,spi-nor"; + rw-mrc-cache { + label = "rw-mrc-cache"; + reg = <0x008e0000 0x00010000>; + u-boot,dm-pre-reloc; + }; + rw-var-mrc-cache { + label = "rw-mrc-cache"; + reg = <0x008f0000 0x0001000>; + u-boot,dm-pre-reloc; + }; + }; + }; + + serial: serial@18,2 { + reg = <0x0200c210 0 0 0 0>; + u-boot,dm-pre-reloc; + compatible = "intel,apl-ns16550"; + early-regs = <0xde000000 0x20>; + reg-shift = <2>; + clock-frequency = <1843200>; + current-speed = <115200>; + }; + + pch: pch@1f,0 { + reg = <0x0000f800 0 0 0 0>; + compatible = "intel,apl-pch"; + u-boot,dm-pre-reloc; + #address-cells = <1>; + #size-cells = <1>; + + lpc { + compatible = "intel,apl-lpc"; + #address-cells = <1>; + #size-cells = <0>; + u-boot,dm-pre-reloc; + cros_ec: cros-ec { + u-boot,dm-pre-reloc; + compatible = "google,cros-ec-lpc"; + reg = <0x204 1 0x200 1 0x880 0x80>; + + /* + * Describes the flash memory within + * the EC + */ + #address-cells = <1>; + #size-cells = <1>; + flash@8000000 { + reg = <0x08000000 0x20000>; + erase-value = <0xff>; + }; + }; + }; + }; + }; + +}; + +&host_bridge { + /* + * PL1 override 12000 mW: the energy calculation is wrong with the + * current VR solution. Experiments show that SoC TDP max (6W) can be + * reached when RAPL PL1 is set to 12W. Set RAPL PL2 to 15W. + */ + tdp-pl-override-mw = <12000 15000>; + + early-pads = < + /* These two are for the debug UART */ + GPIO_46 /* UART2 RX */ + (PAD_CFG0_MODE_NF1 | PAD_CFG0_LOGICAL_RESET_DEEP) + (PAD_CFG1_PULL_NATIVE | PAD_CFG1_IOSSTATE_TX_LAST_RXE) + + GPIO_47 /* UART2 TX */ + (PAD_CFG0_MODE_NF1 | PAD_CFG0_LOGICAL_RESET_DEEP) + (PAD_CFG1_PULL_NATIVE | PAD_CFG1_IOSSTATE_TX_LAST_RXE) + + GPIO_75 /* I2S1_BCLK -- PCH_WP */ + (PAD_CFG0_MODE_GPIO | PAD_CFG0_LOGICAL_RESET_DEEP) + (PAD_CFG1_PULL_UP_20K | PAD_CFG1_IOSSTATE_TXD_RXE) + + /* I2C2 - TPM */ + GPIO_128 /* LPSS_I2C2_SDA */ + (PAD_CFG0_MODE_NF1 | PAD_CFG0_LOGICAL_RESET_DEEP) + (PAD_CFG1_PULL_UP_2K | PAD_CFG1_IOSSTATE_TX_LAST_RXE) + GPIO_129 /* LPSS_I2C2_SCL */ + (PAD_CFG0_MODE_NF1 | PAD_CFG0_LOGICAL_RESET_DEEP) + (PAD_CFG1_PULL_UP_2K | PAD_CFG1_IOSSTATE_TX_LAST_RXE) + GPIO_28 /* TPM IRQ */ + (PAD_CFG0_MODE_GPIO | PAD_CFG0_LOGICAL_RESET_DEEP | + PAD_CFG0_TX_DISABLE | PAD_CFG0_ROUTE_IOAPIC | + PAD_CFG0_TRIG_LEVEL | PAD_CFG0_RX_POL_INVERT) + (PAD_CFG1_PULL_NONE | PAD_CFG1_IOSSTATE_TXD_RXE) + + /* + * WLAN_PE_RST - default to deasserted just in case FSP + * misbehaves + */ + GPIO_122 /* SIO_SPI_2_RXD */ + (PAD_CFG0_MODE_GPIO | PAD_CFG0_LOGICAL_RESET_DEEP | + PAD_CFG0_RX_DISABLE | 0) + (PAD_CFG1_PULL_NONE | PAD_CFG1_IOSSTATE_TX_LAST_RXE) + + /* LPC */ + PAD_CFG_NF(LPC_ILB_SERIRQ, UP_20K, DEEP, NF1) /* LPC_SERIRQ */ + PAD_CFG_NF(LPC_CLKOUT0, NONE, DEEP, NF1) /* LPC_CLKOUT0 */ + PAD_CFG_NF(LPC_CLKOUT1, UP_20K, DEEP, NF1) + PAD_CFG_NF(LPC_AD0, UP_20K, DEEP, NF1) /* LPC_AD0 */ + PAD_CFG_NF(LPC_AD1, UP_20K, DEEP, NF1) /* LPC_AD1 */ + PAD_CFG_NF(LPC_AD2, UP_20K, DEEP, NF1) /* LPC_AD2 */ + PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1) /* LPC_AD3 */ + PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1) /* LPC_CLKRUN_N */ + PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1) /* LPC_FRAME_N */ + >; + + lpddr4-swizzle = /bits/ 8 < + /* LP4_PHYS_CH0A */ + + /* DQA[0:7] pins of LPDDR4 module */ + 6 7 5 4 3 1 0 2 + /* DQA[8:15] pins of LPDDR4 module */ + 12 10 11 13 14 8 9 15 + /* DQB[0:7] pins of LPDDR4 module with offset of 16 */ + 16 22 23 20 18 17 19 21 + /* DQB[7:15] pins of LPDDR4 module with offset of 16 */ + 30 28 29 25 24 26 27 31 + + /* LP4_PHYS_CH0B */ + /* DQA[0:7] pins of LPDDR4 module */ + 7 3 5 2 6 0 1 4 + /* DQA[8:15] pins of LPDDR4 module */ + 9 14 12 13 10 11 8 15 + /* DQB[0:7] pins of LPDDR4 module with offset of 16 */ + 20 22 23 16 19 17 18 21 + /* DQB[7:15] pins of LPDDR4 module with offset of 16 */ + 28 24 26 27 29 30 31 25 + + /* LP4_PHYS_CH1A */ + + /* DQA[0:7] pins of LPDDR4 module */ + 2 1 6 7 5 4 3 0 + /* DQA[8:15] pins of LPDDR4 module */ + 11 10 8 9 12 15 13 14 + /* DQB[0:7] pins of LPDDR4 module with offset of 16 */ + 17 23 19 16 21 22 20 18 + /* DQB[7:15] pins of LPDDR4 module with offset of 16 */ + 31 29 26 25 28 27 24 30 + + /* LP4_PHYS_CH1B */ + + /* DQA[0:7] pins of LPDDR4 module */ + 4 3 7 5 6 1 0 2 + /* DQA[8:15] pins of LPDDR4 module */ + 15 9 8 11 14 13 12 10 + /* DQB[0:7] pins of LPDDR4 module with offset of 16 */ + 20 23 22 21 18 19 16 17 + /* DQB[7:15] pins of LPDDR4 module with offset of 16 */ + 25 28 30 31 26 27 24 29>; +}; + +&fsp_s { + u-boot,dm-pre-proper; + + /* Disable unused clkreq of PCIe root ports */ + pcie-rp-clkreq-pin = /bits/ 8 <0 /* wifi/bt */ + CLKREQ_DISABLED + CLKREQ_DISABLED + CLKREQ_DISABLED + CLKREQ_DISABLED + CLKREQ_DISABLED>; + + /* + * GPIO for PERST_0 + * If the Board has PERST_0 signal, assign the GPIO + * If the Board does not have PERST_0, assign GPIO_PRT0_UDEF + * + * This are not used yet, so comment them out for now. + * + * prt0-gpio = <GPIO_122>; + * + * GPIO for SD card detect + * sdcard-cd-gpio = <GPIO_177>; + */ + + /* + * Order is emmc-tx-data-cntl1, emmc-tx-data-cntl2, + * emmc-rx-cmd-data-cntl1, emmc-rx-cmd-data-cntl2 + * + * EMMC TX DATA Delay 1 + * Refer to EDS-Vol2-22.3 + * [14:8] steps of delay for HS400, each 125ps + * [6:0] steps of delay for SDR104/HS200, each 125ps + + /* + * EMMC TX DATA Delay 2 + * Refer to EDS-Vol2-22.3. + * [30:24] steps of delay for SDR50, each 125ps + * [22:16] steps of delay for DDR50, each 125ps + * [14:8] steps of delay for SDR25/HS50, each 125ps + * [6:0] steps of delay for SDR12, each 125ps + */ + + /* + * EMMC RX CMD/DATA Delay 1 + * Refer to EDS-Vol2-22.3. + * [30:24] steps of delay for SDR50, each 125ps + * [22:16] steps of delay for DDR50, each 125ps + * [14:8] steps of delay for SDR25/HS50, each 125ps + * [6:0] steps of delay for SDR12, each 125ps + */ + + /* + * EMMC RX CMD/DATA Delay 2 + * Refer to EDS-Vol2-22.3. + * [17:16] stands for Rx Clock before Output Buffer + * [14:8] steps of delay for Auto Tuning Mode, each 125ps + * [6:0] steps of delay for HS200, each 125ps + */ + emmc = <0x0c16 0x28162828 0x00181717 0x10008>; + + /* Enable DPTF */ + dptf-enable; + + /* Enable Audio Clock and Power gating */ + hdaudio-clk-gate-enable; + hdaudio-pwr-gate-enable; + hdaudio-bios-config-lockdown; + + /* Enable lpss s0ix */ + lpss-s0ix-enable; + + /* + * TODO(sjg@chromium.org): Move this to the I2C nodes + * Intel Common SoC Config + *+-------------------+---------------------------+ + *| Field | Value | + *+-------------------+---------------------------+ + *| I2C0 | Audio | + *| I2C2 | TPM | + *| I2C3 | Touchscreen | + *| I2C4 | Trackpad | + *| I2C5 | Digitizer | + *+-------------------+---------------------------+ + * + common_soc_config" = "{ + .i2c[0] = { + .speed = I2C_SPEED_FAST, + .rise-time-ns = 104, + .fall-time-ns = 52, + }, + .i2c[2] = { + .early_init = 1, + .speed = I2C_SPEED_FAST, + .rise-time-ns = 57, + .fall-time-ns = 28, + }, + .i2c[3] = { + .speed = I2C_SPEED_FAST, + .rise-time-ns = 76, + .fall-time-ns = 164, + }, + .i2c[4] = { + .speed = I2C_SPEED_FAST, + .rise-time-ns = 114, + .fall-time-ns = 164, + .data_hold_time_ns = 350, + }, + .i2c[5] = { + .speed = I2C_SPEED_FAST, + .rise-time-ns = 152, + .fall-time-ns = 30, + }, + }" + */ + + /* Minimum SLP S3 assertion width 28ms */ + slp-s3-assertion-width-usecs = <28000>; + + pads = < + /* PCIE_WAKE[0:3]_N */ + PAD_CFG_GPI_SCI_LOW(GPIO_205, UP_20K, DEEP, EDGE_SINGLE) /* WLAN */ + PAD_CFG_GPI(GPIO_206, UP_20K, DEEP) /* Unused */ + PAD_CFG_GPI(GPIO_207, UP_20K, DEEP) /* Unused */ + PAD_CFG_GPI(GPIO_208, UP_20K, DEEP) /* Unused */ + + /* EMMC interface */ + PAD_CFG_NF(GPIO_156, DN_20K, DEEP, NF1) /* EMMC_CLK */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_157, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D0 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_158, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D1 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_159, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D2 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_160, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D3 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_161, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D4 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_162, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D5 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_163, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D6 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_164, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D7 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_165, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_CMD */ + PAD_CFG_NF(GPIO_182, DN_20K, DEEP, NF1) /* EMMC_RCLK */ + + /* SDIO -- unused */ + PAD_CFG_GPI(GPIO_166, UP_20K, DEEP) /* SDIO_CLK */ + PAD_CFG_GPI(GPIO_167, UP_20K, DEEP) /* SDIO_D0 */ + /* Configure SDIO to enable power gating */ + PAD_CFG_NF(GPIO_168, UP_20K, DEEP, NF1) /* SDIO_D1 */ + PAD_CFG_GPI(GPIO_169, UP_20K, DEEP) /* SDIO_D2 */ + PAD_CFG_GPI(GPIO_170, UP_20K, DEEP) /* SDIO_D3 */ + PAD_CFG_GPI(GPIO_171, UP_20K, DEEP) /* SDIO_CMD */ + + /* SDCARD */ + /* Pull down clock by 20K */ + PAD_CFG_NF(GPIO_172, DN_20K, DEEP, NF1) /* SDCARD_CLK */ + PAD_CFG_NF(GPIO_173, UP_20K, DEEP, NF1) /* SDCARD_D0 */ + PAD_CFG_NF(GPIO_174, UP_20K, DEEP, NF1) /* SDCARD_D1 */ + PAD_CFG_NF(GPIO_175, UP_20K, DEEP, NF1) /* SDCARD_D2 */ + PAD_CFG_NF(GPIO_176, UP_20K, DEEP, NF1) /* SDCARD_D3 */ + /* Card detect is active LOW with external pull up */ + PAD_CFG_NF(GPIO_177, NONE, DEEP, NF1) /* SDCARD_CD_N */ + PAD_CFG_NF(GPIO_178, UP_20K, DEEP, NF1) /* SDCARD_CMD */ + /* CLK feedback, internal signal, needs 20K pull down */ + PAD_CFG_NF(GPIO_179, DN_20K, DEEP, NF1) /* SDCARD_CLK_FB */ + /* No h/w write proect for uSD cards, pull down by 20K */ + PAD_CFG_NF(GPIO_186, DN_20K, DEEP, NF1) /* SDCARD_LVL_WP */ + /* EN_SD_SOCKET_PWR_L for SD slot power control. Default on */ + PAD_CFG_GPO(GPIO_183, 0, DEEP) /* SDIO_PWR_DOWN_N */ + + /* SMBus -- unused */ + PAD_CFG_GPI(SMB_ALERTB, UP_20K, DEEP) /* SMB_ALERT _N */ + PAD_CFG_GPI(SMB_CLK, UP_20K, DEEP) /* SMB_CLK */ + PAD_CFG_GPI(SMB_DATA, UP_20K, DEEP) /* SMB_DATA */ + + /* LPC */ + PAD_CFG_NF(LPC_ILB_SERIRQ, UP_20K, DEEP, NF1) /* LPC_SERIRQ */ + PAD_CFG_NF(LPC_CLKOUT0, NONE, DEEP, NF1) /* LPC_CLKOUT0 */ + PAD_CFG_NF(LPC_CLKOUT1, UP_20K, DEEP, NF1) + PAD_CFG_NF(LPC_AD0, UP_20K, DEEP, NF1) /* LPC_AD0 */ + PAD_CFG_NF(LPC_AD1, UP_20K, DEEP, NF1) /* LPC_AD1 */ + PAD_CFG_NF(LPC_AD2, UP_20K, DEEP, NF1) /* LPC_AD2 */ + PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1) /* LPC_AD3 */ + PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1) /* LPC_CLKRUN_N */ + PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1) /* LPC_FRAME_N */ + + /* I2C0 - Audio */ + PAD_CFG_NF(GPIO_124, UP_2K, DEEP, NF1) /* LPSS_I2C0_SDA */ + PAD_CFG_NF(GPIO_125, UP_2K, DEEP, NF1) /* LPSS_I2C0_SCL */ + + /* I2C1 - NFC with external pulls */ + PAD_CFG_NF(GPIO_126, NONE, DEEP, NF1) /* LPSS_I2C1_SDA */ + PAD_CFG_NF(GPIO_127, NONE, DEEP, NF1) /* LPSS_I2C1_SCL */ + + /* I2C2 - TPM */ + PAD_CFG_NF(GPIO_128, UP_2K, DEEP, NF1) /* LPSS_I2C2_SDA */ + PAD_CFG_NF(GPIO_129, UP_2K, DEEP, NF1) /* LPSS_I2C2_SCL */ + + /* I2C3 - touch */ + PAD_CFG_NF(GPIO_130, UP_2K, DEEP, NF1) /* LPSS_I2C3_SDA */ + PAD_CFG_NF(GPIO_131, UP_2K, DEEP, NF1) /* LPSS_I2C3_SCL */ + + /* I2C4 - trackpad */ + /* LPSS_I2C4_SDA */ + PAD_CFG_NF_IOSSTATE(GPIO_132, UP_2K, DEEP, NF1, HIZCRX1) + /* LPSS_I2C4_SCL */ + PAD_CFG_NF_IOSSTATE(GPIO_133, UP_2K, DEEP, NF1, HIZCRX1) + + /* I2C5 -- pen with external pulls */ + PAD_CFG_NF(GPIO_134, NONE, DEEP, NF1) /* LPSS_I2C5_SDA */ + PAD_CFG_NF(GPIO_135, NONE, DEEP, NF1) /* LPSS_I2C5_SCL */ + + /* I2C6-7 -- unused */ + PAD_CFG_GPI(GPIO_136, UP_20K, DEEP) /* LPSS_I2C6_SDA */ + PAD_CFG_GPI(GPIO_137, UP_20K, DEEP) /* LPSS_I2C6_SCL */ + PAD_CFG_GPI(GPIO_138, UP_20K, DEEP) /* LPSS_I2C7_SDA */ + PAD_CFG_GPI(GPIO_139, UP_20K, DEEP) /* LPSS_I2C7_SCL */ + + /* Audio Amp - I2S6 */ + PAD_CFG_NF(GPIO_146, NATIVE, DEEP, NF2) /* ISH_GPIO_0 - I2S6_BCLK */ + PAD_CFG_NF(GPIO_147, NATIVE, DEEP, NF2) /* ISH_GPIO_1 - I2S6_WS_SYNC */ + PAD_CFG_GPI(GPIO_148, UP_20K, DEEP) /* ISH_GPIO_2 - unused */ + PAD_CFG_NF(GPIO_149, NATIVE, DEEP, NF2) /* ISH_GPIO_3 - I2S6_SDO */ + + /* NFC Reset */ + PAD_CFG_GPO(GPIO_150, 1, DEEP) /* ISH_GPIO_4 */ + + PAD_CFG_GPI(GPIO_151, UP_20K, DEEP) /* ISH_GPIO_5 - unused */ + + /* Touch enable */ + PAD_CFG_GPO(GPIO_152, 1, DEEP) /* ISH_GPIO_6 */ + + PAD_CFG_GPI(GPIO_153, UP_20K, DEEP) /* ISH_GPIO_7 - unused */ + PAD_CFG_GPI(GPIO_154, UP_20K, DEEP) /* ISH_GPIO_8 - unused */ + PAD_CFG_GPI(GPIO_155, UP_20K, DEEP) /* ISH_GPIO_9 - unused */ + + /* PCIE_CLKREQ[0:3]_N */ + PAD_CFG_NF(GPIO_209, NONE, DEEP, NF1) /* WLAN with external pull */ + PAD_CFG_GPI(GPIO_210, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI(GPIO_211, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI(GPIO_212, UP_20K, DEEP) /* unused */ + + /* OSC_CLK_OUT_[0:4] -- unused */ + PAD_CFG_GPI(OSC_CLK_OUT_0, UP_20K, DEEP) + PAD_CFG_GPI(OSC_CLK_OUT_1, UP_20K, DEEP) + PAD_CFG_GPI(OSC_CLK_OUT_2, UP_20K, DEEP) + PAD_CFG_GPI(OSC_CLK_OUT_3, UP_20K, DEEP) + PAD_CFG_GPI(OSC_CLK_OUT_4, UP_20K, DEEP) + + /* PMU Signals */ + PAD_CFG_GPI(PMU_AC_PRESENT, UP_20K, DEEP) /* PMU_AC_PRESENT - unused */ + PAD_CFG_NF(PMU_BATLOW_B, UP_20K, DEEP, NF1) /* PMU_BATLOW_N */ + PAD_CFG_NF(PMU_PLTRST_B, NONE, DEEP, NF1) /* PMU_PLTRST_N */ + PAD_CFG_NF(PMU_PWRBTN_B, UP_20K, DEEP, NF1) /* PMU_PWRBTN_N */ + PAD_CFG_NF(PMU_RESETBUTTON_B, NONE, DEEP, NF1) /* PMU_RSTBTN_N */ + PAD_CFG_NF_IOSSTATE(PMU_SLP_S0_B, NONE, DEEP, NF1, IGNORE) /* PMU_SLP_S0_N */ + PAD_CFG_NF(PMU_SLP_S3_B, NONE, DEEP, NF1) /* PMU_SLP_S3_N */ + PAD_CFG_NF(PMU_SLP_S4_B, NONE, DEEP, NF1) /* PMU_SLP_S4_N */ + PAD_CFG_NF(PMU_SUSCLK, NONE, DEEP, NF1) /* PMU_SUSCLK */ + PAD_CFG_GPO(PMU_WAKE_B, 1, DEEP) /* EN_PP3300_EMMC */ + PAD_CFG_NF(SUS_STAT_B, NONE, DEEP, NF1) /* SUS_STAT_N */ + PAD_CFG_NF(SUSPWRDNACK, NONE, DEEP, NF1) /* SUSPWRDNACK */ + + /* DDI[0:1] SDA and SCL -- unused */ + PAD_CFG_GPI(GPIO_187, UP_20K, DEEP) /* HV_DDI0_DDC_SDA */ + PAD_CFG_GPI(GPIO_188, UP_20K, DEEP) /* HV_DDI0_DDC_SCL */ + PAD_CFG_GPI(GPIO_189, UP_20K, DEEP) /* HV_DDI1_DDC_SDA */ + PAD_CFG_GPI(GPIO_190, UP_20K, DEEP) /* HV_DDI1_DDC_SCL */ + + /* MIPI I2C -- unused */ + PAD_CFG_GPI(GPIO_191, UP_20K, DEEP) /* MIPI_I2C_SDA */ + PAD_CFG_GPI(GPIO_192, UP_20K, DEEP) /* MIPI_I2C_SCL */ + + /* Panel 0 control */ + PAD_CFG_NF(GPIO_193, NATIVE, DEEP, NF1) /* PNL0_VDDEN */ + PAD_CFG_NF(GPIO_194, NATIVE, DEEP, NF1) /* PNL0_BKLTEN */ + PAD_CFG_NF(GPIO_195, NATIVE, DEEP, NF1) /* PNL0_BKLTCTL */ + + /* Panel 1 control -- unused */ + PAD_CFG_NF(GPIO_196, NATIVE, DEEP, NF1) /* PNL1_VDDEN */ + PAD_CFG_NF(GPIO_197, NATIVE, DEEP, NF1) /* PNL1_BKLTEN */ + PAD_CFG_NF(GPIO_198, NATIVE, DEEP, NF1) /* PNL1_BKLTCTL */ + + /* Hot plug detect */ + PAD_CFG_NF(GPIO_199, UP_20K, DEEP, NF2) /* HV_DDI1_HPD */ + PAD_CFG_NF(GPIO_200, UP_20K, DEEP, NF2) /* HV_DDI0_HPD */ + + /* MDSI signals -- unused */ + PAD_CFG_GPI(GPIO_201, UP_20K, DEEP) /* MDSI_A_TE */ + PAD_CFG_GPI(GPIO_202, UP_20K, DEEP) /* MDSI_A_TE */ + + /* USB overcurrent pins */ + PAD_CFG_NF(GPIO_203, UP_20K, DEEP, NF1) /* USB_OC0_N */ + PAD_CFG_NF(GPIO_204, UP_20K, DEEP, NF1) /* USB_OC1_N */ + + /* PMC SPI -- almost entirely unused */ + PAD_CFG_GPI(PMC_SPI_FS0, UP_20K, DEEP) + PAD_CFG_NF(PMC_SPI_FS1, UP_20K, DEEP, NF2) /* HV_DDI2_HPD -- EDP HPD */ + PAD_CFG_GPI(PMC_SPI_FS2, UP_20K, DEEP) + PAD_CFG_GPI(PMC_SPI_RXD, UP_20K, DEEP) + PAD_CFG_GPI(PMC_SPI_TXD, UP_20K, DEEP) + PAD_CFG_GPI(PMC_SPI_CLK, UP_20K, DEEP) + + /* PMIC Signals Unused signals related to an old PMIC interface */ + PAD_CFG_NF_IOSSTATE(PMIC_RESET_B, NATIVE, DEEP, NF1, IGNORE) /* PMIC_RESET_B */ + PAD_CFG_GPI(GPIO_213, NONE, DEEP) /* unused external pull */ + PAD_CFG_GPI(GPIO_214, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI(GPIO_215, UP_20K, DEEP) /* unused */ + PAD_CFG_NF(PMIC_THERMTRIP_B, UP_20K, DEEP, NF1) /* THERMTRIP_N */ + PAD_CFG_GPI(PMIC_STDBY, UP_20K, DEEP) /* unused */ + PAD_CFG_NF(PROCHOT_B, UP_20K, DEEP, NF1) /* PROCHOT_N */ + PAD_CFG_NF(PMIC_I2C_SCL, UP_1K, DEEP, NF1) /* PMIC_I2C_SCL */ + PAD_CFG_NF(PMIC_I2C_SDA, UP_1K, DEEP, NF1) /* PMIC_I2C_SDA */ + + /* I2S1 -- largely unused */ + PAD_CFG_GPI(GPIO_74, UP_20K, DEEP) /* I2S1_MCLK */ + PAD_CFG_GPI(GPIO_75, UP_20K, DEEP) /* I2S1_BCLK -- PCH_WP */ + PAD_CFG_GPO(GPIO_76, 0, DEEP) /* I2S1_WS_SYNC -- SPK_PA_EN */ + PAD_CFG_GPI(GPIO_77, UP_20K, DEEP) /* I2S1_SDI */ + PAD_CFG_GPO(GPIO_78, 1, DEEP) /* I2S1_SDO -- EN_PP3300_DX_LTE_SOC */ + + /* DMIC or I2S4 */ + /* AVS_DMIC_CLK_A1 */ + PAD_CFG_NF_IOSSTATE(GPIO_79, NATIVE, DEEP, NF1, IGNORE) + PAD_CFG_NF(GPIO_80, NATIVE, DEEP, NF1) /* AVS_DMIC_CLK_B1 */ + PAD_CFG_NF(GPIO_81, NATIVE, DEEP, NF1) /* AVS_DMIC_DATA_1 */ + PAD_CFG_GPI(GPIO_82, DN_20K, DEEP) /* unused -- strap */ + PAD_CFG_NF(GPIO_83, NATIVE, DEEP, NF1) /* AVS_DMIC_DATA_2 */ + + /* I2S2 -- Headset amp */ + PAD_CFG_NF(GPIO_84, NATIVE, DEEP, NF1) /* AVS_I2S2_MCLK */ + PAD_CFG_NF(GPIO_85, NATIVE, DEEP, NF1) /* AVS_I2S2_BCLK */ + PAD_CFG_NF(GPIO_86, NATIVE, DEEP, NF1) /* AVS_I2S2_SW_SYNC */ + PAD_CFG_NF(GPIO_87, NATIVE, DEEP, NF1) /* AVS_I2S2_SDI */ + PAD_CFG_NF(GPIO_88, NATIVE, DEEP, NF1) /* AVS_I2S2_SDO */ + + /* I2S3 -- largely unused */ + PAD_CFG_GPI(GPIO_89, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI(GPIO_90, UP_20K, DEEP) /* GPS_HOST_WAKE */ + PAD_CFG_GPO(GPIO_91, 1, DEEP) /* GPS_EN */ + PAD_CFG_GPI(GPIO_92, DN_20K, DEEP) /* unused -- strap */ + + /* Fast SPI */ + PAD_CFG_NF_IOSSTATE(GPIO_97, NATIVE, DEEP, NF1, IGNORE) /* FST_SPI_CS0_B */ + PAD_CFG_GPI(GPIO_98, UP_20K, DEEP) /* FST_SPI_CS1_B -- unused */ + PAD_CFG_NF_IOSSTATE(GPIO_99, NATIVE, DEEP, NF1, IGNORE) /* FST_SPI_MOSI_IO0 */ + PAD_CFG_NF_IOSSTATE(GPIO_100, NATIVE, DEEP, NF1, IGNORE) /* FST_SPI_MISO_IO1 */ + PAD_CFG_GPI(GPIO_101, NONE, DEEP) /* FST_IO2 -- MEM_CONFIG0 */ + PAD_CFG_GPI(GPIO_102, NONE, DEEP) /* FST_IO3 -- MEM_CONFIG1 */ + PAD_CFG_NF_IOSSTATE(GPIO_103, NATIVE, DEEP, NF1, IGNORE) /* FST_SPI_CLK */ + PAD_CFG_NF_IOSSTATE(FST_SPI_CLK_FB, NATIVE, DEEP, NF1, IGNORE) /* FST_SPI_CLK_FB */ + PAD_CFG_NF_IOSSTATE(GPIO_106, NATIVE, DEEP, NF3, IGNORE) /* FST_SPI_CS2_N */ + + /* SIO_SPI_0 - Used for FP */ + PAD_CFG_NF(GPIO_104, NATIVE, DEEP, NF1) /* SIO_SPI_0_CLK */ + PAD_CFG_NF(GPIO_105, NATIVE, DEEP, NF1) /* SIO_SPI_0_FS0 */ + PAD_CFG_NF(GPIO_109, NATIVE, DEEP, NF1) /* SIO_SPI_0_RXD */ + PAD_CFG_NF(GPIO_110, NATIVE, DEEP, NF1) /* SIO_SPI_0_TXD */ + + /* SIO_SPI_1 -- largely unused */ + PAD_CFG_GPI(GPIO_111, UP_20K, DEEP) /* SIO_SPI_1_CLK */ + PAD_CFG_GPI(GPIO_112, UP_20K, DEEP) /* SIO_SPI_1_FS0 */ + PAD_CFG_GPI(GPIO_113, UP_20K, DEEP) /* SIO_SPI_1_FS1 */ + /* Headset interrupt */ + PAD_CFG_GPI_APIC_LOW(GPIO_116, NONE, DEEP) /* SIO_SPI_1_RXD */ + PAD_CFG_GPI(GPIO_117, UP_20K, DEEP) /* SIO_SPI_1_TXD */ + + /* SIO_SPI_2 -- unused */ + PAD_CFG_GPI(GPIO_118, UP_20K, DEEP) /* SIO_SPI_2_CLK */ + PAD_CFG_GPI(GPIO_119, UP_20K, DEEP) /* SIO_SPI_2_FS0 */ + PAD_CFG_GPI(GPIO_120, UP_20K, DEEP) /* SIO_SPI_2_FS1 */ + PAD_CFG_GPI(GPIO_121, UP_20K, DEEP) /* SIO_SPI_2_FS2 */ + /* WLAN_PE_RST - default to deasserted */ + PAD_CFG_GPO(GPIO_122, 0, DEEP) /* SIO_SPI_2_RXD */ + PAD_CFG_GPI(GPIO_123, UP_20K, DEEP) /* SIO_SPI_2_TXD */ + + /* Debug tracing */ + PAD_CFG_GPI(GPIO_0, UP_20K, DEEP) + PAD_CFG_GPI(GPIO_1, UP_20K, DEEP) + PAD_CFG_GPI(GPIO_2, UP_20K, DEEP) + PAD_CFG_GPI_SCI_HIGH(GPIO_3, DN_20K, DEEP, LEVEL) /* FP_INT */ + PAD_CFG_GPI(GPIO_4, UP_20K, DEEP) + PAD_CFG_GPI(GPIO_5, UP_20K, DEEP) + PAD_CFG_GPI(GPIO_6, UP_20K, DEEP) + PAD_CFG_GPI(GPIO_7, UP_20K, DEEP) + PAD_CFG_GPI(GPIO_8, UP_20K, DEEP) + + PAD_CFG_GPI_APIC_LOW(GPIO_9, NONE, DEEP) /* dTPM IRQ */ + PAD_CFG_GPI(GPIO_10, DN_20K, DEEP) /* Board phase enforcement */ + PAD_CFG_GPI_SCI_LOW(GPIO_11, NONE, DEEP, EDGE_SINGLE) /* EC SCI */ + PAD_CFG_GPI(GPIO_12, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI_APIC_LOW(GPIO_13, NONE, DEEP) /* PEN_INT_ODL */ + PAD_CFG_GPI_APIC_HIGH(GPIO_14, DN_20K, DEEP) /* FP_INT */ + PAD_CFG_GPI_SCI_LOW(GPIO_15, NONE, DEEP, EDGE_SINGLE) /* TRACKPAD_INT_1V8_ODL */ + PAD_CFG_GPI(GPIO_16, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI(GPIO_17, UP_20K, DEEP) /* 1 vs 4 DMIC config */ + PAD_CFG_GPI_APIC_LOW(GPIO_18, NONE, DEEP) /* Trackpad IRQ */ + PAD_CFG_GPI(GPIO_19, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI_APIC_LOW(GPIO_20, UP_20K, DEEP) /* NFC IRQ */ + PAD_CFG_GPI_APIC_LOW(GPIO_21, NONE, DEEP) /* Touch IRQ */ + PAD_CFG_GPI_SCI_LOW(GPIO_22, NONE, DEEP, EDGE_SINGLE) /* EC wake */ + PAD_CFG_GPI(GPIO_23, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI(GPIO_24, NONE, DEEP) /* PEN_PDCT_ODL */ + PAD_CFG_GPI(GPIO_25, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI(GPIO_26, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI(GPIO_27, UP_20K, DEEP) /* unused */ + PAD_CFG_GPI_APIC_LOW(GPIO_28, NONE, DEEP) /* TPM IRQ */ + PAD_CFG_GPO(GPIO_29, 1, DEEP) /* FP reset */ + PAD_CFG_GPI_APIC_LOW(GPIO_30, NONE, DEEP) /* KB IRQ */ + PAD_CFG_GPO(GPIO_31, 0, DEEP) /* NFC FW DL */ + PAD_CFG_NF(GPIO_32, NONE, DEEP, NF5) /* SUS_CLK2 */ + PAD_CFG_GPI_APIC_LOW(GPIO_33, NONE, DEEP) /* PMIC IRQ */ + PAD_CFG_GPI(GPIO_34, UP_20K, DEEP) /* unused */ + PAD_CFG_GPO(GPIO_35, 0, DEEP) /* PEN_RESET - active high */ + PAD_CFG_GPO(GPIO_36, 0, DEEP) /* touch reset */ + PAD_CFG_GPI(GPIO_37, UP_20K, DEEP) /* unused */ + + /* LPSS_UART[0:2] */ + PAD_CFG_GPI(GPIO_38, NONE, DEEP) /* LPSS_UART0_RXD - MEM_CONFIG2*/ + /* Next 2 are straps */ + PAD_CFG_GPI(GPIO_39, DN_20K, DEEP) /* LPSS_UART0_TXD - unused */ + PAD_CFG_GPI(GPIO_40, DN_20K, DEEP) /* LPSS_UART0_RTS - unused */ + PAD_CFG_GPI(GPIO_41, NONE, DEEP) /* LPSS_UART0_CTS - EC_IN_RW */ + PAD_CFG_NF(GPIO_42, NATIVE, DEEP, NF1) /* LPSS_UART1_RXD */ + PAD_CFG_NF(GPIO_43, NATIVE, DEEP, NF1) /* LPSS_UART1_TXD */ + PAD_CFG_GPO(GPIO_44, 1, DEEP) /* GPS_RST_ODL */ + PAD_CFG_GPI(GPIO_45, NONE, DEEP) /* LPSS_UART1_CTS - MEM_CONFIG3 */ + PAD_CFG_NF(GPIO_46, NATIVE, DEEP, NF1) /* LPSS_UART2_RXD */ + PAD_CFG_NF_IOSSTATE(GPIO_47, NATIVE, DEEP, NF1, TX1_RX_DCR_X0) /* UART2 TX */ + PAD_CFG_GPI(GPIO_48, UP_20K, DEEP) /* LPSS_UART2_RTS - unused */ + PAD_CFG_GPI_SMI_LOW(GPIO_49, NONE, DEEP, EDGE_SINGLE) /* LPSS_UART2_CTS - EC_SMI_L */ + + /* Camera interface -- completely unused */ + PAD_CFG_GPI(GPIO_62, UP_20K, DEEP) /* GP_CAMERASB00 */ + PAD_CFG_GPI(GPIO_63, UP_20K, DEEP) /* GP_CAMERASB01 */ + PAD_CFG_GPI(GPIO_64, UP_20K, DEEP) /* GP_CAMERASB02 */ + PAD_CFG_GPI(GPIO_65, UP_20K, DEEP) /* GP_CAMERASB03 */ + PAD_CFG_GPI(GPIO_66, UP_20K, DEEP) /* GP_CAMERASB04 */ + PAD_CFG_GPI(GPIO_67, UP_20K, DEEP) /* GP_CAMERASB05 */ + PAD_CFG_GPI(GPIO_68, UP_20K, DEEP) /* GP_CAMERASB06 */ + PAD_CFG_GPI(GPIO_69, UP_20K, DEEP) /* GP_CAMERASB07 */ + PAD_CFG_GPI(GPIO_70, UP_20K, DEEP) /* GP_CAMERASB08 */ + PAD_CFG_GPI(GPIO_71, UP_20K, DEEP) /* GP_CAMERASB09 */ + PAD_CFG_GPI(GPIO_72, UP_20K, DEEP) /* GP_CAMERASB10 */ + PAD_CFG_GPI(GPIO_73, UP_20K, DEEP) /* GP_CAMERASB11 */ + >; +}; diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 0e87b88e10..f0f8c71761 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -37,62 +37,110 @@ }; #endif #ifdef CONFIG_TPL +#ifdef CONFIG_HAVE_MICROCODE u-boot-tpl-with-ucode-ptr { offset = <CONFIG_TPL_TEXT_BASE>; }; u-boot-tpl-dtb { }; - u-boot-spl { - offset = <CONFIG_SPL_TEXT_BASE>; - }; - u-boot-spl-dtb { +#endif + spl { + type = "section"; + offset = <CONFIG_X86_OFFSET_SPL>; + u-boot-spl { + }; + u-boot-spl-dtb { + }; }; u-boot { - offset = <CONFIG_SYS_TEXT_BASE>; + type = "section"; + offset = <CONFIG_X86_OFFSET_U_BOOT>; + u-boot-nodtb { + }; + u-boot-dtb { + }; }; #elif defined(CONFIG_SPL) u-boot-spl-with-ucode-ptr { - offset = <CONFIG_SPL_TEXT_BASE>; + offset = <CONFIG_X86_OFFSET_SPL>; }; u-boot-dtb-with-ucode2 { type = "u-boot-dtb-with-ucode"; }; u-boot { - /* - * TODO(sjg@chromium.org): - * Normally we use CONFIG_SYS_TEXT_BASE as the flash offset. But - * for boards with textbase in SDRAM we cannot do this. Just use - * an assumed-valid value (1MB before the end of flash) here so - * that we can actually build an image for coreboot, etc. - * We need a better solution, perhaps a separate Kconfig. - */ -#if CONFIG_SYS_TEXT_BASE == 0x1110000 - offset = <0xfff00000>; + offset = <CONFIG_X86_OFFSET_U_BOOT>; + }; #else +# ifdef CONFIG_SPL + u-boot { offset = <CONFIG_SYS_TEXT_BASE>; -#endif }; -#else +# else + /* If there is no SPL then we need to put microcode in U-Boot */ u-boot-with-ucode-ptr { - offset = <CONFIG_SYS_TEXT_BASE>; + offset = <CONFIG_X86_OFFSET_U_BOOT>; }; +# endif #endif +#ifdef CONFIG_HAVE_MICROCODE u-boot-dtb-with-ucode { }; u-boot-ucode { align = <16>; }; +#else + u-boot-dtb { + }; +#endif +#ifdef CONFIG_HAVE_X86_FIT + intel-fit { + }; + intel-fit-ptr { + }; +#endif #ifdef CONFIG_HAVE_MRC intel-mrc { offset = <CONFIG_X86_MRC_ADDR>; }; #endif -#ifdef CONFIG_HAVE_FSP +#ifdef CONFIG_FSP_VERSION1 intel-fsp { filename = CONFIG_FSP_FILE; offset = <CONFIG_FSP_ADDR>; }; #endif +#ifdef CONFIG_FSP_VERSION2 + intel-descriptor { + filename = CONFIG_FLASH_DESCRIPTOR_FILE; + }; + intel-ifwi { + filename = CONFIG_IFWI_INPUT_FILE; + convert-fit; + + section { + size = <0x8000>; + ifwi-replace; + ifwi-subpart = "IBBP"; + ifwi-entry = "IBBL"; + u-boot-tpl { + }; + x86-start16-tpl { + offset = <0x7800>; + }; + x86-reset16-tpl { + offset = <0x7ff0>; + }; + }; + }; + intel-fsp-m { + filename = CONFIG_FSP_FILE_M; + }; + intel-fsp-s { + filename = CONFIG_FSP_FILE_S; + }; +#endif + fdtmap { + }; #ifdef CONFIG_HAVE_CMC intel-cmc { filename = CONFIG_CMC_FILE; @@ -138,5 +186,8 @@ offset = <CONFIG_RESET_VEC_LOC>; }; #endif + image-header { + location = "end"; + }; }; #endif diff --git a/arch/x86/include/asm/arch-apollolake/cpu.h b/arch/x86/include/asm/arch-apollolake/cpu.h new file mode 100644 index 0000000000..5e906c5e7d --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/cpu.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef _ASM_ARCH_CPU_H +#define _ASM_ARCH_CPU_H + +/* Common Timer Copy (CTC) frequency - 19.2MHz */ +#define CTC_FREQ 19200000 + +#define MAX_PCIE_PORTS 6 +#define CLKREQ_DISABLED 0xf + +#ifndef __ASSEMBLY__ +/* Flush L1D to L2 */ +void cpu_flush_l1d_to_l2(void); +#endif + +#endif /* _ASM_ARCH_CPU_H */ diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_configs.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_configs.h new file mode 100644 index 0000000000..9185d94b2b --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_configs.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __FSP_CONFIGS_H__ +#define __FSP_CONFIGS_H__ + +#define FSPT_UPD_SIGNATURE 0x545F4450554C5041 /* 'APLUPD_T' */ +#define FSPM_UPD_SIGNATURE 0x4D5F4450554C5041 /* 'APLUPD_M' */ +#define FSPS_UPD_SIGNATURE 0x535F4450554C5041 /* 'APLUPD_S' */ +#define VBT_SIGNATURE 0x54425624 + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h new file mode 100644 index 0000000000..93bee5b2d1 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright (c) 2019, Intel Corporation. All rights reserved. + * Copyright 2019 Google LLC + */ + +#ifndef __ASM_ARCH_FSP_M_UDP_H +#define __ASM_ARCH_FSP_M_UDP_H + +#include <asm/fsp2/fsp_api.h> + +#define FSP_DRAM_CHANNELS 4 + +struct __packed fspm_arch_upd { + u8 revision; + u8 reserved[3]; + void *nvs_buffer_ptr; + void *stack_base; + u32 stack_size; + u32 boot_loader_tolum_size; + u32 boot_mode; + u8 reserved1[8]; +}; + +struct __packed fsp_ram_channel { + u8 rank_enable; + u8 device_width; + u8 dram_density; + u8 option; + u8 odt_config; + u8 tristate_clk1; + u8 mode2_n; + u8 odt_levels; +}; + +struct __packed fsp_m_config { + u32 serial_debug_port_address; + u8 serial_debug_port_type; + u8 serial_debug_port_device; + u8 serial_debug_port_stride_size; + u8 mrc_fast_boot; + u8 igd; + u8 igd_dvmt50_pre_alloc; + u8 igd_aperture_size; + u8 gtt_size; + u8 primary_video_adaptor; + u8 package; + u8 profile; + u8 memory_down; + + u8 ddr3_l_page_size; + u8 ddr3_lasr; + u8 scrambler_support; + u8 interleaved_mode; + u16 channel_hash_mask; + u16 slice_hash_mask; + u8 channels_slices_enable; + u8 min_ref_rate2x_enable; + u8 dual_rank_support_enable; + u8 rmt_mode; + u16 memory_size_limit; + u16 low_memory_max_value; + + u16 high_memory_max_value; + u8 disable_fast_boot; + u8 dimm0_spd_address; + u8 dimm1_spd_address; + struct fsp_ram_channel chan[FSP_DRAM_CHANNELS]; + u8 rmt_check_run; + u16 rmt_margin_check_scale_high_threshold; + u8 ch_bit_swizzling[FSP_DRAM_CHANNELS][32]; + u32 msg_level_mask; + u8 unused_upd_space0[4]; + + u8 pre_mem_gpio_table_pin_num[4]; + u32 pre_mem_gpio_table_ptr; + u8 pre_mem_gpio_table_entry_num; + u8 enhance_port8xh_decoding; + u8 spd_write_enable; + u8 mrc_data_saving; + u32 oem_loading_base; + + u8 oem_file_name[16]; + + void *mrc_boot_data_ptr; + u8 e_mmc_trace_len; + u8 skip_cse_rbp; + u8 npk_en; + u8 fw_trace_en; + u8 fw_trace_destination; + u8 recover_dump; + u8 msc0_wrap; + u8 msc1_wrap; + u32 msc0_size; + + u32 msc1_size; + u8 pti_mode; + u8 pti_training; + u8 pti_speed; + u8 punit_mlvl; + + u8 pmc_mlvl; + u8 sw_trace_en; + u8 periodic_retraining_disable; + u8 enable_reset_system; + + u8 enable_s3_heci2; + u8 unused_upd_space1[3]; + + void *variable_nvs_buffer_ptr; + u8 reserved_fspm_upd[12]; +}; + +/** FSP-M UPD Configuration */ +struct __packed fspm_upd { + struct fsp_upd_header header; + struct fspm_arch_upd arch; + struct fsp_m_config config; + u8 unused_upd_space2[158]; + u16 upd_terminator; +}; + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_s_upd.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_s_upd.h new file mode 100644 index 0000000000..4a868e80ba --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_s_upd.h @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright (c) 2016, Intel Corporation. All rights reserved. + * Copyright 2019 Google LLC + */ +#ifndef __ASM_ARCH_FSP_S_UDP_H +#define __ASM_ARCH_FSP_S_UDP_H + +#include <asm/fsp2/fsp_api.h> + +struct __packed fsp_s_config { + u8 active_processor_cores; + u8 disable_core1; + u8 disable_core2; + u8 disable_core3; + u8 vmx_enable; + u8 proc_trace_mem_size; + u8 proc_trace_enable; + u8 eist; + u8 boot_p_state; + u8 enable_cx; + u8 c1e; + u8 bi_proc_hot; + u8 pkg_c_state_limit; + u8 c_state_auto_demotion; + u8 c_state_un_demotion; + u8 max_core_c_state; + u8 pkg_c_state_demotion; + u8 pkg_c_state_un_demotion; + u8 turbo_mode; + u8 hda_verb_table_entry_num; + u32 hda_verb_table_ptr; + u8 p2sb_unhide; + u8 ipu_en; + u8 ipu_acpi_mode; + u8 force_wake; + u32 gtt_mm_adr; + u32 gm_adr; + u8 pavp_lock; + u8 graphics_freq_modify; + u8 graphics_freq_req; + u8 graphics_video_freq; + u8 pm_lock; + u8 dop_clock_gating; + u8 unsolicited_attack_override; + u8 wopcm_support; + u8 wopcm_size; + u8 power_gating; + u8 unit_level_clock_gating; + u8 fast_boot; + u8 dyn_sr; + u8 sa_ipu_enable; + u8 pm_support; + u8 enable_render_standby; + u32 logo_size; + u32 logo_ptr; + u32 graphics_config_ptr; + u8 pavp_enable; + u8 pavp_pr3; + u8 cd_clock; + u8 pei_graphics_peim_init; + u8 write_protection_enable[5]; + u8 read_protection_enable[5]; + u16 protected_range_limit[5]; + u16 protected_range_base[5]; + u8 gmm; + u8 clk_gating_pgcb_clk_trunk; + u8 clk_gating_sb; + u8 clk_gating_sb_clk_trunk; + u8 clk_gating_sb_clk_partition; + u8 clk_gating_core; + u8 clk_gating_dma; + u8 clk_gating_reg_access; + u8 clk_gating_host; + u8 clk_gating_partition; + u8 clk_gating_trunk; + u8 hda_enable; + u8 dsp_enable; + u8 pme; + u8 hd_audio_io_buffer_ownership; + u8 hd_audio_io_buffer_voltage; + u8 hd_audio_vc_type; + u8 hd_audio_link_frequency; + u8 hd_audio_i_disp_link_frequency; + u8 hd_audio_i_disp_link_tmode; + u8 dsp_endpoint_dmic; + u8 dsp_endpoint_bluetooth; + u8 dsp_endpoint_i2s_skp; + u8 dsp_endpoint_i2s_hp; + u8 audio_ctl_pwr_gate; + u8 audio_dsp_pwr_gate; + u8 mmt; + u8 hmt; + u8 hd_audio_pwr_gate; + u8 hd_audio_clk_gate; + u32 dsp_feature_mask; + u32 dsp_pp_module_mask; + u8 bios_cfg_lock_down; + u8 hpet; + u8 hpet_bdf_valid; + u8 hpet_bus_number; + u8 hpet_device_number; + u8 hpet_function_number; + u8 io_apic_bdf_valid; + u8 io_apic_bus_number; + u8 io_apic_device_number; + u8 io_apic_function_number; + u8 io_apic_entry24_119; + u8 io_apic_id; + u8 io_apic_range_select; + u8 ish_enable; + u8 bios_interface; + u8 bios_lock; + u8 spi_eiss; + u8 bios_lock_sw_smi_number; + u8 lpss_s0ix_enable; + u8 unused_upd_space0[1]; + u8 i2c_clk_gate_cfg[8]; + u8 hsuart_clk_gate_cfg[4]; + u8 spi_clk_gate_cfg[3]; + u8 i2c0_enable; + u8 i2c1_enable; + u8 i2c2_enable; + u8 i2c3_enable; + u8 i2c4_enable; + u8 i2c5_enable; + u8 i2c6_enable; + u8 i2c7_enable; + u8 hsuart0_enable; + u8 hsuart1_enable; + u8 hsuart2_enable; + u8 hsuart3_enable; + u8 spi0_enable; + u8 spi1_enable; + u8 spi2_enable; + u8 os_dbg_enable; + u8 dci_en; + u32 uart2_kernel_debug_base_address; + u8 pcie_clock_gating_disabled; + u8 pcie_root_port8xh_decode; + u8 pcie8xh_decode_port_index; + u8 pcie_root_port_peer_memory_write_enable; + u8 pcie_aspm_sw_smi_number; + u8 unused_upd_space1[1]; + u8 pcie_root_port_en[6]; + u8 pcie_rp_hide[6]; + u8 pcie_rp_slot_implemented[6]; + u8 pcie_rp_hot_plug[6]; + u8 pcie_rp_pm_sci[6]; + u8 pcie_rp_ext_sync[6]; + u8 pcie_rp_transmitter_half_swing[6]; + u8 pcie_rp_acs_enabled[6]; + u8 pcie_rp_clk_req_supported[6]; + u8 pcie_rp_clk_req_number[6]; + u8 pcie_rp_clk_req_detect[6]; + u8 advanced_error_reporting[6]; + u8 pme_interrupt[6]; + u8 unsupported_request_report[6]; + u8 fatal_error_report[6]; + u8 no_fatal_error_report[6]; + u8 correctable_error_report[6]; + u8 system_error_on_fatal_error[6]; + u8 system_error_on_non_fatal_error[6]; + u8 system_error_on_correctable_error[6]; + u8 pcie_rp_speed[6]; + u8 physical_slot_number[6]; + u8 pcie_rp_completion_timeout[6]; + u8 ptm_enable[6]; + u8 pcie_rp_aspm[6]; + u8 pcie_rp_l1_substates[6]; + u8 pcie_rp_ltr_enable[6]; + u8 pcie_rp_ltr_config_lock[6]; + u8 pme_b0_s5_dis; + u8 pci_clock_run; + u8 timer8254_clk_setting; + u8 enable_sata; + u8 sata_mode; + u8 sata_salp_support; + u8 sata_pwr_opt_enable; + u8 e_sata_speed_limit; + u8 speed_limit; + u8 unused_upd_space2[1]; + u8 sata_ports_enable[2]; + u8 sata_ports_dev_slp[2]; + u8 sata_ports_hot_plug[2]; + u8 sata_ports_interlock_sw[2]; + u8 sata_ports_external[2]; + u8 sata_ports_spin_up[2]; + u8 sata_ports_solid_state_drive[2]; + u8 sata_ports_enable_dito_config[2]; + u8 sata_ports_dm_val[2]; + u8 unused_upd_space3[2]; + u16 sata_ports_dito_val[2]; + u16 sub_system_vendor_id; + u16 sub_system_id; + u8 crid_settings; + u8 reset_select; + u8 sdcard_enabled; + u8 e_mmc_enabled; + u8 e_mmc_host_max_speed; + u8 ufs_enabled; + u8 sdio_enabled; + u8 gpp_lock; + u8 sirq_enable; + u8 sirq_mode; + u8 start_frame_pulse; + u8 smbus_enable; + u8 arp_enable; + u8 unused_upd_space4; + u16 num_rsvd_smbus_addresses; + u8 rsvd_smbus_address_table[128]; + u8 disable_compliance_mode; + u8 usb_per_port_ctl; + u8 usb30_mode; + u8 unused_upd_space5[1]; + u8 port_usb20_enable[8]; + u8 port_us20b_over_current_pin[8]; + u8 usb_otg; + u8 hsic_support_enable; + u8 port_usb30_enable[6]; + u8 port_us30b_over_current_pin[6]; + u8 ssic_port_enable[2]; + u16 dlane_pwr_gating; + u8 vtd_enable; + u8 lock_down_global_smi; + u16 reset_wait_timer; + u8 rtc_lock; + u8 sata_test_mode; + u8 ssic_rate[2]; + u16 dynamic_power_gating; + u16 pcie_rp_ltr_max_snoop_latency[6]; + u8 pcie_rp_snoop_latency_override_mode[6]; + u8 unused_upd_space6[2]; + u16 pcie_rp_snoop_latency_override_value[6]; + u8 pcie_rp_snoop_latency_override_multiplier[6]; + u8 skip_mp_init; + u8 dci_auto_detect; + u16 pcie_rp_ltr_max_non_snoop_latency[6]; + u8 pcie_rp_non_snoop_latency_override_mode[6]; + u8 tco_timer_halt_lock; + u8 pwr_btn_override_period; + u16 pcie_rp_non_snoop_latency_override_value[6]; + u8 pcie_rp_non_snoop_latency_override_multiplier[6]; + u8 pcie_rp_slot_power_limit_scale[6]; + u8 pcie_rp_slot_power_limit_value[6]; + u8 disable_native_power_button; + u8 power_butter_debounce_mode; + u32 sdio_tx_cmd_cntl; + u32 sdio_tx_data_cntl1; + u32 sdio_tx_data_cntl2; + u32 sdio_rx_cmd_data_cntl1; + u32 sdio_rx_cmd_data_cntl2; + u32 sdcard_tx_cmd_cntl; + u32 sdcard_tx_data_cntl1; + u32 sdcard_tx_data_cntl2; + u32 sdcard_rx_cmd_data_cntl1; + u32 sdcard_rx_strobe_cntl; + u32 sdcard_rx_cmd_data_cntl2; + u32 emmc_tx_cmd_cntl; + u32 emmc_tx_data_cntl1; + u32 emmc_tx_data_cntl2; + u32 emmc_rx_cmd_data_cntl1; + u32 emmc_rx_strobe_cntl; + u32 emmc_rx_cmd_data_cntl2; + u32 emmc_master_sw_cntl; + u8 pcie_rp_selectable_deemphasis[6]; + u8 monitor_mwait_enable; + u8 hd_audio_dsp_uaa_compliance; + u32 ipc[4]; + u8 sata_ports_disable_dynamic_pg[2]; + u8 init_s3_cpu; + u8 skip_punit_init; + u8 unused_upd_space7[4]; + u8 port_usb20_per_port_tx_pe_half[8]; + u8 port_usb20_per_port_pe_txi_set[8]; + u8 port_usb20_per_port_txi_set[8]; + u8 port_usb20_hs_skew_sel[8]; + u8 port_usb20_i_usb_tx_emphasis_en[8]; + u8 port_usb20_per_port_rxi_set[8]; + u8 port_usb20_hs_npre_drv_sel[8]; + u8 reserved_fsps_upd[16]; +}; + +/** struct fsps_upd - FSP-S Configuration */ +struct __packed fsps_upd { + struct fsp_upd_header header; + struct fsp_s_config config; + u8 unused_upd_space2[46]; + u16 upd_terminator; +}; + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_vpd.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_vpd.h new file mode 100644 index 0000000000..b14f28b236 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_vpd.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __FSP_VPD_H +#define __FSP_VPD_H + +/* Nothing to declare here for FSP2 */ + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/gpio.h b/arch/x86/include/asm/arch-apollolake/gpio.h new file mode 100644 index 0000000000..10879c168e --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/gpio.h @@ -0,0 +1,485 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Definitions for the GPIO subsystem on Apollolake + * + * Copyright (C) 2015 - 2017 Intel Corp. + * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.) + * + * Placed in a separate file since some of these definitions can be used from + * assembly code + * + * Taken from gpio_apl.h in coreboot + */ + +#ifndef _ASM_ARCH_GPIO_H_ +#define _ASM_ARCH_GPIO_H_ + +/* Port ids */ +#define PID_GPIO_SW 0xC0 +#define PID_GPIO_S 0xC2 +#define PID_GPIO_W 0xC7 +#define PID_GPIO_NW 0xC4 +#define PID_GPIO_N 0xC5 +#define PID_ITSS 0xD0 +#define PID_RTC 0xD1 + +/* + * Miscellaneous Configuration register(MISCCFG). These are community-specific + * registers and are meant to house miscellaneous configuration fields per + * community. There are 8 GPIO groups: GPP_0 -> GPP_8 (Group 3 is absent) + */ +#define GPIO_MISCCFG 0x10 /* Miscellaneous Configuration offset */ +#define GPIO_GPE_SW_31_0 0 /* SOUTHWEST GPIO# 0 ~ 31 belong to GROUP0 */ +#define GPIO_GPE_SW_63_32 1 /* SOUTHWEST GPIO# 32 ~ 42 belong to GROUP1 */ +#define GPIO_GPE_W_31_0 2 /* WEST GPIO# 0 ~ 25 belong to GROUP2 */ +#define GPIO_GPE_NW_31_0 4 /* NORTHWEST GPIO# 0 ~ 17 belong to GROUP4 */ +#define GPIO_GPE_NW_63_32 5 /* NORTHWEST GPIO# 32 ~ 63 belong to GROUP5 */ +#define GPIO_GPE_NW_95_64 6 /* NORTHWEST GPIO# 64 ~ 76 belong to GROUP6 */ +#define GPIO_GPE_N_31_0 7 /* NORTH GPIO# 0 ~ 31 belong to GROUP7 */ +#define GPIO_GPE_N_63_32 8 /* NORTH GPIO# 32 ~ 61 belong to GROUP8 */ + +#define GPIO_MAX_NUM_PER_GROUP 32 + +/* + * Host Software Pad Ownership Register. + * The pins in the community are divided into 3 groups: + * GPIO 0 ~ 31, GPIO 32 ~ 63, GPIO 64 ~ 95 + */ +#define HOSTSW_OWN_REG_0 0x80 + +#define PAD_CFG_BASE 0x500 + +#define GPI_INT_STS_0 0x100 +#define GPI_INT_EN_0 0x110 + +#define GPI_SMI_STS_0 0x140 +#define GPI_SMI_EN_0 0x150 + +#define NUM_N_PADS (PAD_N(SVID0_CLK) + 1) +#define NUM_NW_PADS (PAD_NW(GPIO_123) + 1) +#define NUM_W_PADS (PAD_W(SUSPWRDNACK) + 1) +#define NUM_SW_PADS (PAD_SW(LPC_FRAMEB) + 1) + +#define NUM_N_GPI_REGS \ + (ALIGN(NUM_N_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_NW_GPI_REGS \ + (ALIGN(NUM_NW_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_W_GPI_REGS \ + (ALIGN(NUM_W_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_SW_GPI_REGS \ + (ALIGN(NUM_SW_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +/* + * Total number of GPI status registers across all GPIO communities in the SOC + */ +#define NUM_GPI_STATUS_REGS (NUM_N_GPI_REGS + NUM_NW_GPI_REGS \ + + NUM_W_GPI_REGS + NUM_SW_GPI_REGS) + +/* North community pads */ +#define GPIO_0 0 +#define GPIO_1 1 +#define GPIO_2 2 +#define GPIO_3 3 +#define GPIO_4 4 +#define GPIO_5 5 +#define GPIO_6 6 +#define GPIO_7 7 +#define GPIO_8 8 +#define GPIO_9 9 +#define GPIO_10 10 +#define GPIO_11 11 +#define GPIO_12 12 +#define GPIO_13 13 +#define GPIO_14 14 +#define GPIO_15 15 +#define GPIO_16 16 +#define GPIO_17 17 +#define GPIO_18 18 +#define GPIO_19 19 +#define GPIO_20 20 +#define GPIO_21 21 +#define GPIO_22 22 +#define GPIO_23 23 +#define GPIO_24 24 +#define GPIO_25 25 +#define GPIO_26 26 +#define GPIO_27 27 +#define GPIO_28 28 +#define GPIO_29 29 +#define GPIO_30 30 +#define GPIO_31 31 +#define GPIO_32 32 +#define GPIO_33 33 +#define GPIO_34 34 +#define GPIO_35 35 +#define GPIO_36 36 +#define GPIO_37 37 +#define GPIO_38 38 +#define GPIO_39 39 +#define GPIO_40 40 +#define GPIO_41 41 +#define GPIO_42 42 +#define GPIO_43 43 +#define GPIO_44 44 +#define GPIO_45 45 +#define GPIO_46 46 +#define GPIO_47 47 +#define GPIO_48 48 +#define GPIO_49 49 +#define GPIO_62 50 +#define GPIO_63 51 +#define GPIO_64 52 +#define GPIO_65 53 +#define GPIO_66 54 +#define GPIO_67 55 +#define GPIO_68 56 +#define GPIO_69 57 +#define GPIO_70 58 +#define GPIO_71 59 +#define GPIO_72 60 +#define GPIO_73 61 +#define JTAG_TCK 62 +#define JTAG_TRST_B 63 +#define JTAG_TMS 64 +#define JTAG_TDI 65 +#define JTAG_CX_PMODE 66 +#define JTAG_CX_PREQ_B 67 +#define JTAGX 68 +#define JTAG_CX_PRDY_B 69 +#define JTAG_TDO 70 +#define CNV_BRI_DT 71 +#define CNV_BRI_RSP 72 +#define CNV_RGI_DT 73 +#define CNV_RGI_RSP 74 +#define SVID0_ALERT_B 75 +#define SVID0_DATA 76 +#define SVID0_CLK 77 + +/* Northwest community pads */ +#define GPIO_187 78 +#define GPIO_188 79 +#define GPIO_189 80 +#define GPIO_190 81 +#define GPIO_191 82 +#define GPIO_192 83 +#define GPIO_193 84 +#define GPIO_194 85 +#define GPIO_195 86 +#define GPIO_196 87 +#define GPIO_197 88 +#define GPIO_198 89 +#define GPIO_199 90 +#define GPIO_200 91 +#define GPIO_201 92 +#define GPIO_202 93 +#define GPIO_203 94 +#define GPIO_204 95 +#define PMC_SPI_FS0 96 +#define PMC_SPI_FS1 97 +#define PMC_SPI_FS2 98 +#define PMC_SPI_RXD 99 +#define PMC_SPI_TXD 100 +#define PMC_SPI_CLK 101 +#define PMIC_PWRGOOD 102 +#define PMIC_RESET_B 103 +#define GPIO_213 104 +#define GPIO_214 105 +#define GPIO_215 106 +#define PMIC_THERMTRIP_B 107 +#define PMIC_STDBY 108 +#define PROCHOT_B 109 +#define PMIC_I2C_SCL 110 +#define PMIC_I2C_SDA 111 +#define GPIO_74 112 +#define GPIO_75 113 +#define GPIO_76 114 +#define GPIO_77 115 +#define GPIO_78 116 +#define GPIO_79 117 +#define GPIO_80 118 +#define GPIO_81 119 +#define GPIO_82 120 +#define GPIO_83 121 +#define GPIO_84 122 +#define GPIO_85 123 +#define GPIO_86 124 +#define GPIO_87 125 +#define GPIO_88 126 +#define GPIO_89 127 +#define GPIO_90 128 +#define GPIO_91 129 +#define GPIO_92 130 +#define GPIO_97 131 +#define GPIO_98 132 +#define GPIO_99 133 +#define GPIO_100 134 +#define GPIO_101 135 +#define GPIO_102 136 +#define GPIO_103 137 +#define FST_SPI_CLK_FB 138 +#define GPIO_104 139 +#define GPIO_105 140 +#define GPIO_106 141 +#define GPIO_109 142 +#define GPIO_110 143 +#define GPIO_111 144 +#define GPIO_112 145 +#define GPIO_113 146 +#define GPIO_116 147 +#define GPIO_117 148 +#define GPIO_118 149 +#define GPIO_119 150 +#define GPIO_120 151 +#define GPIO_121 152 +#define GPIO_122 153 +#define GPIO_123 154 + +/* West community pads */ +#define GPIO_124 155 +#define GPIO_125 156 +#define GPIO_126 157 +#define GPIO_127 158 +#define GPIO_128 159 +#define GPIO_129 160 +#define GPIO_130 161 +#define GPIO_131 162 +#define GPIO_132 163 +#define GPIO_133 164 +#define GPIO_134 165 +#define GPIO_135 166 +#define GPIO_136 167 +#define GPIO_137 168 +#define GPIO_138 169 +#define GPIO_139 170 +#define GPIO_146 171 +#define GPIO_147 172 +#define GPIO_148 173 +#define GPIO_149 174 +#define GPIO_150 175 +#define GPIO_151 176 +#define GPIO_152 177 +#define GPIO_153 178 +#define GPIO_154 179 +#define GPIO_155 180 +#define GPIO_209 181 +#define GPIO_210 182 +#define GPIO_211 183 +#define GPIO_212 184 +#define OSC_CLK_OUT_0 185 +#define OSC_CLK_OUT_1 186 +#define OSC_CLK_OUT_2 187 +#define OSC_CLK_OUT_3 188 +#define OSC_CLK_OUT_4 189 +#define PMU_AC_PRESENT 190 +#define PMU_BATLOW_B 191 +#define PMU_PLTRST_B 192 +#define PMU_PWRBTN_B 193 +#define PMU_RESETBUTTON_B 194 +#define PMU_SLP_S0_B 195 +#define PMU_SLP_S3_B 196 +#define PMU_SLP_S4_B 197 +#define PMU_SUSCLK 198 +#define PMU_WAKE_B 199 +#define SUS_STAT_B 200 +#define SUSPWRDNACK 201 + +/* Southwest community pads */ +#define GPIO_205 202 +#define GPIO_206 203 +#define GPIO_207 204 +#define GPIO_208 205 +#define GPIO_156 206 +#define GPIO_157 207 +#define GPIO_158 208 +#define GPIO_159 209 +#define GPIO_160 210 +#define GPIO_161 211 +#define GPIO_162 212 +#define GPIO_163 213 +#define GPIO_164 214 +#define GPIO_165 215 +#define GPIO_166 216 +#define GPIO_167 217 +#define GPIO_168 218 +#define GPIO_169 219 +#define GPIO_170 220 +#define GPIO_171 221 +#define GPIO_172 222 +#define GPIO_179 223 +#define GPIO_173 224 +#define GPIO_174 225 +#define GPIO_175 226 +#define GPIO_176 227 +#define GPIO_177 228 +#define GPIO_178 229 +#define GPIO_186 230 +#define GPIO_182 231 +#define GPIO_183 232 +#define SMB_ALERTB 233 +#define SMB_CLK 234 +#define SMB_DATA 235 +#define LPC_ILB_SERIRQ 236 +#define LPC_CLKOUT0 237 +#define LPC_CLKOUT1 238 +#define LPC_AD0 239 +#define LPC_AD1 240 +#define LPC_AD2 241 +#define LPC_AD3 242 +#define LPC_CLKRUNB 243 +#define LPC_FRAMEB 244 + +/* PERST_0 not defined */ +#define GPIO_PRT0_UDEF 0xFF + +#define TOTAL_PADS 245 +#define N_OFFSET GPIO_0 +#define NW_OFFSET GPIO_187 +#define W_OFFSET GPIO_124 +#define SW_OFFSET GPIO_205 + +/* Macros for translating a global pad offset to a local offset */ +#define PAD_N(pad) (pad - N_OFFSET) +#define PAD_NW(pad) (pad - NW_OFFSET) +#define PAD_W(pad) (pad - W_OFFSET) +#define PAD_SW(pad) (pad - SW_OFFSET) + +/* Linux names of the GPIO devices */ +#define GPIO_COMM_N_NAME "INT3452:00" +#define GPIO_COMM_NW_NAME "INT3452:01" +#define GPIO_COMM_W_NAME "INT3452:02" +#define GPIO_COMM_SW_NAME "INT3452:03" + +/* Following is used in gpio asl */ +#define GPIO_COMM_NAME "INT3452" +#define GPIO_COMM_0_DESC \ + "General Purpose Input/Output (GPIO) Controller - North" +#define GPIO_COMM_1_DESC \ + "General Purpose Input/Output (GPIO) Controller - Northwest" +#define GPIO_COMM_2_DESC \ + "General Purpose Input/Output (GPIO) Controller - West" +#define GPIO_COMM_3_DESC \ + "General Purpose Input/Output (GPIO) Controller - Southwest" + +#define GPIO_COMM0_PID PID_GPIO_N +#define GPIO_COMM1_PID PID_GPIO_NW +#define GPIO_COMM2_PID PID_GPIO_W +#define GPIO_COMM3_PID PID_GPIO_SW + +/* + * IOxAPIC IRQs for the GPIOs, overlap is expected as we encourage to use + * shared IRQ instead of direct IRQ, in case of overlapping, we can easily + * program one of the overlap to shared IRQ to avoid the conflict. + */ + +/* NorthWest community pads */ +#define PMIC_I2C_SDA_IRQ 0x32 +#define GPIO_74_IRQ 0x33 +#define GPIO_75_IRQ 0x34 +#define GPIO_76_IRQ 0x35 +#define GPIO_77_IRQ 0x36 +#define GPIO_78_IRQ 0x37 +#define GPIO_79_IRQ 0x38 +#define GPIO_80_IRQ 0x39 +#define GPIO_81_IRQ 0x3A +#define GPIO_82_IRQ 0x3B +#define GPIO_83_IRQ 0x3C +#define GPIO_84_IRQ 0x3D +#define GPIO_85_IRQ 0x3E +#define GPIO_86_IRQ 0x3F +#define GPIO_87_IRQ 0x40 +#define GPIO_88_IRQ 0x41 +#define GPIO_89_IRQ 0x42 +#define GPIO_90_IRQ 0x43 +#define GPIO_91_IRQ 0x44 +#define GPIO_97_IRQ 0x49 +#define GPIO_98_IRQ 0x4A +#define GPIO_99_IRQ 0x4B +#define GPIO_100_IRQ 0x4C +#define GPIO_101_IRQ 0x4D +#define GPIO_102_IRQ 0x4E +#define GPIO_103_IRQ 0x4F +#define GPIO_104_IRQ 0x50 +#define GPIO_105_IRQ 0x51 +#define GPIO_106_IRQ 0x52 +#define GPIO_109_IRQ 0x54 +#define GPIO_110_IRQ 0x55 +#define GPIO_111_IRQ 0x56 +#define GPIO_112_IRQ 0x57 +#define GPIO_113_IRQ 0x58 +#define GPIO_116_IRQ 0x5B +#define GPIO_117_IRQ 0x5C +#define GPIO_118_IRQ 0x5D +#define GPIO_119_IRQ 0x5E +#define GPIO_120_IRQ 0x5F +#define GPIO_121_IRQ 0x60 +#define GPIO_122_IRQ 0x61 +#define GPIO_123_IRQ 0x62 + +/* North community pads */ +#define GPIO_0_IRQ 0x63 +#define GPIO_1_IRQ 0x64 +#define GPIO_2_IRQ 0x65 +#define GPIO_3_IRQ 0x66 +#define GPIO_4_IRQ 0x67 +#define GPIO_5_IRQ 0x68 +#define GPIO_6_IRQ 0x69 +#define GPIO_7_IRQ 0x6A +#define GPIO_8_IRQ 0x6B +#define GPIO_9_IRQ 0x6C +#define GPIO_10_IRQ 0x6D +#define GPIO_11_IRQ 0x6E +#define GPIO_12_IRQ 0x6F +#define GPIO_13_IRQ 0x70 +#define GPIO_14_IRQ 0x71 +#define GPIO_15_IRQ 0x72 +#define GPIO_16_IRQ 0x73 +#define GPIO_17_IRQ 0x74 +#define GPIO_18_IRQ 0x75 +#define GPIO_19_IRQ 0x76 +#define GPIO_20_IRQ 0x77 +#define GPIO_21_IRQ 0x32 +#define GPIO_22_IRQ 0x33 +#define GPIO_23_IRQ 0x34 +#define GPIO_24_IRQ 0x35 +#define GPIO_25_IRQ 0x36 +#define GPIO_26_IRQ 0x37 +#define GPIO_27_IRQ 0x38 +#define GPIO_28_IRQ 0x39 +#define GPIO_29_IRQ 0x3A +#define GPIO_30_IRQ 0x3B +#define GPIO_31_IRQ 0x3C +#define GPIO_32_IRQ 0x3D +#define GPIO_33_IRQ 0x3E +#define GPIO_34_IRQ 0x3F +#define GPIO_35_IRQ 0x40 +#define GPIO_36_IRQ 0x41 +#define GPIO_37_IRQ 0x42 +#define GPIO_38_IRQ 0x43 +#define GPIO_39_IRQ 0x44 +#define GPIO_40_IRQ 0x45 +#define GPIO_41_IRQ 0x46 +#define GPIO_42_IRQ 0x47 +#define GPIO_43_IRQ 0x48 +#define GPIO_44_IRQ 0x49 +#define GPIO_45_IRQ 0x4A +#define GPIO_46_IRQ 0x4B +#define GPIO_47_IRQ 0x4C +#define GPIO_48_IRQ 0x4D +#define GPIO_49_IRQ 0x4E +#define GPIO_62_IRQ 0x5B +#define GPIO_63_IRQ 0x5C +#define GPIO_64_IRQ 0x5D +#define GPIO_65_IRQ 0x5E +#define GPIO_66_IRQ 0x5F +#define GPIO_67_IRQ 0x60 +#define GPIO_68_IRQ 0x61 +#define GPIO_69_IRQ 0x62 +#define GPIO_70_IRQ 0x63 +#define GPIO_71_IRQ 0x64 +#define GPIO_72_IRQ 0x65 +#define GPIO_73_IRQ 0x66 + +#endif /* _ASM_ARCH_GPIO_H_ */ diff --git a/arch/x86/include/asm/arch-apollolake/iomap.h b/arch/x86/include/asm/arch-apollolake/iomap.h new file mode 100644 index 0000000000..4ce1017055 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/iomap.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 Intel Corporation. + * Take from coreboot project file of the same name + */ + +#ifndef _ASM_ARCH_IOMAP_H +#define _ASM_ARCH_IOMAP_H + +#define R_ACPI_PM1_TMR 0x8 + +/* Put p2sb at 0xd0000000 in TPL */ +#define IOMAP_P2SB_BAR 0xd0000000 + +#define IOMAP_SPI_BASE 0xfe010000 + +#define IOMAP_ACPI_BASE 0x400 +#define IOMAP_ACPI_SIZE 0x100 + +/* + * Use UART2. To use UART1 you need to set '2' to '1', change device tree serial + * node name and 'reg' property, and update CONFIG_DEBUG_UART_BASE. + */ +#define PCH_DEV_UART PCI_BDF(0, 0x18, 2) + +#define PCH_DEV_LPC PCI_BDF(0, 0x1f, 0) +#define PCH_DEV_SPI PCI_BDF(0, 0x0d, 2) + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/itss.h b/arch/x86/include/asm/arch-apollolake/itss.h new file mode 100644 index 0000000000..1e29503974 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/itss.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 Intel Corporation. + * Copyright 2019 Google LLC + * + * Modified from coreboot itss.h + */ + +#ifndef _ASM_ARCH_ITSS_H +#define _ASM_ARCH_ITSS_H + +#define GPIO_IRQ_START 50 +#define GPIO_IRQ_END ITSS_MAX_IRQ + +#define ITSS_MAX_IRQ 119 +#define IRQS_PER_IPC 32 +#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1) / IRQS_PER_IPC) + +/* Max PXRC registers in ITSS */ +#define MAX_PXRC_CONFIG (PCR_ITSS_PIRQH_ROUT - PCR_ITSS_PIRQA_ROUT + 1) + +/* PIRQA Routing Control Register */ +#define PCR_ITSS_PIRQA_ROUT 0x3100 +/* PIRQB Routing Control Register */ +#define PCR_ITSS_PIRQB_ROUT 0x3101 +/* PIRQC Routing Control Register */ +#define PCR_ITSS_PIRQC_ROUT 0x3102 +/* PIRQD Routing Control Register */ +#define PCR_ITSS_PIRQD_ROUT 0x3103 +/* PIRQE Routing Control Register */ +#define PCR_ITSS_PIRQE_ROUT 0x3104 +/* PIRQF Routing Control Register */ +#define PCR_ITSS_PIRQF_ROUT 0x3105 +/* PIRQG Routing Control Register */ +#define PCR_ITSS_PIRQG_ROUT 0x3106 +/* PIRQH Routing Control Register */ +#define PCR_ITSS_PIRQH_ROUT 0x3107 +/* ITSS Interrupt polarity control */ +#define PCR_ITSS_IPC0_CONF 0x3200 +/* ITSS Power reduction control */ +#define PCR_ITSS_ITSSPRC 0x3300 + +#endif /* _ASM_ARCH_ITSS_H */ diff --git a/arch/x86/include/asm/arch-apollolake/lpc.h b/arch/x86/include/asm/arch-apollolake/lpc.h new file mode 100644 index 0000000000..5d2adad319 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/lpc.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 Intel Corporation. + * Take from coreboot project file of the same name + */ + +#ifndef _ASM_ARCH_LPC_H +#define _ASM_ARCH_LPC_H + +#define LPC_SERIRQ_CTL 0x64 +#define LPC_SCNT_EN BIT(7) +#define LPC_SCNT_MODE BIT(6) +#define LPC_IO_DECODE 0x80 +#define LPC_IOD_COMA_RANGE (0 << 0) /* 0x3F8 - 0x3FF COMA*/ +#define LPC_IOD_COMB_RANGE (1 << 4) /* 0x2F8 - 0x2FF COMB*/ +/* + * Use IO_<peripheral>_<IO port> style macros defined in lpc_lib.h + * to enable decoding of I/O locations for a peripheral + */ +#define LPC_IO_ENABLES 0x82 +#define LPC_GENERIC_IO_RANGE(n) ((((n) & 0x3) * 4) + 0x84) +#define LPC_LGIR_AMASK_MASK (0xfc << 16) +#define LPC_LGIR_ADDR_MASK 0xfffc +#define LPC_LGIR_EN BIT(0) +#define LPC_LGIR_MAX_WINDOW_SIZE 256 +#define LPC_GENERIC_MEM_RANGE 0x98 +#define LPC_LGMR_ADDR_MASK 0xffff0000 +#define LPC_LGMR_EN BIT(0) +#define LPC_LGMR_WINDOW_SIZE (64 * KiB) +#define LPC_BIOS_CNTL 0xdc +#define LPC_BC_BILD BIT(7) +#define LPC_BC_LE BIT(1) +#define LPC_BC_EISS BIT(5) +#define LPC_PCCTL 0xE0 /* PCI Clock Control */ +#define LPC_PCCTL_CLKRUN_EN BIT(0) + +/* + * IO decode enable macros are in the format IO_<peripheral>_<IO port>. + * For example, to open ports 0x60, 0x64 for the keyboard controller, + * use IOE_KBC_60_64 macro. For IOE_ macros that do not specify a port range, + * the port range is selectable via the IO decodes register. + */ +#define LPC_IOE_EC_4E_4F BIT(13) +#define LPC_IOE_SUPERIO_2E_2F BIT(12) +#define LPC_IOE_EC_62_66 BIT(11) +#define LPC_IOE_KBC_60_64 BIT(10) +#define LPC_IOE_HGE_208 BIT(9) +#define LPC_IOE_LGE_200 BIT(8) +#define LPC_IOE_FDD_EN BIT(3) +#define LPC_IOE_LPT_EN BIT(2) +#define LPC_IOE_COMB_EN BIT(1) +#define LPC_IOE_COMA_EN BIT(0) +#define LPC_NUM_GENERIC_IO_RANGES 4 + +#define LPC_IO_ENABLES 0x82 + +/** + * lpc_enable_fixed_io_ranges() - enable the fixed I/O ranges + * + * @io_enables: Mask of things to enable (LPC_IOE_.) + */ +void lpc_enable_fixed_io_ranges(uint io_enables); + +/** + * lpc_open_pmio_window() - Open an IO port range + * + * @base: Base I/O address (e.g. 0x800) + * @size: Size of window (e.g. 0x100) + * @return 0 if OK, -ENOSPC if there are no more windows available, -EALREADY + * if already set up + */ +int lpc_open_pmio_window(uint base, uint size); + +/** + * lpc_io_setup_comm_a_b() - Set up basic serial UARTs + * + * Set up the LPC to handle I/O to the COMA/COMB serial UART addresses + * 2f8-2ff and 3f8-3ff. + */ +void lpc_io_setup_comm_a_b(void); + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/pch.h b/arch/x86/include/asm/arch-apollolake/pch.h new file mode 100644 index 0000000000..bf3e1670d2 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/pch.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef _ASM_ARCH_PCH_H +#define _ASM_ARCH_PCH_H + +#endif /* _ASM_ARCH_PCH_H */ diff --git a/arch/x86/include/asm/arch-apollolake/pm.h b/arch/x86/include/asm/arch-apollolake/pm.h new file mode 100644 index 0000000000..6718290c4f --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/pm.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.) + */ + +#ifndef _ASM_ARCH_PM_H +#define _ASM_ARCH_PM_H + +#define PMC_GPE_SW_31_0 0 +#define PMC_GPE_SW_63_32 1 +#define PMC_GPE_NW_31_0 3 +#define PMC_GPE_NW_63_32 4 +#define PMC_GPE_NW_95_64 5 +#define PMC_GPE_N_31_0 6 +#define PMC_GPE_N_63_32 7 +#define PMC_GPE_W_31_0 9 + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/systemagent.h b/arch/x86/include/asm/arch-apollolake/systemagent.h new file mode 100644 index 0000000000..206d8903fa --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/systemagent.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 Intel Corporation. + * Take from coreboot project file of the same name + */ + +#ifndef _ASM_ARCH_SYSTEMAGENT_H +#define _ASM_ARCH_SYSTEMAGENT_H + +/* Device 0:0.0 PCI configuration space */ +#define MCHBAR 0x48 + +/* RAPL Package Power Limit register under MCHBAR */ +#define PUNIT_THERMAL_DEVICE_IRQ 0x700C +#define PUINT_THERMAL_DEVICE_IRQ_VEC_NUMBER 0x18 +#define PUINT_THERMAL_DEVICE_IRQ_LOCK 0x80000000 +#define BIOS_RESET_CPL 0x7078 +#define PCODE_INIT_DONE BIT(8) +#define MCHBAR_RAPL_PPL 0x70A8 +#define CORE_DISABLE_MASK 0x7168 +#define CAPID0_A 0xE4 +#define VTD_DISABLE BIT(23) +#define DEFVTBAR 0x6c80 +#define GFXVTBAR 0x6c88 +#define VTBAR_ENABLED 0x01 +#define VTBAR_MASK GENMASK_ULL(39, 12) +#define VTBAR_SIZE 0x1000 + +/** + * enable_bios_reset_cpl() - Tell the system agent that memory/power are ready + * + * This should be called when U-Boot has set up the memory and power + * management. + */ +void enable_bios_reset_cpl(void); + +#endif diff --git a/arch/x86/include/asm/arch-apollolake/uart.h b/arch/x86/include/asm/arch-apollolake/uart.h new file mode 100644 index 0000000000..d4fffe6525 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/uart.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef _ASM_ARCH_UART_H +#define _ASM_ARCH_UART_H + +/** + * apl_uart_init() - Set up the APL UART device and clock + * + * This enables the PCI device, sets up the MMIO region and turns on the clock + * using LPSS. + * + * The UART won't actually work unless the GPIO settings are correct and the + * signals actually exit the SoC. See board_debug_uart_init() for that. + */ +int apl_uart_init(pci_dev_t bdf, ulong base); + +#endif diff --git a/arch/x86/include/asm/arch-broadwell/cpu.h b/arch/x86/include/asm/arch-broadwell/cpu.h index 3bc3bd6609..2b39a76fbd 100644 --- a/arch/x86/include/asm/arch-broadwell/cpu.h +++ b/arch/x86/include/asm/arch-broadwell/cpu.h @@ -27,7 +27,6 @@ #define MSR_VR_CURRENT_CONFIG 0x601 #define MSR_VR_MISC_CONFIG 0x603 -#define MSR_PKG_POWER_SKU 0x614 #define MSR_DDR_RAPL_LIMIT 0x618 #define MSR_VR_MISC_CONFIG2 0x636 diff --git a/arch/x86/include/asm/arch-ivybridge/model_206ax.h b/arch/x86/include/asm/arch-ivybridge/model_206ax.h index 4839ebc312..5c066294bc 100644 --- a/arch/x86/include/asm/arch-ivybridge/model_206ax.h +++ b/arch/x86/include/asm/arch-ivybridge/model_206ax.h @@ -43,7 +43,6 @@ #define MSR_PP1_CURRENT_CONFIG 0x602 #define PP1_CURRENT_LIMIT_SNB (35 << 3) /* 35 A */ #define PP1_CURRENT_LIMIT_IVB (50 << 3) /* 50 A */ -#define MSR_PKG_POWER_SKU 0x614 #define IVB_CONFIG_TDP_MIN_CPUID 0x306a2 #define MSR_CONFIG_TDP_LEVEL1 0x649 diff --git a/arch/x86/include/asm/fast_spi.h b/arch/x86/include/asm/fast_spi.h new file mode 100644 index 0000000000..6894298526 --- /dev/null +++ b/arch/x86/include/asm/fast_spi.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2017 Intel Corporation. + */ + +#ifndef ASM_FAST_SPI_H +#define ASM_FAST_SPI_H + +/* Register offsets from the MMIO region base (PCI_BASE_ADDRESS_0) */ +struct fast_spi_regs { + u32 bfp; + u32 hsfsts_ctl; + u32 faddr; + u32 dlock; + + u32 fdata[0x10]; + + u32 fracc; + u32 freg[12]; + u32 fpr[5]; + u32 gpr0; + u32 spare2; + u32 sts_ctl; + u16 preop; + u16 optype; + u8 opmenu[8]; + + u32 spare3; + u32 fdoc; + u32 fdod; + u32 spare4; + u32 afc; + u32 vscc[2]; + u32 ptinx; + u32 ptdata; +}; +check_member(fast_spi_regs, ptdata, 0xd0); + +/* Bit definitions for BFPREG (0x00) register */ +#define SPIBAR_BFPREG_PRB_MASK 0x7fff +#define SPIBAR_BFPREG_PRL_SHIFT 16 +#define SPIBAR_BFPREG_PRL_MASK (0x7fff << SPIBAR_BFPREG_PRL_SHIFT) + +/* PCI configuration registers */ +#define SPIBAR_BIOS_CONTROL 0xdc +#define SPIBAR_BIOS_CONTROL_WPD BIT(0) +#define SPIBAR_BIOS_CONTROL_LOCK_ENABLE BIT(1) +#define SPIBAR_BIOS_CONTROL_CACHE_DISABLE BIT(2) +#define SPIBAR_BIOS_CONTROL_PREFETCH_ENABLE BIT(3) +#define SPIBAR_BIOS_CONTROL_EISS BIT(5) +#define SPIBAR_BIOS_CONTROL_BILD BIT(7) + +/** + * fast_spi_get_bios_mmap() - Get memory map for SPI flash + * + * @pdev: PCI device to use (this is the Fast SPI device) + * @map_basep: Returns base memory address for mapped SPI + * @map_sizep: Returns size of mapped SPI + * @offsetp: Returns start offset of SPI flash where the map works + * correctly (offsets before this are not visible) + * @return 0 (always) + */ +int fast_spi_get_bios_mmap(pci_dev_t pdev, ulong *map_basep, uint *map_sizep, + uint *offsetp); + +int fast_spi_early_init(pci_dev_t pdev, ulong mmio_base); + +#endif /* ASM_FAST_SPI_H */ diff --git a/arch/x86/include/asm/fsp/fsp_api.h b/arch/x86/include/asm/fsp/fsp_api.h new file mode 100644 index 0000000000..e9ac86b2da --- /dev/null +++ b/arch/x86/include/asm/fsp/fsp_api.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __ASM_FSP_API_H +#define __ASM_FSP_API_H + +enum fsp_phase { + /* Notification code for post PCI enuermation */ + INIT_PHASE_PCI = 0x20, + /* Notification code before transferring control to the payload */ + INIT_PHASE_BOOT = 0x40 +}; + +struct fsp_notify_params { + /* Notification phase used for NotifyPhase API */ + enum fsp_phase phase; +}; + +/* FspNotify API function prototype */ +typedef asmlinkage u32 (*fsp_notify_f)(struct fsp_notify_params *params); + +#endif diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h index 4ac27d26f5..29e511415c 100644 --- a/arch/x86/include/asm/fsp/fsp_support.h +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -144,13 +144,6 @@ int fsp_init_phase_pci(void); int fsp_scan_for_ram_size(void); /** - * fsp_prepare_mrc_cache() - Find the DRAM training data from the MRC cache - * - * @return pointer to data, or NULL if no cache or no data found in the cache - */ -void *fsp_prepare_mrc_cache(void); - -/** * fsp_notify() - FSP notification wrapper function * * @fsp_hdr: Pointer to FSP information header diff --git a/arch/x86/include/asm/fsp1/fsp_api.h b/arch/x86/include/asm/fsp1/fsp_api.h index f2d70799f3..524da5feb7 100644 --- a/arch/x86/include/asm/fsp1/fsp_api.h +++ b/arch/x86/include/asm/fsp1/fsp_api.h @@ -4,11 +4,11 @@ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> */ -#ifndef __FSP_API_H__ -#define __FSP_API_H__ +#ifndef __FSP1_API_H__ +#define __FSP1_API_H__ #include <linux/linkage.h> - +#include <asm/fsp/fsp_api.h> /* * FSP common configuration structure. * This needs to be included in the platform-specific struct fsp_config_data. @@ -46,22 +46,7 @@ struct common_buf { u32 reserved[6]; /* Reserved */ }; -enum fsp_phase { - /* Notification code for post PCI enuermation */ - INIT_PHASE_PCI = 0x20, - /* Notification code before transfering control to the payload */ - INIT_PHASE_BOOT = 0x40 -}; - -struct fsp_notify_params { - /* Notification phase used for NotifyPhase API */ - enum fsp_phase phase; -}; - /* FspInit API function prototype */ typedef asmlinkage u32 (*fsp_init_f)(struct fsp_init_params *params); -/* FspNotify API function prototype */ -typedef asmlinkage u32 (*fsp_notify_f)(struct fsp_notify_params *params); - #endif diff --git a/arch/x86/include/asm/fsp2/fsp_api.h b/arch/x86/include/asm/fsp2/fsp_api.h new file mode 100644 index 0000000000..af1e8857b9 --- /dev/null +++ b/arch/x86/include/asm/fsp2/fsp_api.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.) + * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.) + * Mostly taken from coreboot fsp2_0/memory_init.c + */ + +#ifndef __ASM_FSP2_API_H +#define __ASM_FSP2_API_H + +#include <asm/fsp/fsp_api.h> + +struct fspm_upd; +struct fsps_upd; +struct hob_header; + +enum fsp_boot_mode { + FSP_BOOT_WITH_FULL_CONFIGURATION = 0x00, + FSP_BOOT_WITH_MINIMAL_CONFIGURATION = 0x01, + FSP_BOOT_ASSUMING_NO_CONFIGURATION_CHANGES = 0x02, + FSP_BOOT_ON_S4_RESUME = 0x05, + FSP_BOOT_ON_S3_RESUME = 0x11, + FSP_BOOT_ON_FLASH_UPDATE = 0x12, + FSP_BOOT_IN_RECOVERY_MODE = 0x20 +}; + +struct __packed fsp_upd_header { + u64 signature; + u8 revision; + u8 reserved[23]; +}; + +/** + * fsp_memory_init() - Init the SDRAM + * + * @s3wake: true if we are booting from resume, so cannot reinit the mememory + * from scatch since we will lose its contents + * @use_spi_flash: true to use the fast SPI driver to read FSP, otherwise use + * mapped SPI + * @return 0 if OK, -ve on error + */ +int fsp_memory_init(bool s3wake, bool use_spi_flash); + +typedef asmlinkage int (*fsp_memory_init_func)(struct fspm_upd *params, + struct hob_header **hobp); + +/** + * fsp_silicon_init() - Init the silicon + * + * This calls the FSP's 'silicon init' entry point + * + * @s3wake: true if we are booting from resume, so cannot reinit the mememory + * from scatch since we will lose its contents + * @use_spi_flash: true to use the fast SPI driver to read FSP, otherwise use + * mapped SPI + * @return 0 if OK, -ve on error + */ +int fsp_silicon_init(bool s3wake, bool use_spi_flash); + +typedef asmlinkage int (*fsp_silicon_init_func)(struct fsps_upd *params); + +#endif diff --git a/arch/x86/include/asm/fsp2/fsp_internal.h b/arch/x86/include/asm/fsp2/fsp_internal.h new file mode 100644 index 0000000000..f751fbf961 --- /dev/null +++ b/arch/x86/include/asm/fsp2/fsp_internal.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.) + * Mostly taken from coreboot + */ + +#ifndef __ASM_FSP_INTERNAL_H +#define __ASM_FSP_INTERNAL_H + +struct binman_entry; +struct fsp_header; +struct fspm_upd; +struct fsps_upd; + +enum fsp_type_t { + FSP_M, + FSP_S, +}; + +int fsp_get_header(ulong offset, ulong size, bool use_spi_flash, + struct fsp_header **fspp); + +/** + * fsp_locate_fsp() - Locate an FSP component + * + * This finds an FSP component by various methods. It is not as general-purpose + * as it looks, since it expects FSP-M to be requested in SPL (only), and FSP-S + * to be requested in U-Boot proper. + * + * @type: Component to locate + * @entry: Returns location of component + * @use_spi_flash: true to read using the Fast SPI driver, false to use + * memory-mapped SPI flash + * @devp: Returns northbridge device + * @hdrp: Returns FSP header + * @rom_offsetp: If non-NULL, returns the offset to add to any image position to + * find the memory-mapped location of that position. For example, for ROM + * position 0x1000, it will be mapped into 0x1000 + *rom_offsetp. + */ +int fsp_locate_fsp(enum fsp_type_t type, struct binman_entry *entry, + bool use_spi_flash, struct udevice **devp, + struct fsp_header **hdrp, ulong *rom_offsetp); + +/** + * arch_fsps_preinit() - Perform init needed before calling FSP-S + * + * This allows use of probed drivers and PCI so is a convenient place to do any + * init that is needed before FSP-S is called. After this, U-Boot relocates and + * calls arch_fsp_init_r() before PCI is probed, and that function is not + * allowed to probe PCI before calling FSP-S. + */ +int arch_fsps_preinit(void); + +/** + * fspm_update_config() - Set up the config structure for FSP-M + * + * @dev: Hostbridge device containing config + * @upd: Config data to fill in + * @return 0 if OK, -ve on error + */ +int fspm_update_config(struct udevice *dev, struct fspm_upd *upd); + +/** + * fspm_done() - Indicate that memory init is complete + * + * This allows the board to do whatever post-init it needs before things + * continue. + * + * @dev: Hostbridge device + * @return 0 if OK, -ve on error + */ +int fspm_done(struct udevice *dev); + +/** + * fsps_update_config() - Set up the config structure for FSP-S + * + * @dev: Hostbridge device containing config + * @rom_offset: Value to add to convert from ROM offset to memory-mapped address + * @upd: Config data to fill in + * @return 0 if OK, -ve on error + */ +int fsps_update_config(struct udevice *dev, ulong rom_offset, + struct fsps_upd *upd); + +/** + * prepare_mrc_cache() - Read the MRC cache into the product-data struct + * + * This looks for cached Memory-reference code (MRC) data and stores it into + * @upd for use by the FSP-M binary. + * + * @return 0 if OK, -ENOENT if no data (whereupon the caller can continue and + * expect a slower boot), other -ve value on other error + */ +int prepare_mrc_cache(struct fspm_upd *upd); + +#endif diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 7f3ada06f6..f4c1839104 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -10,6 +10,7 @@ #ifndef __ASSEMBLY__ #include <asm/processor.h> +#include <asm/mrccache.h> enum pei_boot_mode_t { PEI_BOOT_NONE = 0, @@ -66,6 +67,21 @@ struct mtrr_request { uint64_t size; }; +/** + * struct mrc_output - holds the MRC data + * + * @buf: MRC training data to save for the next boot. This is set to point to + * the raw data after SDRAM init is complete. Then mrccache_setup() + * turns it into a proper cache record with a checksum + * @len: Length of @buf + * @cache: Resulting cache record + */ +struct mrc_output { + char *buf; + uint len; + struct mrc_data_container *cache; +}; + /* Architecture-specific global data */ struct arch_global_data { u64 gdt[X86_GDT_NUM_ENTRIES] __aligned(16); @@ -90,12 +106,12 @@ struct arch_global_data { struct mtrr_request mtrr_req[MAX_MTRR_REQUESTS]; int mtrr_req_count; int has_mtrr; - /* MRC training data to save for the next boot */ - char *mrc_output; - unsigned int mrc_output_len; + /* MRC training data */ + struct mrc_output mrc[MRC_TYPE_COUNT]; ulong table; /* Table pointer from previous loader */ int turbo_state; /* Current turbo state */ struct irq_routing_table *pirq_routing_table; + int dw_i2c_num_cards; /* Used by designware i2c driver */ #ifdef CONFIG_SEABIOS u32 high_table_ptr; u32 high_table_limit; @@ -104,6 +120,9 @@ struct arch_global_data { int prev_sleep_state; /* Previous sleep state ACPI_S0/1../5 */ ulong backup_mem; /* Backup memory address for S3 */ #endif +#ifdef CONFIG_FSP_VERSION2 + struct fsp_header *fsp_s_hdr; /* Pointer to FSP-S header */ +#endif }; #endif diff --git a/arch/x86/include/asm/intel_pinctrl.h b/arch/x86/include/asm/intel_pinctrl.h new file mode 100644 index 0000000000..72fd9246cb --- /dev/null +++ b/arch/x86/include/asm/intel_pinctrl.h @@ -0,0 +1,306 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 Intel Corporation. + * Copyright 2019 Google LLC + * + * Modified from coreboot gpio.h + */ + +#ifndef __ASM_INTEL_PINCTRL_H +#define __ASM_INTEL_PINCTRL_H + +#include <dm/pinctrl.h> + +/** + * struct pad_config - config for a pad + * @pad: offset of pad within community + * @pad_config: Pad config data corresponding to DW0, DW1, etc. + */ +struct pad_config { + int pad; + u32 pad_config[4]; +}; + +#include <asm/arch/gpio.h> + +/* GPIO community IOSF sideband clock gating */ +#define MISCCFG_GPSIDEDPCGEN BIT(5) +/* GPIO community RCOMP clock gating */ +#define MISCCFG_GPRCOMPCDLCGEN BIT(4) +/* GPIO community RTC clock gating */ +#define MISCCFG_GPRTCDLCGEN BIT(3) +/* GFX controller clock gating */ +#define MISCCFG_GSXSLCGEN BIT(2) +/* GPIO community partition clock gating */ +#define MISCCFG_GPDPCGEN BIT(1) +/* GPIO community local clock gating */ +#define MISCCFG_GPDLCGEN BIT(0) +/* Enable GPIO community power management configuration */ +#define MISCCFG_ENABLE_GPIO_PM_CONFIG (MISCCFG_GPSIDEDPCGEN | \ + MISCCFG_GPRCOMPCDLCGEN | MISCCFG_GPRTCDLCGEN | MISCCFG_GSXSLCGEN \ + | MISCCFG_GPDPCGEN | MISCCFG_GPDLCGEN) + +/* + * GPIO numbers may not be contiguous and instead will have a different + * starting pin number for each pad group. + */ +#define INTEL_GPP_BASE(first_of_community, start_of_group, end_of_group,\ + group_pad_base) \ + { \ + .first_pad = (start_of_group) - (first_of_community), \ + .size = (end_of_group) - (start_of_group) + 1, \ + .acpi_pad_base = (group_pad_base), \ + } + +/* + * A pad base of -1 indicates that this group uses contiguous numbering + * and a pad base should not be used for this group. + */ +#define PAD_BASE_NONE -1 + +/* The common/default group numbering is contiguous */ +#define INTEL_GPP(first_of_community, start_of_group, end_of_group) \ + INTEL_GPP_BASE(first_of_community, start_of_group, end_of_group,\ + PAD_BASE_NONE) + +/** + * struct reset_mapping - logical to actual value for PADRSTCFG in DW0 + * + * Note that the values are expected to be within the field placement of the + * register itself. i.e. if the reset field is at 31:30 then the values within + * logical and chipset should occupy 31:30. + */ +struct reset_mapping { + u32 logical; + u32 chipset; +}; + +/** + * struct pad_group - describes the groups within each community + * + * @first_pad: offset of first pad of the group relative to the community + * @size: size of the group + * @acpi_pad_base: starting pin number for the pads in this group when they are + * used in ACPI. This is only needed if the pins are not contiguous across + * groups. Most groups will have this set to PAD_BASE_NONE and use + * contiguous numbering for ACPI. + */ +struct pad_group { + int first_pad; + uint size; + int acpi_pad_base; +}; + +/** + * struct pad_community - community of pads + * + * This describes a community, or each group within a community when multiple + * groups exist inside a community + * + * @name: Community name + * @acpi_path: ACPI path + * @num_gpi_regs: number of gpi registers in community + * @max_pads_per_group: number of pads in each group; number of pads bit-mapped + * in each GPI status/en and Host Own Reg + * @first_pad: first pad in community + * @last_pad: last pad in community + * @host_own_reg_0: offset to Host Ownership Reg 0 + * @gpi_int_sts_reg_0: offset to GPI Int STS Reg 0 + * @gpi_int_en_reg_0: offset to GPI Int Enable Reg 0 + * @gpi_smi_sts_reg_0: offset to GPI SMI STS Reg 0 + * @gpi_smi_en_reg_0: offset to GPI SMI EN Reg 0 + * @pad_cfg_base: offset to first PAD_GFG_DW0 Reg + * @gpi_status_offset: specifies offset in struct gpi_status + * @port: PCR Port ID + * @reset_map: PADRSTCFG logical to chipset mapping + * @num_reset_vals: number of values in @reset_map + * @groups; list of groups for this community + * @num_groups: number of groups + */ +struct pad_community { + const char *name; + const char *acpi_path; + size_t num_gpi_regs; + size_t max_pads_per_group; + uint first_pad; + uint last_pad; + u16 host_own_reg_0; + u16 gpi_int_sts_reg_0; + u16 gpi_int_en_reg_0; + u16 gpi_smi_sts_reg_0; + u16 gpi_smi_en_reg_0; + u16 pad_cfg_base; + u8 gpi_status_offset; + u8 port; + const struct reset_mapping *reset_map; + size_t num_reset_vals; + const struct pad_group *groups; + size_t num_groups; +}; + +/** + * struct intel_pinctrl_priv - private data for each pinctrl device + * + * @comm: Pad community for this device + * @num_cfgs: Number of configuration words for each pad + * @itss: ITSS device (for interrupt handling) + * @itss_pol_cfg: Use to program Interrupt Polarity Control (IPCx) register + * Each bit represents IRQx Active High Polarity Disable configuration: + * when set to 1, the interrupt polarity associated with IRQx is inverted + * to appear as Active Low to IOAPIC and vice versa + */ +struct intel_pinctrl_priv { + const struct pad_community *comm; + int num_cfgs; + struct udevice *itss; + bool itss_pol_cfg; +}; + +/* Exported common operations for the pinctrl driver */ +extern const struct pinctrl_ops intel_pinctrl_ops; + +/* Exported common probe function for the pinctrl driver */ +int intel_pinctrl_probe(struct udevice *dev); + +/** + * intel_pinctrl_ofdata_to_platdata() - Handle common platdata setup + * + * @dev: Pinctrl device + * @comm: Pad community for this device + * @num_cfgs: Number of configuration words for each pad + * @return 0 if OK, -EDOM if @comm is NULL, other -ve value on other error + */ +int intel_pinctrl_ofdata_to_platdata(struct udevice *dev, + const struct pad_community *comm, + int num_cfgs); + +/** + * pinctrl_route_gpe() - set GPIO groups for the general-purpose-event blocks + * + * The values from PMC register GPE_CFG are passed which is then mapped to + * proper groups for MISCCFG. This basically sets the MISCCFG register bits: + * dw0 = gpe0_route[11:8]. This is ACPI GPE0b. + * dw1 = gpe0_route[15:12]. This is ACPI GPE0c. + * dw2 = gpe0_route[19:16]. This is ACPI GPE0d. + * + * @dev: ITSS device + * @gpe0b: Value for GPE0B + * @gpe0c: Value for GPE0C + * @gpe0d: Value for GPE0D + * @return 0 if OK, -ve on error + */ +int pinctrl_route_gpe(struct udevice *dev, uint gpe0b, uint gpe0c, uint gpe0d); + +/** + * pinctrl_config_pads() - Configure a list of pads + * + * Configures multiple pads using the provided data from the device tree. + * + * @dev: pinctrl device (any will do) + * @pads: Pad data, consisting of a pad number followed by num_cfgs entries + * containing the data for that pad (num_cfgs is set by the pinctrl device) + * @pads_count: Number of pads to configure + * @return 0 if OK, -ve on error + */ +int pinctrl_config_pads(struct udevice *dev, u32 *pads, int pads_count); + +/** + * pinctrl_gpi_clear_int_cfg() - Set up the interrupts for use + * + * This enables the interrupt inputs and clears the status register bits + * + * @return 0 if OK, -ve on error + */ +int pinctrl_gpi_clear_int_cfg(void); + +/** + * pinctrl_config_pads_for_node() - Configure pads + * + * Set up the pads using the data in a given node + * + * @dev: pinctrl device (any will do) + * @node: Node containing the 'pads' property with the data in it + * @return 0 if OK, -ve on error + */ +int pinctrl_config_pads_for_node(struct udevice *dev, ofnode node); + +/** + * pinctrl_read_pads() - Read pad data from a node + * + * @dev: pinctrl device (any will do, it is just used to get config) + * @node: Node to read pad data from + * @prop: Property name to use (e.g. "pads") + * @padsp: Returns a pointer to an allocated array of pad data, in the format: + * <pad> + * <pad_config0> + * <pad_config1> + * ... + * + * The number of pad config values is set by the pinctrl controller. + * The caller must free this array. + * @pad_countp: Returns the number of pads read + * @ereturn 0 if OK, -ve on error + */ +int pinctrl_read_pads(struct udevice *dev, ofnode node, const char *prop, + u32 **padsp, int *pad_countp); + +/** + * pinctrl_count_pads() - Count the number of pads in a pad array + * + * This used used with of-platdata where the array may be smaller than its + * maximum size. This function searches for the last pad in the array by finding + * the first 'zero' record + * + * This works out the number of records in the array. Each record has one word + * for the pad and num_cfgs words for the config. + * + * @dev: pinctrl device (any will do) + * @pads: Array of pad data + * @size: Size of pad data in bytes + * @return number of pads represented by the data + */ +int pinctrl_count_pads(struct udevice *dev, u32 *pads, int size); + +/** + * intel_pinctrl_get_config_reg_addr() - Get address of the pin config registers + * + * @dev: Pinctrl device + * @offset: GPIO offset within this device + * @return register offset within the GPIO p2sb region + */ +u32 intel_pinctrl_get_config_reg_addr(struct udevice *dev, uint offset); + +/** + * intel_pinctrl_get_config_reg() - Get the value of a GPIO register + * + * @dev: Pinctrl device + * @offset: GPIO offset within this device + * @return register value within the GPIO p2sb region + */ +u32 intel_pinctrl_get_config_reg(struct udevice *dev, uint offset); + +/** + * intel_pinctrl_get_pad() - Get pad information for a pad + * + * This is used by the GPIO controller to find the pinctrl used by a pad. + * + * @pad: Pad to check + * @devp: Returns pinctrl device containing that pad + * @offsetp: Returns offset of pad within that pinctrl device + */ +int intel_pinctrl_get_pad(uint pad, struct udevice **devp, uint *offsetp); + +/** + * intel_pinctrl_get_acpi_pin() - Get the ACPI pin for a pinctrl pin + * + * Maps a pinctrl pin (in terms of its offset within the pins controlled by that + * pinctrl) to an ACPI GPIO pin-table entry. + * + * @dev: Pinctrl device to check + * @offset: Offset of pin within that device (0 = first) + * @return associated ACPI GPIO pin-table entry, or standard pin number if the + * ACPI pad base is not set + */ +int intel_pinctrl_get_acpi_pin(struct udevice *dev, uint offset); + +#endif diff --git a/arch/x86/include/asm/intel_pinctrl_defs.h b/arch/x86/include/asm/intel_pinctrl_defs.h new file mode 100644 index 0000000000..6da06bb52b --- /dev/null +++ b/arch/x86/include/asm/intel_pinctrl_defs.h @@ -0,0 +1,373 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015-2016 Intel Corp. + * Copyright 2019 Google LLC + * + * Modified from coreboot gpio_defs.h + */ + +#ifndef _ASM_INTEL_PINCTRL_DEFS_H_ +#define _ASM_INTEL_PINCTRL_DEFS_H_ + +/* This file is included by device trees, so avoid BIT() macros */ + +#define PAD_CFG0_TX_STATE_BIT 0 +#define PAD_CFG0_TX_STATE (1 << PAD_CFG0_TX_STATE_BIT) +#define PAD_CFG0_RX_STATE_BIT 1 +#define PAD_CFG0_RX_STATE (1 << PAD_CFG0_RX_STATE_BIT) +#define PAD_CFG0_TX_DISABLE (1 << 8) +#define PAD_CFG0_RX_DISABLE (1 << 9) + +#define PAD_CFG0_MODE_SHIFT 10 +#define PAD_CFG0_MODE_MASK (7 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_GPIO (0 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF1 (1 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF2 (2 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF3 (3 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF4 (4 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF5 (5 << PAD_CFG0_MODE_SHIFT) +#define PAD_CFG0_MODE_NF6 (6 << PAD_CFG0_MODE_SHIFT) + +#define PAD_CFG0_ROUTE_MASK (0xf << 17) +#define PAD_CFG0_ROUTE_NMI (1 << 17) +#define PAD_CFG0_ROUTE_SMI (1 << 18) +#define PAD_CFG0_ROUTE_SCI (1 << 19) +#define PAD_CFG0_ROUTE_IOAPIC (1 << 20) +#define PAD_CFG0_RXTENCFG_MASK (3 << 21) +#define PAD_CFG0_RXINV_MASK (1 << 23) +#define PAD_CFG0_RX_POL_INVERT (1 << 23) +#define PAD_CFG0_RX_POL_NONE (0 << 23) +#define PAD_CFG0_PREGFRXSEL (1 << 24) +#define PAD_CFG0_TRIG_MASK (3 << 25) +#define PAD_CFG0_TRIG_LEVEL (0 << 25) +#define PAD_CFG0_TRIG_EDGE_SINGLE (1 << 25) /* controlled by RX_INVERT*/ +#define PAD_CFG0_TRIG_OFF (2 << 25) +#define PAD_CFG0_TRIG_EDGE_BOTH (3 << 25) +#define PAD_CFG0_RXRAW1_MASK (1 << 28) +#define PAD_CFG0_RXPADSTSEL_MASK (1 << 29) +#define PAD_CFG0_RESET_MASK (3 << 30) +#define PAD_CFG0_LOGICAL_RESET_PWROK (0U << 30) +#define PAD_CFG0_LOGICAL_RESET_DEEP (1U << 30) +#define PAD_CFG0_LOGICAL_RESET_PLTRST (2U << 30) +#define PAD_CFG0_LOGICAL_RESET_RSMRST (3U << 30) + +/* + * Use the fourth bit in IntSel field to indicate gpio ownership. This field is + * RO and hence not used during gpio configuration. + */ +#define PAD_CFG1_GPIO_DRIVER (0x1 << 4) +#define PAD_CFG1_IRQ_MASK (0xff << 0) +#define PAD_CFG1_IOSTERM_MASK (0x3 << 8) +#define PAD_CFG1_IOSTERM_SAME (0x0 << 8) +#define PAD_CFG1_IOSTERM_DISPUPD (0x1 << 8) +#define PAD_CFG1_IOSTERM_ENPD (0x2 << 8) +#define PAD_CFG1_IOSTERM_ENPU (0x3 << 8) +#define PAD_CFG1_PULL_MASK (0xf << 10) +#define PAD_CFG1_PULL_NONE (0x0 << 10) +#define PAD_CFG1_PULL_DN_5K (0x2 << 10) +#define PAD_CFG1_PULL_DN_20K (0x4 << 10) +#define PAD_CFG1_PULL_UP_1K (0x9 << 10) +#define PAD_CFG1_PULL_UP_5K (0xa << 10) +#define PAD_CFG1_PULL_UP_2K (0xb << 10) +#define PAD_CFG1_PULL_UP_20K (0xc << 10) +#define PAD_CFG1_PULL_UP_667 (0xd << 10) +#define PAD_CFG1_PULL_NATIVE (0xf << 10) + +/* Tx enabled driving last value driven, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TX_LAST_RXE (0x0 << 14) +/* + * Tx enabled driving 0, Rx disabled and Rx driving 0 back to its controller + * internally + */ +#define PAD_CFG1_IOSSTATE_TX0_RX_DCR_X0 (0x1 << 14) +/* + * Tx enabled driving 0, Rx disabled and Rx driving 1 back to its controller + * internally + */ +#define PAD_CFG1_IOSSTATE_TX0_RX_DCR_X1 (0x2 << 14) +/* + * Tx enabled driving 1, Rx disabled and Rx driving 0 back to its controller + * internally + */ +#define PAD_CFG1_IOSSTATE_TX1_RX_DCR_X0 (0x3 << 14) +/* + * Tx enabled driving 1, Rx disabled and Rx driving 1 back to its controller + * internally + */ +#define PAD_CFG1_IOSSTATE_TX1_RX_DCR_X1 (0x4 << 14) +/* Tx enabled driving 0, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TX0_RXE (0x5 << 14) +/* Tx enabled driving 1, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TX1_RXE (0x6 << 14) +/* Hi-Z, Rx driving 0 back to its controller internally */ +#define PAD_CFG1_IOSSTATE_HIZCRX0 (0x7 << 14) +/* Hi-Z, Rx driving 1 back to its controller internally */ +#define PAD_CFG1_IOSSTATE_HIZCRX1 (0x8 << 14) +/* Tx disabled, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TXD_RXE (0x9 << 14) +#define PAD_CFG1_IOSSTATE_IGNORE (0xf << 14) /* Ignore Iostandby */ +/* mask to extract Iostandby bits */ +#define PAD_CFG1_IOSSTATE_MASK (0xf << 14) +#define PAD_CFG1_IOSSTATE_SHIFT 14 /* set Iostandby bits [17:14] */ + +#define PAD_CFG2_DEBEN 1 +/* Debounce Duration = (2 ^ PAD_CFG2_DEBOUNCE_x_RTC) * RTC clock duration */ +#define PAD_CFG2_DEBOUNCE_8_RTC (0x3 << 1) +#define PAD_CFG2_DEBOUNCE_16_RTC (0x4 << 1) +#define PAD_CFG2_DEBOUNCE_32_RTC (0x5 << 1) +#define PAD_CFG2_DEBOUNCE_64_RTC (0x6 << 1) +#define PAD_CFG2_DEBOUNCE_128_RTC (0x7 << 1) +#define PAD_CFG2_DEBOUNCE_256_RTC (0x8 << 1) +#define PAD_CFG2_DEBOUNCE_512_RTC (0x9 << 1) +#define PAD_CFG2_DEBOUNCE_1K_RTC (0xa << 1) +#define PAD_CFG2_DEBOUNCE_2K_RTC (0xb << 1) +#define PAD_CFG2_DEBOUNCE_4K_RTC (0xc << 1) +#define PAD_CFG2_DEBOUNCE_8K_RTC (0xd << 1) +#define PAD_CFG2_DEBOUNCE_16K_RTC (0xe << 1) +#define PAD_CFG2_DEBOUNCE_32K_RTC (0xf << 1) +#define PAD_CFG2_DEBOUNCE_MASK 0x1f + +/* voltage tolerance 0=3.3V default 1=1.8V tolerant */ +#if IS_ENABLED(INTEL_PINCTRL_IOSTANDBY) +#define PAD_CFG1_TOL_MASK (0x1 << 25) +#define PAD_CFG1_TOL_1V8 (0x1 << 25) +#endif + +#define PAD_FUNC(value) PAD_CFG0_MODE_##value +#define PAD_RESET(value) PAD_CFG0_LOGICAL_RESET_##value +#define PAD_PULL(value) PAD_CFG1_PULL_##value + +#define PAD_IOSSTATE(value) PAD_CFG1_IOSSTATE_##value +#define PAD_IOSTERM(value) PAD_CFG1_IOSTERM_##value + +#define PAD_IRQ_CFG(route, trig, inv) \ + (PAD_CFG0_ROUTE_##route | \ + PAD_CFG0_TRIG_##trig | \ + PAD_CFG0_RX_POL_##inv) + +#if IS_ENABLED(INTEL_PINCTRL_DUAL_ROUTE_SUPPORT) +#define PAD_IRQ_CFG_DUAL_ROUTE(route1, route2, trig, inv) \ + (PAD_CFG0_ROUTE_##route1 | \ + PAD_CFG0_ROUTE_##route2 | \ + PAD_CFG0_TRIG_##trig | \ + PAD_CFG0_RX_POL_##inv) +#endif /* CONFIG_INTEL_PINCTRL_DUAL_ROUTE_SUPPORT */ + +#define _PAD_CFG_STRUCT(__pad, __config0, __config1) \ + __pad(__config0) (__config1) + +/* Native function configuration */ +#define PAD_CFG_NF(pad, pull, rst, func) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(TX_LAST_RXE)) + +#if IS_ENABLED(CONFIG_INTEL_GPIO_PADCFG_PADTOL) +/* + * Native 1.8V tolerant pad, only applies to some pads like I2C/I2S. Not + * applicable to all SOCs. Refer EDS. + */ +#define PAD_CFG_NF_1V8(pad, pull, rst, func) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) |\ + PAD_IOSSTATE(TX_LAST_RXE) | PAD_CFG1_TOL_1V8) +#endif + +/* Native function configuration for standby state */ +#define PAD_CFG_NF_IOSSTATE(pad, pull, rst, func, iosstate) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate)) + +/* + * Native function configuration for standby state, also configuring iostandby + * as masked + */ +#define PAD_CFG_NF_IOSTANDBY_IGNORE(pad, pull, rst, func) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(IGNORE)) + +/* + * Native function configuration for standby state, also configuring iosstate + * and iosterm + */ +#define PAD_CFG_NF_IOSSTATE_IOSTERM(pad, pull, rst, func, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +/* General purpose output, no pullup/down */ +#define PAD_CFG_GPO(pad, val, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(NONE) | PAD_IOSSTATE(TX_LAST_RXE)) + +/* General purpose output, with termination specified */ +#define PAD_CFG_TERM_GPO(pad, val, pull, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(pull) | PAD_IOSSTATE(TX_LAST_RXE)) + +/* General purpose output, no pullup/down */ +#define PAD_CFG_GPO_GPIO_DRIVER(pad, val, rst, pull) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(pull) | PAD_IOSSTATE(TX_LAST_RXE) | \ + PAD_CFG1_GPIO_DRIVER) + +/* General purpose output */ +#define PAD_CFG_GPO_IOSSTATE_IOSTERM(pad, val, rst, pull, iosstate, ioterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(pull) | PAD_IOSSTATE(iosstate) | PAD_IOSTERM(ioterm)) + +/* General purpose input */ +#define PAD_CFG_GPI(pad, pull, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE, \ + PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input. The following macro sets the + * Host Software Pad Ownership to GPIO Driver mode. + */ +#define PAD_CFG_GPI_GPIO_DRIVER(pad, pull, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE, \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE)) + +#define PAD_CFG_GPIO_DRIVER_HI_Z(pad, pull, rst, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_CFG0_RX_DISABLE, \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +#define PAD_CFG_GPIO_HI_Z(pad, pull, rst, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_CFG0_RX_DISABLE, PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +/* GPIO Interrupt */ +#define PAD_CFG_GPI_INT(pad, pull, rst, trig) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_CFG0_TRIG_##trig | PAD_CFG0_RX_POL_NONE, \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE)) + +/* + * No Connect configuration for unused pad. + * Both TX and RX are disabled. RX disabling is done to avoid unnecessary + * setting of GPI_STS. + */ +#define PAD_NC(pad, pull) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(DEEP) | \ + PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE, \ + PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input, routed to APIC */ +#define PAD_CFG_GPI_APIC(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(IOAPIC, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input, routed to APIC - with IOStandby Config*/ +#define PAD_CFG_GPI_APIC_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(IOAPIC, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +/* + * The following APIC macros assume the APIC will handle the filtering + * on its own end. One just needs to pass an active high message into the + * ITSS. + */ +#define PAD_CFG_GPI_APIC_LOW(pad, pull, rst) \ + PAD_CFG_GPI_APIC(pad, pull, rst, LEVEL, INVERT) + +#define PAD_CFG_GPI_APIC_HIGH(pad, pull, rst) \ + PAD_CFG_GPI_APIC(pad, pull, rst, LEVEL, NONE) + +#define PAD_CFG_GPI_APIC_EDGE_LOW(pad, pull, rst) \ + PAD_CFG_GPI_APIC(pad, pull, rst, EDGE_SINGLE, INVERT) + +/* General purpose input, routed to SMI */ +#define PAD_CFG_GPI_SMI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SMI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input, routed to SMI */ +#define PAD_CFG_GPI_SMI_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SMI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +#define PAD_CFG_GPI_SMI_LOW(pad, pull, rst, trig) \ + PAD_CFG_GPI_SMI(pad, pull, rst, trig, INVERT) + +#define PAD_CFG_GPI_SMI_HIGH(pad, pull, rst, trig) \ + PAD_CFG_GPI_SMI(pad, pull, rst, trig, NONE) + +/* General purpose input, routed to SCI */ +#define PAD_CFG_GPI_SCI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE)) + +/* General purpose input, routed to SCI */ +#define PAD_CFG_GPI_SCI_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm)) + +#define PAD_CFG_GPI_SCI_LOW(pad, pull, rst, trig) \ + PAD_CFG_GPI_SCI(pad, pull, rst, trig, INVERT) + +#define PAD_CFG_GPI_SCI_HIGH(pad, pull, rst, trig) \ + PAD_CFG_GPI_SCI(pad, pull, rst, trig, NONE) + +#define PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, inv, dur) \ + _PAD_CFG_STRUCT_3(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE), PAD_CFG2_DEBEN | PAD_CFG2_##dur) + +#define PAD_CFG_GPI_SCI_LOW_DEBEN(pad, pull, rst, trig, dur) \ + PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, INVERT, dur) + +#define PAD_CFG_GPI_SCI_HIGH_DEBEN(pad, pull, rst, trig, dur) \ + PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, NONE, dur) + +/* General purpose input, routed to NMI */ +#define PAD_CFG_GPI_NMI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(NMI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TXD_RXE)) + +#if IS_ENABLED(INTEL_PINCTRL_DUAL_ROUTE_SUPPORT) +/* GPI, GPIO Driver, SCI interrupt */ +#define PAD_CFG_GPI_GPIO_DRIVER_SCI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE)) + +#define PAD_CFG_GPI_DUAL_ROUTE(pad, pull, rst, trig, inv, route1, route2) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG_DUAL_ROUTE(route1, route2, trig, inv), \ + PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE)) + +#define PAD_CFG_GPI_IRQ_WAKE(pad, pull, rst, trig, inv) \ + PAD_CFG_GPI_DUAL_ROUTE(pad, pull, rst, trig, inv, IOAPIC, SCI) + +#endif /* CONFIG_INTEL_PINCTRL_DUAL_ROUTE_SUPPORT */ + +#endif /* _ASM_INTEL_PINCTRL_DEFS_H_ */ diff --git a/arch/x86/include/asm/lpss.h b/arch/x86/include/asm/lpss.h new file mode 100644 index 0000000000..7814872688 --- /dev/null +++ b/arch/x86/include/asm/lpss.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __ASM_LPSS_H +#define __ASM_LPSS_H + +struct udevice; + +/* D0 and D3 enable config */ +enum lpss_pwr_state { + STATE_D0 = 0, + STATE_D3 = 3 +}; + +/** + * lpss_reset_release() - Release device from reset + * + * This is used for devices which have LPSS support. + * + * @regs: Pointer to device registers + */ +void lpss_reset_release(void *regs); + +/** + * lpss_set_power_state() - Change power state of a device + * + * This is used for devices which have LPSS support. + * + * @dev: Device to update + * @state: New power state to set + */ +void lpss_set_power_state(struct udevice *dev, enum lpss_pwr_state state); + +#endif diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index 40fda856ff..d6b7529073 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -7,7 +7,7 @@ #ifndef _ASM_MRCCACHE_H #define _ASM_MRCCACHE_H -#define MRC_DATA_ALIGN 0x1000 +#define MRC_DATA_ALIGN 0x100 #define MRC_DATA_SIGNATURE (('M' << 0) | ('R' << 8) | \ ('C' << 16) | ('D'<<24)) @@ -27,6 +27,14 @@ struct mrc_region { u32 length; }; +/* Types of MRC data */ +enum mrc_type_t { + MRC_TYPE_NORMAL, + MRC_TYPE_VAR, + + MRC_TYPE_COUNT, +}; + struct udevice; /** @@ -41,21 +49,6 @@ struct udevice; struct mrc_data_container *mrccache_find_current(struct mrc_region *entry); /** - * mrccache_update() - update the MRC cache with a new record - * - * This writes a new record to the end of the MRC cache region. If the new - * record is the same as the latest record then the write is skipped - * - * @sf: SPI flash to write to - * @entry: Position and size of MRC cache in SPI flash - * @cur: Record to write - * @return 0 if updated, -EEXIST if the record is the same as the latest - * record, -EINVAL if the record is not valid, other error if SPI write failed - */ -int mrccache_update(struct udevice *sf, struct mrc_region *entry, - struct mrc_data_container *cur); - -/** * mrccache_reserve() - reserve MRC data on the stack * * This copies MRC data pointed by gd->arch.mrc_output to a new place on the @@ -84,6 +77,7 @@ int mrccache_reserve(void); * triggers PCI bus enumeration during which insufficient memory issue * might be exposed and it causes subsequent SPI flash probe fails). * + * @type: Type of MRC data to use * @devp: Returns pointer to the SPI flash device * @entry: Position and size of MRC cache in SPI flash * @return 0 if success, -ENOENT if SPI flash node does not exist in the @@ -91,7 +85,8 @@ int mrccache_reserve(void); * tree, -EINVAL if MRC region properties format is incorrect, other error * if SPI flash probe failed. */ -int mrccache_get_region(struct udevice **devp, struct mrc_region *entry); +int mrccache_get_region(enum mrc_type_t type, struct udevice **devp, + struct mrc_region *entry); /** * mrccache_save() - save MRC data to the SPI flash diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 5bc8b6c22c..246c14f815 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -70,6 +70,7 @@ #define MSR_IA32_BBL_CR_CTL 0x00000119 #define MSR_IA32_BBL_CR_CTL3 0x0000011e #define MSR_POWER_MISC 0x00000120 +#define FLUSH_DL1_L2 (1 << 8) #define ENABLE_ULFM_AUTOCM_MASK (1 << 2) #define ENABLE_INDP_AUTOCM_MASK (1 << 3) @@ -241,10 +242,17 @@ #define PKG_POWER_LIMIT_CLAMP (1 << 16) #define PKG_POWER_LIMIT_TIME_SHIFT 17 #define PKG_POWER_LIMIT_TIME_MASK 0x7f +/* + * For Mobile, RAPL default PL1 time window value set to 28 seconds. + * RAPL time window calculation defined as follows: + * Time Window = (float)((1+X/4)*(2*^Y), X Corresponds to [23:22], + * Y to [21:17] in MSR 0x610. 28 sec is equal to 0x6e. + */ +#define MB_POWER_LIMIT1_TIME_DEFAULT 0x6e #define MSR_PKG_ENERGY_STATUS 0x00000611 #define MSR_PKG_PERF_STATUS 0x00000613 -#define MSR_PKG_POWER_INFO 0x00000614 +#define MSR_PKG_POWER_SKU 0x614 #define MSR_DRAM_POWER_LIMIT 0x00000618 #define MSR_DRAM_ENERGY_STATUS 0x00000619 diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index f1d9977bcb..d7b6836786 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -25,8 +25,6 @@ /* Length of the public header on Intel microcode blobs */ #define UCODE_HEADER_LEN 0x30 -#ifndef __ASSEMBLY__ - /* * This register is documented in (for example) the Intel Atom Processor E3800 * Product Family Datasheet in "PCU - Power Management Controller (PMC)". @@ -37,11 +35,11 @@ */ #define IO_PORT_RESET 0xcf9 -enum { - SYS_RST = 1 << 1, /* 0 for soft reset, 1 for hard reset */ - RST_CPU = 1 << 2, /* initiate reset */ - FULL_RST = 1 << 3, /* full power cycle */ -}; +#define SYS_RST (1 << 1) /* 0 for soft reset, 1 for hard reset */ +#define RST_CPU (1 << 2) /* initiate reset */ +#define FULL_RST (1 << 3) /* full power cycle */ + +#ifndef __ASSEMBLY__ static inline __attribute__((always_inline)) void cpu_hlt(void) { diff --git a/arch/x86/include/asm/spl.h b/arch/x86/include/asm/spl.h index 1bef4877eb..cc6cac08f2 100644 --- a/arch/x86/include/asm/spl.h +++ b/arch/x86/include/asm/spl.h @@ -11,6 +11,7 @@ enum { BOOT_DEVICE_SPI_MMAP = 10, + BOOT_DEVICE_FAST_SPI, BOOT_DEVICE_CROS_VBOOT, }; diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index ca0ca1066b..5cd4587480 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -4,9 +4,11 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. ifndef CONFIG_X86_64 +ifndef CONFIG_TPL_BUILD obj-y += bios.o obj-y += bios_asm.o obj-y += bios_interrupts.o +endif obj-y += string.o endif ifndef CONFIG_SPL_BUILD diff --git a/arch/x86/lib/fsp/Makefile b/arch/x86/lib/fsp/Makefile index 9e34856473..da6c0a886a 100644 --- a/arch/x86/lib/fsp/Makefile +++ b/arch/x86/lib/fsp/Makefile @@ -4,4 +4,7 @@ obj-y += fsp_common.o obj-y += fsp_dram.o +ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_VIDEO_FSP) += fsp_graphics.o +endif obj-y += fsp_support.o diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index a5efe35f59..5eff0f99aa 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -58,26 +58,6 @@ void board_final_cleanup(void) debug("OK\n"); } -void *fsp_prepare_mrc_cache(void) -{ - struct mrc_data_container *cache; - struct mrc_region entry; - int ret; - - ret = mrccache_get_region(NULL, &entry); - if (ret) - return NULL; - - cache = mrccache_find_current(&entry); - if (!cache) - return NULL; - - debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__, - cache->data, cache->data_size, cache->checksum); - - return cache->data; -} - #ifdef CONFIG_HAVE_ACPI_RESUME int fsp_save_s3_stack(void) { diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index bc456bb4a9..9ce0ddf0d3 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -9,6 +9,7 @@ #include <asm/fsp/fsp_support.h> #include <asm/e820.h> #include <asm/mrccache.h> +#include <asm/mtrr.h> #include <asm/post.h> DECLARE_GLOBAL_DATA_PTR; @@ -38,8 +39,40 @@ int fsp_scan_for_ram_size(void) int dram_init_banksize(void) { + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + phys_addr_t low_end; + uint bank; + + low_end = 0; + for (bank = 1, hdr = gd->arch.hob_list; + bank < CONFIG_NR_DRAM_BANKS && !end_of_hob(hdr); + hdr = get_next_hob(hdr)) { + if (hdr->type != HOB_TYPE_RES_DESC) + continue; + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type != RES_SYS_MEM && + res_desc->type != RES_MEM_RESERVED) + continue; + if (res_desc->phys_start < (1ULL << 32)) { + low_end = max(low_end, + res_desc->phys_start + res_desc->len); + continue; + } + + gd->bd->bi_dram[bank].start = res_desc->phys_start; + gd->bd->bi_dram[bank].size = res_desc->len; + mtrr_add_request(MTRR_TYPE_WRBACK, res_desc->phys_start, + res_desc->len); + log_debug("ram %llx %llx\n", gd->bd->bi_dram[bank].start, + gd->bd->bi_dram[bank].size); + } + + /* Add the memory below 4GB */ gd->bd->bi_dram[0].start = 0; - gd->bd->bi_dram[0].size = gd->ram_size; + gd->bd->bi_dram[0].size = low_end; + + mtrr_add_request(MTRR_TYPE_WRBACK, 0, low_end); return 0; } diff --git a/arch/x86/lib/fsp1/fsp_graphics.c b/arch/x86/lib/fsp/fsp_graphics.c index 52e71334f9..226c7e66b3 100644 --- a/arch/x86/lib/fsp1/fsp_graphics.c +++ b/arch/x86/lib/fsp/fsp_graphics.c @@ -7,7 +7,8 @@ #include <dm.h> #include <vbe.h> #include <video.h> -#include <asm/fsp1/fsp_support.h> +#include <asm/fsp/fsp_support.h> +#include <asm/mtrr.h> DECLARE_GLOBAL_DATA_PTR; @@ -97,6 +98,9 @@ static int fsp_video_probe(struct udevice *dev) if (ret) goto err; + mtrr_add_request(MTRR_TYPE_WRCOMB, vesa->phys_base_ptr, 256 << 20); + mtrr_commit(true); + printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize, vesa->bits_per_pixel); diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c index 983888fd74..ee228117d1 100644 --- a/arch/x86/lib/fsp/fsp_support.c +++ b/arch/x86/lib/fsp/fsp_support.c @@ -5,7 +5,7 @@ */ #include <common.h> -#include <asm/fsp1/fsp_support.h> +#include <asm/fsp/fsp_support.h> #include <asm/post.h> u32 fsp_get_usable_lowmem_top(const void *hob_list) diff --git a/arch/x86/lib/fsp1/Makefile b/arch/x86/lib/fsp1/Makefile index 870de71bd7..1cf5e54191 100644 --- a/arch/x86/lib/fsp1/Makefile +++ b/arch/x86/lib/fsp1/Makefile @@ -5,5 +5,4 @@ obj-y += fsp_car.o obj-y += fsp_common.o obj-y += fsp_dram.o -obj-$(CONFIG_VIDEO_FSP) += fsp_graphics.o obj-y += fsp_support.o diff --git a/arch/x86/lib/fsp1/fsp_common.c b/arch/x86/lib/fsp1/fsp_common.c index e8066d8de3..ec9c218778 100644 --- a/arch/x86/lib/fsp1/fsp_common.c +++ b/arch/x86/lib/fsp1/fsp_common.c @@ -18,6 +18,26 @@ DECLARE_GLOBAL_DATA_PTR; +static void *fsp_prepare_mrc_cache(void) +{ + struct mrc_data_container *cache; + struct mrc_region entry; + int ret; + + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); + if (ret) + return NULL; + + cache = mrccache_find_current(&entry); + if (!cache) + return NULL; + + debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__, + cache->data, cache->data_size, cache->checksum); + + return cache->data; +} + int arch_fsp_init(void) { void *nvs; diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c index 6a3349b42a..5ef89744b9 100644 --- a/arch/x86/lib/fsp1/fsp_dram.c +++ b/arch/x86/lib/fsp1/fsp_dram.c @@ -15,9 +15,11 @@ int dram_init(void) if (ret) return ret; - if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) - gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list, - &gd->arch.mrc_output_len); + if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) { + struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL]; + + mrc->buf = fsp_get_nvs_data(gd->arch.hob_list, &mrc->len); + } return 0; } diff --git a/arch/x86/lib/fsp2/Makefile b/arch/x86/lib/fsp2/Makefile new file mode 100644 index 0000000000..ddbe2d0db2 --- /dev/null +++ b/arch/x86/lib/fsp2/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2019 Google LLC + +obj-y += fsp_common.o +obj-y += fsp_dram.o +obj-y += fsp_init.o +obj-y += fsp_meminit.o +obj-y += fsp_silicon_init.o +obj-y += fsp_support.o diff --git a/arch/x86/lib/fsp2/fsp_common.c b/arch/x86/lib/fsp2/fsp_common.c new file mode 100644 index 0000000000..f69456e43a --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_common.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <init.h> + +int arch_fsp_init(void) +{ + return 0; +} diff --git a/arch/x86/lib/fsp2/fsp_dram.c b/arch/x86/lib/fsp2/fsp_dram.c new file mode 100644 index 0000000000..90a238a224 --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_dram.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <acpi_s3.h> +#include <handoff.h> +#include <spl.h> +#include <asm/arch/cpu.h> +#include <asm/fsp/fsp_support.h> +#include <asm/fsp2/fsp_api.h> +#include <asm/fsp2/fsp_internal.h> + +int dram_init(void) +{ + int ret; + + if (spl_phase() == PHASE_SPL) { +#ifdef CONFIG_HAVE_ACPI_RESUME + bool s3wake = gd->arch.prev_sleep_state == ACPI_S3; +#else + bool s3wake = false; +#endif + + ret = fsp_memory_init(s3wake, + IS_ENABLED(CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH)); + if (ret) { + debug("Memory init failed (err=%x)\n", ret); + return ret; + } + + /* The FSP has already set up DRAM, so grab the info we need */ + ret = fsp_scan_for_ram_size(); + if (ret) + return ret; + +#ifdef CONFIG_ENABLE_MRC_CACHE + gd->arch.mrc[MRC_TYPE_NORMAL].buf = + fsp_get_nvs_data(gd->arch.hob_list, + &gd->arch.mrc[MRC_TYPE_NORMAL].len); + gd->arch.mrc[MRC_TYPE_VAR].buf = + fsp_get_var_nvs_data(gd->arch.hob_list, + &gd->arch.mrc[MRC_TYPE_VAR].len); + log_debug("normal %x, var %x\n", + gd->arch.mrc[MRC_TYPE_NORMAL].len, + gd->arch.mrc[MRC_TYPE_VAR].len); +#endif + } else { +#if CONFIG_IS_ENABLED(HANDOFF) + struct spl_handoff *ho = gd->spl_handoff; + + if (!ho) { + debug("No SPL handoff found\n"); + return -ESTRPIPE; + } + gd->ram_size = ho->ram_size; + handoff_load_dram_banks(ho); +#endif + ret = arch_fsps_preinit(); + if (ret) + return log_msg_ret("fsp_s_preinit", ret); + } + + return 0; +} + +ulong board_get_usable_ram_top(ulong total_size) +{ +#if CONFIG_IS_ENABLED(HANDOFF) + struct spl_handoff *ho = gd->spl_handoff; + + return ho->arch.usable_ram_top; +#endif + + return gd->ram_top; +} diff --git a/arch/x86/lib/fsp2/fsp_init.c b/arch/x86/lib/fsp2/fsp_init.c new file mode 100644 index 0000000000..da9bd6b45c --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_init.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <binman.h> +#include <binman_sym.h> +#include <cbfs.h> +#include <dm.h> +#include <init.h> +#include <spi.h> +#include <spl.h> +#include <spi_flash.h> +#include <asm/intel_pinctrl.h> +#include <dm/uclass-internal.h> +#include <asm/fsp2/fsp_internal.h> + +int arch_cpu_init_dm(void) +{ + struct udevice *dev; + ofnode node; + int ret; + + /* Make sure pads are set up early in U-Boot */ + if (spl_phase() != PHASE_BOARD_F) + return 0; + + /* Probe all pinctrl devices to set up the pads */ + ret = uclass_first_device_err(UCLASS_PINCTRL, &dev); + if (ret) + return log_msg_ret("no fsp pinctrl", ret); + node = ofnode_path("fsp"); + if (!ofnode_valid(node)) + return log_msg_ret("no fsp params", -EINVAL); + ret = pinctrl_config_pads_for_node(dev, node); + if (ret) + return log_msg_ret("pad config", ret); + + return ret; +} + +#if !defined(CONFIG_TPL_BUILD) +binman_sym_declare(ulong, intel_fsp_m, image_pos); +binman_sym_declare(ulong, intel_fsp_m, size); + +/** + * get_cbfs_fsp() - Obtain the FSP by looking up in CBFS + * + * This looks up an FSP in a CBFS. It is used mostly for testing, when booting + * U-Boot from a hybrid image containing coreboot as the first-stage bootloader. + * + * The typical use for this feature is when building a Chrome OS image which + * includes coreboot in it. By adding U-Boot into the 'COREBOOT' CBFS as well, + * it is possible to make coreboot chain-load U-Boot. Thus the initial stages of + * the SoC init can be done by coreboot and the later stages by U-Boot. This is + * a convenient way to start the porting work. The jump to U-Boot can then be + * moved progressively earlier and earlier, until U-Boot takes over all the init + * and you have a native port. + * + * This function looks up a CBFS at a known location and reads the FSP-M from it + * so that U-Boot can init the memory. + * + * This function is not used in the normal boot but is kept here for future + * development. + * + * @type; Type to look up (only FSP_M supported at present) + * @map_base: Base memory address for mapped SPI + * @entry: Returns an entry containing the position of the FSP image + */ +static int get_cbfs_fsp(enum fsp_type_t type, ulong map_base, + struct binman_entry *entry) +{ + /* + * Use a hard-coded position of CBFS in the ROM for now. It would be + * possible to read the position using the FMAP in the ROM, but since + * this code is only used for development, it doesn't seem worth it. + * Use the 'cbfstool <image> layout' command to get these values, e.g.: + * 'COREBOOT' (CBFS, size 1814528, offset 2117632). + */ + ulong cbfs_base = 0x205000; + ulong cbfs_size = 0x1bb000; + struct cbfs_priv *cbfs; + int ret; + + ret = cbfs_init_mem(map_base + cbfs_base, cbfs_size, &cbfs); + if (ret) + return ret; + if (!ret) { + const struct cbfs_cachenode *node; + + node = cbfs_find_file(cbfs, "fspm.bin"); + if (!node) + return log_msg_ret("fspm node", -ENOENT); + + entry->image_pos = (ulong)node->data; + entry->size = node->data_length; + } + + return 0; +} + +int fsp_locate_fsp(enum fsp_type_t type, struct binman_entry *entry, + bool use_spi_flash, struct udevice **devp, + struct fsp_header **hdrp, ulong *rom_offsetp) +{ + ulong mask = CONFIG_ROM_SIZE - 1; + struct udevice *dev; + ulong rom_offset = 0; + uint map_size; + ulong map_base; + uint offset; + int ret; + + /* + * Find the devices but don't probe them, since we don't want to + * auto-config PCI before silicon init runs + */ + ret = uclass_find_first_device(UCLASS_NORTHBRIDGE, &dev); + if (ret) + return log_msg_ret("Cannot get northbridge", ret); + if (!use_spi_flash) { + struct udevice *sf; + + /* Just use the SPI driver to get the memory map */ + ret = uclass_find_first_device(UCLASS_SPI_FLASH, &sf); + if (ret) + return log_msg_ret("Cannot get SPI flash", ret); + ret = dm_spi_get_mmap(sf, &map_base, &map_size, &offset); + if (ret) + return log_msg_ret("Could not get flash mmap", ret); + } + + if (spl_phase() >= PHASE_BOARD_F) { + if (type != FSP_S) + return -EPROTONOSUPPORT; + ret = binman_entry_find("intel-fsp-s", entry); + if (ret) + return log_msg_ret("binman entry", ret); + if (!use_spi_flash) + rom_offset = (map_base & mask) - CONFIG_ROM_SIZE; + } else { + ret = -ENOENT; + if (false) + /* + * Support using a hybrid image build by coreboot. See + * the function comments for details + */ + ret = get_cbfs_fsp(type, map_base, entry); + if (ret) { + ulong mask = CONFIG_ROM_SIZE - 1; + + if (type != FSP_M) + return -EPROTONOSUPPORT; + entry->image_pos = binman_sym(ulong, intel_fsp_m, + image_pos); + entry->size = binman_sym(ulong, intel_fsp_m, size); + if (entry->image_pos != BINMAN_SYM_MISSING) { + ret = 0; + if (use_spi_flash) + entry->image_pos &= mask; + else + entry->image_pos += (map_base & mask); + } else { + ret = -ENOENT; + } + } + } + if (ret) + return log_msg_ret("Cannot find FSP", ret); + entry->image_pos += rom_offset; + + /* + * Account for the time taken to read memory-mapped SPI flash since in + * this case we don't use the SPI driver and BOOTSTAGE_ID_ACCUM_SPI. + */ + if (!use_spi_flash) + bootstage_start(BOOTSTAGE_ID_ACCUM_MMAP_SPI, "mmap_spi"); + ret = fsp_get_header(entry->image_pos, entry->size, use_spi_flash, + hdrp); + if (!use_spi_flash) + bootstage_accum(BOOTSTAGE_ID_ACCUM_MMAP_SPI); + if (ret) + return log_msg_ret("fsp_get_header", ret); + *devp = dev; + if (rom_offsetp) + *rom_offsetp = rom_offset; + + return 0; +} +#endif diff --git a/arch/x86/lib/fsp2/fsp_meminit.c b/arch/x86/lib/fsp2/fsp_meminit.c new file mode 100644 index 0000000000..bf30c47989 --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_meminit.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: Intel +/* + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.) + * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.) + * Mostly taken from coreboot fsp2_0/memory_init.c + */ + +#include <common.h> +#include <binman.h> +#include <asm/mrccache.h> +#include <asm/fsp/fsp_infoheader.h> +#include <asm/fsp2/fsp_api.h> +#include <asm/fsp2/fsp_internal.h> +#include <asm/arch/fsp/fsp_configs.h> +#include <asm/arch/fsp/fsp_m_upd.h> + +static int prepare_mrc_cache_type(enum mrc_type_t type, + struct mrc_data_container **cachep) +{ + struct mrc_data_container *cache; + struct mrc_region entry; + int ret; + + ret = mrccache_get_region(type, NULL, &entry); + if (ret) + return ret; + cache = mrccache_find_current(&entry); + if (!cache) + return -ENOENT; + + log_debug("MRC at %x, size %x\n", (uint)cache->data, cache->data_size); + *cachep = cache; + + return 0; +} + +int prepare_mrc_cache(struct fspm_upd *upd) +{ + struct mrc_data_container *cache; + int ret; + + ret = prepare_mrc_cache_type(MRC_TYPE_NORMAL, &cache); + if (ret) + return log_msg_ret("Cannot get normal cache", ret); + upd->arch.nvs_buffer_ptr = cache->data; + + ret = prepare_mrc_cache_type(MRC_TYPE_VAR, &cache); + if (ret) + return log_msg_ret("Cannot get var cache", ret); + upd->config.variable_nvs_buffer_ptr = cache->data; + + return 0; +} + +int fsp_memory_init(bool s3wake, bool use_spi_flash) +{ + struct fspm_upd upd, *fsp_upd; + fsp_memory_init_func func; + struct binman_entry entry; + struct fsp_header *hdr; + struct hob_header *hob; + struct udevice *dev; + int ret; + + ret = fsp_locate_fsp(FSP_M, &entry, use_spi_flash, &dev, &hdr, NULL); + if (ret) + return log_msg_ret("locate FSP", ret); + debug("Found FSP_M at %x, size %x\n", hdr->img_base, hdr->img_size); + + /* Copy over the default config */ + fsp_upd = (struct fspm_upd *)(hdr->img_base + hdr->cfg_region_off); + if (fsp_upd->header.signature != FSPM_UPD_SIGNATURE) + return log_msg_ret("Bad UPD signature", -EPERM); + memcpy(&upd, fsp_upd, sizeof(upd)); + + ret = fspm_update_config(dev, &upd); + if (ret) + return log_msg_ret("Could not setup config", ret); + + debug("SDRAM init..."); + bootstage_start(BOOTSTATE_ID_ACCUM_FSP_M, "fsp-m"); + func = (fsp_memory_init_func)(hdr->img_base + hdr->fsp_mem_init); + ret = func(&upd, &hob); + bootstage_accum(BOOTSTATE_ID_ACCUM_FSP_M); + if (ret) + return log_msg_ret("SDRAM init fail\n", ret); + + gd->arch.hob_list = hob; + debug("done\n"); + + ret = fspm_done(dev); + if (ret) + return log_msg_ret("fsm_done\n", ret); + + return 0; +} diff --git a/arch/x86/lib/fsp2/fsp_silicon_init.c b/arch/x86/lib/fsp2/fsp_silicon_init.c new file mode 100644 index 0000000000..d7ce43e1eb --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_silicon_init.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: Intel +/* + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.) + * + * Mostly taken from coreboot fsp2_0/silicon_init.c + */ + +#define LOG_CATEGORY UCLASS_NORTHBRIDGE + +#include <common.h> +#include <binman.h> +#include <dm.h> +#include <asm/arch/fsp/fsp_configs.h> +#include <asm/arch/fsp/fsp_s_upd.h> +#include <asm/fsp/fsp_infoheader.h> +#include <asm/fsp2/fsp_internal.h> + +int fsp_silicon_init(bool s3wake, bool use_spi_flash) +{ + struct fsps_upd upd, *fsp_upd; + fsp_silicon_init_func func; + struct fsp_header *hdr; + struct binman_entry entry; + struct udevice *dev; + ulong rom_offset = 0; + int ret; + + ret = fsp_locate_fsp(FSP_S, &entry, use_spi_flash, &dev, &hdr, + &rom_offset); + if (ret) + return log_msg_ret("locate FSP", ret); + gd->arch.fsp_s_hdr = hdr; + + /* Copy over the default config */ + fsp_upd = (struct fsps_upd *)(hdr->img_base + hdr->cfg_region_off); + if (fsp_upd->header.signature != FSPS_UPD_SIGNATURE) + return log_msg_ret("Bad UPD signature", -EPERM); + memcpy(&upd, fsp_upd, sizeof(upd)); + + ret = fsps_update_config(dev, rom_offset, &upd); + if (ret) + return log_msg_ret("Could not setup config", ret); + log_debug("Silicon init..."); + bootstage_start(BOOTSTATE_ID_ACCUM_FSP_S, "fsp-s"); + func = (fsp_silicon_init_func)(hdr->img_base + hdr->fsp_silicon_init); + ret = func(&upd); + bootstage_accum(BOOTSTATE_ID_ACCUM_FSP_S); + if (ret) + return log_msg_ret("Silicon init fail\n", ret); + log_debug("done\n"); + + return 0; +} diff --git a/arch/x86/lib/fsp2/fsp_support.c b/arch/x86/lib/fsp2/fsp_support.c new file mode 100644 index 0000000000..0a04b443f7 --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_support.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: Intel +/* + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <spi_flash.h> +#include <asm/fsp/fsp_support.h> +#include <asm/fsp2/fsp_internal.h> + +/* The amount of the FSP header to probe to obtain what we need */ +#define PROBE_BUF_SIZE 0x180 + +int fsp_get_header(ulong offset, ulong size, bool use_spi_flash, + struct fsp_header **fspp) +{ + static efi_guid_t guid = FSP_HEADER_GUID; + struct fv_ext_header *exhdr; + struct fsp_header *fsp; + struct ffs_file_header *file_hdr; + struct fv_header *fv; + struct raw_section *raw; + void *ptr, *base; + u8 buf[PROBE_BUF_SIZE]; + struct udevice *dev; + int ret; + + /* + * There are quite a very steps to work through all the headers in this + * file and the structs have similar names. Turn on debugging if needed + * to understand what is going wrong. + * + * You are in a maze of twisty little headers all alike. + */ + debug("offset=%x buf=%x\n", (uint)offset, (uint)buf); + if (use_spi_flash) { + ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev); + if (ret) + return log_msg_ret("Cannot find flash device", ret); + ret = spi_flash_read_dm(dev, offset, PROBE_BUF_SIZE, buf); + if (ret) + return log_msg_ret("Cannot read flash", ret); + } else { + memcpy(buf, (void *)offset, PROBE_BUF_SIZE); + } + + /* Initalise the FSP base */ + ptr = buf; + fv = ptr; + + /* Check the FV signature, _FVH */ + debug("offset=%x sign=%x\n", (uint)offset, (uint)fv->sign); + if (fv->sign != EFI_FVH_SIGNATURE) + return log_msg_ret("Base FV signature", -EINVAL); + + /* Go to the end of the FV header and align the address */ + debug("fv->ext_hdr_off = %x\n", fv->ext_hdr_off); + ptr += fv->ext_hdr_off; + exhdr = ptr; + ptr += ALIGN(exhdr->ext_hdr_size, 8); + debug("ptr=%x\n", ptr - (void *)buf); + + /* Check the FFS GUID */ + file_hdr = ptr; + if (memcmp(&file_hdr->name, &guid, sizeof(guid))) + return log_msg_ret("Base FFS GUID", -ENXIO); + /* Add the FFS header size to find the raw section header */ + ptr = file_hdr + 1; + + raw = ptr; + debug("raw->type = %x\n", raw->type); + if (raw->type != EFI_SECTION_RAW) + return log_msg_ret("Section type not RAW", -ENOEXEC); + + /* Add the raw section header size to find the FSP header */ + ptr = raw + 1; + fsp = ptr; + + /* Check the FSPH header */ + debug("fsp %x\n", (uint)fsp); + if (fsp->sign != EFI_FSPH_SIGNATURE) + return log_msg_ret("Base FSPH signature", -EACCES); + + base = (void *)fsp->img_base; + debug("Image base %x\n", (uint)base); + debug("Image addr %x\n", (uint)fsp->fsp_mem_init); + if (use_spi_flash) { + ret = spi_flash_read_dm(dev, offset, size, base); + if (ret) + return log_msg_ret("Could not read FPS-M", ret); + } else { + memcpy(base, (void *)offset, size); + } + ptr = base + (ptr - (void *)buf); + *fspp = ptr; + + return 0; +} + +u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase) +{ + fsp_notify_f notify; + struct fsp_notify_params params; + struct fsp_notify_params *params_ptr; + u32 status; + + if (!fsp_hdr) + fsp_hdr = gd->arch.fsp_s_hdr; + + if (!fsp_hdr) + return log_msg_ret("no FSP", -ENOENT); + + notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify); + params.phase = phase; + params_ptr = ¶ms; + + /* + * Use ASM code to ensure correct parameter is on the stack for + * FspNotify as U-Boot is using different ABI from FSP + */ + asm volatile ( + "pushl %1;" /* push notify phase */ + "call *%%eax;" /* call FspNotify */ + "addl $4, %%esp;" /* clean up the stack */ + : "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr) + ); + + return status; +} diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 33bb52039b..b9420a4cab 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -14,6 +14,8 @@ #include <spi.h> #include <spi_flash.h> #include <asm/mrccache.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> DECLARE_GLOBAL_DATA_PTR; @@ -80,21 +82,31 @@ struct mrc_data_container *mrccache_find_current(struct mrc_region *entry) /** * find_next_mrc_cache() - get next cache entry * + * This moves to the next cache entry in the region, making sure it has enough + * space to hold data of size @data_size. + * * @entry: MRC cache flash area * @cache: Entry to start from + * @data_size: Required data size of the new entry. Note that we assume that + * all cache entries are the same size * * @return next cache entry if found, NULL if we got to the end */ static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry, - struct mrc_data_container *cache) + struct mrc_data_container *prev, int data_size) { + struct mrc_data_container *cache; ulong base_addr, end_addr; base_addr = entry->base + entry->offset; end_addr = base_addr + entry->length; - cache = next_mrc_block(cache); - if ((ulong)cache >= end_addr) { + /* + * We assume that all cache entries are the same size, but let's use + * data_size here for clarity. + */ + cache = next_mrc_block(prev); + if ((ulong)cache + mrc_block_size(data_size) > end_addr) { /* Crossed the boundary */ cache = NULL; debug("%s: no available entries found\n", __func__); @@ -106,8 +118,20 @@ static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry, return cache; } -int mrccache_update(struct udevice *sf, struct mrc_region *entry, - struct mrc_data_container *cur) +/** + * mrccache_update() - update the MRC cache with a new record + * + * This writes a new record to the end of the MRC cache region. If the new + * record is the same as the latest record then the write is skipped + * + * @sf: SPI flash to write to + * @entry: Position and size of MRC cache in SPI flash + * @cur: Record to write + * @return 0 if updated, -EEXIST if the record is the same as the latest + * record, -EINVAL if the record is not valid, other error if SPI write failed + */ +static int mrccache_update(struct udevice *sf, struct mrc_region *entry, + struct mrc_data_container *cur) { struct mrc_data_container *cache; ulong offset; @@ -131,7 +155,7 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry, /* Move to the next block, which will be the first unused block */ if (cache) - cache = find_next_mrc_cache(entry, cache); + cache = find_next_mrc_cache(entry, cache, cur->data_size); /* * If we have got to the end, erase the entire mrc-cache area and start @@ -156,130 +180,158 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry, cur); if (ret) { debug("Failed to write to SPI flash\n"); - return ret; + return log_msg_ret("Cannot update mrccache", ret); } return 0; } -static void mrccache_setup(void *data) +static void mrccache_setup(struct mrc_output *mrc, void *data) { struct mrc_data_container *cache = data; u16 checksum; cache->signature = MRC_DATA_SIGNATURE; - cache->data_size = gd->arch.mrc_output_len; - checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size); + cache->data_size = mrc->len; + checksum = compute_ip_checksum(mrc->buf, cache->data_size); debug("Saving %d bytes for MRC output data, checksum %04x\n", cache->data_size, checksum); cache->checksum = checksum; cache->reserved = 0; - memcpy(cache->data, gd->arch.mrc_output, cache->data_size); + memcpy(cache->data, mrc->buf, cache->data_size); - /* gd->arch.mrc_output now points to the container */ - gd->arch.mrc_output = (char *)cache; + mrc->cache = cache; } int mrccache_reserve(void) { - if (!gd->arch.mrc_output_len) - return 0; + int i; - /* adjust stack pointer to store pure cache data plus the header */ - gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE); - mrccache_setup((void *)gd->start_addr_sp); + for (i = 0; i < MRC_TYPE_COUNT; i++) { + struct mrc_output *mrc = &gd->arch.mrc[i]; - gd->start_addr_sp &= ~0xf; + if (!mrc->len) + continue; + + /* adjust stack pointer to store pure cache data plus header */ + gd->start_addr_sp -= (mrc->len + MRC_DATA_HEADER_SIZE); + mrccache_setup(mrc, (void *)gd->start_addr_sp); + + gd->start_addr_sp &= ~0xf; + } return 0; } -int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) +int mrccache_get_region(enum mrc_type_t type, struct udevice **devp, + struct mrc_region *entry) { - const void *blob = gd->fdt_blob; - int node, mrc_node; + struct udevice *dev; + ofnode mrc_node; + ulong map_base; + uint map_size; + uint offset; u32 reg[2]; int ret; - /* Find the flash chip within the SPI controller node */ - node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); - if (node < 0) { - debug("%s: Cannot find SPI flash\n", __func__); - return -ENOENT; - } - - if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) { - debug("%s: Cannot find memory map\n", __func__); - return -EINVAL; + /* + * Find the flash chip within the SPI controller node. Avoid probing + * the device here since it may put it into a strange state where the + * memory map cannot be read. + */ + ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev); + if (ret) + return log_msg_ret("Cannot find SPI flash\n", ret); + ret = dm_spi_get_mmap(dev, &map_base, &map_size, &offset); + if (!ret) { + entry->base = map_base; + } else { + ret = dev_read_u32_array(dev, "memory-map", reg, 2); + if (ret) + return log_msg_ret("Cannot find memory map\n", ret); + entry->base = reg[0]; } - entry->base = reg[0]; /* Find the place where we put the MRC cache */ - mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache"); - if (mrc_node < 0) { - debug("%s: Cannot find node\n", __func__); - return -EPERM; - } + mrc_node = dev_read_subnode(dev, type == MRC_TYPE_NORMAL ? + "rw-mrc-cache" : "rw-var-mrc-cache"); + if (!ofnode_valid(mrc_node)) + return log_msg_ret("Cannot find node", -EPERM); - if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) { - debug("%s: Cannot find address\n", __func__); - return -EINVAL; - } + ret = ofnode_read_u32_array(mrc_node, "reg", reg, 2); + if (ret) + return log_msg_ret("Cannot find address", ret); entry->offset = reg[0]; entry->length = reg[1]; - if (devp) { - ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, - devp); - debug("ret = %d\n", ret); - if (ret) - return ret; - } + if (devp) + *devp = dev; + debug("MRC cache type %d in '%s', offset %x, len %x, base %x\n", + type, dev->name, entry->offset, entry->length, entry->base); return 0; } -int mrccache_save(void) +static int mrccache_save_type(enum mrc_type_t type) { - struct mrc_data_container *data; + struct mrc_data_container *cache; + struct mrc_output *mrc; struct mrc_region entry; struct udevice *sf; int ret; - if (!gd->arch.mrc_output_len) + mrc = &gd->arch.mrc[type]; + if (!mrc->len) return 0; - debug("Saving %d bytes of MRC output data to SPI flash\n", - gd->arch.mrc_output_len); - - ret = mrccache_get_region(&sf, &entry); + log_debug("Saving %#x bytes of MRC output data type %d to SPI flash\n", + mrc->len, type); + ret = mrccache_get_region(type, &sf, &entry); if (ret) - goto err_entry; - data = (struct mrc_data_container *)gd->arch.mrc_output; - ret = mrccache_update(sf, &entry, data); - if (!ret) { - debug("Saved MRC data with checksum %04x\n", data->checksum); - } else if (ret == -EEXIST) { + return log_msg_ret("Cannot get region", ret); + ret = device_probe(sf); + if (ret) + return log_msg_ret("Cannot probe device", ret); + cache = mrc->cache; + + ret = mrccache_update(sf, &entry, cache); + if (!ret) + debug("Saved MRC data with checksum %04x\n", cache->checksum); + else if (ret == -EEXIST) debug("MRC data is the same as last time, skipping save\n"); - ret = 0; + + return 0; +} + +int mrccache_save(void) +{ + int i; + + for (i = 0; i < MRC_TYPE_COUNT; i++) { + int ret; + + ret = mrccache_save_type(i); + if (ret) + return ret; } -err_entry: - if (ret) - debug("%s: Failed: %d\n", __func__, ret); - return ret; + return 0; } int mrccache_spl_save(void) { - void *data; - int size; - - size = gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE; - data = malloc(size); - if (!data) - return log_msg_ret("Allocate MRC cache block", -ENOMEM); - mrccache_setup(data); - gd->arch.mrc_output = data; + int i; + + for (i = 0; i < MRC_TYPE_COUNT; i++) { + struct mrc_output *mrc = &gd->arch.mrc[i]; + void *data; + int size; + + size = mrc->len + MRC_DATA_HEADER_SIZE; + data = malloc(size); + if (!data) + return log_msg_ret("Allocate MRC cache block", -ENOMEM); + mrccache_setup(mrc, data); + } return mrccache_save(); } diff --git a/arch/x86/lib/pirq_routing.c b/arch/x86/lib/pirq_routing.c index e5f0e61424..17bd2fcb9b 100644 --- a/arch/x86/lib/pirq_routing.c +++ b/arch/x86/lib/pirq_routing.c @@ -10,6 +10,8 @@ #include <asm/pci.h> #include <asm/pirq_routing.h> +DECLARE_GLOBAL_DATA_PTR; + static u8 pirq_get_next_free_irq(struct udevice *dev, u8 *pirq, u16 bitmap, bool irq_already_routed[]) { @@ -131,3 +133,11 @@ u32 copy_pirq_routing_table(u32 addr, struct irq_routing_table *rt) return addr + rt->size; } + +ulong write_pirq_routing_table(ulong addr) +{ + if (!gd->arch.pirq_routing_table) + return addr; + + return copy_pirq_routing_table(addr, gd->arch.pirq_routing_table); +} |