Documentation/internals: Add devicetree documentation
Signed-off-by: Martin Roth <gaumless@gmail.com> Change-Id: I2a43a96911844bd2b682004d5423126ad00a4bf3 Reviewed-on: https://review.coreboot.org/c/coreboot/+/84709 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Nicholas Chin <nic.c3.14@gmail.com>
This commit is contained in:
parent
9c05e9900e
commit
44921d386c
3 changed files with 698 additions and 0 deletions
|
|
@ -219,6 +219,7 @@ Community <community/index.md>
|
|||
Payloads <payloads.md>
|
||||
Distributions <distributions.md>
|
||||
Technotes <technotes/index.md>
|
||||
Internal APIs & Configuration <internals/index.md>
|
||||
ACPI <acpi/index.md>
|
||||
Native Graphics Initialization with libgfxinit <gfx/libgfxinit.md>
|
||||
Display panel <gfx/display-panel.md>
|
||||
|
|
|
|||
684
Documentation/internals/devicetree.md
Normal file
684
Documentation/internals/devicetree.md
Normal file
|
|
@ -0,0 +1,684 @@
|
|||
# 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
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
```text
|
||||
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.
|
||||
|
||||
```text
|
||||
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 structure.
|
||||
* 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).
|
||||
|
||||
```text
|
||||
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`.
|
||||
|
||||
```text
|
||||
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.
|
||||
13
Documentation/internals/index.md
Normal file
13
Documentation/internals/index.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# coreboot internals
|
||||
|
||||
This section contains documentation about the configuration and
|
||||
programming APIs internal to coreboot
|
||||
|
||||
## Configuration
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
coreboot devicetree <devicetree.md>
|
||||
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue