blob: 895958860bb3fce063d3b9e79cc53d6b81d18979 [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>
Patrick Rudolph28cee592018-03-08 15:43:12 +01005#include <drivers/vpd/vpd.h>
Furquan Shaikheb876a52021-03-13 12:35:20 -08006#include <lib.h>
7#include <sar.h>
8#include <stdlib.h>
9#include <string.h>
10#include <types.h>
Robbie Zhanged840022016-12-23 11:43:07 -080011
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053012#define LEGACY_BYTES_PER_GEO_OFFSET 6
13#define LEGACY_BYTES_PER_SAR_LIMIT 10
14#define LEGACY_NUM_SAR_LIMITS 4
15#define LEGACY_SAR_BIN_SIZE 81
16#define LEGACY_SAR_WGDS_BIN_SIZE 119
17#define LEGACY_SAR_NUM_WGDS_GROUPS 3
18
19static uint8_t *wifi_hextostr(const char *sar_str, size_t str_len, size_t *sar_bin_len,
20 bool legacy_hex_format)
21{
22 uint8_t *sar_bin = NULL;
23 size_t bin_len;
24
25 if (!legacy_hex_format) {
26 sar_bin = malloc(str_len);
27 if (!sar_bin) {
28 printk(BIOS_ERR, "ERROR: Failed to allocate space for SAR binary!\n");
29 return NULL;
30 }
31
32 memcpy(sar_bin, sar_str, str_len);
33 *sar_bin_len = str_len;
34 } else {
35 bin_len = ((str_len - 1) / 2);
36 sar_bin = malloc(bin_len);
37 if (!sar_bin) {
38 printk(BIOS_ERR, "ERROR: Failed to allocate space for SAR binary!\n");
39 return NULL;
40 }
41
42 if (hexstrtobin(sar_str, (uint8_t *)sar_bin, bin_len) != bin_len) {
43 printk(BIOS_ERR, "ERROR: sar_limits contains non-hex value!\n");
44 free(sar_bin);
45 return NULL;
46 }
47
48 *sar_bin_len = bin_len;
49 }
50
51 return sar_bin;
52}
53
54static int sar_table_size(const struct sar_profile *sar)
55{
56 if (sar == NULL)
57 return 0;
58
59 return (sizeof(struct sar_profile) + ((1 + sar->dsar_set_count) * sar->chains_count *
60 sar->subbands_count));
61}
62
63static int wgds_table_size(const struct geo_profile *geo)
64{
65 if (geo == NULL)
66 return 0;
67
68 return sizeof(struct geo_profile) + (geo->chains_count * geo->bands_count);
69}
70
Sugnan Prabhu Sd1fc8322021-08-31 07:11:35 +053071static int gain_table_size(const struct gain_profile *gain)
72{
73 if (gain == NULL)
74 return 0;
75
76 return sizeof(struct gain_profile) + (gain->chains_count * gain->bands_count);
77}
78
Sugnan Prabhu Scc507702021-08-31 07:19:30 +053079static int sar_avg_table_size(const struct avg_profile *sar_avg)
80{
81 if (sar_avg == NULL)
82 return 0;
83
84 return sizeof(struct avg_profile);
85}
86
Sugnan Prabhu Sd70f4812021-08-25 17:36:44 +053087static int dsm_table_size(const struct dsm_profile *dsm)
88{
89 if (dsm == NULL)
90 return 0;
91
92 return sizeof(struct dsm_profile);
93}
94
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053095static bool valid_legacy_length(size_t bin_len)
96{
97 if (bin_len == LEGACY_SAR_WGDS_BIN_SIZE)
98 return true;
99
100 if (bin_len == LEGACY_SAR_BIN_SIZE && !CONFIG(GEO_SAR_ENABLE))
101 return true;
102
103 return false;
104}
105
106static int sar_header_size(void)
107{
108 return (MAX_PROFILE_COUNT * sizeof(uint16_t)) + sizeof(struct sar_header);
109}
110
111static int fill_wifi_sar_limits(union wifi_sar_limits *sar_limits, const uint8_t *sar_bin,
112 size_t sar_bin_size)
113{
114 struct sar_header *header;
115 size_t i = 0, expected_sar_bin_size;
116 size_t header_size = sar_header_size();
117
118 if (sar_bin_size < header_size) {
119 printk(BIOS_ERR, "ERROR: Invalid SAR format!\n");
120 return -1;
121 }
122
123 header = (struct sar_header *)sar_bin;
124
125 if (header->version != SAR_FILE_REVISION) {
126 printk(BIOS_ERR, "ERROR: Invalid SAR file version: %d!\n", header->version);
127 return -1;
128 }
129
130 for (i = 0; i < MAX_PROFILE_COUNT; i++) {
131 if (header->offsets[i] > sar_bin_size) {
132 printk(BIOS_ERR, "ERROR: Offset is outside the file size!\n");
133 return -1;
134 }
135
136 if (header->offsets[i])
137 sar_limits->profile[i] = (void *) (sar_bin + header->offsets[i]);
138 }
139
140 expected_sar_bin_size = header_size;
141 expected_sar_bin_size += sar_table_size(sar_limits->sar);
142 expected_sar_bin_size += wgds_table_size(sar_limits->wgds);
Sugnan Prabhu Sd1fc8322021-08-31 07:11:35 +0530143 expected_sar_bin_size += gain_table_size(sar_limits->ppag);
Sugnan Prabhu Scc507702021-08-31 07:19:30 +0530144 expected_sar_bin_size += sar_avg_table_size(sar_limits->wtas);
Sugnan Prabhu Sd70f4812021-08-25 17:36:44 +0530145 expected_sar_bin_size += dsm_table_size(sar_limits->dsm);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530146
147 if (sar_bin_size != expected_sar_bin_size) {
148 printk(BIOS_ERR, "ERROR: Invalid SAR size, expected: %ld, obtained: %ld\n",
149 expected_sar_bin_size, sar_bin_size);
150 return -1;
151 }
152
153 return 0;
154}
155
156static int fill_wifi_sar_limits_legacy(union wifi_sar_limits *sar_limits,
157 const uint8_t *sar_bin, size_t sar_bin_size)
158{
159 uint8_t *new_sar_bin;
160 size_t size = sar_bin_size + sizeof(struct sar_profile);
161
162 if (CONFIG(GEO_SAR_ENABLE))
163 size += sizeof(struct geo_profile);
164
165 new_sar_bin = malloc(size);
166 if (!new_sar_bin) {
167 printk(BIOS_ERR, "ERROR: Failed to allocate space for SAR binary!\n");
168 return -1;
169 }
170
171 sar_limits->sar = (struct sar_profile *) new_sar_bin;
172 sar_limits->sar->revision = 0;
173 sar_limits->sar->dsar_set_count = CONFIG_DSAR_SET_NUM;
174 sar_limits->sar->chains_count = SAR_REV0_CHAINS_COUNT;
175 sar_limits->sar->subbands_count = SAR_REV0_SUBBANDS_COUNT;
176 memcpy(&sar_limits->sar->sar_table, sar_bin,
177 LEGACY_BYTES_PER_SAR_LIMIT * LEGACY_NUM_SAR_LIMITS);
178
179 if (!CONFIG(GEO_SAR_ENABLE))
180 return 0;
181
182 sar_limits->wgds = (struct geo_profile *)(new_sar_bin +
183 sar_table_size(sar_limits->sar));
184 sar_limits->wgds->revision = 0;
185 sar_limits->wgds->chains_count = LEGACY_SAR_NUM_WGDS_GROUPS;
186 sar_limits->wgds->bands_count = LEGACY_BYTES_PER_GEO_OFFSET;
187 memcpy(&sar_limits->wgds->wgds_table,
188 sar_bin + LEGACY_BYTES_PER_SAR_LIMIT * LEGACY_NUM_SAR_LIMITS + REVISION_SIZE,
189 LEGACY_BYTES_PER_GEO_OFFSET * LEGACY_SAR_NUM_WGDS_GROUPS);
190
191 return 0;
192}
193
Furquan Shaikheb876a52021-03-13 12:35:20 -0800194/*
195 * Retrieve WiFi SAR limits data from CBFS and decode it
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530196 * Legacy WiFi SAR data is expected in the format: [<WRDD><EWRD>][WGDS]
Furquan Shaikheb876a52021-03-13 12:35:20 -0800197 *
198 * [<WRDD><EWRD>] = NUM_SAR_LIMITS * BYTES_PER_SAR_LIMIT bytes.
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530199 * [WGDS]=[WGDS_REVISION][WGDS_DATA]
Furquan Shaikheb876a52021-03-13 12:35:20 -0800200 *
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530201 * Current SAR configuration data is expected in the format:
202 * "$SAR" Marker
203 * Version
204 * Offset count
205 * Offsets
206 * [SAR_REVISION,DSAR_SET_COUNT,CHAINS_COUNT,SUBBANDS_COUNT <WRDD>[EWRD]]
207 * [WGDS_REVISION,CHAINS_COUNT,SUBBANDS_COUNT<WGDS_DATA>]
Sugnan Prabhu Sd1fc8322021-08-31 07:11:35 +0530208 * [PPAG_REVISION,MODE,CHAINS_COUNT,SUBBANDS_COUNT<PPAG_DATA>]
Sugnan Prabhu Scc507702021-08-31 07:19:30 +0530209 * [WTAS_REVISION, WTAS_DATA]
Sugnan Prabhu Sd70f4812021-08-25 17:36:44 +0530210 * [DSM_RETURN_VALUES]
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530211 *
212 * The configuration data will always have the revision added in the file for each of the
213 * block, based on the revision number and validity, size of the specific block will be
214 * calculated.
215 *
Furquan Shaikheb876a52021-03-13 12:35:20 -0800216 * [WGDS_DATA] = [GROUP#0][GROUP#1][GROUP#2]
217 *
218 * [GROUP#<i>] =
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530219 * Supported by Revision 0, 1 and 2
220 * [2.4Ghz - Max Allowed][2.4Ghz - Chain A Offset][2.4Ghz - Chain B Offset]
221 * [5Ghz - Max Allowed][5Ghz - Chain A Offset][5Ghz - Chain B Offset]
222 * Supported by Revision 1 and 2
223 * [6Ghz - Max Allowed][6Ghz - Chain A Offset][6Ghz - Chain B Offset]
Furquan Shaikheb876a52021-03-13 12:35:20 -0800224 *
225 * [GROUP#0] is for FCC
226 * [GROUP#1] is for Europe/Japan
227 * [GROUP#2] is for ROW
Sugnan Prabhu Sd1fc8322021-08-31 07:11:35 +0530228 *
229 * [PPAG_DATA] = [ANT_gain Table Chain A] [ANT_gain Table Chain A]
230 *
231 * [ANT_gain Table] =
232 * Supported by Revision 0, 1 and 2
233 * [Antenna gain used for 2400MHz frequency]
234 * [Antenna gain used for 5150-5350MHz frequency]
235 * [Antenna gain used for 5350-5470MHz frequency]
236 * [Antenna gain used for 5470-5725MHz frequency]
237 * [Antenna gain used for 5725-5945MHz frequency]
238 * Supported by Revision 1 and 2
239 * [Antenna gain used for 5945-6165MHz frequency]
240 * [Antenna gain used for 6165-6405MHz frequency]
241 * [Antenna gain used for 6405-6525MHz frequency]
242 * [Antenna gain used for 6525-6705MHz frequency]
243 * [Antenna gain used for 6705-6865MHz frequency]
244 * [Antenna gain used for 6865-7105MHz frequency]
Sugnan Prabhu Scc507702021-08-31 07:19:30 +0530245 *
246 * [WTAS_DATA] =
247 * [Enable/disable the TAS feature]
248 * [Number of blocked countries that are not approved by the OEM to support this feature]
249 * [deny_list_entry_<1-16>: ISO country code to block]
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530250 */
251int get_wifi_sar_limits(union wifi_sar_limits *sar_limits)
Robbie Zhanged840022016-12-23 11:43:07 -0800252{
Furquan Shaikheb876a52021-03-13 12:35:20 -0800253 const char *filename;
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530254 size_t sar_bin_len, sar_str_len;
255 uint8_t *sar_bin;
Furquan Shaikheb876a52021-03-13 12:35:20 -0800256 char *sar_str;
257 int ret = -1;
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530258 bool legacy_hex_format = false;
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700259
Furquan Shaikh7fe5d3d2021-03-13 22:54:16 -0800260 filename = get_wifi_sar_cbfs_filename();
261 if (filename == NULL) {
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530262 printk(BIOS_ERR, "ERROR: Filename missing for CBFS SAR file!\n");
Furquan Shaikh7fe5d3d2021-03-13 22:54:16 -0800263 return ret;
264 }
265
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530266 sar_str = cbfs_map(filename, &sar_str_len);
Furquan Shaikheb876a52021-03-13 12:35:20 -0800267 if (!sar_str) {
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530268 printk(BIOS_ERR, "ERROR: Failed to get the %s file size!\n", filename);
Furquan Shaikheb876a52021-03-13 12:35:20 -0800269 return ret;
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700270 }
Robbie Zhanged840022016-12-23 11:43:07 -0800271
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530272 if (strncmp(sar_str, SAR_STR_PREFIX, SAR_STR_PREFIX_SIZE) == 0) {
273 legacy_hex_format = false;
274 } else if (valid_legacy_length(sar_str_len)) {
275 legacy_hex_format = true;
276 } else {
277 printk(BIOS_ERR, "ERROR: Invalid SAR format!\n");
278 goto error;
279 }
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700280
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530281 sar_bin = wifi_hextostr(sar_str, sar_str_len, &sar_bin_len, legacy_hex_format);
282 if (sar_bin == NULL) {
283 printk(BIOS_ERR, "ERROR: Failed to parse SAR file %s\n", filename);
284 goto error;
Robbie Zhanged840022016-12-23 11:43:07 -0800285 }
286
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700287 memset(sar_limits, 0, sizeof(*sar_limits));
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530288 if (legacy_hex_format) {
289 ret = fill_wifi_sar_limits_legacy(sar_limits, sar_bin, sar_bin_len);
290 free(sar_bin);
291 } else {
292 ret = fill_wifi_sar_limits(sar_limits, sar_bin, sar_bin_len);
293 if (ret < 0)
294 free(sar_bin);
Furquan Shaikheb876a52021-03-13 12:35:20 -0800295 }
296
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530297error:
298 cbfs_unmap(sar_str);
Furquan Shaikheb876a52021-03-13 12:35:20 -0800299 return ret;
Robbie Zhanged840022016-12-23 11:43:07 -0800300}
Justin TerAvestc650d6c2018-12-14 11:05:03 -0700301
302__weak
303const char *get_wifi_sar_cbfs_filename(void)
304{
Furquan Shaikh7fe5d3d2021-03-13 22:54:16 -0800305 return WIFI_SAR_CBFS_DEFAULT_FILENAME;
Justin TerAvestc650d6c2018-12-14 11:05:03 -0700306}