blob: 5636abca6892c13649c3c1c3a745e8780394737e [file] [log] [blame]
Furquan Shaikh2736c822020-10-27 19:46:11 -07001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <acpi/acpi_device.h>
4#include <acpi/acpigen.h>
Tim Wawrzynczakd40a4c22021-02-25 13:14:49 -07005#include <acpi/acpigen_pci.h>
Furquan Shaikh2736c822020-10-27 19:46:11 -07006#include <console/console.h>
7#include <device/pci_ids.h>
8#include <sar.h>
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +05309#include <stdlib.h>
Furquan Shaikh2736c822020-10-27 19:46:11 -070010#include <wrdd.h>
11
12#include "chip.h"
13#include "wifi_private.h"
14
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053015/* WIFI Domain type */
16#define DOMAIN_TYPE_WIFI 0x7
Furquan Shaikh2736c822020-10-27 19:46:11 -070017
18/*
19 * WIFI ACPI NAME = "WF" + hex value of last 8 bits of dev_path_encode + '\0'
20 * The above representation returns unique and consistent name every time
21 * generate_wifi_acpi_name is invoked. The last 8 bits of dev_path_encode is
22 * chosen since it contains the bus address of the device.
23 */
24#define WIFI_ACPI_NAME_MAX_LEN 5
25
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053026__weak int get_wifi_sar_limits(union wifi_sar_limits *sar_limits)
Furquan Shaikh2736c822020-10-27 19:46:11 -070027{
28 return -1;
29}
30
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053031static const uint8_t *sar_fetch_set(const struct sar_profile *sar, size_t set_num)
Furquan Shaikh2736c822020-10-27 19:46:11 -070032{
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053033 const uint8_t *sar_table = &sar->sar_table[0];
Furquan Shaikh2736c822020-10-27 19:46:11 -070034
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053035 return sar_table + (sar->chains_count * sar->subbands_count * set_num);
36}
Furquan Shaikh2736c822020-10-27 19:46:11 -070037
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053038static const uint8_t *wgds_fetch_set(struct geo_profile *wgds, size_t set_num)
39{
40 const uint8_t *wgds_table = &wgds->wgds_table[0];
41
42 return wgds_table + (wgds->bands_count * set_num);
43}
44
Sugnan Prabhu Sd1fc8322021-08-31 07:11:35 +053045static const uint8_t *ppag_fetch_set(struct gain_profile *ppag, size_t set_num)
46{
47 const uint8_t *ppag_table = &ppag->ppag_table[0];
48
49 return ppag_table + (ppag->bands_count * set_num);
50}
51
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053052static void sar_emit_wrds(const struct sar_profile *sar)
53{
54 int i;
55 size_t package_size, table_size;
56 const uint8_t *set;
57
58 if (sar == NULL)
Furquan Shaikh2736c822020-10-27 19:46:11 -070059 return;
Furquan Shaikh2736c822020-10-27 19:46:11 -070060
61 /*
62 * Name ("WRDS", Package () {
63 * Revision,
64 * Package () {
65 * Domain Type, // 0x7:WiFi
66 * WiFi SAR BIOS, // BIOS SAR Enable/disable
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053067 * SAR Table Set // Set#1 of SAR Table
Furquan Shaikh2736c822020-10-27 19:46:11 -070068 * }
69 * })
70 */
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053071 if (sar->revision > MAX_SAR_REVISION) {
72 printk(BIOS_ERR, "ERROR: Invalid SAR table revision: %d\n", sar->revision);
73 return;
74 }
75
Furquan Shaikh2736c822020-10-27 19:46:11 -070076 acpigen_write_name("WRDS");
77 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053078 acpigen_write_dword(sar->revision);
79
80 table_size = sar->chains_count * sar->subbands_count;
81 /* Emit 'Domain Type' + 'WiFi SAR Enable' + Set#1 */
82 package_size = 1 + 1 + table_size;
Furquan Shaikh2736c822020-10-27 19:46:11 -070083 acpigen_write_package(package_size);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053084 acpigen_write_dword(DOMAIN_TYPE_WIFI);
85 acpigen_write_dword(1);
86
87 set = sar_fetch_set(sar, 0);
88 for (i = 0; i < table_size; i++)
89 acpigen_write_byte(set[i]);
90
91 acpigen_write_package_end();
92 acpigen_write_package_end();
93}
94
95static void sar_emit_ewrd(const struct sar_profile *sar)
96{
97 int i;
98 size_t package_size, set_num, table_size;
99 const uint8_t *set;
100
101 if (sar == NULL)
102 return;
Furquan Shaikh2736c822020-10-27 19:46:11 -0700103
104 /*
105 * Name ("EWRD", Package () {
106 * Revision,
107 * Package () {
108 * Domain Type, // 0x7:WiFi
109 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
110 * Extended SAR sets, // Number of optional SAR table sets
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530111 * SAR Table Set, // Set#2 of SAR Table
112 * SAR Table Set, // Set#3 of SAR Table
113 * SAR Table Set // Set#4 of SAR Table
Furquan Shaikh2736c822020-10-27 19:46:11 -0700114 * }
115 * })
116 */
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530117 if (sar->revision > MAX_SAR_REVISION) {
118 printk(BIOS_ERR, "ERROR: Invalid SAR table revision: %d\n", sar->revision);
119 return;
120 }
121
122 if (sar->dsar_set_count == 0) {
123 printk(BIOS_WARNING, "WARNING: DSAR set count is 0\n");
124 return;
125 }
126
Furquan Shaikh2736c822020-10-27 19:46:11 -0700127 acpigen_write_name("EWRD");
128 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530129 acpigen_write_dword(sar->revision);
130
131 table_size = sar->chains_count * sar->subbands_count;
Furquan Shaikh2736c822020-10-27 19:46:11 -0700132 /*
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530133 * Emit 'Domain Type' + 'Dynamic SAR Enable' + 'Extended SAR sets count'
Furquan Shaikh2736c822020-10-27 19:46:11 -0700134 * + number of bytes for Set#2 & 3 & 4
135 */
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530136 package_size = 1 + 1 + 1 + table_size * sar->dsar_set_count;
Furquan Shaikh2736c822020-10-27 19:46:11 -0700137 acpigen_write_package(package_size);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530138 acpigen_write_dword(DOMAIN_TYPE_WIFI);
139 acpigen_write_dword(1);
140 acpigen_write_dword(sar->dsar_set_count);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700141
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530142 for (set_num = 1; set_num <= sar->dsar_set_count; set_num++) {
143 set = sar_fetch_set(sar, set_num);
144 for (i = 0; i < table_size; i++)
145 acpigen_write_byte(set[i]);
146 }
147
148 /* wifi driver always expects 3 DSAR sets */
149 for (i = 0; i < (table_size * (MAX_DSAR_SET_COUNT - sar->dsar_set_count)); i++)
150 acpigen_write_byte(0);
151
152 acpigen_write_package_end();
153 acpigen_write_package_end();
154}
155
156static void sar_emit_wgds(struct geo_profile *wgds)
157{
158 int i;
159 size_t package_size, set_num;
160 const uint8_t *set;
161
162 if (wgds == NULL)
Furquan Shaikh2736c822020-10-27 19:46:11 -0700163 return;
164
165 /*
166 * Name ("WGDS", Package() {
167 * Revision,
168 * Package() {
169 * DomainType, // 0x7:WiFi
170 * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
171 * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
172 * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
173 * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
174 * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
175 * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530176 * WgdsWiFiSarDeltaGroup1PowerMax3, // Group 1 FCC 6000-7000 Max
177 * WgdsWiFiSarDeltaGroup1PowerChainA3, // Group 1 FCC 6000-7000 A Offset
178 * WgdsWiFiSarDeltaGroup1PowerChainB3, // Group 1 FCC 6000-7000 B Offset
Furquan Shaikh2736c822020-10-27 19:46:11 -0700179 * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
180 * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
181 * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
182 * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
183 * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
184 * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530185 * WgdsWiFiSarDeltaGroup2PowerMax3, // Group 2 EC Jap 6000-7000 Max
186 * WgdsWiFiSarDeltaGroup2PowerChainA3, // Group 2 EC Jap 6000-7000 A Offset
187 * WgdsWiFiSarDeltaGroup2PowerChainB3, // Group 2 EC Jap 6000-7000 B Offset
Furquan Shaikh2736c822020-10-27 19:46:11 -0700188 * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
189 * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
190 * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
191 * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
192 * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
193 * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530194 * WgdsWiFiSarDeltaGroup3PowerMax3, // Group 3 ROW 6000-7000 Max
195 * WgdsWiFiSarDeltaGroup3PowerChainA3, // Group 3 ROW 6000-7000 A Offset
196 * WgdsWiFiSarDeltaGroup3PowerChainB3, // Group 3 ROW 6000-7000 B Offset
Furquan Shaikh2736c822020-10-27 19:46:11 -0700197 * }
198 * })
199 */
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530200 if (wgds->revision > MAX_GEO_OFFSET_REVISION) {
201 printk(BIOS_ERR, "ERROR: Invalid WGDS revision: %d\n", wgds->revision);
202 return;
203 }
Furquan Shaikh2736c822020-10-27 19:46:11 -0700204
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530205 package_size = 1 + wgds->chains_count * wgds->bands_count;
206
Furquan Shaikh2736c822020-10-27 19:46:11 -0700207 acpigen_write_name("WGDS");
208 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530209 acpigen_write_dword(wgds->revision);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700210 /* Emit 'Domain Type' +
211 * Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
212 */
Furquan Shaikh2736c822020-10-27 19:46:11 -0700213 acpigen_write_package(package_size);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530214 acpigen_write_dword(DOMAIN_TYPE_WIFI);
215
216 for (set_num = 0; set_num < wgds->chains_count; set_num++) {
217 set = wgds_fetch_set(wgds, set_num);
218 for (i = 0; i < wgds->bands_count; i++)
219 acpigen_write_byte(set[i]);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700220 }
221
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530222 acpigen_write_package_end();
223 acpigen_write_package_end();
224}
225
Sugnan Prabhu Sd1fc8322021-08-31 07:11:35 +0530226static void sar_emit_ppag(struct gain_profile *ppag)
227{
228 int i;
229 size_t package_size, set_num;
230 const uint8_t *set;
231
232 if (ppag == NULL)
233 return;
234
235 /*
236 * Name ("PPAG", Package () {
237 * Revision,
238 * Package () {
239 * Domain Type, // 0x7:WiFi
240 * PPAG Mode, // Defines the mode of ANT_gain control to be used
241 * ANT_gain Table Chain A // Defines the ANT_gain in dBi for chain A
242 * ANT_gain Table Chain B // Defines the ANT_gain in dBi for chain B
243 * }
244 * })
245 */
246 if (ppag->revision > MAX_ANT_GAINS_REVISION) {
247 printk(BIOS_ERR, "Invalid PPAG revision: %d\n", ppag->revision);
248 return;
249 }
250
251 package_size = 1 + 1 + ppag->chains_count * ppag->bands_count;
252
253 acpigen_write_name("PPAG");
254 acpigen_write_package(2);
255 acpigen_write_dword(ppag->revision);
256 acpigen_write_package(package_size);
257 acpigen_write_dword(DOMAIN_TYPE_WIFI);
258 acpigen_write_dword(ppag->mode);
259
260 for (set_num = 0; set_num < ppag->chains_count; set_num++) {
261 set = ppag_fetch_set(ppag, set_num);
262 for (i = 0; i < ppag->bands_count; i++)
263 acpigen_write_byte(set[i]);
264 }
265
266 acpigen_write_package_end();
267 acpigen_write_package_end();
268}
269
Sugnan Prabhu Scc507702021-08-31 07:19:30 +0530270static void sar_emit_wtas(struct avg_profile *wtas)
271{
272 int i;
273 size_t package_size;
274
275 if (wtas == NULL)
276 return;
277
278 /*
279 * Name (WTAS, Package() {
280 * {
281 * Revision,
282 * Package()
283 * {
284 * DomainType, // 0x7:WiFi
285 * WifiTASSelection, // Enable/Disable the TAS feature
286 * WifiTASListEntries, // No. of blocked countries not approved by OEM to
287 * BlockedListEntry1, support this feature
288 * BlockedListEntry2,
289 * BlockedListEntry3,
290 * BlockedListEntry4,
291 * BlockedListEntry5,
292 * BlockedListEntry6,
293 * BlockedListEntry7,
294 * BlockedListEntry8,
295 * BlockedListEntry9,
296 * BlockedListEntry10,
297 * BlockedListEntry11,
298 * BlockedListEntry12,
299 * BlockedListEntry13,
300 * BlockedListEntry14,
301 * BlockedListEntry15,
302 * BlockedListEntry16,
303 * }
304 * })
305 */
306 package_size = 1 + 1 + 1 + MAX_DENYLIST_ENTRY;
307
308 acpigen_write_name("WTAS");
309 acpigen_write_package(2);
310 acpigen_write_dword(wtas->revision);
311 acpigen_write_package(package_size);
312 acpigen_write_dword(DOMAIN_TYPE_WIFI);
313 acpigen_write_dword(wtas->tas_selection);
314 acpigen_write_dword(wtas->tas_list_size);
315 for (i = 0; i < MAX_DENYLIST_ENTRY; i++)
316 acpigen_write_byte(wtas->deny_list_entry[i]);
317
318 acpigen_write_package_end();
319 acpigen_write_package_end();
320}
321
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530322static void emit_sar_acpi_structures(const struct device *dev)
323{
324 union wifi_sar_limits sar_limits;
325
326 /*
327 * If device type is PCI, ensure that the device has Intel vendor ID. CBFS SAR and SAR
328 * ACPI tables are currently used only by Intel WiFi devices.
329 */
330 if (dev->path.type == DEVICE_PATH_PCI && dev->vendor != PCI_VENDOR_ID_INTEL)
331 return;
332
333 /* Retrieve the sar limits data */
334 if (get_wifi_sar_limits(&sar_limits) < 0) {
335 printk(BIOS_ERR, "ERROR: failed getting SAR limits!\n");
336 return;
337 }
338
339 sar_emit_wrds(sar_limits.sar);
340 sar_emit_ewrd(sar_limits.sar);
341 sar_emit_wgds(sar_limits.wgds);
Sugnan Prabhu Sd1fc8322021-08-31 07:11:35 +0530342 sar_emit_ppag(sar_limits.ppag);
Sugnan Prabhu Scc507702021-08-31 07:19:30 +0530343 sar_emit_wtas(sar_limits.wtas);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530344
345 free(sar_limits.sar);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700346}
347
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700348static void wifi_ssdt_write_device(const struct device *dev, const char *path)
Furquan Shaikh2736c822020-10-27 19:46:11 -0700349{
Furquan Shaikh2736c822020-10-27 19:46:11 -0700350 /* Device */
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700351 acpigen_write_device(path);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700352 acpi_device_write_uid(dev);
353
354 if (dev->chip_ops)
355 acpigen_write_name_string("_DDN", dev->chip_ops->name);
356
357 /* Address */
358 acpigen_write_ADR_pci_device(dev);
359
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700360 acpigen_pop_len(); /* Device */
361}
362
363static void wifi_ssdt_write_properties(const struct device *dev, const char *scope)
364{
365 const struct drivers_wifi_generic_config *config = dev->chip_info;
366
367 /* Scope */
368 acpigen_write_scope(scope);
369
Furquan Shaikh2736c822020-10-27 19:46:11 -0700370 /* Wake capabilities */
371 if (config)
372 acpigen_write_PRW(config->wake, ACPI_S3);
373
374 /* Fill regulatory domain structure */
375 if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
376 /*
377 * Name ("WRDD", Package () {
378 * WRDD_REVISION, // Revision
379 * Package () {
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530380 * DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
Furquan Shaikh2736c822020-10-27 19:46:11 -0700381 * wifi_regulatory_domain() // Country Identifier
382 * }
383 * })
384 */
385 acpigen_write_name("WRDD");
386 acpigen_write_package(2);
387 acpigen_write_integer(WRDD_REVISION);
388 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530389 acpigen_write_dword(DOMAIN_TYPE_WIFI);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700390 acpigen_write_dword(wifi_regulatory_domain());
391 acpigen_pop_len();
392 acpigen_pop_len();
393 }
394
395 /* Fill Wifi sar related ACPI structures */
396 if (CONFIG(USE_SAR))
397 emit_sar_acpi_structures(dev);
398
Furquan Shaikh2736c822020-10-27 19:46:11 -0700399 acpigen_pop_len(); /* Scope */
400
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700401 printk(BIOS_INFO, "%s: %s %s\n", scope, dev->chip_ops ? dev->chip_ops->name : "",
402 dev_path(dev));
403}
404
Furquan Shaikhd4367502020-10-27 18:00:46 -0700405void wifi_pcie_fill_ssdt(const struct device *dev)
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700406{
407 const char *path;
408
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700409 path = acpi_device_path(dev);
410 if (!path)
411 return;
412
413 wifi_ssdt_write_device(dev, path);
414 wifi_ssdt_write_properties(dev, path);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700415}
416
Furquan Shaikhd4367502020-10-27 18:00:46 -0700417const char *wifi_pcie_acpi_name(const struct device *dev)
Furquan Shaikh2736c822020-10-27 19:46:11 -0700418{
419 static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
420
421 /* ACPI 6.3, ASL 20.2.2: (Name Objects Encoding). */
422 snprintf(wifi_acpi_name, sizeof(wifi_acpi_name), "WF%02X",
423 (dev_path_encode(dev) & 0xff));
424 return wifi_acpi_name;
425}
Furquan Shaikhd4367502020-10-27 18:00:46 -0700426
427void wifi_cnvi_fill_ssdt(const struct device *dev)
428{
429 const char *path;
430
Furquan Shaikhd4367502020-10-27 18:00:46 -0700431 path = acpi_device_path(dev->bus->dev);
432 if (!path)
433 return;
434
435 wifi_ssdt_write_properties(dev, path);
436}