blob: d78b0076fa34bca006175111e208d4d65ce6e662 [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>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020023#include <device/pci_ops.h>
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010024#include <device/pci_ids.h>
Naresh G Solanki3c6377f2017-07-03 21:57:11 +053025#include <elog.h>
Robbie Zhang3dea69a2016-12-23 12:20:47 -080026#include <sar.h>
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010027#include <smbios.h>
28#include <string.h>
Duncan Laurie5c026442016-05-11 14:05:07 -070029#include <wrdd.h>
30#include "chip.h"
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010031
Naresh G Solanki3c6377f2017-07-03 21:57:11 +053032#define PMCS_DR 0xcc
33#define PME_STS (1 << 15)
34
Julius Wernercd49cce2019-03-05 16:53:33 -080035#if CONFIG(GENERATE_SMBIOS_TABLES)
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010036static int smbios_write_wifi(struct device *dev, int *handle,
37 unsigned long *current)
38{
39 struct smbios_type_intel_wifi {
40 u8 type;
41 u8 length;
42 u16 handle;
43 u8 str;
Konstantin Aladyshevd0df1d72017-08-01 15:52:46 +030044 u8 eos[2];
Stefan Reinauer6a001132017-07-13 02:20:27 +020045 } __packed;
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010046
Duncan Laurie5c026442016-05-11 14:05:07 -070047 struct smbios_type_intel_wifi *t =
48 (struct smbios_type_intel_wifi *)*current;
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010049 int len = sizeof(struct smbios_type_intel_wifi);
50
51 memset(t, 0, sizeof(struct smbios_type_intel_wifi));
52 t->type = 0x85;
53 t->length = len - 2;
54 t->handle = *handle;
Duncan Laurie5c026442016-05-11 14:05:07 -070055 /*
56 * Intel wifi driver expects this string to be in the table 0x85
57 * with PCI IDs enumerated below.
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010058 */
59 t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");
60
61 len = t->length + smbios_string_table_len(t->eos);
62 *current += len;
63 *handle += 1;
64 return len;
65}
Kyösti Mälkki828e73e2016-07-28 17:26:39 +030066#endif
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010067
Aaron Durbin64031672018-04-21 14:45:32 -060068__weak
Aaron Durbin2abbbf12017-05-04 22:26:44 -050069int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
70{
71 return -1;
72}
73
Julius Wernercd49cce2019-03-05 16:53:33 -080074#if CONFIG(HAVE_ACPI_TABLES)
Robbie Zhang3dea69a2016-12-23 12:20:47 -080075static void emit_sar_acpi_structures(void)
76{
77 int i, j, package_size;
78 struct wifi_sar_limits sar_limits;
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -070079 struct wifi_sar_delta_table *wgds;
Robbie Zhang3dea69a2016-12-23 12:20:47 -080080
81 /* Retrieve the sar limits data */
82 if (get_wifi_sar_limits(&sar_limits) < 0) {
83 printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
84 return;
85 }
86
87 /*
88 * Name ("WRDS", Package () {
89 * Revision,
90 * Package () {
91 * Domain Type, // 0x7:WiFi
92 * WiFi SAR BIOS, // BIOS SAR Enable/disable
93 * SAR Table Set // Set#1 of SAR Table (10 bytes)
94 * }
95 * })
96 */
97 acpigen_write_name("WRDS");
98 acpigen_write_package(2);
99 acpigen_write_dword(WRDS_REVISION);
100 /* Emit 'Domain Type' + 'WiFi SAR BIOS' + 10 bytes for Set#1 */
101 package_size = 1 + 1 + BYTES_PER_SAR_LIMIT;
102 acpigen_write_package(package_size);
103 acpigen_write_dword(WRDS_DOMAIN_TYPE_WIFI);
104 acpigen_write_dword(CONFIG_SAR_ENABLE);
105 for (i = 0; i < BYTES_PER_SAR_LIMIT; i++)
106 acpigen_write_byte(sar_limits.sar_limit[0][i]);
107 acpigen_pop_len();
108 acpigen_pop_len();
109
110 /*
111 * Name ("EWRD", Package () {
112 * Revision,
113 * Package () {
114 * Domain Type, // 0x7:WiFi
115 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
116 * Extended SAR sets, // Number of optional SAR table sets
117 * SAR Table Set, // Set#2 of SAR Table (10 bytes)
118 * SAR Table Set, // Set#3 of SAR Table (10 bytes)
119 * SAR Table Set // Set#4 of SAR Table (10 bytes)
120 * }
121 * })
122 */
123 acpigen_write_name("EWRD");
124 acpigen_write_package(2);
125 acpigen_write_dword(EWRD_REVISION);
126 /*
127 * Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets'
128 * + number of bytes for Set#2 & 3 & 4
129 */
130 package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT;
131 acpigen_write_package(package_size);
132 acpigen_write_dword(EWRD_DOMAIN_TYPE_WIFI);
133 acpigen_write_dword(CONFIG_DSAR_ENABLE);
134 acpigen_write_dword(CONFIG_DSAR_SET_NUM);
135 for (i = 1; i < NUM_SAR_LIMITS; i++)
136 for (j = 0; j < BYTES_PER_SAR_LIMIT; j++)
137 acpigen_write_byte(sar_limits.sar_limit[i][j]);
138 acpigen_pop_len();
139 acpigen_pop_len();
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700140
141
Julius Wernercd49cce2019-03-05 16:53:33 -0800142 if (!CONFIG(GEO_SAR_ENABLE))
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700143 return;
144
145 /*
146 * Name ("WGDS", Package() {
147 * Revision,
148 * Package() {
149 * DomainType, // 0x7:WiFi
150 * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
151 * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
152 * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
153 * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
154 * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
155 * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
156 * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
157 * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
158 * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
159 * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
160 * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
161 * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
162 * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
163 * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
164 * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
165 * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
166 * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
167 * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
168 * }
169 * })
170 */
171
172 wgds = &sar_limits.wgds;
173 acpigen_write_name("WGDS");
174 acpigen_write_package(2);
175 acpigen_write_dword(wgds->version);
176 /* Emit 'Domain Type' +
Elyes HAOUASa342f392018-10-17 10:56:26 +0200177 * Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
Pratik Prajapati7fd1e4b2017-08-11 14:06:57 -0700178 */
179 package_size = sizeof(sar_limits.wgds.group) + 1;
180 acpigen_write_package(package_size);
181 acpigen_write_dword(WGDS_DOMAIN_TYPE_WIFI);
182 for (i = 0; i < SAR_NUM_WGDS_GROUPS; i++) {
183 acpigen_write_byte(wgds->group[i].power_max_2400mhz);
184 acpigen_write_byte(wgds->group[i].power_chain_a_2400mhz);
185 acpigen_write_byte(wgds->group[i].power_chain_b_2400mhz);
186 acpigen_write_byte(wgds->group[i].power_max_5200mhz);
187 acpigen_write_byte(wgds->group[i].power_chain_a_5200mhz);
188 acpigen_write_byte(wgds->group[i].power_chain_b_5200mhz);
189 }
190
191 acpigen_pop_len();
192 acpigen_pop_len();
Robbie Zhang3dea69a2016-12-23 12:20:47 -0800193}
194
Duncan Laurie5c026442016-05-11 14:05:07 -0700195static void intel_wifi_fill_ssdt(struct device *dev)
196{
197 struct drivers_intel_wifi_config *config = dev->chip_info;
198 const char *path = acpi_device_path(dev->bus->dev);
199 u32 address;
200
Furquan Shaikh11d0c322018-08-08 13:33:08 -0700201 if (!path || !dev->enabled)
Duncan Laurie5c026442016-05-11 14:05:07 -0700202 return;
203
204 /* Device */
205 acpigen_write_scope(path);
206 acpigen_write_device(acpi_device_name(dev));
207 acpigen_write_name_integer("_UID", 0);
Patrick Rudolph6086b4e2017-06-07 09:39:28 +0200208 if (dev->chip_ops)
209 acpigen_write_name_string("_DDN", dev->chip_ops->name);
Duncan Laurie5c026442016-05-11 14:05:07 -0700210
211 /* Address */
212 address = PCI_SLOT(dev->path.pci.devfn) & 0xffff;
213 address <<= 16;
214 address |= PCI_FUNC(dev->path.pci.devfn) & 0xffff;
215 acpigen_write_name_dword("_ADR", address);
216
217 /* Wake capabilities */
218 if (config && config->wake)
219 acpigen_write_PRW(config->wake, 3);
220
221 /* Fill regulatory domain structure */
Julius Wernercd49cce2019-03-05 16:53:33 -0800222 if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
Duncan Laurie5c026442016-05-11 14:05:07 -0700223 /*
224 * Name ("WRDD", Package () {
225 * WRDD_REVISION, // Revision
226 * Package () {
227 * WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
228 * wifi_regulatory_domain() // Country Identifier
229 * }
230 * })
231 */
232 acpigen_write_name("WRDD");
233 acpigen_write_package(2);
234 acpigen_write_integer(WRDD_REVISION);
235 acpigen_write_package(2);
236 acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI);
237 acpigen_write_dword(wifi_regulatory_domain());
238 acpigen_pop_len();
239 acpigen_pop_len();
240 }
241
Robbie Zhang3dea69a2016-12-23 12:20:47 -0800242 /* Fill Wifi sar related ACPI structures */
Julius Wernercd49cce2019-03-05 16:53:33 -0800243 if (CONFIG(USE_SAR))
Robbie Zhang3dea69a2016-12-23 12:20:47 -0800244 emit_sar_acpi_structures();
245
Duncan Laurie5c026442016-05-11 14:05:07 -0700246 acpigen_pop_len(); /* Device */
247 acpigen_pop_len(); /* Scope */
248
249 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
Patrick Rudolph6086b4e2017-06-07 09:39:28 +0200250 dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
Duncan Laurie5c026442016-05-11 14:05:07 -0700251}
252
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600253static const char *intel_wifi_acpi_name(const struct device *dev)
Duncan Laurie5c026442016-05-11 14:05:07 -0700254{
255 return "WIFI";
256}
257#endif
258
Naresh G Solanki3c6377f2017-07-03 21:57:11 +0530259static void wifi_pci_dev_init(struct device *dev)
260{
261 pci_dev_init(dev);
262
Julius Wernercd49cce2019-03-05 16:53:33 -0800263 if (CONFIG(ELOG)) {
Naresh G Solanki3c6377f2017-07-03 21:57:11 +0530264 uint32_t val;
265 val = pci_read_config16(dev, PMCS_DR);
266 if (val & PME_STS)
267 elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
Elyes HAOUAS88607a42018-10-05 10:36:45 +0200268 }
Naresh G Solanki3c6377f2017-07-03 21:57:11 +0530269}
270
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100271static struct pci_operations pci_ops = {
272 .set_subsystem = pci_dev_set_subsystem,
273};
274
275struct device_operations device_ops = {
Duncan Laurie5c026442016-05-11 14:05:07 -0700276 .read_resources = pci_dev_read_resources,
277 .set_resources = pci_dev_set_resources,
278 .enable_resources = pci_dev_enable_resources,
Naresh G Solanki3c6377f2017-07-03 21:57:11 +0530279 .init = wifi_pci_dev_init,
Julius Wernercd49cce2019-03-05 16:53:33 -0800280#if CONFIG(GENERATE_SMBIOS_TABLES)
Duncan Laurie5c026442016-05-11 14:05:07 -0700281 .get_smbios_data = smbios_write_wifi,
Kyösti Mälkki828e73e2016-07-28 17:26:39 +0300282#endif
Duncan Laurie5c026442016-05-11 14:05:07 -0700283 .ops_pci = &pci_ops,
Julius Wernercd49cce2019-03-05 16:53:33 -0800284#if CONFIG(HAVE_ACPI_TABLES)
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100285 .acpi_name = intel_wifi_acpi_name,
286 .acpi_fill_ssdt_generator = intel_wifi_fill_ssdt,
Duncan Laurie5c026442016-05-11 14:05:07 -0700287#endif
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100288};
289
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100290static const unsigned short pci_device_ids[] = {
Subrata Banikf9529832018-03-22 05:25:45 +0530291 PCI_DEVICE_ID_1000_SERIES_WIFI,
292 PCI_DEVICE_ID_6005_SERIES_WIFI,
293 PCI_DEVICE_ID_6005_I_SERIES_WIFI,
294 PCI_DEVICE_ID_1030_SERIES_WIFI,
295 PCI_DEVICE_ID_6030_I_SERIES_WIFI,
296 PCI_DEVICE_ID_6030_SERIES_WIFI,
297 PCI_DEVICE_ID_6150_SERIES_WIFI,
298 PCI_DEVICE_ID_2030_SERIES_WIFI,
299 PCI_DEVICE_ID_2000_SERIES_WIFI,
300 PCI_DEVICE_ID_0135_SERIES_WIFI,
301 PCI_DEVICE_ID_0105_SERIES_WIFI,
302 PCI_DEVICE_ID_6035_SERIES_WIFI,
303 PCI_DEVICE_ID_5300_SERIES_WIFI,
304 PCI_DEVICE_ID_5100_SERIES_WIFI,
305 PCI_DEVICE_ID_6000_SERIES_WIFI,
306 PCI_DEVICE_ID_6000_I_SERIES_WIFI,
307 PCI_DEVICE_ID_5350_SERIES_WIFI,
308 PCI_DEVICE_ID_5150_SERIES_WIFI,
309 /* Wilkins Peak 2 */
310 PCI_DEVICE_ID_WP_7260_SERIES_1_WIFI,
311 PCI_DEVICE_ID_WP_7260_SERIES_2_WIFI,
312 /* Stone Peak 2 */
313 PCI_DEVICE_ID_SP_7265_SERIES_1_WIFI,
314 PCI_DEVICE_ID_SP_7265_SERIES_2_WIFI,
Subrata Banik4530af22018-09-28 22:43:10 +0530315 /* Stone Field Peak */
316 PCI_DEVICE_ID_SFP_8260_SERIES_1_WIFI,
317 PCI_DEVICE_ID_SFP_8260_SERIES_2_WIFI,
318 /* Windstorm Peak */
319 PCI_DEVICE_ID_WSP_8275_SERIES_1_WIFI,
Subrata Banikf9529832018-03-22 05:25:45 +0530320 /* Jefferson Peak */
321 PCI_DEVICE_ID_JP_9000_SERIES_1_WIFI,
322 PCI_DEVICE_ID_JP_9000_SERIES_2_WIFI,
323 PCI_DEVICE_ID_JP_9000_SERIES_3_WIFI,
Furquan Shaikh39130a42018-05-30 19:57:14 -0700324 /* Thunder Peak 2 */
325 PCI_DEVICE_ID_TP_9260_SERIES_WIFI,
Subrata Banikf9529832018-03-22 05:25:45 +0530326 /* Harrison Peak */
327 PCI_DEVICE_ID_HrP_9560_SERIES_1_WIFI,
328 PCI_DEVICE_ID_HrP_9560_SERIES_2_WIFI,
Subrata Banik71da5fe2019-02-19 12:11:26 +0530329 PCI_DEVICE_ID_HrP_9560_SERIES_3_WIFI,
Duncan Laurie5c026442016-05-11 14:05:07 -0700330 0
331};
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100332
333static const struct pci_driver pch_intel_wifi __pci_driver = {
334 .ops = &device_ops,
335 .vendor = PCI_VENDOR_ID_INTEL,
336 .devices = pci_device_ids,
337};
Duncan Laurie5c026442016-05-11 14:05:07 -0700338
339static void intel_wifi_enable(struct device *dev)
340{
341 dev->ops = &device_ops;
342}
343
344struct chip_operations drivers_intel_wifi_ops = {
345 CHIP_NAME("Intel WiFi")
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100346 .enable_dev = intel_wifi_enable
Duncan Laurie5c026442016-05-11 14:05:07 -0700347};