blob: e8184d8c1340ad0b0552a3fe83f28659724094b1 [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -06002
Furquan Shaikh76cedd22020-05-02 10:24:23 -07003#include <acpi/acpi_device.h>
4#include <acpi/acpigen.h>
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -06005#include <console/console.h>
6#include <device/device.h>
Furquan Shaikh7cb10342020-10-03 14:49:09 -07007#include <device/pci.h>
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -06008#include <device/pci_def.h>
Furquan Shaikha1ddd2a2020-10-04 12:42:09 -07009#include <device/pci_ids.h>
Furquan Shaikh54b27162020-10-03 16:33:07 -070010#include <elog.h>
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -060011#include <sar.h>
Furquan Shaikha1ddd2a2020-10-04 12:42:09 -070012#include <smbios.h>
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -060013#include <string.h>
14#include <wrdd.h>
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -060015#include "chip.h"
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -060016
17/* WRDS Spec Revision */
18#define WRDS_REVISION 0x0
19
20/* EWRD Spec Revision */
21#define EWRD_REVISION 0x0
22
23/* WRDS Domain type */
24#define WRDS_DOMAIN_TYPE_WIFI 0x7
25
26/* EWRD Domain type */
27#define EWRD_DOMAIN_TYPE_WIFI 0x7
28
29/* WGDS Domain type */
30#define WGDS_DOMAIN_TYPE_WIFI 0x7
31
32/*
33 * WIFI ACPI NAME = "WF" + hex value of last 8 bits of dev_path_encode + '\0'
34 * The above representation returns unique and consistent name every time
35 * generate_wifi_acpi_name is invoked. The last 8 bits of dev_path_encode is
36 * chosen since it contains the bus address of the device.
37 */
38#define WIFI_ACPI_NAME_MAX_LEN 5
39
Furquan Shaikh5e003392020-10-04 17:34:04 -070040#if CONFIG(HAVE_ACPI_TABLES)
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -060041__weak
42int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
43{
44 return -1;
45}
46
Furquan Shaikhe31506c2020-10-04 17:48:48 -070047static void emit_sar_acpi_structures(const struct device *dev)
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -060048{
49 int i, j, package_size;
50 struct wifi_sar_limits sar_limits;
51 struct wifi_sar_delta_table *wgds;
52
Furquan Shaikhe31506c2020-10-04 17:48:48 -070053 /* CBFS SAR and SAR ACPI tables are currently used only by Intel WiFi devices. */
54 if (dev->vendor != PCI_VENDOR_ID_INTEL)
55 return;
56
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -060057 /* Retrieve the sar limits data */
58 if (get_wifi_sar_limits(&sar_limits) < 0) {
59 printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
60 return;
61 }
62
63 /*
64 * Name ("WRDS", Package () {
65 * Revision,
66 * Package () {
67 * Domain Type, // 0x7:WiFi
68 * WiFi SAR BIOS, // BIOS SAR Enable/disable
69 * SAR Table Set // Set#1 of SAR Table (10 bytes)
70 * }
71 * })
72 */
73 acpigen_write_name("WRDS");
74 acpigen_write_package(2);
75 acpigen_write_dword(WRDS_REVISION);
76 /* Emit 'Domain Type' + 'WiFi SAR BIOS' + 10 bytes for Set#1 */
77 package_size = 1 + 1 + BYTES_PER_SAR_LIMIT;
78 acpigen_write_package(package_size);
79 acpigen_write_dword(WRDS_DOMAIN_TYPE_WIFI);
80 acpigen_write_dword(CONFIG(SAR_ENABLE));
81 for (i = 0; i < BYTES_PER_SAR_LIMIT; i++)
82 acpigen_write_byte(sar_limits.sar_limit[0][i]);
83 acpigen_pop_len();
84 acpigen_pop_len();
85
86 /*
87 * Name ("EWRD", Package () {
88 * Revision,
89 * Package () {
90 * Domain Type, // 0x7:WiFi
91 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
92 * Extended SAR sets, // Number of optional SAR table sets
93 * SAR Table Set, // Set#2 of SAR Table (10 bytes)
94 * SAR Table Set, // Set#3 of SAR Table (10 bytes)
95 * SAR Table Set // Set#4 of SAR Table (10 bytes)
96 * }
97 * })
98 */
99 acpigen_write_name("EWRD");
100 acpigen_write_package(2);
101 acpigen_write_dword(EWRD_REVISION);
102 /*
103 * Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets'
104 * + number of bytes for Set#2 & 3 & 4
105 */
106 package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT;
107 acpigen_write_package(package_size);
108 acpigen_write_dword(EWRD_DOMAIN_TYPE_WIFI);
109 acpigen_write_dword(CONFIG(DSAR_ENABLE));
110 acpigen_write_dword(CONFIG_DSAR_SET_NUM);
111 for (i = 1; i < NUM_SAR_LIMITS; i++)
112 for (j = 0; j < BYTES_PER_SAR_LIMIT; j++)
113 acpigen_write_byte(sar_limits.sar_limit[i][j]);
114 acpigen_pop_len();
115 acpigen_pop_len();
116
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600117 if (!CONFIG(GEO_SAR_ENABLE))
118 return;
119
120 /*
121 * Name ("WGDS", Package() {
122 * Revision,
123 * Package() {
124 * DomainType, // 0x7:WiFi
125 * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
126 * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
127 * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
128 * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
129 * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
130 * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
131 * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
132 * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
133 * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
134 * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
135 * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
136 * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
137 * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
138 * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
139 * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
140 * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
141 * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
142 * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
143 * }
144 * })
145 */
146
147 wgds = &sar_limits.wgds;
148 acpigen_write_name("WGDS");
149 acpigen_write_package(2);
150 acpigen_write_dword(wgds->version);
151 /* Emit 'Domain Type' +
152 * Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
153 */
154 package_size = sizeof(sar_limits.wgds.group) + 1;
155 acpigen_write_package(package_size);
156 acpigen_write_dword(WGDS_DOMAIN_TYPE_WIFI);
157 for (i = 0; i < SAR_NUM_WGDS_GROUPS; i++) {
158 acpigen_write_byte(wgds->group[i].power_max_2400mhz);
159 acpigen_write_byte(wgds->group[i].power_chain_a_2400mhz);
160 acpigen_write_byte(wgds->group[i].power_chain_b_2400mhz);
161 acpigen_write_byte(wgds->group[i].power_max_5200mhz);
162 acpigen_write_byte(wgds->group[i].power_chain_a_5200mhz);
163 acpigen_write_byte(wgds->group[i].power_chain_b_5200mhz);
164 }
165
166 acpigen_pop_len();
167 acpigen_pop_len();
168}
169
Furquan Shaikh44f14502020-10-04 18:05:28 -0700170static void wifi_generic_fill_ssdt(const struct device *dev)
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600171{
172 const char *path;
173 u32 address;
Furquan Shaikh44f14502020-10-04 18:05:28 -0700174 const struct drivers_wifi_generic_config *config = dev->chip_info;
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600175
176 if (!dev->enabled)
177 return;
178
179 path = acpi_device_path(dev->bus->dev);
180 if (!path)
181 return;
182
183 /* Device */
184 acpigen_write_scope(path);
185 acpigen_write_device(acpi_device_name(dev));
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100186 acpi_device_write_uid(dev);
187
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600188 if (dev->chip_ops)
189 acpigen_write_name_string("_DDN", dev->chip_ops->name);
190
191 /* Address */
192 address = PCI_SLOT(dev->path.pci.devfn) & 0xffff;
193 address <<= 16;
194 address |= PCI_FUNC(dev->path.pci.devfn) & 0xffff;
195 acpigen_write_name_dword("_ADR", address);
196
197 /* Wake capabilities */
198 if (config)
Furquan Shaikh0af19262020-10-04 12:13:07 -0700199 acpigen_write_PRW(config->wake, ACPI_S3);
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600200
201 /* Fill regulatory domain structure */
202 if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
203 /*
204 * Name ("WRDD", Package () {
205 * WRDD_REVISION, // Revision
206 * Package () {
207 * WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
208 * wifi_regulatory_domain() // Country Identifier
209 * }
210 * })
211 */
212 acpigen_write_name("WRDD");
213 acpigen_write_package(2);
214 acpigen_write_integer(WRDD_REVISION);
215 acpigen_write_package(2);
216 acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI);
217 acpigen_write_dword(wifi_regulatory_domain());
218 acpigen_pop_len();
219 acpigen_pop_len();
220 }
221
222 /* Fill Wifi sar related ACPI structures */
223 if (CONFIG(USE_SAR))
Furquan Shaikhe31506c2020-10-04 17:48:48 -0700224 emit_sar_acpi_structures(dev);
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600225
226 acpigen_pop_len(); /* Device */
227 acpigen_pop_len(); /* Scope */
228
229 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
230 dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
231}
232
Furquan Shaikh44f14502020-10-04 18:05:28 -0700233static const char *wifi_generic_acpi_name(const struct device *dev)
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600234{
235 static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
236
Andrew McRae524bcbb2019-09-19 16:55:52 +1000237 /* ACPI 6.3, ASL 20.2.2: (Name Objects Encoding). */
238 snprintf(wifi_acpi_name, sizeof(wifi_acpi_name), "WF%02X",
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600239 (dev_path_encode(dev) & 0xff));
240 return wifi_acpi_name;
241}
Furquan Shaikh5e003392020-10-04 17:34:04 -0700242#endif
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600243
Furquan Shaikh54b27162020-10-03 16:33:07 -0700244static void wifi_pci_dev_init(struct device *dev)
245{
246 if (pci_dev_is_wake_source(dev))
247 elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
248}
249
Furquan Shaikha1ddd2a2020-10-04 12:42:09 -0700250#if CONFIG(GENERATE_SMBIOS_TABLES)
251static int smbios_write_intel_wifi(struct device *dev, int *handle, unsigned long *current)
252{
253 struct smbios_type_intel_wifi {
254 u8 type;
255 u8 length;
256 u16 handle;
257 u8 str;
258 u8 eos[2];
259 } __packed;
260
261 struct smbios_type_intel_wifi *t = (struct smbios_type_intel_wifi *)*current;
262 int len = sizeof(struct smbios_type_intel_wifi);
263
264 memset(t, 0, sizeof(struct smbios_type_intel_wifi));
265 t->type = 0x85;
266 t->length = len - 2;
267 t->handle = *handle;
268 /* Intel wifi driver expects this string to be in the table 0x85. */
269 t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");
270
271 len = t->length + smbios_string_table_len(t->eos);
272 *current += len;
273 *handle += 1;
274 return len;
275}
276
277static int smbios_write_wifi(struct device *dev, int *handle, unsigned long *current)
278{
279 if (dev->vendor == PCI_VENDOR_ID_INTEL)
280 return smbios_write_intel_wifi(dev, handle, current);
281
282 return 0;
283}
284#endif
285
Furquan Shaikh7cb10342020-10-03 14:49:09 -0700286struct device_operations wifi_generic_ops = {
287 .read_resources = pci_dev_read_resources,
288 .set_resources = pci_dev_set_resources,
289 .enable_resources = pci_dev_enable_resources,
Furquan Shaikh54b27162020-10-03 16:33:07 -0700290 .init = wifi_pci_dev_init,
Furquan Shaikh7cb10342020-10-03 14:49:09 -0700291 .ops_pci = &pci_dev_ops_pci,
Furquan Shaikh5e003392020-10-04 17:34:04 -0700292#if CONFIG(HAVE_ACPI_TABLES)
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600293 .acpi_name = wifi_generic_acpi_name,
Furquan Shaikh44f14502020-10-04 18:05:28 -0700294 .acpi_fill_ssdt = wifi_generic_fill_ssdt,
Furquan Shaikh5e003392020-10-04 17:34:04 -0700295#endif
Furquan Shaikha1ddd2a2020-10-04 12:42:09 -0700296#if CONFIG(GENERATE_SMBIOS_TABLES)
297 .get_smbios_data = smbios_write_wifi,
298#endif
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600299};
300
301static void wifi_generic_enable(struct device *dev)
302{
303 struct drivers_wifi_generic_config *config = dev ? dev->chip_info : NULL;
304
305 if (!config)
306 return;
307
308 dev->ops = &wifi_generic_ops;
309}
310
311struct chip_operations drivers_wifi_generic_ops = {
312 CHIP_NAME("WIFI Device")
313 .enable_dev = wifi_generic_enable
314};
Furquan Shaikh8262a2c2020-10-10 19:53:00 -0700315
316static const unsigned short intel_pci_device_ids[] = {
317 PCI_DEVICE_ID_1000_SERIES_WIFI,
318 PCI_DEVICE_ID_6005_SERIES_WIFI,
319 PCI_DEVICE_ID_6005_I_SERIES_WIFI,
320 PCI_DEVICE_ID_1030_SERIES_WIFI,
321 PCI_DEVICE_ID_6030_I_SERIES_WIFI,
322 PCI_DEVICE_ID_6030_SERIES_WIFI,
323 PCI_DEVICE_ID_6150_SERIES_WIFI,
324 PCI_DEVICE_ID_2030_SERIES_WIFI,
325 PCI_DEVICE_ID_2000_SERIES_WIFI,
326 PCI_DEVICE_ID_0135_SERIES_WIFI,
327 PCI_DEVICE_ID_0105_SERIES_WIFI,
328 PCI_DEVICE_ID_6035_SERIES_WIFI,
329 PCI_DEVICE_ID_5300_SERIES_WIFI,
330 PCI_DEVICE_ID_5100_SERIES_WIFI,
331 PCI_DEVICE_ID_6000_SERIES_WIFI,
332 PCI_DEVICE_ID_6000_I_SERIES_WIFI,
333 PCI_DEVICE_ID_5350_SERIES_WIFI,
334 PCI_DEVICE_ID_5150_SERIES_WIFI,
335 /* Wilkins Peak 2 */
336 PCI_DEVICE_ID_WP_7260_SERIES_1_WIFI,
337 PCI_DEVICE_ID_WP_7260_SERIES_2_WIFI,
338 /* Stone Peak 2 */
339 PCI_DEVICE_ID_SP_7265_SERIES_1_WIFI,
340 PCI_DEVICE_ID_SP_7265_SERIES_2_WIFI,
341 /* Stone Field Peak */
342 PCI_DEVICE_ID_SFP_8260_SERIES_1_WIFI,
343 PCI_DEVICE_ID_SFP_8260_SERIES_2_WIFI,
344 /* Windstorm Peak */
345 PCI_DEVICE_ID_WSP_8275_SERIES_1_WIFI,
346 /* Jefferson Peak */
347 PCI_DEVICE_ID_JP_9000_SERIES_1_WIFI,
348 PCI_DEVICE_ID_JP_9000_SERIES_2_WIFI,
349 PCI_DEVICE_ID_JP_9000_SERIES_3_WIFI,
350 /* Thunder Peak 2 */
351 PCI_DEVICE_ID_TP_9260_SERIES_WIFI,
352 /* Harrison Peak */
353 PCI_DEVICE_ID_HrP_9560_SERIES_1_WIFI,
354 PCI_DEVICE_ID_HrP_9560_SERIES_2_WIFI,
355 PCI_DEVICE_ID_HrP_9560_SERIES_3_WIFI,
356 PCI_DEVICE_ID_HrP_9560_SERIES_4_WIFI,
357 PCI_DEVICE_ID_HrP_6SERIES_WIFI,
358 /* Cyclone Peak */
359 PCI_DEVICE_ID_CyP_6SERIES_WIFI,
360 /* Typhoon Peak */
361 PCI_DEVICE_ID_TyP_6SERIES_WIFI,
362 /* Garfield Peak */
363 PCI_DEVICE_ID_GrP_6SERIES_1_WIFI,
364 PCI_DEVICE_ID_GrP_6SERIES_2_WIFI,
365 0
366};
367
368/*
369 * The PCI driver is retained for backward compatibility with boards that never utilized the
370 * chip driver to support Intel WiFi device. For these devices, the PCI driver helps perform the
371 * same operations as above (except exposing the wake property) by utilizing the same
372 * `wifi_generic_ops`.
373 */
374static const struct pci_driver intel_wifi_pci_driver __pci_driver = {
375 .ops = &wifi_generic_ops,
376 .vendor = PCI_VENDOR_ID_INTEL,
377 .devices = intel_pci_device_ids,
378};