blob: 91c21fecff6637d331494db849f2f9c52769ac61 [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
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 or (at your option)
9 * any later version of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010015 */
16
Stefan Reinauer6a001132017-07-13 02:20:27 +020017#include <compiler.h>
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>
Robbie Zhang3dea69a2016-12-23 12:20:47 -080024#include <sar.h>
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010025#include <smbios.h>
26#include <string.h>
Duncan Laurie5c026442016-05-11 14:05:07 -070027#include <wrdd.h>
28#include "chip.h"
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010029
Kyösti Mälkki828e73e2016-07-28 17:26:39 +030030#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010031static int smbios_write_wifi(struct device *dev, int *handle,
32 unsigned long *current)
33{
34 struct smbios_type_intel_wifi {
35 u8 type;
36 u8 length;
37 u16 handle;
38 u8 str;
39 char eos[2];
Stefan Reinauer6a001132017-07-13 02:20:27 +020040 } __packed;
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010041
Duncan Laurie5c026442016-05-11 14:05:07 -070042 struct smbios_type_intel_wifi *t =
43 (struct smbios_type_intel_wifi *)*current;
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010044 int len = sizeof(struct smbios_type_intel_wifi);
45
46 memset(t, 0, sizeof(struct smbios_type_intel_wifi));
47 t->type = 0x85;
48 t->length = len - 2;
49 t->handle = *handle;
Duncan Laurie5c026442016-05-11 14:05:07 -070050 /*
51 * Intel wifi driver expects this string to be in the table 0x85
52 * with PCI IDs enumerated below.
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010053 */
54 t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");
55
56 len = t->length + smbios_string_table_len(t->eos);
57 *current += len;
58 *handle += 1;
59 return len;
60}
Kyösti Mälkki828e73e2016-07-28 17:26:39 +030061#endif
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +010062
Aaron Durbin2abbbf12017-05-04 22:26:44 -050063__attribute__((weak))
64int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
65{
66 return -1;
67}
68
Duncan Laurie5c026442016-05-11 14:05:07 -070069#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
Robbie Zhang3dea69a2016-12-23 12:20:47 -080070static void emit_sar_acpi_structures(void)
71{
72 int i, j, package_size;
73 struct wifi_sar_limits sar_limits;
74
75 /* Retrieve the sar limits data */
76 if (get_wifi_sar_limits(&sar_limits) < 0) {
77 printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
78 return;
79 }
80
81 /*
82 * Name ("WRDS", Package () {
83 * Revision,
84 * Package () {
85 * Domain Type, // 0x7:WiFi
86 * WiFi SAR BIOS, // BIOS SAR Enable/disable
87 * SAR Table Set // Set#1 of SAR Table (10 bytes)
88 * }
89 * })
90 */
91 acpigen_write_name("WRDS");
92 acpigen_write_package(2);
93 acpigen_write_dword(WRDS_REVISION);
94 /* Emit 'Domain Type' + 'WiFi SAR BIOS' + 10 bytes for Set#1 */
95 package_size = 1 + 1 + BYTES_PER_SAR_LIMIT;
96 acpigen_write_package(package_size);
97 acpigen_write_dword(WRDS_DOMAIN_TYPE_WIFI);
98 acpigen_write_dword(CONFIG_SAR_ENABLE);
99 for (i = 0; i < BYTES_PER_SAR_LIMIT; i++)
100 acpigen_write_byte(sar_limits.sar_limit[0][i]);
101 acpigen_pop_len();
102 acpigen_pop_len();
103
104 /*
105 * Name ("EWRD", Package () {
106 * Revision,
107 * Package () {
108 * Domain Type, // 0x7:WiFi
109 * Dynamic SAR Enable, // Dynamic SAR Enable/disable
110 * Extended SAR sets, // Number of optional SAR table sets
111 * SAR Table Set, // Set#2 of SAR Table (10 bytes)
112 * SAR Table Set, // Set#3 of SAR Table (10 bytes)
113 * SAR Table Set // Set#4 of SAR Table (10 bytes)
114 * }
115 * })
116 */
117 acpigen_write_name("EWRD");
118 acpigen_write_package(2);
119 acpigen_write_dword(EWRD_REVISION);
120 /*
121 * Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets'
122 * + number of bytes for Set#2 & 3 & 4
123 */
124 package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT;
125 acpigen_write_package(package_size);
126 acpigen_write_dword(EWRD_DOMAIN_TYPE_WIFI);
127 acpigen_write_dword(CONFIG_DSAR_ENABLE);
128 acpigen_write_dword(CONFIG_DSAR_SET_NUM);
129 for (i = 1; i < NUM_SAR_LIMITS; i++)
130 for (j = 0; j < BYTES_PER_SAR_LIMIT; j++)
131 acpigen_write_byte(sar_limits.sar_limit[i][j]);
132 acpigen_pop_len();
133 acpigen_pop_len();
134}
135
Duncan Laurie5c026442016-05-11 14:05:07 -0700136static void intel_wifi_fill_ssdt(struct device *dev)
137{
138 struct drivers_intel_wifi_config *config = dev->chip_info;
139 const char *path = acpi_device_path(dev->bus->dev);
140 u32 address;
141
142 if (!path)
143 return;
144
145 /* Device */
146 acpigen_write_scope(path);
147 acpigen_write_device(acpi_device_name(dev));
148 acpigen_write_name_integer("_UID", 0);
Patrick Rudolph6086b4e2017-06-07 09:39:28 +0200149 if (dev->chip_ops)
150 acpigen_write_name_string("_DDN", dev->chip_ops->name);
Duncan Laurie5c026442016-05-11 14:05:07 -0700151
152 /* Address */
153 address = PCI_SLOT(dev->path.pci.devfn) & 0xffff;
154 address <<= 16;
155 address |= PCI_FUNC(dev->path.pci.devfn) & 0xffff;
156 acpigen_write_name_dword("_ADR", address);
157
158 /* Wake capabilities */
159 if (config && config->wake)
160 acpigen_write_PRW(config->wake, 3);
161
162 /* Fill regulatory domain structure */
163 if (IS_ENABLED(CONFIG_HAVE_REGULATORY_DOMAIN)) {
164 /*
165 * Name ("WRDD", Package () {
166 * WRDD_REVISION, // Revision
167 * Package () {
168 * WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
169 * wifi_regulatory_domain() // Country Identifier
170 * }
171 * })
172 */
173 acpigen_write_name("WRDD");
174 acpigen_write_package(2);
175 acpigen_write_integer(WRDD_REVISION);
176 acpigen_write_package(2);
177 acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI);
178 acpigen_write_dword(wifi_regulatory_domain());
179 acpigen_pop_len();
180 acpigen_pop_len();
181 }
182
Robbie Zhang3dea69a2016-12-23 12:20:47 -0800183 /* Fill Wifi sar related ACPI structures */
184 if (IS_ENABLED(CONFIG_USE_SAR))
185 emit_sar_acpi_structures();
186
Duncan Laurie5c026442016-05-11 14:05:07 -0700187 acpigen_pop_len(); /* Device */
188 acpigen_pop_len(); /* Scope */
189
190 printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
Patrick Rudolph6086b4e2017-06-07 09:39:28 +0200191 dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
Duncan Laurie5c026442016-05-11 14:05:07 -0700192}
193
194static const char *intel_wifi_acpi_name(struct device *dev)
195{
196 return "WIFI";
197}
198#endif
199
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100200static struct pci_operations pci_ops = {
201 .set_subsystem = pci_dev_set_subsystem,
202};
203
204struct device_operations device_ops = {
Duncan Laurie5c026442016-05-11 14:05:07 -0700205 .read_resources = pci_dev_read_resources,
206 .set_resources = pci_dev_set_resources,
207 .enable_resources = pci_dev_enable_resources,
208 .init = pci_dev_init,
Kyösti Mälkki828e73e2016-07-28 17:26:39 +0300209#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
Duncan Laurie5c026442016-05-11 14:05:07 -0700210 .get_smbios_data = smbios_write_wifi,
Kyösti Mälkki828e73e2016-07-28 17:26:39 +0300211#endif
Duncan Laurie5c026442016-05-11 14:05:07 -0700212 .ops_pci = &pci_ops,
213#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
214 .acpi_name = &intel_wifi_acpi_name,
215 .acpi_fill_ssdt_generator = &intel_wifi_fill_ssdt,
216#endif
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100217};
218
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100219static const unsigned short pci_device_ids[] = {
220 0x0084, 0x0085, 0x0089, 0x008b, 0x008e, 0x0090,
221 0x0886, 0x0888, 0x0891, 0x0893, 0x0895, 0x088f,
222 0x4236, 0x4237, 0x4238, 0x4239, 0x423b, 0x423d,
Duncan Laurie5c026442016-05-11 14:05:07 -0700223 0x08b1, 0x08b2, /* Wilkins Peak 2 */
224 0x095a, 0x095b, /* Stone Peak 2 */
225 0
226};
Vladimir Serbinenko41f55b72014-10-31 09:10:16 +0100227
228static const struct pci_driver pch_intel_wifi __pci_driver = {
229 .ops = &device_ops,
230 .vendor = PCI_VENDOR_ID_INTEL,
231 .devices = pci_device_ids,
232};
Duncan Laurie5c026442016-05-11 14:05:07 -0700233
234static void intel_wifi_enable(struct device *dev)
235{
236 dev->ops = &device_ops;
237}
238
239struct chip_operations drivers_intel_wifi_ops = {
240 CHIP_NAME("Intel WiFi")
241 .enable_dev = &intel_wifi_enable
242};