brintos

brintos / linux-shallow public Read only

0
0
Text · 8.9 KiB · 9317f8f Raw
410 lines · c
1// SPDX-License-Identifier: ISC2/* Copyright (C) 2023 MediaTek Inc. */3 4#include <linux/acpi.h>5#include "mt792x.h"6 7static int8mt792x_acpi_read(struct mt792x_dev *dev, u8 *method, u8 **tbl, u32 *len)9{10	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };11	struct mt76_dev *mdev = &dev->mt76;12	union acpi_object *sar_root;13	acpi_handle root, handle;14	acpi_status status;15	u32 i = 0;16	int ret;17 18	root = ACPI_HANDLE(mdev->dev);19	if (!root)20		return -EOPNOTSUPP;21 22	status = acpi_get_handle(root, method, &handle);23	if (ACPI_FAILURE(status))24		return -EIO;25 26	status = acpi_evaluate_object(handle, NULL, NULL, &buf);27	if (ACPI_FAILURE(status))28		return -EIO;29 30	sar_root = buf.pointer;31	if (sar_root->type != ACPI_TYPE_PACKAGE ||32	    sar_root->package.count < 4 ||33	    sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) {34		dev_err(mdev->dev, "sar cnt = %d\n",35			sar_root->package.count);36		ret = -EINVAL;37		goto free;38	}39 40	if (!*tbl) {41		*tbl = devm_kzalloc(mdev->dev, sar_root->package.count,42				    GFP_KERNEL);43		if (!*tbl) {44			ret = -ENOMEM;45			goto free;46		}47	}48 49	if (len)50		*len = sar_root->package.count;51 52	for (i = 0; i < sar_root->package.count; i++) {53		union acpi_object *sar_unit = &sar_root->package.elements[i];54 55		if (sar_unit->type != ACPI_TYPE_INTEGER)56			break;57 58		*(*tbl + i) = (u8)sar_unit->integer.value;59	}60 61	ret = i == sar_root->package.count ? 0 : -EINVAL;62free:63	kfree(sar_root);64 65	return ret;66}67 68/* MTCL : Country List Table for 6G band */69static int70mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version)71{72	int ret;73 74	*version = ((ret = mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL)) < 0)75		   ? 1 : 2;76 77	return ret;78}79 80/* MTDS : Dynamic SAR Power Table */81static int82mt792x_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version)83{84	int len, ret, sarlen, prelen, tblcnt;85	bool enable;86 87	ret = mt792x_acpi_read(dev, MT792x_ACPI_MTDS, table, &len);88	if (ret)89		return ret;90 91	/* Table content validation */92	switch (version) {93	case 1:94		enable = ((struct mt792x_asar_dyn *)*table)->enable;95		sarlen = sizeof(struct mt792x_asar_dyn_limit);96		prelen = sizeof(struct mt792x_asar_dyn);97		break;98	case 2:99		enable = ((struct mt792x_asar_dyn_v2 *)*table)->enable;100		sarlen = sizeof(struct mt792x_asar_dyn_limit_v2);101		prelen = sizeof(struct mt792x_asar_dyn_v2);102		break;103	default:104		return -EINVAL;105	}106 107	tblcnt = (len - prelen) / sarlen;108	if (!enable ||109	    tblcnt > MT792x_ASAR_MAX_DYN || tblcnt < MT792x_ASAR_MIN_DYN)110		return -EINVAL;111 112	return 0;113}114 115/* MTGS : Geo SAR Power Table */116static int117mt792x_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version)118{119	int len, ret, sarlen, prelen, tblcnt;120 121	ret = mt792x_acpi_read(dev, MT792x_ACPI_MTGS, table, &len);122	if (ret)123		return ret;124 125	/* Table content validation */126	switch (version) {127	case 1:128		sarlen = sizeof(struct mt792x_asar_geo_limit);129		prelen = sizeof(struct mt792x_asar_geo);130		break;131	case 2:132		sarlen = sizeof(struct mt792x_asar_geo_limit_v2);133		prelen = sizeof(struct mt792x_asar_geo_v2);134		break;135	default:136		return -EINVAL;137	}138 139	tblcnt = (len - prelen) / sarlen;140	if (tblcnt > MT792x_ASAR_MAX_GEO || tblcnt < MT792x_ASAR_MIN_GEO)141		return -EINVAL;142 143	return 0;144}145 146/* MTFG : Flag Table */147static int148mt792x_asar_acpi_read_mtfg(struct mt792x_dev *dev, u8 **table)149{150	int len, ret;151 152	ret = mt792x_acpi_read(dev, MT792x_ACPI_MTFG, table, &len);153	if (ret)154		return ret;155 156	if (len < MT792x_ASAR_MIN_FG)157		return -EINVAL;158 159	return 0;160}161 162int mt792x_init_acpi_sar(struct mt792x_dev *dev)163{164	struct mt792x_acpi_sar *asar;165	int ret;166 167	asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL);168	if (!asar)169		return -ENOMEM;170 171	ret = mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver);172	if (ret) {173		devm_kfree(dev->mt76.dev, asar->countrylist);174		asar->countrylist = NULL;175	}176 177	ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver);178	if (ret) {179		devm_kfree(dev->mt76.dev, asar->dyn);180		asar->dyn = NULL;181	}182 183	/* MTGS is optional */184	ret = mt792x_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver);185	if (ret) {186		devm_kfree(dev->mt76.dev, asar->geo);187		asar->geo = NULL;188	}189 190	/* MTFG is optional */191	ret = mt792x_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg);192	if (ret) {193		devm_kfree(dev->mt76.dev, asar->fg);194		asar->fg = NULL;195	}196	dev->phy.acpisar = asar;197 198	return 0;199}200EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar);201 202static s8203mt792x_asar_get_geo_pwr(struct mt792x_phy *phy,204			enum nl80211_band band, s8 dyn_power)205{206	struct mt792x_acpi_sar *asar = phy->acpisar;207	struct mt792x_asar_geo_band *band_pwr;208	s8 geo_power;209	u8 idx, max;210 211	if (!asar->geo)212		return dyn_power;213 214	switch (phy->mt76->dev->region) {215	case NL80211_DFS_FCC:216		idx = 0;217		break;218	case NL80211_DFS_ETSI:219		idx = 1;220		break;221	default: /* WW */222		idx = 2;223		break;224	}225 226	if (asar->ver == 1) {227		band_pwr = &asar->geo->tbl[idx].band[0];228		max = ARRAY_SIZE(asar->geo->tbl[idx].band);229	} else {230		band_pwr = &asar->geo_v2->tbl[idx].band[0];231		max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band);232	}233 234	switch (band) {235	case NL80211_BAND_2GHZ:236		idx = 0;237		break;238	case NL80211_BAND_5GHZ:239		idx = 1;240		break;241	case NL80211_BAND_6GHZ:242		idx = 2;243		break;244	default:245		return dyn_power;246	}247 248	if (idx >= max)249		return dyn_power;250 251	geo_power = (band_pwr + idx)->pwr;252	dyn_power += (band_pwr + idx)->offset;253 254	return min(geo_power, dyn_power);255}256 257static s8258mt792x_asar_range_pwr(struct mt792x_phy *phy,259		      const struct cfg80211_sar_freq_ranges *range,260		      u8 idx)261{262	const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;263	struct mt792x_acpi_sar *asar = phy->acpisar;264	u8 *limit, band, max;265 266	if (!capa)267		return 127;268 269	if (asar->ver == 1) {270		limit = &asar->dyn->tbl[0].frp[0];271		max = ARRAY_SIZE(asar->dyn->tbl[0].frp);272	} else {273		limit = &asar->dyn_v2->tbl[0].frp[0];274		max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp);275	}276 277	if (idx >= max)278		return 127;279 280	if (range->start_freq >= 5945)281		band = NL80211_BAND_6GHZ;282	else if (range->start_freq >= 5150)283		band = NL80211_BAND_5GHZ;284	else285		band = NL80211_BAND_2GHZ;286 287	return mt792x_asar_get_geo_pwr(phy, band, limit[idx]);288}289 290int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default)291{292	const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;293	int i;294 295	if (!phy->acpisar || !((struct mt792x_acpi_sar *)phy->acpisar)->dyn)296		return 0;297 298	/* When ACPI SAR enabled in HW, we should apply rules for .frp299	 * 1. w/o .sar_specs : set ACPI SAR power as the defatul value300	 * 2. w/  .sar_specs : set power with min(.sar_specs, ACPI_SAR)301	 */302	for (i = 0; i < capa->num_freq_ranges; i++) {303		struct mt76_freq_range_power *frp = &phy->mt76->frp[i];304 305		frp->range = set_default ? &capa->freq_ranges[i] : frp->range;306		if (!frp->range)307			continue;308 309		frp->power = min_t(s8, set_default ? 127 : frp->power,310				   mt792x_asar_range_pwr(phy, frp->range, i));311	}312 313	return 0;314}315EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar_power);316 317u8 mt792x_acpi_get_flags(struct mt792x_phy *phy)318{319	struct mt792x_acpi_sar *acpisar = phy->acpisar;320	struct mt792x_asar_fg *fg;321	struct {322		u8 acpi_idx;323		u8 chip_idx;324	} map[] = {325		{ 1, 1 },326		{ 4, 2 },327	};328	u8 flags = BIT(0);329	int i, j;330 331	if (!acpisar)332		return 0;333 334	fg = acpisar->fg;335	if (!fg)336		return flags;337 338	/* pickup necessary settings per device and339	 * translate the index of bitmap for chip command.340	 */341	for (i = 0; i < fg->nr_flag; i++) {342		for (j = 0; j < ARRAY_SIZE(map); j++) {343			if (fg->flag[i] == map[j].acpi_idx) {344				flags |= BIT(map[j].chip_idx);345				break;346			}347		}348	}349 350	return flags;351}352EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags);353 354static u8355mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl)356{357	u8 config = 0;358	u8 mode_6g, mode_5g9;359 360	mode_6g = (cl->mode_6g > 0x02) ? 0 : cl->mode_6g;361	mode_5g9 = (cl->mode_5g9 > 0x01) ? 0 : cl->mode_5g9;362 363	if ((cl->cl6g[row] & BIT(column)) || cl->mode_6g == 0x02)364		config |= (mode_6g & 0x3) << 2;365	if (cl->version > 1 && cl->cl5g9[row] & BIT(column))366		config |= (mode_5g9 & 0x3);367 368	return config;369}370 371u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2)372{373	static const char * const cc_list_all[] = {374		"00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR",375		"CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME",376		"MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR",377		"TW", "TH", "UA", "GB", "US", "VN", "KH", "PY",378	};379	static const char * const cc_list_eu[] = {380		"AT", "BE", "BG", "CY", "CZ", "HR", "DK", "EE",381		"FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT",382		"LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL",383		"PT", "RO", "SK", "SI", "ES", "SE", "CH",384	};385	struct mt792x_acpi_sar *sar = phy->acpisar;386	struct mt792x_asar_cl *cl;387	int col, row, i;388 389	if (!sar)390		return 0xf;391 392	cl = sar->countrylist;393	if (!cl)394		return 0xc;395 396	for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) {397		col = 7 - i % 8;398		row = i / 8;399		if (!memcmp(cc_list_all[i], alpha2, 2))400			return mt792x_acpi_get_mtcl_map(row, col, cl);401	}402 403	for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++)404		if (!memcmp(cc_list_eu[i], alpha2, 2))405			return mt792x_acpi_get_mtcl_map(0, 6, cl);406 407	return mt792x_acpi_get_mtcl_map(0, 7, cl);408}409EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf);410