blob: 2f7186cc86f9c6dd341076fd3d68c878a4f2ce55 [file] [log] [blame]
Duncan Laurie36e6c6f2020-05-09 19:20:10 -07001/* SPDX-License-Identifier: GPL-2.0-only */
2
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -06003#include <assert.h>
Duncan Laurie36e6c6f2020-05-09 19:20:10 -07004#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>
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060010#include <inttypes.h>
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -060011#include <lib.h>
Duncan Laurie36e6c6f2020-05-09 19:20:10 -070012#include <stdbool.h>
13#include <stdint.h>
14
Tim Wawrzynczakc70505a2020-10-09 17:06:28 -060015uint64_t fw_config_get(void)
Duncan Laurie36e6c6f2020-05-09 19:20:10 -070016{
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060017 static uint64_t fw_config_value;
Duncan Laurie36e6c6f2020-05-09 19:20:10 -070018 static bool fw_config_value_initialized;
19
20 /* Nothing to prepare if setup is already done. */
21 if (fw_config_value_initialized)
22 return fw_config_value;
23 fw_config_value_initialized = true;
24
25 /* Look in CBFS to allow override of value. */
26 if (CONFIG(FW_CONFIG_SOURCE_CBFS)) {
Julius Werner834b3ec2020-03-04 16:52:08 -080027 if (cbfs_load(CONFIG_CBFS_PREFIX "/fw_config", &fw_config_value,
28 sizeof(fw_config_value)) != sizeof(fw_config_value)) {
Duncan Laurie36e6c6f2020-05-09 19:20:10 -070029 printk(BIOS_WARNING, "%s: Could not get fw_config from CBFS\n",
30 __func__);
31 fw_config_value = 0;
32 } else {
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060033 printk(BIOS_INFO, "FW_CONFIG value from CBFS is 0x%" PRIx64 "\n",
Duncan Laurie36e6c6f2020-05-09 19:20:10 -070034 fw_config_value);
35 return fw_config_value;
36 }
37 }
38
39 /* Read the value from EC CBI. */
40 if (CONFIG(FW_CONFIG_SOURCE_CHROMEEC_CBI)) {
41 if (google_chromeec_cbi_get_fw_config(&fw_config_value))
42 printk(BIOS_WARNING, "%s: Could not get fw_config from EC\n", __func__);
43 }
44
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060045 printk(BIOS_INFO, "FW_CONFIG value is 0x%" PRIx64 "\n", fw_config_value);
Duncan Laurie36e6c6f2020-05-09 19:20:10 -070046 return fw_config_value;
47}
48
49bool fw_config_probe(const struct fw_config *match)
50{
51 /* Compare to system value. */
52 if ((fw_config_get() & match->mask) == match->value) {
53 if (match->field_name && match->option_name)
54 printk(BIOS_INFO, "fw_config match found: %s=%s\n", match->field_name,
55 match->option_name);
56 else
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060057 printk(BIOS_INFO, "fw_config match found: mask=0x%" PRIx64 " value=0x%"
58 PRIx64 "\n",
Duncan Laurie36e6c6f2020-05-09 19:20:10 -070059 match->mask, match->value);
60 return true;
61 }
62
63 return false;
64}
65
66#if ENV_RAMSTAGE
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -060067
68/*
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060069 * The maximum number of fw_config fields is limited by the 64-bit mask that is used to
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -060070 * represent them.
71 */
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060072#define MAX_CACHE_ELEMENTS (8 * sizeof(uint64_t))
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -060073
74static const struct fw_config *cached_configs[MAX_CACHE_ELEMENTS];
75
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060076static size_t probe_index(uint64_t mask)
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -060077{
78 assert(mask);
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060079 return __ffs64(mask);
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -060080}
81
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -060082const struct fw_config *fw_config_get_found(uint64_t field_mask)
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -060083{
84 const struct fw_config *config;
85 config = cached_configs[probe_index(field_mask)];
86 if (config && config->mask == field_mask)
87 return config;
88
89 return NULL;
90}
91
92void fw_config_for_each_found(void (*cb)(const struct fw_config *config, void *arg), void *arg)
93{
94 size_t i;
95
96 for (i = 0; i < MAX_CACHE_ELEMENTS; ++i)
97 if (cached_configs[i])
98 cb(cached_configs[i], arg);
99}
100
Duncan Laurie36e6c6f2020-05-09 19:20:10 -0700101static void fw_config_init(void *unused)
102{
103 struct device *dev;
104
105 for (dev = all_devices; dev; dev = dev->next) {
106 const struct fw_config *probe;
107 bool match = false;
108
109 if (!dev->probe_list)
110 continue;
111
112 for (probe = dev->probe_list; probe && probe->mask != 0; probe++) {
113 if (fw_config_probe(probe)) {
114 match = true;
Tim Wawrzynczak299f3f82020-08-25 16:49:45 -0600115 cached_configs[probe_index(probe->mask)] = probe;
Duncan Laurie36e6c6f2020-05-09 19:20:10 -0700116 break;
117 }
118 }
119
120 if (!match) {
121 printk(BIOS_INFO, "%s disabled by fw_config\n", dev_path(dev));
122 dev->enabled = 0;
123 }
124 }
125}
Nick Vaccaro79943752020-10-02 11:48:17 -0700126BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_ENTRY, fw_config_init, NULL);
Duncan Laurie36e6c6f2020-05-09 19:20:10 -0700127#endif