SMBIOS: Introduce `smbios_carve_table` function
[coreboot.git] / src / mainboard / pcengines / apu1 / mainboard.c
blob87bab716517a57d880c96ff785335b63271fb2a7
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <amdblocks/acpimmio.h>
5 #include <console/console.h>
6 #include <device/device.h>
7 #include <device/mmio.h>
8 #include <device/pci_ops.h>
9 #include <device/pci_def.h>
10 #include <southbridge/amd/common/amd_pci_util.h>
11 #include <smbios.h>
12 #include <string.h>
13 #include <southbridge/amd/cimx/sb800/pci_devs.h>
14 #include <northbridge/amd/agesa/agesa_helper.h>
15 #include <northbridge/amd/agesa/family14/pci_devs.h>
16 #include <superio/nuvoton/nct5104d/nct5104d.h>
17 #include "gpio_ftns.h"
18 #include <AGESA.h>
19 #include <AMD.h>
20 #include <southbridge/amd/cimx/sb800/SBPLATFORM.h>
22 /***********************************************************
23 * These arrays set up the FCH PCI_INTR registers 0xC00/0xC01.
24 * This table is responsible for physically routing the PIC and
25 * IOAPIC IRQs to the different PCI devices on the system. It
26 * is read and written via registers 0xC00/0xC01 as an
27 * Index/Data pair. These values are chipset and mainboard
28 * dependent and should be updated accordingly.
30 * These values are used by the PCI configuration space,
31 * MP Tables. TODO: Make ACPI use these values too.
33 * The PCI INTA/B/C/D pins are connected to
34 * FCH pins INTE/F/G/H on the schematic so these need
35 * to be routed as well.
37 static const u8 mainboard_picr_data[FCH_INT_TABLE_SIZE] = {
38 /* INTA# - INTH# */
39 [0x00] = 0x0A,0x0B,0x0A,0x0B,0x0A,0x0B,0x0A,0x0B,
40 /* Misc-nil,0,1,2, INT from Serial irq */
41 [0x08] = 0x00,0xF1,0x00,0x00,0x1F,0x1F,0x1F,0x1F,
42 /* SCI, SMBUS0, ASF, HDA, FC, GEC, PerfMon */
43 [0x10] = 0x1F,0x1F,0x1F,0x0A,0x1F,0x1F,0x1F,
44 /* IMC INT0 - 5 */
45 [0x20] = 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
46 /* USB Devs 18/19/20/22 INTA-C */
47 [0x30] = 0x0A,0x0B,0x0A,0x0B,0x0A,0x0B,0x0A,
48 /* IDE, SATA */
49 [0x40] = 0x0B,0x0B,
50 /* GPPInt0 - 3 */
51 [0x50] = 0x0A,0x0B,0x0A,0x0B
54 static const u8 mainboard_intr_data[FCH_INT_TABLE_SIZE] = {
55 /* INTA# - INTH# */
56 [0x00] = 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
57 /* Misc-nil,0,1,2, INT from Serial irq */
58 [0x08] = 0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F,
59 /* SCI, SMBUS0, ASF, HDA, FC, GEC, PerMon */
60 [0x10] = 0x09,0x1F,0x1F,0x10,0x1F,0x12,0x1F,
61 /* IMC INT0 - 5 */
62 [0x20] = 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
63 /* USB Devs 18/19/22/20 INTA-C */
64 [0x30] = 0x12,0x11,0x12,0x11,0x12,0x11,0x12,
65 /* IDE, SATA */
66 [0x40] = 0x11,0x13,
67 /* GPPInt0 - 3 */
68 [0x50] = 0x10,0x11,0x12,0x13
72 * This table defines the index into the picr/intr_data
73 * tables for each device. Any enabled device and slot
74 * that uses hardware interrupts should have an entry
75 * in this table to define its index into the FCH
76 * PCI_INTR register 0xC00/0xC01. This index will define
77 * the interrupt that it should use. Putting PIRQ_A into
78 * the PIN A index for a device will tell that device to
79 * use PIC IRQ 10 if it uses PIN A for its hardware INT.
82 * The PCI slot INTA/B/C/D connected to PIRQE/F/G/H
83 * but because of PCI INT_PIN swizzle isn't implemented to match
84 * the IDSEL (dev 3) of the slot, the table is adjusted for the
85 * swizzle and INTA is connected to PIRQH so PINA/B/C/D on
86 * off-chip devices should get mapped to PIRQH/E/F/G.
88 static const struct pirq_struct mainboard_pirq_data[] = {
89 /* {PCI_devfn, {PIN A, PIN B, PIN C, PIN D}}, */
90 {GFX_DEVFN, {PIRQ_A, PIRQ_B, PIRQ_NC, PIRQ_NC}}, /* VGA: 01.0 */
91 {NB_PCIE_PORT1_DEVFN, {PIRQ_A, PIRQ_B, PIRQ_C, PIRQ_D}}, /* NIC: 04.0 */
92 {NB_PCIE_PORT2_DEVFN, {PIRQ_A, PIRQ_B, PIRQ_C, PIRQ_D}}, /* NIC: 05.0 */
93 {NB_PCIE_PORT3_DEVFN, {PIRQ_A, PIRQ_B, PIRQ_C, PIRQ_D}}, /* NIC: 06.0 */
94 {NB_PCIE_PORT4_DEVFN, {PIRQ_A, PIRQ_B, PIRQ_C, PIRQ_D}}, /* miniPCIe: 07.0 */
95 {SATA_DEVFN, {PIRQ_SATA, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* SATA: 11.0 */
96 {OHCI1_DEVFN, {PIRQ_OHCI1, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* OHCI1: 12.0 */
97 {EHCI1_DEVFN, {PIRQ_NC, PIRQ_EHCI1, PIRQ_NC, PIRQ_NC}}, /* EHCI1: 12.2 */
98 {OHCI2_DEVFN, {PIRQ_OHCI2, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* OHCI2: 13.0 */
99 {EHCI2_DEVFN, {PIRQ_NC, PIRQ_EHCI2, PIRQ_NC, PIRQ_NC}}, /* EHCI2: 13.2 */
100 {SMBUS_DEVFN, {PIRQ_SMBUS, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* SMBUS: 14.0 */
101 {IDE_DEVFN, {PIRQ_NC, PIRQ_IDE, PIRQ_NC, PIRQ_NC}}, /* IDE: 14.1 */
102 {HDA_DEVFN, {PIRQ_HDA, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* HDA: 14.2 */
103 {SB_PCI_PORT_DEVFN, {PIRQ_H, PIRQ_E, PIRQ_F, PIRQ_G}}, /* PCI bdg: 14.4 */
104 {OHCI4_DEVFN, {PIRQ_NC, PIRQ_NC, PIRQ_OHCI4, PIRQ_NC}}, /* OHCI4: 14.5 */
105 {SB_PCIE_PORT1_DEVFN, {PIRQ_A, PIRQ_B, PIRQ_C, PIRQ_D}}, /* miniPCIe: 15.0 */
106 {OHCI3_DEVFN, {PIRQ_OHCI3, PIRQ_NC, PIRQ_NC, PIRQ_NC}}, /* OHCI3: 16.0 */
107 {EHCI3_DEVFN, {PIRQ_NC, PIRQ_EHCI3, PIRQ_NC, PIRQ_NC}}, /* EHCI3: 16.2 */
110 /* PIRQ Setup */
111 static void pirq_setup(void)
113 pirq_data_ptr = mainboard_pirq_data;
114 pirq_data_size = ARRAY_SIZE(mainboard_pirq_data);
115 intr_data_ptr = mainboard_intr_data;
116 picr_data_ptr = mainboard_picr_data;
119 /* Wrapper to enable GPIO/UART devices under menuconfig. Revisit
120 * once configuration file format for SPI flash storage is complete.
122 #define SIO_PORT 0x2e
124 static void config_gpio_mux(void)
126 struct device *uart, *gpio;
128 uart = dev_find_slot_pnp(SIO_PORT, NCT5104D_SP3);
129 gpio = dev_find_slot_pnp(SIO_PORT, NCT5104D_GPIO0);
130 if (uart)
131 uart->enabled = CONFIG(APU1_PINMUX_UART_C);
132 if (gpio)
133 gpio->enabled = CONFIG(APU1_PINMUX_GPIO0);
135 uart = dev_find_slot_pnp(SIO_PORT, NCT5104D_SP4);
136 gpio = dev_find_slot_pnp(SIO_PORT, NCT5104D_GPIO1);
137 if (uart)
138 uart->enabled = CONFIG(APU1_PINMUX_UART_D);
139 if (gpio)
140 gpio->enabled = CONFIG(APU1_PINMUX_GPIO1);
143 static void pnp_raw_resource(struct device *dev, u8 reg, u8 val)
145 struct resource *res;
146 res = new_resource(dev, reg);
147 res->base = val;
148 res->size = 0;
149 res->flags |= IORESOURCE_IRQ | IORESOURCE_ASSIGNED;
152 static void config_addon_uart(void)
154 struct device *uart;
156 uart = dev_find_slot_pnp(SIO_PORT, NCT5104D_SP3);
157 if (uart && uart->enabled && CONFIG(UART_C_RS485))
158 pnp_raw_resource(uart, 0xf2, 0x12);
160 uart = dev_find_slot_pnp(SIO_PORT, NCT5104D_SP4);
161 if (uart && uart->enabled && CONFIG(UART_D_RS485))
162 pnp_raw_resource(uart, 0xf2, 0x12);
165 /**********************************************
166 * Enable the dedicated functions of the board.
167 **********************************************/
168 #if CONFIG(GENERATE_SMBIOS_TABLES)
169 static int mainboard_smbios_type16(DMI_INFO *agesa_dmi, int *handle, unsigned long *current)
171 const u32 max_capacity = get_spd_offset() ? 4 : 2; /* 4GB or 2GB variant */
173 struct smbios_type16 *t = smbios_carve_table(*current, SMBIOS_PHYS_MEMORY_ARRAY,
174 sizeof(*t), *handle);
176 t->use = MEMORY_ARRAY_USE_SYSTEM;
177 t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
178 t->memory_error_correction = agesa_dmi->T16.MemoryErrorCorrection;
179 t->maximum_capacity = max_capacity * 1024 * 1024;
180 t->memory_error_information_handle = 0xfffe;
181 t->number_of_memory_devices = 1;
183 const int len = sizeof(*t);
184 *current += len;
185 return len;
188 static int mainboard_smbios_type17(DMI_INFO *agesa_dmi, int *handle, unsigned long *current)
190 struct smbios_type17 *t = smbios_carve_table(*current, SMBIOS_MEMORY_DEVICE,
191 sizeof(*t), *handle + 1);
193 t->phys_memory_array_handle = *handle;
194 t->memory_error_information_handle = 0xfffe;
195 t->total_width = agesa_dmi->T17[0][0][0].TotalWidth;
196 t->data_width = agesa_dmi->T17[0][0][0].DataWidth;
197 t->size = agesa_dmi->T17[0][0][0].MemorySize;
198 /* AGESA DMI returns form factor = 0, override it with SPD value */
199 t->form_factor = MEMORY_FORMFACTOR_SODIMM;
200 t->device_set = agesa_dmi->T17[0][0][0].DeviceSet;
201 t->device_locator = smbios_add_string(t->eos, agesa_dmi->T17[0][0][0].DeviceLocator);
202 t->bank_locator = smbios_add_string(t->eos, agesa_dmi->T17[0][0][0].BankLocator);
203 t->memory_type = agesa_dmi->T17[0][0][0].MemoryType;
204 t->type_detail = *(u16 *)&agesa_dmi->T17[0][0][0].TypeDetail;
205 t->speed = agesa_dmi->T17[0][0][0].Speed;
206 t->manufacturer = agesa_dmi->T17[0][0][0].ManufacturerIdCode;
207 t->serial_number = smbios_add_string(t->eos, agesa_dmi->T17[0][0][0].SerialNumber);
208 t->part_number = smbios_add_string(t->eos, agesa_dmi->T17[0][0][0].PartNumber);
209 t->attributes = agesa_dmi->T17[0][0][0].Attributes;
210 t->extended_size = agesa_dmi->T17[0][0][0].ExtSize;
211 t->clock_speed = agesa_dmi->T17[0][0][0].ConfigSpeed;
212 t->minimum_voltage = 1500; /* From SPD: 1.5V */
213 t->maximum_voltage = 1500;
215 const int len = t->length + smbios_string_table_len(t->eos);
216 *current += len;
217 return len;
220 static int mainboard_smbios_data(struct device *dev, int *handle,
221 unsigned long *current)
223 DMI_INFO *agesa_dmi;
224 int len;
226 agesa_dmi = agesawrapper_getlateinitptr(PICK_DMI);
228 if (!agesa_dmi)
229 return 0;
231 len = mainboard_smbios_type16(agesa_dmi, handle, current);
232 len += mainboard_smbios_type17(agesa_dmi, handle, current);
234 *handle += 2;
236 return len;
238 #endif
240 static void mainboard_enable(struct device *dev)
242 /* Maintain this text unchanged for manufacture process. */
243 printk(BIOS_INFO, "Mainboard " CONFIG_MAINBOARD_PART_NUMBER " Enable.\n");
245 config_gpio_mux();
246 config_addon_uart();
248 /* Power off unused clock pins of GPP PCIe devices
249 * GPP CLK0-2 are connected to the 3 ethernet chips
250 * GPP CLK3-4 are connected to the miniPCIe slots
252 misc_write8(0, 0x21);
253 misc_write8(1, 0x43);
254 /* GPP CLK5 is only connected to test pads -> disable */
255 misc_write8(2, 0x05);
256 /* disable unconnected GPP CLK6-8 and SLT_GFX_CLK */
257 misc_write8(3, 0);
258 misc_write8(4, 0);
260 /* Initialize the PIRQ data structures for consumption */
261 pirq_setup();
262 #if CONFIG(GENERATE_SMBIOS_TABLES)
263 dev->ops->get_smbios_data = mainboard_smbios_data;
264 #endif
268 * We will stuff a modified version of the first NICs (BDF 1:0.0) MAC address
269 * into the smbios serial number location.
271 const char *smbios_mainboard_serial_number(void)
273 static char serial[10];
274 struct device *dev;
275 uintptr_t bar18;
276 u32 mac_addr = 0;
277 int i;
279 /* Already initialized. */
280 if (serial[0] != 0)
281 return serial;
283 dev = pcidev_on_root(4, 0);
284 if (dev)
285 dev = pcidev_path_behind(dev->link_list, PCI_DEVFN(0, 0));
286 if (!dev)
287 return serial;
289 /* Read in the last 3 bytes of NIC's MAC address. */
290 bar18 = pci_read_config32(dev, PCI_BASE_ADDRESS_2);
291 bar18 &= 0xFFFFFFF0;
292 for (i = 3; i < 6; i++) {
293 mac_addr <<= 8;
294 mac_addr |= read8((u8 *)bar18 + i);
296 mac_addr &= 0x00FFFFFF;
297 mac_addr /= 4;
298 mac_addr -= 64;
300 snprintf(serial, sizeof(serial), "%d", mac_addr);
301 return serial;
305 * Set up "Over Current Control 1" (reg 0x58) on the first OHCI device.
306 * The remaining ports on the second device are for mcpie2/sdcard and
307 * can stay at the power-on default value.
309 * The schematic shows this transposed mapping for the first device:
310 * chipset port 0 -> port 1 (j12 external 2, usboc0#)
311 * chipset port 1 -> port 4 (j17 mpcie1)
312 * chipset port 2 -> port 2 (j14 header row1, usboc1#)
313 * chipset port 3 -> port 3 (j14 header row2, usboc1#)
314 * chipset port 4 -> port 0 (j12 external 1. usboc0#)
316 * Register mapping:
317 * bit0-3: Mapping for HS Port 0
318 * bit4-7: Mapping for HS Port 1
319 * bit8-11: Mapping for HS Port 2
320 * bit12-15: Mapping for HS Port 3
321 * bit16-19: Mapping for HS Port 4
322 * bit20-31: Reserved (0)
324 * power-on default: 0xfffff
325 * A value >7 will disable the overcurrent detection.
327 static void usb_oc_setup(void)
329 struct device *dev = pcidev_on_root(0x12, 0);
331 pci_write_config32(dev, 0x58, 0x011f0);
335 * We will stuff the memory size into the smbios sku location.
337 const char *smbios_system_sku(void)
339 static char sku[5];
340 if (sku[0] != 0)
341 return sku;
343 if (!get_spd_offset())
344 snprintf(sku, sizeof(sku), "2 GB");
345 else
346 snprintf(sku, sizeof(sku), "4 GB");
347 return sku;
350 static void mainboard_final(void *chip_info)
352 /* Maintain this text unchanged for manufacture process. */
353 printk(BIOS_INFO, "Mainboard " CONFIG_MAINBOARD_PART_NUMBER " Final.\n");
356 * LED1/D7/GPIO_189 should be 0
357 * LED2/D6/GPIO_190 should be 1
358 * LED3/D5/GPIO_191 should be 1
360 configure_gpio(GPIO_189, GPIO_FTN_1, GPIO_OUTPUT | GPIO_DATA_LOW);
361 configure_gpio(GPIO_190, GPIO_FTN_1, GPIO_OUTPUT | GPIO_DATA_HIGH);
362 configure_gpio(GPIO_191, GPIO_FTN_1, GPIO_OUTPUT | GPIO_DATA_HIGH);
363 usb_oc_setup();
366 struct chip_operations mainboard_ops = {
367 .enable_dev = mainboard_enable,
368 .final = mainboard_final,