libpayload: configs: Add new config.featuretest to broaden CI
[coreboot2.git] / src / vendorcode / google / chromeos / sar.c
blobeef3bb3df514cc5226dccf357f818fa1fb79c111
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <cbfs.h>
4 #include <console/console.h>
5 #include <drivers/vpd/vpd.h>
6 #include <fw_config.h>
7 #include <lib.h>
8 #include <sar.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <types.h>
14 #define LEGACY_BYTES_PER_GEO_OFFSET 6
15 #define LEGACY_BYTES_PER_SAR_LIMIT 10
16 #define LEGACY_NUM_SAR_LIMITS 4
17 #define LEGACY_SAR_BIN_SIZE 81
18 #define LEGACY_SAR_WGDS_BIN_SIZE 119
19 #define LEGACY_SAR_NUM_WGDS_GROUPS 3
21 static uint8_t *wifi_hextostr(const char *sar_str, size_t str_len, size_t *sar_bin_len,
22 bool legacy_hex_format)
24 uint8_t *sar_bin = NULL;
25 size_t bin_len;
27 if (!legacy_hex_format) {
28 sar_bin = malloc(str_len);
29 if (!sar_bin) {
30 printk(BIOS_ERR, "Failed to allocate space for SAR binary!\n");
31 return NULL;
34 memcpy(sar_bin, sar_str, str_len);
35 *sar_bin_len = str_len;
36 } else {
37 bin_len = ((str_len - 1) / 2);
38 sar_bin = malloc(bin_len);
39 if (!sar_bin) {
40 printk(BIOS_ERR, "Failed to allocate space for SAR binary!\n");
41 return NULL;
44 if (hexstrtobin(sar_str, (uint8_t *)sar_bin, bin_len) != bin_len) {
45 printk(BIOS_ERR, "sar_limits contains non-hex value!\n");
46 free(sar_bin);
47 return NULL;
50 *sar_bin_len = bin_len;
53 return sar_bin;
56 static size_t sar_table_size(const struct sar_profile *sar)
58 if (sar == NULL)
59 return 0;
61 return (sizeof(struct sar_profile) + ((1 + sar->dsar_set_count) * sar->chains_count *
62 sar->subbands_count));
65 static size_t wgds_table_size(const struct geo_profile *geo)
67 if (geo == NULL)
68 return 0;
70 return sizeof(struct geo_profile) + (geo->chains_count * geo->bands_count);
73 static size_t gain_table_size(const struct gain_profile *gain)
75 if (gain == NULL)
76 return 0;
78 return sizeof(struct gain_profile) + (gain->chains_count * gain->bands_count);
81 static size_t sar_avg_table_size(const struct avg_profile *sar_avg)
83 if (sar_avg == NULL)
84 return 0;
86 return sizeof(struct avg_profile);
89 static size_t dsm_table_size(const struct dsm_profile *dsm)
91 if (dsm == NULL)
92 return 0;
94 return sizeof(struct dsm_profile);
97 static size_t bsar_table_size(const struct bsar_profile *bsar)
99 int revs_offset = offsetof(struct bsar_profile, revs);
101 if (bsar == NULL)
102 return 0;
104 if (bsar->revision == 2)
105 return revs_offset + sizeof(bsar->revs.rev2);
106 return revs_offset + sizeof(bsar->revs.rev1);
109 static size_t wbem_table_size(const struct wbem_profile *wbem)
111 if (wbem == NULL)
112 return 0;
114 return sizeof(struct wbem_profile);
117 static size_t bpag_table_size(const struct bpag_profile *bpag)
119 if (bpag == NULL)
120 return 0;
122 return sizeof(struct bpag_profile);
125 static size_t bbfb_table_size(const struct bbfb_profile *bbfb)
127 if (bbfb == NULL)
128 return 0;
130 return sizeof(struct bbfb_profile);
133 static size_t bdcm_table_size(const struct bdcm_profile *bdcm)
135 if (bdcm == NULL)
136 return 0;
138 return sizeof(struct bdcm_profile);
141 static size_t bbsm_table_size(const struct bbsm_profile *bbsm)
143 if (bbsm == NULL)
144 return 0;
146 return sizeof(struct bbsm_profile);
149 static size_t bucs_table_size(const struct bucs_profile *bucs)
151 if (bucs == NULL)
152 return 0;
154 return sizeof(struct bucs_profile);
157 static size_t bdmm_table_size(const struct bdmm_profile *bdmm)
159 if (bdmm == NULL)
160 return 0;
162 return sizeof(struct bdmm_profile);
165 static size_t ebrd_table_size(const struct ebrd_profile *ebrd)
167 if (ebrd == NULL)
168 return 0;
170 return sizeof(struct ebrd_profile);
173 static size_t wpfc_table_size(const struct wpfc_profile *wpfc)
175 if (wpfc == NULL)
176 return 0;
178 return sizeof(struct wpfc_profile);
181 static size_t dsbr_table_size(const struct dsbr_profile *dsbr)
183 if (dsbr == NULL)
184 return 0;
186 return sizeof(struct dsbr_profile);
189 static bool valid_legacy_length(size_t bin_len)
191 if (bin_len == LEGACY_SAR_WGDS_BIN_SIZE)
192 return true;
194 if (bin_len == LEGACY_SAR_BIN_SIZE && !CONFIG(GEO_SAR_ENABLE))
195 return true;
197 return false;
200 static size_t sar_header_size(void)
202 return (MAX_PROFILE_COUNT * sizeof(uint16_t)) + sizeof(struct sar_header);
205 static int fill_wifi_sar_limits(union wifi_sar_limits *sar_limits, const uint8_t *sar_bin,
206 size_t sar_bin_size)
208 struct sar_header *header;
209 size_t i = 0, expected_sar_bin_size;
210 size_t header_size = sar_header_size();
212 if (sar_bin_size < header_size) {
213 printk(BIOS_ERR, "Invalid SAR format!\n");
214 return -1;
217 header = (struct sar_header *)sar_bin;
219 if (header->version != SAR_FILE_REVISION) {
220 printk(BIOS_ERR, "Invalid SAR file version: %d!\n", header->version);
221 return -1;
224 for (i = 0; i < MAX_PROFILE_COUNT; i++) {
225 if (header->offsets[i] > sar_bin_size) {
226 printk(BIOS_ERR, "Offset is outside the file size!\n");
227 return -1;
230 if (header->offsets[i])
231 sar_limits->profile[i] = (void *) (sar_bin + header->offsets[i]);
234 expected_sar_bin_size = header_size;
235 expected_sar_bin_size += sar_table_size(sar_limits->sar);
236 expected_sar_bin_size += wgds_table_size(sar_limits->wgds);
237 expected_sar_bin_size += gain_table_size(sar_limits->ppag);
238 expected_sar_bin_size += sar_avg_table_size(sar_limits->wtas);
239 expected_sar_bin_size += dsm_table_size(sar_limits->dsm);
240 expected_sar_bin_size += bsar_table_size(sar_limits->bsar);
241 expected_sar_bin_size += wbem_table_size(sar_limits->wbem);
242 expected_sar_bin_size += bpag_table_size(sar_limits->bpag);
243 expected_sar_bin_size += bbfb_table_size(sar_limits->bbfb);
244 expected_sar_bin_size += bdcm_table_size(sar_limits->bdcm);
245 expected_sar_bin_size += bbsm_table_size(sar_limits->bbsm);
246 expected_sar_bin_size += bucs_table_size(sar_limits->bucs);
247 expected_sar_bin_size += bdmm_table_size(sar_limits->bdmm);
248 expected_sar_bin_size += ebrd_table_size(sar_limits->ebrd);
249 expected_sar_bin_size += wpfc_table_size(sar_limits->wpfc);
250 expected_sar_bin_size += dsbr_table_size(sar_limits->dsbr);
252 if (sar_bin_size != expected_sar_bin_size) {
253 printk(BIOS_ERR, "Invalid SAR size, expected: %zu, obtained: %zu\n",
254 expected_sar_bin_size, sar_bin_size);
255 return -1;
258 return 0;
261 static int fill_wifi_sar_limits_legacy(union wifi_sar_limits *sar_limits,
262 const uint8_t *sar_bin, size_t sar_bin_size)
264 uint8_t *new_sar_bin;
265 size_t size = sar_bin_size + sizeof(struct sar_profile);
267 if (CONFIG(GEO_SAR_ENABLE))
268 size += sizeof(struct geo_profile);
270 new_sar_bin = malloc(size);
271 if (!new_sar_bin) {
272 printk(BIOS_ERR, "Failed to allocate space for SAR binary!\n");
273 return -1;
276 sar_limits->sar = (struct sar_profile *) new_sar_bin;
277 sar_limits->sar->revision = 0;
278 sar_limits->sar->dsar_set_count = CONFIG_DSAR_SET_NUM;
279 sar_limits->sar->chains_count = SAR_REV0_CHAINS_COUNT;
280 sar_limits->sar->subbands_count = SAR_REV0_SUBBANDS_COUNT;
281 memcpy(&sar_limits->sar->sar_table, sar_bin,
282 LEGACY_BYTES_PER_SAR_LIMIT * LEGACY_NUM_SAR_LIMITS);
284 if (!CONFIG(GEO_SAR_ENABLE))
285 return 0;
287 sar_limits->wgds = (struct geo_profile *)(new_sar_bin +
288 sar_table_size(sar_limits->sar));
289 sar_limits->wgds->revision = 0;
290 sar_limits->wgds->chains_count = LEGACY_SAR_NUM_WGDS_GROUPS;
291 sar_limits->wgds->bands_count = LEGACY_BYTES_PER_GEO_OFFSET;
292 memcpy(&sar_limits->wgds->wgds_table,
293 sar_bin + LEGACY_BYTES_PER_SAR_LIMIT * LEGACY_NUM_SAR_LIMITS + REVISION_SIZE,
294 LEGACY_BYTES_PER_GEO_OFFSET * LEGACY_SAR_NUM_WGDS_GROUPS);
296 return 0;
300 * Retrieve WiFi SAR limits data from CBFS and decode it
301 * Legacy WiFi SAR data is expected in the format: [<WRDD><EWRD>][WGDS]
303 * [<WRDD><EWRD>] = NUM_SAR_LIMITS * BYTES_PER_SAR_LIMIT bytes.
304 * [WGDS]=[WGDS_REVISION][WGDS_DATA]
306 * Current SAR configuration data is expected in the format:
307 * "$SAR" Marker
308 * Version
309 * Offset count
310 * Offsets
311 * [SAR_REVISION,DSAR_SET_COUNT,CHAINS_COUNT,SUBBANDS_COUNT <WRDD>[EWRD]]
312 * [WGDS_REVISION,CHAINS_COUNT,SUBBANDS_COUNT<WGDS_DATA>]
313 * [PPAG_REVISION,MODE,CHAINS_COUNT,SUBBANDS_COUNT<PPAG_DATA>]
314 * [WTAS_REVISION, WTAS_DATA]
315 * [DSM_RETURN_VALUES]
316 * [BSAR_REVISION,IPML,LB,BR,EDR2,EDR3,LE,LE2,LE_LR]
317 * [WBEM_REVISION, WBEM_DATA]
319 * The configuration data will always have the revision added in the file for each of the
320 * block, based on the revision number and validity, size of the specific block will be
321 * calculated.
323 * [WGDS_DATA] = [GROUP#0][GROUP#1][GROUP#2]
325 * [GROUP#<i>] =
326 * Supported by Revision 0, 1 and 2
327 * [2.4Ghz - Max Allowed][2.4Ghz - Chain A Offset][2.4Ghz - Chain B Offset]
328 * [5Ghz - Max Allowed][5Ghz - Chain A Offset][5Ghz - Chain B Offset]
329 * Supported by Revision 1 and 2
330 * [6Ghz - Max Allowed][6Ghz - Chain A Offset][6Ghz - Chain B Offset]
332 * [GROUP#0] is for FCC
333 * [GROUP#1] is for Europe/Japan
334 * [GROUP#2] is for ROW
336 * [PPAG_DATA] = [ANT_gain Table Chain A] [ANT_gain Table Chain A]
338 * [ANT_gain Table] =
339 * Supported by Revision 0, 1 and 2
340 * [Antenna gain used for 2400MHz frequency]
341 * [Antenna gain used for 5150-5350MHz frequency]
342 * [Antenna gain used for 5350-5470MHz frequency]
343 * [Antenna gain used for 5470-5725MHz frequency]
344 * [Antenna gain used for 5725-5945MHz frequency]
345 * Supported by Revision 1 and 2
346 * [Antenna gain used for 5945-6165MHz frequency]
347 * [Antenna gain used for 6165-6405MHz frequency]
348 * [Antenna gain used for 6405-6525MHz frequency]
349 * [Antenna gain used for 6525-6705MHz frequency]
350 * [Antenna gain used for 6705-6865MHz frequency]
351 * [Antenna gain used for 6865-7105MHz frequency]
353 * [WTAS_DATA] =
354 * [Enable/disable the TAS feature]
355 * [Number of blocked countries that are not approved by the OEM to support this feature]
356 * [deny_list_entry_<1-16>: ISO country code to block]
357 * [WBEM_DATA] =
358 * [Enable or disable 320MHZ Bandwidth for Japan, SouthKorea]
360 int get_wifi_sar_limits(union wifi_sar_limits *sar_limits)
362 const char *filename;
363 size_t sar_bin_len, sar_str_len;
364 uint8_t *sar_bin;
365 char *sar_str;
366 int ret = -1;
367 bool legacy_hex_format = false;
369 filename = get_wifi_sar_cbfs_filename();
370 if (filename == NULL) {
371 printk(BIOS_ERR, "Filename missing for CBFS SAR file!\n");
372 return ret;
375 sar_str = cbfs_map(filename, &sar_str_len);
376 if (!sar_str) {
377 printk(BIOS_ERR, "Failed to get the %s file size!\n", filename);
378 return ret;
381 if (strncmp(sar_str, SAR_STR_PREFIX, SAR_STR_PREFIX_SIZE) == 0) {
382 legacy_hex_format = false;
383 } else if (valid_legacy_length(sar_str_len)) {
384 legacy_hex_format = true;
385 } else {
386 printk(BIOS_ERR, "Invalid SAR format!\n");
387 goto error;
390 sar_bin = wifi_hextostr(sar_str, sar_str_len, &sar_bin_len, legacy_hex_format);
391 if (sar_bin == NULL) {
392 printk(BIOS_ERR, "Failed to parse SAR file %s\n", filename);
393 goto error;
396 memset(sar_limits, 0, sizeof(*sar_limits));
397 if (legacy_hex_format) {
398 ret = fill_wifi_sar_limits_legacy(sar_limits, sar_bin, sar_bin_len);
399 free(sar_bin);
400 } else {
401 ret = fill_wifi_sar_limits(sar_limits, sar_bin, sar_bin_len);
402 if (ret < 0)
403 free(sar_bin);
406 error:
407 cbfs_unmap(sar_str);
408 return ret;
411 __weak
412 const char *get_wifi_sar_cbfs_filename(void)
414 return WIFI_SAR_CBFS_DEFAULT_FILENAME;
417 char *get_wifi_sar_fw_config_filename(const struct fw_config_field *field)
419 uint64_t sar_id = fw_config_get_field(field);
420 if (sar_id == UNDEFINED_FW_CONFIG) {
421 printk(BIOS_WARNING, "fw_config unprovisioned, set sar filename to NULL\n");
422 return NULL;
424 static char filename[20];
425 printk(BIOS_INFO, "Use wifi_sar_%lld.hex.\n", sar_id);
426 if (snprintf(filename, sizeof(filename), "wifi_sar_%lld.hex", sar_id) < 0) {
427 printk(BIOS_ERR, "Error occurred with snprintf, set sar filename to NULL\n");
428 return NULL;
430 return filename;