xref: /aosp_15_r20/external/coreboot/src/lib/fw_config.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <bootstate.h>
5 #include <cbfs.h>
6 #include <console/console.h>
7 #include <device/device.h>
8 #include <ec/google/chromeec/ec.h>
9 #include <fw_config.h>
10 #include <inttypes.h>
11 #include <lib.h>
12 #include <drivers/vpd/vpd.h>
13 
fw_config_get(void)14 uint64_t fw_config_get(void)
15 {
16 	static uint64_t fw_config_value;
17 	static bool fw_config_value_initialized;
18 
19 	/* Nothing to prepare if setup is already done. */
20 	if (fw_config_value_initialized)
21 		return fw_config_value;
22 	fw_config_value_initialized = true;
23 	fw_config_value = UNDEFINED_FW_CONFIG;
24 
25 	/* Read the value from EC CBI. */
26 	if (CONFIG(FW_CONFIG_SOURCE_CHROMEEC_CBI)) {
27 		if (google_chromeec_cbi_get_fw_config(&fw_config_value))
28 			printk(BIOS_WARNING, "%s: Could not get fw_config from CBI\n",
29 				__func__);
30 		else
31 			printk(BIOS_INFO, "FW_CONFIG value from CBI is 0x%" PRIx64 "\n",
32 				fw_config_value);
33 	}
34 
35 	/* Look in CBFS to allow override of value. */
36 	if (CONFIG(FW_CONFIG_SOURCE_CBFS) && fw_config_value == UNDEFINED_FW_CONFIG) {
37 		if (cbfs_load(CONFIG_CBFS_PREFIX "/fw_config", &fw_config_value,
38 			      sizeof(fw_config_value)) != sizeof(fw_config_value))
39 			printk(BIOS_WARNING, "%s: Could not get fw_config from CBFS\n",
40 				__func__);
41 		else
42 			printk(BIOS_INFO, "FW_CONFIG value from CBFS is 0x%" PRIx64 "\n",
43 				fw_config_value);
44 	}
45 
46 	if (CONFIG(FW_CONFIG_SOURCE_VPD) && fw_config_value == UNDEFINED_FW_CONFIG) {
47 		int vpd_value;
48 		if (vpd_get_int("fw_config", VPD_RW_THEN_RO, &vpd_value)) {
49 			fw_config_value = vpd_value;
50 			printk(BIOS_INFO, "FW_CONFIG value from VPD is 0x%" PRIx64 "\n",
51 				fw_config_value);
52 		} else
53 			printk(BIOS_WARNING, "%s: Could not get fw_config from vpd\n",
54 				__func__);
55 	}
56 
57 	return fw_config_value;
58 }
59 
fw_config_get_field(const struct fw_config_field * field)60 uint64_t fw_config_get_field(const struct fw_config_field *field)
61 {
62 	/* If fw_config is not provisioned, then there is nothing to get. */
63 	if (!fw_config_is_provisioned())
64 		return UNDEFINED_FW_CONFIG;
65 
66 	int shift = __ffs64(field->mask);
67 	const uint64_t value = (fw_config_get() & field->mask) >> shift;
68 
69 	printk(BIOS_INFO, "fw_config get field name=%s, mask=0x%" PRIx64 ", shift=%d, value=0x%"
70 		PRIx64 "\n", field->field_name, field->mask, shift, value);
71 
72 	return value;
73 }
74 
fw_config_probe(const struct fw_config * match)75 bool fw_config_probe(const struct fw_config *match)
76 {
77 	/* If fw_config is not provisioned, then there is nothing to match. */
78 	if (!fw_config_is_provisioned())
79 		return false;
80 
81 	/* Compare to system value. */
82 	if ((fw_config_get() & match->mask) == match->value) {
83 		if (match->field_name && match->option_name)
84 			printk(BIOS_INFO, "fw_config match found: %s=%s\n", match->field_name,
85 			       match->option_name);
86 		else
87 			printk(BIOS_INFO, "fw_config match found: mask=0x%" PRIx64 " value=0x%"
88 			       PRIx64 "\n",
89 			       match->mask, match->value);
90 		return true;
91 	}
92 
93 	return false;
94 }
95 
fw_config_probe_dev(const struct device * dev,const struct fw_config ** matching_probe)96 bool fw_config_probe_dev(const struct device *dev, const struct fw_config **matching_probe)
97 {
98 	const struct fw_config *probe;
99 
100 	if (matching_probe)
101 		*matching_probe = NULL;
102 
103 	/* If the device does not have a probe list, then probing is not required. */
104 	if (!dev->probe_list)
105 		return true;
106 
107 	for (probe = dev->probe_list; probe && probe->mask != 0; probe++) {
108 		if (!fw_config_probe(probe))
109 			continue;
110 
111 		if (matching_probe)
112 			*matching_probe = probe;
113 		return true;
114 	}
115 
116 	return false;
117 }
118 
119 #if ENV_RAMSTAGE
120 
121 /*
122  * The maximum number of fw_config fields is limited by the 64-bit mask that is used to
123  * represent them.
124  */
125 #define MAX_CACHE_ELEMENTS	(8 * sizeof(uint64_t))
126 
127 static const struct fw_config *cached_configs[MAX_CACHE_ELEMENTS];
128 
probe_index(uint64_t mask)129 static size_t probe_index(uint64_t mask)
130 {
131 	assert(mask);
132 	return __ffs64(mask);
133 }
134 
fw_config_get_found(uint64_t field_mask)135 const struct fw_config *fw_config_get_found(uint64_t field_mask)
136 {
137 	const struct fw_config *config;
138 	config = cached_configs[probe_index(field_mask)];
139 	if (config && config->mask == field_mask)
140 		return config;
141 
142 	return NULL;
143 }
144 
fw_config_for_each_found(void (* cb)(const struct fw_config * config,void * arg),void * arg)145 void fw_config_for_each_found(void (*cb)(const struct fw_config *config, void *arg), void *arg)
146 {
147 	size_t i;
148 
149 	for (i = 0; i < MAX_CACHE_ELEMENTS; ++i)
150 		if (cached_configs[i])
151 			cb(cached_configs[i], arg);
152 }
153 
fw_config_init(void * unused)154 static void fw_config_init(void *unused)
155 {
156 	struct device *dev;
157 
158 	for (dev = all_devices; dev; dev = dev->next) {
159 		const struct fw_config *probe;
160 
161 		if (!fw_config_probe_dev(dev, &probe)) {
162 			printk(BIOS_INFO, "%s disabled by fw_config\n", dev_path(dev));
163 			dev->enabled = 0;
164 			continue;
165 		}
166 
167 		if (probe)
168 			cached_configs[probe_index(probe->mask)] = probe;
169 	}
170 }
171 BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_ENTRY, fw_config_init, NULL);
172 #endif
173