diff options
Diffstat (limited to 'arch/x86')
86 files changed, 7468 insertions, 276 deletions
| diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 17a6fe6d3d9..89b93e5de25 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 6296b55ff8a..5b40838e60a 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 00000000000..fcff176c27d --- /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 00000000000..1760df54d81 --- /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 00000000000..3d05c82a5c6 --- /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 00000000000..ba6bda37bc5 --- /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 00000000000..8a39c3128e0 --- /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 00000000000..5308af8ed45 --- /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 00000000000..9804227f80b --- /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 00000000000..793853d5b5c --- /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 00000000000..8789f8e6bb9 --- /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 00000000000..45b2144fc68 --- /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 00000000000..eb27861b7a4 --- /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 00000000000..1a5a985221f --- /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 00000000000..683c6082f2c --- /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 00000000000..1a131fb0b14 --- /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 00000000000..7ab7243311c --- /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 00000000000..b6bc2ba14f1 --- /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 00000000000..f2b356eb447 --- /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 dfd8afc35f5..15bfc5811cb 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 93f61f2fa4f..c8e6a889d02 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 4e59476fc99..d626e38fd18 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 0c47252610d..18e152074a7 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 c66382bdd2f..2b27617ca3a 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 07f27c29ec7..cc4e1c962b9 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 00000000000..086f987477e --- /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 00000000000..aba3a5381e5 --- /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 00000000000..a6e3d0a5bfc --- /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 00000000000..26a2d2d1e36 --- /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 3adc155818c..ed9938f7f7f 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 51ca4ad3017..cf34f94a91d 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 fefbf8f7282..7b09f90cd51 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 00000000000..49e9dfcf691 --- /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 995e119fb6f..2bf90dcfc62 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 3ea4c9958cf..58a9ca01a9e 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 c1e9bfbf66f..e6c22895b35 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 d4bdf62be6d..be209aaaf8f 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 00000000000..24fcbb50631 --- /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 0e87b88e105..f0f8c71761a 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 00000000000..5e906c5e7d7 --- /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 00000000000..9185d94b2bc --- /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 00000000000..93bee5b2d1c --- /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 00000000000..4a868e80ba8 --- /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 00000000000..b14f28b2364 --- /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 00000000000..10879c168ec --- /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 00000000000..4ce10170558 --- /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 00000000000..1e295039745 --- /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 00000000000..5d2adad3197 --- /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 00000000000..bf3e1670d29 --- /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 00000000000..6718290c4fe --- /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 00000000000..206d8903fa5 --- /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 00000000000..d4fffe6525c --- /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 3bc3bd6609e..2b39a76fbdb 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 4839ebc3124..5c066294bc2 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 00000000000..6894298526e --- /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 00000000000..e9ac86b2da6 --- /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 4ac27d26f55..29e511415cd 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 f2d70799f33..524da5feb75 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 00000000000..af1e8857b97 --- /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 00000000000..f751fbf961a --- /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 7f3ada06f61..f4c1839104e 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 00000000000..72fd9246cbd --- /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 00000000000..6da06bb52b4 --- /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 00000000000..78148726881 --- /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 40fda856ff4..d6b75290739 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 5bc8b6c22c7..246c14f815b 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 f1d9977bcb3..d7b68367861 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 1bef4877eb3..cc6cac08f23 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 ca0ca1066b0..5cd45874803 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 9e348564737..da6c0a886ae 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 a5efe35f593..5eff0f99aad 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 bc456bb4a9e..9ce0ddf0d3d 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 52e71334f95..226c7e66b3f 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 983888fd743..ee228117d13 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 870de71bd71..1cf5e541913 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 e8066d8de39..ec9c218778d 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 6a3349b42af..5ef89744b94 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 00000000000..ddbe2d0db26 --- /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 00000000000..f69456e43a2 --- /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 00000000000..90a238a2245 --- /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 00000000000..da9bd6b45cf --- /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 00000000000..bf30c479899 --- /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 00000000000..d7ce43e1eb2 --- /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 00000000000..0a04b443f7e --- /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 33bb52039bd..b9420a4cab5 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 e5f0e614241..17bd2fcb9b4 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); +} | 
