Commit e885871e authored by Zong-Zhe Yang's avatar Zong-Zhe Yang Committed by Kalle Valo
Browse files

rtw89: 8852c: support bb gain info



Add parser for bb gain table and configure bb gain table for 8852c.
While ctrl_ch, obtain bb gain error settings and write them to phy.

Signed-off-by: default avatarZong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220414062027.62638-7-pkshih@realtek.com
parent cc99eefa
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -3000,6 +3000,41 @@ struct rtw89_hw_scan_info {
	u8 op_band;
};

enum rtw89_phy_bb_gain_band {
	RTW89_BB_GAIN_BAND_2G = 0,
	RTW89_BB_GAIN_BAND_5G_L = 1,
	RTW89_BB_GAIN_BAND_5G_M = 2,
	RTW89_BB_GAIN_BAND_5G_H = 3,
	RTW89_BB_GAIN_BAND_6G_L = 4,
	RTW89_BB_GAIN_BAND_6G_M = 5,
	RTW89_BB_GAIN_BAND_6G_H = 6,
	RTW89_BB_GAIN_BAND_6G_UH = 7,

	RTW89_BB_GAIN_BAND_NR,
};

enum rtw89_phy_bb_rxsc_num {
	RTW89_BB_RXSC_NUM_40 = 9, /* SC: 0, 1~8 */
	RTW89_BB_RXSC_NUM_80 = 13, /* SC: 0, 1~8, 9~12 */
	RTW89_BB_RXSC_NUM_160 = 15, /* SC: 0, 1~8, 9~12, 13~14 */
};

struct rtw89_phy_bb_gain_info {
	s8 lna_gain[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX][LNA_GAIN_NUM];
	s8 tia_gain[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX][TIA_GAIN_NUM];
	s8 lna_gain_bypass[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX][LNA_GAIN_NUM];
	s8 lna_op1db[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX][LNA_GAIN_NUM];
	s8 tia_lna_op1db[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX]
			[LNA_GAIN_NUM + 1]; /* TIA0_LNA0~6 + TIA1_LNA6 */
	s8 rpl_ofst_20[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX];
	s8 rpl_ofst_40[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX]
		      [RTW89_BB_RXSC_NUM_40];
	s8 rpl_ofst_80[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX]
		      [RTW89_BB_RXSC_NUM_80];
	s8 rpl_ofst_160[RTW89_BB_GAIN_BAND_NR][RF_PATH_MAX]
		       [RTW89_BB_RXSC_NUM_160];
};

struct rtw89_dev {
	struct ieee80211_hw *hw;
	struct device *dev;
@@ -3062,6 +3097,8 @@ struct rtw89_dev {
	struct rtw89_env_monitor_info env_monitor;
	struct rtw89_dig_info dig;
	struct rtw89_phy_ch_info ch_info;
	struct rtw89_phy_bb_gain_info bb_gain;

	struct delayed_work track_work;
	struct delayed_work coex_act1_work;
	struct delayed_work coex_bt_devinfo_work;
+243 −0
Original line number Diff line number Diff line
@@ -790,6 +790,245 @@ static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev,
		rtw89_phy_write32(rtwdev, reg->addr, reg->data);
}

union rtw89_phy_bb_gain_arg {
	u32 addr;
	struct {
		union {
			u8 type;
			struct {
				u8 rxsc_start:4;
				u8 bw:4;
			};
		};
		u8 path;
		u8 gain_band;
		u8 cfg_type;
	};
} __packed;

static void
rtw89_phy_cfg_bb_gain_error(struct rtw89_dev *rtwdev,
			    union rtw89_phy_bb_gain_arg arg, u32 data)
{
	struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
	u8 type = arg.type;
	u8 path = arg.path;
	u8 gband = arg.gain_band;
	int i;

