From ea8330ed819c0d0b70ebfb0ab9eaf341fd683c11 Mon Sep 17 00:00:00 2001 From: David Ruth Date: Wed, 6 Dec 2023 21:39:54 +0000 Subject: drivers/wifi: Add MTCL function to ACPI SSDT The MTCL function provides a country list to the Linux kernel via an ACPI function in SSDT for MediaTek WiFi chipsets that are capable of operating on the 6GHz band. The country list is used to selectively disable 6GHz and 5.9GHz operation based on the country the device is operating in. The function needs to read a binary file and send it as a package via the MTCL method in SSDT for PCIe WiFi with MediaTek chipsets. Change Summary: * Add src/drivers/wifi/generic/mtcl.c to abstract functionaltity related to MTCL * Add write_mtcl_aml function to convert the byte data into the format expected by the MTCL functionality in the Linux kernel. * Add validate_mtcl function to validate that the byte data read in from a file is in the expected format. * Add write_mtcl_function function to read a binary file called "wifi_mtcl".bin" from cbfs, then call validate_mtcl to verify that it is in an expected format, and if so write the aml via acpigen * Add config flag DRIVERS_MTK_WIFI to src/drivers/wifi/generic in order to include MediaTek WiFi specific functionality * Add config flag USE_MTCL which depends on DRIVERS_MTK_WIFI and enables including the specific ACPI function defined in SSDT * Add config flag CONFIG_MTCL_CBFS_FILEPATH which depends on DRIVERS_MTK_WIFI which enables configuring the file to add as "wifi_mtcl.bin" * Add a call to write_mtcl_function to src/drivers/wifi/generic/acpi.c to include the MTCL function in SSDT for MTK WiFi devices when USE_MTCL is enabled. * Add MediaTek VID to src/include/device/pci_ids.h. BUG=b:295544553 TEST=Add Kconfig entry USE_MTCL for pujjo TEST=Add wifi_mtcl_defaults.bin blob to cbfs TEST=Build coreboot for pujjo `emerge-nissa coreboot chromeos-bootimage` TEST=Verify that MTCL defined in the file is present: TEST=`acpidump -b` TEST=`iasl ssdt.dat` TEST=`less ssdt.dsl` TEST=Search for MTCL Signed-off-by: David Ruth Change-Id: I9b5e7312a44e114270e664b983626faa6cfee350 Reviewed-on: https://review.coreboot.org/c/coreboot/+/80170 Reviewed-by: Subrata Banik Reviewed-by: Martin L Roth Reviewed-by: Kapil Porwal Reviewed-by: Nico Huber Tested-by: build bot (Jenkins) Reviewed-by: Eric Lai --- src/drivers/wifi/generic/Kconfig | 23 +++++ src/drivers/wifi/generic/Makefile.mk | 11 +++ src/drivers/wifi/generic/acpi.c | 14 ++- src/drivers/wifi/generic/mtcl.c | 166 +++++++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 src/drivers/wifi/generic/mtcl.c (limited to 'src/drivers/wifi') 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 #include #include +#include #include #include #include @@ -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 +#include +#include +#include +#include + +#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); +} -- cgit v1.2.3