Angel Pons | ae59387 | 2020-04-04 18:50:57 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 2 | |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 3 | #include <device/mmio.h> |
| 4 | #include <bootstate.h> |
Raul E Rangel | be2b5ac | 2020-06-04 16:36:33 -0600 | [diff] [blame] | 5 | #include <cpu/amd/msr.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 6 | #include <cpu/x86/smm.h> |
Marshall Dawson | 39a4ac1 | 2019-06-20 16:28:33 -0600 | [diff] [blame] | 7 | #include <cpu/x86/msr.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 8 | #include <device/device.h> |
| 9 | #include <device/pci.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 10 | #include <device/pci_ops.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 11 | #include <amdblocks/amd_pci_util.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 12 | #include <amdblocks/reset.h> |
| 13 | #include <amdblocks/acpimmio.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 14 | #include <amdblocks/acpi.h> |
Felix Held | dea4e0f | 2021-09-22 20:05:53 +0200 | [diff] [blame] | 15 | #include <amdblocks/gpio.h> |
Karthikeyan Ramasubramanian | 4f87ae1 | 2021-03-18 23:16:29 -0600 | [diff] [blame] | 16 | #include <amdblocks/i2c.h> |
Felix Held | a5a5295 | 2020-12-01 18:14:01 +0100 | [diff] [blame] | 17 | #include <amdblocks/smi.h> |
Aaron Durbin | aa8f165 | 2020-08-17 17:41:28 -0600 | [diff] [blame] | 18 | #include <soc/acpi.h> |
Marshall Dawson | 39a4ac1 | 2019-06-20 16:28:33 -0600 | [diff] [blame] | 19 | #include <soc/cpu.h> |
Felix Held | 5b01f2b | 2020-05-20 16:01:43 +0200 | [diff] [blame] | 20 | #include <soc/i2c.h> |
Felix Held | da5553c | 2021-02-03 14:42:42 +0100 | [diff] [blame] | 21 | #include <soc/iomap.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 22 | #include <soc/southbridge.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 23 | #include <soc/smi.h> |
| 24 | #include <soc/amd_pci_int_defs.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 25 | #include <soc/pci_devs.h> |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 26 | #include <types.h> |
Furquan Shaikh | 69c2811 | 2020-04-28 18:57:52 -0700 | [diff] [blame] | 27 | #include "chip.h" |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 28 | |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 29 | /* |
| 30 | * Table of APIC register index and associated IRQ name. Using IDX_XXX_NAME |
| 31 | * provides a visible association with the index, therefore helping |
| 32 | * maintainability of table. If a new index/name is defined in |
| 33 | * amd_pci_int_defs.h, just add the pair at the end of this table. |
| 34 | * Order is not important. |
| 35 | */ |
| 36 | const static struct irq_idx_name irq_association[] = { |
| 37 | { PIRQ_A, "INTA#" }, |
| 38 | { PIRQ_B, "INTB#" }, |
| 39 | { PIRQ_C, "INTC#" }, |
| 40 | { PIRQ_D, "INTD#" }, |
| 41 | { PIRQ_E, "INTE#" }, |
Marshall Dawson | 39a4ac1 | 2019-06-20 16:28:33 -0600 | [diff] [blame] | 42 | { PIRQ_F, "INTF#/GENINT2" }, |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 43 | { PIRQ_G, "INTG#" }, |
| 44 | { PIRQ_H, "INTH#" }, |
| 45 | { PIRQ_MISC, "Misc" }, |
| 46 | { PIRQ_MISC0, "Misc0" }, |
| 47 | { PIRQ_MISC1, "Misc1" }, |
| 48 | { PIRQ_MISC2, "Misc2" }, |
| 49 | { PIRQ_SIRQA, "Ser IRQ INTA" }, |
| 50 | { PIRQ_SIRQB, "Ser IRQ INTB" }, |
| 51 | { PIRQ_SIRQC, "Ser IRQ INTC" }, |
| 52 | { PIRQ_SIRQD, "Ser IRQ INTD" }, |
| 53 | { PIRQ_SCI, "SCI" }, |
| 54 | { PIRQ_SMBUS, "SMBUS" }, |
| 55 | { PIRQ_ASF, "ASF" }, |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 56 | { PIRQ_PMON, "PerMon" }, |
| 57 | { PIRQ_SD, "SD" }, |
Marshall Dawson | 39a4ac1 | 2019-06-20 16:28:33 -0600 | [diff] [blame] | 58 | { PIRQ_SDIO, "SDIO" }, |
| 59 | { PIRQ_CIR, "CIR" }, |
| 60 | { PIRQ_GPIOA, "GPIOa" }, |
| 61 | { PIRQ_GPIOB, "GPIOb" }, |
| 62 | { PIRQ_GPIOC, "GPIOc" }, |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 63 | { PIRQ_SATA, "SATA" }, |
Marshall Dawson | 39a4ac1 | 2019-06-20 16:28:33 -0600 | [diff] [blame] | 64 | { PIRQ_EMMC, "eMMC" }, |
| 65 | { PIRQ_GPP0, "GPP0" }, |
| 66 | { PIRQ_GPP1, "GPP1" }, |
| 67 | { PIRQ_GPP2, "GPP2" }, |
| 68 | { PIRQ_GPP3, "GPP3" }, |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 69 | { PIRQ_GPIO, "GPIO" }, |
| 70 | { PIRQ_I2C0, "I2C0" }, |
| 71 | { PIRQ_I2C1, "I2C1" }, |
| 72 | { PIRQ_I2C2, "I2C2" }, |
| 73 | { PIRQ_I2C3, "I2C3" }, |
| 74 | { PIRQ_UART0, "UART0" }, |
| 75 | { PIRQ_UART1, "UART1" }, |
Marshall Dawson | 39a4ac1 | 2019-06-20 16:28:33 -0600 | [diff] [blame] | 76 | { PIRQ_I2C4, "I2C4" }, |
| 77 | { PIRQ_I2C5, "I2C5" }, |
| 78 | { PIRQ_UART2, "UART2" }, |
| 79 | { PIRQ_UART3, "UART3" }, |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 80 | }; |
| 81 | |
| 82 | const struct irq_idx_name *sb_get_apic_reg_association(size_t *size) |
| 83 | { |
| 84 | *size = ARRAY_SIZE(irq_association); |
| 85 | return irq_association; |
| 86 | } |
| 87 | |
Felix Held | f66e781 | 2021-07-22 17:38:27 +0200 | [diff] [blame] | 88 | static void fch_clk_output_48Mhz(void) |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 89 | { |
| 90 | u32 ctrl; |
Karthikeyan Ramasubramanian | 39b7afa | 2021-04-29 16:50:51 -0600 | [diff] [blame] | 91 | const struct soc_amd_picasso_config *cfg = config_of_soc(); |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 92 | |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 93 | ctrl = misc_read32(MISC_CLK_CNTL1); |
Eric Lai | dd32e65 | 2020-12-15 14:51:50 +0800 | [diff] [blame] | 94 | /* If used external clock source for I2S, disable the internal clock output */ |
Karthikeyan Ramasubramanian | 39b7afa | 2021-04-29 16:50:51 -0600 | [diff] [blame] | 95 | if (cfg->acp_i2s_use_external_48mhz_osc && |
| 96 | cfg->common_config.acp_config.acp_pin_cfg == I2S_PINS_I2S_TDM) |
Eric Lai | dd32e65 | 2020-12-15 14:51:50 +0800 | [diff] [blame] | 97 | ctrl &= ~BP_X48M0_OUTPUT_EN; |
| 98 | else |
| 99 | ctrl |= BP_X48M0_OUTPUT_EN; |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 100 | misc_write32(MISC_CLK_CNTL1, ctrl); |
| 101 | } |
| 102 | |
Chris Wang | ad4f6d7 | 2021-01-26 20:09:34 +0800 | [diff] [blame] | 103 | static void sb_rfmux_config_override(void) |
| 104 | { |
| 105 | u8 port; |
| 106 | const struct soc_amd_picasso_config *cfg; |
| 107 | |
| 108 | cfg = config_of_soc(); |
| 109 | |
| 110 | for (port = 0; port < USB_PD_PORT_COUNT; port++) { |
| 111 | if (cfg->usb_pd_config_override[port].rfmux_override_en) { |
| 112 | write32((void *)(USB_PD_PORT_CONTROL + PD_PORT_MUX_OFFSET(port)), |
| 113 | cfg->usb_pd_config_override[port].rfmux_config |
| 114 | | USB_PD_RFMUX_OVERRIDE); |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | |
Felix Held | ee1fb0a | 2021-02-02 01:10:59 +0100 | [diff] [blame] | 119 | static void fch_init_acpi_ports(void) |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 120 | { |
| 121 | u32 reg; |
| 122 | |
| 123 | /* We use some of these ports in SMM regardless of whether or not |
| 124 | * ACPI tables are generated. Enable these ports indiscriminately. |
| 125 | */ |
| 126 | |
| 127 | pm_write16(PM_EVT_BLK, ACPI_PM_EVT_BLK); |
| 128 | pm_write16(PM1_CNT_BLK, ACPI_PM1_CNT_BLK); |
| 129 | pm_write16(PM_TMR_BLK, ACPI_PM_TMR_BLK); |
| 130 | pm_write16(PM_GPE0_BLK, ACPI_GPE0_BLK); |
Marshall Dawson | 39a4ac1 | 2019-06-20 16:28:33 -0600 | [diff] [blame] | 131 | |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 132 | if (CONFIG(HAVE_SMI_HANDLER)) { |
| 133 | /* APMC - SMI Command Port */ |
| 134 | pm_write16(PM_ACPI_SMI_CMD, APM_CNT); |
| 135 | configure_smi(SMITYPE_SMI_CMD_PORT, SMI_MODE_SMI); |
| 136 | |
| 137 | /* SMI on SlpTyp requires sending SMI before completion |
Felix Held | 5dd52c7 | 2021-02-10 19:53:38 +0100 | [diff] [blame] | 138 | response of the I/O write. */ |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 139 | reg = pm_read32(PM_PCI_CTRL); |
| 140 | reg |= FORCE_SLPSTATE_RETRY; |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 141 | pm_write32(PM_PCI_CTRL, reg); |
| 142 | |
| 143 | /* Disable SlpTyp feature */ |
| 144 | reg = pm_read8(PM_RST_CTRL1); |
| 145 | reg &= ~SLPTYPE_CONTROL_EN; |
| 146 | pm_write8(PM_RST_CTRL1, reg); |
| 147 | |
| 148 | configure_smi(SMITYPE_SLP_TYP, SMI_MODE_SMI); |
| 149 | } else { |
| 150 | pm_write16(PM_ACPI_SMI_CMD, 0); |
| 151 | } |
| 152 | |
| 153 | /* Decode ACPI registers and enable standard features */ |
| 154 | pm_write8(PM_ACPI_CONF, PM_ACPI_DECODE_STD | |
| 155 | PM_ACPI_GLOBAL_EN | |
| 156 | PM_ACPI_RTC_EN_EN | |
| 157 | PM_ACPI_TIMER_EN_EN); |
| 158 | } |
| 159 | |
Matt Papageorge | ab83b43 | 2020-06-26 08:47:00 -0500 | [diff] [blame] | 160 | /* |
| 161 | * A-Link to AHB bridge, part of the AMBA fabric. These are internal clocks |
| 162 | * and unneeded for Raven/Picasso so gate them to save power. |
| 163 | */ |
| 164 | static void al2ahb_clock_gate(void) |
| 165 | { |
| 166 | uint8_t al2ahb_val; |
| 167 | uintptr_t al2ahb_base = ALINK_AHB_ADDRESS; |
| 168 | |
| 169 | al2ahb_val = read8((void *)(al2ahb_base + AL2AHB_CONTROL_CLK_OFFSET)); |
| 170 | al2ahb_val |= AL2AHB_CLK_GATE_EN; |
| 171 | write8((void *)(al2ahb_base + AL2AHB_CONTROL_CLK_OFFSET), al2ahb_val); |
| 172 | al2ahb_val = read8((void *)(al2ahb_base + AL2AHB_CONTROL_HCLK_OFFSET)); |
| 173 | al2ahb_val |= AL2AHB_HCLK_GATE_EN; |
| 174 | write8((void *)(al2ahb_base + AL2AHB_CONTROL_HCLK_OFFSET), al2ahb_val); |
| 175 | } |
| 176 | |
Martin Roth | 26f97f9 | 2021-10-01 14:53:22 -0600 | [diff] [blame] | 177 | /* configure the general purpose PCIe clock outputs according to the devicetree settings */ |
Felix Held | 82a0a63 | 2020-08-28 01:40:20 +0200 | [diff] [blame] | 178 | static void gpp_clk_setup(void) |
| 179 | { |
| 180 | const struct soc_amd_picasso_config *cfg = config_of_soc(); |
| 181 | |
| 182 | /* look-up table to be able to iterate over the PCIe clock output settings */ |
| 183 | const uint8_t gpp_clk_shift_lut[GPP_CLK_OUTPUT_COUNT] = { |
| 184 | GPP_CLK0_REQ_SHIFT, |
| 185 | GPP_CLK1_REQ_SHIFT, |
| 186 | GPP_CLK2_REQ_SHIFT, |
| 187 | GPP_CLK3_REQ_SHIFT, |
| 188 | GPP_CLK4_REQ_SHIFT, |
| 189 | GPP_CLK5_REQ_SHIFT, |
| 190 | GPP_CLK6_REQ_SHIFT, |
| 191 | }; |
| 192 | |
| 193 | uint32_t gpp_clk_ctl = misc_read32(GPP_CLK_CNTRL); |
| 194 | |
| 195 | for (int i = 0; i < GPP_CLK_OUTPUT_COUNT; i++) { |
| 196 | gpp_clk_ctl &= ~GPP_CLK_REQ_MASK(gpp_clk_shift_lut[i]); |
| 197 | /* |
| 198 | * The remapping of values is done so that the default of the enum used for the |
| 199 | * devicetree settings is the clock being enabled, so that a missing devicetree |
| 200 | * configuration for this will result in an always active clock and not an |
| 201 | * inactive PCIe clock output. |
| 202 | */ |
| 203 | switch (cfg->gpp_clk_config[i]) { |
| 204 | case GPP_CLK_REQ: |
| 205 | gpp_clk_ctl |= GPP_CLK_REQ_EXT(gpp_clk_shift_lut[i]); |
| 206 | break; |
| 207 | case GPP_CLK_OFF: |
| 208 | gpp_clk_ctl |= GPP_CLK_REQ_OFF(gpp_clk_shift_lut[i]); |
| 209 | break; |
| 210 | case GPP_CLK_ON: |
| 211 | default: |
| 212 | gpp_clk_ctl |= GPP_CLK_REQ_ON(gpp_clk_shift_lut[i]); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | misc_write32(GPP_CLK_CNTRL, gpp_clk_ctl); |
| 217 | } |
| 218 | |
Felix Held | faaafb4 | 2021-01-28 23:19:40 +0100 | [diff] [blame] | 219 | void fch_init(void *chip_info) |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 220 | { |
Aaron Durbin | 09f60ff | 2020-04-09 15:24:50 -0600 | [diff] [blame] | 221 | i2c_soc_init(); |
Felix Held | ee1fb0a | 2021-02-02 01:10:59 +0100 | [diff] [blame] | 222 | fch_init_acpi_ports(); |
Aaron Durbin | 404a5c3 | 2020-08-14 16:27:27 -0600 | [diff] [blame] | 223 | |
Kyösti Mälkki | b0db813 | 2021-01-21 16:34:43 +0200 | [diff] [blame] | 224 | acpi_pm_gpe_add_events_print_events(); |
| 225 | gpio_add_events(); |
| 226 | |
Matt Papageorge | ab83b43 | 2020-06-26 08:47:00 -0500 | [diff] [blame] | 227 | al2ahb_clock_gate(); |
Felix Held | 82a0a63 | 2020-08-28 01:40:20 +0200 | [diff] [blame] | 228 | |
| 229 | gpp_clk_setup(); |
Eric Lai | 3b648ba | 2020-12-18 10:51:46 +0800 | [diff] [blame] | 230 | |
Felix Held | f66e781 | 2021-07-22 17:38:27 +0200 | [diff] [blame] | 231 | fch_clk_output_48Mhz(); |
Chris Wang | ad4f6d7 | 2021-01-26 20:09:34 +0800 | [diff] [blame] | 232 | |
| 233 | sb_rfmux_config_override(); |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 234 | } |
| 235 | |
Felix Held | faaafb4 | 2021-01-28 23:19:40 +0100 | [diff] [blame] | 236 | void fch_final(void *chip_info) |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 237 | { |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 238 | } |
| 239 | |
| 240 | /* |
| 241 | * Update the PCI devices with a valid IRQ number |
| 242 | * that is set in the mainboard PCI_IRQ structures. |
| 243 | */ |
| 244 | static void set_pci_irqs(void *unused) |
| 245 | { |
| 246 | /* Write PCI_INTR regs 0xC00/0xC01 */ |
| 247 | write_pci_int_table(); |
| 248 | |
Raul E Rangel | 4e80fae | 2020-12-16 10:08:41 -0700 | [diff] [blame] | 249 | /* pirq_data is consumed by `write_pci_cfg_irqs` */ |
| 250 | populate_pirq_data(); |
| 251 | |
Martin Roth | 5c354b9 | 2019-04-22 14:55:16 -0600 | [diff] [blame] | 252 | /* Write IRQs for all devicetree enabled devices */ |
| 253 | write_pci_cfg_irqs(); |
| 254 | } |
| 255 | |
| 256 | /* |
| 257 | * Hook this function into the PCI state machine |
| 258 | * on entry into BS_DEV_ENABLE. |
| 259 | */ |
| 260 | BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_ENTRY, set_pci_irqs, NULL); |