1 From 315c23a64e99552502dd4d18d6ddc073fad9a7c3 Mon Sep 17 00:00:00 2001
2 From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
3 Date: Thu, 11 Jul 2024 01:11:33 +0300
4 Subject: [PATCH] wifi: rtw88: usb: Support USB 3 with RTL8822CU/RTL8822BU
6 The Realtek wifi 5 devices which support USB 3 are weird: when first
7 plugged in, they pretend to be USB 2. The driver needs to send some
8 commands to the device, which make it disappear and come back as a
11 Implement the required commands in rtw88.
13 When a USB 3 device is plugged into a USB 2 port, rtw88 will try to
14 switch it to USB 3 mode only once. The device will disappear and come
15 back still in USB 2 mode, of course.
17 Some people experience heavy interference in the 2.4 GHz band in
18 USB 3 mode, so add a module parameter switch_usb_mode with the
19 default value 1 to let people disable the switching.
21 Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
22 Acked-by: Ping-Ke Shih <pkshih@realtek.com>
23 Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
24 Link: https://patch.msgid.link/77906c62-5674-426f-bde1-1b2a12a0339d@gmail.com
26 drivers/net/wireless/realtek/rtw88/debug.h | 1 +
27 drivers/net/wireless/realtek/rtw88/main.h | 2 +
28 drivers/net/wireless/realtek/rtw88/reg.h | 11 +++
29 drivers/net/wireless/realtek/rtw88/rtw8822b.c | 1 +
30 drivers/net/wireless/realtek/rtw88/rtw8822b.h | 4 +-
31 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 1 +
32 drivers/net/wireless/realtek/rtw88/rtw8822c.h | 24 +++---
33 drivers/net/wireless/realtek/rtw88/usb.c | 84 +++++++++++++++++++
34 8 files changed, 116 insertions(+), 12 deletions(-)
36 --- a/drivers/net/wireless/realtek/rtw88/debug.h
37 +++ b/drivers/net/wireless/realtek/rtw88/debug.h
38 @@ -25,6 +25,7 @@ enum rtw_debug_mask {
39 RTW_DBG_HW_SCAN = 0x00010000,
40 RTW_DBG_STATE = 0x00020000,
41 RTW_DBG_SDIO = 0x00040000,
42 + RTW_DBG_USB = 0x00080000,
44 RTW_DBG_UNEXP = 0x80000000,
45 RTW_DBG_ALL = 0xffffffff
46 --- a/drivers/net/wireless/realtek/rtw88/main.h
47 +++ b/drivers/net/wireless/realtek/rtw88/main.h
48 @@ -1785,6 +1785,8 @@ struct rtw_efuse {
57 --- a/drivers/net/wireless/realtek/rtw88/reg.h
58 +++ b/drivers/net/wireless/realtek/rtw88/reg.h
60 #define BIT_WLOCK_1C_B6 BIT(5)
61 #define REG_SYS_PW_CTRL 0x0004
62 #define BIT_PFM_WOWL BIT(3)
63 +#define BIT_APFM_OFFMAC BIT(9)
64 #define REG_SYS_CLK_CTRL 0x0008
65 #define BIT_CPU_CLK_EN BIT(14)
68 #define REG_PMC_DBG_CTRL1 0xa8
69 #define BITS_PMC_BT_IQK_STS GENMASK(22, 21)
71 +#define REG_PAD_CTRL2 0x00C4
72 +#define BIT_RSM_EN_V1 BIT(16)
73 +#define BIT_NO_PDN_CHIPOFF_V1 BIT(17)
74 +#define BIT_MASK_USB23_SW_MODE_V1 GENMASK(19, 18)
75 +#define BIT_USB3_USB2_TRANSITION BIT(20)
76 +#define BIT_USB_MODE_U2 1
77 +#define BIT_USB_MODE_U3 2
79 #define REG_EFUSE_ACCESS 0x00CF
80 #define EFUSE_ACCESS_ON 0x69
81 #define EFUSE_ACCESS_OFF 0x00
83 #define BIT_WL_SECURITY_CLK BIT(15)
84 #define BIT_DDMA_EN BIT(8)
86 +#define REG_SW_MDIO 0x10C0
88 #define REG_H2C_PKT_READADDR 0x10D0
89 #define REG_H2C_PKT_WRITEADDR 0x10D4
90 #define REG_FW_DBG6 0x10F8
91 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
92 +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
93 @@ -46,6 +46,7 @@ static int rtw8822b_read_efuse(struct rt
95 map = (struct rtw8822b_efuse *)log_map;
97 + efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(7));
98 efuse->rfe_option = map->rfe_option;
99 efuse->rf_board_option = map->rf_board_option;
100 efuse->crystal_cap = map->xtal_k;
101 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h
102 +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h
103 @@ -72,7 +72,9 @@ struct rtw8822bs_efuse {
105 struct rtw8822b_efuse {
112 /* power index for four RF paths */
113 struct rtw_txpwr_idx txpwr_idx_table[4];
114 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
115 +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
116 @@ -49,6 +49,7 @@ static int rtw8822c_read_efuse(struct rt
118 map = (struct rtw8822c_efuse *)log_map;
120 + efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(7));
121 efuse->rfe_option = map->rfe_option;
122 efuse->rf_board_option = map->rf_board_option;
123 efuse->crystal_cap = map->xtal_k & XCAP_MASK;
124 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
125 +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
126 @@ -59,16 +59,18 @@ struct rtw8822ce_efuse {
128 struct rtw8822c_efuse {
135 /* power index for four RF paths */
136 struct rtw_txpwr_idx txpwr_idx_table[4];
138 u8 channel_plan; /* 0xb8 */
143 - u8 res2[5]; /* 0xbc */
144 + u8 res3[5]; /* 0xbc */
146 u8 rf_feature_option;
148 @@ -80,21 +82,21 @@ struct rtw8822c_efuse {
149 u8 rf_antenna_option; /* 0xc9 */
154 u8 path_a_thermal; /* 0xd0 */
158 u8 rx_gain_gap_2g_ofdm;
160 - u8 rx_gain_gap_2g_cck;
162 - u8 rx_gain_gap_5gl;
163 + u8 rx_gain_gap_2g_cck;
165 - u8 rx_gain_gap_5gm;
166 + u8 rx_gain_gap_5gl;
168 - u8 rx_gain_gap_5gh;
169 + u8 rx_gain_gap_5gm;
172 + u8 rx_gain_gap_5gh;
176 struct rtw8822ce_efuse e;
177 struct rtw8822cu_efuse u;
178 --- a/drivers/net/wireless/realtek/rtw88/usb.c
179 +++ b/drivers/net/wireless/realtek/rtw88/usb.c
184 +static bool rtw_switch_usb_mode = true;
185 +module_param_named(switch_usb_mode, rtw_switch_usb_mode, bool, 0644);
186 +MODULE_PARM_DESC(switch_usb_mode,
187 + "Set to N to disable switching to USB 3 mode to avoid potential interference in the 2.4 GHz band (default: Y)");
189 #define RTW_USB_MAX_RXQ_LEN 512
191 struct rtw_usb_txcb {
192 @@ -841,6 +846,77 @@ static void rtw_usb_intf_deinit(struct r
193 usb_set_intfdata(intf, NULL);
196 +static int rtw_usb_switch_mode_new(struct rtw_dev *rtwdev)
198 + enum usb_device_speed cur_speed;
199 + u8 id = rtwdev->chip->id;
203 + if (rtw_read8(rtwdev, REG_SYS_CFG2 + 3) == 0x20)
204 + cur_speed = USB_SPEED_SUPER;
206 + cur_speed = USB_SPEED_HIGH;
208 + if (cur_speed == USB_SPEED_SUPER)
211 + pad_ctrl2 = rtw_read32(rtwdev, REG_PAD_CTRL2);
213 + can_switch = !!(pad_ctrl2 & (BIT_MASK_USB23_SW_MODE_V1 |
214 + BIT_USB3_USB2_TRANSITION));
217 + rtw_dbg(rtwdev, RTW_DBG_USB,
218 + "Switching to USB 3 mode unsupported by the chip\n");
222 + /* At this point cur_speed is USB_SPEED_HIGH. If we already tried
223 + * to switch don't try again - it's a USB 2 port.
225 + if (u32_get_bits(pad_ctrl2, BIT_MASK_USB23_SW_MODE_V1) == BIT_USB_MODE_U3)
228 + /* Enable IO wrapper timeout */
229 + if (id == RTW_CHIP_TYPE_8822B || id == RTW_CHIP_TYPE_8821C)
230 + rtw_write8_clr(rtwdev, REG_SW_MDIO + 3, BIT(0));
232 + u32p_replace_bits(&pad_ctrl2, BIT_USB_MODE_U3, BIT_MASK_USB23_SW_MODE_V1);
233 + pad_ctrl2 |= BIT_RSM_EN_V1;
235 + rtw_write32(rtwdev, REG_PAD_CTRL2, pad_ctrl2);
236 + rtw_write8(rtwdev, REG_PAD_CTRL2 + 1, 4);
238 + rtw_write16_set(rtwdev, REG_SYS_PW_CTRL, BIT_APFM_OFFMAC);
239 + usleep_range(1000, 1001);
240 + rtw_write32_set(rtwdev, REG_PAD_CTRL2, BIT_NO_PDN_CHIPOFF_V1);
245 +static int rtw_usb_switch_mode(struct rtw_dev *rtwdev)
247 + u8 id = rtwdev->chip->id;
249 + if (id != RTW_CHIP_TYPE_8822C && id != RTW_CHIP_TYPE_8822B)
252 + if (!rtwdev->efuse.usb_mode_switch) {
253 + rtw_dbg(rtwdev, RTW_DBG_USB,
254 + "Switching to USB 3 mode disabled by chip's efuse\n");
258 + if (!rtw_switch_usb_mode) {
259 + rtw_dbg(rtwdev, RTW_DBG_USB,
260 + "Switching to USB 3 mode disabled by module parameter\n");
264 + return rtw_usb_switch_mode_new(rtwdev);
267 int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
269 struct rtw_dev *rtwdev;
270 @@ -896,6 +972,14 @@ int rtw_usb_probe(struct usb_interface *
271 goto err_destroy_rxwq;
274 + ret = rtw_usb_switch_mode(rtwdev);
276 + /* Not a fail, but we do need to skip rtw_register_hw. */
277 + rtw_dbg(rtwdev, RTW_DBG_USB, "switching to USB 3 mode\n");
279 + goto err_destroy_rxwq;
282 ret = rtw_register_hw(rtwdev, rtwdev->hw);
284 rtw_err(rtwdev, "failed to register hw\n");