Martin L Roth has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/87187?usp=email )
Change subject: Documentation: Add Timers, Stopwatch, and Delays ......................................................................
Documentation: Add Timers, Stopwatch, and Delays
Change-Id: I3b58817c1ed06e6d7d5d5668b0e38ec8cfedf122 Signed-off-by: Martin Roth gaumless@gmail.com --- M Documentation/internals/index.md A Documentation/internals/stopwatch.md 2 files changed, 661 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/87/87187/1
diff --git a/Documentation/internals/index.md b/Documentation/internals/index.md index 2600069..098011c 100644 --- a/Documentation/internals/index.md +++ b/Documentation/internals/index.md @@ -19,5 +19,6 @@ :maxdepth: 1
Timestamps <timestamps.md> +Timers, Stopwatch, and delays <stopwatch.md>
``` diff --git a/Documentation/internals/stopwatch.md b/Documentation/internals/stopwatch.md new file mode 100644 index 0000000..0ca5ae5 --- /dev/null +++ b/Documentation/internals/stopwatch.md @@ -0,0 +1,660 @@ +# Devicetree + +## Introduction to the coreboot devicetree + +The first thing that may come to mind when one hears “DeviceTree" is a +different sort of description file that is generally passed to the Linux +kernel to describe a system’s components. Both that devicetree and +coreboot’s devicetree serve fundamentally the same purpose, but are +otherwise unrelated and have completely different syntax. The term +devicetree was used long before either version was created, and was +initially used in coreboot as a generic term. + +coreboot's devicetree’s main use is to define and describe the runtime +configuration and settings of the hardware on a board, chip or device +level. It defines which of the functions of the chips on the board are +enabled, and how they’re configured. + +The devicetree file is parsed during the build process by a utility +named `sconfig`, which translates the devicetree into a tree of C +structures containing the included devices. This code is placed in the +file `static.c` and a couple of header files, all under the `build` +directory. This file is then built into the binaries for the various +coreboot stages and is referred to during the coreboot boot process. + +For the early stages of the coreboot boot process, the data that is +generated by `sconfig` is a useful resource, but this structure is the +critical architectural glue of ramstage. This structure gets filled in +with pointers to every chip's initialization code, allowing ramstage to +find and initialize those devices through the `chip_operations` +structures. + +### History of coreboot’s devicetree + +The initial devicetree in coreboot was introduced in 2003 by Ron Minnich +as a part of the linuxbios config file, `config.lb`. At this point both +the devicetree and config options were in the same file. In 2009, +when Kconfig was added into the coreboot build, devicetree was split +out into its own file for each mainboard in a commit with this message: + +```text +devicetree.cb + +The devicetree that formerly resided in src/mainboard/*/*/Config.lb. + +Just without the build system crap +``` + +The devicetree structure was initially mainly used only in ramstage for +PCI device enumeration, configuration and resource allocation. It has +since expanded for use in the pre-ram stages as a read-only structure. + +The language used in the devicetree has been expanded greatly since it +was first introduced as well, adding new features every year or so. + +### Devicetree Registers + +In coreboot, the devicetree register setting is one of the two main +methods used to configure a board’s properties. In this way, devicetree +is similar in function to Kconfig. It’s more flexible in many ways as +it can specify not only single values, but also arrays or structures. +It's also even more static than Kconfig because there’s no update +mechanism for it other than editing the devicetree files. + +Chip-specific configuration values are often set using `register` +definitions within a `chip` block, corresponding to a `struct` defined +in the chip's `chip.h` file. + +For example, in a `chip drivers/gpio/acpi` block, you might set a GPE: + +```text +register "gpe0_sts" = "0x42" +``` + +### Adding new static configuration options: Devicetree or Kconfig + +When adding options for a new board or chip, there is frequently a +decision that needs to be made about how the option should be added. +Using the devicetree or Kconfig are the two typical methods of +build-time configuration. Below are some general guidelines on when to +use each. + +Kconfig should be used if the option configures the build in a Makefile, +or if the option is something that should be user selectable. Kconfig +is also preferred if the configuration is a global option and not limited +to a single chip. Another thing Kconfig excels at is handling decisions +based on other configuration options, which devicetree cannot do. + +Devicetree should obviously be used to define the hardware hierarchy. +It's also preferred if the option is only used in C code and is static +for a mainboard, or if the option is chip-specific. As mentioned +earlier, devicetree registers can also define structures or arrays, +which Kconfig cannot. + +Both Kconfig and devicetree can be used in C code for runtime +configuration, but there’s a significant difference in how they are +handled. Because Kconfig generates a `#define` for the choice, the +compiler can eliminate code paths not used by the option. Devicetree +options, however, are actual runtime selections, and the code for all +choices remains in the final build. + +## Basic Devicetree Syntax + +The coreboot devicetree uses a custom language parsed by the `sconfig` +utility. Here's a brief overview of the main keywords and concepts: + +* **`chip <directory>`**: Defines a collection of devices associated + with the code in the specified directory. `sconfig` may also parse a + `chip.h` file within this directory for register definitions. +* **`device <type> <id> [on|off] [alias <name>] ... end`**: Defines a + specific hardware device. + * `<type>`: Specifies the device type (e.g., `pci`, `cpu_cluster`, + `i2c`). + * `<id>`: A unique identifier for the device within its type/bus + (e.g., PCI BDF `17.0`, I2C address `0x50`). + * `on`/`off`: Enables or disables the device definition. + * `alias <name>`: Assigns a human-readable alias for referencing + this device elsewhere (often used in `chipset.cb`). + * `end`: Marks the end of the device definition block. Registers + and other properties are defined between `device` and `end`. +* **`register "<name>" = <value>`**: Sets the value of a configuration + register defined in the corresponding `chip.h` structure. The value + can be a number, string, or complex structure initialization. +* **`probe <field> <option>`**: Used for firmware configuration + (`fw_config`), indicating a setting should be probed at runtime. +* **`ops "<identifier>"`**: Associates a `chip_operations` structure + with the device, used primarily in ramstage for device initialization. +* **`fw_config field <name> size <bits> ... end`**: Defines a firmware + configuration field, often used for passing board-specific data to + payloads. Options within the field are defined using `option`. +* **`ref <alias>`**: Used within `device` definitions in `devicetree.cb` + or `overridetree.cb` to refer to a device defined (usually via an + `alias`) in a lower-level file like `chipset.cb`. +* **`# <comment text>`**: Single-line comments. + +Device definitions can be nested within `chip` blocks. `end` keywords +close the current block (`device` or `chip`). + +## Three levels of devicetree files + +There are currently three different levels of devicetrees used to build +up the structure of components and register values in coreboot. From +the lowest, most general level to the highest and most specific, they +are `chipset.cb`, `devicetree.cb`, and `overridetree.cb`. + +Unless there’s a specific reason to name them something other than these +names, they should be used. + +For newer SoCs and chipsets, there will generally be a `chipset.cb` file. +Every mainboard requires a `devicetree.cb` file, although it can be empty +if everything is inherited from the `chipset.cb`. An `overridetree.cb` +file is only required if variants have differences from the primary +mainboard's `devicetree.cb`. + +### SoC / chipset level, `chipset.cb` + +The `chipset.cb` file was added in October 2020, allowing a single +chipset or SoC to provide a "base level" devicetree, reducing +duplication between mainboards. + +The `chipset.cb` file also typically defines human-readable "aliases" +for particular devices so that mainboards can use those instead of PCI +device/function numbers or other hardware identifiers. + +The use of the `chipset.cb` file is specified in Kconfig by the +`CHIPSET_DEVICETREE` symbol, which provides the path to the file. + +In a `chipset.cb` file, you might see lines like this: + +```text +# Chip definition for the SoC/chipset itself +chip soc/intel/common/block + + # Define PCI device 17.0, alias it to "sata", and default it off + device pci 17.0 alias sata off end + + # Define PCI device 1e.0, alias it to "uart0", and default it off + device pci 1e.0 alias uart0 off end + +end # chip soc/intel/common/block +``` + +This defines the devices, assigns aliases, and sets their default state. + +### Primary mainboard level, `devicetree.cb` + +Each mainboard must have a `devicetree.cb` file. The filename and path are +typically set by the `DEVICETREE` Kconfig symbol, defaulting to +`src/mainboard/<VENDOR>/<BOARD>/devicetree.cb`. + +If a mainboard using the above `chipset.cb` wanted both devices enabled, +its `devicetree.cb` might contain: + +```text +# Reference the SATA device by its alias and enable it +device ref sata on end + +# Reference the UART0 device by its alias and enable it +device ref uart0 on end +``` + +The `ref` keyword looks up the device (usually by alias) defined in a +lower-level file (`chipset.cb` in this case) and modifies its properties. + +### Mainboard variant level, `overridetree.cb` + +Introduced in 2018 to reduce duplication and maintenance for board +variants, the `overridetree.cb` file is the most specific level. + +This allows a base `devicetree.cb` at the top mainboard level shared by +all variants. Each variant then only needs an `overridetree.cb` to +specify its differences. + +The override tree filename is set in Kconfig with the +`OVERRIDE_DEVICETREE` symbol and is typically named `overridetree.cb`. + +Finally, if one variant of the mainboard lacked a SATA connector, it +could disable the SATA device again using the following in its specific +`overridetree.cb`: + +```text +# Reference the SATA device by alias and disable it for this variant +device ref sata off end +``` + +## Additional files + +### `chip.h` files + +coreboot looks at a "chip" as a collection of devices. This collection +can be a single logical device or multiple different ones. The `chip` +keyword starts this collection. Following the `chip` keyword is a +directory path (relative to `src/`) containing the code for that chip +or logical block of hardware. + +There may optionally be a `chip.h` file in that directory. If present, +`sconfig` parses this file to define a C structure containing the +"register definitions" for the chip. The values for this structure's +members are set using the `register` keyword in one of the devicetree +files (`chipset.cb`, `devicetree.cb`, `overridetree.cb`). If not +explicitly set, members typically default to 0 or follow standard C +initialization rules. The `chip.h` file frequently also contains C +macros, enums, and sub-structures used for setting the members of the +main register structure. + +The C structure for the chip’s register definition is named after the +directory containing the `chip.h` file, with slashes (`/`) changed to +underscores (`_`), and `_config` appended. The leading `src/` is omitted. + +This means that a line in a devicetree file like: +`chip drivers/i2c/hid` +would cause `sconfig` to look for `src/drivers/i2c/hid/chip.h`. If found, +the register definition structure it contains would be named +`drivers_i2c_hid_config`. + +Here is the content of `src/drivers/i2c/hid/chip.h`: + +```c +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __DRIVERS_I2C_HID_CHIP_H__ +#define __DRIVERS_I2C_HID_CHIP_H__ +#include <drivers/i2c/generic/chip.h> +#define I2C_HID_CID "PNP0C50" + +struct drivers_i2c_hid_config { + struct drivers_i2c_generic_config generic; + uint8_t hid_desc_reg_offset; +}; + +#endif /* __I2C_HID_CHIP_H__ */ +``` + +In a devicetree, you could set `hid_desc_reg_offset` like this: + +```text +chip drivers/i2c/hid + device i2c 0x2c on + # Set the HID descriptor register offset + register "hid_desc_reg_offset" = "0x01" + end +end +``` + +## The `sconfig` utility and generated files + +### `util/sconfig` + +`sconfig` is the tool that parses the coreboot devicetrees and turns +them into a collection of C structures. This is a coreboot-specific +tool, built using flex & bison to define and parse the domain-specific +language used by coreboot’s devicetree. + +`sconfig` is called by the makefiles during the build process and doesn’t +generally need to be run directly. If run manually (e.g., +`build/util/sconfig/sconfig --help`), it shows its command-line options. +The exact options might vary slightly, but typically include: + +```text +usage: sconfig <options> + + -c | --output_c : Path to output static.c file (required) + -r | --output_h : Path to header static.h file (required) + -d | --output_d : Path to header static_devices.h file (required) + -f | --output_f : Path to header static_fw_config.h file (required) + -m | --mainboard_devtree : Path to mainboard devicetree file (required) + -o | --override_devtree : Path to override devicetree file (optional) + -p | --chipset_devtree : Path to chipset/SOC devicetree file (optional) +``` + +### `sconfig` inputs + +The `sconfig` input files `chip.h`, `chipset.cb`, `devicetree.cb`, and +`overridetree.cb` were discussed previously. As the usage above shows, +the only required input file is the mainboard devicetree (`-m`). The +additional devicetree files, `chipset.cb` (`-p`) and `overridetree.cb` +(`-o`), are optional. The `chip.h` files do not need to be specified on +the command line; their locations are determined by the `chip` directory +paths within the `.cb` files. + +Constructing the devicetree input files will be discussed later. + +### `sconfig` outputs + +#### `static.c` + +This is the primary C file generated by `sconfig`. It contains the static +definitions of the device tree structures, including device nodes, bus +links, and register configuration data. + +For historic reasons, `static.c` is generated in the +`build/mainboard/<VENDOR>/<BOARD>` directory. + +#### `static.h` + +The `static.h` file is the main header file included by most coreboot C +files that need access to the devicetree data. It is included by +`src/include/device/device.h`, which provides the primary API +(definitions, structures, function prototypes) for interacting with the +devicetree-generated output. + +`static.h` used to contain all generated declarations directly. As of +October 2020, it simply includes the other two generated header files +(`static_devices.h` and `static_fw_config.h`). This separation allows +the firmware config options (`fw_config`) to be used independently, for +example, by a payload. + +#### `static_devices.h` + +The file `static_devices.h` contains `extern` declarations for all the +device structures (`struct device`) defined in `static.c`. This allows +other C files to reference the generated device tree nodes. + +#### `static_fw_config.h` + +`static_fw_config.h` contains only the `FW_CONFIG_FIELD_*` macro results, +derived from `fw_config` entries in the devicetree. This makes it easily +consumable by payloads or other components needing platform `FW_CONFIG` +data without pulling in the full device tree structure. + +## Devicetree Example + +### A very simple devicetree + +This is the `devicetree.cb` file from +`src/mainboard/sifive/hifive-unleashed`, with line numbers added for +reference. Non-x86 devicetree files are often simpler than their x86 +counterparts. + +```text + 1 # SPDX-License-Identifier: GPL-2.0-only + 2 chip soc/sifive/fu540 + 3 device cpu_cluster 0 on end + 4 end +``` + +This can be broken down as follows: + +Line 1: Comments start with `#`. This line is the SPDX license +identifier for the file. + +Line 2: `chip soc/sifive/fu540` starts a block for the SiFive FU540 SoC. +`sconfig` will look for code and potentially a `chip.h` in +`src/soc/sifive/fu540/`. + +Line 3: `device cpu_cluster 0 on end` defines a device of type +`cpu_cluster` with ID `0`. It's marked as enabled (`on`). Since there are +no registers or other properties defined between `device` and `end`, this +is a simple enablement entry. + +Line 4: `end` closes the block started by the `chip` keyword on line 2. + +### Generated files + +Continuing with the simple `sifive/hifive-unleashed` mainboard example, +these are the files generated by `sconfig` from the devicetree above (as +of mid-2022; exact output can change). Because the input devicetree is +minimal, the generated files are also quite sparse. + +#### `build/static.h` + +```c +#ifndef __STATIC_DEVICE_TREE_H +#define __STATIC_DEVICE_TREE_H + +#include <static_fw_config.h> +#include <static_devices.h> + +#endif /* __STATIC_DEVICE_TREE_H */ +``` +(Includes the other generated headers.) + +#### `build/static_devices.h` + +```c +#ifndef __STATIC_DEVICES_H +#define __STATIC_DEVICES_H +#include <device/device.h> +/* expose_device_names */ +#endif /* __STATIC_DEVICE_NAMES_H */ +``` +(Includes `device/device.h` but contains no actual device externs beyond +the implicit root device, as the simple example didn't define complex +devices requiring separate structs.) + +#### `build/static_fw_config.h` + +```c +#ifndef __STATIC_FW_CONFIG_H +#define __STATIC_FW_CONFIG_H +#endif /* __STATIC_FW_CONFIG_H */ +``` +(Empty because the example `devicetree.cb` did not use `fw_config`.) + +#### `build/mainboard/sifive/hifive-unleashed/static.c` + +##### Includes + +```c +1 #include <boot/coreboot_tables.h> +2 #include <device/device.h> +3 #include <device/pci.h> +4 #include <fw_config.h> +5 #include <static.h> +``` + +Lines 1-5: Includes header files required for the following structure +definitions and macros. + +##### Declarations for chip-ops + +```c +6 +7 #if !DEVTREE_EARLY +8 __attribute__((weak)) struct chip_operations mainboard_ops = {}; +9 extern struct chip_operations soc_sifive_fu540_ops; +10 #endif +``` + +Lines 7 & 10: The `ops` structures inside this `#if !DEVTREE_EARLY` block +are only relevant and linked in ramstage. + +Lines 8-9: Declarations for `chip_operations` structures. This section +expands as more chips are added to the devicetree. +* Line 8: `mainboard_ops` is always present. It’s defined as `weak` + because the mainboard C code may or may not provide this structure. +* Line 9: This `extern` is generated by the `chip soc/sifive/fu540` + declaration in the `devicetree.cb`. There will be a similar line for + every `chip` declared. + +##### `STORAGE` definition + +```c +11 +12 #define STORAGE static __unused DEVTREE_CONST +``` + +Line 12: This macro conditionally adds `const` based on the build stage. +It resolves to `static __unused const` in early stages (pre-RAM) and +`static __unused` in ramstage, where the structures might be modified. + +##### Structure definitions + +```c +13 +14 +15 /* pass 0 */ +16 STORAGE struct bus dev_root_links[]; +17 STORAGE struct device _dev_0; +18 DEVTREE_CONST struct device * DEVTREE_CONST last_dev = &_dev_0; +``` + +Lines 16-18: Forward declarations of the static structures generated by +`sconfig` based on the devicetree input. `_dev_0` corresponds to the +`cpu_cluster 0` device. + +##### Register Structures + +```c +19 +20 /* chip configs */ +``` + +Line 20: This section is empty for this mainboard because the +`soc/sifive/fu540/chip.h` file (if it exists) does not define a register +structure, or the devicetree did not instantiate it using `register`. +Otherwise, this section would contain the static initialization of chip +configuration structures based on `register` entries. + +##### `dev_root` structure + +Lines 21-44: `dev_root`. This structure represents the root of the +coreboot device tree. It is always generated, regardless of the content +of the `devicetree.cb` file. It serves as the entry point for traversing +the tree. + +```c +21 +22 /* pass 1 */ +23 DEVTREE_CONST struct device dev_root = { +24 #if !DEVTREE_EARLY +25 .ops = &default_dev_ops_root, +26 #endif +27 .bus = &dev_root_links[0], +28 .path = { .type = DEVICE_PATH_ROOT }, +29 .enabled = 1, +30 .hidden = 0, +31 .mandatory = 0, +32 .on_mainboard = 1, +33 .link_list = &dev_root_links[0], +34 .sibling = NULL, +35 #if !DEVTREE_EARLY +36 .chip_ops = &mainboard_ops, +37 .name = mainboard_name, +38 #endif +39 .next=&_dev_0, +40 #if !DEVTREE_EARLY +41 #if CONFIG(GENERATE_SMBIOS_TABLES) +42 #endif +43 #endif +44 }; +``` + +* Lines 24-26: Points to a default ramstage `device_operation` + structure (`default_dev_ops_root`) found in + `src/device/root_device.c`. This structure typically does little by + default but can be overridden or utilized by mainboard code via the + `chip_operations->enable_dev()` hook for tasks like ACPI table + generation. +* Line 27: `.bus`: Pointer to the bus structure associated with this + device. For the root device, this points to its own bus link array, + `dev_root_links`. +* Line 28: `.path`: The unique path identifier for this device. The type + is `DEVICE_PATH_ROOT`. +* Lines 29-32: Device status flags. + * `enabled`: Set based on `on`/`off` in the devicetree (always on + for `dev_root`). Can be modified later (e.g., during enumeration + in ramstage). + * `hidden`, `mandatory`: Set only by corresponding keywords in the + devicetree (not used here). + * `on_mainboard`: Indicates the device was defined in the static + devicetree, as opposed to being discovered dynamically (e.g., via + PCI enumeration). Always true for `dev_root`. +* Line 33: `.link_list`: Pointer to the list of child buses attached to + this device. +* Line 34: `.sibling`: Pointer to the next device at the same level in + the tree. Should always be `NULL` for `dev_root`. +* Line 36: `.chip_ops`: Pointer to the mainboard's `chip_operations` + structure (the `weak` `mainboard_ops`). Although not a physical + chip, the mainboard gets this to hook into the boot process like + other chips. +* Line 37: `.name`: A string identifier, typically the mainboard name, + set at build time (from `src/device/root_device.c`). +* Line 39: `.next`: Pointer used internally by `sconfig` during tree + construction. Points to the next device structure processed (`_dev_0`). + +##### `dev_root_links` + +Lines 45-52: The `dev_root` bus structure array. + +This array (`struct bus`) holds pointers defining the bus topology. Each +element represents a link on a bus. `dev_root` acts as the bridge for the +top-level bus. + +A new bus structure array is typically created for each distinct bus type +or domain originating from a bridge device in the devicetree (e.g., PCI +domain 0, LPC bus). + +```c +45 STORAGE struct bus dev_root_links[] = { +46 [0] = { +47 .link_num = 0, +48 .dev = &dev_root, +49 .children = &_dev_0, +50 .next = NULL, +51 }, +52 }; +``` + +* Line 47: `.link_num`: Index of this link within the bus array. +* Line 48: `.dev`: Pointer back to the bridge device structure for this + bus (`dev_root`). +* Line 49: `.children`: Pointer to the first child device structure on + this bus (`_dev_0`). +* Line 50: `.next`: Pointer to the next bridge device on the *parent* + bus. Since `dev_root` has no parent bus, this is `NULL`. + +##### `_dev_0` + +Lines 53-72: The `cpu_cluster` device structure (`_dev_0`). + +This structure corresponds directly to the +`device cpu_cluster 0 on end` line in the `devicetree.cb`. + +```c +53 STORAGE struct device _dev_0 = { +54 #if !DEVTREE_EARLY +55 .ops = NULL, +56 #endif +57 .bus = &dev_root_links[0], +58 .path = {.type=DEVICE_PATH_CPU_CLUSTER,{.cpu_cluster={ .cluster = 0x0 }}}, +59 .enabled = 1, +60 .hidden = 0, +61 .mandatory = 0, +62 .on_mainboard = 1, +63 .link_list = NULL, +64 .sibling = NULL, +65 #if !DEVTREE_EARLY +66 .chip_ops = &soc_sifive_fu540_ops, +67 #endif +68 #if !DEVTREE_EARLY +69 #if CONFIG(GENERATE_SMBIOS_TABLES) +70 #endif +71 #endif +72 }; +``` + +* Lines 54-56: `.ops`: Pointer to a `device_operations` structure. This + is `NULL` because this entry represents the `chip` itself, not a + specific functional sub-device requiring device-level operations. The + chip-level operations are handled by `chip_ops`. +* Line 57: `.bus`: Pointer to the bus structure this device resides on. + Since it's directly under `dev_root`, it points to `dev_root_links[0]`. +* Line 58: `.path`: The unique device path structure (defined in + `src/include/device/path.h`). Type is `DEVICE_PATH_CPU_CLUSTER`, + and the cluster ID is `0`, matching the devicetree entry. This path + is used when searching the tree (e.g., with `dev_find_path()`). +* Lines 59-62: Enumeration Status. Similar to `dev_root`. `enabled = 1` + comes from the `on` keyword. +* Line 63: `.link_list`: Pointer to child buses. `NULL` because this + `cpu_cluster` device doesn't bridge to any further buses in this + simple example. +* Line 64: `.sibling`: Pointer to the next device at the same level + (i.e., another device directly under `dev_root`). `NULL` as it's the + only child. +* Lines 65-67: `.chip_ops`: Pointer to the processor's `chip_operations` + structure (`soc_sifive_fu540_ops`), used in ramstage for SoC/CPU + initialization steps. This link comes from the `chip soc/sifive/fu540` + declaration. +* Lines 68-71: Placeholder for SMBIOS information, enabled by Kconfig. + Not used in this example.