	switch (type) {
	case 0:
		for (i = 0; i < 4; i++, data >>= 8)
			gain->lna_gain[gband][path][i] = data & 0xff;
		break;
	case 1:
		for (i = 4; i < 7; i++, data >>= 8)
			gain->lna_gain[gband][path][i] = data & 0xff;
		break;
	case 2:
		for (i = 0; i < 2; i++, data >>= 8)
			gain->tia_gain[gband][path][i] = data & 0xff;
		break;
	default:
		rtw89_warn(rtwdev,
			   "bb gain error {0x%x:0x%x} with unknown type: %d\n",
			   arg.addr, data, type);
		break;
	}
}

enum rtw89_phy_bb_rxsc_start_idx {
	RTW89_BB_RXSC_START_IDX_FULL = 0,
	RTW89_BB_RXSC_START_IDX_20 = 1,
	RTW89_BB_RXSC_START_IDX_20_1 = 5,
	RTW89_BB_RXSC_START_IDX_40 = 9,
	RTW89_BB_RXSC_START_IDX_80 = 13,
};

static void
rtw89_phy_cfg_bb_rpl_ofst(struct rtw89_dev *rtwdev,
			  union rtw89_phy_bb_gain_arg arg, u32 data)
{
	struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
	u8 rxsc_start = arg.rxsc_start;
	u8 bw = arg.bw;
	u8 path = arg.path;
	u8 gband = arg.gain_band;
	u8 rxsc;
	s8 ofst;
	int i;

	switch (bw) {
	case RTW89_CHANNEL_WIDTH_20:
		gain->rpl_ofst_20[gband][path] = (s8)data;
		break;
	case RTW89_CHANNEL_WIDTH_40:
		if (rxsc_start == RTW89_BB_RXSC_START_IDX_FULL) {
			gain->rpl_ofst_40[gband][path][0] = (s8)data;
		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_20) {
			for (i = 0; i < 2; i++, data >>= 8) {
				rxsc = RTW89_BB_RXSC_START_IDX_20 + i;
				ofst = (s8)(data & 0xff);
				gain->rpl_ofst_40[gband][path][rxsc] = ofst;
			}
		}
		break;
	case RTW89_CHANNEL_WIDTH_80:
		if (rxsc_start == RTW89_BB_RXSC_START_IDX_FULL) {
			gain->rpl_ofst_80[gband][path][0] = (s8)data;
		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_20) {
			for (i = 0; i < 4; i++, data >>= 8) {
				rxsc = RTW89_BB_RXSC_START_IDX_20 + i;
				ofst = (s8)(data & 0xff);
				gain->rpl_ofst_80[gband][path][rxsc] = ofst;
			}
		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_40) {
			for (i = 0; i < 2; i++, data >>= 8) {
				rxsc = RTW89_BB_RXSC_START_IDX_40 + i;
				ofst = (s8)(data & 0xff);
				gain->rpl_ofst_80[gband][path][rxsc] = ofst;
			}
		}
		break;
	case RTW89_CHANNEL_WIDTH_160:
		if (rxsc_start == RTW89_BB_RXSC_START_IDX_FULL) {
			gain->rpl_ofst_160[gband][path][0] = (s8)data;
		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_20) {
			for (i = 0; i < 4; i++, data >>= 8) {
				rxsc = RTW89_BB_RXSC_START_IDX_20 + i;
				ofst = (s8)(data & 0xff);
				gain->rpl_ofst_160[gband][path][rxsc] = ofst;
			}
		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_20_1) {
			for (i = 0; i < 4; i++, data >>= 8) {
				rxsc = RTW89_BB_RXSC_START_IDX_20_1 + i;
				ofst = (s8)(data & 0xff);
				gain->rpl_ofst_160[gband][path][rxsc] = ofst;
			}
		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_40) {
			for (i = 0; i < 4; i++, data >>= 8) {
				rxsc = RTW89_BB_RXSC_START_IDX_40 + i;
				ofst = (s8)(data & 0xff);
				gain->rpl_ofst_160[gband][path][rxsc] = ofst;
			}
		} else if (rxsc_start == RTW89_BB_RXSC_START_IDX_80) {
			for (i = 0; i < 2; i++, data >>= 8) {
				rxsc = RTW89_BB_RXSC_START_IDX_80 + i;
				ofst = (s8)(data & 0xff);
				gain->rpl_ofst_160[gband][path][rxsc] = ofst;
			}
		}
		break;
	default:
		rtw89_warn(rtwdev,
			   "bb rpl ofst {0x%x:0x%x} with unknown bw: %d\n",
			   arg.addr, data, bw);
		break;
	}
}

static void
rtw89_phy_cfg_bb_gain_bypass(struct rtw89_dev *rtwdev,
			     union rtw89_phy_bb_gain_arg arg, u32 data)
{
	struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
	u8 type = arg.type;
	u8 path = arg.path;
	u8 gband = arg.gain_band;
	int i;

