162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * RTL8XXXU mac80211 USB driver - 8723a specific subdriver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2014 - 2017 Jes Sorensen <Jes.Sorensen@gmail.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Portions, notably calibration code:
862306a36Sopenharmony_ci * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * This driver was written as a replacement for the vendor provided
1162306a36Sopenharmony_ci * rtl8723au driver. As the Realtek 8xxx chips are very similar in
1262306a36Sopenharmony_ci * their programming interface, I have started adding support for
1362306a36Sopenharmony_ci * additional 8xxx chips like the 8192cu, 8188cus, etc.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/sched.h>
1962306a36Sopenharmony_ci#include <linux/errno.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci#include <linux/spinlock.h>
2362306a36Sopenharmony_ci#include <linux/list.h>
2462306a36Sopenharmony_ci#include <linux/usb.h>
2562306a36Sopenharmony_ci#include <linux/netdevice.h>
2662306a36Sopenharmony_ci#include <linux/etherdevice.h>
2762306a36Sopenharmony_ci#include <linux/ethtool.h>
2862306a36Sopenharmony_ci#include <linux/wireless.h>
2962306a36Sopenharmony_ci#include <linux/firmware.h>
3062306a36Sopenharmony_ci#include <linux/moduleparam.h>
3162306a36Sopenharmony_ci#include <net/mac80211.h>
3262306a36Sopenharmony_ci#include "rtl8xxxu.h"
3362306a36Sopenharmony_ci#include "rtl8xxxu_regs.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic struct rtl8xxxu_power_base rtl8723a_power_base = {
3662306a36Sopenharmony_ci	.reg_0e00 = 0x0a0c0c0c,
3762306a36Sopenharmony_ci	.reg_0e04 = 0x02040608,
3862306a36Sopenharmony_ci	.reg_0e08 = 0x00000000,
3962306a36Sopenharmony_ci	.reg_086c = 0x00000000,
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	.reg_0e10 = 0x0a0c0d0e,
4262306a36Sopenharmony_ci	.reg_0e14 = 0x02040608,
4362306a36Sopenharmony_ci	.reg_0e18 = 0x0a0c0d0e,
4462306a36Sopenharmony_ci	.reg_0e1c = 0x02040608,
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	.reg_0830 = 0x0a0c0c0c,
4762306a36Sopenharmony_ci	.reg_0834 = 0x02040608,
4862306a36Sopenharmony_ci	.reg_0838 = 0x00000000,
4962306a36Sopenharmony_ci	.reg_086c_2 = 0x00000000,
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	.reg_083c = 0x0a0c0d0e,
5262306a36Sopenharmony_ci	.reg_0848 = 0x02040608,
5362306a36Sopenharmony_ci	.reg_084c = 0x0a0c0d0e,
5462306a36Sopenharmony_ci	.reg_0868 = 0x02040608,
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic const struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = {
5862306a36Sopenharmony_ci	{0x00, 0x00030159}, {0x01, 0x00031284},
5962306a36Sopenharmony_ci	{0x02, 0x00098000}, {0x03, 0x00039c63},
6062306a36Sopenharmony_ci	{0x04, 0x000210e7}, {0x09, 0x0002044f},
6162306a36Sopenharmony_ci	{0x0a, 0x0001a3f1}, {0x0b, 0x00014787},
6262306a36Sopenharmony_ci	{0x0c, 0x000896fe}, {0x0d, 0x0000e02c},
6362306a36Sopenharmony_ci	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
6462306a36Sopenharmony_ci	{0x19, 0x00000000}, {0x1a, 0x00030355},
6562306a36Sopenharmony_ci	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
6662306a36Sopenharmony_ci	{0x1d, 0x000a1250}, {0x1e, 0x0000024f},
6762306a36Sopenharmony_ci	{0x1f, 0x00000000}, {0x20, 0x0000b614},
6862306a36Sopenharmony_ci	{0x21, 0x0006c000}, {0x22, 0x00000000},
6962306a36Sopenharmony_ci	{0x23, 0x00001558}, {0x24, 0x00000060},
7062306a36Sopenharmony_ci	{0x25, 0x00000483}, {0x26, 0x0004f000},
7162306a36Sopenharmony_ci	{0x27, 0x000ec7d9}, {0x28, 0x00057730},
7262306a36Sopenharmony_ci	{0x29, 0x00004783}, {0x2a, 0x00000001},
7362306a36Sopenharmony_ci	{0x2b, 0x00021334}, {0x2a, 0x00000000},
7462306a36Sopenharmony_ci	{0x2b, 0x00000054}, {0x2a, 0x00000001},
7562306a36Sopenharmony_ci	{0x2b, 0x00000808}, {0x2b, 0x00053333},
7662306a36Sopenharmony_ci	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
7762306a36Sopenharmony_ci	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
7862306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
7962306a36Sopenharmony_ci	{0x2b, 0x00000808}, {0x2b, 0x00063333},
8062306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
8162306a36Sopenharmony_ci	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
8262306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
8362306a36Sopenharmony_ci	{0x2b, 0x00000808}, {0x2b, 0x00073333},
8462306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
8562306a36Sopenharmony_ci	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
8662306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
8762306a36Sopenharmony_ci	{0x2b, 0x00000709}, {0x2b, 0x00063333},
8862306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
8962306a36Sopenharmony_ci	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
9062306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
9162306a36Sopenharmony_ci	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
9262306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
9362306a36Sopenharmony_ci	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
9462306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
9562306a36Sopenharmony_ci	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
9662306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
9762306a36Sopenharmony_ci	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
9862306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
9962306a36Sopenharmony_ci	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
10062306a36Sopenharmony_ci	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
10162306a36Sopenharmony_ci	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
10262306a36Sopenharmony_ci	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
10362306a36Sopenharmony_ci	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
10462306a36Sopenharmony_ci	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
10562306a36Sopenharmony_ci	{0x10, 0x0002000f}, {0x11, 0x000203f9},
10662306a36Sopenharmony_ci	{0x10, 0x0003000f}, {0x11, 0x000ff500},
10762306a36Sopenharmony_ci	{0x10, 0x00000000}, {0x11, 0x00000000},
10862306a36Sopenharmony_ci	{0x10, 0x0008000f}, {0x11, 0x0003f100},
10962306a36Sopenharmony_ci	{0x10, 0x0009000f}, {0x11, 0x00023100},
11062306a36Sopenharmony_ci	{0x12, 0x00032000}, {0x12, 0x00071000},
11162306a36Sopenharmony_ci	{0x12, 0x000b0000}, {0x12, 0x000fc000},
11262306a36Sopenharmony_ci	{0x13, 0x000287b3}, {0x13, 0x000244b7},
11362306a36Sopenharmony_ci	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
11462306a36Sopenharmony_ci	{0x13, 0x00018493}, {0x13, 0x0001429b},
11562306a36Sopenharmony_ci	{0x13, 0x00010299}, {0x13, 0x0000c29c},
11662306a36Sopenharmony_ci	{0x13, 0x000081a0}, {0x13, 0x000040ac},
11762306a36Sopenharmony_ci	{0x13, 0x00000020}, {0x14, 0x0001944c},
11862306a36Sopenharmony_ci	{0x14, 0x00059444}, {0x14, 0x0009944c},
11962306a36Sopenharmony_ci	{0x14, 0x000d9444}, {0x15, 0x0000f474},
12062306a36Sopenharmony_ci	{0x15, 0x0004f477}, {0x15, 0x0008f455},
12162306a36Sopenharmony_ci	{0x15, 0x000cf455}, {0x16, 0x00000339},
12262306a36Sopenharmony_ci	{0x16, 0x00040339}, {0x16, 0x00080339},
12362306a36Sopenharmony_ci	{0x16, 0x000c0366}, {0x00, 0x00010159},
12462306a36Sopenharmony_ci	{0x18, 0x0000f401}, {0xfe, 0x00000000},
12562306a36Sopenharmony_ci	{0xfe, 0x00000000}, {0x1f, 0x00000003},
12662306a36Sopenharmony_ci	{0xfe, 0x00000000}, {0xfe, 0x00000000},
12762306a36Sopenharmony_ci	{0x1e, 0x00000247}, {0x1f, 0x00000000},
12862306a36Sopenharmony_ci	{0x00, 0x00030159},
12962306a36Sopenharmony_ci	{0xff, 0xffffffff}
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int rtl8723au_identify_chip(struct rtl8xxxu_priv *priv)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct device *dev = &priv->udev->dev;
13562306a36Sopenharmony_ci	u32 val32, sys_cfg, vendor;
13662306a36Sopenharmony_ci	int ret = 0;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG);
13962306a36Sopenharmony_ci	priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK);
14062306a36Sopenharmony_ci	if (sys_cfg & SYS_CFG_TRP_VAUX_EN) {
14162306a36Sopenharmony_ci		dev_info(dev, "Unsupported test chip\n");
14262306a36Sopenharmony_ci		ret = -ENOTSUPP;
14362306a36Sopenharmony_ci		goto out;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	strscpy(priv->chip_name, "8723AU", sizeof(priv->chip_name));
14762306a36Sopenharmony_ci	priv->usb_interrupts = 1;
14862306a36Sopenharmony_ci	priv->rtl_chip = RTL8723A;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	priv->rf_paths = 1;
15162306a36Sopenharmony_ci	priv->rx_paths = 1;
15262306a36Sopenharmony_ci	priv->tx_paths = 1;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL);
15562306a36Sopenharmony_ci	if (val32 & MULTI_WIFI_FUNC_EN)
15662306a36Sopenharmony_ci		priv->has_wifi = 1;
15762306a36Sopenharmony_ci	if (val32 & MULTI_BT_FUNC_EN)
15862306a36Sopenharmony_ci		priv->has_bluetooth = 1;
15962306a36Sopenharmony_ci	if (val32 & MULTI_GPS_FUNC_EN)
16062306a36Sopenharmony_ci		priv->has_gps = 1;
16162306a36Sopenharmony_ci	priv->is_multi_func = 1;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	vendor = sys_cfg & SYS_CFG_VENDOR_ID;
16462306a36Sopenharmony_ci	rtl8xxxu_identify_vendor_1bit(priv, vendor);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS);
16762306a36Sopenharmony_ci	priv->rom_rev = u32_get_bits(val32, GPIO_RF_RL_ID);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	rtl8xxxu_config_endpoints_sie(priv);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/*
17262306a36Sopenharmony_ci	 * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX
17362306a36Sopenharmony_ci	 */
17462306a36Sopenharmony_ci	if (!priv->ep_tx_count)
17562306a36Sopenharmony_ci		ret = rtl8xxxu_config_endpoints_no_sie(priv);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ciout:
17862306a36Sopenharmony_ci	return ret;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct rtl8723au_efuse *efuse = &priv->efuse_wifi.efuse8723;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (efuse->rtl_id != cpu_to_le16(0x8129))
18662306a36Sopenharmony_ci		return -EINVAL;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	ether_addr_copy(priv->mac_addr, efuse->mac_addr);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	memcpy(priv->cck_tx_power_index_A,
19162306a36Sopenharmony_ci	       efuse->cck_tx_power_index_A,
19262306a36Sopenharmony_ci	       sizeof(efuse->cck_tx_power_index_A));
19362306a36Sopenharmony_ci	memcpy(priv->cck_tx_power_index_B,
19462306a36Sopenharmony_ci	       efuse->cck_tx_power_index_B,
19562306a36Sopenharmony_ci	       sizeof(efuse->cck_tx_power_index_B));
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	memcpy(priv->ht40_1s_tx_power_index_A,
19862306a36Sopenharmony_ci	       efuse->ht40_1s_tx_power_index_A,
19962306a36Sopenharmony_ci	       sizeof(efuse->ht40_1s_tx_power_index_A));
20062306a36Sopenharmony_ci	memcpy(priv->ht40_1s_tx_power_index_B,
20162306a36Sopenharmony_ci	       efuse->ht40_1s_tx_power_index_B,
20262306a36Sopenharmony_ci	       sizeof(efuse->ht40_1s_tx_power_index_B));
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	memcpy(priv->ht20_tx_power_index_diff,
20562306a36Sopenharmony_ci	       efuse->ht20_tx_power_index_diff,
20662306a36Sopenharmony_ci	       sizeof(efuse->ht20_tx_power_index_diff));
20762306a36Sopenharmony_ci	memcpy(priv->ofdm_tx_power_index_diff,
20862306a36Sopenharmony_ci	       efuse->ofdm_tx_power_index_diff,
20962306a36Sopenharmony_ci	       sizeof(efuse->ofdm_tx_power_index_diff));
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	memcpy(priv->ht40_max_power_offset,
21262306a36Sopenharmony_ci	       efuse->ht40_max_power_offset,
21362306a36Sopenharmony_ci	       sizeof(efuse->ht40_max_power_offset));
21462306a36Sopenharmony_ci	memcpy(priv->ht20_max_power_offset,
21562306a36Sopenharmony_ci	       efuse->ht20_max_power_offset,
21662306a36Sopenharmony_ci	       sizeof(efuse->ht20_max_power_offset));
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (priv->efuse_wifi.efuse8723.version >= 0x01)
21962306a36Sopenharmony_ci		priv->default_crystal_cap = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
22062306a36Sopenharmony_ci	else
22162306a36Sopenharmony_ci		priv->fops->set_crystal_cap = NULL;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	priv->power_base = &rtl8723a_power_base;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return 0;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	const char *fw_name;
23162306a36Sopenharmony_ci	int ret;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	switch (priv->chip_cut) {
23462306a36Sopenharmony_ci	case 0:
23562306a36Sopenharmony_ci		fw_name = "rtlwifi/rtl8723aufw_A.bin";
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	case 1:
23862306a36Sopenharmony_ci		if (priv->enable_bluetooth)
23962306a36Sopenharmony_ci			fw_name = "rtlwifi/rtl8723aufw_B.bin";
24062306a36Sopenharmony_ci		else
24162306a36Sopenharmony_ci			fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin";
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		break;
24462306a36Sopenharmony_ci	default:
24562306a36Sopenharmony_ci		return -EINVAL;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	ret = rtl8xxxu_load_firmware(priv, fw_name);
24962306a36Sopenharmony_ci	return ret;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int rtl8723au_init_phy_rf(struct rtl8xxxu_priv *priv)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	int ret;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	ret = rtl8xxxu_init_phy_rf(priv, rtl8723au_radioa_1t_init_table, RF_A);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* Reduce 80M spur */
25962306a36Sopenharmony_ci	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d);
26062306a36Sopenharmony_ci	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
26162306a36Sopenharmony_ci	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82);
26262306a36Sopenharmony_ci	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return ret;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int rtl8723a_emu_to_active(struct rtl8xxxu_priv *priv)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	u8 val8;
27062306a36Sopenharmony_ci	u32 val32;
27162306a36Sopenharmony_ci	int count, ret = 0;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* 0x20[0] = 1 enable LDOA12 MACRO block for all interface*/
27462306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
27562306a36Sopenharmony_ci	val8 |= LDOA15_ENABLE;
27662306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* 0x67[0] = 0 to disable BT_GPS_SEL pins*/
27962306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, 0x0067);
28062306a36Sopenharmony_ci	val8 &= ~BIT(4);
28162306a36Sopenharmony_ci	rtl8xxxu_write8(priv, 0x0067, val8);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	mdelay(1);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* 0x00[5] = 0 release analog Ips to digital, 1:isolation */
28662306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
28762306a36Sopenharmony_ci	val8 &= ~SYS_ISO_ANALOG_IPS;
28862306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* disable SW LPS 0x04[10]= 0 */
29162306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
29262306a36Sopenharmony_ci	val8 &= ~BIT(2);
29362306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* wait till 0x04[17] = 1 power ready*/
29662306a36Sopenharmony_ci	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
29762306a36Sopenharmony_ci		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
29862306a36Sopenharmony_ci		if (val32 & BIT(17))
29962306a36Sopenharmony_ci			break;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		udelay(10);
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!count) {
30562306a36Sopenharmony_ci		ret = -EBUSY;
30662306a36Sopenharmony_ci		goto exit;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* We should be able to optimize the following three entries into one */
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* release WLON reset 0x04[16]= 1*/
31262306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
31362306a36Sopenharmony_ci	val8 |= BIT(0);
31462306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* disable HWPDN 0x04[15]= 0*/
31762306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
31862306a36Sopenharmony_ci	val8 &= ~BIT(7);
31962306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/* disable WL suspend*/
32262306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
32362306a36Sopenharmony_ci	val8 &= ~(BIT(3) | BIT(4));
32462306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* set, then poll until 0 */
32762306a36Sopenharmony_ci	val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
32862306a36Sopenharmony_ci	val32 |= APS_FSMCO_MAC_ENABLE;
32962306a36Sopenharmony_ci	rtl8xxxu_write32(priv, REG_APS_FSMCO, val32);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
33262306a36Sopenharmony_ci		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
33362306a36Sopenharmony_ci		if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) {
33462306a36Sopenharmony_ci			ret = 0;
33562306a36Sopenharmony_ci			break;
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci		udelay(10);
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!count) {
34162306a36Sopenharmony_ci		ret = -EBUSY;
34262306a36Sopenharmony_ci		goto exit;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* 0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */
34662306a36Sopenharmony_ci	/*
34762306a36Sopenharmony_ci	 * Note: Vendor driver actually clears this bit, despite the
34862306a36Sopenharmony_ci	 * documentation claims it's being set!
34962306a36Sopenharmony_ci	 */
35062306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
35162306a36Sopenharmony_ci	val8 |= LEDCFG2_DPDT_SELECT;
35262306a36Sopenharmony_ci	val8 &= ~LEDCFG2_DPDT_SELECT;
35362306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ciexit:
35662306a36Sopenharmony_ci	return ret;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int rtl8723au_power_on(struct rtl8xxxu_priv *priv)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	u8 val8;
36262306a36Sopenharmony_ci	u16 val16;
36362306a36Sopenharmony_ci	u32 val32;
36462306a36Sopenharmony_ci	int ret;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/*
36762306a36Sopenharmony_ci	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
36862306a36Sopenharmony_ci	 */
36962306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	rtl8xxxu_disabled_to_emu(priv);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	ret = rtl8723a_emu_to_active(priv);
37462306a36Sopenharmony_ci	if (ret)
37562306a36Sopenharmony_ci		goto exit;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/*
37862306a36Sopenharmony_ci	 * 0x0004[19] = 1, reset 8051
37962306a36Sopenharmony_ci	 */
38062306a36Sopenharmony_ci	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
38162306a36Sopenharmony_ci	val8 |= BIT(3);
38262306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/*
38562306a36Sopenharmony_ci	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
38662306a36Sopenharmony_ci	 * Set CR bit10 to enable 32k calibration.
38762306a36Sopenharmony_ci	 */
38862306a36Sopenharmony_ci	val16 = rtl8xxxu_read16(priv, REG_CR);
38962306a36Sopenharmony_ci	val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
39062306a36Sopenharmony_ci		  CR_TXDMA_ENABLE | CR_RXDMA_ENABLE |
39162306a36Sopenharmony_ci		  CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE |
39262306a36Sopenharmony_ci		  CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE |
39362306a36Sopenharmony_ci		  CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE);
39462306a36Sopenharmony_ci	rtl8xxxu_write16(priv, REG_CR, val16);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* For EFuse PG */
39762306a36Sopenharmony_ci	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
39862306a36Sopenharmony_ci	val32 &= ~(BIT(28) | BIT(29) | BIT(30));
39962306a36Sopenharmony_ci	val32 |= (0x06 << 28);
40062306a36Sopenharmony_ci	rtl8xxxu_write32(priv, REG_EFUSE_CTRL, val32);
40162306a36Sopenharmony_ciexit:
40262306a36Sopenharmony_ci	return ret;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci#define XTAL1	GENMASK(23, 18)
40662306a36Sopenharmony_ci#define XTAL0	GENMASK(17, 12)
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_civoid rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking;
41162306a36Sopenharmony_ci	u32 val32;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (crystal_cap == cfo->crystal_cap)
41462306a36Sopenharmony_ci		return;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	dev_dbg(&priv->udev->dev,
41962306a36Sopenharmony_ci	        "%s: Adjusting crystal cap from 0x%x (actually 0x%lx 0x%lx) to 0x%x\n",
42062306a36Sopenharmony_ci	        __func__,
42162306a36Sopenharmony_ci	        cfo->crystal_cap,
42262306a36Sopenharmony_ci	        FIELD_GET(XTAL1, val32),
42362306a36Sopenharmony_ci	        FIELD_GET(XTAL0, val32),
42462306a36Sopenharmony_ci	        crystal_cap);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	val32 &= ~(XTAL1 | XTAL0);
42762306a36Sopenharmony_ci	val32 |= FIELD_PREP(XTAL1, crystal_cap) |
42862306a36Sopenharmony_ci		 FIELD_PREP(XTAL0, crystal_cap);
42962306a36Sopenharmony_ci	rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	cfo->crystal_cap = crystal_cap;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cis8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, struct rtl8723au_phy_stats *phy_stats)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a;
43762306a36Sopenharmony_ci	s8 rx_pwr_all = 0x00;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	switch (cck_agc_rpt & 0xc0) {
44062306a36Sopenharmony_ci	case 0xc0:
44162306a36Sopenharmony_ci		rx_pwr_all = -46 - (cck_agc_rpt & 0x3e);
44262306a36Sopenharmony_ci		break;
44362306a36Sopenharmony_ci	case 0x80:
44462306a36Sopenharmony_ci		rx_pwr_all = -26 - (cck_agc_rpt & 0x3e);
44562306a36Sopenharmony_ci		break;
44662306a36Sopenharmony_ci	case 0x40:
44762306a36Sopenharmony_ci		rx_pwr_all = -12 - (cck_agc_rpt & 0x3e);
44862306a36Sopenharmony_ci		break;
44962306a36Sopenharmony_ci	case 0x00:
45062306a36Sopenharmony_ci		rx_pwr_all = 16 - (cck_agc_rpt & 0x3e);
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return rx_pwr_all;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int rtl8723au_led_brightness_set(struct led_classdev *led_cdev,
45862306a36Sopenharmony_ci					enum led_brightness brightness)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct rtl8xxxu_priv *priv = container_of(led_cdev,
46162306a36Sopenharmony_ci						  struct rtl8xxxu_priv,
46262306a36Sopenharmony_ci						  led_cdev);
46362306a36Sopenharmony_ci	u8 ledcfg = rtl8xxxu_read8(priv, REG_LEDCFG2);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (brightness == LED_OFF) {
46662306a36Sopenharmony_ci		ledcfg &= ~LEDCFG2_HW_LED_CONTROL;
46762306a36Sopenharmony_ci		ledcfg |= LEDCFG2_SW_LED_CONTROL | LEDCFG2_SW_LED_DISABLE;
46862306a36Sopenharmony_ci	} else if (brightness == LED_ON) {
46962306a36Sopenharmony_ci		ledcfg &= ~(LEDCFG2_HW_LED_CONTROL | LEDCFG2_SW_LED_DISABLE);
47062306a36Sopenharmony_ci		ledcfg |= LEDCFG2_SW_LED_CONTROL;
47162306a36Sopenharmony_ci	} else if (brightness == RTL8XXXU_HW_LED_CONTROL) {
47262306a36Sopenharmony_ci		ledcfg &= ~LEDCFG2_SW_LED_DISABLE;
47362306a36Sopenharmony_ci		ledcfg |= LEDCFG2_HW_LED_CONTROL | LEDCFG2_HW_LED_ENABLE;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	rtl8xxxu_write8(priv, REG_LEDCFG2, ledcfg);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	return 0;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistruct rtl8xxxu_fileops rtl8723au_fops = {
48262306a36Sopenharmony_ci	.identify_chip = rtl8723au_identify_chip,
48362306a36Sopenharmony_ci	.parse_efuse = rtl8723au_parse_efuse,
48462306a36Sopenharmony_ci	.load_firmware = rtl8723au_load_firmware,
48562306a36Sopenharmony_ci	.power_on = rtl8723au_power_on,
48662306a36Sopenharmony_ci	.power_off = rtl8xxxu_power_off,
48762306a36Sopenharmony_ci	.read_efuse = rtl8xxxu_read_efuse,
48862306a36Sopenharmony_ci	.reset_8051 = rtl8xxxu_reset_8051,
48962306a36Sopenharmony_ci	.llt_init = rtl8xxxu_init_llt_table,
49062306a36Sopenharmony_ci	.init_phy_bb = rtl8xxxu_gen1_init_phy_bb,
49162306a36Sopenharmony_ci	.init_phy_rf = rtl8723au_init_phy_rf,
49262306a36Sopenharmony_ci	.phy_lc_calibrate = rtl8723a_phy_lc_calibrate,
49362306a36Sopenharmony_ci	.phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate,
49462306a36Sopenharmony_ci	.config_channel = rtl8xxxu_gen1_config_channel,
49562306a36Sopenharmony_ci	.parse_rx_desc = rtl8xxxu_parse_rxdesc16,
49662306a36Sopenharmony_ci	.parse_phystats = rtl8723au_rx_parse_phystats,
49762306a36Sopenharmony_ci	.init_aggregation = rtl8xxxu_gen1_init_aggregation,
49862306a36Sopenharmony_ci	.enable_rf = rtl8xxxu_gen1_enable_rf,
49962306a36Sopenharmony_ci	.disable_rf = rtl8xxxu_gen1_disable_rf,
50062306a36Sopenharmony_ci	.usb_quirks = rtl8xxxu_gen1_usb_quirks,
50162306a36Sopenharmony_ci	.set_tx_power = rtl8xxxu_gen1_set_tx_power,
50262306a36Sopenharmony_ci	.update_rate_mask = rtl8xxxu_update_rate_mask,
50362306a36Sopenharmony_ci	.report_connect = rtl8xxxu_gen1_report_connect,
50462306a36Sopenharmony_ci	.report_rssi = rtl8xxxu_gen1_report_rssi,
50562306a36Sopenharmony_ci	.fill_txdesc = rtl8xxxu_fill_txdesc_v1,
50662306a36Sopenharmony_ci	.set_crystal_cap = rtl8723a_set_crystal_cap,
50762306a36Sopenharmony_ci	.cck_rssi = rtl8723a_cck_rssi,
50862306a36Sopenharmony_ci	.led_classdev_brightness_set = rtl8723au_led_brightness_set,
50962306a36Sopenharmony_ci	.writeN_block_size = 1024,
51062306a36Sopenharmony_ci	.rx_agg_buf_size = 16000,
51162306a36Sopenharmony_ci	.tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
51262306a36Sopenharmony_ci	.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
51362306a36Sopenharmony_ci	.adda_1t_init = 0x0b1b25a0,
51462306a36Sopenharmony_ci	.adda_1t_path_on = 0x0bdb25a0,
51562306a36Sopenharmony_ci	.adda_2t_path_on_a = 0x04db25a4,
51662306a36Sopenharmony_ci	.adda_2t_path_on_b = 0x0b1b25a4,
51762306a36Sopenharmony_ci	.trxff_boundary = 0x27ff,
51862306a36Sopenharmony_ci	.pbp_rx = PBP_PAGE_SIZE_128,
51962306a36Sopenharmony_ci	.pbp_tx = PBP_PAGE_SIZE_128,
52062306a36Sopenharmony_ci	.mactable = rtl8xxxu_gen1_mac_init_table,
52162306a36Sopenharmony_ci	.total_page_num = TX_TOTAL_PAGE_NUM,
52262306a36Sopenharmony_ci	.page_num_hi = TX_PAGE_NUM_HI_PQ,
52362306a36Sopenharmony_ci	.page_num_lo = TX_PAGE_NUM_LO_PQ,
52462306a36Sopenharmony_ci	.page_num_norm = TX_PAGE_NUM_NORM_PQ,
52562306a36Sopenharmony_ci};
526