Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /* Copyright (C) 2022 MediaTek Inc. */
0003 
0004 #include <linux/acpi.h>
0005 #include "mt7921.h"
0006 
0007 static int
0008 mt7921_acpi_read(struct mt7921_dev *dev, u8 *method, u8 **tbl, u32 *len)
0009 {
0010     struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
0011     union acpi_object *sar_root, *sar_unit;
0012     struct mt76_dev *mdev = &dev->mt76;
0013     acpi_handle root, handle;
0014     acpi_status status;
0015     u32 i = 0;
0016 
0017     root = ACPI_HANDLE(mdev->dev);
0018     if (!root)
0019         return -EOPNOTSUPP;
0020 
0021     status = acpi_get_handle(root, method, &handle);
0022     if (ACPI_FAILURE(status))
0023         return -EIO;
0024 
0025     status = acpi_evaluate_object(handle, NULL, NULL, &buf);
0026     if (ACPI_FAILURE(status))
0027         return -EIO;
0028 
0029     sar_root = buf.pointer;
0030     if (sar_root->type != ACPI_TYPE_PACKAGE ||
0031         sar_root->package.count < 4 ||
0032         sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) {
0033         dev_err(mdev->dev, "sar cnt = %d\n",
0034             sar_root->package.count);
0035         goto free;
0036     }
0037 
0038     if (!*tbl) {
0039         *tbl = devm_kzalloc(mdev->dev, sar_root->package.count,
0040                     GFP_KERNEL);
0041         if (!*tbl)
0042             goto free;
0043     }
0044     if (len)
0045         *len = sar_root->package.count;
0046 
0047     for (i = 0; i < sar_root->package.count; i++) {
0048         sar_unit = &sar_root->package.elements[i];
0049 
0050         if (sar_unit->type != ACPI_TYPE_INTEGER)
0051             break;
0052         *(*tbl + i) = (u8)sar_unit->integer.value;
0053     }
0054 free:
0055     kfree(sar_root);
0056 
0057     return (i == sar_root->package.count) ? 0 : -EINVAL;
0058 }
0059 
0060 /* MTCL : Country List Table for 6G band */
0061 static int
0062 mt7921_asar_acpi_read_mtcl(struct mt7921_dev *dev, u8 **table, u8 *version)
0063 {
0064     *version = (mt7921_acpi_read(dev, MT7921_ACPI_MTCL, table, NULL) < 0)
0065            ? 1 : 2;
0066     return 0;
0067 }
0068 
0069 /* MTDS : Dynamic SAR Power Table */
0070 static int
0071 mt7921_asar_acpi_read_mtds(struct mt7921_dev *dev, u8 **table, u8 version)
0072 {
0073     int len, ret, sarlen, prelen, tblcnt;
0074     bool enable;
0075 
0076     ret = mt7921_acpi_read(dev, MT7921_ACPI_MTDS, table, &len);
0077     if (ret)
0078         return ret;
0079 
0080     /* Table content validation */
0081     switch (version) {
0082     case 1:
0083         enable = ((struct mt7921_asar_dyn *)*table)->enable;
0084         sarlen = sizeof(struct mt7921_asar_dyn_limit);
0085         prelen = sizeof(struct mt7921_asar_dyn);
0086         break;
0087     case 2:
0088         enable = ((struct mt7921_asar_dyn_v2 *)*table)->enable;
0089         sarlen = sizeof(struct mt7921_asar_dyn_limit_v2);
0090         prelen = sizeof(struct mt7921_asar_dyn_v2);
0091         break;
0092     default:
0093         return -EINVAL;
0094     }
0095 
0096     tblcnt = (len - prelen) / sarlen;
0097     if (!enable ||
0098         tblcnt > MT7921_ASAR_MAX_DYN || tblcnt < MT7921_ASAR_MIN_DYN)
0099         ret = -EINVAL;
0100 
0101     return ret;
0102 }
0103 
0104 /* MTGS : Geo SAR Power Table */
0105 static int
0106 mt7921_asar_acpi_read_mtgs(struct mt7921_dev *dev, u8 **table, u8 version)
0107 {
0108     int len, ret = 0, sarlen, prelen, tblcnt;
0109 
0110     ret = mt7921_acpi_read(dev, MT7921_ACPI_MTGS, table, &len);
0111     if (ret)
0112         return ret;
0113 
0114     /* Table content validation */
0115     switch (version) {
0116     case 1:
0117         sarlen = sizeof(struct mt7921_asar_geo_limit);
0118         prelen = sizeof(struct mt7921_asar_geo);
0119         break;
0120     case 2:
0121         sarlen = sizeof(struct mt7921_asar_geo_limit_v2);
0122         prelen = sizeof(struct mt7921_asar_geo_v2);
0123         break;
0124     default:
0125         return -EINVAL;
0126     }
0127 
0128     tblcnt = (len - prelen) / sarlen;
0129     if (tblcnt > MT7921_ASAR_MAX_GEO || tblcnt < MT7921_ASAR_MIN_GEO)
0130         ret = -EINVAL;
0131 
0132     return ret;
0133 }
0134 
0135 int mt7921_init_acpi_sar(struct mt7921_dev *dev)
0136 {
0137     struct mt7921_acpi_sar *asar;
0138     int ret;
0139 
0140     asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL);
0141     if (!asar)
0142         return -ENOMEM;
0143 
0144     mt7921_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver);
0145 
0146     /* MTDS is mandatory. Return error if table is invalid */
0147     ret = mt7921_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver);
0148     if (ret) {
0149         devm_kfree(dev->mt76.dev, asar->dyn);
0150         devm_kfree(dev->mt76.dev, asar->countrylist);
0151         devm_kfree(dev->mt76.dev, asar);
0152         return ret;
0153     }
0154 
0155     /* MTGS is optional */
0156     ret = mt7921_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver);
0157     if (ret) {
0158         devm_kfree(dev->mt76.dev, asar->geo);
0159         asar->geo = NULL;
0160     }
0161 
0162     dev->phy.acpisar = asar;
0163 
0164     return 0;
0165 }
0166 
0167 static s8
0168 mt7921_asar_get_geo_pwr(struct mt7921_phy *phy,
0169             enum nl80211_band band, s8 dyn_power)
0170 {
0171     struct mt7921_acpi_sar *asar = phy->acpisar;
0172     struct mt7921_asar_geo_band *band_pwr;
0173     s8 geo_power;
0174     u8 idx, max;
0175 
0176     if (!asar->geo)
0177         return dyn_power;
0178 
0179     switch (phy->mt76->dev->region) {
0180     case NL80211_DFS_FCC:
0181         idx = 0;
0182         break;
0183     case NL80211_DFS_ETSI:
0184         idx = 1;
0185         break;
0186     default: /* WW */
0187         idx = 2;
0188         break;
0189     }
0190 
0191     if (asar->ver == 1) {
0192         band_pwr = &asar->geo->tbl[idx].band[0];
0193         max = ARRAY_SIZE(asar->geo->tbl[idx].band);
0194     } else {
0195         band_pwr = &asar->geo_v2->tbl[idx].band[0];
0196         max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band);
0197     }
0198 
0199     switch (band) {
0200     case NL80211_BAND_2GHZ:
0201         idx = 0;
0202         break;
0203     case NL80211_BAND_5GHZ:
0204         idx = 1;
0205         break;
0206     case NL80211_BAND_6GHZ:
0207         idx = 2;
0208         break;
0209     default:
0210         return dyn_power;
0211     }
0212 
0213     if (idx >= max)
0214         return dyn_power;
0215 
0216     geo_power = (band_pwr + idx)->pwr;
0217     dyn_power += (band_pwr + idx)->offset;
0218 
0219     return min(geo_power, dyn_power);
0220 }
0221 
0222 static s8
0223 mt7921_asar_range_pwr(struct mt7921_phy *phy,
0224               const struct cfg80211_sar_freq_ranges *range,
0225               u8 idx)
0226 {
0227     const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
0228     struct mt7921_acpi_sar *asar = phy->acpisar;
0229     u8 *limit, band, max;
0230 
0231     if (!capa)
0232         return 127;
0233 
0234     if (asar->ver == 1) {
0235         limit = &asar->dyn->tbl[0].frp[0];
0236         max = ARRAY_SIZE(asar->dyn->tbl[0].frp);
0237     } else {
0238         limit = &asar->dyn_v2->tbl[0].frp[0];
0239         max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp);
0240     }
0241 
0242     if (idx >= max)
0243         return 127;
0244 
0245     if (range->start_freq >= 5945)
0246         band = NL80211_BAND_6GHZ;
0247     else if (range->start_freq >= 5150)
0248         band = NL80211_BAND_5GHZ;
0249     else
0250         band = NL80211_BAND_2GHZ;
0251 
0252     return mt7921_asar_get_geo_pwr(phy, band, limit[idx]);
0253 }
0254 
0255 int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default)
0256 {
0257     const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
0258     int i;
0259 
0260     if (!phy->acpisar)
0261         return 0;
0262 
0263     /* When ACPI SAR enabled in HW, we should apply rules for .frp
0264      * 1. w/o .sar_specs : set ACPI SAR power as the defatul value
0265      * 2. w/  .sar_specs : set power with min(.sar_specs, ACPI_SAR)
0266      */
0267     for (i = 0; i < capa->num_freq_ranges; i++) {
0268         struct mt76_freq_range_power *frp = &phy->mt76->frp[i];
0269 
0270         frp->range = set_default ? &capa->freq_ranges[i] : frp->range;
0271         if (!frp->range)
0272             continue;
0273 
0274         frp->power = min_t(s8, set_default ? 127 : frp->power,
0275                    mt7921_asar_range_pwr(phy, frp->range, i));
0276     }
0277 
0278     return 0;
0279 }