This change drops maxsleep parameter from chip config and instead hardcodes the deepest sleep state from which the WiFi device can wake the system up from to SLP_TYP_S3. This is similar to how other device drivers in coreboot report _PRW property in ACPI. It relieves the users from adding another register attribute to devicetree since all mainboards configure the same value. If this changes in the future, it should be easy to bring the maxsleep config parameter back. BUG=b:169802515 BRANCH=zork Change-Id: I42131fced008da0d51f0f777b7f2d99deaf68827 Signed-off-by: Furquan Shaikh <furquan@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/46033 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Michael Niewöhner <foss@mniewoehner.de> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
271 lines
7.8 KiB
C
271 lines
7.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <acpi/acpi_device.h>
|
|
#include <acpi/acpigen.h>
|
|
#include <console/console.h>
|
|
#include <device/device.h>
|
|
#include <device/pci.h>
|
|
#include <device/pci_def.h>
|
|
#include <elog.h>
|
|
#include <sar.h>
|
|
#include <string.h>
|
|
#include <wrdd.h>
|
|
#include "chip.h"
|
|
|
|
/* WRDS Spec Revision */
|
|
#define WRDS_REVISION 0x0
|
|
|
|
/* EWRD Spec Revision */
|
|
#define EWRD_REVISION 0x0
|
|
|
|
/* WRDS Domain type */
|
|
#define WRDS_DOMAIN_TYPE_WIFI 0x7
|
|
|
|
/* EWRD Domain type */
|
|
#define EWRD_DOMAIN_TYPE_WIFI 0x7
|
|
|
|
/* WGDS Domain type */
|
|
#define WGDS_DOMAIN_TYPE_WIFI 0x7
|
|
|
|
/*
|
|
* WIFI ACPI NAME = "WF" + hex value of last 8 bits of dev_path_encode + '\0'
|
|
* The above representation returns unique and consistent name every time
|
|
* generate_wifi_acpi_name is invoked. The last 8 bits of dev_path_encode is
|
|
* chosen since it contains the bus address of the device.
|
|
*/
|
|
#define WIFI_ACPI_NAME_MAX_LEN 5
|
|
|
|
__weak
|
|
int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static void emit_sar_acpi_structures(void)
|
|
{
|
|
int i, j, package_size;
|
|
struct wifi_sar_limits sar_limits;
|
|
struct wifi_sar_delta_table *wgds;
|
|
|
|
/* Retrieve the sar limits data */
|
|
if (get_wifi_sar_limits(&sar_limits) < 0) {
|
|
printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Name ("WRDS", Package () {
|
|
* Revision,
|
|
* Package () {
|
|
* Domain Type, // 0x7:WiFi
|
|
* WiFi SAR BIOS, // BIOS SAR Enable/disable
|
|
* SAR Table Set // Set#1 of SAR Table (10 bytes)
|
|
* }
|
|
* })
|
|
*/
|
|
acpigen_write_name("WRDS");
|
|
acpigen_write_package(2);
|
|
acpigen_write_dword(WRDS_REVISION);
|
|
/* Emit 'Domain Type' + 'WiFi SAR BIOS' + 10 bytes for Set#1 */
|
|
package_size = 1 + 1 + BYTES_PER_SAR_LIMIT;
|
|
acpigen_write_package(package_size);
|
|
acpigen_write_dword(WRDS_DOMAIN_TYPE_WIFI);
|
|
acpigen_write_dword(CONFIG(SAR_ENABLE));
|
|
for (i = 0; i < BYTES_PER_SAR_LIMIT; i++)
|
|
acpigen_write_byte(sar_limits.sar_limit[0][i]);
|
|
acpigen_pop_len();
|
|
acpigen_pop_len();
|
|
|
|
/*
|
|
* Name ("EWRD", Package () {
|
|
* Revision,
|
|
* Package () {
|
|
* Domain Type, // 0x7:WiFi
|
|
* Dynamic SAR Enable, // Dynamic SAR Enable/disable
|
|
* Extended SAR sets, // Number of optional SAR table sets
|
|
* SAR Table Set, // Set#2 of SAR Table (10 bytes)
|
|
* SAR Table Set, // Set#3 of SAR Table (10 bytes)
|
|
* SAR Table Set // Set#4 of SAR Table (10 bytes)
|
|
* }
|
|
* })
|
|
*/
|
|
acpigen_write_name("EWRD");
|
|
acpigen_write_package(2);
|
|
acpigen_write_dword(EWRD_REVISION);
|
|
/*
|
|
* Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets'
|
|
* + number of bytes for Set#2 & 3 & 4
|
|
*/
|
|
package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT;
|
|
acpigen_write_package(package_size);
|
|
acpigen_write_dword(EWRD_DOMAIN_TYPE_WIFI);
|
|
acpigen_write_dword(CONFIG(DSAR_ENABLE));
|
|
acpigen_write_dword(CONFIG_DSAR_SET_NUM);
|
|
for (i = 1; i < NUM_SAR_LIMITS; i++)
|
|
for (j = 0; j < BYTES_PER_SAR_LIMIT; j++)
|
|
acpigen_write_byte(sar_limits.sar_limit[i][j]);
|
|
acpigen_pop_len();
|
|
acpigen_pop_len();
|
|
|
|
if (!CONFIG(GEO_SAR_ENABLE))
|
|
return;
|
|
|
|
/*
|
|
* Name ("WGDS", Package() {
|
|
* Revision,
|
|
* Package() {
|
|
* DomainType, // 0x7:WiFi
|
|
* WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
|
|
* WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
|
|
* WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
|
|
* WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
|
|
* WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
|
|
* WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
|
|
* WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
|
|
* WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
|
|
* WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
|
|
* WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
|
|
* WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
|
|
* WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
|
|
* WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
|
|
* WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
|
|
* WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
|
|
* WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
|
|
* WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
|
|
* WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
|
|
* }
|
|
* })
|
|
*/
|
|
|
|
wgds = &sar_limits.wgds;
|
|
acpigen_write_name("WGDS");
|
|
acpigen_write_package(2);
|
|
acpigen_write_dword(wgds->version);
|
|
/* Emit 'Domain Type' +
|
|
* Group specific delta of power (6 bytes * NUM_WGDS_SAR_GROUPS)
|
|
*/
|
|
package_size = sizeof(sar_limits.wgds.group) + 1;
|
|
acpigen_write_package(package_size);
|
|
acpigen_write_dword(WGDS_DOMAIN_TYPE_WIFI);
|
|
for (i = 0; i < SAR_NUM_WGDS_GROUPS; i++) {
|
|
acpigen_write_byte(wgds->group[i].power_max_2400mhz);
|
|
acpigen_write_byte(wgds->group[i].power_chain_a_2400mhz);
|
|
acpigen_write_byte(wgds->group[i].power_chain_b_2400mhz);
|
|
acpigen_write_byte(wgds->group[i].power_max_5200mhz);
|
|
acpigen_write_byte(wgds->group[i].power_chain_a_5200mhz);
|
|
acpigen_write_byte(wgds->group[i].power_chain_b_5200mhz);
|
|
}
|
|
|
|
acpigen_pop_len();
|
|
acpigen_pop_len();
|
|
}
|
|
|
|
void wifi_generic_fill_ssdt(const struct device *dev,
|
|
const struct drivers_wifi_generic_config *config)
|
|
{
|
|
const char *path;
|
|
u32 address;
|
|
|
|
if (!dev->enabled)
|
|
return;
|
|
|
|
path = acpi_device_path(dev->bus->dev);
|
|
if (!path)
|
|
return;
|
|
|
|
/* Device */
|
|
acpigen_write_scope(path);
|
|
acpigen_write_device(acpi_device_name(dev));
|
|
acpi_device_write_uid(dev);
|
|
|
|
if (dev->chip_ops)
|
|
acpigen_write_name_string("_DDN", dev->chip_ops->name);
|
|
|
|
/* Address */
|
|
address = PCI_SLOT(dev->path.pci.devfn) & 0xffff;
|
|
address <<= 16;
|
|
address |= PCI_FUNC(dev->path.pci.devfn) & 0xffff;
|
|
acpigen_write_name_dword("_ADR", address);
|
|
|
|
/* Wake capabilities */
|
|
if (config)
|
|
acpigen_write_PRW(config->wake, ACPI_S3);
|
|
|
|
/* Fill regulatory domain structure */
|
|
if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
|
|
/*
|
|
* Name ("WRDD", Package () {
|
|
* WRDD_REVISION, // Revision
|
|
* Package () {
|
|
* WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi
|
|
* wifi_regulatory_domain() // Country Identifier
|
|
* }
|
|
* })
|
|
*/
|
|
acpigen_write_name("WRDD");
|
|
acpigen_write_package(2);
|
|
acpigen_write_integer(WRDD_REVISION);
|
|
acpigen_write_package(2);
|
|
acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI);
|
|
acpigen_write_dword(wifi_regulatory_domain());
|
|
acpigen_pop_len();
|
|
acpigen_pop_len();
|
|
}
|
|
|
|
/* Fill Wifi sar related ACPI structures */
|
|
if (CONFIG(USE_SAR))
|
|
emit_sar_acpi_structures();
|
|
|
|
acpigen_pop_len(); /* Device */
|
|
acpigen_pop_len(); /* Scope */
|
|
|
|
printk(BIOS_INFO, "%s.%s: %s %s\n", path, acpi_device_name(dev),
|
|
dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
|
|
}
|
|
|
|
const char *wifi_generic_acpi_name(const struct device *dev)
|
|
{
|
|
static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
|
|
|
|
/* ACPI 6.3, ASL 20.2.2: (Name Objects Encoding). */
|
|
snprintf(wifi_acpi_name, sizeof(wifi_acpi_name), "WF%02X",
|
|
(dev_path_encode(dev) & 0xff));
|
|
return wifi_acpi_name;
|
|
}
|
|
|
|
static void wifi_generic_fill_ssdt_generator(const struct device *dev)
|
|
{
|
|
wifi_generic_fill_ssdt(dev, dev->chip_info);
|
|
}
|
|
|
|
static void wifi_pci_dev_init(struct device *dev)
|
|
{
|
|
if (pci_dev_is_wake_source(dev))
|
|
elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
|
|
}
|
|
|
|
struct device_operations wifi_generic_ops = {
|
|
.read_resources = pci_dev_read_resources,
|
|
.set_resources = pci_dev_set_resources,
|
|
.enable_resources = pci_dev_enable_resources,
|
|
.init = wifi_pci_dev_init,
|
|
.ops_pci = &pci_dev_ops_pci,
|
|
.acpi_name = wifi_generic_acpi_name,
|
|
.acpi_fill_ssdt = wifi_generic_fill_ssdt_generator,
|
|
};
|
|
|
|
static void wifi_generic_enable(struct device *dev)
|
|
{
|
|
struct drivers_wifi_generic_config *config = dev ? dev->chip_info : NULL;
|
|
|
|
if (!config)
|
|
return;
|
|
|
|
dev->ops = &wifi_generic_ops;
|
|
}
|
|
|
|
struct chip_operations drivers_wifi_generic_ops = {
|
|
CHIP_NAME("WIFI Device")
|
|
.enable_dev = wifi_generic_enable
|
|
};
|