1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <console/console.h>
5 #include <drivers/vpd/vpd.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
;
27 if (!legacy_hex_format
) {
28 sar_bin
= malloc(str_len
);
30 printk(BIOS_ERR
, "Failed to allocate space for SAR binary!\n");
34 memcpy(sar_bin
, sar_str
, str_len
);
35 *sar_bin_len
= str_len
;
37 bin_len
= ((str_len
- 1) / 2);
38 sar_bin
= malloc(bin_len
);
40 printk(BIOS_ERR
, "Failed to allocate space for SAR binary!\n");
44 if (hexstrtobin(sar_str
, (uint8_t *)sar_bin
, bin_len
) != bin_len
) {
45 printk(BIOS_ERR
, "sar_limits contains non-hex value!\n");
50 *sar_bin_len
= bin_len
;
56 static size_t sar_table_size(const struct sar_profile
*sar
)
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
)
70 return sizeof(struct geo_profile
) + (geo
->chains_count
* geo
->bands_count
);
73 static size_t gain_table_size(const struct gain_profile
*gain
)
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
)
86 return sizeof(struct avg_profile
);
89 static size_t dsm_table_size(const struct dsm_profile
*dsm
)
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
);
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
)
114 return sizeof(struct wbem_profile
);
117 static size_t bpag_table_size(const struct bpag_profile
*bpag
)
122 return sizeof(struct bpag_profile
);
125 static size_t bbfb_table_size(const struct bbfb_profile
*bbfb
)
130 return sizeof(struct bbfb_profile
);
133 static size_t bdcm_table_size(const struct bdcm_profile
*bdcm
)
138 return sizeof(struct bdcm_profile
);
141 static size_t bbsm_table_size(const struct bbsm_profile
*bbsm
)
146 return sizeof(struct bbsm_profile
);
149 static size_t bucs_table_size(const struct bucs_profile
*bucs
)
154 return sizeof(struct bucs_profile
);
157 static size_t bdmm_table_size(const struct bdmm_profile
*bdmm
)
162 return sizeof(struct bdmm_profile
);
165 static size_t ebrd_table_size(const struct ebrd_profile
*ebrd
)
170 return sizeof(struct ebrd_profile
);
173 static size_t wpfc_table_size(const struct wpfc_profile
*wpfc
)
178 return sizeof(struct wpfc_profile
);
181 static size_t dsbr_table_size(const struct dsbr_profile
*dsbr
)
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
)
194 if (bin_len
== LEGACY_SAR_BIN_SIZE
&& !CONFIG(GEO_SAR_ENABLE
))
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
,
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");
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
);
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");
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
);
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
);
272 printk(BIOS_ERR
, "Failed to allocate space for SAR binary!\n");
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
))
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
);
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:
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
323 * [WGDS_DATA] = [GROUP#0][GROUP#1][GROUP#2]
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]
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]
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]
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
;
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");
375 sar_str
= cbfs_map(filename
, &sar_str_len
);
377 printk(BIOS_ERR
, "Failed to get the %s file size!\n", filename
);
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;
386 printk(BIOS_ERR
, "Invalid SAR format!\n");
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
);
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
);
401 ret
= fill_wifi_sar_limits(sar_limits
, sar_bin
, sar_bin_len
);
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");
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");