blob: aa49be35e2028d1ab4d65cb3a010fd2274859424 [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
45static void sar_emit_wrds(const struct sar_profile *sar)
46{
47 int i;
48 size_t package_size, table_size;
49 const uint8_t *set;
50
51 if (sar == NULL)
Furquan Shaikh2736c822020-10-27 19:46:11 -070052 return;
Furquan Shaikh2736c822020-10-27 19:46:11 -070053
54 /*
55 * Name ("WRDS", Package () {
56 * Revision,
57 * Package () {
58 * Domain Type, // 0x7:WiFi
59 * WiFi SAR BIOS, // BIOS SAR Enable/disable
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053060 * SAR Table Set // Set#1 of SAR Table
Furquan Shaikh2736c822020-10-27 19:46:11 -070061 * }
62 * })
63 */
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053064 if (sar->revision > MAX_SAR_REVISION) {
65 printk(BIOS_ERR, "ERROR: Invalid SAR table revision: %d\n", sar->revision);
66 return;
67 }
68
Furquan Shaikh2736c822020-10-27 19:46:11 -070069 acpigen_write_name("WRDS");
70 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053071 acpigen_write_dword(sar->revision);
72
73 table_size = sar->chains_count * sar->subbands_count;
74 /* Emit 'Domain Type' + 'WiFi SAR Enable' + Set#1 */
75 package_size = 1 + 1 + table_size;
Furquan Shaikh2736c822020-10-27 19:46:11 -070076 acpigen_write_package(package_size);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +053077 acpigen_write_dword(DOMAIN_TYPE_WIFI);
78 acpigen_write_dword(1);
79
80 set = sar_fetch_set(sar, 0);
81 for (i = 0; i < table_size; i++)
82 acpigen_write_byte(set[i]);
83
84 acpigen_write_package_end();
85 acpigen_write_package_end();
86}
87
88static void sar_emit_ewrd(const struct sar_profile *sar)
89{
90 int i;
91 size_t package_size, set_num, table_size;
92 const uint8_t *set;
93
94 if (sar == NULL)
95 return;
Furquan Shaikh2736c822020-10-27 19:46:11 -070096
97 /*
98 * Name ("EWRD", Package () {
99 * Revision,
100 * Package () {
101 * Domain Type, // 0x7:WiFi
102 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
103 * Extended SAR sets, // Number of optional SAR table sets
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530104 * SAR Table Set, // Set#2 of SAR Table
105 * SAR Table Set, // Set#3 of SAR Table
106 * SAR Table Set // Set#4 of SAR Table
Furquan Shaikh2736c822020-10-27 19:46:11 -0700107 * }
108 * })
109 */
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530110 if (sar->revision > MAX_SAR_REVISION) {
111 printk(BIOS_ERR, "ERROR: Invalid SAR table revision: %d\n", sar->revision);
112 return;
113 }
114
115 if (sar->dsar_set_count == 0) {
116 printk(BIOS_WARNING, "WARNING: DSAR set count is 0\n");
117 return;
118 }
119
Furquan Shaikh2736c822020-10-27 19:46:11 -0700120 acpigen_write_name("EWRD");
121 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530122 acpigen_write_dword(sar->revision);
123
124 table_size = sar->chains_count * sar->subbands_count;
Furquan Shaikh2736c822020-10-27 19:46:11 -0700125 /*
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530126 * Emit 'Domain Type' + 'Dynamic SAR Enable' + 'Extended SAR sets count'
Furquan Shaikh2736c822020-10-27 19:46:11 -0700127 * + number of bytes for Set#2 & 3 & 4
128 */
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530129 package_size = 1 + 1 + 1 + table_size * sar->dsar_set_count;
Furquan Shaikh2736c822020-10-27 19:46:11 -0700130 acpigen_write_package(package_size);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530131 acpigen_write_dword(DOMAIN_TYPE_WIFI);
132 acpigen_write_dword(1);
133 acpigen_write_dword(sar->dsar_set_count);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700134
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530135 for (set_num = 1; set_num <= sar->dsar_set_count; set_num++) {
136 set = sar_fetch_set(sar, set_num);
137 for (i = 0; i < table_size; i++)
138 acpigen_write_byte(set[i]);
139 }
140
141 /* wifi driver always expects 3 DSAR sets */
142 for (i = 0; i < (table_size * (MAX_DSAR_SET_COUNT - sar->dsar_set_count)); i++)
143 acpigen_write_byte(0);
144
145 acpigen_write_package_end();
146 acpigen_write_package_end();
147}
148
149static void sar_emit_wgds(struct geo_profile *wgds)
150{
151 int i;
152 size_t package_size, set_num;
153 const uint8_t *set;
154
155 if (wgds == NULL)
Furquan Shaikh2736c822020-10-27 19:46:11 -0700156 return;
157
158 /*
159 * Name ("WGDS", Package() {
160 * Revision,
161 * Package() {
162 * DomainType, // 0x7:WiFi
163 * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
164 * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
165 * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
166 * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
167 * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
168 * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530169 * WgdsWiFiSarDeltaGroup1PowerMax3, // Group 1 FCC 6000-7000 Max
170 * WgdsWiFiSarDeltaGroup1PowerChainA3, // Group 1 FCC 6000-7000 A Offset
171 * WgdsWiFiSarDeltaGroup1PowerChainB3, // Group 1 FCC 6000-7000 B Offset
Furquan Shaikh2736c822020-10-27 19:46:11 -0700172 * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
173 * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
174 * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
175 * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
176 * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
177 * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530178 * WgdsWiFiSarDeltaGroup2PowerMax3, // Group 2 EC Jap 6000-7000 Max
179 * WgdsWiFiSarDeltaGroup2PowerChainA3, // Group 2 EC Jap 6000-7000 A Offset
180 * WgdsWiFiSarDeltaGroup2PowerChainB3, // Group 2 EC Jap 6000-7000 B Offset
Furquan Shaikh2736c822020-10-27 19:46:11 -0700181 * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
182 * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
183 * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
184 * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
185 * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
186 * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530187 * WgdsWiFiSarDeltaGroup3PowerMax3, // Group 3 ROW 6000-7000 Max
188 * WgdsWiFiSarDeltaGroup3PowerChainA3, // Group 3 ROW 6000-7000 A Offset
189 * WgdsWiFiSarDeltaGroup3PowerChainB3, // Group 3 ROW 6000-7000 B Offset
Furquan Shaikh2736c822020-10-27 19:46:11 -0700190 * }
191 * })
192 */
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530193 if (wgds->revision > MAX_GEO_OFFSET_REVISION) {
194 printk(BIOS_ERR, "ERROR: Invalid WGDS revision: %d\n", wgds->revision);
195 return;
196 }
Furquan Shaikh2736c822020-10-27 19:46:11 -0700197
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530198 package_size = 1 + wgds->chains_count * wgds->bands_count;
199
Furquan Shaikh2736c822020-10-27 19:46:11 -0700200 acpigen_write_name("WGDS");
201 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530202 acpigen_write_dword(wgds->revision);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700203 /* Emit 'Domain Type' +
204 * Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
205 */
Furquan Shaikh2736c822020-10-27 19:46:11 -0700206 acpigen_write_package(package_size);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530207 acpigen_write_dword(DOMAIN_TYPE_WIFI);
208
209 for (set_num = 0; set_num < wgds->chains_count; set_num++) {
210 set = wgds_fetch_set(wgds, set_num);
211 for (i = 0; i < wgds->bands_count; i++)
212 acpigen_write_byte(set[i]);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700213 }
214
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530215 acpigen_write_package_end();
216 acpigen_write_package_end();
217}
218
219static void emit_sar_acpi_structures(const struct device *dev)
220{
221 union wifi_sar_limits sar_limits;
222
223 /*
224 * If device type is PCI, ensure that the device has Intel vendor ID. CBFS SAR and SAR
225 * ACPI tables are currently used only by Intel WiFi devices.
226 */
227 if (dev->path.type == DEVICE_PATH_PCI && dev->vendor != PCI_VENDOR_ID_INTEL)
228 return;
229
230 /* Retrieve the sar limits data */
231 if (get_wifi_sar_limits(&sar_limits) < 0) {
232 printk(BIOS_ERR, "ERROR: failed getting SAR limits!\n");
233 return;
234 }
235
236 sar_emit_wrds(sar_limits.sar);
237 sar_emit_ewrd(sar_limits.sar);
238 sar_emit_wgds(sar_limits.wgds);
239
240 free(sar_limits.sar);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700241}
242
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700243static void wifi_ssdt_write_device(const struct device *dev, const char *path)
Furquan Shaikh2736c822020-10-27 19:46:11 -0700244{
Furquan Shaikh2736c822020-10-27 19:46:11 -0700245 /* Device */
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700246 acpigen_write_device(path);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700247 acpi_device_write_uid(dev);
248
249 if (dev->chip_ops)
250 acpigen_write_name_string("_DDN", dev->chip_ops->name);
251
252 /* Address */
253 acpigen_write_ADR_pci_device(dev);
254
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700255 acpigen_pop_len(); /* Device */
256}
257
258static void wifi_ssdt_write_properties(const struct device *dev, const char *scope)
259{
260 const struct drivers_wifi_generic_config *config = dev->chip_info;
261
262 /* Scope */
263 acpigen_write_scope(scope);
264
Furquan Shaikh2736c822020-10-27 19:46:11 -0700265 /* Wake capabilities */
266 if (config)
267 acpigen_write_PRW(config->wake, ACPI_S3);
268
269 /* Fill regulatory domain structure */
270 if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
271 /*
272 * Name ("WRDD", Package () {
273 * WRDD_REVISION, // Revision
274 * Package () {
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530275 * DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
Furquan Shaikh2736c822020-10-27 19:46:11 -0700276 * wifi_regulatory_domain() // Country Identifier
277 * }
278 * })
279 */
280 acpigen_write_name("WRDD");
281 acpigen_write_package(2);
282 acpigen_write_integer(WRDD_REVISION);
283 acpigen_write_package(2);
Sugnan Prabhu Sfcb4f2d2021-07-30 20:12:22 +0530284 acpigen_write_dword(DOMAIN_TYPE_WIFI);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700285 acpigen_write_dword(wifi_regulatory_domain());
286 acpigen_pop_len();
287 acpigen_pop_len();
288 }
289
290 /* Fill Wifi sar related ACPI structures */
291 if (CONFIG(USE_SAR))
292 emit_sar_acpi_structures(dev);
293
Furquan Shaikh2736c822020-10-27 19:46:11 -0700294 acpigen_pop_len(); /* Scope */
295
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700296 printk(BIOS_INFO, "%s: %s %s\n", scope, dev->chip_ops ? dev->chip_ops->name : "",
297 dev_path(dev));
298}
299
Furquan Shaikhd4367502020-10-27 18:00:46 -0700300void wifi_pcie_fill_ssdt(const struct device *dev)
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700301{
302 const char *path;
303
Furquan Shaikh6017abb2020-10-27 17:41:09 -0700304 path = acpi_device_path(dev);
305 if (!path)
306 return;
307
308 wifi_ssdt_write_device(dev, path);
309 wifi_ssdt_write_properties(dev, path);
Furquan Shaikh2736c822020-10-27 19:46:11 -0700310}
311
Furquan Shaikhd4367502020-10-27 18:00:46 -0700312const char *wifi_pcie_acpi_name(const struct device *dev)
Furquan Shaikh2736c822020-10-27 19:46:11 -0700313{
314 static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
315
316 /* ACPI 6.3, ASL 20.2.2: (Name Objects Encoding). */
317 snprintf(wifi_acpi_name, sizeof(wifi_acpi_name), "WF%02X",
318 (dev_path_encode(dev) & 0xff));
319 return wifi_acpi_name;
320}
Furquan Shaikhd4367502020-10-27 18:00:46 -0700321
322void wifi_cnvi_fill_ssdt(const struct device *dev)
323{
324 const char *path;
325
Furquan Shaikhd4367502020-10-27 18:00:46 -0700326 path = acpi_device_path(dev->bus->dev);
327 if (!path)
328 return;
329
330 wifi_ssdt_write_properties(dev, path);
331}