blob: e551bf36371d8183754b09d17c081c93d7aa3265 [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
40__weak
41int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
42{
43 return -1;
44}
45
46static void emit_sar_acpi_structures(void)
47{
48 int i, j, package_size;
49 struct wifi_sar_limits sar_limits;
50 struct wifi_sar_delta_table *wgds;
51
52 /* Retrieve the sar limits data */
53 if (get_wifi_sar_limits(&sar_limits) < 0) {
54 printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
55 return;
56 }
57
58 /*
59 * Name ("WRDS", Package () {
60 * Revision,
61 * Package () {
62 * Domain Type, // 0x7:WiFi
63 * WiFi SAR BIOS, // BIOS SAR Enable/disable
64 * SAR Table Set // Set#1 of SAR Table (10 bytes)
65 * }
66 * })
67 */
68 acpigen_write_name("WRDS");
69 acpigen_write_package(2);
70 acpigen_write_dword(WRDS_REVISION);
71 /* Emit 'Domain Type' + 'WiFi SAR BIOS' + 10 bytes for Set#1 */
72 package_size = 1 + 1 + BYTES_PER_SAR_LIMIT;
73 acpigen_write_package(package_size);
74 acpigen_write_dword(WRDS_DOMAIN_TYPE_WIFI);
75 acpigen_write_dword(CONFIG(SAR_ENABLE));
76 for (i = 0; i < BYTES_PER_SAR_LIMIT; i++)
77 acpigen_write_byte(sar_limits.sar_limit[0][i]);
78 acpigen_pop_len();
79 acpigen_pop_len();
80
81 /*
82 * Name ("EWRD", Package () {
83 * Revision,
84 * Package () {
85 * Domain Type, // 0x7:WiFi
86 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
87 * Extended SAR sets, // Number of optional SAR table sets
88 * SAR Table Set, // Set#2 of SAR Table (10 bytes)
89 * SAR Table Set, // Set#3 of SAR Table (10 bytes)
90 * SAR Table Set // Set#4 of SAR Table (10 bytes)
91 * }
92 * })
93 */
94 acpigen_write_name("EWRD");
95 acpigen_write_package(2);
96 acpigen_write_dword(EWRD_REVISION);
97 /*
98 * Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets'
99 * + number of bytes for Set#2 & 3 & 4
100 */
101 package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT;
102 acpigen_write_package(package_size);
103 acpigen_write_dword(EWRD_DOMAIN_TYPE_WIFI);
104 acpigen_write_dword(CONFIG(DSAR_ENABLE));
105 acpigen_write_dword(CONFIG_DSAR_SET_NUM);
106 for (i = 1; i < NUM_SAR_LIMITS; i++)
107 for (j = 0; j < BYTES_PER_SAR_LIMIT; j++)
108 acpigen_write_byte(sar_limits.sar_limit[i][j]);
109 acpigen_pop_len();
110 acpigen_pop_len();
111
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600112 if (!CONFIG(GEO_SAR_ENABLE))
113 return;
114
115 /*
116 * Name ("WGDS", Package() {
117 * Revision,
118 * Package() {
119 * DomainType, // 0x7:WiFi
120 * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
121 * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
122 * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
123 * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
124 * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
125 * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
126 * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
127 * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
128 * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
129 * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
130 * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
131 * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
132 * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
133 * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
134 * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
135 * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
136 * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
137 * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
138 * }
139 * })
140 */
141
142 wgds = &sar_limits.wgds;
143 acpigen_write_name("WGDS");
144 acpigen_write_package(2);
145 acpigen_write_dword(wgds->version);
146 /* Emit 'Domain Type' +
147 * Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
148 */
149 package_size = sizeof(sar_limits.wgds.group) + 1;
150 acpigen_write_package(package_size);
151 acpigen_write_dword(WGDS_DOMAIN_TYPE_WIFI);
152 for (i = 0; i < SAR_NUM_WGDS_GROUPS; i++) {
153 acpigen_write_byte(wgds->group[i].power_max_2400mhz);
154 acpigen_write_byte(wgds->group[i].power_chain_a_2400mhz);
155 acpigen_write_byte(wgds->group[i].power_chain_b_2400mhz);
156 acpigen_write_byte(wgds->group[i].power_max_5200mhz);
157 acpigen_write_byte(wgds->group[i].power_chain_a_5200mhz);
158 acpigen_write_byte(wgds->group[i].power_chain_b_5200mhz);
159 }
160
161 acpigen_pop_len();
162 acpigen_pop_len();
163}
164
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600165void wifi_generic_fill_ssdt(const struct device *dev,
166 const struct drivers_wifi_generic_config *config)
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600167{
168 const char *path;
169 u32 address;
170
171 if (!dev->enabled)
172 return;
173
174 path = acpi_device_path(dev->bus->dev);
175 if (!path)
176 return;
177
178 /* Device */
179 acpigen_write_scope(path);
180 acpigen_write_device(acpi_device_name(dev));
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100181 acpi_device_write_uid(dev);
182
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600183 if (dev->chip_ops)
184 acpigen_write_name_string("_DDN", dev->chip_ops->name);
185
186 /* Address */
187 address = PCI_SLOT(dev->path.pci.devfn) & 0xffff;
188 address <<= 16;
189 address |= PCI_FUNC(dev->path.pci.devfn) & 0xffff;
190 acpigen_write_name_dword("_ADR", address);
191
192 /* Wake capabilities */
193 if (config)
Furquan Shaikh0af19262020-10-04 12:13:07 -0700194 acpigen_write_PRW(config->wake, ACPI_S3);
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600195
196 /* Fill regulatory domain structure */
197 if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
198 /*
199 * Name ("WRDD", Package () {
200 * WRDD_REVISION, // Revision
201 * Package () {
202 * WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
203 * wifi_regulatory_domain() // Country Identifier
204 * }
205 * })
206 */
207 acpigen_write_name("WRDD");
208 acpigen_write_package(2);
209 acpigen_write_integer(WRDD_REVISION);
210 acpigen_write_package(2);
211 acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI);
212 acpigen_write_dword(wifi_regulatory_domain());
213 acpigen_pop_len();
214 acpigen_pop_len();
215 }
216
217 /* Fill Wifi sar related ACPI structures */
218 if (CONFIG(USE_SAR))
219 emit_sar_acpi_structures();
220
221 acpigen_pop_len(); /* Device */
222 acpigen_pop_len(); /* Scope */
223
224 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
225 dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
226}
227
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600228const char *wifi_generic_acpi_name(const struct device *dev)
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600229{
230 static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
231
Andrew McRae524bcbb2019-09-19 16:55:52 +1000232 /* ACPI 6.3, ASL 20.2.2: (Name Objects Encoding). */
233 snprintf(wifi_acpi_name, sizeof(wifi_acpi_name), "WF%02X",
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600234 (dev_path_encode(dev) & 0xff));
235 return wifi_acpi_name;
236}
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600237
238static void wifi_generic_fill_ssdt_generator(const struct device *dev)
239{
240 wifi_generic_fill_ssdt(dev, dev->chip_info);
241}
242
Furquan Shaikh54b27162020-10-03 16:33:07 -0700243static void wifi_pci_dev_init(struct device *dev)
244{
245 if (pci_dev_is_wake_source(dev))
246 elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
247}
248
Furquan Shaikha1ddd2a2020-10-04 12:42:09 -0700249#if CONFIG(GENERATE_SMBIOS_TABLES)
250static int smbios_write_intel_wifi(struct device *dev, int *handle, unsigned long *current)
251{
252 struct smbios_type_intel_wifi {
253 u8 type;
254 u8 length;
255 u16 handle;
256 u8 str;
257 u8 eos[2];
258 } __packed;
259
260 struct smbios_type_intel_wifi *t = (struct smbios_type_intel_wifi *)*current;
261 int len = sizeof(struct smbios_type_intel_wifi);
262
263 memset(t, 0, sizeof(struct smbios_type_intel_wifi));
264 t->type = 0x85;
265 t->length = len - 2;
266 t->handle = *handle;
267 /* Intel wifi driver expects this string to be in the table 0x85. */
268 t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");
269
270 len = t->length + smbios_string_table_len(t->eos);
271 *current += len;
272 *handle += 1;
273 return len;
274}
275
276static int smbios_write_wifi(struct device *dev, int *handle, unsigned long *current)
277{
278 if (dev->vendor == PCI_VENDOR_ID_INTEL)
279 return smbios_write_intel_wifi(dev, handle, current);
280
281 return 0;
282}
283#endif
284
Furquan Shaikh7cb10342020-10-03 14:49:09 -0700285struct device_operations wifi_generic_ops = {
286 .read_resources = pci_dev_read_resources,
287 .set_resources = pci_dev_set_resources,
288 .enable_resources = pci_dev_enable_resources,
Furquan Shaikh54b27162020-10-03 16:33:07 -0700289 .init = wifi_pci_dev_init,
Furquan Shaikh7cb10342020-10-03 14:49:09 -0700290 .ops_pci = &pci_dev_ops_pci,
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600291 .acpi_name = wifi_generic_acpi_name,
292 .acpi_fill_ssdt = wifi_generic_fill_ssdt_generator,
Furquan Shaikha1ddd2a2020-10-04 12:42:09 -0700293#if CONFIG(GENERATE_SMBIOS_TABLES)
294 .get_smbios_data = smbios_write_wifi,
295#endif
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600296};
297
298static void wifi_generic_enable(struct device *dev)
299{
300 struct drivers_wifi_generic_config *config = dev ? dev->chip_info : NULL;
301
302 if (!config)
303 return;
304
305 dev->ops = &wifi_generic_ops;
306}
307
308struct chip_operations drivers_wifi_generic_ops = {
309 CHIP_NAME("WIFI Device")
310 .enable_dev = wifi_generic_enable
311};