Xeon-SP boards: Factor out OCP VPD `get_cxl_mode()` impl
[coreboot2.git] / src / device / pci_rom.c
blobd60720eb49a568362a534c40f6f3b56e5b10751b
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <commonlib/endian.h>
5 #include <device/device.h>
6 #include <device/pci.h>
7 #include <device/pci_ids.h>
8 #include <device/pci_ops.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <cbfs.h>
12 #include <cbmem.h>
13 #include <acpi/acpigen.h>
15 /* Rmodules don't like weak symbols. */
16 u32 __weak map_oprom_vendev(u32 vendev) { return vendev; }
18 void vga_oprom_preload(void)
20 /* The CONFIG_VGA_BIOS_ID symbol is only defined when VGA_BIOS is selected */
21 #if CONFIG(VGA_BIOS)
22 const char name[] = "pci" CONFIG_VGA_BIOS_ID ".rom";
24 if (!CONFIG(CBFS_PRELOAD))
25 return;
27 printk(BIOS_DEBUG, "Preloading VGA ROM %s\n", name);
29 cbfs_preload(name);
30 #endif
33 static void *cbfs_boot_map_optionrom(uint16_t vendor, uint16_t device)
35 char name[17] = "pciXXXX,XXXX.rom";
37 snprintf(name, sizeof(name), "pci%04hx,%04hx.rom", vendor, device);
39 return cbfs_map(name, NULL);
42 struct rom_header *pci_rom_probe(const struct device *dev)
44 struct rom_header *rom_header = NULL;
45 struct pci_data *rom_data;
46 u32 vendev = (dev->vendor << 16) | dev->device;
47 u32 mapped_vendev = vendev;
49 /* If the ROM is in flash, then don't check the PCI device for it. */
50 mapped_vendev = map_oprom_vendev(vendev);
51 rom_header = cbfs_boot_map_optionrom(mapped_vendev >> 16, mapped_vendev & 0xffff);
53 /* Handle the case of VGA_BIOS_ID not being set to the remapped PCI ID. This is a
54 workaround that should be removed once the underlying issue is fixed. */
55 if (!rom_header && vendev != mapped_vendev) {
56 rom_header = cbfs_boot_map_optionrom(vendev >> 16, vendev & 0xffff);
57 if (rom_header) {
58 printk(BIOS_NOTICE, "VGA_BIOS_ID should be the remapped PCI ID "
59 "%04hx,%04hx in the VBIOS file\n",
60 mapped_vendev >> 16, mapped_vendev & 0xffff);
64 if (rom_header) {
65 printk(BIOS_DEBUG, "In CBFS, ROM address for %s = %p\n",
66 dev_path(dev), rom_header);
67 } else if (CONFIG(ON_DEVICE_ROM_LOAD)) {
68 uintptr_t rom_address;
70 rom_address = pci_read_config32(dev, PCI_ROM_ADDRESS);
72 if (rom_address == 0x00000000 || rom_address == 0xffffffff) {
73 if (CONFIG(CPU_QEMU_X86) && (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
74 rom_address = 0xc0000;
75 else
76 return NULL;
77 } else {
78 /* Enable expansion ROM address decoding. */
79 pci_write_config32(dev, PCI_ROM_ADDRESS,
80 rom_address|PCI_ROM_ADDRESS_ENABLE);
83 rom_address &= PCI_ROM_ADDRESS_MASK;
85 printk(BIOS_DEBUG, "Option ROM address for %s = %lx\n",
86 dev_path(dev), (unsigned long)rom_address);
87 rom_header = (struct rom_header *)rom_address;
88 } else {
89 printk(BIOS_DEBUG, "PCI Option ROM loading disabled for %s\n",
90 dev_path(dev));
91 return NULL;
94 printk(BIOS_SPEW,
95 "PCI expansion ROM, signature 0x%04x, INIT size 0x%04x, data ptr 0x%04x\n",
96 le32_to_cpu(rom_header->signature),
97 rom_header->size * 512, le32_to_cpu(rom_header->data));
99 if (le32_to_cpu(rom_header->signature) != PCI_ROM_HDR) {
100 printk(BIOS_ERR, "Incorrect expansion ROM header signature %04x\n",
101 le32_to_cpu(rom_header->signature));
102 return NULL;
105 rom_data = (((void *)rom_header) + le32_to_cpu(rom_header->data));
107 printk(BIOS_SPEW, "PCI ROM image, vendor ID %04x, device ID %04x,\n",
108 rom_data->vendor, rom_data->device);
109 /* If the device id is mapped, a mismatch is expected */
110 if ((dev->vendor != rom_data->vendor
111 || dev->device != rom_data->device)
112 && (vendev == mapped_vendev)) {
113 printk(BIOS_ERR, "ID mismatch: vendor ID %04x, device ID %04x\n",
114 dev->vendor, dev->device);
115 return NULL;
118 printk(BIOS_SPEW, "PCI ROM image, Class Code %04x%02x, Code Type %02x\n",
119 rom_data->class_hi, rom_data->class_lo,
120 rom_data->type);
122 if (dev->class != ((rom_data->class_hi << 8) | rom_data->class_lo)) {
123 printk(BIOS_DEBUG, "Class Code mismatch ROM %08x, dev %08x\n",
124 (rom_data->class_hi << 8) | rom_data->class_lo,
125 dev->class);
126 // return NULL;
129 return rom_header;
132 static void *pci_ram_image_start = (void *)PCI_RAM_IMAGE_START;
134 struct rom_header *pci_rom_load(struct device *dev,
135 struct rom_header *rom_header)
137 struct pci_data * rom_data;
138 unsigned int rom_size;
139 unsigned int image_size=0;
141 do {
142 /* Get next image. */
143 rom_header = (struct rom_header *)((void *)rom_header
144 + image_size);
146 rom_data = (struct pci_data *)((void *)rom_header
147 + le32_to_cpu(rom_header->data));
149 image_size = le32_to_cpu(rom_data->ilen) * 512;
150 } while ((rom_data->type != 0) && (rom_data->indicator != 0)); // make sure we got x86 version
152 if (rom_data->type != 0)
153 return NULL;
155 rom_size = rom_header->size * 512;
158 * We check to see if the device thinks it is a VGA device not
159 * whether the ROM image is for a VGA device because some
160 * devices have a mismatch between the hardware and the ROM.
162 if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
163 extern struct device *vga_pri; /* Primary VGA device (device.c). */
164 if (dev != vga_pri) return NULL; /* Only one VGA supported. */
165 if ((void *)PCI_VGA_RAM_IMAGE_START != rom_header) {
166 printk(BIOS_DEBUG,
167 "Copying VGA ROM Image from %p to 0x%x, 0x%x bytes\n",
168 rom_header, PCI_VGA_RAM_IMAGE_START, rom_size);
169 memcpy((void *)PCI_VGA_RAM_IMAGE_START, rom_header,
170 rom_size);
172 return (struct rom_header *)(PCI_VGA_RAM_IMAGE_START);
175 printk(BIOS_DEBUG, "Copying non-VGA ROM image from %p to %p, 0x%x bytes\n",
176 rom_header, pci_ram_image_start, rom_size);
178 memcpy(pci_ram_image_start, rom_header, rom_size);
179 pci_ram_image_start += rom_size;
180 return (struct rom_header *)(pci_ram_image_start-rom_size);
183 /* ACPI */
184 #if CONFIG(HAVE_ACPI_TABLES)
186 /* VBIOS may be modified after oprom init so use the copy if present. */
187 static struct rom_header *check_initialized(const struct device *dev)
189 struct rom_header *run_rom;
190 struct pci_data *rom_data;
192 if (!CONFIG(VGA_ROM_RUN) && !CONFIG(RUN_FSP_GOP))
193 return NULL;
195 run_rom = (struct rom_header *)(uintptr_t)PCI_VGA_RAM_IMAGE_START;
196 if (read_le16(&run_rom->signature) != PCI_ROM_HDR)
197 return NULL;
199 rom_data = (struct pci_data *)((u8 *)run_rom
200 + read_le16(&run_rom->data));
202 if (read_le32(&rom_data->signature) == PCI_DATA_HDR
203 && read_le16(&rom_data->device) == dev->device
204 && read_le16(&rom_data->vendor) == dev->vendor)
205 return run_rom;
206 else
207 return NULL;
210 static unsigned long
211 ati_rom_acpi_fill_vfct(const struct device *device, acpi_vfct_t *vfct_struct,
212 unsigned long current)
214 acpi_vfct_image_hdr_t *header = &vfct_struct->image_hdr;
215 struct rom_header *rom;
217 rom = check_initialized(device);
218 if (!rom)
219 rom = pci_rom_probe(device);
220 if (!rom) {
221 printk(BIOS_ERR, "%s failed\n", __func__);
222 return current;
224 if (device->upstream->segment_group) {
225 printk(BIOS_ERR, "VFCT only supports GPU in first PCI segment group.\n");
226 return current;
229 printk(BIOS_DEBUG, " Copying %sVBIOS image from %p\n",
230 rom == (struct rom_header *)
231 (uintptr_t)PCI_VGA_RAM_IMAGE_START ?
232 "initialized " : "",
233 rom);
235 header->DeviceID = device->device;
236 header->VendorID = device->vendor;
237 header->PCIBus = device->upstream->secondary;
238 header->PCIFunction = PCI_FUNC(device->path.pci.devfn);
239 header->PCIDevice = PCI_SLOT(device->path.pci.devfn);
240 header->ImageLength = rom->size * 512;
241 memcpy((void *)header->VbiosContent, rom, header->ImageLength);
243 vfct_struct->VBIOSImageOffset = (size_t)header - (size_t)vfct_struct;
245 /* Calculate and set checksum for VBIOS data if FSP GOP driver used,
246 Since GOP driver modifies ATOMBIOS tables at end of VBIOS */
247 if (CONFIG(RUN_FSP_GOP)) {
248 /* Clear existing checksum before recalculating */
249 header->VbiosContent[VFCT_VBIOS_CHECKSUM_OFFSET] = 0;
250 header->VbiosContent[VFCT_VBIOS_CHECKSUM_OFFSET] =
251 acpi_checksum(header->VbiosContent, header->ImageLength);
254 current += header->ImageLength;
255 return current;
258 unsigned long
259 pci_rom_write_acpi_tables(const struct device *device, unsigned long current,
260 struct acpi_rsdp *rsdp)
262 /* Only handle VGA devices */
263 if ((device->class >> 8) != PCI_CLASS_DISPLAY_VGA)
264 return current;
266 /* Only handle enabled devices */
267 if (!device->enabled)
268 return current;
270 /* AMD/ATI uses VFCT */
271 if (device->vendor == PCI_VID_ATI) {
272 acpi_vfct_t *vfct;
274 current = ALIGN_UP(current, 8);
275 vfct = (acpi_vfct_t *)current;
276 acpi_create_vfct(device, vfct, ati_rom_acpi_fill_vfct);
277 if (vfct->header.length) {
278 printk(BIOS_DEBUG, "ACPI: * VFCT at %lx\n", current);
279 current += vfct->header.length;
280 acpi_add_table(rsdp, vfct);
284 return current;
287 void pci_rom_ssdt(const struct device *device)
289 static size_t ngfx;
291 /* Only handle display devices */
292 if ((device->class >> 16) != PCI_BASE_CLASS_DISPLAY)
293 return;
295 /* Only handle enabled devices */
296 if (!device->enabled)
297 return;
299 /* Probe for option rom */
300 const struct rom_header *rom = pci_rom_probe(device);
301 if (!rom || !rom->size) {
302 printk(BIOS_WARNING, "%s: Missing PCI Option ROM\n",
303 dev_path(device));
304 return;
307 const char *scope = acpi_device_path(device);
308 if (!scope) {
309 printk(BIOS_ERR, "%s: Missing ACPI scope\n", dev_path(device));
310 return;
313 /* Supports up to four devices. */
314 if ((CBMEM_ID_ROM0 + ngfx) > CBMEM_ID_ROM3) {
315 printk(BIOS_ERR, "%s: Out of CBMEM IDs.\n", dev_path(device));
316 return;
319 /* Prepare memory */
320 const size_t cbrom_length = rom->size * 512;
321 if (!cbrom_length) {
322 printk(BIOS_ERR, "%s: ROM has zero length!\n",
323 dev_path(device));
324 return;
327 void *cbrom = cbmem_add(CBMEM_ID_ROM0 + ngfx, cbrom_length);
328 if (!cbrom) {
329 printk(BIOS_ERR, "%s: Failed to allocate CBMEM.\n",
330 dev_path(device));
331 return;
333 /* Increment CBMEM id for next device */
334 ngfx++;
336 memcpy(cbrom, rom, cbrom_length);
338 /* write _ROM method */
339 acpigen_write_scope(scope);
340 acpigen_write_rom(cbrom, cbrom_length);
341 acpigen_pop_len(); /* pop scope */
343 #endif