Commit 57b328bc authored by Bitterblue Smith's avatar Bitterblue Smith Committed by Kalle Valo
Browse files

wifi: rtl8xxxu: Add central frequency offset tracking



According to Realtek programmers, "to adjust oscillator to align
central frequency of connected AP. Then, it can yield better
performance." From commit fb8517f4 ("rtw88: 8822c: add CFO
tracking").

The RTL8192CU and a version of RTL8723AU apparently don't have the
ability to adjust the oscillator, so this doesn't apply to them.

This also doesn't apply to the wifi + bluetooth combo chips (RTL8723AU
and RTL8723BU) because the CFO tracking should only be done when
bluetooth is disabled, and determining that looked complicated.

That leaves only the RTL8192EU and RTL8188FU chips. I tested this with
the latter.

Signed-off-by: default avatarBitterblue Smith <rtl8821cerfe2@gmail.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/80aba428-0aff-f4b2-dea5-35d1425982b6@gmail.com
parent 683b9728
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -570,7 +570,7 @@ struct rtl8723au_phy_stats {
	u8	cck_rpt_b_ofdm_cfosho_b;
	u8	reserved_1;
	u8	noise_power_db_msb;
	u8	path_cfotail[RTL8723A_MAX_RF_PATHS];
	s8	path_cfotail[RTL8723A_MAX_RF_PATHS];
	u8	pcts_mask[RTL8723A_MAX_RF_PATHS];
	s8	stream_rxevm[RTL8723A_MAX_RF_PATHS];
	u8	path_rxsnr[RTL8723A_MAX_RF_PATHS];
@@ -1323,6 +1323,19 @@ struct rtl8xxxu_ra_report {
	u8 desc_rate;
};

#define CFO_TH_XTAL_HIGH	20 /* kHz */
#define CFO_TH_XTAL_LOW	10 /* kHz */
#define CFO_TH_ATC		80 /* kHz */

struct rtl8xxxu_cfo_tracking {
	bool adjust;
	bool atc_status;
	int cfo_tail[2];
	u8 crystal_cap;
	u32 packet_count;
	u32 packet_count_pre;
};

struct rtl8xxxu_priv {
	struct ieee80211_hw *hw;
	struct usb_device *udev;
@@ -1381,9 +1394,8 @@ struct rtl8xxxu_priv {
	u32 ep_tx_high_queue:1;
	u32 ep_tx_normal_queue:1;
	u32 ep_tx_low_queue:1;
	u32 has_xtalk:1;
	u32 rx_buf_aggregation:1;
	u8 xtalk;
	u8 default_crystal_cap;
	unsigned int pipe_interrupt;
	unsigned int pipe_in;
	unsigned int pipe_out[TXDESC_QUEUE_MAX];
@@ -1441,6 +1453,7 @@ struct rtl8xxxu_priv {
	struct sk_buff_head c2hcmd_queue;
	struct rtl8xxxu_btcoex bt_coex;
	struct rtl8xxxu_ra_report ra_report;
	struct rtl8xxxu_cfo_tracking cfo_tracking;
};

struct rtl8xxxu_rx_urb {
@@ -1485,6 +1498,7 @@ struct rtl8xxxu_fileops {
			     struct rtl8xxxu_txdesc32 *tx_desc, bool sgi,
			     bool short_preamble, bool ampdu_enable,
			     u32 rts_rate);
	void (*set_crystal_cap) (struct rtl8xxxu_priv *priv, u8 crystal_cap);
	int writeN_block_size;
	int rx_agg_buf_size;
	char tx_desc_size;
@@ -1594,6 +1608,7 @@ void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv,
			   u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5);
void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv);
void rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap);

extern struct rtl8xxxu_fileops rtl8188fu_fops;
extern struct rtl8xxxu_fileops rtl8192cu_fops;
+31 −8
Original line number Diff line number Diff line
@@ -703,7 +703,7 @@ static int rtl8188fu_parse_efuse(struct rtl8xxxu_priv *priv)
	priv->ofdm_tx_power_diff[0].a = efuse->tx_power_index_A.ht20_ofdm_1s_diff.a;
	priv->ht20_tx_power_diff[0].a = efuse->tx_power_index_A.ht20_ofdm_1s_diff.b;

	priv->xtalk = efuse->xtal_k & 0x3f;
	priv->default_crystal_cap = efuse->xtal_k & 0x3f;

	dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name);
	dev_info(&priv->udev->dev, "Product: %.7s\n", efuse->device_name);
@@ -737,7 +737,6 @@ static void rtl8188fu_init_phy_bb(struct rtl8xxxu_priv *priv)
{
	u8 val8;
	u16 val16;
	u32 val32;

	/* Enable BB and RF */
	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
@@ -759,12 +758,6 @@ static void rtl8188fu_init_phy_bb(struct rtl8xxxu_priv *priv)

	rtl8xxxu_init_phy_regs(priv, rtl8188fu_phy_init_table);
	rtl8xxxu_init_phy_regs(priv, rtl8188f_agc_table);

	val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
	val8 = priv->xtalk;
	val32 &= ~0x007FF800;
	val32 |= ((val8 | (val8 << 6)) << 11);
	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
}

static int rtl8188fu_init_phy_rf(struct rtl8xxxu_priv *priv)
@@ -1636,6 +1629,35 @@ static void rtl8188f_usb_quirks(struct rtl8xxxu_priv *priv)
	rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32);
}

#define XTAL1	GENMASK(22, 17)
#define XTAL0	GENMASK(16, 11)

