summaryrefslogtreecommitdiffstats
path: root/Documentation/lib/fw_config.md
blob: 884ba3f237330e287da91dc34be1dd4180a3c926 (plain)
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
# Firmware Configuration Interface in coreboot

## Motivation

The firmware configuration interface in coreboot is designed to support a wide variety of
configuration options in that are dictated by the hardware at runtime.  This allows a single
BIOS image to be used across a wide variety of devices which may have key differences but are
otherwise similar enough to use the same coreboot build target.

The initial implementation is designed to take advantage of a bitmask returned by the Embedded
Controller on Google ChromeOS devices which allows the manufacturer to use the same firmware
image across multiple devices by selecting various options at runtime.  See the ChromiumOS
[Firmware Config][1] documentation for more information.

This firmware configuration interface differs from the CMOS option interface in that this
bitmask value is not intended as a user-configurable setting as the configuration values must
match the actual hardware.  In the case where a user was to swap their hardware this value
would need to be updated or overridden.

## Device Presence

One common example of why a firmware configuration interface is important is determining if a
device is present in the system.  With some bus topologies and hardware mechanisms it is
possible to probe and enumerate this at runtime:

- PCI is a self-discoverable bus and is very easy to handle.
- I2C devices can often be probed with a combination of bus and address.
- The use of GPIOs with external strap to ground or different voltages can be used to detect
presence of a device.

However there are several cases where this is insufficient:

- I2C peripherals that require different drivers but have the same bus address cannot be
uniquely identified at runtime.
- A mainboard may be designed with multiple daughter board combinations which contain devices
and configurations that cannot be detected.
- While presence detect GPIOs are a convenient way for a single device presence, they are
unable to distinguish between different devices so it can require a large number of GPIOs to
support relatively few options.

This presence detection can impact different stages of boot:

### ACPI

Devices that are not present should not provide an ACPI device indicating that they are
present or the operating system may not be able to handle it correctly.

The ACPI devices are largely driven by chips defined in the mainboard `devicetree.cb` and
the variant overridetree.cb.  This means it is important to be able to specify when a device
is present or not directly in `devicetree.cb` itself.  Otherwise each mainboard needs custom
code to parse the tree and disable unused devices.

### GPIO

GPIOs with multiple functions may need to be configured correctly depending on the attached
device.  Given the wide variety of GPIO configuration possibilities it is not feasible to
specify all combinations directly in `devicetree.cb` and it is best left to code provided by
the mainboard.

### FSP UPD

Enabling and disabling devices may require altering FSP UPD values that are provided to the
various stages of FSP.  These options are also not easy to specify multiple times for
different configurations in `devicetree.cb` and can be provided by the mainboard as code.

## Firmware Configuration Interface

The firmware configuration interface can be enabled by selecting `CONFIG_FW_CONFIG` and also
providing a source for the value by defining an additional Kconfig option defined below.

If the firmware configuration interface is disabled via Kconfig then all probe attempts will
return true.

## Firmware Configuration Value

The 64-bit value used as the firmware configuration bitmask is meant to be determined at runtime
but could also be defined at compile time if needed.

There are two supported sources for providing this information to coreboot.

### CBFS

The value can be provided with a 64-bit raw value in CBFS that is read by coreboot.  The value
can be set at build time but also adjusted in an existing image with `cbfstool`.

To enable this select the `CONFIG_FW_CONFIG_CBFS` option in the build configuration and add a
raw 64-bit value to CBFS with the name of the current prefix at `CONFIG_FW_PREFIX/fw_config`.

When `fw_config_probe_device()` or `fw_config_probe()` is called it will look for the specified
file in CBFS use the value it contains when matching fields and options.

### Embedded Controller

Google ChromeOS devices support an Embedded Controller interface for reading and writing the
firmware configuration value, along with other board-specific information.  It is possible for
coreboot to read this value at boot on systems that support this feature.

This option is selected by default for the mainboards that use it with
`CONFIG_FW_CONFIG_CHROME_EC_CBI` and it is not typically necessary to adjust the value.  It is
possible by enabling the CBFS source and coreboot will look in CBFS first for a valid value
before asking the embedded controller.

It is also possible to adjust the value in the embedded controller *(after disabling write
protection)* with the `ectool` command in a ChromeOS environment.

For more information on the firmware configuration field on ChromeOS devices see the Chromium
documentation for [Firmware Config][1] and [Board Info][2].