	switch (type) {
	case 0:
		for (i = 0; i < 4; i++, data >>= 8)
			gain->lna_gain_bypass[gband][path][i] = data & 0xff;
		break;
	case 1:
		for (i = 4; i < 7; i++, data >>= 8)
			gain->lna_gain_bypass[gband][path][i] = data & 0xff;
		break;
	default:
		rtw89_warn(rtwdev,
			   "bb gain bypass {0x%x:0x%x} with unknown type: %d\n",
			   arg.addr, data, type);
		break;
	}
}

static void
rtw89_phy_cfg_bb_gain_op1db(struct rtw89_dev *rtwdev,
			    union rtw89_phy_bb_gain_arg arg, u32 data)
{
	struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
	u8 type = arg.type;
	u8 path = arg.path;
	u8 gband = arg.gain_band;
	int i;

	switch (type) {
	case 0:
		for (i = 0; i < 4; i++, data >>= 8)
			gain->lna_op1db[gband][path][i] = data & 0xff;
		break;
	case 1:
		for (i = 4; i < 7; i++, data >>= 8)
			gain->lna_op1db[gband][path][i] = data & 0xff;
		break;
	case 2:
		for (i = 0; i < 4; i++, data >>= 8)
			gain->tia_lna_op1db[gband][path][i] = data & 0xff;
		break;
	case 3:
		for (i = 4; i < 8; i++, data >>= 8)
			gain->tia_lna_op1db[gband][path][i] = data & 0xff;
		break;
	default:
		rtw89_warn(rtwdev,
			   "bb gain op1db {0x%x:0x%x} with unknown type: %d\n",
			   arg.addr, data, type);
		break;
	}
}

static void rtw89_phy_config_bb_gain(struct rtw89_dev *rtwdev,
				     const struct rtw89_reg2_def *reg,
				     enum rtw89_rf_path rf_path,
				     void *extra_data)
{
	const struct rtw89_chip_info *chip = rtwdev->chip;
	union rtw89_phy_bb_gain_arg arg = { .addr = reg->addr };

	if (arg.gain_band >= RTW89_BB_GAIN_BAND_NR)
		return;

	if (arg.path >= chip->rf_path_num)
		return;

	if (arg.addr >= 0xf9 && arg.addr <= 0xfe) {
		rtw89_warn(rtwdev, "bb gain table with flow ctrl\n");
		return;
	}

	switch (arg.cfg_type) {
	case 0:
		rtw89_phy_cfg_bb_gain_error(rtwdev, arg, reg->data);
		break;
	case 1:
		rtw89_phy_cfg_bb_rpl_ofst(rtwdev, arg, reg->data);
		break;
	case 2:
		rtw89_phy_cfg_bb_gain_bypass(rtwdev, arg, reg->data);
		break;
	case 3:
		rtw89_phy_cfg_bb_gain_op1db(rtwdev, arg, reg->data);
		break;
	default:
		rtw89_warn(rtwdev,
			   "bb gain {0x%x:0x%x} with unknown cfg type: %d\n",
			   arg.addr, reg->data, arg.cfg_type);
		break;
	}
}

static void
rtw89_phy_cofig_rf_reg_store(struct rtw89_dev *rtwdev,
			     const struct rtw89_reg2_def *reg,
@@ -1033,9 +1272,13 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev)
{
	const struct rtw89_chip_info *chip = rtwdev->chip;
	const struct rtw89_phy_table *bb_table = chip->bb_table;
	const struct rtw89_phy_table *bb_gain_table = chip->bb_gain_table;

	rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, NULL);
	rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0);
	if (bb_gain_table)
		rtw89_phy_init_reg(rtwdev, bb_gain_table,
				   rtw89_phy_config_bb_gain, NULL);
	rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0);
}

+178 −0
Original line number Diff line number Diff line
@@ -495,6 +495,184 @@ static void rtw8852c_power_trim(struct rtw89_dev *rtwdev)
	rtw8852c_pa_bias_trim(rtwdev);
}

struct rtw8852c_bb_gain {
	u32 gain_g[BB_PATH_NUM_8852C];
	u32 gain_a[BB_PATH_NUM_8852C];
	u32 gain_mask;
};

