diff options
Diffstat (limited to 'src/drivers/wifi')
-rw-r--r-- | src/drivers/wifi/generic/Kconfig | 23 | ||||
-rw-r--r-- | src/drivers/wifi/generic/Makefile.mk | 11 | ||||
-rw-r--r-- | src/drivers/wifi/generic/acpi.c | 14 | ||||
-rw-r--r-- | src/drivers/wifi/generic/mtcl.c | 166 |
4 files changed, 213 insertions, 1 deletions
diff --git a/src/drivers/wifi/generic/Kconfig b/src/drivers/wifi/generic/Kconfig index 1d0e19f005..814059e6df 100644 --- a/src/drivers/wifi/generic/Kconfig +++ b/src/drivers/wifi/generic/Kconfig @@ -14,6 +14,15 @@ config DRIVERS_INTEL_WIFI When enabled, add identifiers in ACPI and SMBIOS tables to make OS drivers work with certain Intel PCI-e WiFi chipsets. +config DRIVERS_MTK_WIFI + bool "Support MediaTek PCI-e WiFi adapters" + depends on PCI + default y if PCIEXP_PLUGIN_SUPPORT + select DRIVERS_WIFI_GENERIC + help + When enabled, add identifiers in ACPI tables to make OS + drivers work with certain MediaTek PCI-e WiFi chipsets. + if DRIVERS_WIFI_GENERIC config USE_SAR @@ -50,3 +59,17 @@ config DSAR_SET_NUM There can be up to 3 optional SAR table sets. endif # DRIVERS_WIFI_GENERIC + +config USE_MTCL + bool + default n + depends on DRIVERS_MTK_WIFI + help + When enabled, adds the MTCL function for MediaTek WiFi chipsets. + This function supplies country list information used to enable or + disable operation on 5.9GHz and 6GHz bands. + +config WIFI_MTCL_CBFS_FILEPATH + string "The cbfs file which has WIFI MTCL defaults" + depends on USE_MTCL + default "" diff --git a/src/drivers/wifi/generic/Makefile.mk b/src/drivers/wifi/generic/Makefile.mk index 337b8fe1ec..2231115f76 100644 --- a/src/drivers/wifi/generic/Makefile.mk +++ b/src/drivers/wifi/generic/Makefile.mk @@ -8,6 +8,7 @@ romstage-y += generic.c ramstage-y += generic.c ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c +ramstage-$(CONFIG_USE_MTCL) += mtcl.c CONFIG_WIFI_SAR_CBFS_FILEPATH := $(call strip_quotes,$(CONFIG_WIFI_SAR_CBFS_FILEPATH)) @@ -19,4 +20,14 @@ wifi_sar_defaults.hex-type := raw endif +CONFIG_MTCL_CBFS_FILEPATH := $(call strip_quotes,$(CONFIG_MTCL_CBFS_FILEPATH)) + +ifneq ($(CONFIG_MTCL_CBFS_FILEPATH),) + +cbfs-files-$(CONFIG_USE_MTCL) += wifi_mtcl.bin +wifi_mtcl.bin-file := $(CONFIG_MTCL_CBFS_FILEPATH) +wifi_mtcl.bin-type := raw + +endif + endif diff --git a/src/drivers/wifi/generic/acpi.c b/src/drivers/wifi/generic/acpi.c index 6abad83f85..9e2936d037 100644 --- a/src/drivers/wifi/generic/acpi.c +++ b/src/drivers/wifi/generic/acpi.c @@ -5,6 +5,7 @@ #include <acpi/acpigen_pci.h> #include <console/console.h> #include <device/pci_ids.h> +#include <mtcl.h> #include <sar.h> #include <stdlib.h> #include <wrdd.h> @@ -576,7 +577,18 @@ static void wifi_ssdt_write_properties(const struct device *dev, const char *sco acpigen_write_dsm_uuid_arr(dsm_ids, dsm_count); - acpigen_pop_len(); /* Scope */ + /* + * Fill MediaTek MTCL related ACPI structure iff the device type is PCI, + * the device has the MediaTek vendor ID, and the MTCL feature is + * configured. + */ + if (CONFIG(USE_MTCL)) { + if (dev->path.type == DEVICE_PATH_PCI && + dev->vendor == PCI_VID_MEDIATEK) + write_mtcl_function(); + } + + acpigen_write_scope_end(); /* Scope */ printk(BIOS_INFO, "%s: %s %s\n", scope, dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev)); diff --git a/src/drivers/wifi/generic/mtcl.c b/src/drivers/wifi/generic/mtcl.c new file mode 100644 index 0000000000..4604f8dd1c --- /dev/null +++ b/src/drivers/wifi/generic/mtcl.c @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpigen.h> +#include <cbfs.h> +#include <mtcl.h> +#include <stdint.h> +#include <string.h> + +#define WIFI_MTCL_CBFS_DEFAULT_FILENAME "wifi_mtcl.bin" +#define MAX_VERSION 2 +#define MAX_SUPPORT_STATE 2 +#define COUNTRY_LIST_SIZE 6 +#define NAME_SIZE 4 +#define MTCL_NAME "MTCL" + +/* + * Represent the structured MTCL data. + * This struct is used to cast from an array of uint8_t in order to help + * understand the semantic purpose of individual bytes. This struct is used in + * order to verify that the bytes included match the known MTCL data format. + * This struct is explicitly __packed because it is explicitly cast to from an + * array of uint8_t. + */ +struct wifi_mtcl { + uint8_t name[NAME_SIZE]; + uint8_t revision; + uint8_t support_6ghz; + uint8_t country_list_6ghz[COUNTRY_LIST_SIZE]; + uint8_t support_5p9ghz; + uint8_t country_list_5p9ghz[COUNTRY_LIST_SIZE]; +} __packed; + +void write_mtcl_aml(uint8_t *bytes, size_t count); +int validate_mtcl(uint8_t *mtcl_bytes, size_t count); + +/* + * Generate ACPI AML code for MTCL method. + * This function takes as input an array of bytes that correspond to the value + * map to be passed as a package, as well as the count of bytes to be written. + * + * AML code generate would look like: + * Method(MTCL, 0, Serialized) + * { + * Name (LIST, Package() + * { + * // data table + * }) + * Return (LIST) + * } + */ +void write_mtcl_aml(uint8_t *bytes, size_t count) +{ + /* Method (MTCL, 0, Serialized) */ + acpigen_write_method_serialized("MTCL", 0x0); + + /* Name (LIST */ + acpigen_write_name("LIST"); + + /* Package () */ + acpigen_write_package(count); + + /* Write the provided bytes. */ + for (int i = 0; i < count; ++i) + acpigen_write_byte(bytes[i]); + + acpigen_write_package_end(); /* Package */ + + /* Return MTCL */ + acpigen_write_return_namestr("LIST"); + acpigen_write_method_end(); /* Method MTCL */ +} + +/* + * Validate the WiFi MTCL data that is passed in from CBFS. + * + * Data is expected in the format: + * [Revision, + * 6GHz Support, + * 6GHz Country List, + * 5.9GHz Support, + * 5.9GHz Country List] + * + * The revision is expected to be "2". + * + * 6GHz support is a byte with the following states: + * - 0 - 6GHz operation disabled + * - 1 - 6GHz operation dictated by the country list and Operating System + * - 2 - 6GHz operation dictated by the Operating System + * + * 6GHz Country List is a set of 6 bytes that represent a bitmask of countries + * in which 6GHz operation is enabled. + * + * 5.9GHz Support is a byte with the following known states: + * - 0 - 5.9GHz operation disabled + * - 1 - 5.9GHz operation dictated by the country list and Operating System + * - 2 - 5.9GHz operation dictated by the Operating System + * + * 5.9GHz Country List is a set of 6 bytes that represent a bitmask of countries + * in which 5.9GHz operation is enabled + * + * Validation: + * - Verify that there are MTCL_SIZE bytes. + * - Verify that the name is MTCL_NAME. + * - Verify that the version is less than or equal to MAX_MTCL_VERSION. + * - Verify that the support bytes are less than or equal to the + * MAX_SUPPORT_STATE. + * + * Returns 0 for a valid file, -1 for an invalid file. + */ +int validate_mtcl(uint8_t *mtcl_bytes, size_t count) +{ + if (!mtcl_bytes) { + printk(BIOS_ERR, "Failed to get the %s file size!\n", + WIFI_MTCL_CBFS_DEFAULT_FILENAME); + return -1; + } + + if (count != sizeof(struct wifi_mtcl)) { + printk(BIOS_ERR, "Size of file read was: %zu, expected: %zu\n", + count, sizeof(struct wifi_mtcl)); + return -1; + } + + struct wifi_mtcl *mtcl = (struct wifi_mtcl *)mtcl_bytes; + + if (strncmp(((char *)mtcl->name), MTCL_NAME, NAME_SIZE)) { + printk(BIOS_ERR, "MTCL string not present but expected\n"); + return -1; + } + + if (mtcl->revision > MAX_VERSION) { + printk(BIOS_ERR, "MTCL version too high\n"); + return -1; + } + + if (mtcl->support_6ghz > MAX_SUPPORT_STATE) { + printk(BIOS_ERR, "MTCL 6GHz support state too high\n"); + return -1; + } + + if (mtcl->support_5p9ghz > MAX_SUPPORT_STATE) { + printk(BIOS_ERR, "MTCL 5.9GHz support state too high\n"); + return -1; + } + + return 0; +} + +/* + * Retrieve WiFi MTCL data from CBFS, decode it, validate it and write it to + * AML. + * + * Returns the number of bytes read. + */ +void write_mtcl_function(void) +{ + size_t mtcl_bin_len; + uint8_t *mtcl_bin; + + mtcl_bin = cbfs_map(WIFI_MTCL_CBFS_DEFAULT_FILENAME, &mtcl_bin_len); + + if (validate_mtcl(mtcl_bin, mtcl_bin_len) == 0) + write_mtcl_aml(mtcl_bin, mtcl_bin_len); + + cbfs_unmap(mtcl_bin); +} |