#include <linux/nvmem-consumer.h>
#include <linux/etherdevice.h>
#include "mt76.h"
+#include "mt76_connac.h"
+
+enum mt76_sku_type {
+ MT76_SKU_RATE,
+ MT76_SKU_BACKOFF,
+ MT76_SKU_BACKOFF_BF_OFFSET,
+};
static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
{
}
EXPORT_SYMBOL_GPL(mt76_find_channel_node);
-
static s8
mt76_get_txs_delta(struct device_node *np, u8 nss)
{
return be32_to_cpu(val[nss - 1]);
}
+static inline u8 mt76_backoff_n_chains(struct mt76_dev *dev, u8 idx)
+{
+ /* 0:1T1ss, 1:2T1ss, ..., 14:5T5ss */
+ static const u8 connac3_table[] = {
+ 1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5};
+ static const u8 connac2_table[] = {
+ 1, 2, 3, 4, 2, 3, 4, 3, 4, 4, 0, 0, 0, 0, 0};
+
+ if (idx >= ARRAY_SIZE(connac3_table))
+ return 0;
+
+ return is_mt799x(dev) ? connac3_table[idx] : connac2_table[idx];
+}
+
static void
-mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data,
- s8 target_power, s8 nss_delta, s8 *max_power)
+mt76_apply_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len,
+ const s8 *data, s8 target_power, s8 nss_delta,
+ s8 *max_power, int n_chains, enum mt76_sku_type type)
{
int i;
return;
for (i = 0; i < pwr_len; i++) {
- pwr[i] = min_t(s8, target_power, data[i] + nss_delta);
+ u8 backoff_chain_idx = i;
+ int backoff_n_chains;
+ s8 backoff_delta;
+ s8 delta;
+
+ switch (type) {
+ case MT76_SKU_RATE:
+ delta = 0;
+ backoff_delta = 0;
+ backoff_n_chains = 0;
+ break;
+ case MT76_SKU_BACKOFF_BF_OFFSET:
+ backoff_chain_idx += 1;
+ fallthrough;
+ case MT76_SKU_BACKOFF:
+ delta = mt76_tx_power_path_delta(n_chains);
+ backoff_n_chains = mt76_backoff_n_chains(dev, backoff_chain_idx);
+ backoff_delta = mt76_tx_power_path_delta(backoff_n_chains);
+ break;
+ default:
+ return;
+ }
+
+ pwr[i] = min_t(s8, target_power + delta - backoff_delta, data[i] + nss_delta);
+
+ /* used for padding, doesn't need to be considered */
+ if (data[i] >= S8_MAX - 1)
+ continue;
+
+ /* only consider backoff value for the configured chain number */
+ if (type != MT76_SKU_RATE && n_chains != backoff_n_chains)
+ continue;
+
*max_power = max(*max_power, pwr[i]);
}
}
static void
-mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
- const s8 *data, size_t len, s8 target_power,
- s8 nss_delta)
+mt76_apply_multi_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len,
+ s8 pwr_num, const s8 *data, size_t len,
+ s8 target_power, s8 nss_delta, s8 *max_power,
+ int n_chains, enum mt76_sku_type type)
{
+ static const int connac2_backoff_ru_idx = 2;
int i, cur;
- s8 max_power = -128;
if (!data)
return;
if (len < pwr_len + 1)
break;
- mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1,
- target_power, nss_delta, &max_power);
+ /* Each RU entry (RU26, RU52, RU106, BW20, ...) in the DTS
+ * corresponds to 10 stream combinations (1T1ss, 2T1ss, 3T1ss,
+ * 4T1ss, 2T2ss, 3T2ss, 4T2ss, 3T3ss, 4T3ss, 4T4ss).
+ *
+ * For beamforming tables:
+ * - In connac2, beamforming entries for BW20~BW160 and OFDM
+ * do not include 1T1ss.
+ * - In connac3, beamforming entries for BW20~BW160 and RU
+ * include 1T1ss, but OFDM beamforming does not include 1T1ss.
+ *
+ * Non-beamforming and RU entries for both connac2 and connac3
+ * include 1T1ss.
+ */
+ if (!is_mt799x(dev) && type == MT76_SKU_BACKOFF &&
+ i > connac2_backoff_ru_idx)
+ type = MT76_SKU_BACKOFF_BF_OFFSET;
+
+ mt76_apply_array_limit(dev, pwr + pwr_len * i, pwr_len, data + 1,
+ target_power, nss_delta, max_power,
+ n_chains, type);
if (--cur > 0)
continue;
struct device_node *np;
const s8 *val;
char name[16];
- u32 mcs_rates = dev->drv->mcs_rates;
- u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
char band;
size_t len;
- s8 max_power = 0;
- s8 max_power_backoff = -127;
+ s8 max_power = -127;
s8 txs_delta;
int n_chains = hweight16(phy->chainmask);
- s8 target_power_combine = target_power + mt76_tx_power_path_delta(n_chains);
-
- if (!mcs_rates)
- mcs_rates = 10;
memset(dest, target_power, sizeof(*dest) - sizeof(dest->path));
memset(&dest->path, 0, sizeof(dest->path));
txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask));
val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck));
- mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val,
- target_power, txs_delta, &max_power);
+ mt76_apply_array_limit(dev, dest->cck, ARRAY_SIZE(dest->cck), val,
+ target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE);
- val = mt76_get_of_array_s8(np, "rates-ofdm",
- &len, ARRAY_SIZE(dest->ofdm));
- mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
- target_power, txs_delta, &max_power);
+ val = mt76_get_of_array_s8(np, "rates-ofdm", &len, ARRAY_SIZE(dest->ofdm));
+ mt76_apply_array_limit(dev, dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
+ target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE);
- val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1);
- mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
- ARRAY_SIZE(dest->mcs), val, len,
- target_power, txs_delta);
+ val = mt76_get_of_array_s8(np, "rates-mcs", &len, ARRAY_SIZE(dest->mcs[0]) + 1);
+ mt76_apply_multi_array_limit(dev, dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
+ ARRAY_SIZE(dest->mcs), val, len, target_power,
+ txs_delta, &max_power, n_chains, MT76_SKU_RATE);
- val = mt76_get_of_array_s8(np, "rates-ru", &len, ru_rates + 1);
- mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
- ARRAY_SIZE(dest->ru), val, len,
- target_power, txs_delta);
+ val = mt76_get_of_array_s8(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1);
+ mt76_apply_multi_array_limit(dev, dest->ru[0], ARRAY_SIZE(dest->ru[0]),
+ ARRAY_SIZE(dest->ru), val, len, target_power,
+ txs_delta, &max_power, n_chains, MT76_SKU_RATE);
- max_power_backoff = max_power;
val = mt76_get_of_array_s8(np, "paths-cck", &len, ARRAY_SIZE(dest->path.cck));
- mt76_apply_array_limit(dest->path.cck, ARRAY_SIZE(dest->path.cck), val,
- target_power_combine, txs_delta, &max_power_backoff);
+ mt76_apply_array_limit(dev, dest->path.cck, ARRAY_SIZE(dest->path.cck), val,
+ target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ofdm", &len, ARRAY_SIZE(dest->path.ofdm));
- mt76_apply_array_limit(dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val,
- target_power_combine, txs_delta, &max_power_backoff);
+ mt76_apply_array_limit(dev, dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val,
+ target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest->path.ofdm_bf));
- mt76_apply_array_limit(dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val,
- target_power_combine, txs_delta, &max_power_backoff);
+ mt76_apply_array_limit(dev, dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val,
+ target_power, txs_delta, &max_power, n_chains,
+ MT76_SKU_BACKOFF_BF_OFFSET);
val = mt76_get_of_array_s8(np, "paths-ru", &len, ARRAY_SIZE(dest->path.ru[0]) + 1);
- mt76_apply_multi_array_limit(dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]),
- ARRAY_SIZE(dest->path.ru), val, len,
- target_power_combine, txs_delta);
+ mt76_apply_multi_array_limit(dev, dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]),
+ ARRAY_SIZE(dest->path.ru), val, len, target_power,
+ txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
val = mt76_get_of_array_s8(np, "paths-ru-bf", &len, ARRAY_SIZE(dest->path.ru_bf[0]) + 1);
- mt76_apply_multi_array_limit(dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]),
- ARRAY_SIZE(dest->path.ru_bf), val, len,
- target_power_combine, txs_delta);
+ mt76_apply_multi_array_limit(dev, dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]),
+ ARRAY_SIZE(dest->path.ru_bf), val, len, target_power,
+ txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
return max_power;
}