[1]: http://chromium.googlesource.com/chromiumos/docs/+/HEAD/design_docs/firmware_config.md
[2]: http://chromium.googlesource.com/chromiumos/docs/+/HEAD/design_docs/cros_board_info.md

## Firmware Configuration Table

The firmware configuration table itself is defined in the mainboard `devicetree.cb` with
special tokens for defining fields and options.

The table itself is enclosed in a `fw_config` token and terminated with `end` and it contains
a mix of field and option definitions.

Each field is defined by providing the field name and the start and end bit marking the exact
location in the bitmask.  Field names must be at least three characters long in order to
satisfy the sconfig parser requirements and they must be unique with non-overlapping masks.

	field <name> <start-bit> <end-bit> [option...] end

For single-bit fields only one number is needed:

	field <name> <bit> [option...] end

A field definition can also contain multiple sets of bit masks, which can be dis-contiguous.
They are treated as if they are contiguous when defining option values.  This allows for
extending fields even after the bits after its current masks are occupied.

	field <name> <start-bit0> <end-bit0> | <start-bit1> <end-bit1> | ...

For example, if more audio options need to be supported:

	field AUDIO 3 3
		option AUDIO_0  0
		option AUDIO_1  1
	end
	field OTHER 4 4
		...
	end

the following can be done:

	field AUDIO 3 3 | 5 5
		option AUDIO_FOO   0
		option AUDIO_BLAH  1
		option AUDIO_BAR   2
		option AUDIO_BAZ   3
	end
	field OTHER 4 4
		...
	end

In that case, the AUDIO masks are extended like so:

	#define FW_CONFIG_FIELD_AUDIO_MASK						0x28
	#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_FOO_VALUE	0x0
	#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BLAH_VALUE	0x8
	#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BAR_VALUE	0x20
	#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BAz_VALUE	0x28

Each `field` definition starts a new block that can be composed of zero or more field options,
and it is terminated with `end`.

Inside the field block the options can be defined by providing the option name and the field
value that this option represents when the bit offsets are used to apply a mask and shift.
Option names must also be at least three characters for the sconfig parser.

	option <name> <value>

It is possible for there to be multiple `fw_config` blocks and for subsequent `field` blocks
to add additional `option` definitions to the existing field.  These subsequent definitions
should not provide the field bitmask as it has already been defined earlier in the file and
this is just matching an existing field by name.

	field <name> [option...] end

This allows a baseboard to define the major fields and options in `devicetree.cb` and a board
variant to add specific options to fields in or define new fields in the unused bitmask in
`overridetree.cb`.

It is not possible to redefine a field mask or override the value of an existing option this
way, only to add new options to a field or new fields to the table.

### Firmware Configuration Table Example

In this example a baseboard defines a simple boolean feature that is enabled or disabled
depending on the value of bit 0, and a field at bits 1-2 that indicates which daughter board
is attached.

The baseboard itself defines one daughter board and the variant adds two more possibilities.
This way each variant can support multiple possible daughter boards in addition to the one
that was defined by the baseboard.

#### devicetree.cb

    fw_config
        field FEATURE 0
            option DISABLED 0
            option ENABLED 1
        end
        field DAUGHTER_BOARD 1 2
            option NONE 0
            option REFERENCE_DB 1
        end
    end

#### overridetree.cb

    fw_config
        field DAUGHTER_BOARD
            option VARIANT_DB_ONE 2
            option VARIANT_DB_TWO 3
        end
    end

The result of this table defined in `devicetree.cb` is a list of constants that can be used
to check if fields match the firmware configuration options determined at runtime with a
simple check of the field mask and the option value.

#### static.h

```c
/* field: FEATURE */
#define FW_CONFIG_FIELD_FEATURE_NAME "FEATURE"
#define FW_CONFIG_FIELD_FEATURE_MASK 0x00000001
#define FW_CONFIG_FIELD_FEATURE_OPTION_DISABLED_NAME "DISABLED"
#define FW_CONFIG_FIELD_FEATURE_OPTION_DISABLED_VALUE 0x00000000
#define FW_CONFIG_FIELD_FEATURE_OPTION_ENABLED_NAME "ENABLED"
#define FW_CONFIG_FIELD_FEATURE_OPTION_ENABLED_VALUE 0x00000001

/* field: DAUGHTER_BOARD */
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_NAME "DAUGHTER_BOARD"
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_MASK 0x00000006
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_NONE_NAME "NONE"
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_NONE_VALUE 0x00000000
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_REFERENCE_DB_NAME "REFERENCE_DB"
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_REFERENCE_DB_VALUE 0x00000002
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_ONE_NAME "VARIANT_DB_ONE"
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_ONE_VALUE 0x00000004
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_NAME "VARIANT_DB_TWO"
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_VALUE 0x00000006
```

