summaryrefslogtreecommitdiff
path: root/src/soc/amd
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/amd')
-rw-r--r--src/soc/amd/stoneyridge/include/soc/southbridge.h29
-rw-r--r--src/soc/amd/stoneyridge/southbridge.c121
2 files changed, 150 insertions, 0 deletions
diff --git a/src/soc/amd/stoneyridge/include/soc/southbridge.h b/src/soc/amd/stoneyridge/include/soc/southbridge.h
index 3b9ea80934..bbf6344f6a 100644
--- a/src/soc/amd/stoneyridge/include/soc/southbridge.h
+++ b/src/soc/amd/stoneyridge/include/soc/southbridge.h
@@ -290,6 +290,9 @@
#define OC_PORT2_SHIFT 8
#define OC_PORT3_SHIFT 12
+#define WIDEIO_RANGE_ERROR -1
+#define TOTAL_WIDEIO_PORTS 3
+
static inline int sb_sata_enable(void)
{
/* True if IDE or AHCI. */
@@ -343,6 +346,32 @@ uint32_t xhci_pm_read32(uint8_t reg);
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);
+/**
+ * @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
diff --git a/src/soc/amd/stoneyridge/southbridge.c b/src/soc/amd/stoneyridge/southbridge.c
index 44dbf62a1c..f8e06b3c5e 100644
--- a/src/soc/amd/stoneyridge/southbridge.c
+++ b/src/soc/amd/stoneyridge/southbridge.c
@@ -82,12 +82,133 @@ const static struct irq_idx_name irq_association[] = {
{ PIRQ_UART1, "UART1\t" },
};
+/*
+ * 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)
+{
+ uint32_t enable_register;
+ int i, index = WIDEIO_RANGE_ERROR;
+ uint16_t end, current_size, start_wideio, end_wideio;
+
+ end = start + size;
+ enable_register = pci_read_config32(SOC_LPC_DEV,
+ LPC_IO_OR_MEM_DECODE_ENABLE);
+ 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;
+}
+
void configure_stoneyridge_uart(void)
{
u8 byte, byte2;