File: devicetree.md

package info (click to toggle)
coreboot 25.09%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 217,084 kB
  • sloc: ansic: 1,685,313; sh: 15,803; python: 11,200; perl: 10,186; asm: 8,519; makefile: 5,179; cpp: 4,724; pascal: 2,327; ada: 1,985; yacc: 1,264; lex: 731; sed: 75; ruby: 5; lisp: 5; awk: 4
file content (684 lines) | stat: -rw-r--r-- 25,456 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
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.