From 6ab5ed3b66fc215d0d03b19ab02fdcf8613c7d09 Mon Sep 17 00:00:00 2001 From: Marshall Dawson Date: Wed, 29 May 2019 09:24:18 -0600 Subject: 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/32653 Reviewed-by: Martin Roth Tested-by: build bot (Jenkins) --- src/soc/amd/common/acpi/lpc.asl | 110 +++++++ src/soc/amd/common/block/include/amdblocks/lpc.h | 176 +++++++++++ src/soc/amd/common/block/lpc/Kconfig | 5 + src/soc/amd/common/block/lpc/Makefile.inc | 8 + src/soc/amd/common/block/lpc/lpc.c | 346 ++++++++++++++++++++++ src/soc/amd/common/block/lpc/lpc_util.c | 308 +++++++++++++++++++ src/soc/amd/stoneyridge/Kconfig | 1 + src/soc/amd/stoneyridge/Makefile.inc | 1 - src/soc/amd/stoneyridge/acpi/lpc.asl | 110 ------- src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl | 2 +- src/soc/amd/stoneyridge/include/soc/southbridge.h | 155 +--------- src/soc/amd/stoneyridge/lpc.c | 340 --------------------- src/soc/amd/stoneyridge/southbridge.c | 283 +----------------- src/soc/amd/stoneyridge/spi.c | 7 +- 14 files changed, 973 insertions(+), 879 deletions(-) create mode 100644 src/soc/amd/common/acpi/lpc.asl create mode 100644 src/soc/amd/common/block/include/amdblocks/lpc.h create mode 100644 src/soc/amd/common/block/lpc/Kconfig create mode 100644 src/soc/amd/common/block/lpc/Makefile.inc create mode 100644 src/soc/amd/common/block/lpc/lpc.c create mode 100644 src/soc/amd/common/block/lpc/lpc_util.c delete mode 100644 src/soc/amd/stoneyridge/acpi/lpc.asl delete mode 100644 src/soc/amd/stoneyridge/lpc.c (limited to 'src/soc/amd') diff --git a/src/soc/amd/common/acpi/lpc.asl b/src/soc/amd/common/acpi/lpc.asl new file mode 100644 index 0000000000..93b405619d --- /dev/null +++ b/src/soc/amd/common/acpi/lpc.asl @@ -0,0 +1,110 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Sage Electronic Engineering, LLC + * + * 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. + */ + +#if MAINBOARD_HAS_SPEAKER +#define IO61_HID "PNP0800" /* AT style speaker */ +#else +#define IO61_HID "PNP0C02" /* reserved resource */ +#endif + +/* 0:14.3 - LPC */ +Device(LPCB) { + Name(_ADR, 0x00140003) + + /* Method(_INI) { + * DBGO("\\_SB\\PCI0\\LpcIsaBr\\_INI\n") + } */ /* End Method(_SB.SBRDG._INI) */ + + OperationRegion(CFG,PCI_Config,0x0,0x100) // Map PCI Configuration Space + Field(CFG,DWordAcc,NoLock,Preserve){ + Offset(0xA0), + BAR,32} // SPI Controller Base Address Register (Index 0xA0) + + Device(LDRC) // LPC device: Resource consumption + { + Name (_HID, EISAID("PNP0C02")) // ID for Motherboard resources + Name (CRS, ResourceTemplate () // Current Motherboard resources + { + Memory32Fixed(ReadWrite, // Setup for fixed resource location for SPI base address + 0x00000000, // Address Base + 0x00000000, // Address Length + BAR0 // Descriptor Name + ) + }) + + Method(_CRS,0,Serialized) + { + CreateDwordField(^CRS,^BAR0._BAS,SPIB) // Field to hold SPI base address + CreateDwordField(^CRS,^BAR0._LEN,SPIL) // Field to hold SPI address length + Store(BAR,SPIB) // SPI base address mapped + Store(0x1000,SPIL) // 4k space mapped + Return(CRS) + } + } + + /* Real Time Clock Device */ + Device(RTC0) { + Name(_HID, EISAID("PNP0B00")) /* AT Real Time Clock (not PIIX4 compatible) */ + Name(_CRS, ResourceTemplate() { + IRQNoFlags(){8} + IO(Decode16,0x0070, 0x0070, 0, 2) + }) + } /* End Device(_SB.PCI0.LpcIsaBr.RTC0) */ + + Device(TMR) { /* Timer */ + Name(_HID,EISAID("PNP0100")) /* System Timer */ + Name(_CRS, ResourceTemplate() { + IRQNoFlags(){0} + IO(Decode16, 0x0040, 0x0040, 0, 4) + }) + } /* End Device(_SB.PCI0.LpcIsaBr.TMR) */ + + Device(SPKR) { /* Speaker */ + Name(_HID,EISAID(IO61_HID)) + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x0061, 0x0061, 0, 1) + }) + } /* End Device(_SB.PCI0.LpcIsaBr.SPKR) */ + + Device(PIC) { + Name(_HID,EISAID("PNP0000")) /* AT Interrupt Controller */ + Name(_CRS, ResourceTemplate() { + IRQNoFlags(){2} + IO(Decode16,0x0020, 0x0020, 0, 2) + IO(Decode16,0x00a0, 0x00a0, 0, 2) + }) + } /* End Device(_SB.PCI0.LpcIsaBr.PIC) */ + + Device(MAD) { /* 8257 DMA */ + Name(_HID,EISAID("PNP0200")) /* Hardware Device ID */ + Name(_CRS, ResourceTemplate() { + DMA(Compatibility,BusMaster,Transfer8){4} + IO(Decode16, 0x0000, 0x0000, 0x10, 0x10) + IO(Decode16, 0x0081, 0x0081, 0x01, 0x03) + IO(Decode16, 0x0087, 0x0087, 0x01, 0x01) + IO(Decode16, 0x0089, 0x0089, 0x01, 0x03) + IO(Decode16, 0x008f, 0x008f, 0x01, 0x01) + IO(Decode16, 0x00c0, 0x00c0, 0x10, 0x20) + }) /* End Name(_SB.PCI0.LpcIsaBr.MAD._CRS) */ + } /* End Device(_SB.PCI0.LpcIsaBr.MAD) */ + + Device(COPR) { + Name(_HID,EISAID("PNP0C04")) /* Math Coprocessor */ + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x00f0, 0x00f0, 0, 0x10) + IRQNoFlags(){13} + }) + } /* End Device(_SB.PCI0.LpcIsaBr.COPR) */ +} /* end LPCB */ 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 0000000000..7b33d7ad11 --- /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 + +/* 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 0000000000..b0d59a55f4 --- /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 0000000000..72b1e42013 --- /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/common/block/lpc/lpc.c b/src/soc/amd/common/block/lpc/lpc.c new file mode 100644 index 0000000000..b896517214 --- /dev/null +++ b/src/soc/amd/common/block/lpc/lpc.c @@ -0,0 +1,346 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010-2017 Advanced Micro Devices, Inc. + * Copyright (C) 2014 Sage Electronic Engineering, LLC + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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(); + + /* Enable DMA transaction on the LPC bus */ + byte = pci_read_config8(dev, LPC_PCI_CONTROL); + byte |= LEGACY_DMA_EN; + pci_write_config8(dev, LPC_PCI_CONTROL, byte); + + /* Disable the timeout mechanism on LPC */ + byte = pci_read_config8(dev, LPC_IO_OR_MEM_DECODE_ENABLE); + byte &= ~LPC_SYNC_TIMEOUT_COUNT_ENABLE; + pci_write_config8(dev, LPC_IO_OR_MEM_DECODE_ENABLE, byte); + + /* Disable LPC MSI Capability */ + byte = pci_read_config8(dev, LPC_MISC_CONTROL_BITS); + /* BIT 1 is not defined in public datasheet. */ + byte &= ~(1 << 1); + + /* + * Keep the old way. i.e., when bus master/DMA cycle is going + * on on LPC, it holds PCI grant, so no LPC slave cycle can + * interrupt and visit LPC. + */ + byte &= ~LPC_NOHOG; + pci_write_config8(dev, LPC_MISC_CONTROL_BITS, byte); + + /* + * 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; + pci_write_config8(dev, LPC_HOST_CONTROL, byte); + + cmos_check_update_date(); + + /* + * Initialize the real time clock. + * The 0 argument tells cmos_init not to + * update CMOS unless it is invalid. + * 1 tells cmos_init to always initialize the CMOS. + */ + cmos_init(0); + + /* Initialize i8259 pic */ + setup_i8259(); + + /* Initialize i8254 timers */ + setup_i8254(); + + /* Set up SERIRQ, enable continuous mode */ + byte = (PM_SERIRQ_NUM_BITS_21 | PM_SERIRQ_ENABLE); + if (!CONFIG(SERIRQ_CONTINUOUS_MODE)) + byte |= PM_SERIRQ_MODE; + + pm_write8(PM_SERIRQ_CONF, byte); +} + +static void lpc_read_resources(struct device *dev) +{ + struct resource *res; + global_nvs_t *gnvs; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + /* Add an extra subtractive resource for both memory and I/O. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); + res->base = 0; + res->size = 0x1000; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + res->base = FLASH_BASE_ADDR; + res->size = CONFIG_ROM_SIZE; + res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + /* Add a memory resource for the SPI BAR. */ + fixed_mem_resource(dev, 2, SPI_BASE_ADDRESS / 1024, 1, + IORESOURCE_SUBTRACTIVE); + + res = new_resource(dev, 3); /* IOAPIC */ + res->base = IO_APIC_ADDR; + res->size = 0x00001000; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + /* I2C devices (all 4 devices) */ + res = new_resource(dev, 4); + res->base = I2C_BASE_ADDRESS; + res->size = I2C_DEVICE_SIZE * I2C_DEVICE_COUNT; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + compact_resources(dev); + + /* Allocate ACPI NVS in CBMEM */ + gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(global_nvs_t)); + printk(BIOS_DEBUG, "ACPI GNVS at %p\n", gnvs); +} + +static void lpc_set_resources(struct device *dev) +{ + struct resource *res; + u32 spi_enable_bits; + + /* Special case. The SpiRomEnable and other enables should STAY set. */ + res = find_resource(dev, 2); + spi_enable_bits = pci_read_config32(dev, SPIROM_BASE_ADDRESS_REGISTER); + spi_enable_bits &= SPI_BASE_ALIGNMENT - 1; + pci_write_config32(dev, SPIROM_BASE_ADDRESS_REGISTER, + res->base | spi_enable_bits); + + pci_dev_set_resources(dev); +} + +static void set_child_resource(struct device *dev, struct device *child, + u32 *reg, u32 *reg_x) +{ + struct resource *res; + u32 base, end; + u32 rsize = 0, set = 0, set_x = 0; + int wideio_index; + + /* + * Be a bit relaxed, tolerate that LPC region might be bigger than + * resource we try to fit, do it like this for all regions < 16 bytes. + * If there is a resource > 16 bytes it must be 512 bytes to be able + * to allocate the fresh LPC window. + * + * AGESA and early initialization can set a wide IO port. This code + * will verify if required region was previously set and will avoid + * setting a new wide IO resource if one is already set. + */ + + for (res = child->resource_list; res; res = res->next) { + if (!(res->flags & IORESOURCE_IO)) + continue; + base = res->base; + end = resource_end(res); + printk(BIOS_DEBUG, + "Southbridge LPC decode:%s, base=0x%08x, end=0x%08x\n", + dev_path(child), base, end); + /* find a resource size */ + switch (base) { + case 0x60: /* KB */ + case 0x64: /* MS */ + set |= DECODE_ENABLE_KBC_PORT; + rsize = 1; + break; + case 0x3f8: /* COM1 */ + set |= DECODE_ENABLE_SERIAL_PORT0; + rsize = 8; + break; + case 0x2f8: /* COM2 */ + set |= DECODE_ENABLE_SERIAL_PORT1; + rsize = 8; + break; + case 0x378: /* Parallel 1 */ + set |= DECODE_ENABLE_PARALLEL_PORT0; + /* enable 0x778 for ECP mode */ + set |= DECODE_ENABLE_PARALLEL_PORT1; + rsize = 8; + break; + case 0x3f0: /* FD0 */ + set |= DECODE_ENABLE_FDC_PORT0; + rsize = 8; + break; + case 0x220: /* 0x220 - 0x227 */ + set |= DECODE_ENABLE_SERIAL_PORT2; + rsize = 8; + break; + case 0x228: /* 0x228 - 0x22f */ + set |= DECODE_ENABLE_SERIAL_PORT3; + rsize = 8; + break; + case 0x238: /* 0x238 - 0x23f */ + set |= DECODE_ENABLE_SERIAL_PORT4; + rsize = 8; + break; + case 0x300: /* 0x300 - 0x301 */ + set |= DECODE_ENABLE_MIDI_PORT0; + rsize = 2; + break; + case 0x400: + set_x |= DECODE_IO_PORT_ENABLE0; + rsize = 0x40; + break; + case 0x480: + set_x |= DECODE_IO_PORT_ENABLE1; + rsize = 0x40; + break; + case 0x500: + set_x |= DECODE_IO_PORT_ENABLE2; + rsize = 0x40; + break; + case 0x580: + set_x |= DECODE_IO_PORT_ENABLE3; + rsize = 0x40; + break; + case 0x4700: + set_x |= DECODE_IO_PORT_ENABLE5; + rsize = 0xc; + break; + case 0xfd60: + set_x |= DECODE_IO_PORT_ENABLE6; + rsize = 16; + break; + default: + rsize = 0; + wideio_index = lpc_find_wideio_range(base, res->size); + if (wideio_index != WIDEIO_RANGE_ERROR) { + rsize = lpc_wideio_size(wideio_index); + printk(BIOS_DEBUG, "Covered by wideIO"); + printk(BIOS_DEBUG, " %d\n", wideio_index); + } + } + /* check if region found and matches the enable */ + if (res->size <= rsize) { + *reg |= set; + *reg_x |= set_x; + /* check if we can fit resource in variable range */ + } else { + 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, + LPC_IO_OR_MEM_DECODE_ENABLE); + + printk(BIOS_DEBUG, + "Range assigned to wide IO %d\n", + wideio_index); + } else { + printk(BIOS_ERR, + "cannot fit LPC decode region:"); + printk(BIOS_ERR, + "%s, base = 0x%08x, end = 0x%08x\n", + dev_path(child), base, end); + } + } + } +} + +/** + * @brief Enable resources for children devices + * + * @param dev the device whose children's resources are to be enabled + * + */ +static void lpc_enable_childrens_resources(struct device *dev) +{ + struct bus *link; + u32 reg, reg_x; + + reg = pci_read_config32(dev, LPC_IO_PORT_DECODE_ENABLE); + reg_x = pci_read_config32(dev, LPC_IO_OR_MEM_DECODE_ENABLE); + + for (link = dev->link_list; link; link = link->next) { + struct device *child; + for (child = link->children; child; + child = child->sibling) { + if (child->enabled + && (child->path.type == DEVICE_PATH_PNP)) + set_child_resource(dev, child, ®, ®_x); + } + } + pci_write_config32(dev, LPC_IO_PORT_DECODE_ENABLE, reg); + pci_write_config32(dev, LPC_IO_OR_MEM_DECODE_ENABLE, reg_x); +} + +static void lpc_enable_resources(struct device *dev) +{ + pci_dev_enable_resources(dev); + lpc_enable_childrens_resources(dev); +} + +static struct pci_operations lops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + +static struct device_operations lpc_ops = { + .read_resources = lpc_read_resources, + .set_resources = lpc_set_resources, + .enable_resources = lpc_enable_resources, + .acpi_inject_dsdt_generator = southbridge_inject_dsdt, + .write_acpi_tables = southbridge_write_acpi_tables, + .init = lpc_init, + .scan_bus = scan_lpc_bus, + .ops_pci = &lops_pci, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DEVICE_ID_AMD_SB900_LPC, + PCI_DEVICE_ID_AMD_CZ_LPC, + 0 +}; +static const struct pci_driver lpc_driver __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_AMD, + .devices = pci_device_ids, +}; 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 0000000000..008d14c34e --- /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 +#include +#include +#include +#include +#include +#include + +/* The LPC-ISA bridge is always at D14F3 */ +#if !defined(__SIMPLE_DEVICE__) +#include +#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 5333f5933a..ef7a7ae33f 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -48,6 +48,7 @@ config CPU_SPECIFIC_OPTIONS 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 68dba097c1..e235adaab2 100644 --- a/src/soc/amd/stoneyridge/Makefile.inc +++ b/src/soc/amd/stoneyridge/Makefile.inc @@ -104,7 +104,6 @@ ramstage-y += iommu.c 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/lpc.asl b/src/soc/amd/stoneyridge/acpi/lpc.asl deleted file mode 100644 index 93b405619d..0000000000 --- a/src/soc/amd/stoneyridge/acpi/lpc.asl +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 Sage Electronic Engineering, LLC - * - * 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. - */ - -#if MAINBOARD_HAS_SPEAKER -#define IO61_HID "PNP0800" /* AT style speaker */ -#else -#define IO61_HID "PNP0C02" /* reserved resource */ -#endif - -/* 0:14.3 - LPC */ -Device(LPCB) { - Name(_ADR, 0x00140003) - - /* Method(_INI) { - * DBGO("\\_SB\\PCI0\\LpcIsaBr\\_INI\n") - } */ /* End Method(_SB.SBRDG._INI) */ - - OperationRegion(CFG,PCI_Config,0x0,0x100) // Map PCI Configuration Space - Field(CFG,DWordAcc,NoLock,Preserve){ - Offset(0xA0), - BAR,32} // SPI Controller Base Address Register (Index 0xA0) - - Device(LDRC) // LPC device: Resource consumption - { - Name (_HID, EISAID("PNP0C02")) // ID for Motherboard resources - Name (CRS, ResourceTemplate () // Current Motherboard resources - { - Memory32Fixed(ReadWrite, // Setup for fixed resource location for SPI base address - 0x00000000, // Address Base - 0x00000000, // Address Length - BAR0 // Descriptor Name - ) - }) - - Method(_CRS,0,Serialized) - { - CreateDwordField(^CRS,^BAR0._BAS,SPIB) // Field to hold SPI base address - CreateDwordField(^CRS,^BAR0._LEN,SPIL) // Field to hold SPI address length - Store(BAR,SPIB) // SPI base address mapped - Store(0x1000,SPIL) // 4k space mapped - Return(CRS) - } - } - - /* Real Time Clock Device */ - Device(RTC0) { - Name(_HID, EISAID("PNP0B00")) /* AT Real Time Clock (not PIIX4 compatible) */ - Name(_CRS, ResourceTemplate() { - IRQNoFlags(){8} - IO(Decode16,0x0070, 0x0070, 0, 2) - }) - } /* End Device(_SB.PCI0.LpcIsaBr.RTC0) */ - - Device(TMR) { /* Timer */ - Name(_HID,EISAID("PNP0100")) /* System Timer */ - Name(_CRS, ResourceTemplate() { - IRQNoFlags(){0} - IO(Decode16, 0x0040, 0x0040, 0, 4) - }) - } /* End Device(_SB.PCI0.LpcIsaBr.TMR) */ - - Device(SPKR) { /* Speaker */ - Name(_HID,EISAID(IO61_HID)) - Name(_CRS, ResourceTemplate() { - IO(Decode16, 0x0061, 0x0061, 0, 1) - }) - } /* End Device(_SB.PCI0.LpcIsaBr.SPKR) */ - - Device(PIC) { - Name(_HID,EISAID("PNP0000")) /* AT Interrupt Controller */ - Name(_CRS, ResourceTemplate() { - IRQNoFlags(){2} - IO(Decode16,0x0020, 0x0020, 0, 2) - IO(Decode16,0x00a0, 0x00a0, 0, 2) - }) - } /* End Device(_SB.PCI0.LpcIsaBr.PIC) */ - - Device(MAD) { /* 8257 DMA */ - Name(_HID,EISAID("PNP0200")) /* Hardware Device ID */ - Name(_CRS, ResourceTemplate() { - DMA(Compatibility,BusMaster,Transfer8){4} - IO(Decode16, 0x0000, 0x0000, 0x10, 0x10) - IO(Decode16, 0x0081, 0x0081, 0x01, 0x03) - IO(Decode16, 0x0087, 0x0087, 0x01, 0x01) - IO(Decode16, 0x0089, 0x0089, 0x01, 0x03) - IO(Decode16, 0x008f, 0x008f, 0x01, 0x01) - IO(Decode16, 0x00c0, 0x00c0, 0x10, 0x20) - }) /* End Name(_SB.PCI0.LpcIsaBr.MAD._CRS) */ - } /* End Device(_SB.PCI0.LpcIsaBr.MAD) */ - - Device(COPR) { - Name(_HID,EISAID("PNP0C04")) /* Math Coprocessor */ - Name(_CRS, ResourceTemplate() { - IO(Decode16, 0x00f0, 0x00f0, 0, 0x10) - IRQNoFlags(){13} - }) - } /* End Device(_SB.PCI0.LpcIsaBr.COPR) */ -} /* end LPCB */ diff --git a/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl b/src/soc/amd/stoneyridge/acpi/sb_pci0_fch.asl index 1334df11c4..3623814080 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 @@ Device(SBUS) { /* 0:14.2 - I2S Audio */ /* 0:14.3 - LPC */ -#include "lpc.asl" +#include /* 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 0ac43857e5..6a7c58f96a 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 @@ struct soc_power_reg { #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 @@ uint32_t get_uma_size(void); * @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/lpc.c b/src/soc/amd/stoneyridge/lpc.c deleted file mode 100644 index 1741e92e0c..0000000000 --- a/src/soc/amd/stoneyridge/lpc.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2010-2017 Advanced Micro Devices, Inc. - * Copyright (C) 2014 Sage Electronic Engineering, LLC - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void lpc_init(struct device *dev) -{ - u8 byte; - - /* Initialize isa dma */ - isa_dma_init(); - - /* Enable DMA transaction on the LPC bus */ - byte = pci_read_config8(dev, LPC_PCI_CONTROL); - byte |= LEGACY_DMA_EN; - pci_write_config8(dev, LPC_PCI_CONTROL, byte); - - /* Disable the timeout mechanism on LPC */ - byte = pci_read_config8(dev, LPC_IO_OR_MEM_DECODE_ENABLE); - byte &= ~LPC_SYNC_TIMEOUT_COUNT_ENABLE; - pci_write_config8(dev, LPC_IO_OR_MEM_DECODE_ENABLE, byte); - - /* Disable LPC MSI Capability */ - byte = pci_read_config8(dev, LPC_MISC_CONTROL_BITS); - /* BIT 1 is not defined in public datasheet. */ - byte &= ~(1 << 1); - - /* - * Keep the old way. i.e., when bus master/DMA cycle is going - * on on LPC, it holds PCI grant, so no LPC slave cycle can - * interrupt and visit LPC. - */ - byte &= ~LPC_NOHOG; - pci_write_config8(dev, LPC_MISC_CONTROL_BITS, byte); - - /* - * Enable hand-instance of the pulse generator and SPI - * controller prefetch of flash. - */ - byte = pci_read_config8(dev, LPC_HOST_CONTROL); - byte |= PREFETCH_EN_SPI_FROM_HOST | T_START_ENH; - pci_write_config8(dev, LPC_HOST_CONTROL, byte); - - cmos_check_update_date(); - - /* - * Initialize the real time clock. - * The 0 argument tells cmos_init not to - * update CMOS unless it is invalid. - * 1 tells cmos_init to always initialize the CMOS. - */ - cmos_init(0); - - /* Initialize i8259 pic */ - setup_i8259(); - - /* Initialize i8254 timers */ - setup_i8254(); - - /* Set up SERIRQ, enable continuous mode */ - byte = (PM_SERIRQ_NUM_BITS_21 | PM_SERIRQ_ENABLE); - if (!CONFIG(SERIRQ_CONTINUOUS_MODE)) - byte |= PM_SERIRQ_MODE; - - pm_write8(PM_SERIRQ_CONF, byte); -} - -static void lpc_read_resources(struct device *dev) -{ - struct resource *res; - global_nvs_t *gnvs; - - /* Get the normal pci resources of this device */ - pci_dev_read_resources(dev); - - /* Add an extra subtractive resource for both memory and I/O. */ - res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); - res->base = 0; - res->size = 0x1000; - res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | - IORESOURCE_ASSIGNED | IORESOURCE_FIXED; - - res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); - res->base = FLASH_BASE_ADDR; - res->size = CONFIG_ROM_SIZE; - res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | - IORESOURCE_ASSIGNED | IORESOURCE_FIXED; - - /* Add a memory resource for the SPI BAR. */ - fixed_mem_resource(dev, 2, SPI_BASE_ADDRESS / 1024, 1, - IORESOURCE_SUBTRACTIVE); - - res = new_resource(dev, 3); /* IOAPIC */ - res->base = IO_APIC_ADDR; - res->size = 0x00001000; - res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; - - /* I2C devices (all 4 devices) */ - res = new_resource(dev, 4); - res->base = I2C_BASE_ADDRESS; - res->size = I2C_DEVICE_SIZE * I2C_DEVICE_COUNT; - res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; - - compact_resources(dev); - - /* Allocate ACPI NVS in CBMEM */ - gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(global_nvs_t)); - printk(BIOS_DEBUG, "ACPI GNVS at %p\n", gnvs); -} - -static void lpc_set_resources(struct device *dev) -{ - struct resource *res; - u32 spi_enable_bits; - - /* Special case. The SpiRomEnable and other enables should STAY set. */ - res = find_resource(dev, 2); - spi_enable_bits = pci_read_config32(dev, SPIROM_BASE_ADDRESS_REGISTER); - spi_enable_bits &= SPI_BASE_ALIGNMENT - 1; - pci_write_config32(dev, SPIROM_BASE_ADDRESS_REGISTER, - res->base | spi_enable_bits); - - pci_dev_set_resources(dev); -} - -static void set_child_resource(struct device *dev, struct device *child, - u32 *reg, u32 *reg_x) -{ - struct resource *res; - u32 base, end; - u32 rsize = 0, set = 0, set_x = 0; - int wideio_index; - - /* - * Be a bit relaxed, tolerate that LPC region might be bigger than - * resource we try to fit, do it like this for all regions < 16 bytes. - * If there is a resource > 16 bytes it must be 512 bytes to be able - * to allocate the fresh LPC window. - * - * AGESA and early initialization can set a wide IO port. This code - * will verify if required region was previously set and will avoid - * setting a new wide IO resource if one is already set. - */ - - for (res = child->resource_list; res; res = res->next) { - if (!(res->flags & IORESOURCE_IO)) - continue; - base = res->base; - end = resource_end(res); - printk(BIOS_DEBUG, - "Southbridge LPC decode:%s, base=0x%08x, end=0x%08x\n", - dev_path(child), base, end); - /* find a resource size */ - switch (base) { - case 0x60: /* KB */ - case 0x64: /* MS */ - set |= DECODE_ENABLE_KBC_PORT; - rsize = 1; - break; - case 0x3f8: /* COM1 */ - set |= DECODE_ENABLE_SERIAL_PORT0; - rsize = 8; - break; - case 0x2f8: /* COM2 */ - set |= DECODE_ENABLE_SERIAL_PORT1; - rsize = 8; - break; - case 0x378: /* Parallel 1 */ - set |= DECODE_ENABLE_PARALLEL_PORT0; - /* enable 0x778 for ECP mode */ - set |= DECODE_ENABLE_PARALLEL_PORT1; - rsize = 8; - break; - case 0x3f0: /* FD0 */ - set |= DECODE_ENABLE_FDC_PORT0; - rsize = 8; - break; - case 0x220: /* 0x220 - 0x227 */ - set |= DECODE_ENABLE_SERIAL_PORT2; - rsize = 8; - break; - case 0x228: /* 0x228 - 0x22f */ - set |= DECODE_ENABLE_SERIAL_PORT3; - rsize = 8; - break; - case 0x238: /* 0x238 - 0x23f */ - set |= DECODE_ENABLE_SERIAL_PORT4; - rsize = 8; - break; - case 0x300: /* 0x300 - 0x301 */ - set |= DECODE_ENABLE_MIDI_PORT0; - rsize = 2; - break; - case 0x400: - set_x |= DECODE_IO_PORT_ENABLE0; - rsize = 0x40; - break; - case 0x480: - set_x |= DECODE_IO_PORT_ENABLE1; - rsize = 0x40; - break; - case 0x500: - set_x |= DECODE_IO_PORT_ENABLE2; - rsize = 0x40; - break; - case 0x580: - set_x |= DECODE_IO_PORT_ENABLE3; - rsize = 0x40; - break; - case 0x4700: - set_x |= DECODE_IO_PORT_ENABLE5; - rsize = 0xc; - break; - case 0xfd60: - set_x |= DECODE_IO_PORT_ENABLE6; - rsize = 16; - break; - default: - rsize = 0; - wideio_index = sb_find_wideio_range(base, res->size); - if (wideio_index != WIDEIO_RANGE_ERROR) { - rsize = sb_wideio_size(wideio_index); - printk(BIOS_DEBUG, "Covered by wideIO"); - printk(BIOS_DEBUG, " %d\n", wideio_index); - } - } - /* check if region found and matches the enable */ - if (res->size <= rsize) { - *reg |= set; - *reg_x |= set_x; - /* check if we can fit resource in variable range */ - } else { - wideio_index = sb_set_wideio_range(base, res->size); - if (wideio_index != WIDEIO_RANGE_ERROR) { - /* preserve wide IO related bits. */ - *reg_x = pci_read_config32(dev, - LPC_IO_OR_MEM_DECODE_ENABLE); - - printk(BIOS_DEBUG, - "Range assigned to wide IO %d\n", - wideio_index); - } else { - printk(BIOS_ERR, - "cannot fit LPC decode region:"); - printk(BIOS_ERR, - "%s, base = 0x%08x, end = 0x%08x\n", - dev_path(child), base, end); - } - } - } -} - -/** - * @brief Enable resources for children devices - * - * @param dev the device whose children's resources are to be enabled - * - */ -static void lpc_enable_childrens_resources(struct device *dev) -{ - struct bus *link; - u32 reg, reg_x; - - reg = pci_read_config32(dev, LPC_IO_PORT_DECODE_ENABLE); - reg_x = pci_read_config32(dev, LPC_IO_OR_MEM_DECODE_ENABLE); - - for (link = dev->link_list; link; link = link->next) { - struct device *child; - for (child = link->children; child; - child = child->sibling) { - if (child->enabled - && (child->path.type == DEVICE_PATH_PNP)) - set_child_resource(dev, child, ®, ®_x); - } - } - pci_write_config32(dev, LPC_IO_PORT_DECODE_ENABLE, reg); - pci_write_config32(dev, LPC_IO_OR_MEM_DECODE_ENABLE, reg_x); -} - -static void lpc_enable_resources(struct device *dev) -{ - pci_dev_enable_resources(dev); - lpc_enable_childrens_resources(dev); -} - -static struct pci_operations lops_pci = { - .set_subsystem = pci_dev_set_subsystem, -}; - -static struct device_operations lpc_ops = { - .read_resources = lpc_read_resources, - .set_resources = lpc_set_resources, - .enable_resources = lpc_enable_resources, - .acpi_inject_dsdt_generator = southbridge_inject_dsdt, - .write_acpi_tables = southbridge_write_acpi_tables, - .init = lpc_init, - .scan_bus = scan_lpc_bus, - .ops_pci = &lops_pci, -}; - -static const unsigned short pci_device_ids[] = { - PCI_DEVICE_ID_AMD_SB900_LPC, - PCI_DEVICE_ID_AMD_CZ_LPC, - 0 -}; -static const struct pci_driver lpc_driver __pci_driver = { - .ops = &lpc_ops, - .vendor = PCI_VENDOR_ID_AMD, - .devices = pci_device_ids, -}; diff --git a/src/soc/amd/stoneyridge/southbridge.c b/src/soc/amd/stoneyridge/southbridge.c index b8d0595965..cd910319a5 100644 --- a/src/soc/amd/stoneyridge/southbridge.c +++ b/src/soc/amd/stoneyridge/southbridge.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -152,130 +153,12 @@ const static struct irq_idx_name irq_association[] = { { 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 @@ void enable_aoac_devices(void) } 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 @@ void sb_lpc_port80(void) 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 @@ void sb_lpc_decode(void) | 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 @@ void sb_clk_output_48Mhz(u32 osc) 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 @@ void sb_read_mode(u32 mode) & ~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 @@ void bootblock_fch_early_init(void) { 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 c682d980bb..8abfa160f4 100644 --- a/src/soc/amd/stoneyridge/spi.c +++ b/src/soc/amd/stoneyridge/spi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #define SPI_DEBUG_DRIVER CONFIG(DEBUG_SPI_FLASH) @@ -103,11 +104,7 @@ static int execute_command(void) 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, -- cgit v1.2.3