static const struct rtw8852c_bb_gain bb_gain_lna[LNA_GAIN_NUM] = {
	{ .gain_g = {0x4678, 0x475C}, .gain_a = {0x45DC, 0x4740},
	  .gain_mask = 0x00ff0000 },
	{ .gain_g = {0x4678, 0x475C}, .gain_a = {0x45DC, 0x4740},
	  .gain_mask = 0xff000000 },
	{ .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744},
	  .gain_mask = 0x000000ff },
	{ .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744},
	  .gain_mask = 0x0000ff00 },
	{ .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744},
	  .gain_mask = 0x00ff0000 },
	{ .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744},
	  .gain_mask = 0xff000000 },
	{ .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748},
	  .gain_mask = 0x000000ff },
};

static const struct rtw8852c_bb_gain bb_gain_tia[TIA_GAIN_NUM] = {
	{ .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748},
	  .gain_mask = 0x00ff0000 },
	{ .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748},
	  .gain_mask = 0xff000000 },
};

struct rtw8852c_bb_gain_bypass {
	u32 gain_g[BB_PATH_NUM_8852C];
	u32 gain_a[BB_PATH_NUM_8852C];
	u32 gain_mask_g;
	u32 gain_mask_a;
};

static
const struct rtw8852c_bb_gain_bypass bb_gain_bypass_lna[LNA_GAIN_NUM] = {
	{ .gain_g = {0x4BB8, 0x4C7C}, .gain_a = {0x4BB4, 0x4C78},
	  .gain_mask_g = 0xff000000, .gain_mask_a = 0xff},
	{ .gain_g = {0x4BBC, 0x4C80}, .gain_a = {0x4BB4, 0x4C78},
	  .gain_mask_g = 0xff, .gain_mask_a = 0xff00},
	{ .gain_g = {0x4BBC, 0x4C80}, .gain_a = {0x4BB4, 0x4C78},
	  .gain_mask_g = 0xff00, .gain_mask_a = 0xff0000},
	{ .gain_g = {0x4BBC, 0x4C80}, .gain_a = {0x4BB4, 0x4C78},
	  .gain_mask_g = 0xff0000, .gain_mask_a = 0xff000000},
	{ .gain_g = {0x4BBC, 0x4C80}, .gain_a = {0x4BB8, 0x4C7C},
	  .gain_mask_g = 0xff000000, .gain_mask_a = 0xff},
	{ .gain_g = {0x4BC0, 0x4C84}, .gain_a = {0x4BB8, 0x4C7C},
	  .gain_mask_g = 0xff, .gain_mask_a = 0xff00},
	{ .gain_g = {0x4BC0, 0x4C84}, .gain_a = {0x4BB8, 0x4C7C},
	  .gain_mask_g = 0xff00, .gain_mask_a = 0xff0000},
};

struct rtw8852c_bb_gain_op1db {
	struct {
		u32 lna[BB_PATH_NUM_8852C];
		u32 tia_lna[BB_PATH_NUM_8852C];
		u32 mask;
	} reg[LNA_GAIN_NUM];
	u32 reg_tia0_lna6[BB_PATH_NUM_8852C];
	u32 mask_tia0_lna6;
};

static const struct rtw8852c_bb_gain_op1db bb_gain_op1db_a = {
	.reg = {
		{ .lna = {0x4668, 0x474c}, .tia_lna = {0x4670, 0x4754},
		  .mask = 0xff},
		{ .lna = {0x4668, 0x474c}, .tia_lna = {0x4670, 0x4754},
		  .mask = 0xff00},
		{ .lna = {0x4668, 0x474c}, .tia_lna = {0x4670, 0x4754},
		  .mask = 0xff0000},
		{ .lna = {0x4668, 0x474c}, .tia_lna = {0x4670, 0x4754},
		  .mask = 0xff000000},
		{ .lna = {0x466c, 0x4750}, .tia_lna = {0x4674, 0x4758},
		  .mask = 0xff},
		{ .lna = {0x466c, 0x4750}, .tia_lna = {0x4674, 0x4758},
		  .mask = 0xff00},
		{ .lna = {0x466c, 0x4750}, .tia_lna = {0x4674, 0x4758},
		  .mask = 0xff0000},
	},
	.reg_tia0_lna6 = {0x4674, 0x4758},
	.mask_tia0_lna6 = 0xff000000,
};

