blob: fe2e39d29d84c01a06a552377e02863f249deb66 [file] [log] [blame]
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -06001/*
2 * This file is part of the coreboot project.
3 *
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -06004 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 or (at your option)
7 * any later version of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <arch/acpi_device.h>
16#include <arch/acpigen.h>
17#include <console/console.h>
18#include <device/device.h>
19#include <device/pci_def.h>
20#include <sar.h>
21#include <string.h>
22#include <wrdd.h>
23#include "generic_wifi.h"
24
25/* WRDS Spec Revision */
26#define WRDS_REVISION 0x0
27
28/* EWRD Spec Revision */
29#define EWRD_REVISION 0x0
30
31/* WRDS Domain type */
32#define WRDS_DOMAIN_TYPE_WIFI 0x7
33
34/* EWRD Domain type */
35#define EWRD_DOMAIN_TYPE_WIFI 0x7
36
37/* WGDS Domain type */
38#define WGDS_DOMAIN_TYPE_WIFI 0x7
39
40/*
41 * WIFI ACPI NAME = "WF" + hex value of last 8 bits of dev_path_encode + '\0'
42 * The above representation returns unique and consistent name every time
43 * generate_wifi_acpi_name is invoked. The last 8 bits of dev_path_encode is
44 * chosen since it contains the bus address of the device.
45 */
46#define WIFI_ACPI_NAME_MAX_LEN 5
47
48__weak
49int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
50{
51 return -1;
52}
53
54static void emit_sar_acpi_structures(void)
55{
56 int i, j, package_size;
57 struct wifi_sar_limits sar_limits;
58 struct wifi_sar_delta_table *wgds;
59
60 /* Retrieve the sar limits data */
61 if (get_wifi_sar_limits(&sar_limits) < 0) {
62 printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
63 return;
64 }
65
66 /*
67 * Name ("WRDS", Package () {
68 * Revision,
69 * Package () {
70 * Domain Type, // 0x7:WiFi
71 * WiFi SAR BIOS, // BIOS SAR Enable/disable
72 * SAR Table Set // Set#1 of SAR Table (10 bytes)
73 * }
74 * })
75 */
76 acpigen_write_name("WRDS");
77 acpigen_write_package(2);
78 acpigen_write_dword(WRDS_REVISION);
79 /* Emit 'Domain Type' + 'WiFi SAR BIOS' + 10 bytes for Set#1 */
80 package_size = 1 + 1 + BYTES_PER_SAR_LIMIT;
81 acpigen_write_package(package_size);
82 acpigen_write_dword(WRDS_DOMAIN_TYPE_WIFI);
83 acpigen_write_dword(CONFIG(SAR_ENABLE));
84 for (i = 0; i < BYTES_PER_SAR_LIMIT; i++)
85 acpigen_write_byte(sar_limits.sar_limit[0][i]);
86 acpigen_pop_len();
87 acpigen_pop_len();
88
89 /*
90 * Name ("EWRD", Package () {
91 * Revision,
92 * Package () {
93 * Domain Type, // 0x7:WiFi
94 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
95 * Extended SAR sets, // Number of optional SAR table sets
96 * SAR Table Set, // Set#2 of SAR Table (10 bytes)
97 * SAR Table Set, // Set#3 of SAR Table (10 bytes)
98 * SAR Table Set // Set#4 of SAR Table (10 bytes)
99 * }
100 * })
101 */
102 acpigen_write_name("EWRD");
103 acpigen_write_package(2);
104 acpigen_write_dword(EWRD_REVISION);
105 /*
106 * Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets'
107 * + number of bytes for Set#2 & 3 & 4
108 */
109 package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT;
110 acpigen_write_package(package_size);
111 acpigen_write_dword(EWRD_DOMAIN_TYPE_WIFI);
112 acpigen_write_dword(CONFIG(DSAR_ENABLE));
113 acpigen_write_dword(CONFIG_DSAR_SET_NUM);
114 for (i = 1; i < NUM_SAR_LIMITS; i++)
115 for (j = 0; j < BYTES_PER_SAR_LIMIT; j++)
116 acpigen_write_byte(sar_limits.sar_limit[i][j]);
117 acpigen_pop_len();
118 acpigen_pop_len();
119
120
121 if (!CONFIG(GEO_SAR_ENABLE))
122 return;
123
124 /*
125 * Name ("WGDS", Package() {
126 * Revision,
127 * Package() {
128 * DomainType, // 0x7:WiFi
129 * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
130 * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
131 * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
132 * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
133 * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
134 * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
135 * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
136 * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
137 * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
138 * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
139 * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
140 * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
141 * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
142 * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
143 * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
144 * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
145 * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
146 * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
147 * }
148 * })
149 */
150
151 wgds = &sar_limits.wgds;
152 acpigen_write_name("WGDS");
153 acpigen_write_package(2);
154 acpigen_write_dword(wgds->version);
155 /* Emit 'Domain Type' +
156 * Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
157 */
158 package_size = sizeof(sar_limits.wgds.group) + 1;
159 acpigen_write_package(package_size);
160 acpigen_write_dword(WGDS_DOMAIN_TYPE_WIFI);
161 for (i = 0; i < SAR_NUM_WGDS_GROUPS; i++) {
162 acpigen_write_byte(wgds->group[i].power_max_2400mhz);
163 acpigen_write_byte(wgds->group[i].power_chain_a_2400mhz);
164 acpigen_write_byte(wgds->group[i].power_chain_b_2400mhz);
165 acpigen_write_byte(wgds->group[i].power_max_5200mhz);
166 acpigen_write_byte(wgds->group[i].power_chain_a_5200mhz);
167 acpigen_write_byte(wgds->group[i].power_chain_b_5200mhz);
168 }
169
170 acpigen_pop_len();
171 acpigen_pop_len();
172}
173
174void generic_wifi_fill_ssdt(struct device *dev,
175 const struct generic_wifi_config *config)
176{
177 const char *path;
178 u32 address;
179
180 if (!dev->enabled)
181 return;
182
183 path = acpi_device_path(dev->bus->dev);
184 if (!path)
185 return;
186
187 /* Device */
188 acpigen_write_scope(path);
189 acpigen_write_device(acpi_device_name(dev));
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100190 acpi_device_write_uid(dev);
191
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600192 if (dev->chip_ops)
193 acpigen_write_name_string("_DDN", dev->chip_ops->name);
194
195 /* Address */
196 address = PCI_SLOT(dev->path.pci.devfn) & 0xffff;
197 address <<= 16;
198 address |= PCI_FUNC(dev->path.pci.devfn) & 0xffff;
199 acpigen_write_name_dword("_ADR", address);
200
201 /* Wake capabilities */
202 if (config)
203 acpigen_write_PRW(config->wake, config->maxsleep);
204
205 /* Fill regulatory domain structure */
206 if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
207 /*
208 * Name ("WRDD", Package () {
209 * WRDD_REVISION, // Revision
210 * Package () {
211 * WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
212 * wifi_regulatory_domain() // Country Identifier
213 * }
214 * })
215 */
216 acpigen_write_name("WRDD");
217 acpigen_write_package(2);
218 acpigen_write_integer(WRDD_REVISION);
219 acpigen_write_package(2);
220 acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI);
221 acpigen_write_dword(wifi_regulatory_domain());
222 acpigen_pop_len();
223 acpigen_pop_len();
224 }
225
226 /* Fill Wifi sar related ACPI structures */
227 if (CONFIG(USE_SAR))
228 emit_sar_acpi_structures();
229
230 acpigen_pop_len(); /* Device */
231 acpigen_pop_len(); /* Scope */
232
233 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
234 dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
235}
236
237const char *generic_wifi_acpi_name(const struct device *dev)
238{
239 static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
240
Andrew McRae524bcbb2019-09-19 16:55:52 +1000241 /* ACPI 6.3, ASL 20.2.2: (Name Objects Encoding). */
242 snprintf(wifi_acpi_name, sizeof(wifi_acpi_name), "WF%02X",
Karthikeyan Ramasubramanianfd5d7882019-05-29 15:09:42 -0600243 (dev_path_encode(dev) & 0xff));
244 return wifi_acpi_name;
245}