coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
fch.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <amdblocks/acpi.h>
4 #include <amdblocks/acpimmio.h>
6 #include <amdblocks/gpio.h>
7 #include <amdblocks/i2c.h>
8 #include <amdblocks/smi.h>
9 #include <assert.h>
10 #include <bootstate.h>
11 #include <cpu/x86/smm.h>
12 #include <device/device.h>
13 #include <device/pci.h>
14 #include <device/pci_ids.h>
15 #include <fw_config.h>
16 #include <soc/amd_pci_int_defs.h>
17 #include <soc/iomap.h>
18 #include <soc/i2c.h>
19 #include <soc/platform_descriptors.h>
20 #include <soc/smi.h>
21 #include <soc/southbridge.h>
22 #include "chip.h"
23 
24 /*
25  * Table of APIC register index and associated IRQ name. Using IDX_XXX_NAME
26  * provides a visible association with the index, therefore helping
27  * maintainability of table. If a new index/name is defined in
28  * amd_pci_int_defs.h, just add the pair at the end of this table.
29  * Order is not important.
30  */
31 const static struct irq_idx_name irq_association[] = {
32  { PIRQ_A, "INTA#" },
33  { PIRQ_B, "INTB#" },
34  { PIRQ_C, "INTC#" },
35  { PIRQ_D, "INTD#" },
36  { PIRQ_E, "INTE#" },
37  { PIRQ_F, "INTF#/GENINT2" },
38  { PIRQ_G, "INTG#" },
39  { PIRQ_H, "INTH#" },
40  { PIRQ_MISC, "Misc" },
41  { PIRQ_MISC0, "Misc0" },
42  { PIRQ_HPET_L, "HPET_L" },
43  { PIRQ_HPET_H, "HPET_H" },
44  { PIRQ_SIRQA, "Ser IRQ INTA" },
45  { PIRQ_SIRQB, "Ser IRQ INTB" },
46  { PIRQ_SIRQC, "Ser IRQ INTC" },
47  { PIRQ_SIRQD, "Ser IRQ INTD" },
48  { PIRQ_SCI, "SCI" },
49  { PIRQ_SMBUS, "SMBUS" },
50  { PIRQ_ASF, "ASF" },
51  { PIRQ_PMON, "PerMon" },
52  { PIRQ_SD, "SD" },
53  { PIRQ_SDIO, "SDIO" },
54  { PIRQ_CIR, "CIR" },
55  { PIRQ_GPIOA, "GPIOa" },
56  { PIRQ_GPIOB, "GPIOb" },
57  { PIRQ_GPIOC, "GPIOc" },
58  { PIRQ_SATA, "SATA" },
59  { PIRQ_EMMC, "eMMC" },
60  { PIRQ_GPP0, "GPP0" },
61  { PIRQ_GPP1, "GPP1" },
62  { PIRQ_GPP2, "GPP2" },
63  { PIRQ_GPP3, "GPP3" },
64  { PIRQ_GPIO, "GPIO" },
65  { PIRQ_I2C0, "I2C0" },
66  { PIRQ_I2C1, "I2C1" },
67  { PIRQ_I2C2, "I2C2" },
68  { PIRQ_I2C3, "I2C3" },
69  { PIRQ_UART0, "UART0" },
70  { PIRQ_UART1, "UART1" },
71  { PIRQ_I2C4, "I2C4" },
72  { PIRQ_I2C5, "I2C5" },
73 };
74 
75 const struct irq_idx_name *sb_get_apic_reg_association(size_t *size)
76 {
77  *size = ARRAY_SIZE(irq_association);
78  return irq_association;
79 }
80 
81 static void fch_clk_output_48Mhz(void)
82 {
84  /* Enable BP_X48M0 Clock Output */
85  ctrl |= BP_X48M0_OUTPUT_EN;
86  /* Disable clock output in S0i3 */
87  ctrl |= BP_X48M0_S0I3_DIS;
89 }
90 
91 static void fch_init_acpi_ports(void)
92 {
93  u32 reg;
94 
95  /* We use some of these ports in SMM regardless of whether or not
96  * ACPI tables are generated. Enable these ports indiscriminately.
97  */
98 
103 
104  if (CONFIG(HAVE_SMI_HANDLER)) {
105  /* APMC - SMI Command Port */
108 
109  /* SMI on SlpTyp requires sending SMI before completion
110  response of the I/O write. */
111  reg = pm_read32(PM_PCI_CTRL);
112  reg |= FORCE_SLPSTATE_RETRY;
113  pm_write32(PM_PCI_CTRL, reg);
114 
115  /* Disable SlpTyp feature */
116  reg = pm_read8(PM_RST_CTRL1);
117  reg &= ~SLPTYPE_CONTROL_EN;
118  pm_write8(PM_RST_CTRL1, reg);
119 
121  } else {
123  }
124 
125  /* Decode ACPI registers and enable standard features */
130 }
131 
132 static void fch_init_resets(void)
133 {
135 }
136 
137 /* Update gpp glk req config based on DXIO descriptors and enabled devices. */
138 static void gpp_dxio_update_clk_req_config(enum gpp_clk_req *gpp_clk_config,
139  size_t gpp_clk_config_num)
140 {
141  const fsp_dxio_descriptor *dxio_descs = NULL;
142  const fsp_ddi_descriptor *ddi_descs = NULL;
143  size_t dxio_num = 0;
144  size_t ddi_num = 0;
145 
146  mainboard_get_dxio_ddi_descriptors(&dxio_descs, &dxio_num, &ddi_descs, &ddi_num);
147  if (dxio_descs == NULL) {
149  "No DXIO descriptors found, GPP clk req may not reflect enabled devices\n");
150  return;
151  }
152 
153  for (int i = 0; i < dxio_num; i++) {
154  const fsp_dxio_descriptor *dxio_desc = &dxio_descs[i];
155 
156  /* Only consider PCIe and unused engine types. */
157  if (dxio_desc->engine_type != PCIE_ENGINE
158  && dxio_desc->engine_type != UNUSED_ENGINE)
159  continue;
160  enum cpm_clk_req dxio_clk_req = dxio_desc->clk_req;
161 
162  /* CLK_DISABLE means there's no corresponding clk req line in use */
163  if (dxio_clk_req == CLK_DISABLE)
164  continue;
165 
166  /*
167  * dxio_clk_req is only 4 bits so having CLK_ENABLE as a value for
168  * a descriptor should cause a compiler error. 0xF isn't a
169  * valid clk_req value according to AMD's internal code either.
170  * This is here to draw attention in case this code is ever used
171  * in a situation where this has changed.
172  */
173  if (dxio_clk_req == (CLK_ENABLE & 0xF)) {
175  "CLK_ENABLE is an invalid clk_req value for PCIe device %d.%d, DXIO descriptor %d\n",
176  dxio_desc->device_number, dxio_desc->function_number, i);
177  continue;
178  }
179 
180  /* cpm_clk_req 0 is CLK_DISABLE */
181  int gpp_req_index = dxio_clk_req - CLK_REQ0;
182  /* Ensure that our index is valid */
183  if (gpp_req_index < 0 || gpp_req_index >= gpp_clk_config_num) {
184  printk(BIOS_ERR, "Failed to convert DXIO clk req value %d to GPP clk req index for PCIe device %d.%d, DXIO descriptor %d, clk req settings may be incorrect\n",
185  dxio_clk_req, dxio_desc->device_number,
186  dxio_desc->function_number, i);
187  continue;
188  }
189 
190  const struct device *pci_device = pcidev_path_on_root(
191  PCI_DEVFN(dxio_desc->device_number, dxio_desc->function_number));
192  if (pci_device == NULL) {
193  gpp_clk_config[gpp_req_index] = GPP_CLK_OFF;
195  "Cannot find PCIe device %d.%d, disabling GPP clk req %d, DXIO descriptor %d\n",
196  dxio_desc->device_number, dxio_desc->function_number, i,
197  gpp_req_index);
198  continue;
199  }
200 
201  /* PCIe devices haven't been fully set up yet, so directly read the vendor id
202  * and device id to determine if a device is physically present. If a device
203  * is not present then the id should be 0xffffffff. 0x00000000, 0xffff0000,
204  * and 0x0000ffff are there to account for any odd failure cases. */
205  u32 id = pci_read_config32(pci_device, PCI_VENDOR_ID);
206  bool enabled = pci_device->enabled && (id != 0xffffffff) &&
207  (id != 0x00000000) && (id != 0x0000ffff) && (id != 0xffff0000);
208 
209  /* Inform of possible mismatches between devices and SoC gpp_clk_config. */
210  if (!enabled && gpp_clk_config[gpp_req_index] != GPP_CLK_OFF) {
211  gpp_clk_config[gpp_req_index] = GPP_CLK_OFF;
213  "PCIe device %d.%d disabled, disabling GPP clk req %d, DXIO descriptor %d\n",
214  dxio_desc->device_number, dxio_desc->function_number,
215  gpp_req_index, i);
216  } else if (enabled && gpp_clk_config[gpp_req_index] == GPP_CLK_OFF) {
218  "PCIe device %d.%d enabled, GPP clk req is off, DXIO descriptor %d\n",
219  dxio_desc->device_number, dxio_desc->function_number, i);
220  }
221  }
222 }
223 
224 /* Configure the general purpose PCIe clock outputs according to the devicetree settings */
225 static void gpp_clk_setup(void)
226 {
227  struct soc_amd_cezanne_config *cfg = config_of_soc();
228 
229  /* look-up table to be able to iterate over the PCIe clock output settings */
230  const uint8_t gpp_clk_shift_lut[GPP_CLK_OUTPUT_COUNT] = {
238  };
239 
240  uint32_t gpp_clk_ctl = misc_read32(GPP_CLK_CNTRL);
241 
243  for (int i = 0; i < GPP_CLK_OUTPUT_COUNT; i++) {
244  gpp_clk_ctl &= ~GPP_CLK_REQ_MASK(gpp_clk_shift_lut[i]);
245 
246  /*
247  * The remapping of values is done so that the default of the enum used for the
248  * devicetree settings is the clock being enabled, so that a missing devicetree
249  * configuration for this will result in an always active clock and not an
250  * inactive PCIe clock output.
251  */
252  switch (cfg->gpp_clk_config[i]) {
253  case GPP_CLK_REQ:
254  gpp_clk_ctl |= GPP_CLK_REQ_EXT(gpp_clk_shift_lut[i]);
255  break;
256  case GPP_CLK_OFF:
257  gpp_clk_ctl |= GPP_CLK_REQ_OFF(gpp_clk_shift_lut[i]);
258  break;
259  case GPP_CLK_ON:
260  default:
261  gpp_clk_ctl |= GPP_CLK_REQ_ON(gpp_clk_shift_lut[i]);
262  }
263  }
264 
265  misc_write32(GPP_CLK_CNTRL, gpp_clk_ctl);
266 }
267 
268 static void cgpll_clock_gate_init(void)
269 {
270  uint32_t t;
271 
273  t |= ALINKCLK_GATEOFFEN;
274  t |= BLINKCLK_GATEOFFEN;
278 
284 
286  t |= ABCLKGATEEN;
288 }
289 
290 void fch_init(void *chip_info)
291 {
292  fch_init_resets();
293  i2c_soc_init();
295 
297  gpio_add_events();
298 
299  gpp_clk_setup();
302 }
303 
304 void fch_final(void *chip_info)
305 {
306 }
307 
308 static void set_pci_irqs(void *unused)
309 {
310  /* Write PCI_INTR regs 0xC00/0xC01 */
312 
313  /* pirq_data is consumed by `write_pci_cfg_irqs` */
315 
316  /* Write IRQs for all devicetree enabled devices */
318 }
319 
320 /*
321  * Hook this function into the PCI state machine
322  * on entry into BS_DEV_ENABLE.
323  */
@ PIRQ_A
Definition: acpi_pirq_gen.h:22
@ PIRQ_C
Definition: acpi_pirq_gen.h:24
@ PIRQ_G
Definition: acpi_pirq_gen.h:28
@ PIRQ_H
Definition: acpi_pirq_gen.h:29
@ PIRQ_E
Definition: acpi_pirq_gen.h:26
@ PIRQ_D
Definition: acpi_pirq_gen.h:25
@ PIRQ_F
Definition: acpi_pirq_gen.h:27
@ PIRQ_B
Definition: acpi_pirq_gen.h:23
#define SLPTYPE_CONTROL_EN
Definition: acpimmio.h:32
static void pm_write32(uint8_t reg, uint32_t value)
Definition: acpimmio.h:191
static uint8_t pm_read8(uint8_t reg)
Definition: acpimmio.h:166
static void pm_write16(uint8_t reg, uint16_t value)
Definition: acpimmio.h:186
static uint32_t misc_read32(uint8_t reg)
Definition: acpimmio.h:266
static uint32_t pm_read32(uint8_t reg)
Definition: acpimmio.h:176
static void misc_write32(uint8_t reg, uint32_t value)
Definition: acpimmio.h:281
static uint16_t pm_read16(uint8_t reg)
Definition: acpimmio.h:171
static void pm_write8(uint8_t reg, uint8_t value)
Definition: acpimmio.h:181
#define PM_RST_CTRL1
Definition: acpimmio.h:31
void mainboard_get_dxio_ddi_descriptors(const fsp_dxio_descriptor **dxio_descs, size_t *dxio_num, const fsp_ddi_descriptor **ddi_descs, size_t *ddi_num)
#define ACPI_PM1_CNT_BLK
Definition: iomap.h:43
#define ACPI_PM_TMR_BLK
Definition: iomap.h:44
#define ACPI_GPE0_BLK
Definition: iomap.h:46
#define ACPI_PM_EVT_BLK
Definition: iomap.h:40
@ BS_DEV_ENABLE
Definition: bootstate.h:82
@ BS_ON_ENTRY
Definition: bootstate.h:95
#define ARRAY_SIZE(a)
Definition: helpers.h:12
static void gpp_clk_setup(void)
Definition: fch.c:225
const struct irq_idx_name * sb_get_apic_reg_association(size_t *size)
Definition: fch.c:75
static void gpp_dxio_update_clk_req_config(enum gpp_clk_req *gpp_clk_config, size_t gpp_clk_config_num)
Definition: fch.c:138
BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_ENTRY, set_pci_irqs, NULL)
static void cgpll_clock_gate_init(void)
Definition: fch.c:268
static void fch_init_acpi_ports(void)
Definition: fch.c:91
void fch_init(void *chip_info)
Definition: fch.c:290
static const struct irq_idx_name irq_association[]
Definition: fch.c:31
static void fch_clk_output_48Mhz(void)
Definition: fch.c:81
void fch_final(void *chip_info)
Definition: fch.c:304
static void fch_init_resets(void)
Definition: fch.c:132
static void set_pci_irqs(void *unused)
Definition: fch.c:308
#define GPP_CLK_REQ_MASK(clk_shift)
Definition: southbridge.h:98
#define USB_PHY_CMCLK_S3_DIS
Definition: southbridge.h:109
#define GPP_CLK_REQ_ON(clk_shift)
Definition: southbridge.h:99
#define GPP_CLK5_REQ_SHIFT
Definition: southbridge.h:95
#define GPP_CLK2_REQ_SHIFT
Definition: southbridge.h:93
#define XTAL_PAD_S5_TURNOFF_EN
Definition: southbridge.h:107
#define PM_TMR_BLK
Definition: southbridge.h:40
#define PM_ACPI_CONF
Definition: southbridge.h:43
#define GPP_CLK_CNTRL
Definition: southbridge.h:89
#define PM_ACPI_TIMER_EN_EN
Definition: southbridge.h:48
#define FORCE_SLPSTATE_RETRY
Definition: southbridge.h:12
#define PWR_RESET_CFG
Definition: southbridge.h:13
#define PM_ACPI_GLOBAL_EN
Definition: southbridge.h:45
#define MISC_CGPLL_CONFIGURATION0
Definition: southbridge.h:108
#define GPP_CLK_OUTPUT_COUNT
Definition: southbridge.h:97
#define PM_ACPI_DECODE_STD
Definition: southbridge.h:44
#define GPP_CLK6_REQ_SHIFT
Definition: southbridge.h:96
#define BP_X48M0_OUTPUT_EN
Definition: southbridge.h:114
#define BLINKCLK_GATEOFFEN
Definition: southbridge.h:105
#define MISC_CLKGATEDCNTL
Definition: southbridge.h:103
#define GPP_CLK1_REQ_SHIFT
Definition: southbridge.h:91
#define USB_PHY_CMCLK_S0I3_DIS
Definition: southbridge.h:110
#define PM_ACPI_RTC_EN_EN
Definition: southbridge.h:46
#define MISC_CLK_CNTL0
Definition: southbridge.h:112
#define BP_X48M0_S0I3_DIS
Definition: southbridge.h:113
#define PM_EVT_BLK
Definition: southbridge.h:26
#define GPP_CLK4_REQ_SHIFT
Definition: southbridge.h:92
#define GPP_CLK0_REQ_SHIFT
Definition: southbridge.h:90
#define PM_GPE0_BLK
Definition: southbridge.h:41
#define XTAL_PAD_S3_TURNOFF_EN
Definition: southbridge.h:106
#define USB_PHY_CMCLK_S5_DIS
Definition: southbridge.h:111
#define PM_ACPI_SMI_CMD
Definition: southbridge.h:42
#define PM_ISACONTROL
Definition: southbridge.h:9
#define PM_PCI_CTRL
Definition: southbridge.h:11
#define GPP_CLK_REQ_EXT(clk_shift)
Definition: southbridge.h:100
#define ALINKCLK_GATEOFFEN
Definition: southbridge.h:104
#define GPP_CLK_REQ_OFF(clk_shift)
Definition: southbridge.h:101
#define PM1_CNT_BLK
Definition: southbridge.h:39
#define TOGGLE_ALL_PWR_GOOD
Definition: southbridge.h:14
#define ABCLKGATEEN
Definition: southbridge.h:10
#define GPP_CLK3_REQ_SHIFT
Definition: southbridge.h:94
#define printk(level,...)
Definition: stdlib.h:16
DEVTREE_CONST struct device * pcidev_path_on_root(pci_devfn_t devfn)
Definition: device_const.c:255
@ CONFIG
Definition: dsi_common.h:201
#define APM_CNT
Definition: smm.h:19
#define config_of_soc()
Definition: device.h:394
static __always_inline u32 pci_read_config32(const struct device *dev, u16 reg)
Definition: pci_ops.h:58
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
#define PCI_DEVFN(slot, func)
Definition: pci_def.h:548
#define PCI_VENDOR_ID
Definition: pci_def.h:8
gpp_clk_req
Definition: chip.h:15
@ GPP_CLK_REQ
Definition: chip.h:17
@ GPP_CLK_ON
Definition: chip.h:16
@ GPP_CLK_OFF
Definition: chip.h:18
#define PIRQ_EMMC
#define PIRQ_SATA
#define PIRQ_GPIOB
#define PIRQ_SDIO
#define PIRQ_GPP2
#define PIRQ_GPP1
#define PIRQ_PMON
#define PIRQ_I2C0
#define PIRQ_SIRQA
#define PIRQ_SMBUS
#define PIRQ_HPET_L
#define PIRQ_MISC0
#define PIRQ_ASF
#define PIRQ_GPP0
#define PIRQ_CIR
#define PIRQ_SIRQC
#define PIRQ_SCI
#define PIRQ_GPIOA
#define PIRQ_SIRQD
#define PIRQ_I2C5
#define PIRQ_MISC
#define PIRQ_SD
#define PIRQ_UART0
#define PIRQ_HPET_H
#define PIRQ_GPP3
#define PIRQ_I2C3
#define PIRQ_I2C4
#define PIRQ_I2C2
#define PIRQ_UART1
#define PIRQ_I2C1
#define PIRQ_GPIO
#define PIRQ_SIRQB
#define PIRQ_GPIOC
#define SMITYPE_SLP_TYP
Definition: smi.h:107
#define SMITYPE_SMI_CMD_PORT
Definition: smi.h:113
void acpi_pm_gpe_add_events_print_events(void)
Definition: acpi.c:77
void gpio_add_events(void)
Definition: gpio.c:382
void i2c_soc_init(void)
Definition: i2c.c:113
void write_pci_cfg_irqs(void)
Definition: amd_pci_util.c:84
void write_pci_int_table(void)
Definition: amd_pci_util.c:41
void populate_pirq_data(void)
void configure_smi(uint8_t smi_num, uint8_t mode)
Definition: smi_util.c:12
@ SMI_MODE_SMI
Definition: smi.h:10
#define NULL
Definition: stddef.h:19
unsigned int uint32_t
Definition: stdint.h:14
uint32_t u32
Definition: stdint.h:51
unsigned char uint8_t
Definition: stdint.h:8
Definition: device.h:107
unsigned int enabled
Definition: device.h:122
enum gpp_clk_req gpp_clk_config[GPP_CLK_OUTPUT_COUNT]
Definition: chip.h:100