static enum rtw89_phy_bb_gain_band
rtw8852c_mapping_gain_band(enum rtw89_subband subband)
{
	switch (subband) {
	default:
	case RTW89_CH_2G:
		return RTW89_BB_GAIN_BAND_2G;
	case RTW89_CH_5G_BAND_1:
		return RTW89_BB_GAIN_BAND_5G_L;
	case RTW89_CH_5G_BAND_3:
		return RTW89_BB_GAIN_BAND_5G_M;
	case RTW89_CH_5G_BAND_4:
		return RTW89_BB_GAIN_BAND_5G_H;
	case RTW89_CH_6G_BAND_IDX0:
	case RTW89_CH_6G_BAND_IDX1:
		return RTW89_BB_GAIN_BAND_6G_L;
	case RTW89_CH_6G_BAND_IDX2:
	case RTW89_CH_6G_BAND_IDX3:
		return RTW89_BB_GAIN_BAND_6G_M;
	case RTW89_CH_6G_BAND_IDX4:
	case RTW89_CH_6G_BAND_IDX5:
		return RTW89_BB_GAIN_BAND_6G_H;
	case RTW89_CH_6G_BAND_IDX6:
	case RTW89_CH_6G_BAND_IDX7:
		return RTW89_BB_GAIN_BAND_6G_UH;
	}
}

static void rtw8852c_set_gain_error(struct rtw89_dev *rtwdev,
				    enum rtw89_subband subband,
				    enum rtw89_rf_path path)
{
	const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
	u8 gain_band = rtw8852c_mapping_gain_band(subband);
	s32 val;
	u32 reg;
	u32 mask;
	int i;

	for (i = 0; i < LNA_GAIN_NUM; i++) {
		if (subband == RTW89_CH_2G)
			reg = bb_gain_lna[i].gain_g[path];
		else
			reg = bb_gain_lna[i].gain_a[path];

		mask = bb_gain_lna[i].gain_mask;
		val = gain->lna_gain[gain_band][path][i];
		rtw89_phy_write32_mask(rtwdev, reg, mask, val);

		if (subband == RTW89_CH_2G) {
			reg = bb_gain_bypass_lna[i].gain_g[path];
			mask = bb_gain_bypass_lna[i].gain_mask_g;
		} else {
			reg = bb_gain_bypass_lna[i].gain_a[path];
			mask = bb_gain_bypass_lna[i].gain_mask_a;
		}

		val = gain->lna_gain_bypass[gain_band][path][i];
		rtw89_phy_write32_mask(rtwdev, reg, mask, val);

		if (subband != RTW89_CH_2G) {
			reg = bb_gain_op1db_a.reg[i].lna[path];
			mask = bb_gain_op1db_a.reg[i].mask;
			val = gain->lna_op1db[gain_band][path][i];
			rtw89_phy_write32_mask(rtwdev, reg, mask, val);

			reg = bb_gain_op1db_a.reg[i].tia_lna[path];
			mask = bb_gain_op1db_a.reg[i].mask;
			val = gain->tia_lna_op1db[gain_band][path][i];
			rtw89_phy_write32_mask(rtwdev, reg, mask, val);
		}
	}

	if (subband != RTW89_CH_2G) {
		reg = bb_gain_op1db_a.reg_tia0_lna6[path];
		mask = bb_gain_op1db_a.mask_tia0_lna6;
		val = gain->tia_lna_op1db[gain_band][path][7];
		rtw89_phy_write32_mask(rtwdev, reg, mask, val);
	}

	for (i = 0; i < TIA_GAIN_NUM; i++) {
		if (subband == RTW89_CH_2G)
			reg = bb_gain_tia[i].gain_g[path];
		else
			reg = bb_gain_tia[i].gain_a[path];

		mask = bb_gain_tia[i].gain_mask;
		val = gain->tia_gain[gain_band][path][i];
		rtw89_phy_write32_mask(rtwdev, reg, mask, val);
	}
}

static void rtw8852c_bb_reset_all(struct rtw89_dev *rtwdev,
				  enum rtw89_phy_idx phy_idx)
{
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include "core.h"

#define RF_PATH_NUM_8852C 2
#define BB_PATH_NUM_8852C 2

struct rtw8852c_u_efuse {
	u8 rsvd[0x38];