SoC development is best done in parallel with development for a specific board. The combined steps are listed here. The development steps for the SoC are listed below:
Create the directory as src/soc/<Vendor>/<Chip Family>.
The following files are required to build a new SoC:
Some SoC parts require additional firmware components in the flash. This section describes how to add those pieces.
The Intel Firmware Descriptor (IFD) is located at the base of the flash part. The following command overwrites the base of the flash image with the Intel Firmware Descriptor:
dd if=descriptor.bin of=build/coreboot.rom conv=notrunc >/dev/null 2>&1
Some SoC parts contain and require that the Management Engine (ME) be running before it is possible to bring the x86 processor out of reset. A binary file containing the management engine code must be added to the firmware using the ifdtool. The following commands add this binary blob:
util/ifdtool/ifdtool -i ME:me.bin build/coreboot.rom
mv build/coreboot.rom.new build/coreboot.rom
Early debugging between the reset vector and the time the serial port is enabled is most easily done by writing values to port 0x80.
When the reset vector is successfully invoked, port 0x80 will output the following value:
Implement the bootblock using the following steps:
Build Note: The following files are included into the default bootblock image:
Enable the call to TempRamInit in two stages:
Use the following steps to locate the FSP binary:
Use the following steps to debug the call to TempRamInit:
util/cbfstool/cbfstool build/coreboot.rom add -t microcode -n cpu_microcode_blob.bin -b <base address> -f cpu_microcode_blob.bin
The following steps add the serial output support for romstage:
The following steps implement the code to get the previous sleep state:
The following steps implement the code to support the FSP MemoryInit call:
Build Note: The src/mainboard/<Vendor>/<Board>/devicetree.cb file specifies the default values for these parameters. The build process creates the static.c module which contains the config data structure containing these values.
The src/mainboard/<Vendor>/<Board>/devicetree.cb file drives the execution during ramstage. This file is processed by the util/sconfig utility to generate build/mainboard/<Vendor>/<Board>/static.c. The various state routines in src/lib/hardwaremain.c call dev_* routines which use the tables in static.c to locate operation tables associated with the various chips and devices. After location the operation tables, the state routines call one or more functions depending upon the state of the state machine.
Kick-starting the ramstage state machine requires creating the operation table for the chip listed in devicetree.cb:
coreboot uses the domain operation table to initiate operations on all of the devices in the domain. By default coreboot enables all PCI devices which it finds. Listing a device in devicetree.cb gives the board vendor control over the device state. Non-PCI devices may also be listed under PCI device such as the LPC bus or SMbus devices.
static struct device_operations pci_domain_ops = {
.read_resources = pci_domain_read_resources,
.set_resources = pci_domain_set_resources,
.scan_bus = pci_domain_scan_bus,
.ops_pci_bus = pci_bus_default_ops,
};
if (dev->path.type == DEVICE_PATH_DOMAIN) {
dev->ops = &pci_domain_ops;
}
PCI device drivers consist of a ".c" file which contains a "pci_driver" data structure at the end of the file with the attribute tag "__pci_driver". This attribute tag places an entry into a link time table listing the various coreboot device drivers.
Specify the following fields in the table:
PCI subsystem IDs are assigned during the BS_DEV_ENABLE state. The device driver may use the common mechanism to assign subsystem IDs by adding the ".ops_pci" to the pci_driver data structure. This field points to a "struct pci_operations" that specifies a routine to set the subsystem IDs for the device. The routine might look something like this:
static void pci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
if (!vendor || !device) {
vendor = pci_read_config32(dev, PCI_VENDOR_ID);
device = vendor >> 16;
}
printk(BIOS_SPEW,
"PCI: %02x:%02x:%d subsystem vendor: 0x%04x, device: 0x%04x\n",
0, PCI_SLOT(dev->path.pci.devfn), PCI_FUNC(dev->path.pci.devfn),
vendor & 0xffff, device);
pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
((device & 0xffff) << 16) | (vendor & 0xffff));
}
The memory map is built by the various PCI device drivers during the BS_DEV_RESOURCES state of ramstage. The northcluster driver will typically specify the DRAM resources while the other drivers will typically specify the IO resources. These resources are hung off the device_t data structure by src/device/device_util.c/new_resource.
During the BS_WRITE_TABLES state, coreboot collects these resources and places them into a data structure identified by LB_MEM_TABLE.
Edit the device driver file:
Testing: Verify that the resources are properly displayed by coreboot during the BS_WRITE_TABLES state.
One of the payloads that needs ACPI tables is the EDK2 CorebootPayloadPkg.
The EDK2 module CorebootModulePkg/Library/CbParseLib/CbParseLib.c requires that the FADT contains the values in the table below. These values are placed into a HOB identified by gUefiAcpiBoardInfoGuid by routine CorebootModulePkg/CbSupportPei/CbSupportPei/CbPeiEntryPoint.
Coreboot Field | EDK2 Field | gUefiAcpiBoardInfoGuid | Use | ACPI Spec. Section |
gpe0_blk gpe0_blk_len |
Gpe0Blk Gpe0BlkLen |
PmGpeEnBase | Shutdown | 4.8.4.1 |
pm1a_cnt_blk | Pm1aCntBlk | PmCtrlRegBase |
Shutdown Suspend |
4.8.3.2.1 |
pm1a_evt_blk | Pm1aEvtBlk | PmEvtBase | Shutdown | 4.8.3.1.1 |
pm_tmr_blk | PmTmrBlk | PmTimerRegBase | Timer | 4.8.3.3 |
reset_reg. | ResetReg.Address | ResetRegAddress | Cold and Warm resets | 4.3.3.6 |
reset_value | ResetValue | ResetValue | Cold and Warm resets | 4.8.3.6 |
The EDK2 data structure is defined in MdeModulePkg/Include/IndustryStandard/Acpi61.h The coreboot data structure is defined in src/arch/x86/include/arch/acpi.h
Modified: 28 February 2016