blob: 2ecaadc5f7801bed4e0ab60129596c0063f4e03f [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 Shaikh54b27162020-10-03 16:33:07 -07009#include <elog.h>
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -060010#include <sar.h>
11#include <string.h>
12#include <wrdd.h>
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -060013#include "chip.h"
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -060014
15/* WRDS Spec Revision */
16#define WRDS_REVISION 0x0
17
18/* EWRD Spec Revision */
19#define EWRD_REVISION 0x0
20
21/* WRDS Domain type */
22#define WRDS_DOMAIN_TYPE_WIFI 0x7
23
24/* EWRD Domain type */
25#define EWRD_DOMAIN_TYPE_WIFI 0x7
26
27/* WGDS Domain type */
28#define WGDS_DOMAIN_TYPE_WIFI 0x7
29
30/*
31 * WIFI ACPI NAME = "WF" + hex value of last 8 bits of dev_path_encode + '\0'
32 * The above representation returns unique and consistent name every time
33 * generate_wifi_acpi_name is invoked. The last 8 bits of dev_path_encode is
34 * chosen since it contains the bus address of the device.
35 */
36#define WIFI_ACPI_NAME_MAX_LEN 5
37
38__weak
39int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
40{
41 return -1;
42}
43
44static void emit_sar_acpi_structures(void)
45{
46 int i, j, package_size;
47 struct wifi_sar_limits sar_limits;
48 struct wifi_sar_delta_table *wgds;
49
50 /* Retrieve the sar limits data */
51 if (get_wifi_sar_limits(&sar_limits) < 0) {
52 printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
53 return;
54 }
55
56 /*
57 * Name ("WRDS", Package () {
58 * Revision,
59 * Package () {
60 * Domain Type, // 0x7:WiFi
61 * WiFi SAR BIOS, // BIOS SAR Enable/disable
62 * SAR Table Set // Set#1 of SAR Table (10 bytes)
63 * }
64 * })
65 */
66 acpigen_write_name("WRDS");
67 acpigen_write_package(2);
68 acpigen_write_dword(WRDS_REVISION);
69 /* Emit 'Domain Type' + 'WiFi SAR BIOS' + 10 bytes for Set#1 */
70 package_size = 1 + 1 + BYTES_PER_SAR_LIMIT;
71 acpigen_write_package(package_size);
72 acpigen_write_dword(WRDS_DOMAIN_TYPE_WIFI);
73 acpigen_write_dword(CONFIG(SAR_ENABLE));
74 for (i = 0; i < BYTES_PER_SAR_LIMIT; i++)
75 acpigen_write_byte(sar_limits.sar_limit[0][i]);
76 acpigen_pop_len();
77 acpigen_pop_len();
78
79 /*
80 * Name ("EWRD", Package () {
81 * Revision,
82 * Package () {
83 * Domain Type, // 0x7:WiFi
84 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
85 * Extended SAR sets, // Number of optional SAR table sets
86 * SAR Table Set, // Set#2 of SAR Table (10 bytes)
87 * SAR Table Set, // Set#3 of SAR Table (10 bytes)
88 * SAR Table Set // Set#4 of SAR Table (10 bytes)
89 * }
90 * })
91 */
92 acpigen_write_name("EWRD");
93 acpigen_write_package(2);
94 acpigen_write_dword(EWRD_REVISION);
95 /*
96 * Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets'
97 * + number of bytes for Set#2 & 3 & 4
98 */
99 package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT;
100 acpigen_write_package(package_size);
101 acpigen_write_dword(EWRD_DOMAIN_TYPE_WIFI);
102 acpigen_write_dword(CONFIG(DSAR_ENABLE));
103 acpigen_write_dword(CONFIG_DSAR_SET_NUM);
104 for (i = 1; i < NUM_SAR_LIMITS; i++)
105 for (j = 0; j < BYTES_PER_SAR_LIMIT; j++)
106 acpigen_write_byte(sar_limits.sar_limit[i][j]);
107 acpigen_pop_len();
108 acpigen_pop_len();
109
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600110 if (!CONFIG(GEO_SAR_ENABLE))
111 return;
112
113 /*
114 * Name ("WGDS", Package() {
115 * Revision,
116 * Package() {
117 * DomainType, // 0x7:WiFi
118 * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
119 * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
120 * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
121 * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
122 * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
123 * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
124 * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
125 * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
126 * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
127 * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
128 * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
129 * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
130 * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
131 * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
132 * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
133 * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
134 * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
135 * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
136 * }
137 * })
138 */
139
140 wgds = &sar_limits.wgds;
141 acpigen_write_name("WGDS");
142 acpigen_write_package(2);
143 acpigen_write_dword(wgds->version);
144 /* Emit 'Domain Type' +
145 * Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
146 */
147 package_size = sizeof(sar_limits.wgds.group) + 1;
148 acpigen_write_package(package_size);
149 acpigen_write_dword(WGDS_DOMAIN_TYPE_WIFI);
150 for (i = 0; i < SAR_NUM_WGDS_GROUPS; i++) {
151 acpigen_write_byte(wgds->group[i].power_max_2400mhz);
152 acpigen_write_byte(wgds->group[i].power_chain_a_2400mhz);
153 acpigen_write_byte(wgds->group[i].power_chain_b_2400mhz);
154 acpigen_write_byte(wgds->group[i].power_max_5200mhz);
155 acpigen_write_byte(wgds->group[i].power_chain_a_5200mhz);
156 acpigen_write_byte(wgds->group[i].power_chain_b_5200mhz);
157 }
158
159 acpigen_pop_len();
160 acpigen_pop_len();
161}
162
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600163void wifi_generic_fill_ssdt(const struct device *dev,
164 const struct drivers_wifi_generic_config *config)
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600165{
166 const char *path;
167 u32 address;
168
169 if (!dev->enabled)
170 return;
171
172 path = acpi_device_path(dev->bus->dev);
173 if (!path)
174 return;
175
176 /* Device */
177 acpigen_write_scope(path);
178 acpigen_write_device(acpi_device_name(dev));
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100179 acpi_device_write_uid(dev);
180
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600181 if (dev->chip_ops)
182 acpigen_write_name_string("_DDN", dev->chip_ops->name);
183
184 /* Address */
185 address = PCI_SLOT(dev->path.pci.devfn) & 0xffff;
186 address <<= 16;
187 address |= PCI_FUNC(dev->path.pci.devfn) & 0xffff;
188 acpigen_write_name_dword("_ADR", address);
189
190 /* Wake capabilities */
191 if (config)
192 acpigen_write_PRW(config->wake, config->maxsleep);
193
194 /* Fill regulatory domain structure */
195 if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
196 /*
197 * Name ("WRDD", Package () {
198 * WRDD_REVISION, // Revision
199 * Package () {
200 * WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
201 * wifi_regulatory_domain() // Country Identifier
202 * }
203 * })
204 */
205 acpigen_write_name("WRDD");
206 acpigen_write_package(2);
207 acpigen_write_integer(WRDD_REVISION);
208 acpigen_write_package(2);
209 acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI);
210 acpigen_write_dword(wifi_regulatory_domain());
211 acpigen_pop_len();
212 acpigen_pop_len();
213 }
214
215 /* Fill Wifi sar related ACPI structures */
216 if (CONFIG(USE_SAR))
217 emit_sar_acpi_structures();
218
219 acpigen_pop_len(); /* Device */
220 acpigen_pop_len(); /* Scope */
221
222 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
223 dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
224}
225
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600226const char *wifi_generic_acpi_name(const struct device *dev)
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600227{
228 static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
229
Andrew McRae524bcbb2019-09-19 16:55:52 +1000230 /* ACPI 6.3, ASL 20.2.2: (Name Objects Encoding). */
231 snprintf(wifi_acpi_name, sizeof(wifi_acpi_name), "WF%02X",
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600232 (dev_path_encode(dev) & 0xff));
233 return wifi_acpi_name;
234}
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600235
236static void wifi_generic_fill_ssdt_generator(const struct device *dev)
237{
238 wifi_generic_fill_ssdt(dev, dev->chip_info);
239}
240
Furquan Shaikh54b27162020-10-03 16:33:07 -0700241static void wifi_pci_dev_init(struct device *dev)
242{
243 if (pci_dev_is_wake_source(dev))
244 elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
245}
246
Furquan Shaikh7cb10342020-10-03 14:49:09 -0700247struct device_operations wifi_generic_ops = {
248 .read_resources = pci_dev_read_resources,
249 .set_resources = pci_dev_set_resources,
250 .enable_resources = pci_dev_enable_resources,
Furquan Shaikh54b27162020-10-03 16:33:07 -0700251 .init = wifi_pci_dev_init,
Furquan Shaikh7cb10342020-10-03 14:49:09 -0700252 .ops_pci = &pci_dev_ops_pci,
Karthikeyan Ramasubramanianafeb7b32020-07-23 00:25:25 -0600253 .acpi_name = wifi_generic_acpi_name,
254 .acpi_fill_ssdt = wifi_generic_fill_ssdt_generator,
255};
256
257static void wifi_generic_enable(struct device *dev)
258{
259 struct drivers_wifi_generic_config *config = dev ? dev->chip_info : NULL;
260
261 if (!config)
262 return;
263
264 dev->ops = &wifi_generic_ops;
265}
266
267struct chip_operations drivers_wifi_generic_ops = {
268 CHIP_NAME("WIFI Device")
269 .enable_dev = wifi_generic_enable
270};