blob: 416b04b909deae3517e0bbfd44bfe66b87478178 [file] [log] [blame]
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 Vladimir Serbinenko
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -07005 * Copyright (C) 2018 Intel Corp.
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +01006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 or (at your option)
10 * any later version of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010016 */
17
Duncan Laurie5c026442016-05-11 14:05:07 -070018#include <arch/acpi_device.h>
19#include <arch/acpigen.h>
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010020#include <console/console.h>
21#include <device/device.h>
22#include <device/pci.h>
23#include <device/pci_ids.h>
Naresh G Solanki3c6377f2017-07-03 21:57:11 +053024#include <elog.h>
Robbie Zhang3dea69a2016-12-23 12:20:47 -080025#include <sar.h>
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010026#include <smbios.h>
27#include <string.h>
Duncan Laurie5c026442016-05-11 14:05:07 -070028#include <wrdd.h>
29#include "chip.h"
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010030
Naresh G Solanki3c6377f2017-07-03 21:57:11 +053031#define PMCS_DR 0xcc
32#define PME_STS (1 << 15)
33
Kyösti Mälkki828e73e2016-07-28 17:26:39 +030034#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010035static int smbios_write_wifi(struct device *dev, int *handle,
36 unsigned long *current)
37{
38 struct smbios_type_intel_wifi {
39 u8 type;
40 u8 length;
41 u16 handle;
42 u8 str;
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +030043 u8 eos[2];
Stefan Reinauer6a001132017-07-13 02:20:27 +020044 } __packed;
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010045
Duncan Laurie5c026442016-05-11 14:05:07 -070046 struct smbios_type_intel_wifi *t =
47 (struct smbios_type_intel_wifi *)*current;
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010048 int len = sizeof(struct smbios_type_intel_wifi);
49
50 memset(t, 0, sizeof(struct smbios_type_intel_wifi));
51 t->type = 0x85;
52 t->length = len - 2;
53 t->handle = *handle;
Duncan Laurie5c026442016-05-11 14:05:07 -070054 /*
55 * Intel wifi driver expects this string to be in the table 0x85
56 * with PCI IDs enumerated below.
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010057 */
58 t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");
59
60 len = t->length + smbios_string_table_len(t->eos);
61 *current += len;
62 *handle += 1;
63 return len;
64}
Kyösti Mälkki828e73e2016-07-28 17:26:39 +030065#endif
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010066
Aaron Durbin64031672018-04-21 14:45:32 -060067__weak
Aaron Durbin2abbbf12017-05-04 22:26:44 -050068int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
69{
70 return -1;
71}
72
Duncan Laurie5c026442016-05-11 14:05:07 -070073#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
Robbie Zhang3dea69a2016-12-23 12:20:47 -080074static void emit_sar_acpi_structures(void)
75{
76 int i, j, package_size;
77 struct wifi_sar_limits sar_limits;
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070078 struct wifi_sar_delta_table *wgds;
Robbie Zhang3dea69a2016-12-23 12:20:47 -080079
80 /* Retrieve the sar limits data */
81 if (get_wifi_sar_limits(&sar_limits) < 0) {
82 printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
83 return;
84 }
85
86 /*
87 * Name ("WRDS", Package () {
88 * Revision,
89 * Package () {
90 * Domain Type, // 0x7:WiFi
91 * WiFi SAR BIOS, // BIOS SAR Enable/disable
92 * SAR Table Set // Set#1 of SAR Table (10 bytes)
93 * }
94 * })
95 */
96 acpigen_write_name("WRDS");
97 acpigen_write_package(2);
98 acpigen_write_dword(WRDS_REVISION);
99 /* Emit 'Domain Type' + 'WiFi SAR BIOS' + 10 bytes for Set#1 */
100 package_size = 1 + 1 + BYTES_PER_SAR_LIMIT;
101 acpigen_write_package(package_size);
102 acpigen_write_dword(WRDS_DOMAIN_TYPE_WIFI);
103 acpigen_write_dword(CONFIG_SAR_ENABLE);
104 for (i = 0; i < BYTES_PER_SAR_LIMIT; i++)
105 acpigen_write_byte(sar_limits.sar_limit[0][i]);
106 acpigen_pop_len();
107 acpigen_pop_len();
108
109 /*
110 * Name ("EWRD", Package () {
111 * Revision,
112 * Package () {
113 * Domain Type, // 0x7:WiFi
114 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
115 * Extended SAR sets, // Number of optional SAR table sets
116 * SAR Table Set, // Set#2 of SAR Table (10 bytes)
117 * SAR Table Set, // Set#3 of SAR Table (10 bytes)
118 * SAR Table Set // Set#4 of SAR Table (10 bytes)
119 * }
120 * })
121 */
122 acpigen_write_name("EWRD");
123 acpigen_write_package(2);
124 acpigen_write_dword(EWRD_REVISION);
125 /*
126 * Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets'
127 * + number of bytes for Set#2 & 3 & 4
128 */
129 package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT;
130 acpigen_write_package(package_size);
131 acpigen_write_dword(EWRD_DOMAIN_TYPE_WIFI);
132 acpigen_write_dword(CONFIG_DSAR_ENABLE);
133 acpigen_write_dword(CONFIG_DSAR_SET_NUM);
134 for (i = 1; i < NUM_SAR_LIMITS; i++)
135 for (j = 0; j < BYTES_PER_SAR_LIMIT; j++)
136 acpigen_write_byte(sar_limits.sar_limit[i][j]);
137 acpigen_pop_len();
138 acpigen_pop_len();
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700139
140
141 if (!IS_ENABLED(CONFIG_GEO_SAR_ENABLE))
142 return;
143
144 /*
145 * Name ("WGDS", Package() {
146 * Revision,
147 * Package() {
148 * DomainType, // 0x7:WiFi
149 * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
150 * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
151 * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
152 * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
153 * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
154 * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
155 * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
156 * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
157 * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
158 * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
159 * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
160 * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
161 * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
162 * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
163 * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
164 * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
165 * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
166 * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
167 * }
168 * })
169 */
170
171 wgds = &sar_limits.wgds;
172 acpigen_write_name("WGDS");
173 acpigen_write_package(2);
174 acpigen_write_dword(wgds->version);
175 /* Emit 'Domain Type' +
Elyes HAOUASa342f392018-10-17 10:56:26 +0200176 * Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700177 */
178 package_size = sizeof(sar_limits.wgds.group) + 1;
179 acpigen_write_package(package_size);
180 acpigen_write_dword(WGDS_DOMAIN_TYPE_WIFI);
181 for (i = 0; i < SAR_NUM_WGDS_GROUPS; i++) {
182 acpigen_write_byte(wgds->group[i].power_max_2400mhz);
183 acpigen_write_byte(wgds->group[i].power_chain_a_2400mhz);
184 acpigen_write_byte(wgds->group[i].power_chain_b_2400mhz);
185 acpigen_write_byte(wgds->group[i].power_max_5200mhz);
186 acpigen_write_byte(wgds->group[i].power_chain_a_5200mhz);
187 acpigen_write_byte(wgds->group[i].power_chain_b_5200mhz);
188 }
189
190 acpigen_pop_len();
191 acpigen_pop_len();
Robbie Zhang3dea69a2016-12-23 12:20:47 -0800192}
193
Duncan Laurie5c026442016-05-11 14:05:07 -0700194static void intel_wifi_fill_ssdt(struct device *dev)
195{
196 struct drivers_intel_wifi_config *config = dev->chip_info;
197 const char *path = acpi_device_path(dev->bus->dev);
198 u32 address;
199
Furquan Shaikh11d0c322018-08-08 13:33:08 -0700200 if (!path || !dev->enabled)
Duncan Laurie5c026442016-05-11 14:05:07 -0700201 return;
202
203 /* Device */
204 acpigen_write_scope(path);
205 acpigen_write_device(acpi_device_name(dev));
206 acpigen_write_name_integer("_UID", 0);
Patrick Rudolph6086b4e2017-06-07 09:39:28 +0200207 if (dev->chip_ops)
208 acpigen_write_name_string("_DDN", dev->chip_ops->name);
Duncan Laurie5c026442016-05-11 14:05:07 -0700209
210 /* Address */
211 address = PCI_SLOT(dev->path.pci.devfn) & 0xffff;
212 address <<= 16;
213 address |= PCI_FUNC(dev->path.pci.devfn) & 0xffff;
214 acpigen_write_name_dword("_ADR", address);
215
216 /* Wake capabilities */
217 if (config && config->wake)
218 acpigen_write_PRW(config->wake, 3);
219
220 /* Fill regulatory domain structure */
221 if (IS_ENABLED(CONFIG_HAVE_REGULATORY_DOMAIN)) {
222 /*
223 * Name ("WRDD", Package () {
224 * WRDD_REVISION, // Revision
225 * Package () {
226 * WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
227 * wifi_regulatory_domain() // Country Identifier
228 * }
229 * })
230 */
231 acpigen_write_name("WRDD");
232 acpigen_write_package(2);
233 acpigen_write_integer(WRDD_REVISION);
234 acpigen_write_package(2);
235 acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI);
236 acpigen_write_dword(wifi_regulatory_domain());
237 acpigen_pop_len();
238 acpigen_pop_len();
239 }
240
Robbie Zhang3dea69a2016-12-23 12:20:47 -0800241 /* Fill Wifi sar related ACPI structures */
242 if (IS_ENABLED(CONFIG_USE_SAR))
243 emit_sar_acpi_structures();
244
Duncan Laurie5c026442016-05-11 14:05:07 -0700245 acpigen_pop_len(); /* Device */
246 acpigen_pop_len(); /* Scope */
247
248 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
Patrick Rudolph6086b4e2017-06-07 09:39:28 +0200249 dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
Duncan Laurie5c026442016-05-11 14:05:07 -0700250}
251
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600252static const char *intel_wifi_acpi_name(const struct device *dev)
Duncan Laurie5c026442016-05-11 14:05:07 -0700253{
254 return "WIFI";
255}
256#endif
257
Gaggery Tsai3afb84a2018-12-28 10:26:44 -0800258static void pci_dev_apply_quirks(struct device *dev)
259{
260 unsigned int cap;
261 uint16_t val;
262 struct device *root = dev->bus->dev;
263
264 switch (dev->device) {
265 case PCI_DEVICE_ID_TP_9260_SERIES_WIFI:
266 cap = pci_find_capability(root, PCI_CAP_ID_PCIE);
267 /* Check the LTR for root port and enable it */
268 if (cap) {
269 val = pci_read_config16(root, cap +
270 PCI_EXP_DEV_CAP2_OFFSET);
271 if (val & LTR_MECHANISM_SUPPORT) {
272 val = pci_read_config16(root, cap +
273 PCI_EXP_DEV_CTL_STS2_CAP_OFFSET);
274 val |= LTR_MECHANISM_EN;
275 pci_write_config16(root, cap +
276 PCI_EXP_DEV_CTL_STS2_CAP_OFFSET, val);
277 }
278 }
279 }
280}
281
Naresh G Solanki3c6377f2017-07-03 21:57:11 +0530282static void wifi_pci_dev_init(struct device *dev)
283{
284 pci_dev_init(dev);
Gaggery Tsai3afb84a2018-12-28 10:26:44 -0800285 pci_dev_apply_quirks(dev);
Naresh G Solanki3c6377f2017-07-03 21:57:11 +0530286
287 if (IS_ENABLED(CONFIG_ELOG)) {
288 uint32_t val;
289 val = pci_read_config16(dev, PMCS_DR);
290 if (val & PME_STS)
291 elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
Elyes HAOUAS88607a42018-10-05 10:36:45 +0200292 }
Naresh G Solanki3c6377f2017-07-03 21:57:11 +0530293}
294
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100295static struct pci_operations pci_ops = {
296 .set_subsystem = pci_dev_set_subsystem,
297};
298
299struct device_operations device_ops = {
Duncan Laurie5c026442016-05-11 14:05:07 -0700300 .read_resources = pci_dev_read_resources,
301 .set_resources = pci_dev_set_resources,
302 .enable_resources = pci_dev_enable_resources,
Naresh G Solanki3c6377f2017-07-03 21:57:11 +0530303 .init = wifi_pci_dev_init,
Kyösti Mälkki828e73e2016-07-28 17:26:39 +0300304#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
Duncan Laurie5c026442016-05-11 14:05:07 -0700305 .get_smbios_data = smbios_write_wifi,
Kyösti Mälkki828e73e2016-07-28 17:26:39 +0300306#endif
Duncan Laurie5c026442016-05-11 14:05:07 -0700307 .ops_pci = &pci_ops,
308#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100309 .acpi_name = intel_wifi_acpi_name,
310 .acpi_fill_ssdt_generator = intel_wifi_fill_ssdt,
Duncan Laurie5c026442016-05-11 14:05:07 -0700311#endif
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100312};
313
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100314static const unsigned short pci_device_ids[] = {
Subrata Banikf9529832018-03-22 05:25:45 +0530315 PCI_DEVICE_ID_1000_SERIES_WIFI,
316 PCI_DEVICE_ID_6005_SERIES_WIFI,
317 PCI_DEVICE_ID_6005_I_SERIES_WIFI,
318 PCI_DEVICE_ID_1030_SERIES_WIFI,
319 PCI_DEVICE_ID_6030_I_SERIES_WIFI,
320 PCI_DEVICE_ID_6030_SERIES_WIFI,
321 PCI_DEVICE_ID_6150_SERIES_WIFI,
322 PCI_DEVICE_ID_2030_SERIES_WIFI,
323 PCI_DEVICE_ID_2000_SERIES_WIFI,
324 PCI_DEVICE_ID_0135_SERIES_WIFI,
325 PCI_DEVICE_ID_0105_SERIES_WIFI,
326 PCI_DEVICE_ID_6035_SERIES_WIFI,
327 PCI_DEVICE_ID_5300_SERIES_WIFI,
328 PCI_DEVICE_ID_5100_SERIES_WIFI,
329 PCI_DEVICE_ID_6000_SERIES_WIFI,
330 PCI_DEVICE_ID_6000_I_SERIES_WIFI,
331 PCI_DEVICE_ID_5350_SERIES_WIFI,
332 PCI_DEVICE_ID_5150_SERIES_WIFI,
333 /* Wilkins Peak 2 */
334 PCI_DEVICE_ID_WP_7260_SERIES_1_WIFI,
335 PCI_DEVICE_ID_WP_7260_SERIES_2_WIFI,
336 /* Stone Peak 2 */
337 PCI_DEVICE_ID_SP_7265_SERIES_1_WIFI,
338 PCI_DEVICE_ID_SP_7265_SERIES_2_WIFI,
Subrata Banik4530af22018-09-28 22:43:10 +0530339 /* Stone Field Peak */
340 PCI_DEVICE_ID_SFP_8260_SERIES_1_WIFI,
341 PCI_DEVICE_ID_SFP_8260_SERIES_2_WIFI,
342 /* Windstorm Peak */
343 PCI_DEVICE_ID_WSP_8275_SERIES_1_WIFI,
Subrata Banikf9529832018-03-22 05:25:45 +0530344 /* Jefferson Peak */
345 PCI_DEVICE_ID_JP_9000_SERIES_1_WIFI,
346 PCI_DEVICE_ID_JP_9000_SERIES_2_WIFI,
347 PCI_DEVICE_ID_JP_9000_SERIES_3_WIFI,
Furquan Shaikh39130a42018-05-30 19:57:14 -0700348 /* Thunder Peak 2 */
349 PCI_DEVICE_ID_TP_9260_SERIES_WIFI,
Subrata Banikf9529832018-03-22 05:25:45 +0530350 /* Harrison Peak */
351 PCI_DEVICE_ID_HrP_9560_SERIES_1_WIFI,
352 PCI_DEVICE_ID_HrP_9560_SERIES_2_WIFI,
Subrata Banik71da5fe2019-02-19 12:11:26 +0530353 PCI_DEVICE_ID_HrP_9560_SERIES_3_WIFI,
Duncan Laurie5c026442016-05-11 14:05:07 -0700354 0
355};
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100356
357static const struct pci_driver pch_intel_wifi __pci_driver = {
358 .ops = &device_ops,
359 .vendor = PCI_VENDOR_ID_INTEL,
360 .devices = pci_device_ids,
361};
Duncan Laurie5c026442016-05-11 14:05:07 -0700362
363static void intel_wifi_enable(struct device *dev)
364{
365 dev->ops = &device_ops;
366}
367
368struct chip_operations drivers_intel_wifi_ops = {
369 CHIP_NAME("Intel WiFi")
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100370 .enable_dev = intel_wifi_enable
Duncan Laurie5c026442016-05-11 14:05:07 -0700371};