18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
48c2ecf20Sopenharmony_ci * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "mt76x02_eeprom.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic int
128c2ecf20Sopenharmony_cimt76x02_efuse_read(struct mt76x02_dev *dev, u16 addr, u8 *data,
138c2ecf20Sopenharmony_ci		   enum mt76x02_eeprom_modes mode)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	u32 val;
168c2ecf20Sopenharmony_ci	int i;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	val = mt76_rr(dev, MT_EFUSE_CTRL);
198c2ecf20Sopenharmony_ci	val &= ~(MT_EFUSE_CTRL_AIN |
208c2ecf20Sopenharmony_ci		 MT_EFUSE_CTRL_MODE);
218c2ecf20Sopenharmony_ci	val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
228c2ecf20Sopenharmony_ci	val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode);
238c2ecf20Sopenharmony_ci	val |= MT_EFUSE_CTRL_KICK;
248c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_EFUSE_CTRL, val);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
278c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	udelay(2);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	val = mt76_rr(dev, MT_EFUSE_CTRL);
328c2ecf20Sopenharmony_ci	if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
338c2ecf20Sopenharmony_ci		memset(data, 0xff, 16);
348c2ecf20Sopenharmony_ci		return 0;
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
388c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT_EFUSE_DATA(i));
398c2ecf20Sopenharmony_ci		put_unaligned_le32(val, data + 4 * i);
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return 0;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciint mt76x02_eeprom_copy(struct mt76x02_dev *dev,
468c2ecf20Sopenharmony_ci			enum mt76x02_eeprom_field field,
478c2ecf20Sopenharmony_ci			void *dest, int len)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	if (field + len > dev->mt76.eeprom.size)
508c2ecf20Sopenharmony_ci		return -1;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	memcpy(dest, dev->mt76.eeprom.data + field, len);
538c2ecf20Sopenharmony_ci	return 0;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_eeprom_copy);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ciint mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf,
588c2ecf20Sopenharmony_ci			   int len, enum mt76x02_eeprom_modes mode)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	int ret, i;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	for (i = 0; i + 16 <= len; i += 16) {
638c2ecf20Sopenharmony_ci		ret = mt76x02_efuse_read(dev, base + i, buf + i, mode);
648c2ecf20Sopenharmony_ci		if (ret)
658c2ecf20Sopenharmony_ci			return ret;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return 0;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_get_efuse_data);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_civoid mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) {
778c2ecf20Sopenharmony_ci	case BOARD_TYPE_5GHZ:
788c2ecf20Sopenharmony_ci		dev->mphy.cap.has_5ghz = true;
798c2ecf20Sopenharmony_ci		break;
808c2ecf20Sopenharmony_ci	case BOARD_TYPE_2GHZ:
818c2ecf20Sopenharmony_ci		dev->mphy.cap.has_2ghz = true;
828c2ecf20Sopenharmony_ci		break;
838c2ecf20Sopenharmony_ci	default:
848c2ecf20Sopenharmony_ci		dev->mphy.cap.has_2ghz = true;
858c2ecf20Sopenharmony_ci		dev->mphy.cap.has_5ghz = true;
868c2ecf20Sopenharmony_ci		break;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cibool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (band == NL80211_BAND_5GHZ)
968c2ecf20Sopenharmony_ci		return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G);
978c2ecf20Sopenharmony_ci	else
988c2ecf20Sopenharmony_ci		return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_civoid mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band,
1038c2ecf20Sopenharmony_ci			 u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	u16 val;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN);
1088c2ecf20Sopenharmony_ci	*lna_2g = val & 0xff;
1098c2ecf20Sopenharmony_ci	lna_5g[0] = val >> 8;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1);
1128c2ecf20Sopenharmony_ci	lna_5g[1] = val >> 8;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1);
1158c2ecf20Sopenharmony_ci	lna_5g[2] = val >> 8;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (!mt76x02_field_valid(lna_5g[1]))
1188c2ecf20Sopenharmony_ci		lna_5g[1] = lna_5g[0];
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (!mt76x02_field_valid(lna_5g[2]))
1218c2ecf20Sopenharmony_ci		lna_5g[2] = lna_5g[0];
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (band == NL80211_BAND_2GHZ)
1248c2ecf20Sopenharmony_ci		*rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0);
1258c2ecf20Sopenharmony_ci	else
1268c2ecf20Sopenharmony_ci		*rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_get_rx_gain);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciu8 mt76x02_get_lna_gain(struct mt76x02_dev *dev,
1318c2ecf20Sopenharmony_ci			s8 *lna_2g, s8 *lna_5g,
1328c2ecf20Sopenharmony_ci			struct ieee80211_channel *chan)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	u8 lna;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (chan->band == NL80211_BAND_2GHZ)
1378c2ecf20Sopenharmony_ci		lna = *lna_2g;
1388c2ecf20Sopenharmony_ci	else if (chan->hw_value <= 64)
1398c2ecf20Sopenharmony_ci		lna = lna_5g[0];
1408c2ecf20Sopenharmony_ci	else if (chan->hw_value <= 128)
1418c2ecf20Sopenharmony_ci		lna = lna_5g[1];
1428c2ecf20Sopenharmony_ci	else
1438c2ecf20Sopenharmony_ci		lna = lna_5g[2];
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return lna != 0xff ? lna : 0;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_get_lna_gain);
148