summaryrefslogtreecommitdiffstats
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/wifi/generic/Kconfig23
-rw-r--r--src/drivers/wifi/generic/Makefile.mk11
-rw-r--r--src/drivers/wifi/generic/acpi.c14
-rw-r--r--src/drivers/wifi/generic/mtcl.c166
4 files changed, 213 insertions, 1 deletions
diff --git a/src/drivers/wifi/generic/Kconfig b/src/drivers/wifi/generic/Kconfig
index 1d0e19f00514..814059e6df63 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 337b8fe1ec7d..2231115f7630 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 6abad83f8577..9e2936d037c1 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 000000000000..4604f8dd1c40
--- /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);
+}