Richard Spiegel has uploaded this change for review. ( https://review.coreboot.org/22590
Change subject: amd/stoneyridge: Create new wide IO functions ......................................................................
amd/stoneyridge: Create new wide IO functions
Create new generic wide IO functions in southbridge.c. These new functions must be usable by kahlee/ec.c and amd/stoneyridge/lpc.c.
BUG=b:64033893
Change-Id: Icd0841a1959f3e109b3c35fa35bb4b3c44099dc3 Signed-off-by: Richard Spiegel richard.spiegel@silverbackltd.com --- M src/soc/amd/stoneyridge/include/soc/southbridge.h M src/soc/amd/stoneyridge/southbridge.c 2 files changed, 134 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/90/22590/1
diff --git a/src/soc/amd/stoneyridge/include/soc/southbridge.h b/src/soc/amd/stoneyridge/include/soc/southbridge.h index 238feba..beb9af8 100644 --- a/src/soc/amd/stoneyridge/include/soc/southbridge.h +++ b/src/soc/amd/stoneyridge/include/soc/southbridge.h @@ -259,6 +259,12 @@
#define FCH_MISC_REG40_OSCOUT1_EN BIT(2)
+/* Return values for sb_find_wideio_range and sb_set_wideio_range. */ +#define WIDE_IO_RANGE_0 0x00 +#define WIDE_IO_RANGE_1 0x01 +#define WIDE_IO_RANGE_2 0x02 +#define WIDE_IO_RANGE_FAILED 0x80 + static inline int sb_sata_enable(void) { /* True if IDE or AHCI. */ @@ -306,5 +312,8 @@ int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos); int s3_save_nvram_early(u32 dword, int size, int nvram_pos); void bootblock_fch_early_init(void); +uint16_t sb_wideio_size(uint8_t index); +uint8_t sb_find_wideio_range(uint16_t start, uint16_t end); +uint8_t sb_set_wideio_range(uint16_t start, uint16_t size);
#endif /* __STONEYRIDGE_H__ */ diff --git a/src/soc/amd/stoneyridge/southbridge.c b/src/soc/amd/stoneyridge/southbridge.c index dbf27bc..51e0e96 100644 --- a/src/soc/amd/stoneyridge/southbridge.c +++ b/src/soc/amd/stoneyridge/southbridge.c @@ -31,6 +31,131 @@ #include <delay.h> #include <soc/pci_devs.h>
+/* + * 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[3]; + uint16_t port[3]; + uint8_t alt[3]; +} wio_io_en = { + { + LPC_WIDEIO0_ENABLE, + LPC_WIDEIO1_ENABLE, + LPC_WIDEIO2_ENABLE + }, + { + LPC_WIDEIO_GENERIC_PORT, + LPC_WIDEIO1_GENERIC_PORT, + LPC_WIDEIO2_GENERIC_PORT + }, + { + LPC_ALT_WIDEIO0_ENABLE, + LPC_ALT_WIDEIO1_ENABLE, + 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 sb_wideio_size(uint8_t index) +{ + uint32_t enable_register; + uint16_t size = 0; + uint8_t alternate_register; + + if (index < 3) { + 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.enable[index]) + size = (alternate_register & wio_io_en.alt[index]) ? + 16 : 512; + } + return size; +} + +/** + * @brief Identify if any LPC wide IO is covering the IO range + * + * @param start = start of IO range + * @param end = end of IO range + * + * @return Index of wide IO covering the range or error + */ +uint8_t sb_find_wideio_range(uint16_t start, uint16_t end) +{ + uint32_t enable_register; + int i; + uint16_t reg_var[3], current_size; + uint16_t end_wideio; + uint8_t index = WIDE_IO_RANGE_FAILED; + + enable_register = pci_read_config32(SOC_LPC_DEV, + LPC_IO_OR_MEM_DECODE_ENABLE); + for (i = 0; i < 3; i++) + reg_var[i] = pci_read_config16(SOC_LPC_DEV, wio_io_en.port[i]); + + for (i = 0; i < 3; i++) { + current_size = sb_wideio_size(i); + if (current_size == 0) + continue; + end_wideio = reg_var[i] + current_size; + if ((start >= reg_var[i]) && (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 + */ +uint8_t sb_set_wideio_range(uint16_t start, uint16_t size) +{ + int i; + uint32_t enable_register; + uint8_t alternate_register; + uint8_t status = WIDE_IO_RANGE_FAILED; + + 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 < 3; i++) { + if ((enable_register & wio_io_en.enable[i]) == 0) { + status = i; + pci_write_config16(SOC_LPC_DEV, wio_io_en.port[i], + start); + enable_register |= wio_io_en.enable[i]; + pci_write_config32(SOC_LPC_DEV, + LPC_IO_OR_MEM_DECODE_ENABLE, + enable_register); + if (size <= 16) { + alternate_register |= wio_io_en.alt[i]; + pci_write_config8(SOC_LPC_DEV, + LPC_ALT_WIDEIO_RANGE_ENABLE, + alternate_register); + } + break; + } + } + return status; +} + void configure_stoneyridge_uart(void) { u8 byte, byte2;