diff options
Diffstat (limited to 'src/drivers')
-rw-r--r-- | src/drivers/wifi/generic/acpi.c | 215 |
1 files changed, 145 insertions, 70 deletions
diff --git a/src/drivers/wifi/generic/acpi.c b/src/drivers/wifi/generic/acpi.c index 3e3b5c1d8e..aa49be35e2 100644 --- a/src/drivers/wifi/generic/acpi.c +++ b/src/drivers/wifi/generic/acpi.c @@ -6,25 +6,14 @@ #include <console/console.h> #include <device/pci_ids.h> #include <sar.h> +#include <stdlib.h> #include <wrdd.h> #include "chip.h" #include "wifi_private.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 Domain type */ +#define DOMAIN_TYPE_WIFI 0x7 /* * WIFI ACPI NAME = "WF" + hex value of last 8 bits of dev_path_encode + '\0' @@ -34,29 +23,33 @@ */ #define WIFI_ACPI_NAME_MAX_LEN 5 -__weak int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits) +__weak int get_wifi_sar_limits(union wifi_sar_limits *sar_limits) { return -1; } -static void emit_sar_acpi_structures(const struct device *dev) +static const uint8_t *sar_fetch_set(const struct sar_profile *sar, size_t set_num) { - int i, j, package_size; - struct wifi_sar_limits sar_limits; - struct wifi_sar_delta_table *wgds; + const uint8_t *sar_table = &sar->sar_table[0]; - /* - * If device type is PCI, ensure that the device has Intel vendor ID. CBFS SAR and SAR - * ACPI tables are currently used only by Intel WiFi devices. - */ - if (dev->path.type == DEVICE_PATH_PCI && dev->vendor != PCI_VENDOR_ID_INTEL) - return; + return sar_table + (sar->chains_count * sar->subbands_count * set_num); +} - /* Retrieve the sar limits data */ - if (get_wifi_sar_limits(&sar_limits) < 0) { - printk(BIOS_DEBUG, "failed from getting SAR limits!\n"); +static const uint8_t *wgds_fetch_set(struct geo_profile *wgds, size_t set_num) +{ + const uint8_t *wgds_table = &wgds->wgds_table[0]; + + return wgds_table + (wgds->bands_count * set_num); +} + +static void sar_emit_wrds(const struct sar_profile *sar) +{ + int i; + size_t package_size, table_size; + const uint8_t *set; + + if (sar == NULL) return; - } /* * Name ("WRDS", Package () { @@ -64,22 +57,42 @@ static void emit_sar_acpi_structures(const struct device *dev) * Package () { * Domain Type, // 0x7:WiFi * WiFi SAR BIOS, // BIOS SAR Enable/disable - * SAR Table Set // Set#1 of SAR Table (10 bytes) + * SAR Table Set // Set#1 of SAR Table * } * }) */ + if (sar->revision > MAX_SAR_REVISION) { + printk(BIOS_ERR, "ERROR: Invalid SAR table revision: %d\n", sar->revision); + return; + } + 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_dword(sar->revision); + + table_size = sar->chains_count * sar->subbands_count; + /* Emit 'Domain Type' + 'WiFi SAR Enable' + Set#1 */ + package_size = 1 + 1 + table_size; 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(); + acpigen_write_dword(DOMAIN_TYPE_WIFI); + acpigen_write_dword(1); + + set = sar_fetch_set(sar, 0); + for (i = 0; i < table_size; i++) + acpigen_write_byte(set[i]); + + acpigen_write_package_end(); + acpigen_write_package_end(); +} + +static void sar_emit_ewrd(const struct sar_profile *sar) +{ + int i; + size_t package_size, set_num, table_size; + const uint8_t *set; + + if (sar == NULL) + return; /* * Name ("EWRD", Package () { @@ -88,31 +101,58 @@ static void emit_sar_acpi_structures(const struct device *dev) * 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) + * SAR Table Set, // Set#2 of SAR Table + * SAR Table Set, // Set#3 of SAR Table + * SAR Table Set // Set#4 of SAR Table * } * }) */ + if (sar->revision > MAX_SAR_REVISION) { + printk(BIOS_ERR, "ERROR: Invalid SAR table revision: %d\n", sar->revision); + return; + } + + if (sar->dsar_set_count == 0) { + printk(BIOS_WARNING, "WARNING: DSAR set count is 0\n"); + return; + } + acpigen_write_name("EWRD"); acpigen_write_package(2); - acpigen_write_dword(EWRD_REVISION); + acpigen_write_dword(sar->revision); + + table_size = sar->chains_count * sar->subbands_count; /* - * Emit 'Domain Type' + "Dynamic SAR Enable' + 'Extended SAR sets' + * Emit 'Domain Type' + 'Dynamic SAR Enable' + 'Extended SAR sets count' * + number of bytes for Set#2 & 3 & 4 */ - package_size = 1 + 1 + 1 + (NUM_SAR_LIMITS - 1) * BYTES_PER_SAR_LIMIT; + package_size = 1 + 1 + 1 + table_size * sar->dsar_set_count; 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)) + acpigen_write_dword(DOMAIN_TYPE_WIFI); + acpigen_write_dword(1); + acpigen_write_dword(sar->dsar_set_count); + + for (set_num = 1; set_num <= sar->dsar_set_count; set_num++) { + set = sar_fetch_set(sar, set_num); + for (i = 0; i < table_size; i++) + acpigen_write_byte(set[i]); + } + + /* wifi driver always expects 3 DSAR sets */ + for (i = 0; i < (table_size * (MAX_DSAR_SET_COUNT - sar->dsar_set_count)); i++) + acpigen_write_byte(0); + + acpigen_write_package_end(); + acpigen_write_package_end(); +} + +static void sar_emit_wgds(struct geo_profile *wgds) +{ + int i; + size_t package_size, set_num; + const uint8_t *set; + + if (wgds == NULL) return; /* @@ -126,43 +166,78 @@ static void emit_sar_acpi_structures(const struct device *dev) * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset + * WgdsWiFiSarDeltaGroup1PowerMax3, // Group 1 FCC 6000-7000 Max + * WgdsWiFiSarDeltaGroup1PowerChainA3, // Group 1 FCC 6000-7000 A Offset + * WgdsWiFiSarDeltaGroup1PowerChainB3, // Group 1 FCC 6000-7000 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 + * WgdsWiFiSarDeltaGroup2PowerMax3, // Group 2 EC Jap 6000-7000 Max + * WgdsWiFiSarDeltaGroup2PowerChainA3, // Group 2 EC Jap 6000-7000 A Offset + * WgdsWiFiSarDeltaGroup2PowerChainB3, // Group 2 EC Jap 6000-7000 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 + * WgdsWiFiSarDeltaGroup3PowerMax3, // Group 3 ROW 6000-7000 Max + * WgdsWiFiSarDeltaGroup3PowerChainA3, // Group 3 ROW 6000-7000 A Offset + * WgdsWiFiSarDeltaGroup3PowerChainB3, // Group 3 ROW 6000-7000 B Offset * } * }) */ + if (wgds->revision > MAX_GEO_OFFSET_REVISION) { + printk(BIOS_ERR, "ERROR: Invalid WGDS revision: %d\n", wgds->revision); + return; + } + + package_size = 1 + wgds->chains_count * wgds->bands_count; - wgds = &sar_limits.wgds; acpigen_write_name("WGDS"); acpigen_write_package(2); - acpigen_write_dword(wgds->version); + acpigen_write_dword(wgds->revision); /* 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_write_dword(DOMAIN_TYPE_WIFI); + + for (set_num = 0; set_num < wgds->chains_count; set_num++) { + set = wgds_fetch_set(wgds, set_num); + for (i = 0; i < wgds->bands_count; i++) + acpigen_write_byte(set[i]); + } + + acpigen_write_package_end(); + acpigen_write_package_end(); +} + +static void emit_sar_acpi_structures(const struct device *dev) +{ + union wifi_sar_limits sar_limits; + + /* + * If device type is PCI, ensure that the device has Intel vendor ID. CBFS SAR and SAR + * ACPI tables are currently used only by Intel WiFi devices. + */ + if (dev->path.type == DEVICE_PATH_PCI && dev->vendor != PCI_VENDOR_ID_INTEL) + return; + + /* Retrieve the sar limits data */ + if (get_wifi_sar_limits(&sar_limits) < 0) { + printk(BIOS_ERR, "ERROR: failed getting SAR limits!\n"); + return; } - acpigen_pop_len(); - acpigen_pop_len(); + sar_emit_wrds(sar_limits.sar); + sar_emit_ewrd(sar_limits.sar); + sar_emit_wgds(sar_limits.wgds); + + free(sar_limits.sar); } static void wifi_ssdt_write_device(const struct device *dev, const char *path) @@ -197,7 +272,7 @@ static void wifi_ssdt_write_properties(const struct device *dev, const char *sco * Name ("WRDD", Package () { * WRDD_REVISION, // Revision * Package () { - * WRDD_DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi + * DOMAIN_TYPE_WIFI, // Domain Type, 7:WiFi * wifi_regulatory_domain() // Country Identifier * } * }) @@ -206,7 +281,7 @@ static void wifi_ssdt_write_properties(const struct device *dev, const char *sco acpigen_write_package(2); acpigen_write_integer(WRDD_REVISION); acpigen_write_package(2); - acpigen_write_dword(WRDD_DOMAIN_TYPE_WIFI); + acpigen_write_dword(DOMAIN_TYPE_WIFI); acpigen_write_dword(wifi_regulatory_domain()); acpigen_pop_len(); acpigen_pop_len(); |