blob: 8b31e8125e5c3a7471199465c5aec5c67bd5b393 [file] [log] [blame]
Angel Pons3ef916f2020-04-02 23:49:13 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -07002
3#include <cbfs.h>
Robbie Zhanged840022016-12-23 11:43:07 -08004#include <console/console.h>
Robbie Zhangfeb4ef62017-01-09 15:28:24 -08005#include <lib.h>
Robbie Zhanged840022016-12-23 11:43:07 -08006#include <types.h>
7#include <string.h>
8#include <sar.h>
Patrick Rudolph28cee592018-03-08 15:43:12 +01009#include <drivers/vpd/vpd.h>
Robbie Zhanged840022016-12-23 11:43:07 -080010
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070011#define WIFI_SAR_CBFS_FILENAME "wifi_sar_defaults.hex"
Patrick Rudolph28cee592018-03-08 15:43:12 +010012#define CROS_VPD_WIFI_SAR_NAME "wifi_sar"
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070013
14static int load_sar_file_from_cbfs(void *buf, size_t buffer_size)
15{
Justin TerAvestc650d6c2018-12-14 11:05:03 -070016 const char *filename = get_wifi_sar_cbfs_filename();
17 if (filename == NULL)
18 filename = WIFI_SAR_CBFS_FILENAME;
Julius Werner834b3ec2020-03-04 16:52:08 -080019 return cbfs_load(filename, buf, buffer_size);
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070020}
21
22/* Retrieve the wifi SAR limits data from VPD and decode it
23
24For VPD: key,value pair is in this format
25"wifi_sar"=[<WRDD><EWRD>][WGDS]
26
27WIFI SAR data in CBFS file is expected in same format: [<WRDD><EWRD>][WGDS]
28
29[<WRDD><EWRD>] = NUM_SAR_LIMITS * BYTES_PER_SAR_LIMIT bytes.
30[WGDS]=[WGDS_VERSION][WGDS_DATA]
31
32For [WGDS_VERSION] 0x00,
33[WGDS_DATA] = [GROUP#0][GROUP#1][GROUP#2]
34
35[GROUP#<i>] =
36 [2.4Ghz – Max Allowed][2.4Ghz – Chain A Offset]
37 [2.4Ghz – Chain B Offset][5Ghz – Max Allowed]
38 [5Ghz – Chain A Offset][5Ghz – Chain B Offset]
39
40[GROUP#0] is for FCC
41[GROUP#1] is for Europe/Japan
42[GROUP#2] is for ROW
43
44*/
Robbie Zhanged840022016-12-23 11:43:07 -080045int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
46{
47 const char *wifi_sar_limit_key = CROS_VPD_WIFI_SAR_NAME;
Patrick Rudolph28cee592018-03-08 15:43:12 +010048 /* vpd_gets() reads in one less than size characters from the VPD
Robbie Zhanged840022016-12-23 11:43:07 -080049 * with a terminating null byte ('\0') stored as the last character into
Jacob Garber9172b692019-06-26 16:18:16 -060050 * the buffer, thus the increasing by 1 for the buffer size. */
51 char wifi_sar_limit_str[2 * sizeof(struct wifi_sar_limits) + 1];
Robbie Zhanged840022016-12-23 11:43:07 -080052 uint8_t bin_buffer[sizeof(struct wifi_sar_limits)];
Jacob Garber9172b692019-06-26 16:18:16 -060053 const size_t buffer_size = ARRAY_SIZE(wifi_sar_limit_str);
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070054 size_t sar_cbfs_len, sar_expected_len, bin_buff_adjusted_size;
55
56 /* keep it backward compatible. Some older platform are shipping
57 without GEO SAR and so older wifi_sar VPD key */
58
59 sar_expected_len = buffer_size;
60 bin_buff_adjusted_size = sizeof(struct wifi_sar_limits);
61
Julius Wernercd49cce2019-03-05 16:53:33 -080062 if (!CONFIG(GEO_SAR_ENABLE)) {
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070063 sar_expected_len = buffer_size -
64 sizeof(struct wifi_sar_delta_table) *
65 sizeof(uint8_t) * 2;
66 bin_buff_adjusted_size = sizeof(struct wifi_sar_limits) -
67 sizeof(struct wifi_sar_delta_table);
68 }
Robbie Zhanged840022016-12-23 11:43:07 -080069
70 /* Try to read the SAR limit entry from VPD */
Patrick Rudolph28cee592018-03-08 15:43:12 +010071 if (!vpd_gets(wifi_sar_limit_key, wifi_sar_limit_str,
Jonathan Zhanga9117ed2020-05-28 11:02:13 -070072 buffer_size, VPD_RO_THEN_RW)) {
Maulik V Vaghela0fd62f52020-11-11 12:44:28 +053073 printk(BIOS_DEBUG, "Could not locate '%s' in VPD.\n",
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070074 wifi_sar_limit_key);
75
Julius Wernercd49cce2019-03-05 16:53:33 -080076 if (!CONFIG(WIFI_SAR_CBFS))
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070077 return -1;
78
79 printk(BIOS_DEBUG, "Checking CBFS for default SAR values\n");
80
81 sar_cbfs_len = load_sar_file_from_cbfs(
82 (void *) wifi_sar_limit_str,
83 sar_expected_len);
84
85 if (sar_cbfs_len != sar_expected_len) {
86 printk(BIOS_ERR, "%s has bad len in CBFS\n",
87 WIFI_SAR_CBFS_FILENAME);
88 return -1;
89 }
90 } else {
91 /* VPD key "wifi_sar" found. strlen is checked with addition of
92 * 1 as we have created buffer size 1 char larger for the reason
93 * mentioned at start of this function itself */
94 if (strlen(wifi_sar_limit_str) + 1 != sar_expected_len) {
95 printk(BIOS_ERR, "WIFI SAR key has bad len in VPD\n");
96 return -1;
97 }
Robbie Zhanged840022016-12-23 11:43:07 -080098 }
Robbie Zhanged840022016-12-23 11:43:07 -080099
100 /* Decode the heximal encoded string to binary values */
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700101 if (hexstrtobin(wifi_sar_limit_str, bin_buffer, bin_buff_adjusted_size)
102 < bin_buff_adjusted_size) {
103 printk(BIOS_ERR, "Error: wifi_sar contains non-hex value!\n");
Robbie Zhanged840022016-12-23 11:43:07 -0800104 return -1;
105 }
106
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700107 memset(sar_limits, 0, sizeof(*sar_limits));
108 memcpy(sar_limits, bin_buffer, bin_buff_adjusted_size);
Robbie Zhanged840022016-12-23 11:43:07 -0800109 return 0;
110}
Justin TerAvestc650d6c2018-12-14 11:05:03 -0700111
112__weak
113const char *get_wifi_sar_cbfs_filename(void)
114{
Kevin Chiucc69f7b2020-08-21 20:56:04 +0800115 return WIFI_SAR_CBFS_FILENAME;
Justin TerAvestc650d6c2018-12-14 11:05:03 -0700116}