## Device Probing

One use of the firmware configuration interface in devicetree is to allow device probing to be
specified directly with the devices themselves.  A new `probe` token is introduced to allow a
device to be probed by field and option name.  Multiple `probe` entries may be present for
each device and any successful probe will consider the device to be present.

### Probing Example

Continuing with the previous example this device would be considered present if the field
`DAUGHTER_BOARD` was set to either `VARIANT_DB_ONE` or `VARIANT_DB_TWO`:

#### overridetree.cb

    chip drivers/generic/example
        device generic 0 on
            probe DAUGHTER_BOARD VARIANT_DB_ONE
            probe DAUGHTER_BOARD VARIANT_DB_TWO
        end
    end

If the field were set to any other option, including `NONE` and `REFERENCE_DB` and any
undefined value then the device would be disabled.

### Probe Overrides

When a device is declared with a probe in the baseboard `devicetree.cb` and the same device
is also present in the `overridetree.cb` then the probing information from the baseboard
is discarded and the override device must provide all necessary probing information.

In this example a device is listed in the baseboard with `DAUGHTER_BOARD` field probing for
`REFERENCE_DB` as a field option,  It is also defined as an override device with the field
probing for the `VARIANT_DB_ONE` option instead.

In this case only the probe listed in the override is checked and a field option of
`REFERENCE_DB` will not mark this device present.  If both options are desired then the
override device must list both.  This allows an override device to remove a probe entry that
was defined in the baseboard.

#### devicetree.cb

    chip drivers/generic/example
	    device generic 0 on
		    probe DAUGHTER_BOARD REFERENCE_DB
	    end
	end

#### overridetree.cb

    chip drivers/generic/example
	    device generic 0 on
		    probe DAUGHTER_BOARD VARIANT_DB_ONE
	    end
	end

### Automatic Device Probing

At boot time the firmware configuration interface will walk the device tree and apply any
probe entries that were defined in `devicetree.cb`.  This probing takes effect before the
`BS_DEV_ENUMERATE` step during the boot state machine in ramstage.

Devices that have a probe list but do do not find a match are disabled by setting
`dev->enabled = 0` but the chip `enable_dev()` and device `enable()` handlers will still
be executed to allow any device disable code to execute.

The result of this probe definition is to provide an array of structures describing each
field and option to check.

#### fw_config.h

```c
/**
 * struct fw_config - Firmware configuration field and option.
 * @field_name: Name of the field that this option belongs to.
 * @option_name: Name of the option within this field.
 * @mask: Bitmask of the field.
 * @value: Value of the option within the mask.
 */
struct fw_config {
	const char *field_name;
	const char *option_name;
	uint64_t mask;
	uint64_t value;
};
```

#### static.c

```c
STORAGE struct fw_config __devN_probe_list[] = {
	{
		.field_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_NAME,
		.option_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_ONE_NAME,
		.mask = FW_CONFIG_FIELD_DAUGHTER_BOARD_MASK,
		.value = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_ONE_VALUE
	},
	{
		.field_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_NAME,
		.option_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_NAME,
		.mask = FW_CONFIG_FIELD_DAUGHTER_BOARD_MASK,
		.value = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_VALUE
	},
	{ }
};
```

### Runtime Probing

The device driver probing allows for seamless integration with the mainboard but it is only
effective in ramstage and for specific devices declared in devicetree.cb.  There are other
situations where code may need to probe or check the value of a field in romstage or at other
points in ramstage.  For this reason it is also possible to use the firmware configuration
interface directly.

```c
/**
 * fw_config_probe() - Check if field and option matches.
 * @match: Structure containing field and option to probe.
 *
 * Return %true if match is found, %false if match is not found.
 */
bool fw_config_probe(const struct fw_config *match);
```

The argument provided to this function can be created from a macro for easy use:

	FW_CONFIG(field, option)

This example has a mainboard check if a feature is disabled and set an FSP UPD before memory
training.  This example expects that the default value of this `register` is set to `true` in
`devicetree.cb` and this code is disabling that feature before FSP is executed.

```c
#include <fw_config.h>

void mainboard_memory_init_params(FSPM_UPD *mupd)
{
	if (fw_config_probe(FW_CONFIG(FEATURE, DISABLED))
		mupd->ExampleFeature = false;
}
```