From 29f5a494f7a22ab4661dc835c1d208e1a61793e7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 28 Jun 2023 15:07:18 +0800 Subject: wifi: mt76: mt7921: move acpi_sar code in mt792x-lib module Move acpi_sar code in mt792x-lib module since it is shared between mt7921 and mt7925 driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 1 + drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 1 - .../net/wireless/mediatek/mt76/mt7921/acpi_sar.c | 341 -------------------- .../net/wireless/mediatek/mt76/mt7921/acpi_sar.h | 105 ------- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 11 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 24 -- drivers/net/wireless/mediatek/mt76/mt792x.h | 23 ++ .../net/wireless/mediatek/mt76/mt792x_acpi_sar.c | 350 +++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt792x_acpi_sar.h | 105 +++++++ 11 files changed, 485 insertions(+), 480 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index d6231948dd6e..f8a1928d62b2 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -33,6 +33,7 @@ mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o mt76_connac3_mac.o mt792x-lib-y := mt792x_core.o mt792x_mac.o mt792x_trace.o \ mt792x_debugfs.o mt792x_dma.o +mt792x-lib-$(CONFIG_ACPI) += mt792x_acpi_sar.o obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index fd82dff76dae..f380ec4b6de1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_MT7921U) += mt7921u.o mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o -mt7921-common-$(CONFIG_ACPI) += acpi_sar.o mt7921e-y := pci.o pci_mac.o pci_mcu.o dma.o mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o mt7921u-y := usb.o usb_mac.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c deleted file mode 100644 index 057767ab45ff..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c +++ /dev/null @@ -1,341 +0,0 @@ -// SPDX-License-Identifier: ISC -/* Copyright (C) 2022 MediaTek Inc. */ - -#include -#include "mt7921.h" - -static int -mt7921_acpi_read(struct mt792x_dev *dev, u8 *method, u8 **tbl, u32 *len) -{ - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *sar_root, *sar_unit; - struct mt76_dev *mdev = &dev->mt76; - acpi_handle root, handle; - acpi_status status; - u32 i = 0; - int ret; - - root = ACPI_HANDLE(mdev->dev); - if (!root) - return -EOPNOTSUPP; - - status = acpi_get_handle(root, method, &handle); - if (ACPI_FAILURE(status)) - return -EIO; - - status = acpi_evaluate_object(handle, NULL, NULL, &buf); - if (ACPI_FAILURE(status)) - return -EIO; - - sar_root = buf.pointer; - if (sar_root->type != ACPI_TYPE_PACKAGE || - sar_root->package.count < 4 || - sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) { - dev_err(mdev->dev, "sar cnt = %d\n", - sar_root->package.count); - ret = -EINVAL; - goto free; - } - - if (!*tbl) { - *tbl = devm_kzalloc(mdev->dev, sar_root->package.count, - GFP_KERNEL); - if (!*tbl) { - ret = -ENOMEM; - goto free; - } - } - if (len) - *len = sar_root->package.count; - - for (i = 0; i < sar_root->package.count; i++) { - sar_unit = &sar_root->package.elements[i]; - - if (sar_unit->type != ACPI_TYPE_INTEGER) - break; - *(*tbl + i) = (u8)sar_unit->integer.value; - } - ret = (i == sar_root->package.count) ? 0 : -EINVAL; - -free: - kfree(sar_root); - - return ret; -} - -/* MTCL : Country List Table for 6G band */ -static int -mt7921_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version) -{ - *version = (mt7921_acpi_read(dev, MT7921_ACPI_MTCL, table, NULL) < 0) - ? 1 : 2; - return 0; -} - -/* MTDS : Dynamic SAR Power Table */ -static int -mt7921_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version) -{ - int len, ret, sarlen, prelen, tblcnt; - bool enable; - - ret = mt7921_acpi_read(dev, MT7921_ACPI_MTDS, table, &len); - if (ret) - return ret; - - /* Table content validation */ - switch (version) { - case 1: - enable = ((struct mt7921_asar_dyn *)*table)->enable; - sarlen = sizeof(struct mt7921_asar_dyn_limit); - prelen = sizeof(struct mt7921_asar_dyn); - break; - case 2: - enable = ((struct mt7921_asar_dyn_v2 *)*table)->enable; - sarlen = sizeof(struct mt7921_asar_dyn_limit_v2); - prelen = sizeof(struct mt7921_asar_dyn_v2); - break; - default: - return -EINVAL; - } - - tblcnt = (len - prelen) / sarlen; - if (!enable || - tblcnt > MT7921_ASAR_MAX_DYN || tblcnt < MT7921_ASAR_MIN_DYN) - ret = -EINVAL; - - return ret; -} - -/* MTGS : Geo SAR Power Table */ -static int -mt7921_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version) -{ - int len, ret = 0, sarlen, prelen, tblcnt; - - ret = mt7921_acpi_read(dev, MT7921_ACPI_MTGS, table, &len); - if (ret) - return ret; - - /* Table content validation */ - switch (version) { - case 1: - sarlen = sizeof(struct mt7921_asar_geo_limit); - prelen = sizeof(struct mt7921_asar_geo); - break; - case 2: - sarlen = sizeof(struct mt7921_asar_geo_limit_v2); - prelen = sizeof(struct mt7921_asar_geo_v2); - break; - default: - return -EINVAL; - } - - tblcnt = (len - prelen) / sarlen; - if (tblcnt > MT7921_ASAR_MAX_GEO || tblcnt < MT7921_ASAR_MIN_GEO) - ret = -EINVAL; - - return ret; -} - -/* MTFG : Flag Table */ -static int -mt7921_asar_acpi_read_mtfg(struct mt792x_dev *dev, u8 **table) -{ - int len, ret; - - ret = mt7921_acpi_read(dev, MT7921_ACPI_MTFG, table, &len); - if (ret) - return ret; - - if (len < MT7921_ASAR_MIN_FG) - ret = -EINVAL; - - return ret; -} - -int mt7921_init_acpi_sar(struct mt792x_dev *dev) -{ - struct mt7921_acpi_sar *asar; - int ret; - - asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL); - if (!asar) - return -ENOMEM; - - mt7921_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); - - /* MTDS is mandatory. Return error if table is invalid */ - ret = mt7921_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver); - if (ret) { - devm_kfree(dev->mt76.dev, asar->dyn); - devm_kfree(dev->mt76.dev, asar->countrylist); - devm_kfree(dev->mt76.dev, asar); - return ret; - } - - /* MTGS is optional */ - ret = mt7921_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver); - if (ret) { - devm_kfree(dev->mt76.dev, asar->geo); - asar->geo = NULL; - } - - /* MTFG is optional */ - ret = mt7921_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg); - if (ret) { - devm_kfree(dev->mt76.dev, asar->fg); - asar->fg = NULL; - } - dev->phy.acpisar = asar; - - return 0; -} - -static s8 -mt7921_asar_get_geo_pwr(struct mt792x_phy *phy, - enum nl80211_band band, s8 dyn_power) -{ - struct mt7921_acpi_sar *asar = phy->acpisar; - struct mt7921_asar_geo_band *band_pwr; - s8 geo_power; - u8 idx, max; - - if (!asar->geo) - return dyn_power; - - switch (phy->mt76->dev->region) { - case NL80211_DFS_FCC: - idx = 0; - break; - case NL80211_DFS_ETSI: - idx = 1; - break; - default: /* WW */ - idx = 2; - break; - } - - if (asar->ver == 1) { - band_pwr = &asar->geo->tbl[idx].band[0]; - max = ARRAY_SIZE(asar->geo->tbl[idx].band); - } else { - band_pwr = &asar->geo_v2->tbl[idx].band[0]; - max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band); - } - - switch (band) { - case NL80211_BAND_2GHZ: - idx = 0; - break; - case NL80211_BAND_5GHZ: - idx = 1; - break; - case NL80211_BAND_6GHZ: - idx = 2; - break; - default: - return dyn_power; - } - - if (idx >= max) - return dyn_power; - - geo_power = (band_pwr + idx)->pwr; - dyn_power += (band_pwr + idx)->offset; - - return min(geo_power, dyn_power); -} - -static s8 -mt7921_asar_range_pwr(struct mt792x_phy *phy, - const struct cfg80211_sar_freq_ranges *range, - u8 idx) -{ - const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; - struct mt7921_acpi_sar *asar = phy->acpisar; - u8 *limit, band, max; - - if (!capa) - return 127; - - if (asar->ver == 1) { - limit = &asar->dyn->tbl[0].frp[0]; - max = ARRAY_SIZE(asar->dyn->tbl[0].frp); - } else { - limit = &asar->dyn_v2->tbl[0].frp[0]; - max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp); - } - - if (idx >= max) - return 127; - - if (range->start_freq >= 5945) - band = NL80211_BAND_6GHZ; - else if (range->start_freq >= 5150) - band = NL80211_BAND_5GHZ; - else - band = NL80211_BAND_2GHZ; - - return mt7921_asar_get_geo_pwr(phy, band, limit[idx]); -} - -int mt7921_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default) -{ - const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; - int i; - - if (!phy->acpisar) - return 0; - - /* When ACPI SAR enabled in HW, we should apply rules for .frp - * 1. w/o .sar_specs : set ACPI SAR power as the defatul value - * 2. w/ .sar_specs : set power with min(.sar_specs, ACPI_SAR) - */ - for (i = 0; i < capa->num_freq_ranges; i++) { - struct mt76_freq_range_power *frp = &phy->mt76->frp[i]; - - frp->range = set_default ? &capa->freq_ranges[i] : frp->range; - if (!frp->range) - continue; - - frp->power = min_t(s8, set_default ? 127 : frp->power, - mt7921_asar_range_pwr(phy, frp->range, i)); - } - - return 0; -} - -u8 mt7921_acpi_get_flags(struct mt792x_phy *phy) -{ - struct mt7921_acpi_sar *acpisar = phy->acpisar; - struct mt7921_asar_fg *fg; - struct { - u8 acpi_idx; - u8 chip_idx; - } map[] = { - {1, 1}, - {4, 2}, - }; - u8 flags = BIT(0); - int i, j; - - if (!acpisar) - return 0; - - fg = acpisar->fg; - if (!fg) - return flags; - - /* pickup necessary settings per device and - * translate the index of bitmap for chip command. - */ - for (i = 0; i < fg->nr_flag; i++) - for (j = 0; j < ARRAY_SIZE(map); j++) - if (fg->flag[i] == map[j].acpi_idx) { - flags |= BIT(map[j].chip_idx); - break; - } - - return flags; -} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h deleted file mode 100644 index 6f2c4a572572..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h +++ /dev/null @@ -1,105 +0,0 @@ -/* SPDX-License-Identifier: ISC */ -/* Copyright (C) 2022 MediaTek Inc. */ - -#ifndef __MT7921_ACPI_SAR_H -#define __MT7921_ACPI_SAR_H - -#define MT7921_ASAR_MIN_DYN 1 -#define MT7921_ASAR_MAX_DYN 8 -#define MT7921_ASAR_MIN_GEO 3 -#define MT7921_ASAR_MAX_GEO 8 -#define MT7921_ASAR_MIN_FG 8 - -#define MT7921_ACPI_MTCL "MTCL" -#define MT7921_ACPI_MTDS "MTDS" -#define MT7921_ACPI_MTGS "MTGS" -#define MT7921_ACPI_MTFG "MTFG" - -struct mt7921_asar_dyn_limit { - u8 idx; - u8 frp[5]; -} __packed; - -struct mt7921_asar_dyn { - u8 names[4]; - u8 enable; - u8 nr_tbl; - DECLARE_FLEX_ARRAY(struct mt7921_asar_dyn_limit, tbl); -} __packed; - -struct mt7921_asar_dyn_limit_v2 { - u8 idx; - u8 frp[11]; -} __packed; - -struct mt7921_asar_dyn_v2 { - u8 names[4]; - u8 enable; - u8 rsvd; - u8 nr_tbl; - DECLARE_FLEX_ARRAY(struct mt7921_asar_dyn_limit_v2, tbl); -} __packed; - -struct mt7921_asar_geo_band { - u8 pwr; - u8 offset; -} __packed; - -struct mt7921_asar_geo_limit { - u8 idx; - /* 0:2G, 1:5G */ - struct mt7921_asar_geo_band band[2]; -} __packed; - -struct mt7921_asar_geo { - u8 names[4]; - u8 version; - u8 nr_tbl; - DECLARE_FLEX_ARRAY(struct mt7921_asar_geo_limit, tbl); -} __packed; - -struct mt7921_asar_geo_limit_v2 { - u8 idx; - /* 0:2G, 1:5G, 2:6G */ - struct mt7921_asar_geo_band band[3]; -} __packed; - -struct mt7921_asar_geo_v2 { - u8 names[4]; - u8 version; - u8 rsvd; - u8 nr_tbl; - DECLARE_FLEX_ARRAY(struct mt7921_asar_geo_limit_v2, tbl); -} __packed; - -struct mt7921_asar_cl { - u8 names[4]; - u8 version; - u8 mode_6g; - u8 cl6g[6]; -} __packed; - -struct mt7921_asar_fg { - u8 names[4]; - u8 version; - u8 rsvd; - u8 nr_flag; - u8 rsvd1; - u8 flag[]; -} __packed; - -struct mt7921_acpi_sar { - u8 ver; - union { - struct mt7921_asar_dyn *dyn; - struct mt7921_asar_dyn_v2 *dyn_v2; - }; - union { - struct mt7921_asar_geo *geo; - struct mt7921_asar_geo_v2 *geo_v2; - }; - struct mt7921_asar_cl *countrylist; - struct mt7921_asar_fg *fg; -}; - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 3ff0205919c2..7b8876bf8fc8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -230,7 +230,7 @@ int mt7921_register_device(struct mt792x_dev *dev) if (!mt76_is_mmio(&dev->mt76)) hw->extra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE; - mt7921_init_acpi_sar(dev); + mt792x_init_acpi_sar(dev); ret = mt792x_init_wcid(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 73f29fed216f..0844d28b3223 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1153,19 +1153,16 @@ int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar) { struct mt76_phy *mphy = hw->priv; - int err; if (sar) { - err = mt76_init_sar_power(hw, sar); + int err = mt76_init_sar_power(hw, sar); + if (err) return err; } + mt792x_init_acpi_sar_power(mt792x_hw_phy(hw), !sar); - mt7921_init_acpi_sar_power(mt792x_hw_phy(hw), !sar); - - err = mt76_connac_mcu_set_rate_txpower(mphy); - - return err; + return mt76_connac_mcu_set_rate_txpower(mphy); } static int mt7921_set_sar_specs(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index bd40ca489447..e9caf750bca5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1197,7 +1197,7 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, } __packed req = { .idx = idx, .env = env_cap, - .acpi_conf = mt7921_acpi_get_flags(&dev->phy), + .acpi_conf = mt792x_acpi_get_flags(&dev->phy), }; int ret, valid_cnt = 0; u8 i, *pos; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 0c60a1559041..3ba873ec6bc4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -6,7 +6,6 @@ #include "../mt792x.h" #include "regs.h" -#include "acpi_sar.h" #define MT7921_PM_TIMEOUT (HZ / 12) #define MT7921_HW_SCAN_TIMEOUT (HZ / 10) @@ -345,29 +344,6 @@ int mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool enable); -#ifdef CONFIG_ACPI -int mt7921_init_acpi_sar(struct mt792x_dev *dev); -int mt7921_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default); -u8 mt7921_acpi_get_flags(struct mt792x_phy *phy); -#else -static inline int -mt7921_init_acpi_sar(struct mt792x_dev *dev) -{ - return 0; -} - -static inline int -mt7921_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default) -{ - return 0; -} - -static inline u8 -mt7921_acpi_get_flags(struct mt792x_phy *phy) -{ - return 0; -} -#endif int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 54ff9627530f..1ed688186fe7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -9,6 +9,7 @@ #include "mt76_connac_mcu.h" #include "mt792x_regs.h" +#include "mt792x_acpi_sar.h" #define MT792x_MAX_INTERFACES 4 #define MT792x_WTBL_SIZE 20 @@ -297,4 +298,26 @@ int __mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev); int mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev); int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev); +#ifdef CONFIG_ACPI +int mt792x_init_acpi_sar(struct mt792x_dev *dev); +int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default); +u8 mt792x_acpi_get_flags(struct mt792x_phy *phy); +#else +static inline int mt792x_init_acpi_sar(struct mt792x_dev *dev) +{ + return 0; +} + +static inline int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, + bool set_default) +{ + return 0; +} + +static inline u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) +{ + return 0; +} +#endif + #endif /* __MT7925_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c new file mode 100644 index 000000000000..303c0f5c9c66 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2023 MediaTek Inc. */ + +#include +#include "mt792x.h" + +static int +mt792x_acpi_read(struct mt792x_dev *dev, u8 *method, u8 **tbl, u32 *len) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; + struct mt76_dev *mdev = &dev->mt76; + union acpi_object *sar_root; + acpi_handle root, handle; + acpi_status status; + u32 i = 0; + int ret; + + root = ACPI_HANDLE(mdev->dev); + if (!root) + return -EOPNOTSUPP; + + status = acpi_get_handle(root, method, &handle); + if (ACPI_FAILURE(status)) + return -EIO; + + status = acpi_evaluate_object(handle, NULL, NULL, &buf); + if (ACPI_FAILURE(status)) + return -EIO; + + sar_root = buf.pointer; + if (sar_root->type != ACPI_TYPE_PACKAGE || + sar_root->package.count < 4 || + sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) { + dev_err(mdev->dev, "sar cnt = %d\n", + sar_root->package.count); + ret = -EINVAL; + goto free; + } + + if (!*tbl) { + *tbl = devm_kzalloc(mdev->dev, sar_root->package.count, + GFP_KERNEL); + if (!*tbl) { + ret = -ENOMEM; + goto free; + } + } + + if (len) + *len = sar_root->package.count; + + for (i = 0; i < sar_root->package.count; i++) { + union acpi_object *sar_unit = &sar_root->package.elements[i]; + + if (sar_unit->type != ACPI_TYPE_INTEGER) + break; + + *(*tbl + i) = (u8)sar_unit->integer.value; + } + + ret = i == sar_root->package.count ? 0 : -EINVAL; +free: + kfree(sar_root); + + return ret; +} + +/* MTCL : Country List Table for 6G band */ +static void +mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version) +{ + if (mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL) < 0) + *version = 1; + else + *version = 2; +} + +/* MTDS : Dynamic SAR Power Table */ +static int +mt792x_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version) +{ + int len, ret, sarlen, prelen, tblcnt; + bool enable; + + ret = mt792x_acpi_read(dev, MT792x_ACPI_MTDS, table, &len); + if (ret) + return ret; + + /* Table content validation */ + switch (version) { + case 1: + enable = ((struct mt792x_asar_dyn *)*table)->enable; + sarlen = sizeof(struct mt792x_asar_dyn_limit); + prelen = sizeof(struct mt792x_asar_dyn); + break; + case 2: + enable = ((struct mt792x_asar_dyn_v2 *)*table)->enable; + sarlen = sizeof(struct mt792x_asar_dyn_limit_v2); + prelen = sizeof(struct mt792x_asar_dyn_v2); + break; + default: + return -EINVAL; + } + + tblcnt = (len - prelen) / sarlen; + if (!enable || + tblcnt > MT792x_ASAR_MAX_DYN || tblcnt < MT792x_ASAR_MIN_DYN) + return -EINVAL; + + return 0; +} + +/* MTGS : Geo SAR Power Table */ +static int +mt792x_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version) +{ + int len, ret, sarlen, prelen, tblcnt; + + ret = mt792x_acpi_read(dev, MT792x_ACPI_MTGS, table, &len); + if (ret) + return ret; + + /* Table content validation */ + switch (version) { + case 1: + sarlen = sizeof(struct mt792x_asar_geo_limit); + prelen = sizeof(struct mt792x_asar_geo); + break; + case 2: + sarlen = sizeof(struct mt792x_asar_geo_limit_v2); + prelen = sizeof(struct mt792x_asar_geo_v2); + break; + default: + return -EINVAL; + } + + tblcnt = (len - prelen) / sarlen; + if (tblcnt > MT792x_ASAR_MAX_GEO || tblcnt < MT792x_ASAR_MIN_GEO) + return -EINVAL; + + return 0; +} + +/* MTFG : Flag Table */ +static int +mt792x_asar_acpi_read_mtfg(struct mt792x_dev *dev, u8 **table) +{ + int len, ret; + + ret = mt792x_acpi_read(dev, MT792x_ACPI_MTFG, table, &len); + if (ret) + return ret; + + if (len < MT792x_ASAR_MIN_FG) + return -EINVAL; + + return 0; +} + +int mt792x_init_acpi_sar(struct mt792x_dev *dev) +{ + struct mt792x_acpi_sar *asar; + int ret; + + asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL); + if (!asar) + return -ENOMEM; + + mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); + + /* MTDS is mandatory. Return error if table is invalid */ + ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver); + if (ret) { + devm_kfree(dev->mt76.dev, asar->dyn); + devm_kfree(dev->mt76.dev, asar->countrylist); + devm_kfree(dev->mt76.dev, asar); + + return ret; + } + + /* MTGS is optional */ + ret = mt792x_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver); + if (ret) { + devm_kfree(dev->mt76.dev, asar->geo); + asar->geo = NULL; + } + + /* MTFG is optional */ + ret = mt792x_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg); + if (ret) { + devm_kfree(dev->mt76.dev, asar->fg); + asar->fg = NULL; + } + dev->phy.acpisar = asar; + + return 0; +} +EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar); + +static s8 +mt792x_asar_get_geo_pwr(struct mt792x_phy *phy, + enum nl80211_band band, s8 dyn_power) +{ + struct mt792x_acpi_sar *asar = phy->acpisar; + struct mt792x_asar_geo_band *band_pwr; + s8 geo_power; + u8 idx, max; + + if (!asar->geo) + return dyn_power; + + switch (phy->mt76->dev->region) { + case NL80211_DFS_FCC: + idx = 0; + break; + case NL80211_DFS_ETSI: + idx = 1; + break; + default: /* WW */ + idx = 2; + break; + } + + if (asar->ver == 1) { + band_pwr = &asar->geo->tbl[idx].band[0]; + max = ARRAY_SIZE(asar->geo->tbl[idx].band); + } else { + band_pwr = &asar->geo_v2->tbl[idx].band[0]; + max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band); + } + + switch (band) { + case NL80211_BAND_2GHZ: + idx = 0; + break; + case NL80211_BAND_5GHZ: + idx = 1; + break; + case NL80211_BAND_6GHZ: + idx = 2; + break; + default: + return dyn_power; + } + + if (idx >= max) + return dyn_power; + + geo_power = (band_pwr + idx)->pwr; + dyn_power += (band_pwr + idx)->offset; + + return min(geo_power, dyn_power); +} + +static s8 +mt792x_asar_range_pwr(struct mt792x_phy *phy, + const struct cfg80211_sar_freq_ranges *range, + u8 idx) +{ + const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; + struct mt792x_acpi_sar *asar = phy->acpisar; + u8 *limit, band, max; + + if (!capa) + return 127; + + if (asar->ver == 1) { + limit = &asar->dyn->tbl[0].frp[0]; + max = ARRAY_SIZE(asar->dyn->tbl[0].frp); + } else { + limit = &asar->dyn_v2->tbl[0].frp[0]; + max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp); + } + + if (idx >= max) + return 127; + + if (range->start_freq >= 5945) + band = NL80211_BAND_6GHZ; + else if (range->start_freq >= 5150) + band = NL80211_BAND_5GHZ; + else + band = NL80211_BAND_2GHZ; + + return mt792x_asar_get_geo_pwr(phy, band, limit[idx]); +} + +int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default) +{ + const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; + int i; + + if (!phy->acpisar) + return 0; + + /* When ACPI SAR enabled in HW, we should apply rules for .frp + * 1. w/o .sar_specs : set ACPI SAR power as the defatul value + * 2. w/ .sar_specs : set power with min(.sar_specs, ACPI_SAR) + */ + for (i = 0; i < capa->num_freq_ranges; i++) { + struct mt76_freq_range_power *frp = &phy->mt76->frp[i]; + + frp->range = set_default ? &capa->freq_ranges[i] : frp->range; + if (!frp->range) + continue; + + frp->power = min_t(s8, set_default ? 127 : frp->power, + mt792x_asar_range_pwr(phy, frp->range, i)); + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar_power); + +u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) +{ + struct mt792x_acpi_sar *acpisar = phy->acpisar; + struct mt792x_asar_fg *fg; + struct { + u8 acpi_idx; + u8 chip_idx; + } map[] = { + { 1, 1 }, + { 4, 2 }, + }; + u8 flags = BIT(0); + int i, j; + + if (!acpisar) + return 0; + + fg = acpisar->fg; + if (!fg) + return flags; + + /* pickup necessary settings per device and + * translate the index of bitmap for chip command. + */ + for (i = 0; i < fg->nr_flag; i++) { + for (j = 0; j < ARRAY_SIZE(map); j++) { + if (fg->flag[i] == map[j].acpi_idx) { + flags |= BIT(map[j].chip_idx); + break; + } + } + } + + return flags; +} +EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h new file mode 100644 index 000000000000..d6d332e863ba --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2023 MediaTek Inc. */ + +#ifndef __MT7921_ACPI_SAR_H +#define __MT7921_ACPI_SAR_H + +#define MT792x_ASAR_MIN_DYN 1 +#define MT792x_ASAR_MAX_DYN 8 +#define MT792x_ASAR_MIN_GEO 3 +#define MT792x_ASAR_MAX_GEO 8 +#define MT792x_ASAR_MIN_FG 8 + +#define MT792x_ACPI_MTCL "MTCL" +#define MT792x_ACPI_MTDS "MTDS" +#define MT792x_ACPI_MTGS "MTGS" +#define MT792x_ACPI_MTFG "MTFG" + +struct mt792x_asar_dyn_limit { + u8 idx; + u8 frp[5]; +} __packed; + +struct mt792x_asar_dyn { + u8 names[4]; + u8 enable; + u8 nr_tbl; + DECLARE_FLEX_ARRAY(struct mt792x_asar_dyn_limit, tbl); +} __packed; + +struct mt792x_asar_dyn_limit_v2 { + u8 idx; + u8 frp[11]; +} __packed; + +struct mt792x_asar_dyn_v2 { + u8 names[4]; + u8 enable; + u8 rsvd; + u8 nr_tbl; + DECLARE_FLEX_ARRAY(struct mt792x_asar_dyn_limit_v2, tbl); +} __packed; + +struct mt792x_asar_geo_band { + u8 pwr; + u8 offset; +} __packed; + +struct mt792x_asar_geo_limit { + u8 idx; + /* 0:2G, 1:5G */ + struct mt792x_asar_geo_band band[2]; +} __packed; + +struct mt792x_asar_geo { + u8 names[4]; + u8 version; + u8 nr_tbl; + DECLARE_FLEX_ARRAY(struct mt792x_asar_geo_limit, tbl); +} __packed; + +struct mt792x_asar_geo_limit_v2 { + u8 idx; + /* 0:2G, 1:5G, 2:6G */ + struct mt792x_asar_geo_band band[3]; +} __packed; + +struct mt792x_asar_geo_v2 { + u8 names[4]; + u8 version; + u8 rsvd; + u8 nr_tbl; + DECLARE_FLEX_ARRAY(struct mt792x_asar_geo_limit_v2, tbl); +} __packed; + +struct mt792x_asar_cl { + u8 names[4]; + u8 version; + u8 mode_6g; + u8 cl6g[6]; +} __packed; + +struct mt792x_asar_fg { + u8 names[4]; + u8 version; + u8 rsvd; + u8 nr_flag; + u8 rsvd1; + u8 flag[]; +} __packed; + +struct mt792x_acpi_sar { + u8 ver; + union { + struct mt792x_asar_dyn *dyn; + struct mt792x_asar_dyn_v2 *dyn_v2; + }; + union { + struct mt792x_asar_geo *geo; + struct mt792x_asar_geo_v2 *geo_v2; + }; + struct mt792x_asar_cl *countrylist; + struct mt792x_asar_fg *fg; +}; + +#endif -- cgit