Hello Richard Spiegel, Martin Roth, Furquan Shaikh,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/32653
to review the following change.
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
soc/amd/stoneyridge: Move LPC support to common
AMD devices traditionally have the LPC-ISA bus at 14.3 and the definition has been very consistent. Relocate the feature from stoneyridge into common/block.
Change-Id: I8d7175b8642bb17533bb2287b3e3ee3d52e85a75 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/ec.c R src/soc/amd/common/acpi/lpc.asl A src/soc/amd/common/block/include/amdblocks/lpc.h A src/soc/amd/common/block/lpc/Kconfig A src/soc/amd/common/block/lpc/Makefile.inc R src/soc/amd/common/block/lpc/lpc.c A src/soc/amd/common/block/lpc/lpc_util.c M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/Makefile.inc M src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl M src/soc/amd/stoneyridge/include/soc/southbridge.h M src/soc/amd/stoneyridge/southbridge.c M src/soc/amd/stoneyridge/spi.c 14 files changed, 532 insertions(+), 435 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/53/32653/1
diff --git a/src/mainboard/google/kahlee/bootblock/bootblock.c b/src/mainboard/google/kahlee/bootblock/bootblock.c index 3be308e..e403684 100644 --- a/src/mainboard/google/kahlee/bootblock/bootblock.c +++ b/src/mainboard/google/kahlee/bootblock/bootblock.c @@ -17,6 +17,7 @@ #include <bootblock_common.h> #include <soc/gpio.h> #include <soc/southbridge.h> +#include <amdblocks/lpc.h> #include <variant/ec.h> #include <variant/gpio.h>
@@ -61,5 +62,5 @@ }
/* Setup TPM decode before verstage */ - sb_tpm_decode_spi(); + lpc_tpm_decode_spi(); } diff --git a/src/mainboard/google/kahlee/ec.c b/src/mainboard/google/kahlee/ec.c index 7164591..1080902 100644 --- a/src/mainboard/google/kahlee/ec.c +++ b/src/mainboard/google/kahlee/ec.c @@ -16,6 +16,7 @@ #include <arch/acpi.h> #include <console/console.h> #include <ec/google/chromeec/ec.h> +#include <amdblocks/lpc.h> #include <soc/southbridge.h> #include <variant/ec.h>
@@ -49,7 +50,7 @@ printk(BIOS_DEBUG, "LPC Setup google_chromeec_ioport_range: %04x, %08zx\n", ec_ioport_base, ec_ioport_size); - status = sb_set_wideio_range(ec_ioport_base, ec_ioport_size); + status = lpc_set_wideio_range(ec_ioport_base, ec_ioport_size); if (status == WIDEIO_RANGE_ERROR) printk(BIOS_WARNING, "ERROR: Failed to assign a range\n"); else diff --git a/src/soc/amd/stoneyridge/acpi/lpc.asl b/src/soc/amd/common/acpi/lpc.asl similarity index 100% rename from src/soc/amd/stoneyridge/acpi/lpc.asl rename to src/soc/amd/common/acpi/lpc.asl diff --git a/src/soc/amd/common/block/include/amdblocks/lpc.h b/src/soc/amd/common/block/include/amdblocks/lpc.h new file mode 100644 index 0000000..31688b4 --- /dev/null +++ b/src/soc/amd/common/block/include/amdblocks/lpc.h @@ -0,0 +1,176 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AMDBLOCKS_LPC_H__ +#define __AMDBLOCKS_LPC_H__ + +#include <types.h> + +/* PCI registers for D14F3 */ +#define LPC_PCI_CONTROL 0x40 +#define LEGACY_DMA_EN BIT(2) + +#define LPC_IO_PORT_DECODE_ENABLE 0x44 +#define DECODE_ENABLE_PARALLEL_PORT0 BIT(0) +#define DECODE_ENABLE_PARALLEL_PORT1 BIT(1) +#define DECODE_ENABLE_PARALLEL_PORT2 BIT(2) +#define DECODE_ENABLE_PARALLEL_PORT3 BIT(3) +#define DECODE_ENABLE_PARALLEL_PORT4 BIT(4) +#define DECODE_ENABLE_PARALLEL_PORT5 BIT(5) +#define DECODE_ENABLE_SERIAL_PORT0 BIT(6) +#define DECODE_ENABLE_SERIAL_PORT1 BIT(7) +#define DECODE_ENABLE_SERIAL_PORT2 BIT(8) +#define DECODE_ENABLE_SERIAL_PORT3 BIT(9) +#define DECODE_ENABLE_SERIAL_PORT4 BIT(10) +#define DECODE_ENABLE_SERIAL_PORT5 BIT(11) +#define DECODE_ENABLE_SERIAL_PORT6 BIT(12) +#define DECODE_ENABLE_SERIAL_PORT7 BIT(13) +#define DECODE_ENABLE_AUDIO_PORT0 BIT(14) +#define DECODE_ENABLE_AUDIO_PORT1 BIT(15) +#define DECODE_ENABLE_AUDIO_PORT2 BIT(16) +#define DECODE_ENABLE_AUDIO_PORT3 BIT(17) +#define DECODE_ENABLE_MIDI_PORT0 BIT(18) +#define DECODE_ENABLE_MIDI_PORT1 BIT(19) +#define DECODE_ENABLE_MIDI_PORT2 BIT(20) +#define DECODE_ENABLE_MIDI_PORT3 BIT(21) +#define DECODE_ENABLE_MSS_PORT0 BIT(22) +#define DECODE_ENABLE_MSS_PORT1 BIT(23) +#define DECODE_ENABLE_MSS_PORT2 BIT(24) +#define DECODE_ENABLE_MSS_PORT3 BIT(25) +#define DECODE_ENABLE_FDC_PORT0 BIT(26) +#define DECODE_ENABLE_FDC_PORT1 BIT(27) +#define DECODE_ENABLE_GAME_PORT BIT(28) +#define DECODE_ENABLE_KBC_PORT BIT(29) +#define DECODE_ENABLE_ACPIUC_PORT BIT(30) +#define DECODE_ENABLE_ADLIB_PORT BIT(31) + +#define LPC_IO_OR_MEM_DECODE_ENABLE 0x48 +#define LPC_WIDEIO2_ENABLE BIT(25) +#define LPC_WIDEIO1_ENABLE BIT(24) +#define DECODE_IO_PORT_ENABLE6 BIT(23) +#define DECODE_IO_PORT_ENABLE5 BIT(22) +#define DECODE_IO_PORT_ENABLE4 BIT(21) +#define DECODE_MEM_PORT_ENABLE1 BIT(20) +#define DECODE_IO_PORT_ENABLE3 BIT(19) +#define DECODE_IO_PORT_ENABLE2 BIT(18) +#define DECODE_IO_PORT_ENABLE1 BIT(17) +#define DECODE_IO_PORT_ENABLE0 BIT(16) +#define LPC_SYNC_TIMEOUT_COUNT_ENABLE BIT(7) +#define LPC_DECODE_RTC_IO_ENABLE BIT(6) +#define DECODE_MEM_PORT_ENABLE0 BIT(5) +#define LPC_WIDEIO0_ENABLE BIT(2) +#define DECODE_ALTERNATE_SIO_ENABLE BIT(1) +#define DECODE_SIO_ENABLE BIT(0) +#define WIDEIO_RANGE_ERROR -1 +#define TOTAL_WIDEIO_PORTS 3 + +/* Assuming word access to higher word (register 0x4a) */ +#define LPC_IO_OR_MEM_DEC_EN_HIGH 0x4a +#define LPC_WIDEIO2_ENABLE_H BIT(9) +#define LPC_WIDEIO1_ENABLE_H BIT(8) +#define DECODE_IO_PORT_ENABLE6_H BIT(7) +#define DECODE_IO_PORT_ENABLE5_H BIT(6) +#define DECODE_IO_PORT_ENABLE4_H BIT(5) +#define DECODE_IO_PORT_ENABLE3_H BIT(3) +#define DECODE_IO_PORT_ENABLE2_H BIT(2) +#define DECODE_IO_PORT_ENABLE1_H BIT(1) +#define DECODE_IO_PORT_ENABLE0_H BIT(0) + +#define LPC_MEM_PORT1 0x4c +#define LPC_MEM_PORT0 0x60 + +/* Register 0x64 is 32-bit, composed by two 16-bit sub-registers. + For ease of access, each sub-register is declared separetely. */ +#define LPC_WIDEIO_GENERIC_PORT 0x64 +#define LPC_WIDEIO1_GENERIC_PORT 0x66 +#define ROM_ADDRESS_RANGE1_START 0x68 +#define ROM_ADDRESS_RANGE1_END 0x6a +#define ROM_ADDRESS_RANGE2_START 0x6c +#define ROM_ADDRESS_RANGE2_END 0x6e + +#define LPC_ALT_WIDEIO_RANGE_ENABLE 0x74 +#define LPC_ALT_WIDEIO2_ENABLE BIT(3) +#define LPC_ALT_WIDEIO1_ENABLE BIT(2) +#define LPC_ALT_WIDEIO0_ENABLE BIT(0) + +#define LPC_MISC_CONTROL_BITS 0x78 +#define LPC_NOHOG BIT(0) + +#define LPC_TRUSTED_PLATFORM_MODULE 0x7c +#define TPM_12_EN BIT(0) +#define TPM_LEGACY_EN BIT(2) + +#define LPC_WIDEIO2_GENERIC_PORT 0x90 + +#define SPIROM_BASE_ADDRESS_REGISTER 0xa0 +#define SPI_BASE_RESERVED (BIT(4) | BIT(5)) +#define ROUTE_TPM_2_SPI BIT(3) +#define SPI_ABORT_ENABLE BIT(2) +#define SPI_ROM_ENABLE BIT(1) +#define SPI_ROM_ALT_ENABLE BIT(0) +#define SPI_PRESERVE_BITS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +/* LPC register 0xb8 is DWORD, here there are definitions for byte + access. For example, bits 31-24 are accessed through byte access + at register 0xbb. */ +#define LPC_ROM_DMA_EC_HOST_CONTROL 0xb8 +#define SPI_FROM_HOST_PREFETCH_EN BIT(24) +#define SPI_FROM_USB_PREFETCH_EN BIT(23) + +#define LPC_HOST_CONTROL 0xbb +#define PREFETCH_EN_SPI_FROM_HOST BIT(0) +#define T_START_ENH BIT(3) + +void late_lpc_bridge_enable(void); +void lpc_enable_port80(void); +void lpc_enable_pci_port80(void); +void lpc_enable_decode(uint32_t decodes); +uintptr_t lpc_spibase(void); +void lpc_tpm_decode(void); +void lpc_tpm_decode_spi(void); +void lpc_enable_rom(void); +void lpc_enable_spi_prefetch(void); + +/** + * @brief Find the size of a particular wide IO + * + * @param index = index of desired wide IO + * + * @return size of desired wide IO + */ +uint16_t lpc_wideio_size(int index); +/** + * @brief Identify if any LPC wide IO is covering the IO range + * + * @param start = start of IO range + * @param size = size of IO range + * + * @return Index of wide IO covering the range or error + */ +int lpc_find_wideio_range(uint16_t start, uint16_t size); +/** + * @brief Program a LPC wide IO to support an IO range + * + * @param start = start of range to be routed through wide IO + * @param size = size of range to be routed through wide IO + * + * @return Index of wide IO register used or error + */ +int lpc_set_wideio_range(uint16_t start, uint16_t size); + +uintptr_t lpc_get_spibase(void); +void lpc_set_spibase(uint32_t base, uint32_t enable); + +#endif /* __AMDBLOCKS_LPC_H__ */ diff --git a/src/soc/amd/common/block/lpc/Kconfig b/src/soc/amd/common/block/lpc/Kconfig new file mode 100644 index 0000000..b0d59a5 --- /dev/null +++ b/src/soc/amd/common/block/lpc/Kconfig @@ -0,0 +1,5 @@ +config SOC_AMD_COMMON_BLOCK_LPC + bool + default n + help + Select this option to use the traditional LPC-ISA bridge at D14F3. diff --git a/src/soc/amd/common/block/lpc/Makefile.inc b/src/soc/amd/common/block/lpc/Makefile.inc new file mode 100644 index 0000000..72b1e42 --- /dev/null +++ b/src/soc/amd/common/block/lpc/Makefile.inc @@ -0,0 +1,8 @@ +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc.c + +bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +verstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +postcar-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c diff --git a/src/soc/amd/stoneyridge/lpc.c b/src/soc/amd/common/block/lpc/lpc.c similarity index 94% rename from src/soc/amd/stoneyridge/lpc.c rename to src/soc/amd/common/block/lpc/lpc.c index 1741e92..8285b58 100644 --- a/src/soc/amd/stoneyridge/lpc.c +++ b/src/soc/amd/common/block/lpc/lpc.c @@ -28,15 +28,21 @@ #include <pc80/i8254.h> #include <pc80/i8259.h> #include <amdblocks/acpimmio.h> +#include <amdblocks/lpc.h> #include <soc/acpi.h> -#include <soc/pci_devs.h> #include <soc/southbridge.h> #include <soc/nvs.h> +#include <soc/iomap.h> + +/* Most systems should have already enabled the bridge */ +void __weak late_lpc_bridge_enable(void) { }
static void lpc_init(struct device *dev) { u8 byte;
+ late_lpc_bridge_enable(); + /* Initialize isa dma */ isa_dma_init();
@@ -64,8 +70,8 @@ pci_write_config8(dev, LPC_MISC_CONTROL_BITS, byte);
/* - * Enable hand-instance of the pulse generator and SPI - * controller prefetch of flash. + * Enable hand-instance of the pulse generator and SPI prefetch from + * host (earlier is recommended for boot speed). */ byte = pci_read_config8(dev, LPC_HOST_CONTROL); byte |= PREFETCH_EN_SPI_FROM_HOST | T_START_ENH; @@ -247,9 +253,9 @@ break; default: rsize = 0; - wideio_index = sb_find_wideio_range(base, res->size); + wideio_index = lpc_find_wideio_range(base, res->size); if (wideio_index != WIDEIO_RANGE_ERROR) { - rsize = sb_wideio_size(wideio_index); + rsize = lpc_wideio_size(wideio_index); printk(BIOS_DEBUG, "Covered by wideIO"); printk(BIOS_DEBUG, " %d\n", wideio_index); } @@ -260,7 +266,7 @@ *reg_x |= set_x; /* check if we can fit resource in variable range */ } else { - wideio_index = sb_set_wideio_range(base, res->size); + wideio_index = lpc_set_wideio_range(base, res->size); if (wideio_index != WIDEIO_RANGE_ERROR) { /* preserve wide IO related bits. */ *reg_x = pci_read_config32(dev, diff --git a/src/soc/amd/common/block/lpc/lpc_util.c b/src/soc/amd/common/block/lpc/lpc_util.c new file mode 100644 index 0000000..436eb15 --- /dev/null +++ b/src/soc/amd/common/block/lpc/lpc_util.c @@ -0,0 +1,308 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010-2017 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdint.h> +#include <device/device.h> +#include <device/pci_ops.h> +#include <device/pci_def.h> +#include <amdblocks/lpc.h> +#include <soc/iomap.h> +#include <soc/southbridge.h> + +/* The LPC-ISA bridge is always at D14F3 */ +#if !defined(__SIMPLE_DEVICE__) +#include <device/device.h> +#define _LPCB_DEV pcidev_on_root(0x14, 0x3) +#else +#define _LPCB_DEV PCI_DEV(0, 0x14, 0x3) +#endif + +/* + * Structure to simplify code obtaining the total of used wide IO + * registers and the size assigned to each. + */ +static struct wide_io_ioport_and_bits { + uint32_t enable; + uint16_t port; + uint8_t alt; +} wio_io_en[TOTAL_WIDEIO_PORTS] = { + { + LPC_WIDEIO0_ENABLE, + LPC_WIDEIO_GENERIC_PORT, + LPC_ALT_WIDEIO0_ENABLE + }, + { + LPC_WIDEIO1_ENABLE, + LPC_WIDEIO1_GENERIC_PORT, + LPC_ALT_WIDEIO1_ENABLE + }, + { + LPC_WIDEIO2_ENABLE, + LPC_WIDEIO2_GENERIC_PORT, + LPC_ALT_WIDEIO2_ENABLE + } +}; + +/** + * @brief Find the size of a particular wide IO + * + * @param index = index of desired wide IO + * + * @return size of desired wide IO + */ +uint16_t lpc_wideio_size(int index) +{ + uint32_t enable_register; + uint16_t size = 0; + uint8_t alternate_register; + + if (index >= TOTAL_WIDEIO_PORTS) + return size; + enable_register = pci_read_config32(_LPCB_DEV, + LPC_IO_OR_MEM_DECODE_ENABLE); + alternate_register = pci_read_config8(_LPCB_DEV, + LPC_ALT_WIDEIO_RANGE_ENABLE); + if (enable_register & wio_io_en[index].enable) + size = (alternate_register & wio_io_en[index].alt) ? + 16 : 512; + return size; +} + +/** + * @brief Identify if any LPC wide IO is covering the IO range + * + * @param start = start of IO range + * @param size = size of IO range + * + * @return Index of wide IO covering the range or error + */ +int lpc_find_wideio_range(uint16_t start, uint16_t size) +{ + int i, index = WIDEIO_RANGE_ERROR; + uint16_t end, current_size, start_wideio, end_wideio; + + end = start + size; + for (i = 0; i < TOTAL_WIDEIO_PORTS; i++) { + current_size = lpc_wideio_size(i); + if (current_size == 0) + continue; + start_wideio = pci_read_config16(_LPCB_DEV, + wio_io_en[i].port); + end_wideio = start_wideio + current_size; + if ((start >= start_wideio) && (end <= end_wideio)) { + index = i; + break; + } + } + return index; +} + +/** + * @brief Program a LPC wide IO to support an IO range + * + * @param start = start of range to be routed through wide IO + * @param size = size of range to be routed through wide IO + * + * @return Index of wide IO register used or error + */ +int lpc_set_wideio_range(uint16_t start, uint16_t size) +{ + int i, index = WIDEIO_RANGE_ERROR; + uint32_t enable_register; + uint8_t alternate_register; + + enable_register = pci_read_config32(_LPCB_DEV, + LPC_IO_OR_MEM_DECODE_ENABLE); + alternate_register = pci_read_config8(_LPCB_DEV, + LPC_ALT_WIDEIO_RANGE_ENABLE); + for (i = 0; i < TOTAL_WIDEIO_PORTS; i++) { + if (enable_register & wio_io_en[i].enable) + continue; + index = i; + pci_write_config16(_LPCB_DEV, wio_io_en[i].port, start); + enable_register |= wio_io_en[i].enable; + pci_write_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, + enable_register); + if (size <= 16) + alternate_register |= wio_io_en[i].alt; + else + alternate_register &= ~wio_io_en[i].alt; + pci_write_config8(_LPCB_DEV, + LPC_ALT_WIDEIO_RANGE_ENABLE, + alternate_register); + break; + } + return index; +} + +void lpc_enable_port80(void) +{ + u8 byte; + + byte = pci_read_config8(_LPCB_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH); + byte |= DECODE_IO_PORT_ENABLE4_H; + pci_write_config8(_LPCB_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH, byte); +} + +void lpc_enable_pci_port80(void) +{ + u8 byte; + + byte = pci_read_config8(_LPCB_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH); + byte &= ~DECODE_IO_PORT_ENABLE4_H; /* disable lpc port 80 */ + pci_write_config8(_LPCB_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH, byte); +} + +void lpc_enable_decode(uint32_t decodes) +{ + pci_write_config32(_LPCB_DEV, LPC_IO_PORT_DECODE_ENABLE, decodes); +} + +uintptr_t lpc_spibase(void) +{ + u32 base, enables; + + /* Make sure the base address is predictable */ + base = pci_read_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER); + enables = base & SPI_PRESERVE_BITS; + base &= ~(SPI_PRESERVE_BITS | SPI_BASE_RESERVED); + + if (!base) { + base = SPI_BASE_ADDRESS; + pci_write_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER, + base | enables | SPI_ROM_ENABLE); + /* PCI_COMMAND_MEMORY is read-only and enabled. */ + } + return (uintptr_t)base; +} + +/* + * Enable FCH to decode TPM associated Memory and IO regions + * + * Enable decoding of TPM cycles defined in TPM 1.2 spec + * Enable decoding of legacy TPM addresses: IO addresses 0x7f- + * 0x7e and 0xef-0xee. + * This function should be called if TPM is connected in any way to the FCH and + * conforms to the regions decoded. + * Absent any other routing configuration the TPM cycles will be claimed by the + * LPC bus + */ +void lpc_tpm_decode(void) +{ + u32 value; + + value = pci_read_config32(_LPCB_DEV, LPC_TRUSTED_PLATFORM_MODULE); + value |= TPM_12_EN | TPM_LEGACY_EN; + pci_write_config32(_LPCB_DEV, LPC_TRUSTED_PLATFORM_MODULE, value); +} + +/* + * Enable FCH to decode TPM associated Memory and IO regions to SPI + * + * This should be used if TPM is connected to SPI bus. + * Assumes SPI address space is already configured via a call to lpc_spibase(). + */ +void lpc_tpm_decode_spi(void) +{ + /* Enable TPM decoding to FCH */ + lpc_tpm_decode(); + + /* Route TPM accesses to SPI */ + u32 spibase = pci_read_config32(_LPCB_DEV, + SPIROM_BASE_ADDRESS_REGISTER); + pci_write_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER, spibase + | ROUTE_TPM_2_SPI); +} + +/* + * Enable 4MB (LPC) ROM access at 0xFFC00000 - 0xFFFFFFFF. + * + * Hardware should enable LPC ROM by pin straps. This function does not + * handle the theoretically possible PCI ROM, FWH, or SPI ROM configurations. + * + * The southbridge power-on default is to map 512K ROM space. + * + */ +void lpc_enable_rom(void) +{ + u8 reg8; + + /* + * Decode variable LPC ROM address ranges 1 and 2. + * Bits 3-4 are not defined in any publicly available datasheet + */ + reg8 = pci_read_config8(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE); + reg8 |= (1 << 3) | (1 << 4); + pci_write_config8(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, reg8); + + /* + * LPC ROM address range 1: + * Enable LPC ROM range mirroring start at 0x000e(0000). + */ + pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE1_START, 0x000e); + + /* Enable LPC ROM range mirroring end at 0x000f(ffff). */ + pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE1_END, 0x000f); + + /* + * LPC ROM address range 2: + * + * Enable LPC ROM range start at: + * 0xfff8(0000): 512KB + * 0xfff0(0000): 1MB + * 0xffe0(0000): 2MB + * 0xffc0(0000): 4MB + */ + pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE2_START, 0x10000 + - (CONFIG_COREBOOT_ROMSIZE_KB >> 6)); + + /* Enable LPC ROM range end at 0xffff(ffff). */ + pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE2_END, 0xffff); +} + +void lpc_enable_spi_prefetch(void) +{ + uint32_t dword; + + dword = pci_read_config32(_LPCB_DEV, LPC_ROM_DMA_EC_HOST_CONTROL); + dword |= SPI_FROM_HOST_PREFETCH_EN | SPI_FROM_USB_PREFETCH_EN; + pci_write_config32(_LPCB_DEV, LPC_ROM_DMA_EC_HOST_CONTROL, dword); +} + +uintptr_t lpc_get_spibase(void) +{ + u32 base; + + base = pci_read_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER); + base = ALIGN_DOWN(base, SPI_BASE_ALIGNMENT); + return (uintptr_t)base; +} + +void lpc_set_spibase(u32 base, u32 enable) +{ + u32 reg32; + + /* only two types of CS# enables are allowed */ + enable &= SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE; + + reg32 = pci_read_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER); + + reg32 &= SPI_BASE_ALIGNMENT - 1; /* preserve only reserved, enables */ + reg32 &= ~(SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE); + reg32 |= enable; + reg32 |= ALIGN_DOWN(base, SPI_BASE_ALIGNMENT); + + pci_write_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER, reg32); +} diff --git a/src/soc/amd/stoneyridge/Kconfig b/src/soc/amd/stoneyridge/Kconfig index 5333f59..ef7a7ae 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -48,6 +48,7 @@ select SOC_AMD_COMMON_BLOCK select SOC_AMD_COMMON_BLOCK_ACPIMMIO select SOC_AMD_COMMON_BLOCK_BANKED_GPIOS + select SOC_AMD_COMMON_BLOCK_LPC select SOC_AMD_COMMON_BLOCK_PCI select SOC_AMD_COMMON_BLOCK_PI select SOC_AMD_COMMON_BLOCK_PSP diff --git a/src/soc/amd/stoneyridge/Makefile.inc b/src/soc/amd/stoneyridge/Makefile.inc index 68dba09..e235ada 100644 --- a/src/soc/amd/stoneyridge/Makefile.inc +++ b/src/soc/amd/stoneyridge/Makefile.inc @@ -104,7 +104,6 @@ ramstage-y += monotonic_timer.c ramstage-y += southbridge.c ramstage-y += sb_util.c -ramstage-y += lpc.c ramstage-y += northbridge.c ramstage-y += pmutil.c ramstage-y += reset.c diff --git a/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl b/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl index 15e4d2f..e81f29d 100644 --- a/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl +++ b/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl @@ -51,7 +51,7 @@ /* 0:14.2 - I2S Audio */
/* 0:14.3 - LPC */ -#include "lpc.asl" +#include <soc/amd/common/acpi/lpc.asl>
/* 0:14.7 - SD Controller */ Device(SDCN) { diff --git a/src/soc/amd/stoneyridge/include/soc/southbridge.h b/src/soc/amd/stoneyridge/include/soc/southbridge.h index 4688ee3..aa0e783 100644 --- a/src/soc/amd/stoneyridge/include/soc/southbridge.h +++ b/src/soc/amd/stoneyridge/include/soc/southbridge.h @@ -256,123 +256,8 @@ #define GPE0_LIMIT 28 #define TOTAL_BITS(a) (8 * sizeof(a))
-/* - * PCI Config Space Definitions - */ - -/* ISA Bridge D14F3 */ -#define LPC_PCI_CONTROL 0x40 -#define LEGACY_DMA_EN BIT(2) - -#define LPC_IO_PORT_DECODE_ENABLE 0x44 -#define DECODE_ENABLE_PARALLEL_PORT0 BIT(0) -#define DECODE_ENABLE_PARALLEL_PORT1 BIT(1) -#define DECODE_ENABLE_PARALLEL_PORT2 BIT(2) -#define DECODE_ENABLE_PARALLEL_PORT3 BIT(3) -#define DECODE_ENABLE_PARALLEL_PORT4 BIT(4) -#define DECODE_ENABLE_PARALLEL_PORT5 BIT(5) -#define DECODE_ENABLE_SERIAL_PORT0 BIT(6) -#define DECODE_ENABLE_SERIAL_PORT1 BIT(7) -#define DECODE_ENABLE_SERIAL_PORT2 BIT(8) -#define DECODE_ENABLE_SERIAL_PORT3 BIT(9) -#define DECODE_ENABLE_SERIAL_PORT4 BIT(10) -#define DECODE_ENABLE_SERIAL_PORT5 BIT(11) -#define DECODE_ENABLE_SERIAL_PORT6 BIT(12) -#define DECODE_ENABLE_SERIAL_PORT7 BIT(13) -#define DECODE_ENABLE_AUDIO_PORT0 BIT(14) -#define DECODE_ENABLE_AUDIO_PORT1 BIT(15) -#define DECODE_ENABLE_AUDIO_PORT2 BIT(16) -#define DECODE_ENABLE_AUDIO_PORT3 BIT(17) -#define DECODE_ENABLE_MIDI_PORT0 BIT(18) -#define DECODE_ENABLE_MIDI_PORT1 BIT(19) -#define DECODE_ENABLE_MIDI_PORT2 BIT(20) -#define DECODE_ENABLE_MIDI_PORT3 BIT(21) -#define DECODE_ENABLE_MSS_PORT0 BIT(22) -#define DECODE_ENABLE_MSS_PORT1 BIT(23) -#define DECODE_ENABLE_MSS_PORT2 BIT(24) -#define DECODE_ENABLE_MSS_PORT3 BIT(25) -#define DECODE_ENABLE_FDC_PORT0 BIT(26) -#define DECODE_ENABLE_FDC_PORT1 BIT(27) -#define DECODE_ENABLE_GAME_PORT BIT(28) -#define DECODE_ENABLE_KBC_PORT BIT(29) -#define DECODE_ENABLE_ACPIUC_PORT BIT(30) -#define DECODE_ENABLE_ADLIB_PORT BIT(31) - -#define LPC_IO_OR_MEM_DECODE_ENABLE 0x48 -#define LPC_WIDEIO2_ENABLE BIT(25) -#define LPC_WIDEIO1_ENABLE BIT(24) -#define DECODE_IO_PORT_ENABLE6 BIT(23) -#define DECODE_IO_PORT_ENABLE5 BIT(22) -#define DECODE_IO_PORT_ENABLE4 BIT(21) -#define DECODE_MEM_PORT_ENABLE1 BIT(20) -#define DECODE_IO_PORT_ENABLE3 BIT(19) -#define DECODE_IO_PORT_ENABLE2 BIT(18) -#define DECODE_IO_PORT_ENABLE1 BIT(17) -#define DECODE_IO_PORT_ENABLE0 BIT(16) -#define LPC_SYNC_TIMEOUT_COUNT_ENABLE BIT(7) -#define LPC_DECODE_RTC_IO_ENABLE BIT(6) -#define DECODE_MEM_PORT_ENABLE0 BIT(5) -#define LPC_WIDEIO0_ENABLE BIT(2) -#define DECODE_ALTERNATE_SIO_ENABLE BIT(1) -#define DECODE_SIO_ENABLE BIT(0) -#define WIDEIO_RANGE_ERROR -1 -#define TOTAL_WIDEIO_PORTS 3 - -/* Assuming word access to higher word (register 0x4a) */ -#define LPC_IO_OR_MEM_DEC_EN_HIGH 0x4a -#define LPC_WIDEIO2_ENABLE_H BIT(9) -#define LPC_WIDEIO1_ENABLE_H BIT(8) -#define DECODE_IO_PORT_ENABLE6_H BIT(7) -#define DECODE_IO_PORT_ENABLE5_H BIT(6) -#define DECODE_IO_PORT_ENABLE4_H BIT(5) -#define DECODE_IO_PORT_ENABLE3_H BIT(3) -#define DECODE_IO_PORT_ENABLE2_H BIT(2) -#define DECODE_IO_PORT_ENABLE1_H BIT(1) -#define DECODE_IO_PORT_ENABLE0_H BIT(0) - -#define LPC_MEM_PORT1 0x4c -#define LPC_MEM_PORT0 0x60 - -/* Register 0x64 is 32-bit, composed by two 16-bit sub-registers. - For ease of access, each sub-register is declared separetely. */ -#define LPC_WIDEIO_GENERIC_PORT 0x64 -#define LPC_WIDEIO1_GENERIC_PORT 0x66 -#define ROM_ADDRESS_RANGE1_START 0x68 -#define ROM_ADDRESS_RANGE1_END 0x6a -#define ROM_ADDRESS_RANGE2_START 0x6c -#define ROM_ADDRESS_RANGE2_END 0x6e - -#define LPC_ALT_WIDEIO_RANGE_ENABLE 0x74 -#define LPC_ALT_WIDEIO2_ENABLE BIT(3) -#define LPC_ALT_WIDEIO1_ENABLE BIT(2) -#define LPC_ALT_WIDEIO0_ENABLE BIT(0) - -#define LPC_MISC_CONTROL_BITS 0x78 -#define LPC_NOHOG BIT(0) - -#define LPC_TRUSTED_PLATFORM_MODULE 0x7c -#define TPM_12_EN BIT(0) -#define TPM_LEGACY_EN BIT(2) - -#define LPC_WIDEIO2_GENERIC_PORT 0x90 - -#define SPIROM_BASE_ADDRESS_REGISTER 0xa0 +/* ISA Bridge SPI BASE at D14F3xA0 */ #define SPI_BASE_ALIGNMENT 32 -#define ROUTE_TPM_2_SPI BIT(3) -#define SPI_ABORT_ENABLE BIT(2) -#define SPI_ROM_ENABLE BIT(1) -#define SPI_ROM_ALT_ENABLE BIT(0) - -/* LPC register 0xb8 is DWORD, here there are definitions for byte - access. For example, bits 31-24 are accessed through byte access - at register 0xbb. */ -#define LPC_ROM_DMA_EC_HOST_CONTROL 0xb8 -#define SPI_FROM_HOST_PREFETCH_EN BIT(24) -#define SPI_FROM_USB_PREFETCH_EN BIT(23) - -#define LPC_HOST_CONTROL 0xbb -#define PREFETCH_EN_SPI_FROM_HOST BIT(0) -#define T_START_ENH BIT(3)
/* SPI Controller (base address in D14F3xA0) */ #define SPI_CNTRL0 0x00 @@ -474,21 +359,13 @@ #define XHCI_FW_BOOTRAM_SIZE 0x8000
void enable_aoac_devices(void); -void sb_enable_rom(void); void sb_clk_output_48Mhz(u32 osc); void sb_disable_4dw_burst(void); void sb_enable(struct device *dev); void southbridge_final(void *chip_info); void southbridge_init(void *chip_info); -void sb_lpc_port80(void); -void sb_lpc_decode(void); -void sb_pci_port80(void); void sb_read_mode(u32 mode); void sb_set_spi100(u16 norm, u16 fast, u16 alt, u16 tpm); -void sb_tpm_decode(void); -void sb_tpm_decode_spi(void); -void lpc_wideio_512_window(uint16_t base); -void lpc_wideio_16_window(uint16_t base); uint16_t pm_acpi_pm_cnt_blk(void); uint16_t pm_acpi_pm_evt_blk(void); void bootblock_fch_early_init(void); @@ -525,33 +402,6 @@ * @return 64bit base address */ uint64_t get_uma_base(void); -/** - * @brief Find the size of a particular wide IO - * - * @param index = index of desired wide IO - * - * @return size of desired wide IO - */ -uint16_t sb_wideio_size(int index); -/** - * @brief Identify if any LPC wide IO is covering the IO range - * - * @param start = start of IO range - * @param size = size of IO range - * - * @return Index of wide IO covering the range or error - */ -int sb_find_wideio_range(uint16_t start, uint16_t size); -/** - * @brief Program a LPC wide IO to support an IO range - * - * @param start = start of range to be routed through wide IO - * @param size = size of range to be routed through wide IO - * - * @return Index of wide IO register used or error - */ -int sb_set_wideio_range(uint16_t start, uint16_t size); - /* * Call the mainboard to get the USB Over Current Map. The mainboard * returns the map and 0 on Success or -1 on error or no map. There is diff --git a/src/soc/amd/stoneyridge/southbridge.c b/src/soc/amd/stoneyridge/southbridge.c index 3b14a9a..f86e4a9 100644 --- a/src/soc/amd/stoneyridge/southbridge.c +++ b/src/soc/amd/stoneyridge/southbridge.c @@ -29,6 +29,7 @@ #include <amdblocks/agesawrapper.h> #include <amdblocks/reset.h> #include <amdblocks/acpimmio.h> +#include <amdblocks/lpc.h> #include <soc/southbridge.h> #include <soc/smbus.h> #include <soc/smi.h> @@ -153,130 +154,12 @@ { PIRQ_UART1, "UART1" }, };
-/* - * Structure to simplify code obtaining the total of used wide IO - * registers and the size assigned to each. - */ -static struct wide_io_ioport_and_bits { - uint32_t enable; - uint16_t port; - uint8_t alt; -} wio_io_en[TOTAL_WIDEIO_PORTS] = { - { - LPC_WIDEIO0_ENABLE, - LPC_WIDEIO_GENERIC_PORT, - LPC_ALT_WIDEIO0_ENABLE - }, - { - LPC_WIDEIO1_ENABLE, - LPC_WIDEIO1_GENERIC_PORT, - LPC_ALT_WIDEIO1_ENABLE - }, - { - LPC_WIDEIO2_ENABLE, - LPC_WIDEIO2_GENERIC_PORT, - LPC_ALT_WIDEIO2_ENABLE - } -}; - const struct irq_idx_name *sb_get_apic_reg_association(size_t *size) { *size = ARRAY_SIZE(irq_association); return irq_association; }
-/** - * @brief Find the size of a particular wide IO - * - * @param index = index of desired wide IO - * - * @return size of desired wide IO - */ -uint16_t sb_wideio_size(int index) -{ - uint32_t enable_register; - uint16_t size = 0; - uint8_t alternate_register; - - if (index >= TOTAL_WIDEIO_PORTS) - return size; - enable_register = pci_read_config32(SOC_LPC_DEV, - LPC_IO_OR_MEM_DECODE_ENABLE); - alternate_register = pci_read_config8(SOC_LPC_DEV, - LPC_ALT_WIDEIO_RANGE_ENABLE); - if (enable_register & wio_io_en[index].enable) - size = (alternate_register & wio_io_en[index].alt) ? - 16 : 512; - return size; -} - -/** - * @brief Identify if any LPC wide IO is covering the IO range - * - * @param start = start of IO range - * @param size = size of IO range - * - * @return Index of wide IO covering the range or error - */ -int sb_find_wideio_range(uint16_t start, uint16_t size) -{ - int i, index = WIDEIO_RANGE_ERROR; - uint16_t end, current_size, start_wideio, end_wideio; - - end = start + size; - for (i = 0; i < TOTAL_WIDEIO_PORTS; i++) { - current_size = sb_wideio_size(i); - if (current_size == 0) - continue; - start_wideio = pci_read_config16(SOC_LPC_DEV, - wio_io_en[i].port); - end_wideio = start_wideio + current_size; - if ((start >= start_wideio) && (end <= end_wideio)) { - index = i; - break; - } - } - return index; -} - -/** - * @brief Program a LPC wide IO to support an IO range - * - * @param start = start of range to be routed through wide IO - * @param size = size of range to be routed through wide IO - * - * @return Index of wide IO register used or error - */ -int sb_set_wideio_range(uint16_t start, uint16_t size) -{ - int i, index = WIDEIO_RANGE_ERROR; - uint32_t enable_register; - uint8_t alternate_register; - - enable_register = pci_read_config32(SOC_LPC_DEV, - LPC_IO_OR_MEM_DECODE_ENABLE); - alternate_register = pci_read_config8(SOC_LPC_DEV, - LPC_ALT_WIDEIO_RANGE_ENABLE); - for (i = 0; i < TOTAL_WIDEIO_PORTS; i++) { - if (enable_register & wio_io_en[i].enable) - continue; - index = i; - pci_write_config16(SOC_LPC_DEV, wio_io_en[i].port, start); - enable_register |= wio_io_en[i].enable; - pci_write_config32(SOC_LPC_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, - enable_register); - if (size <= 16) - alternate_register |= wio_io_en[i].alt; - else - alternate_register &= ~wio_io_en[i].alt; - pci_write_config8(SOC_LPC_DEV, - LPC_ALT_WIDEIO_RANGE_ENABLE, - alternate_register); - break; - } - return index; -} - static void power_on_aoac_device(int aoac_device_control_register) { uint8_t byte; @@ -316,16 +199,7 @@ } while (!status); }
-void sb_pci_port80(void) -{ - u8 byte; - - byte = pci_read_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH); - byte &= ~DECODE_IO_PORT_ENABLE4_H; /* disable lpc port 80 */ - pci_write_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH, byte); -} - -void sb_lpc_port80(void) +static void sb_enable_lpc(void) { u8 byte;
@@ -333,14 +207,9 @@ byte = pm_io_read8(PM_LPC_GATING); byte |= PM_LPC_ENABLE; pm_io_write8(PM_LPC_GATING, byte); - - /* Enable port 80 LPC decode in pci function 3 configuration space. */ - byte = pci_read_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH); - byte |= DECODE_IO_PORT_ENABLE4_H; /* enable port 80 */ - pci_write_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH, byte); }
-void sb_lpc_decode(void) +static void sb_lpc_decode(void) { u32 tmp = 0;
@@ -358,7 +227,11 @@ | DECODE_ENABLE_KBC_PORT | DECODE_ENABLE_ACPIUC_PORT | DECODE_ENABLE_ADLIB_PORT;
- pci_write_config32(SOC_LPC_DEV, LPC_IO_PORT_DECODE_ENABLE, tmp); + /* Decode SIOs at 2E/2F and 4E/4F */ + if (CONFIG(STONEYRIDGE_LEGACY_FREE)) + tmp |= DECODE_ALTERNATE_SIO_ENABLE | DECODE_SIO_ENABLE; + + lpc_enable_decode(tmp); }
static void sb_enable_cf9_io(void) @@ -398,41 +271,15 @@ misc_write32(MISC_CLK_CNTL1, ctrl); }
-static uintptr_t sb_get_spibase(void) -{ - u32 base; - - base = pci_read_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER); - base = ALIGN_DOWN(base, SPI_BASE_ALIGNMENT); - return (uintptr_t)base; -} - -static void sb_set_spibase(u32 base, u32 enable) -{ - u32 reg32; - - /* only two types of CS# enables are allowed */ - enable &= SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE; - - reg32 = pci_read_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER); - - reg32 &= SPI_BASE_ALIGNMENT - 1; /* preserve only reserved, enables */ - reg32 &= ~(SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE); - reg32 |= enable; - reg32 |= ALIGN_DOWN(base, SPI_BASE_ALIGNMENT); - - pci_write_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER, reg32); -} - static uintptr_t sb_init_spi_base(void) { u32 base;
/* Make sure the base address is predictable */ - base = sb_get_spibase(); + base = lpc_get_spibase();
if (!base) - sb_set_spibase(SPI_BASE_ADDRESS, SPI_ROM_ENABLE); + lpc_set_spibase(SPI_BASE_ADDRESS, SPI_ROM_ENABLE);
return (uintptr_t)base; } @@ -465,109 +312,6 @@ & ~SPI_READ_MODE_MASK) | mode); }
-/* - * Enable FCH to decode TPM associated Memory and IO regions - * - * Enable decoding of TPM cycles defined in TPM 1.2 spec - * Enable decoding of legacy TPM addresses: IO addresses 0x7f- - * 0x7e and 0xef-0xee. - * This function should be called if TPM is connected in any way to the FCH and - * conforms to the regions decoded. - * Absent any other routing configuration the TPM cycles will be claimed by the - * LPC bus - */ -void sb_tpm_decode(void) -{ - u32 value; - - value = pci_read_config32(SOC_LPC_DEV, LPC_TRUSTED_PLATFORM_MODULE); - value |= TPM_12_EN | TPM_LEGACY_EN; - pci_write_config32(SOC_LPC_DEV, LPC_TRUSTED_PLATFORM_MODULE, value); -} - -/* - * Enable FCH to decode TPM associated Memory and IO regions to SPI - * - * This should be used if TPM is connected to SPI bus. - * Assumes SPI address space is already configured. - */ -void sb_tpm_decode_spi(void) -{ - /* Enable TPM decoding to FCH */ - sb_tpm_decode(); - - /* Route TPM accesses to SPI */ - u32 spibase = pci_read_config32(SOC_LPC_DEV, - SPIROM_BASE_ADDRESS_REGISTER); - pci_write_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER, spibase - | ROUTE_TPM_2_SPI); -} - -/* - * Enable 4MB (LPC) ROM access at 0xFFC00000 - 0xFFFFFFFF. - * - * Hardware should enable LPC ROM by pin straps. This function does not - * handle the theoretically possible PCI ROM, FWH, or SPI ROM configurations. - * - * The southbridge power-on default is to map 512K ROM space. - * - */ -void sb_enable_rom(void) -{ - u8 reg8; - - /* - * Decode variable LPC ROM address ranges 1 and 2. - * Bits 3-4 are not defined in any publicly available datasheet - */ - reg8 = pci_read_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DECODE_ENABLE); - reg8 |= (1 << 3) | (1 << 4); - pci_write_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, reg8); - - /* - * LPC ROM address range 1: - * Enable LPC ROM range mirroring start at 0x000e(0000). - */ - pci_write_config16(SOC_LPC_DEV, ROM_ADDRESS_RANGE1_START, 0x000e); - - /* Enable LPC ROM range mirroring end at 0x000f(ffff). */ - pci_write_config16(SOC_LPC_DEV, ROM_ADDRESS_RANGE1_END, 0x000f); - - /* - * LPC ROM address range 2: - * - * Enable LPC ROM range start at: - * 0xfff8(0000): 512KB - * 0xfff0(0000): 1MB - * 0xffe0(0000): 2MB - * 0xffc0(0000): 4MB - */ - pci_write_config16(SOC_LPC_DEV, ROM_ADDRESS_RANGE2_START, 0x10000 - - (CONFIG_COREBOOT_ROMSIZE_KB >> 6)); - - /* Enable LPC ROM range end at 0xffff(ffff). */ - pci_write_config16(SOC_LPC_DEV, ROM_ADDRESS_RANGE2_END, 0xffff); -} - -static void sb_lpc_early_setup(void) -{ - uint32_t dword; - - /* Enable SPI prefetch */ - dword = pci_read_config32(SOC_LPC_DEV, LPC_ROM_DMA_EC_HOST_CONTROL); - dword |= SPI_FROM_HOST_PREFETCH_EN | SPI_FROM_USB_PREFETCH_EN; - pci_write_config32(SOC_LPC_DEV, LPC_ROM_DMA_EC_HOST_CONTROL, dword); - - if (CONFIG(STONEYRIDGE_LEGACY_FREE)) { - /* Decode SIOs at 2E/2F and 4E/4F */ - dword = pci_read_config32(SOC_LPC_DEV, - LPC_IO_OR_MEM_DECODE_ENABLE); - dword |= DECODE_ALTERNATE_SIO_ENABLE | DECODE_SIO_ENABLE; - pci_write_config32(SOC_LPC_DEV, - LPC_IO_OR_MEM_DECODE_ENABLE, dword); - } -} - static void setup_spread_spectrum(int *reboot) { uint16_t rstcfg = pm_read16(PWR_RESET_CFG); @@ -650,10 +394,11 @@ { int reboot = 0;
- sb_enable_rom(); - sb_lpc_port80(); + lpc_enable_rom(); + sb_enable_lpc(); + lpc_enable_port80(); sb_lpc_decode(); - sb_lpc_early_setup(); + lpc_enable_spi_prefetch(); sb_init_spi_base(); sb_disable_4dw_burst(); /* Must be disabled on CZ(ST) */ enable_acpimmio_decode(); diff --git a/src/soc/amd/stoneyridge/spi.c b/src/soc/amd/stoneyridge/spi.c index c682d98..8abfa16 100644 --- a/src/soc/amd/stoneyridge/spi.c +++ b/src/soc/amd/stoneyridge/spi.c @@ -26,6 +26,7 @@ #include <device/pci.h> #include <device/pci_ops.h> #include <soc/southbridge.h> +#include <amdblocks/lpc.h> #include <soc/pci_devs.h>
#define SPI_DEBUG_DRIVER CONFIG(DEBUG_SPI_FLASH) @@ -103,11 +104,7 @@
void spi_init(void) { - uintptr_t bar; - - bar = pci_read_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER); - bar = ALIGN_DOWN(bar, 64); - set_spibar(bar); + set_spibar(lpc_get_spibase()); }
static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
Richard Spiegel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32653 )
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
Patch Set 2: Code-Review+2
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32653 )
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
Patch Set 4:
(4 comments)
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc.c File src/soc/amd/common/block/lpc/lpc.c:
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc.c@3... PS4, Line 38: late_lpc_bridge_enable If a function is supposed to be implemented by the SoC, it would be helpful to add _soc_ in its name and add a comment in the .h file indicating when it is supposed to be used/defined.
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... File src/soc/amd/common/block/lpc/lpc_util.c:
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... PS4, Line 36: struct const
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... PS4, Line 40: TOTAL_WIDEIO_PORTS Is this something that the SoC is supposed to provide? If this is always going to be 3, do we really need to get that from the SoC?
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... PS4, Line 188: (uintptr_t) Is this typecast necessary?
Hello Richard Spiegel, build bot (Jenkins), Furquan Shaikh, Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32653
to look at the new patch set (#5).
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
soc/amd/stoneyridge: Move LPC support to common
AMD devices traditionally have the LPC-ISA bus at 14.3 and the definition has been very consistent. Relocate the feature from stoneyridge into common/block.
BUG=b:131682806
Change-Id: I8d7175b8642bb17533bb2287b3e3ee3d52e85a75 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/ec.c R src/soc/amd/common/acpi/lpc.asl A src/soc/amd/common/block/include/amdblocks/lpc.h A src/soc/amd/common/block/lpc/Kconfig A src/soc/amd/common/block/lpc/Makefile.inc R src/soc/amd/common/block/lpc/lpc.c A src/soc/amd/common/block/lpc/lpc_util.c M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/Makefile.inc M src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl M src/soc/amd/stoneyridge/include/soc/southbridge.h M src/soc/amd/stoneyridge/southbridge.c M src/soc/amd/stoneyridge/spi.c 14 files changed, 533 insertions(+), 437 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/53/32653/5
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32653 )
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
Patch Set 5:
(4 comments)
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc.c File src/soc/amd/common/block/lpc/lpc.c:
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc.c@3... PS4, Line 38: late_lpc_bridge_enable
If a function is supposed to be implemented by the SoC, it would be helpful to add _soc_ in its name […]
Done
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... File src/soc/amd/common/block/lpc/lpc_util.c:
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... PS4, Line 36: struct
const
Done
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... PS4, Line 40: TOTAL_WIDEIO_PORTS
Is this something that the SoC is supposed to provide? If this is always going to be 3, do we really […]
It looks like that went in here https://review.coreboot.org/c/coreboot/+/22590, and I'd guess it was to make walking the array easier. However, I looked at a handful of BKDGs and docs for discrete FCHs, and I'm comfortable that it hasn't changed.
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... PS4, Line 188: (uintptr_t)
Is this typecast necessary?
Done
Richard Spiegel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32653 )
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
Patch Set 6:
(2 comments)
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... File src/soc/amd/common/block/lpc/lpc_util.c:
https://review.coreboot.org/#/c/32653/4/src/soc/amd/common/block/lpc/lpc_uti... PS4, Line 40: TOTAL_WIDEIO_PORTS
It looks like that went in here https://review.coreboot. […]
Yes, that is correct. I could have used wio_io_en[] and get the number of total wide IO from the structure number of elements... but this way makes the intention clear. At the time I created it, it was intended to stoneyridge only, but now Marshall is moving it to common. However, as Marshall mentioned, it has not changed for a while and might not change in the future. So far the max I have ever seen used were 2 wide IO registers, and I don't believe AMD will need to change that number any time soon.
https://review.coreboot.org/#/c/32653/6/src/soc/amd/stoneyridge/southbridge.... File src/soc/amd/stoneyridge/southbridge.c:
https://review.coreboot.org/#/c/32653/6/src/soc/amd/stoneyridge/southbridge.... PS6, Line 230: STONEYRIDGE_LEGACY_FREE Why dependency on legacy free? Couldn't we have a legacy board using external SIO?
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32653 )
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
Patch Set 6:
(1 comment)
https://review.coreboot.org/#/c/32653/6/src/soc/amd/stoneyridge/southbridge.... File src/soc/amd/stoneyridge/southbridge.c:
https://review.coreboot.org/#/c/32653/6/src/soc/amd/stoneyridge/southbridge.... PS6, Line 230: STONEYRIDGE_LEGACY_FREE
Why dependency on legacy free? Couldn't we have a legacy board using external SIO?
I don't disagree with your thinking, but this source is simply relocated from line 560.
It went into the code in https://review.coreboot.org/c/coreboot/+/25755 which you'd reviewed. The FCH AGESA code contains a LegacyFree configuration, which may be the original impetus for the symbol. (Now it looks like it's used primarily for setting the FADT properly.)
Given that Marc was pulling functionality from AGESA into coreboot in 25755, and I'm not modifying that behavior, I'd like to leave this here for now and consider a followon patch if we want to remove the if(CONFIG()).
Martin Roth has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32653 )
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
Patch Set 6: Code-Review+2
(1 comment)
https://review.coreboot.org/#/c/32653/6/src/soc/amd/stoneyridge/southbridge.... File src/soc/amd/stoneyridge/southbridge.c:
https://review.coreboot.org/#/c/32653/6/src/soc/amd/stoneyridge/southbridge.... PS6, Line 230: STONEYRIDGE_LEGACY_FREE
I don't disagree with your thinking, but this source is simply relocated from line 560. […]
I'm fine with fixing this in a follow-on commit. Isn't the logic here backwards though?
If the system is legacy free, why do we enable LPC decode if there's no SIO on the LPC?
Martin Roth has submitted this change and it was merged. ( https://review.coreboot.org/c/coreboot/+/32653 )
Change subject: soc/amd/stoneyridge: Move LPC support to common ......................................................................
soc/amd/stoneyridge: Move LPC support to common
AMD devices traditionally have the LPC-ISA bus at 14.3 and the definition has been very consistent. Relocate the feature from stoneyridge into common/block.
BUG=b:131682806
Change-Id: I8d7175b8642bb17533bb2287b3e3ee3d52e85a75 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com Reviewed-on: https://review.coreboot.org/c/coreboot/+/32653 Reviewed-by: Martin Roth martinroth@google.com Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/ec.c R src/soc/amd/common/acpi/lpc.asl A src/soc/amd/common/block/include/amdblocks/lpc.h A src/soc/amd/common/block/lpc/Kconfig A src/soc/amd/common/block/lpc/Makefile.inc R src/soc/amd/common/block/lpc/lpc.c A src/soc/amd/common/block/lpc/lpc_util.c M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/Makefile.inc M src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl M src/soc/amd/stoneyridge/include/soc/southbridge.h M src/soc/amd/stoneyridge/southbridge.c M src/soc/amd/stoneyridge/spi.c 14 files changed, 533 insertions(+), 437 deletions(-)
Approvals: build bot (Jenkins): Verified Martin Roth: Looks good to me, approved
diff --git a/src/mainboard/google/kahlee/bootblock/bootblock.c b/src/mainboard/google/kahlee/bootblock/bootblock.c index 3be308e..e403684 100644 --- a/src/mainboard/google/kahlee/bootblock/bootblock.c +++ b/src/mainboard/google/kahlee/bootblock/bootblock.c @@ -17,6 +17,7 @@ #include <bootblock_common.h> #include <soc/gpio.h> #include <soc/southbridge.h> +#include <amdblocks/lpc.h> #include <variant/ec.h> #include <variant/gpio.h>
@@ -61,5 +62,5 @@ }
/* Setup TPM decode before verstage */ - sb_tpm_decode_spi(); + lpc_tpm_decode_spi(); } diff --git a/src/mainboard/google/kahlee/ec.c b/src/mainboard/google/kahlee/ec.c index 7164591..1080902 100644 --- a/src/mainboard/google/kahlee/ec.c +++ b/src/mainboard/google/kahlee/ec.c @@ -16,6 +16,7 @@ #include <arch/acpi.h> #include <console/console.h> #include <ec/google/chromeec/ec.h> +#include <amdblocks/lpc.h> #include <soc/southbridge.h> #include <variant/ec.h>
@@ -49,7 +50,7 @@ printk(BIOS_DEBUG, "LPC Setup google_chromeec_ioport_range: %04x, %08zx\n", ec_ioport_base, ec_ioport_size); - status = sb_set_wideio_range(ec_ioport_base, ec_ioport_size); + status = lpc_set_wideio_range(ec_ioport_base, ec_ioport_size); if (status == WIDEIO_RANGE_ERROR) printk(BIOS_WARNING, "ERROR: Failed to assign a range\n"); else diff --git a/src/soc/amd/stoneyridge/acpi/lpc.asl b/src/soc/amd/common/acpi/lpc.asl similarity index 100% rename from src/soc/amd/stoneyridge/acpi/lpc.asl rename to src/soc/amd/common/acpi/lpc.asl diff --git a/src/soc/amd/common/block/include/amdblocks/lpc.h b/src/soc/amd/common/block/include/amdblocks/lpc.h new file mode 100644 index 0000000..7b33d7a --- /dev/null +++ b/src/soc/amd/common/block/include/amdblocks/lpc.h @@ -0,0 +1,176 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AMDBLOCKS_LPC_H__ +#define __AMDBLOCKS_LPC_H__ + +#include <types.h> + +/* PCI registers for D14F3 */ +#define LPC_PCI_CONTROL 0x40 +#define LEGACY_DMA_EN BIT(2) + +#define LPC_IO_PORT_DECODE_ENABLE 0x44 +#define DECODE_ENABLE_PARALLEL_PORT0 BIT(0) +#define DECODE_ENABLE_PARALLEL_PORT1 BIT(1) +#define DECODE_ENABLE_PARALLEL_PORT2 BIT(2) +#define DECODE_ENABLE_PARALLEL_PORT3 BIT(3) +#define DECODE_ENABLE_PARALLEL_PORT4 BIT(4) +#define DECODE_ENABLE_PARALLEL_PORT5 BIT(5) +#define DECODE_ENABLE_SERIAL_PORT0 BIT(6) +#define DECODE_ENABLE_SERIAL_PORT1 BIT(7) +#define DECODE_ENABLE_SERIAL_PORT2 BIT(8) +#define DECODE_ENABLE_SERIAL_PORT3 BIT(9) +#define DECODE_ENABLE_SERIAL_PORT4 BIT(10) +#define DECODE_ENABLE_SERIAL_PORT5 BIT(11) +#define DECODE_ENABLE_SERIAL_PORT6 BIT(12) +#define DECODE_ENABLE_SERIAL_PORT7 BIT(13) +#define DECODE_ENABLE_AUDIO_PORT0 BIT(14) +#define DECODE_ENABLE_AUDIO_PORT1 BIT(15) +#define DECODE_ENABLE_AUDIO_PORT2 BIT(16) +#define DECODE_ENABLE_AUDIO_PORT3 BIT(17) +#define DECODE_ENABLE_MIDI_PORT0 BIT(18) +#define DECODE_ENABLE_MIDI_PORT1 BIT(19) +#define DECODE_ENABLE_MIDI_PORT2 BIT(20) +#define DECODE_ENABLE_MIDI_PORT3 BIT(21) +#define DECODE_ENABLE_MSS_PORT0 BIT(22) +#define DECODE_ENABLE_MSS_PORT1 BIT(23) +#define DECODE_ENABLE_MSS_PORT2 BIT(24) +#define DECODE_ENABLE_MSS_PORT3 BIT(25) +#define DECODE_ENABLE_FDC_PORT0 BIT(26) +#define DECODE_ENABLE_FDC_PORT1 BIT(27) +#define DECODE_ENABLE_GAME_PORT BIT(28) +#define DECODE_ENABLE_KBC_PORT BIT(29) +#define DECODE_ENABLE_ACPIUC_PORT BIT(30) +#define DECODE_ENABLE_ADLIB_PORT BIT(31) + +#define LPC_IO_OR_MEM_DECODE_ENABLE 0x48 +#define LPC_WIDEIO2_ENABLE BIT(25) +#define LPC_WIDEIO1_ENABLE BIT(24) +#define DECODE_IO_PORT_ENABLE6 BIT(23) +#define DECODE_IO_PORT_ENABLE5 BIT(22) +#define DECODE_IO_PORT_ENABLE4 BIT(21) +#define DECODE_MEM_PORT_ENABLE1 BIT(20) +#define DECODE_IO_PORT_ENABLE3 BIT(19) +#define DECODE_IO_PORT_ENABLE2 BIT(18) +#define DECODE_IO_PORT_ENABLE1 BIT(17) +#define DECODE_IO_PORT_ENABLE0 BIT(16) +#define LPC_SYNC_TIMEOUT_COUNT_ENABLE BIT(7) +#define LPC_DECODE_RTC_IO_ENABLE BIT(6) +#define DECODE_MEM_PORT_ENABLE0 BIT(5) +#define LPC_WIDEIO0_ENABLE BIT(2) +#define DECODE_ALTERNATE_SIO_ENABLE BIT(1) +#define DECODE_SIO_ENABLE BIT(0) +#define WIDEIO_RANGE_ERROR -1 + +/* Assuming word access to higher word (register 0x4a) */ +#define LPC_IO_OR_MEM_DEC_EN_HIGH 0x4a +#define LPC_WIDEIO2_ENABLE_H BIT(9) +#define LPC_WIDEIO1_ENABLE_H BIT(8) +#define DECODE_IO_PORT_ENABLE6_H BIT(7) +#define DECODE_IO_PORT_ENABLE5_H BIT(6) +#define DECODE_IO_PORT_ENABLE4_H BIT(5) +#define DECODE_IO_PORT_ENABLE3_H BIT(3) +#define DECODE_IO_PORT_ENABLE2_H BIT(2) +#define DECODE_IO_PORT_ENABLE1_H BIT(1) +#define DECODE_IO_PORT_ENABLE0_H BIT(0) + +#define LPC_MEM_PORT1 0x4c +#define LPC_MEM_PORT0 0x60 + +/* Register 0x64 is 32-bit, composed by two 16-bit sub-registers. + For ease of access, each sub-register is declared separetely. */ +#define LPC_WIDEIO_GENERIC_PORT 0x64 +#define LPC_WIDEIO1_GENERIC_PORT 0x66 +#define ROM_ADDRESS_RANGE1_START 0x68 +#define ROM_ADDRESS_RANGE1_END 0x6a +#define ROM_ADDRESS_RANGE2_START 0x6c +#define ROM_ADDRESS_RANGE2_END 0x6e + +#define LPC_ALT_WIDEIO_RANGE_ENABLE 0x74 +#define LPC_ALT_WIDEIO2_ENABLE BIT(3) +#define LPC_ALT_WIDEIO1_ENABLE BIT(2) +#define LPC_ALT_WIDEIO0_ENABLE BIT(0) + +#define LPC_MISC_CONTROL_BITS 0x78 +#define LPC_NOHOG BIT(0) + +#define LPC_TRUSTED_PLATFORM_MODULE 0x7c +#define TPM_12_EN BIT(0) +#define TPM_LEGACY_EN BIT(2) + +#define LPC_WIDEIO2_GENERIC_PORT 0x90 + +#define SPIROM_BASE_ADDRESS_REGISTER 0xa0 +#define SPI_BASE_RESERVED (BIT(4) | BIT(5)) +#define ROUTE_TPM_2_SPI BIT(3) +#define SPI_ABORT_ENABLE BIT(2) +#define SPI_ROM_ENABLE BIT(1) +#define SPI_ROM_ALT_ENABLE BIT(0) +#define SPI_PRESERVE_BITS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +/* LPC register 0xb8 is DWORD, here there are definitions for byte + access. For example, bits 31-24 are accessed through byte access + at register 0xbb. */ +#define LPC_ROM_DMA_EC_HOST_CONTROL 0xb8 +#define SPI_FROM_HOST_PREFETCH_EN BIT(24) +#define SPI_FROM_USB_PREFETCH_EN BIT(23) + +#define LPC_HOST_CONTROL 0xbb +#define PREFETCH_EN_SPI_FROM_HOST BIT(0) +#define T_START_ENH BIT(3) + +/* LPC is typically enabled very early, but this function is last opportunity */ +void soc_late_lpc_bridge_enable(void); +void lpc_enable_port80(void); +void lpc_enable_pci_port80(void); +void lpc_enable_decode(uint32_t decodes); +uintptr_t lpc_spibase(void); +void lpc_tpm_decode(void); +void lpc_tpm_decode_spi(void); +void lpc_enable_rom(void); +void lpc_enable_spi_prefetch(void); + +/** + * @brief Find the size of a particular wide IO + * + * @param index = index of desired wide IO + * + * @return size of desired wide IO + */ +uint16_t lpc_wideio_size(int index); +/** + * @brief Identify if any LPC wide IO is covering the IO range + * + * @param start = start of IO range + * @param size = size of IO range + * + * @return Index of wide IO covering the range or error + */ +int lpc_find_wideio_range(uint16_t start, uint16_t size); +/** + * @brief Program a LPC wide IO to support an IO range + * + * @param start = start of range to be routed through wide IO + * @param size = size of range to be routed through wide IO + * + * @return Index of wide IO register used or error + */ +int lpc_set_wideio_range(uint16_t start, uint16_t size); + +uintptr_t lpc_get_spibase(void); +void lpc_set_spibase(uint32_t base, uint32_t enable); + +#endif /* __AMDBLOCKS_LPC_H__ */ diff --git a/src/soc/amd/common/block/lpc/Kconfig b/src/soc/amd/common/block/lpc/Kconfig new file mode 100644 index 0000000..b0d59a5 --- /dev/null +++ b/src/soc/amd/common/block/lpc/Kconfig @@ -0,0 +1,5 @@ +config SOC_AMD_COMMON_BLOCK_LPC + bool + default n + help + Select this option to use the traditional LPC-ISA bridge at D14F3. diff --git a/src/soc/amd/common/block/lpc/Makefile.inc b/src/soc/amd/common/block/lpc/Makefile.inc new file mode 100644 index 0000000..72b1e42 --- /dev/null +++ b/src/soc/amd/common/block/lpc/Makefile.inc @@ -0,0 +1,8 @@ +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc.c + +bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +verstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +postcar-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c +smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_LPC) += lpc_util.c diff --git a/src/soc/amd/stoneyridge/lpc.c b/src/soc/amd/common/block/lpc/lpc.c similarity index 94% rename from src/soc/amd/stoneyridge/lpc.c rename to src/soc/amd/common/block/lpc/lpc.c index 1741e92..b896517 100644 --- a/src/soc/amd/stoneyridge/lpc.c +++ b/src/soc/amd/common/block/lpc/lpc.c @@ -28,15 +28,21 @@ #include <pc80/i8254.h> #include <pc80/i8259.h> #include <amdblocks/acpimmio.h> +#include <amdblocks/lpc.h> #include <soc/acpi.h> -#include <soc/pci_devs.h> #include <soc/southbridge.h> #include <soc/nvs.h> +#include <soc/iomap.h> + +/* Most systems should have already enabled the bridge */ +void __weak soc_late_lpc_bridge_enable(void) { }
static void lpc_init(struct device *dev) { u8 byte;
+ soc_late_lpc_bridge_enable(); + /* Initialize isa dma */ isa_dma_init();
@@ -64,8 +70,8 @@ pci_write_config8(dev, LPC_MISC_CONTROL_BITS, byte);
/* - * Enable hand-instance of the pulse generator and SPI - * controller prefetch of flash. + * Enable hand-instance of the pulse generator and SPI prefetch from + * host (earlier is recommended for boot speed). */ byte = pci_read_config8(dev, LPC_HOST_CONTROL); byte |= PREFETCH_EN_SPI_FROM_HOST | T_START_ENH; @@ -247,9 +253,9 @@ break; default: rsize = 0; - wideio_index = sb_find_wideio_range(base, res->size); + wideio_index = lpc_find_wideio_range(base, res->size); if (wideio_index != WIDEIO_RANGE_ERROR) { - rsize = sb_wideio_size(wideio_index); + rsize = lpc_wideio_size(wideio_index); printk(BIOS_DEBUG, "Covered by wideIO"); printk(BIOS_DEBUG, " %d\n", wideio_index); } @@ -260,7 +266,7 @@ *reg_x |= set_x; /* check if we can fit resource in variable range */ } else { - wideio_index = sb_set_wideio_range(base, res->size); + wideio_index = lpc_set_wideio_range(base, res->size); if (wideio_index != WIDEIO_RANGE_ERROR) { /* preserve wide IO related bits. */ *reg_x = pci_read_config32(dev, diff --git a/src/soc/amd/common/block/lpc/lpc_util.c b/src/soc/amd/common/block/lpc/lpc_util.c new file mode 100644 index 0000000..008d14c --- /dev/null +++ b/src/soc/amd/common/block/lpc/lpc_util.c @@ -0,0 +1,308 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010-2017 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdint.h> +#include <device/device.h> +#include <device/pci_ops.h> +#include <device/pci_def.h> +#include <amdblocks/lpc.h> +#include <soc/iomap.h> +#include <soc/southbridge.h> + +/* The LPC-ISA bridge is always at D14F3 */ +#if !defined(__SIMPLE_DEVICE__) +#include <device/device.h> +#define _LPCB_DEV pcidev_on_root(0x14, 0x3) +#else +#define _LPCB_DEV PCI_DEV(0, 0x14, 0x3) +#endif + +/* + * Structure to simplify code obtaining the total of used wide IO + * registers and the size assigned to each. + */ +static const struct wide_io_ioport_and_bits { + uint32_t enable; + uint16_t port; + uint8_t alt; +} wio_io_en[] = { + { + .enable = LPC_WIDEIO0_ENABLE, + .port = LPC_WIDEIO_GENERIC_PORT, + .alt = LPC_ALT_WIDEIO0_ENABLE + }, + { + .enable = LPC_WIDEIO1_ENABLE, + .port = LPC_WIDEIO1_GENERIC_PORT, + .alt = LPC_ALT_WIDEIO1_ENABLE + }, + { + .enable = LPC_WIDEIO2_ENABLE, + .port = LPC_WIDEIO2_GENERIC_PORT, + .alt = LPC_ALT_WIDEIO2_ENABLE + } +}; + +/** + * @brief Find the size of a particular wide IO + * + * @param index = index of desired wide IO + * + * @return size of desired wide IO + */ +uint16_t lpc_wideio_size(int index) +{ + uint32_t enable_register; + uint16_t size = 0; + uint8_t alternate_register; + + if (index >= ARRAY_SIZE(wio_io_en)) + return size; + enable_register = pci_read_config32(_LPCB_DEV, + LPC_IO_OR_MEM_DECODE_ENABLE); + alternate_register = pci_read_config8(_LPCB_DEV, + LPC_ALT_WIDEIO_RANGE_ENABLE); + if (enable_register & wio_io_en[index].enable) + size = (alternate_register & wio_io_en[index].alt) ? + 16 : 512; + return size; +} + +/** + * @brief Identify if any LPC wide IO is covering the IO range + * + * @param start = start of IO range + * @param size = size of IO range + * + * @return Index of wide IO covering the range or error + */ +int lpc_find_wideio_range(uint16_t start, uint16_t size) +{ + int i, index = WIDEIO_RANGE_ERROR; + uint16_t end, current_size, start_wideio, end_wideio; + + end = start + size; + for (i = 0; i < ARRAY_SIZE(wio_io_en); i++) { + current_size = lpc_wideio_size(i); + if (current_size == 0) + continue; + start_wideio = pci_read_config16(_LPCB_DEV, + wio_io_en[i].port); + end_wideio = start_wideio + current_size; + if ((start >= start_wideio) && (end <= end_wideio)) { + index = i; + break; + } + } + return index; +} + +/** + * @brief Program a LPC wide IO to support an IO range + * + * @param start = start of range to be routed through wide IO + * @param size = size of range to be routed through wide IO + * + * @return Index of wide IO register used or error + */ +int lpc_set_wideio_range(uint16_t start, uint16_t size) +{ + int i, index = WIDEIO_RANGE_ERROR; + uint32_t enable_register; + uint8_t alternate_register; + + enable_register = pci_read_config32(_LPCB_DEV, + LPC_IO_OR_MEM_DECODE_ENABLE); + alternate_register = pci_read_config8(_LPCB_DEV, + LPC_ALT_WIDEIO_RANGE_ENABLE); + for (i = 0; i < ARRAY_SIZE(wio_io_en); i++) { + if (enable_register & wio_io_en[i].enable) + continue; + index = i; + pci_write_config16(_LPCB_DEV, wio_io_en[i].port, start); + enable_register |= wio_io_en[i].enable; + pci_write_config32(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, + enable_register); + if (size <= 16) + alternate_register |= wio_io_en[i].alt; + else + alternate_register &= ~wio_io_en[i].alt; + pci_write_config8(_LPCB_DEV, + LPC_ALT_WIDEIO_RANGE_ENABLE, + alternate_register); + break; + } + return index; +} + +void lpc_enable_port80(void) +{ + u8 byte; + + byte = pci_read_config8(_LPCB_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH); + byte |= DECODE_IO_PORT_ENABLE4_H; + pci_write_config8(_LPCB_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH, byte); +} + +void lpc_enable_pci_port80(void) +{ + u8 byte; + + byte = pci_read_config8(_LPCB_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH); + byte &= ~DECODE_IO_PORT_ENABLE4_H; /* disable lpc port 80 */ + pci_write_config8(_LPCB_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH, byte); +} + +void lpc_enable_decode(uint32_t decodes) +{ + pci_write_config32(_LPCB_DEV, LPC_IO_PORT_DECODE_ENABLE, decodes); +} + +uintptr_t lpc_spibase(void) +{ + u32 base, enables; + + /* Make sure the base address is predictable */ + base = pci_read_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER); + enables = base & SPI_PRESERVE_BITS; + base &= ~(SPI_PRESERVE_BITS | SPI_BASE_RESERVED); + + if (!base) { + base = SPI_BASE_ADDRESS; + pci_write_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER, + base | enables | SPI_ROM_ENABLE); + /* PCI_COMMAND_MEMORY is read-only and enabled. */ + } + return base; +} + +/* + * Enable FCH to decode TPM associated Memory and IO regions + * + * Enable decoding of TPM cycles defined in TPM 1.2 spec + * Enable decoding of legacy TPM addresses: IO addresses 0x7f- + * 0x7e and 0xef-0xee. + * This function should be called if TPM is connected in any way to the FCH and + * conforms to the regions decoded. + * Absent any other routing configuration the TPM cycles will be claimed by the + * LPC bus + */ +void lpc_tpm_decode(void) +{ + u32 value; + + value = pci_read_config32(_LPCB_DEV, LPC_TRUSTED_PLATFORM_MODULE); + value |= TPM_12_EN | TPM_LEGACY_EN; + pci_write_config32(_LPCB_DEV, LPC_TRUSTED_PLATFORM_MODULE, value); +} + +/* + * Enable FCH to decode TPM associated Memory and IO regions to SPI + * + * This should be used if TPM is connected to SPI bus. + * Assumes SPI address space is already configured via a call to lpc_spibase(). + */ +void lpc_tpm_decode_spi(void) +{ + /* Enable TPM decoding to FCH */ + lpc_tpm_decode(); + + /* Route TPM accesses to SPI */ + u32 spibase = pci_read_config32(_LPCB_DEV, + SPIROM_BASE_ADDRESS_REGISTER); + pci_write_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER, spibase + | ROUTE_TPM_2_SPI); +} + +/* + * Enable 4MB (LPC) ROM access at 0xFFC00000 - 0xFFFFFFFF. + * + * Hardware should enable LPC ROM by pin straps. This function does not + * handle the theoretically possible PCI ROM, FWH, or SPI ROM configurations. + * + * The southbridge power-on default is to map 512K ROM space. + * + */ +void lpc_enable_rom(void) +{ + u8 reg8; + + /* + * Decode variable LPC ROM address ranges 1 and 2. + * Bits 3-4 are not defined in any publicly available datasheet + */ + reg8 = pci_read_config8(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE); + reg8 |= (1 << 3) | (1 << 4); + pci_write_config8(_LPCB_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, reg8); + + /* + * LPC ROM address range 1: + * Enable LPC ROM range mirroring start at 0x000e(0000). + */ + pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE1_START, 0x000e); + + /* Enable LPC ROM range mirroring end at 0x000f(ffff). */ + pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE1_END, 0x000f); + + /* + * LPC ROM address range 2: + * + * Enable LPC ROM range start at: + * 0xfff8(0000): 512KB + * 0xfff0(0000): 1MB + * 0xffe0(0000): 2MB + * 0xffc0(0000): 4MB + */ + pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE2_START, 0x10000 + - (CONFIG_COREBOOT_ROMSIZE_KB >> 6)); + + /* Enable LPC ROM range end at 0xffff(ffff). */ + pci_write_config16(_LPCB_DEV, ROM_ADDRESS_RANGE2_END, 0xffff); +} + +void lpc_enable_spi_prefetch(void) +{ + uint32_t dword; + + dword = pci_read_config32(_LPCB_DEV, LPC_ROM_DMA_EC_HOST_CONTROL); + dword |= SPI_FROM_HOST_PREFETCH_EN | SPI_FROM_USB_PREFETCH_EN; + pci_write_config32(_LPCB_DEV, LPC_ROM_DMA_EC_HOST_CONTROL, dword); +} + +uintptr_t lpc_get_spibase(void) +{ + u32 base; + + base = pci_read_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER); + base = ALIGN_DOWN(base, SPI_BASE_ALIGNMENT); + return (uintptr_t)base; +} + +void lpc_set_spibase(u32 base, u32 enable) +{ + u32 reg32; + + /* only two types of CS# enables are allowed */ + enable &= SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE; + + reg32 = pci_read_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER); + + reg32 &= SPI_BASE_ALIGNMENT - 1; /* preserve only reserved, enables */ + reg32 &= ~(SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE); + reg32 |= enable; + reg32 |= ALIGN_DOWN(base, SPI_BASE_ALIGNMENT); + + pci_write_config32(_LPCB_DEV, SPIROM_BASE_ADDRESS_REGISTER, reg32); +} diff --git a/src/soc/amd/stoneyridge/Kconfig b/src/soc/amd/stoneyridge/Kconfig index 5333f59..ef7a7ae 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -48,6 +48,7 @@ select SOC_AMD_COMMON_BLOCK select SOC_AMD_COMMON_BLOCK_ACPIMMIO select SOC_AMD_COMMON_BLOCK_BANKED_GPIOS + select SOC_AMD_COMMON_BLOCK_LPC select SOC_AMD_COMMON_BLOCK_PCI select SOC_AMD_COMMON_BLOCK_PI select SOC_AMD_COMMON_BLOCK_PSP diff --git a/src/soc/amd/stoneyridge/Makefile.inc b/src/soc/amd/stoneyridge/Makefile.inc index 68dba09..e235ada 100644 --- a/src/soc/amd/stoneyridge/Makefile.inc +++ b/src/soc/amd/stoneyridge/Makefile.inc @@ -104,7 +104,6 @@ ramstage-y += monotonic_timer.c ramstage-y += southbridge.c ramstage-y += sb_util.c -ramstage-y += lpc.c ramstage-y += northbridge.c ramstage-y += pmutil.c ramstage-y += reset.c diff --git a/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl b/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl index 1334df1..3623814 100644 --- a/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl +++ b/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl @@ -51,7 +51,7 @@ /* 0:14.2 - I2S Audio */
/* 0:14.3 - LPC */ -#include "lpc.asl" +#include <soc/amd/common/acpi/lpc.asl>
/* 0:14.7 - SD Controller */ Device(SDCN) { diff --git a/src/soc/amd/stoneyridge/include/soc/southbridge.h b/src/soc/amd/stoneyridge/include/soc/southbridge.h index 0ac4385..6a7c58f 100644 --- a/src/soc/amd/stoneyridge/include/soc/southbridge.h +++ b/src/soc/amd/stoneyridge/include/soc/southbridge.h @@ -256,125 +256,9 @@ #define GPE0_LIMIT 28 #define TOTAL_BITS(a) (8 * sizeof(a))
-/* - * PCI Config Space Definitions - */ - -/* ISA Bridge D14F3 */ -#define LPC_PCI_CONTROL 0x40 -#define LEGACY_DMA_EN BIT(2) - -#define LPC_IO_PORT_DECODE_ENABLE 0x44 -#define DECODE_ENABLE_PARALLEL_PORT0 BIT(0) -#define DECODE_ENABLE_PARALLEL_PORT1 BIT(1) -#define DECODE_ENABLE_PARALLEL_PORT2 BIT(2) -#define DECODE_ENABLE_PARALLEL_PORT3 BIT(3) -#define DECODE_ENABLE_PARALLEL_PORT4 BIT(4) -#define DECODE_ENABLE_PARALLEL_PORT5 BIT(5) -#define DECODE_ENABLE_SERIAL_PORT0 BIT(6) -#define DECODE_ENABLE_SERIAL_PORT1 BIT(7) -#define DECODE_ENABLE_SERIAL_PORT2 BIT(8) -#define DECODE_ENABLE_SERIAL_PORT3 BIT(9) -#define DECODE_ENABLE_SERIAL_PORT4 BIT(10) -#define DECODE_ENABLE_SERIAL_PORT5 BIT(11) -#define DECODE_ENABLE_SERIAL_PORT6 BIT(12) -#define DECODE_ENABLE_SERIAL_PORT7 BIT(13) -#define DECODE_ENABLE_AUDIO_PORT0 BIT(14) -#define DECODE_ENABLE_AUDIO_PORT1 BIT(15) -#define DECODE_ENABLE_AUDIO_PORT2 BIT(16) -#define DECODE_ENABLE_AUDIO_PORT3 BIT(17) -#define DECODE_ENABLE_MIDI_PORT0 BIT(18) -#define DECODE_ENABLE_MIDI_PORT1 BIT(19) -#define DECODE_ENABLE_MIDI_PORT2 BIT(20) -#define DECODE_ENABLE_MIDI_PORT3 BIT(21) -#define DECODE_ENABLE_MSS_PORT0 BIT(22) -#define DECODE_ENABLE_MSS_PORT1 BIT(23) -#define DECODE_ENABLE_MSS_PORT2 BIT(24) -#define DECODE_ENABLE_MSS_PORT3 BIT(25) -#define DECODE_ENABLE_FDC_PORT0 BIT(26) -#define DECODE_ENABLE_FDC_PORT1 BIT(27) -#define DECODE_ENABLE_GAME_PORT BIT(28) -#define DECODE_ENABLE_KBC_PORT BIT(29) -#define DECODE_ENABLE_ACPIUC_PORT BIT(30) -#define DECODE_ENABLE_ADLIB_PORT BIT(31) - -#define LPC_IO_OR_MEM_DECODE_ENABLE 0x48 -#define LPC_WIDEIO2_ENABLE BIT(25) -#define LPC_WIDEIO1_ENABLE BIT(24) -#define DECODE_IO_PORT_ENABLE6 BIT(23) -#define DECODE_IO_PORT_ENABLE5 BIT(22) -#define DECODE_IO_PORT_ENABLE4 BIT(21) -#define DECODE_MEM_PORT_ENABLE1 BIT(20) -#define DECODE_IO_PORT_ENABLE3 BIT(19) -#define DECODE_IO_PORT_ENABLE2 BIT(18) -#define DECODE_IO_PORT_ENABLE1 BIT(17) -#define DECODE_IO_PORT_ENABLE0 BIT(16) -#define LPC_SYNC_TIMEOUT_COUNT_ENABLE BIT(7) -#define LPC_DECODE_RTC_IO_ENABLE BIT(6) -#define DECODE_MEM_PORT_ENABLE0 BIT(5) -#define LPC_WIDEIO0_ENABLE BIT(2) -#define DECODE_ALTERNATE_SIO_ENABLE BIT(1) -#define DECODE_SIO_ENABLE BIT(0) -#define WIDEIO_RANGE_ERROR -1 -#define TOTAL_WIDEIO_PORTS 3 - -/* Assuming word access to higher word (register 0x4a) */ -#define LPC_IO_OR_MEM_DEC_EN_HIGH 0x4a -#define LPC_WIDEIO2_ENABLE_H BIT(9) -#define LPC_WIDEIO1_ENABLE_H BIT(8) -#define DECODE_IO_PORT_ENABLE6_H BIT(7) -#define DECODE_IO_PORT_ENABLE5_H BIT(6) -#define DECODE_IO_PORT_ENABLE4_H BIT(5) -#define DECODE_IO_PORT_ENABLE3_H BIT(3) -#define DECODE_IO_PORT_ENABLE2_H BIT(2) -#define DECODE_IO_PORT_ENABLE1_H BIT(1) -#define DECODE_IO_PORT_ENABLE0_H BIT(0) - -#define LPC_MEM_PORT1 0x4c -#define LPC_MEM_PORT0 0x60 - -/* Register 0x64 is 32-bit, composed by two 16-bit sub-registers. - For ease of access, each sub-register is declared separetely. */ -#define LPC_WIDEIO_GENERIC_PORT 0x64 -#define LPC_WIDEIO1_GENERIC_PORT 0x66 -#define ROM_ADDRESS_RANGE1_START 0x68 -#define ROM_ADDRESS_RANGE1_END 0x6a -#define ROM_ADDRESS_RANGE2_START 0x6c -#define ROM_ADDRESS_RANGE2_END 0x6e - -#define LPC_ALT_WIDEIO_RANGE_ENABLE 0x74 -#define LPC_ALT_WIDEIO2_ENABLE BIT(3) -#define LPC_ALT_WIDEIO1_ENABLE BIT(2) -#define LPC_ALT_WIDEIO0_ENABLE BIT(0) - -#define LPC_MISC_CONTROL_BITS 0x78 -#define LPC_NOHOG BIT(0) - -#define LPC_TRUSTED_PLATFORM_MODULE 0x7c -#define TPM_12_EN BIT(0) -#define TPM_LEGACY_EN BIT(2) - -#define LPC_WIDEIO2_GENERIC_PORT 0x90 - -#define SPIROM_BASE_ADDRESS_REGISTER 0xa0 -#define SPI_BASE_ALIGNMENT BIT(6) -#define ROUTE_TPM_2_SPI BIT(3) -#define SPI_ABORT_ENABLE BIT(2) -#define SPI_ROM_ENABLE BIT(1) -#define SPI_ROM_ALT_ENABLE BIT(0) - -/* LPC register 0xb8 is DWORD, here there are definitions for byte - access. For example, bits 31-24 are accessed through byte access - at register 0xbb. */ -#define LPC_ROM_DMA_EC_HOST_CONTROL 0xb8 -#define SPI_FROM_HOST_PREFETCH_EN BIT(24) -#define SPI_FROM_USB_PREFETCH_EN BIT(23) - -#define LPC_HOST_CONTROL 0xbb -#define PREFETCH_EN_SPI_FROM_HOST BIT(0) -#define T_START_ENH BIT(3) - /* SPI Controller (base address in D14F3xA0) */ +#define SPI_BASE_ALIGNMENT BIT(6) + #define SPI_CNTRL0 0x00 #define SPI_BUSY BIT(31) #define SPI_READ_MODE_MASK (BIT(30) | BIT(29) | BIT(18)) @@ -474,21 +358,13 @@ #define XHCI_FW_BOOTRAM_SIZE 0x8000
void enable_aoac_devices(void); -void sb_enable_rom(void); void sb_clk_output_48Mhz(u32 osc); void sb_disable_4dw_burst(void); void sb_enable(struct device *dev); void southbridge_final(void *chip_info); void southbridge_init(void *chip_info); -void sb_lpc_port80(void); -void sb_lpc_decode(void); -void sb_pci_port80(void); void sb_read_mode(u32 mode); void sb_set_spi100(u16 norm, u16 fast, u16 alt, u16 tpm); -void sb_tpm_decode(void); -void sb_tpm_decode_spi(void); -void lpc_wideio_512_window(uint16_t base); -void lpc_wideio_16_window(uint16_t base); uint16_t pm_acpi_pm_cnt_blk(void); uint16_t pm_acpi_pm_evt_blk(void); void bootblock_fch_early_init(void); @@ -525,33 +401,6 @@ * @return 64bit base address */ uint64_t get_uma_base(void); -/** - * @brief Find the size of a particular wide IO - * - * @param index = index of desired wide IO - * - * @return size of desired wide IO - */ -uint16_t sb_wideio_size(int index); -/** - * @brief Identify if any LPC wide IO is covering the IO range - * - * @param start = start of IO range - * @param size = size of IO range - * - * @return Index of wide IO covering the range or error - */ -int sb_find_wideio_range(uint16_t start, uint16_t size); -/** - * @brief Program a LPC wide IO to support an IO range - * - * @param start = start of range to be routed through wide IO - * @param size = size of range to be routed through wide IO - * - * @return Index of wide IO register used or error - */ -int sb_set_wideio_range(uint16_t start, uint16_t size); - /* * Call the mainboard to get the USB Over Current Map. The mainboard * returns the map and 0 on Success or -1 on error or no map. There is diff --git a/src/soc/amd/stoneyridge/southbridge.c b/src/soc/amd/stoneyridge/southbridge.c index b8d0595..cd91031 100644 --- a/src/soc/amd/stoneyridge/southbridge.c +++ b/src/soc/amd/stoneyridge/southbridge.c @@ -27,6 +27,7 @@ #include <amdblocks/agesawrapper.h> #include <amdblocks/reset.h> #include <amdblocks/acpimmio.h> +#include <amdblocks/lpc.h> #include <soc/southbridge.h> #include <soc/smbus.h> #include <soc/smi.h> @@ -152,130 +153,12 @@ { PIRQ_UART1, "UART1" }, };
-/* - * Structure to simplify code obtaining the total of used wide IO - * registers and the size assigned to each. - */ -static struct wide_io_ioport_and_bits { - uint32_t enable; - uint16_t port; - uint8_t alt; -} wio_io_en[TOTAL_WIDEIO_PORTS] = { - { - LPC_WIDEIO0_ENABLE, - LPC_WIDEIO_GENERIC_PORT, - LPC_ALT_WIDEIO0_ENABLE - }, - { - LPC_WIDEIO1_ENABLE, - LPC_WIDEIO1_GENERIC_PORT, - LPC_ALT_WIDEIO1_ENABLE - }, - { - LPC_WIDEIO2_ENABLE, - LPC_WIDEIO2_GENERIC_PORT, - LPC_ALT_WIDEIO2_ENABLE - } -}; - const struct irq_idx_name *sb_get_apic_reg_association(size_t *size) { *size = ARRAY_SIZE(irq_association); return irq_association; }
-/** - * @brief Find the size of a particular wide IO - * - * @param index = index of desired wide IO - * - * @return size of desired wide IO - */ -uint16_t sb_wideio_size(int index) -{ - uint32_t enable_register; - uint16_t size = 0; - uint8_t alternate_register; - - if (index >= TOTAL_WIDEIO_PORTS) - return size; - enable_register = pci_read_config32(SOC_LPC_DEV, - LPC_IO_OR_MEM_DECODE_ENABLE); - alternate_register = pci_read_config8(SOC_LPC_DEV, - LPC_ALT_WIDEIO_RANGE_ENABLE); - if (enable_register & wio_io_en[index].enable) - size = (alternate_register & wio_io_en[index].alt) ? - 16 : 512; - return size; -} - -/** - * @brief Identify if any LPC wide IO is covering the IO range - * - * @param start = start of IO range - * @param size = size of IO range - * - * @return Index of wide IO covering the range or error - */ -int sb_find_wideio_range(uint16_t start, uint16_t size) -{ - int i, index = WIDEIO_RANGE_ERROR; - uint16_t end, current_size, start_wideio, end_wideio; - - end = start + size; - for (i = 0; i < TOTAL_WIDEIO_PORTS; i++) { - current_size = sb_wideio_size(i); - if (current_size == 0) - continue; - start_wideio = pci_read_config16(SOC_LPC_DEV, - wio_io_en[i].port); - end_wideio = start_wideio + current_size; - if ((start >= start_wideio) && (end <= end_wideio)) { - index = i; - break; - } - } - return index; -} - -/** - * @brief Program a LPC wide IO to support an IO range - * - * @param start = start of range to be routed through wide IO - * @param size = size of range to be routed through wide IO - * - * @return Index of wide IO register used or error - */ -int sb_set_wideio_range(uint16_t start, uint16_t size) -{ - int i, index = WIDEIO_RANGE_ERROR; - uint32_t enable_register; - uint8_t alternate_register; - - enable_register = pci_read_config32(SOC_LPC_DEV, - LPC_IO_OR_MEM_DECODE_ENABLE); - alternate_register = pci_read_config8(SOC_LPC_DEV, - LPC_ALT_WIDEIO_RANGE_ENABLE); - for (i = 0; i < TOTAL_WIDEIO_PORTS; i++) { - if (enable_register & wio_io_en[i].enable) - continue; - index = i; - pci_write_config16(SOC_LPC_DEV, wio_io_en[i].port, start); - enable_register |= wio_io_en[i].enable; - pci_write_config32(SOC_LPC_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, - enable_register); - if (size <= 16) - alternate_register |= wio_io_en[i].alt; - else - alternate_register &= ~wio_io_en[i].alt; - pci_write_config8(SOC_LPC_DEV, - LPC_ALT_WIDEIO_RANGE_ENABLE, - alternate_register); - break; - } - return index; -} - static void power_on_aoac_device(int aoac_device_control_register) { uint8_t byte; @@ -315,16 +198,7 @@ } while (!status); }
-void sb_pci_port80(void) -{ - u8 byte; - - byte = pci_read_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH); - byte &= ~DECODE_IO_PORT_ENABLE4_H; /* disable lpc port 80 */ - pci_write_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH, byte); -} - -void sb_lpc_port80(void) +static void sb_enable_lpc(void) { u8 byte;
@@ -332,14 +206,9 @@ byte = pm_io_read8(PM_LPC_GATING); byte |= PM_LPC_ENABLE; pm_io_write8(PM_LPC_GATING, byte); - - /* Enable port 80 LPC decode in pci function 3 configuration space. */ - byte = pci_read_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH); - byte |= DECODE_IO_PORT_ENABLE4_H; /* enable port 80 */ - pci_write_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DEC_EN_HIGH, byte); }
-void sb_lpc_decode(void) +static void sb_lpc_decode(void) { u32 tmp = 0;
@@ -357,7 +226,11 @@ | DECODE_ENABLE_KBC_PORT | DECODE_ENABLE_ACPIUC_PORT | DECODE_ENABLE_ADLIB_PORT;
- pci_write_config32(SOC_LPC_DEV, LPC_IO_PORT_DECODE_ENABLE, tmp); + /* Decode SIOs at 2E/2F and 4E/4F */ + if (CONFIG(STONEYRIDGE_LEGACY_FREE)) + tmp |= DECODE_ALTERNATE_SIO_ENABLE | DECODE_SIO_ENABLE; + + lpc_enable_decode(tmp); }
static void sb_enable_cf9_io(void) @@ -397,43 +270,17 @@ misc_write32(MISC_CLK_CNTL1, ctrl); }
-static uintptr_t sb_get_spibase(void) -{ - u32 base; - - base = pci_read_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER); - base = ALIGN_DOWN(base, SPI_BASE_ALIGNMENT); - return (uintptr_t)base; -} - -static void sb_set_spibase(u32 base, u32 enable) -{ - u32 reg32; - - /* only two types of CS# enables are allowed */ - enable &= SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE; - - reg32 = pci_read_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER); - - reg32 &= SPI_BASE_ALIGNMENT - 1; /* preserve only reserved, enables */ - reg32 &= ~(SPI_ROM_ENABLE | SPI_ROM_ALT_ENABLE); - reg32 |= enable; - reg32 |= ALIGN_DOWN(base, SPI_BASE_ALIGNMENT); - - pci_write_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER, reg32); -} - static uintptr_t sb_init_spi_base(void) { uintptr_t base;
/* Make sure the base address is predictable */ - base = sb_get_spibase(); + base = lpc_get_spibase();
if (base) return base;
- sb_set_spibase(SPI_BASE_ADDRESS, SPI_ROM_ENABLE); + lpc_set_spibase(SPI_BASE_ADDRESS, SPI_ROM_ENABLE); return SPI_BASE_ADDRESS; }
@@ -464,109 +311,6 @@ & ~SPI_READ_MODE_MASK) | mode); }
-/* - * Enable FCH to decode TPM associated Memory and IO regions - * - * Enable decoding of TPM cycles defined in TPM 1.2 spec - * Enable decoding of legacy TPM addresses: IO addresses 0x7f- - * 0x7e and 0xef-0xee. - * This function should be called if TPM is connected in any way to the FCH and - * conforms to the regions decoded. - * Absent any other routing configuration the TPM cycles will be claimed by the - * LPC bus - */ -void sb_tpm_decode(void) -{ - u32 value; - - value = pci_read_config32(SOC_LPC_DEV, LPC_TRUSTED_PLATFORM_MODULE); - value |= TPM_12_EN | TPM_LEGACY_EN; - pci_write_config32(SOC_LPC_DEV, LPC_TRUSTED_PLATFORM_MODULE, value); -} - -/* - * Enable FCH to decode TPM associated Memory and IO regions to SPI - * - * This should be used if TPM is connected to SPI bus. - * Assumes SPI address space is already configured. - */ -void sb_tpm_decode_spi(void) -{ - /* Enable TPM decoding to FCH */ - sb_tpm_decode(); - - /* Route TPM accesses to SPI */ - u32 spibase = pci_read_config32(SOC_LPC_DEV, - SPIROM_BASE_ADDRESS_REGISTER); - pci_write_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER, spibase - | ROUTE_TPM_2_SPI); -} - -/* - * Enable 4MB (LPC) ROM access at 0xFFC00000 - 0xFFFFFFFF. - * - * Hardware should enable LPC ROM by pin straps. This function does not - * handle the theoretically possible PCI ROM, FWH, or SPI ROM configurations. - * - * The southbridge power-on default is to map 512K ROM space. - * - */ -void sb_enable_rom(void) -{ - u8 reg8; - - /* - * Decode variable LPC ROM address ranges 1 and 2. - * Bits 3-4 are not defined in any publicly available datasheet - */ - reg8 = pci_read_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DECODE_ENABLE); - reg8 |= (1 << 3) | (1 << 4); - pci_write_config8(SOC_LPC_DEV, LPC_IO_OR_MEM_DECODE_ENABLE, reg8); - - /* - * LPC ROM address range 1: - * Enable LPC ROM range mirroring start at 0x000e(0000). - */ - pci_write_config16(SOC_LPC_DEV, ROM_ADDRESS_RANGE1_START, 0x000e); - - /* Enable LPC ROM range mirroring end at 0x000f(ffff). */ - pci_write_config16(SOC_LPC_DEV, ROM_ADDRESS_RANGE1_END, 0x000f); - - /* - * LPC ROM address range 2: - * - * Enable LPC ROM range start at: - * 0xfff8(0000): 512KB - * 0xfff0(0000): 1MB - * 0xffe0(0000): 2MB - * 0xffc0(0000): 4MB - */ - pci_write_config16(SOC_LPC_DEV, ROM_ADDRESS_RANGE2_START, 0x10000 - - (CONFIG_COREBOOT_ROMSIZE_KB >> 6)); - - /* Enable LPC ROM range end at 0xffff(ffff). */ - pci_write_config16(SOC_LPC_DEV, ROM_ADDRESS_RANGE2_END, 0xffff); -} - -static void sb_lpc_early_setup(void) -{ - uint32_t dword; - - /* Enable SPI prefetch */ - dword = pci_read_config32(SOC_LPC_DEV, LPC_ROM_DMA_EC_HOST_CONTROL); - dword |= SPI_FROM_HOST_PREFETCH_EN | SPI_FROM_USB_PREFETCH_EN; - pci_write_config32(SOC_LPC_DEV, LPC_ROM_DMA_EC_HOST_CONTROL, dword); - - if (CONFIG(STONEYRIDGE_LEGACY_FREE)) { - /* Decode SIOs at 2E/2F and 4E/4F */ - dword = pci_read_config32(SOC_LPC_DEV, - LPC_IO_OR_MEM_DECODE_ENABLE); - dword |= DECODE_ALTERNATE_SIO_ENABLE | DECODE_SIO_ENABLE; - pci_write_config32(SOC_LPC_DEV, - LPC_IO_OR_MEM_DECODE_ENABLE, dword); - } -} - static void setup_spread_spectrum(int *reboot) { uint16_t rstcfg = pm_read16(PWR_RESET_CFG); @@ -649,10 +393,11 @@ { int reboot = 0;
- sb_enable_rom(); - sb_lpc_port80(); + lpc_enable_rom(); + sb_enable_lpc(); + lpc_enable_port80(); sb_lpc_decode(); - sb_lpc_early_setup(); + lpc_enable_spi_prefetch(); sb_init_spi_base(); sb_disable_4dw_burst(); /* Must be disabled on CZ(ST) */ enable_acpimmio_decode(); diff --git a/src/soc/amd/stoneyridge/spi.c b/src/soc/amd/stoneyridge/spi.c index c682d98..8abfa16 100644 --- a/src/soc/amd/stoneyridge/spi.c +++ b/src/soc/amd/stoneyridge/spi.c @@ -26,6 +26,7 @@ #include <device/pci.h> #include <device/pci_ops.h> #include <soc/southbridge.h> +#include <amdblocks/lpc.h> #include <soc/pci_devs.h>
#define SPI_DEBUG_DRIVER CONFIG(DEBUG_SPI_FLASH) @@ -103,11 +104,7 @@
void spi_init(void) { - uintptr_t bar; - - bar = pci_read_config32(SOC_LPC_DEV, SPIROM_BASE_ADDRESS_REGISTER); - bar = ALIGN_DOWN(bar, 64); - set_spibar(bar); + set_spibar(lpc_get_spibase()); }
static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,