static void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap)
{
	struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking;
	u32 val32;

	if (crystal_cap == cfo->crystal_cap)
		return;

	val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);

	dev_dbg(&priv->udev->dev,
	        "%s: Adjusting crystal cap from 0x%x (actually 0x%lx 0x%lx) to 0x%x\n",
	        __func__,
	        cfo->crystal_cap,
	        FIELD_GET(XTAL1, val32),
	        FIELD_GET(XTAL0, val32),
	        crystal_cap);

	val32 &= ~(XTAL1 | XTAL0);
	val32 |= FIELD_PREP(XTAL1, crystal_cap) |
		 FIELD_PREP(XTAL0, crystal_cap);
	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);

	cfo->crystal_cap = crystal_cap;
}

struct rtl8xxxu_fileops rtl8188fu_fops = {
	.parse_efuse = rtl8188fu_parse_efuse,
	.load_firmware = rtl8188fu_load_firmware,
@@ -1659,6 +1681,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = {
	.update_rate_mask = rtl8xxxu_gen2_update_rate_mask,
	.report_connect = rtl8xxxu_gen2_report_connect,
	.fill_txdesc = rtl8xxxu_fill_txdesc_v2,
	.set_crystal_cap = rtl8188f_set_crystal_cap,
	.writeN_block_size = 128,
	.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24),
	.tx_desc_size = sizeof(struct rtl8xxxu_txdesc40),
+2 −2
Original line number Diff line number Diff line
@@ -635,8 +635,7 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv)
			efuse->tx_power_index_B.pwr_diff[i - 1].ht40;
	}

	priv->has_xtalk = 1;
	priv->xtalk = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f;
	priv->default_crystal_cap = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f;

	/*
	 * device_info section seems to be laid out as records
@@ -1691,6 +1690,7 @@ struct rtl8xxxu_fileops rtl8192eu_fops = {
	.update_rate_mask = rtl8xxxu_gen2_update_rate_mask,
	.report_connect = rtl8xxxu_gen2_report_connect,
	.fill_txdesc = rtl8xxxu_fill_txdesc_v2,
	.set_crystal_cap = rtl8723a_set_crystal_cap,
	.writeN_block_size = 128,
	.tx_desc_size = sizeof(struct rtl8xxxu_txdesc40),
	.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24),
+34 −4
Original line number Diff line number Diff line
@@ -166,10 +166,10 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv)
	       efuse->ht20_max_power_offset,
	       sizeof(efuse->ht20_max_power_offset));

	if (priv->efuse_wifi.efuse8723.version >= 0x01) {
		priv->has_xtalk = 1;
		priv->xtalk = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
	}
	if (priv->efuse_wifi.efuse8723.version >= 0x01)
		priv->default_crystal_cap = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
	else
		priv->fops->set_crystal_cap = NULL;

	priv->power_base = &rtl8723a_power_base;

@@ -357,6 +357,35 @@ static int rtl8723au_power_on(struct rtl8xxxu_priv *priv)
	return ret;
}

#define XTAL1	GENMASK(23, 18)
#define XTAL0	GENMASK(17, 12)

void rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap)
{
	struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking;
	u32 val32;

	if (crystal_cap == cfo->crystal_cap)
		return;

	val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL);

	dev_dbg(&priv->udev->dev,
	        "%s: Adjusting crystal cap from 0x%x (actually 0x%lx 0x%lx) to 0x%x\n",
	        __func__,
	        cfo->crystal_cap,
	        FIELD_GET(XTAL1, val32),
	        FIELD_GET(XTAL0, val32),
	        crystal_cap);

	val32 &= ~(XTAL1 | XTAL0);
	val32 |= FIELD_PREP(XTAL1, crystal_cap) |
		 FIELD_PREP(XTAL0, crystal_cap);
	rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32);

	cfo->crystal_cap = crystal_cap;
}

struct rtl8xxxu_fileops rtl8723au_fops = {
	.parse_efuse = rtl8723au_parse_efuse,
	.load_firmware = rtl8723au_load_firmware,
@@ -378,6 +407,7 @@ struct rtl8xxxu_fileops rtl8723au_fops = {
	.update_rate_mask = rtl8xxxu_update_rate_mask,
	.report_connect = rtl8xxxu_gen1_report_connect,
	.fill_txdesc = rtl8xxxu_fill_txdesc_v1,
	.set_crystal_cap = rtl8723a_set_crystal_cap,
	.writeN_block_size = 1024,
	.rx_agg_buf_size = 16000,
	.tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
+2 −2
Original line number Diff line number Diff line
@@ -445,8 +445,7 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv)
			efuse->tx_power_index_B.pwr_diff[i - 1].ht40;
	}

	priv->has_xtalk = 1;
	priv->xtalk = priv->efuse_wifi.efuse8723bu.xtal_k & 0x3f;
	priv->default_crystal_cap = priv->efuse_wifi.efuse8723bu.xtal_k & 0x3f;

	dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name);
	dev_info(&priv->udev->dev, "Product: %.41s\n", efuse->device_name);
@@ -1663,6 +1662,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = {
	.update_rate_mask = rtl8xxxu_gen2_update_rate_mask,
	.report_connect = rtl8xxxu_gen2_report_connect,
	.fill_txdesc = rtl8xxxu_fill_txdesc_v2,
	.set_crystal_cap = rtl8723a_set_crystal_cap,
	.writeN_block_size = 1024,
	.tx_desc_size = sizeof(struct rtl8xxxu_txdesc40),
	.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24),
Loading