blob: ed5b63221654f54a701c8d7da452e11b18e5712f [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 Sfcb4f2d2021-07-30 20:12:22 +0530270static void emit_sar_acpi_structures(const struct device *dev)
271{
272 union wifi_sar_limits sar_limits;
273
274 /*
275 * If device type is PCI, ensure that the device has Intel vendor ID. CBFS SAR and SAR
276 * ACPI tables are currently used only by Intel WiFi devices.
277 */
278 if (dev->path.type == DEVICE_PATH_PCI && dev->vendor != PCI_VENDOR_ID_INTEL)
279 return;
280
281 /* Retrieve the sar limits data */
282 if (get_wifi_sar_limits(&sar_limits) < 0) {
283 printk(BIOS_ERR, "ERROR: failed getting SAR limits!\n");
284 return;
285 }
286
287 sar_emit_wrds(sar_limits.sar);
288 sar_emit_ewrd(sar_limits.sar);
289 sar_emit_wgds(sar_limits.wgds);
Sugnan Prabhu Sd1fc8322021-08-31 07:11:35 +0530290 sar_emit_ppag(sar_limits.ppag);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530291
292 free(sar_limits.sar);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700293}
294
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700295static void wifi_ssdt_write_device(const struct device *dev, const char *path)
Furquan Shaikh2736c822020-10-27 19:46:11 -0700296{
Furquan Shaikh2736c822020-10-27 19:46:11 -0700297 /* Device */
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700298 acpigen_write_device(path);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700299 acpi_device_write_uid(dev);
300
301 if (dev->chip_ops)
302 acpigen_write_name_string("_DDN", dev->chip_ops->name);
303
304 /* Address */
305 acpigen_write_ADR_pci_device(dev);
306
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700307 acpigen_pop_len(); /* Device */
308}
309
310static void wifi_ssdt_write_properties(const struct device *dev, const char *scope)
311{
312 const struct drivers_wifi_generic_config *config = dev->chip_info;
313
314 /* Scope */
315 acpigen_write_scope(scope);
316
Furquan Shaikh2736c822020-10-27 19:46:11 -0700317 /* Wake capabilities */
318 if (config)
319 acpigen_write_PRW(config->wake, ACPI_S3);
320
321 /* Fill regulatory domain structure */
322 if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
323 /*
324 * Name ("WRDD", Package () {
325 * WRDD_REVISION, // Revision
326 * Package () {
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530327 * DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
Furquan Shaikh2736c822020-10-27 19:46:11 -0700328 * wifi_regulatory_domain() // Country Identifier
329 * }
330 * })
331 */
332 acpigen_write_name("WRDD");
333 acpigen_write_package(2);
334 acpigen_write_integer(WRDD_REVISION);
335 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530336 acpigen_write_dword(DOMAIN_TYPE_WIFI);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700337 acpigen_write_dword(wifi_regulatory_domain());
338 acpigen_pop_len();
339 acpigen_pop_len();
340 }
341
342 /* Fill Wifi sar related ACPI structures */
343 if (CONFIG(USE_SAR))
344 emit_sar_acpi_structures(dev);
345
Furquan Shaikh2736c822020-10-27 19:46:11 -0700346 acpigen_pop_len(); /* Scope */
347
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700348 printk(BIOS_INFO, "%s: %s %s\n", scope, dev->chip_ops ? dev->chip_ops->name : "",
349 dev_path(dev));
350}
351
Furquan Shaikhd4367502020-10-27 18:00:46 -0700352void wifi_pcie_fill_ssdt(const struct device *dev)
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700353{
354 const char *path;
355
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700356 path = acpi_device_path(dev);
357 if (!path)
358 return;
359
360 wifi_ssdt_write_device(dev, path);
361 wifi_ssdt_write_properties(dev, path);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700362}
363
Furquan Shaikhd4367502020-10-27 18:00:46 -0700364const char *wifi_pcie_acpi_name(const struct device *dev)
Furquan Shaikh2736c822020-10-27 19:46:11 -0700365{
366 static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
367
368 /* ACPI 6.3, ASL 20.2.2: (Name Objects Encoding). */
369 snprintf(wifi_acpi_name, sizeof(wifi_acpi_name), "WF%02X",
370 (dev_path_encode(dev) & 0xff));
371 return wifi_acpi_name;
372}
Furquan Shaikhd4367502020-10-27 18:00:46 -0700373
374void wifi_cnvi_fill_ssdt(const struct device *dev)
375{
376 const char *path;
377
Furquan Shaikhd4367502020-10-27 18:00:46 -0700378 path = acpi_device_path(dev->bus->dev);
379 if (!path)
380 return;
381
382 wifi_ssdt_write_properties(dev, path);
383}