1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2*4882a593Smuzhiyun /* Copyright(c) 2018-2019 Realtek Corporation
3*4882a593Smuzhiyun */
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include "main.h"
6*4882a593Smuzhiyun #include "mac.h"
7*4882a593Smuzhiyun #include "reg.h"
8*4882a593Smuzhiyun #include "fw.h"
9*4882a593Smuzhiyun #include "debug.h"
10*4882a593Smuzhiyun
rtw_set_channel_mac(struct rtw_dev * rtwdev,u8 channel,u8 bw,u8 primary_ch_idx)11*4882a593Smuzhiyun void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw,
12*4882a593Smuzhiyun u8 primary_ch_idx)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun u8 txsc40 = 0, txsc20 = 0;
15*4882a593Smuzhiyun u32 value32;
16*4882a593Smuzhiyun u8 value8;
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun txsc20 = primary_ch_idx;
19*4882a593Smuzhiyun if (bw == RTW_CHANNEL_WIDTH_80) {
20*4882a593Smuzhiyun if (txsc20 == RTW_SC_20_UPPER || txsc20 == RTW_SC_20_UPMOST)
21*4882a593Smuzhiyun txsc40 = RTW_SC_40_UPPER;
22*4882a593Smuzhiyun else
23*4882a593Smuzhiyun txsc40 = RTW_SC_40_LOWER;
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun rtw_write8(rtwdev, REG_DATA_SC,
26*4882a593Smuzhiyun BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40));
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_WMAC_TRXPTCL_CTL);
29*4882a593Smuzhiyun value32 &= ~BIT_RFMOD;
30*4882a593Smuzhiyun switch (bw) {
31*4882a593Smuzhiyun case RTW_CHANNEL_WIDTH_80:
32*4882a593Smuzhiyun value32 |= BIT_RFMOD_80M;
33*4882a593Smuzhiyun break;
34*4882a593Smuzhiyun case RTW_CHANNEL_WIDTH_40:
35*4882a593Smuzhiyun value32 |= BIT_RFMOD_40M;
36*4882a593Smuzhiyun break;
37*4882a593Smuzhiyun case RTW_CHANNEL_WIDTH_20:
38*4882a593Smuzhiyun default:
39*4882a593Smuzhiyun break;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun rtw_write32(rtwdev, REG_WMAC_TRXPTCL_CTL, value32);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun if (rtw_chip_wcpu_11n(rtwdev))
44*4882a593Smuzhiyun return;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_AFE_CTRL1) & ~(BIT_MAC_CLK_SEL);
47*4882a593Smuzhiyun value32 |= (MAC_CLK_HW_DEF_80M << BIT_SHIFT_MAC_CLK_SEL);
48*4882a593Smuzhiyun rtw_write32(rtwdev, REG_AFE_CTRL1, value32);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun rtw_write8(rtwdev, REG_USTIME_TSF, MAC_CLK_SPEED);
51*4882a593Smuzhiyun rtw_write8(rtwdev, REG_USTIME_EDCA, MAC_CLK_SPEED);
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun value8 = rtw_read8(rtwdev, REG_CCK_CHECK);
54*4882a593Smuzhiyun value8 = value8 & ~BIT_CHECK_CCK_EN;
55*4882a593Smuzhiyun if (IS_CH_5G_BAND(channel))
56*4882a593Smuzhiyun value8 |= BIT_CHECK_CCK_EN;
57*4882a593Smuzhiyun rtw_write8(rtwdev, REG_CCK_CHECK, value8);
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun EXPORT_SYMBOL(rtw_set_channel_mac);
60*4882a593Smuzhiyun
rtw_mac_pre_system_cfg(struct rtw_dev * rtwdev)61*4882a593Smuzhiyun static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun u32 value32;
64*4882a593Smuzhiyun u8 value8;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun rtw_write8(rtwdev, REG_RSV_CTRL, 0);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun if (rtw_chip_wcpu_11n(rtwdev)) {
69*4882a593Smuzhiyun if (rtw_read32(rtwdev, REG_SYS_CFG1) & BIT_LDO)
70*4882a593Smuzhiyun rtw_write8(rtwdev, REG_LDO_SWR_CTRL, LDO_SEL);
71*4882a593Smuzhiyun else
72*4882a593Smuzhiyun rtw_write8(rtwdev, REG_LDO_SWR_CTRL, SPS_SEL);
73*4882a593Smuzhiyun return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun switch (rtw_hci_type(rtwdev)) {
77*4882a593Smuzhiyun case RTW_HCI_TYPE_PCIE:
78*4882a593Smuzhiyun rtw_write32_set(rtwdev, REG_HCI_OPT_CTRL, BIT_BT_DIG_CLK_EN);
79*4882a593Smuzhiyun break;
80*4882a593Smuzhiyun case RTW_HCI_TYPE_USB:
81*4882a593Smuzhiyun break;
82*4882a593Smuzhiyun default:
83*4882a593Smuzhiyun return -EINVAL;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /* config PIN Mux */
87*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_PAD_CTRL1);
88*4882a593Smuzhiyun value32 |= BIT_PAPE_WLBT_SEL | BIT_LNAON_WLBT_SEL;
89*4882a593Smuzhiyun rtw_write32(rtwdev, REG_PAD_CTRL1, value32);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_LED_CFG);
92*4882a593Smuzhiyun value32 &= ~(BIT_PAPE_SEL_EN | BIT_LNAON_SEL_EN);
93*4882a593Smuzhiyun rtw_write32(rtwdev, REG_LED_CFG, value32);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_GPIO_MUXCFG);
96*4882a593Smuzhiyun value32 |= BIT_WLRFE_4_5_EN;
97*4882a593Smuzhiyun rtw_write32(rtwdev, REG_GPIO_MUXCFG, value32);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* disable BB/RF */
100*4882a593Smuzhiyun value8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
101*4882a593Smuzhiyun value8 &= ~(BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST);
102*4882a593Smuzhiyun rtw_write8(rtwdev, REG_SYS_FUNC_EN, value8);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun value8 = rtw_read8(rtwdev, REG_RF_CTRL);
105*4882a593Smuzhiyun value8 &= ~(BIT_RF_SDM_RSTB | BIT_RF_RSTB | BIT_RF_EN);
106*4882a593Smuzhiyun rtw_write8(rtwdev, REG_RF_CTRL, value8);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_WLRF1);
109*4882a593Smuzhiyun value32 &= ~BIT_WLRF1_BBRF_EN;
110*4882a593Smuzhiyun rtw_write32(rtwdev, REG_WLRF1, value32);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun return 0;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
do_pwr_poll_cmd(struct rtw_dev * rtwdev,u32 addr,u32 mask,u32 target)115*4882a593Smuzhiyun static bool do_pwr_poll_cmd(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun u32 val;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun target &= mask;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun return read_poll_timeout_atomic(rtw_read8, val, (val & mask) == target,
122*4882a593Smuzhiyun 50, 50 * RTW_PWR_POLLING_CNT, false,
123*4882a593Smuzhiyun rtwdev, addr) == 0;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
rtw_pwr_cmd_polling(struct rtw_dev * rtwdev,const struct rtw_pwr_seq_cmd * cmd)126*4882a593Smuzhiyun static int rtw_pwr_cmd_polling(struct rtw_dev *rtwdev,
127*4882a593Smuzhiyun const struct rtw_pwr_seq_cmd *cmd)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun u8 value;
130*4882a593Smuzhiyun u32 offset;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (cmd->base == RTW_PWR_ADDR_SDIO)
133*4882a593Smuzhiyun offset = cmd->offset | SDIO_LOCAL_OFFSET;
134*4882a593Smuzhiyun else
135*4882a593Smuzhiyun offset = cmd->offset;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (do_pwr_poll_cmd(rtwdev, offset, cmd->mask, cmd->value))
138*4882a593Smuzhiyun return 0;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (rtw_hci_type(rtwdev) != RTW_HCI_TYPE_PCIE)
141*4882a593Smuzhiyun goto err;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /* if PCIE, toggle BIT_PFM_WOWL and try again */
144*4882a593Smuzhiyun value = rtw_read8(rtwdev, REG_SYS_PW_CTRL);
145*4882a593Smuzhiyun if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D)
146*4882a593Smuzhiyun rtw_write8(rtwdev, REG_SYS_PW_CTRL, value & ~BIT_PFM_WOWL);
147*4882a593Smuzhiyun rtw_write8(rtwdev, REG_SYS_PW_CTRL, value | BIT_PFM_WOWL);
148*4882a593Smuzhiyun rtw_write8(rtwdev, REG_SYS_PW_CTRL, value & ~BIT_PFM_WOWL);
149*4882a593Smuzhiyun if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D)
150*4882a593Smuzhiyun rtw_write8(rtwdev, REG_SYS_PW_CTRL, value | BIT_PFM_WOWL);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (do_pwr_poll_cmd(rtwdev, offset, cmd->mask, cmd->value))
153*4882a593Smuzhiyun return 0;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun err:
156*4882a593Smuzhiyun rtw_err(rtwdev, "failed to poll offset=0x%x mask=0x%x value=0x%x\n",
157*4882a593Smuzhiyun offset, cmd->mask, cmd->value);
158*4882a593Smuzhiyun return -EBUSY;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
rtw_sub_pwr_seq_parser(struct rtw_dev * rtwdev,u8 intf_mask,u8 cut_mask,const struct rtw_pwr_seq_cmd * cmd)161*4882a593Smuzhiyun static int rtw_sub_pwr_seq_parser(struct rtw_dev *rtwdev, u8 intf_mask,
162*4882a593Smuzhiyun u8 cut_mask,
163*4882a593Smuzhiyun const struct rtw_pwr_seq_cmd *cmd)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun const struct rtw_pwr_seq_cmd *cur_cmd;
166*4882a593Smuzhiyun u32 offset;
167*4882a593Smuzhiyun u8 value;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun for (cur_cmd = cmd; cur_cmd->cmd != RTW_PWR_CMD_END; cur_cmd++) {
170*4882a593Smuzhiyun if (!(cur_cmd->intf_mask & intf_mask) ||
171*4882a593Smuzhiyun !(cur_cmd->cut_mask & cut_mask))
172*4882a593Smuzhiyun continue;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun switch (cur_cmd->cmd) {
175*4882a593Smuzhiyun case RTW_PWR_CMD_WRITE:
176*4882a593Smuzhiyun offset = cur_cmd->offset;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (cur_cmd->base == RTW_PWR_ADDR_SDIO)
179*4882a593Smuzhiyun offset |= SDIO_LOCAL_OFFSET;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun value = rtw_read8(rtwdev, offset);
182*4882a593Smuzhiyun value &= ~cur_cmd->mask;
183*4882a593Smuzhiyun value |= (cur_cmd->value & cur_cmd->mask);
184*4882a593Smuzhiyun rtw_write8(rtwdev, offset, value);
185*4882a593Smuzhiyun break;
186*4882a593Smuzhiyun case RTW_PWR_CMD_POLLING:
187*4882a593Smuzhiyun if (rtw_pwr_cmd_polling(rtwdev, cur_cmd))
188*4882a593Smuzhiyun return -EBUSY;
189*4882a593Smuzhiyun break;
190*4882a593Smuzhiyun case RTW_PWR_CMD_DELAY:
191*4882a593Smuzhiyun if (cur_cmd->value == RTW_PWR_DELAY_US)
192*4882a593Smuzhiyun udelay(cur_cmd->offset);
193*4882a593Smuzhiyun else
194*4882a593Smuzhiyun mdelay(cur_cmd->offset);
195*4882a593Smuzhiyun break;
196*4882a593Smuzhiyun case RTW_PWR_CMD_READ:
197*4882a593Smuzhiyun break;
198*4882a593Smuzhiyun default:
199*4882a593Smuzhiyun return -EINVAL;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun return 0;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
rtw_pwr_seq_parser(struct rtw_dev * rtwdev,const struct rtw_pwr_seq_cmd ** cmd_seq)206*4882a593Smuzhiyun static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
207*4882a593Smuzhiyun const struct rtw_pwr_seq_cmd **cmd_seq)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun u8 cut_mask;
210*4882a593Smuzhiyun u8 intf_mask;
211*4882a593Smuzhiyun u8 cut;
212*4882a593Smuzhiyun u32 idx = 0;
213*4882a593Smuzhiyun const struct rtw_pwr_seq_cmd *cmd;
214*4882a593Smuzhiyun int ret;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun cut = rtwdev->hal.cut_version;
217*4882a593Smuzhiyun cut_mask = cut_version_to_mask(cut);
218*4882a593Smuzhiyun switch (rtw_hci_type(rtwdev)) {
219*4882a593Smuzhiyun case RTW_HCI_TYPE_PCIE:
220*4882a593Smuzhiyun intf_mask = BIT(2);
221*4882a593Smuzhiyun break;
222*4882a593Smuzhiyun case RTW_HCI_TYPE_USB:
223*4882a593Smuzhiyun intf_mask = BIT(1);
224*4882a593Smuzhiyun break;
225*4882a593Smuzhiyun default:
226*4882a593Smuzhiyun return -EINVAL;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun do {
230*4882a593Smuzhiyun cmd = cmd_seq[idx];
231*4882a593Smuzhiyun if (!cmd)
232*4882a593Smuzhiyun break;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun ret = rtw_sub_pwr_seq_parser(rtwdev, intf_mask, cut_mask, cmd);
235*4882a593Smuzhiyun if (ret)
236*4882a593Smuzhiyun return -EBUSY;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun idx++;
239*4882a593Smuzhiyun } while (1);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun return 0;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
rtw_mac_power_switch(struct rtw_dev * rtwdev,bool pwr_on)244*4882a593Smuzhiyun static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
247*4882a593Smuzhiyun const struct rtw_pwr_seq_cmd **pwr_seq;
248*4882a593Smuzhiyun u8 rpwm;
249*4882a593Smuzhiyun bool cur_pwr;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun if (rtw_chip_wcpu_11ac(rtwdev)) {
252*4882a593Smuzhiyun rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /* Check FW still exist or not */
255*4882a593Smuzhiyun if (rtw_read16(rtwdev, REG_MCUFW_CTRL) == 0xC078) {
256*4882a593Smuzhiyun rpwm = (rpwm ^ BIT_RPWM_TOGGLE) & BIT_RPWM_TOGGLE;
257*4882a593Smuzhiyun rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, rpwm);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun if (rtw_read8(rtwdev, REG_CR) == 0xea)
262*4882a593Smuzhiyun cur_pwr = false;
263*4882a593Smuzhiyun else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB &&
264*4882a593Smuzhiyun (rtw_read8(rtwdev, REG_SYS_STATUS1 + 1) & BIT(0)))
265*4882a593Smuzhiyun cur_pwr = false;
266*4882a593Smuzhiyun else
267*4882a593Smuzhiyun cur_pwr = true;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun if (pwr_on == cur_pwr)
270*4882a593Smuzhiyun return -EALREADY;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq;
273*4882a593Smuzhiyun if (rtw_pwr_seq_parser(rtwdev, pwr_seq))
274*4882a593Smuzhiyun return -EINVAL;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun return 0;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
__rtw_mac_init_system_cfg(struct rtw_dev * rtwdev)279*4882a593Smuzhiyun static int __rtw_mac_init_system_cfg(struct rtw_dev *rtwdev)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun u8 sys_func_en = rtwdev->chip->sys_func_en;
282*4882a593Smuzhiyun u8 value8;
283*4882a593Smuzhiyun u32 value, tmp;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun value = rtw_read32(rtwdev, REG_CPU_DMEM_CON);
286*4882a593Smuzhiyun value |= BIT_WL_PLATFORM_RST | BIT_DDMA_EN;
287*4882a593Smuzhiyun rtw_write32(rtwdev, REG_CPU_DMEM_CON, value);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en);
290*4882a593Smuzhiyun value8 = (rtw_read8(rtwdev, REG_CR_EXT + 3) & 0xF0) | 0x0C;
291*4882a593Smuzhiyun rtw_write8(rtwdev, REG_CR_EXT + 3, value8);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /* disable boot-from-flash for driver's DL FW */
294*4882a593Smuzhiyun tmp = rtw_read32(rtwdev, REG_MCUFW_CTRL);
295*4882a593Smuzhiyun if (tmp & BIT_BOOT_FSPI_EN) {
296*4882a593Smuzhiyun rtw_write32(rtwdev, REG_MCUFW_CTRL, tmp & (~BIT_BOOT_FSPI_EN));
297*4882a593Smuzhiyun value = rtw_read32(rtwdev, REG_GPIO_MUXCFG) & (~BIT_FSPI_EN);
298*4882a593Smuzhiyun rtw_write32(rtwdev, REG_GPIO_MUXCFG, value);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun return 0;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
__rtw_mac_init_system_cfg_legacy(struct rtw_dev * rtwdev)304*4882a593Smuzhiyun static int __rtw_mac_init_system_cfg_legacy(struct rtw_dev *rtwdev)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun rtw_write8(rtwdev, REG_CR, 0xff);
307*4882a593Smuzhiyun mdelay(2);
308*4882a593Smuzhiyun rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0x7f);
309*4882a593Smuzhiyun mdelay(2);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_SYS_CLKR, BIT_WAKEPAD_EN);
312*4882a593Smuzhiyun rtw_write16_clr(rtwdev, REG_GPIO_MUXCFG, BIT_EN_SIC);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun rtw_write16(rtwdev, REG_CR, 0x2ff);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun return 0;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
rtw_mac_init_system_cfg(struct rtw_dev * rtwdev)319*4882a593Smuzhiyun static int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun if (rtw_chip_wcpu_11n(rtwdev))
322*4882a593Smuzhiyun return __rtw_mac_init_system_cfg_legacy(rtwdev);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun return __rtw_mac_init_system_cfg(rtwdev);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
rtw_mac_power_on(struct rtw_dev * rtwdev)327*4882a593Smuzhiyun int rtw_mac_power_on(struct rtw_dev *rtwdev)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun int ret = 0;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun ret = rtw_mac_pre_system_cfg(rtwdev);
332*4882a593Smuzhiyun if (ret)
333*4882a593Smuzhiyun goto err;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun ret = rtw_mac_power_switch(rtwdev, true);
336*4882a593Smuzhiyun if (ret == -EALREADY) {
337*4882a593Smuzhiyun rtw_mac_power_switch(rtwdev, false);
338*4882a593Smuzhiyun ret = rtw_mac_power_switch(rtwdev, true);
339*4882a593Smuzhiyun if (ret)
340*4882a593Smuzhiyun goto err;
341*4882a593Smuzhiyun } else if (ret) {
342*4882a593Smuzhiyun goto err;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun ret = rtw_mac_init_system_cfg(rtwdev);
346*4882a593Smuzhiyun if (ret)
347*4882a593Smuzhiyun goto err;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun return 0;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun err:
352*4882a593Smuzhiyun rtw_err(rtwdev, "mac power on failed");
353*4882a593Smuzhiyun return ret;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
rtw_mac_power_off(struct rtw_dev * rtwdev)356*4882a593Smuzhiyun void rtw_mac_power_off(struct rtw_dev *rtwdev)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun rtw_mac_power_switch(rtwdev, false);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
check_firmware_size(const u8 * data,u32 size)361*4882a593Smuzhiyun static bool check_firmware_size(const u8 *data, u32 size)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data;
364*4882a593Smuzhiyun u32 dmem_size;
365*4882a593Smuzhiyun u32 imem_size;
366*4882a593Smuzhiyun u32 emem_size;
367*4882a593Smuzhiyun u32 real_size;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun dmem_size = le32_to_cpu(fw_hdr->dmem_size);
370*4882a593Smuzhiyun imem_size = le32_to_cpu(fw_hdr->imem_size);
371*4882a593Smuzhiyun emem_size = (fw_hdr->mem_usage & BIT(4)) ?
372*4882a593Smuzhiyun le32_to_cpu(fw_hdr->emem_size) : 0;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun dmem_size += FW_HDR_CHKSUM_SIZE;
375*4882a593Smuzhiyun imem_size += FW_HDR_CHKSUM_SIZE;
376*4882a593Smuzhiyun emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0;
377*4882a593Smuzhiyun real_size = FW_HDR_SIZE + dmem_size + imem_size + emem_size;
378*4882a593Smuzhiyun if (real_size != size)
379*4882a593Smuzhiyun return false;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun return true;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
wlan_cpu_enable(struct rtw_dev * rtwdev,bool enable)384*4882a593Smuzhiyun static void wlan_cpu_enable(struct rtw_dev *rtwdev, bool enable)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun if (enable) {
387*4882a593Smuzhiyun /* cpu io interface enable */
388*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF);
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /* cpu enable */
391*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN);
392*4882a593Smuzhiyun } else {
393*4882a593Smuzhiyun /* cpu io interface disable */
394*4882a593Smuzhiyun rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun /* cpu disable */
397*4882a593Smuzhiyun rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun #define DLFW_RESTORE_REG_NUM 6
402*4882a593Smuzhiyun
download_firmware_reg_backup(struct rtw_dev * rtwdev,struct rtw_backup_info * bckp)403*4882a593Smuzhiyun static void download_firmware_reg_backup(struct rtw_dev *rtwdev,
404*4882a593Smuzhiyun struct rtw_backup_info *bckp)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun u8 tmp;
407*4882a593Smuzhiyun u8 bckp_idx = 0;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun /* set HIQ to hi priority */
410*4882a593Smuzhiyun bckp[bckp_idx].len = 1;
411*4882a593Smuzhiyun bckp[bckp_idx].reg = REG_TXDMA_PQ_MAP + 1;
412*4882a593Smuzhiyun bckp[bckp_idx].val = rtw_read8(rtwdev, REG_TXDMA_PQ_MAP + 1);
413*4882a593Smuzhiyun bckp_idx++;
414*4882a593Smuzhiyun tmp = RTW_DMA_MAPPING_HIGH << 6;
415*4882a593Smuzhiyun rtw_write8(rtwdev, REG_TXDMA_PQ_MAP + 1, tmp);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* DLFW only use HIQ, map HIQ to hi priority */
418*4882a593Smuzhiyun bckp[bckp_idx].len = 1;
419*4882a593Smuzhiyun bckp[bckp_idx].reg = REG_CR;
420*4882a593Smuzhiyun bckp[bckp_idx].val = rtw_read8(rtwdev, REG_CR);
421*4882a593Smuzhiyun bckp_idx++;
422*4882a593Smuzhiyun bckp[bckp_idx].len = 4;
423*4882a593Smuzhiyun bckp[bckp_idx].reg = REG_H2CQ_CSR;
424*4882a593Smuzhiyun bckp[bckp_idx].val = BIT_H2CQ_FULL;
425*4882a593Smuzhiyun bckp_idx++;
426*4882a593Smuzhiyun tmp = BIT_HCI_TXDMA_EN | BIT_TXDMA_EN;
427*4882a593Smuzhiyun rtw_write8(rtwdev, REG_CR, tmp);
428*4882a593Smuzhiyun rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun /* Config hi priority queue and public priority queue page number */
431*4882a593Smuzhiyun bckp[bckp_idx].len = 2;
432*4882a593Smuzhiyun bckp[bckp_idx].reg = REG_FIFOPAGE_INFO_1;
433*4882a593Smuzhiyun bckp[bckp_idx].val = rtw_read16(rtwdev, REG_FIFOPAGE_INFO_1);
434*4882a593Smuzhiyun bckp_idx++;
435*4882a593Smuzhiyun bckp[bckp_idx].len = 4;
436*4882a593Smuzhiyun bckp[bckp_idx].reg = REG_RQPN_CTRL_2;
437*4882a593Smuzhiyun bckp[bckp_idx].val = rtw_read32(rtwdev, REG_RQPN_CTRL_2) | BIT_LD_RQPN;
438*4882a593Smuzhiyun bckp_idx++;
439*4882a593Smuzhiyun rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, 0x200);
440*4882a593Smuzhiyun rtw_write32(rtwdev, REG_RQPN_CTRL_2, bckp[bckp_idx - 1].val);
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /* Disable beacon related functions */
443*4882a593Smuzhiyun tmp = rtw_read8(rtwdev, REG_BCN_CTRL);
444*4882a593Smuzhiyun bckp[bckp_idx].len = 1;
445*4882a593Smuzhiyun bckp[bckp_idx].reg = REG_BCN_CTRL;
446*4882a593Smuzhiyun bckp[bckp_idx].val = tmp;
447*4882a593Smuzhiyun bckp_idx++;
448*4882a593Smuzhiyun tmp = (u8)((tmp & (~BIT_EN_BCN_FUNCTION)) | BIT_DIS_TSF_UDT);
449*4882a593Smuzhiyun rtw_write8(rtwdev, REG_BCN_CTRL, tmp);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun WARN(bckp_idx != DLFW_RESTORE_REG_NUM, "wrong backup number\n");
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
download_firmware_reset_platform(struct rtw_dev * rtwdev)454*4882a593Smuzhiyun static void download_firmware_reset_platform(struct rtw_dev *rtwdev)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun rtw_write8_clr(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16);
457*4882a593Smuzhiyun rtw_write8_clr(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8);
458*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16);
459*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8);
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
download_firmware_reg_restore(struct rtw_dev * rtwdev,struct rtw_backup_info * bckp,u8 bckp_num)462*4882a593Smuzhiyun static void download_firmware_reg_restore(struct rtw_dev *rtwdev,
463*4882a593Smuzhiyun struct rtw_backup_info *bckp,
464*4882a593Smuzhiyun u8 bckp_num)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun rtw_restore_reg(rtwdev, bckp, bckp_num);
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun #define TX_DESC_SIZE 48
470*4882a593Smuzhiyun
send_firmware_pkt_rsvd_page(struct rtw_dev * rtwdev,u16 pg_addr,const u8 * data,u32 size)471*4882a593Smuzhiyun static int send_firmware_pkt_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
472*4882a593Smuzhiyun const u8 *data, u32 size)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun u8 *buf;
475*4882a593Smuzhiyun int ret;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun buf = kmemdup(data, size, GFP_KERNEL);
478*4882a593Smuzhiyun if (!buf)
479*4882a593Smuzhiyun return -ENOMEM;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun ret = rtw_fw_write_data_rsvd_page(rtwdev, pg_addr, buf, size);
482*4882a593Smuzhiyun kfree(buf);
483*4882a593Smuzhiyun return ret;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun static int
send_firmware_pkt(struct rtw_dev * rtwdev,u16 pg_addr,const u8 * data,u32 size)487*4882a593Smuzhiyun send_firmware_pkt(struct rtw_dev *rtwdev, u16 pg_addr, const u8 *data, u32 size)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun int ret;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB &&
492*4882a593Smuzhiyun !((size + TX_DESC_SIZE) & (512 - 1)))
493*4882a593Smuzhiyun size += 1;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun ret = send_firmware_pkt_rsvd_page(rtwdev, pg_addr, data, size);
496*4882a593Smuzhiyun if (ret)
497*4882a593Smuzhiyun rtw_err(rtwdev, "failed to download rsvd page\n");
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return ret;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun static int
iddma_enable(struct rtw_dev * rtwdev,u32 src,u32 dst,u32 ctrl)503*4882a593Smuzhiyun iddma_enable(struct rtw_dev *rtwdev, u32 src, u32 dst, u32 ctrl)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun rtw_write32(rtwdev, REG_DDMA_CH0SA, src);
506*4882a593Smuzhiyun rtw_write32(rtwdev, REG_DDMA_CH0DA, dst);
507*4882a593Smuzhiyun rtw_write32(rtwdev, REG_DDMA_CH0CTRL, ctrl);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0))
510*4882a593Smuzhiyun return -EBUSY;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun return 0;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
iddma_download_firmware(struct rtw_dev * rtwdev,u32 src,u32 dst,u32 len,u8 first)515*4882a593Smuzhiyun static int iddma_download_firmware(struct rtw_dev *rtwdev, u32 src, u32 dst,
516*4882a593Smuzhiyun u32 len, u8 first)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun u32 ch0_ctrl = BIT_DDMACH0_CHKSUM_EN | BIT_DDMACH0_OWN;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0))
521*4882a593Smuzhiyun return -EBUSY;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun ch0_ctrl |= len & BIT_MASK_DDMACH0_DLEN;
524*4882a593Smuzhiyun if (!first)
525*4882a593Smuzhiyun ch0_ctrl |= BIT_DDMACH0_CHKSUM_CONT;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (iddma_enable(rtwdev, src, dst, ch0_ctrl))
528*4882a593Smuzhiyun return -EBUSY;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun return 0;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun static bool
check_fw_checksum(struct rtw_dev * rtwdev,u32 addr)534*4882a593Smuzhiyun check_fw_checksum(struct rtw_dev *rtwdev, u32 addr)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun u8 fw_ctrl;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun fw_ctrl = rtw_read8(rtwdev, REG_MCUFW_CTRL);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun if (rtw_read32(rtwdev, REG_DDMA_CH0CTRL) & BIT_DDMACH0_CHKSUM_STS) {
541*4882a593Smuzhiyun if (addr < OCPBASE_DMEM_88XX) {
542*4882a593Smuzhiyun fw_ctrl |= BIT_IMEM_DW_OK;
543*4882a593Smuzhiyun fw_ctrl &= ~BIT_IMEM_CHKSUM_OK;
544*4882a593Smuzhiyun rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
545*4882a593Smuzhiyun } else {
546*4882a593Smuzhiyun fw_ctrl |= BIT_DMEM_DW_OK;
547*4882a593Smuzhiyun fw_ctrl &= ~BIT_DMEM_CHKSUM_OK;
548*4882a593Smuzhiyun rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun rtw_err(rtwdev, "invalid fw checksum\n");
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun return false;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun if (addr < OCPBASE_DMEM_88XX) {
557*4882a593Smuzhiyun fw_ctrl |= (BIT_IMEM_DW_OK | BIT_IMEM_CHKSUM_OK);
558*4882a593Smuzhiyun rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
559*4882a593Smuzhiyun } else {
560*4882a593Smuzhiyun fw_ctrl |= (BIT_DMEM_DW_OK | BIT_DMEM_CHKSUM_OK);
561*4882a593Smuzhiyun rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun return true;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun static int
download_firmware_to_mem(struct rtw_dev * rtwdev,const u8 * data,u32 src,u32 dst,u32 size)568*4882a593Smuzhiyun download_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data,
569*4882a593Smuzhiyun u32 src, u32 dst, u32 size)
570*4882a593Smuzhiyun {
571*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
572*4882a593Smuzhiyun u32 desc_size = chip->tx_pkt_desc_sz;
573*4882a593Smuzhiyun u8 first_part;
574*4882a593Smuzhiyun u32 mem_offset;
575*4882a593Smuzhiyun u32 residue_size;
576*4882a593Smuzhiyun u32 pkt_size;
577*4882a593Smuzhiyun u32 max_size = 0x1000;
578*4882a593Smuzhiyun u32 val;
579*4882a593Smuzhiyun int ret;
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun mem_offset = 0;
582*4882a593Smuzhiyun first_part = 1;
583*4882a593Smuzhiyun residue_size = size;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun val = rtw_read32(rtwdev, REG_DDMA_CH0CTRL);
586*4882a593Smuzhiyun val |= BIT_DDMACH0_RESET_CHKSUM_STS;
587*4882a593Smuzhiyun rtw_write32(rtwdev, REG_DDMA_CH0CTRL, val);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun while (residue_size) {
590*4882a593Smuzhiyun if (residue_size >= max_size)
591*4882a593Smuzhiyun pkt_size = max_size;
592*4882a593Smuzhiyun else
593*4882a593Smuzhiyun pkt_size = residue_size;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun ret = send_firmware_pkt(rtwdev, (u16)(src >> 7),
596*4882a593Smuzhiyun data + mem_offset, pkt_size);
597*4882a593Smuzhiyun if (ret)
598*4882a593Smuzhiyun return ret;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun ret = iddma_download_firmware(rtwdev, OCPBASE_TXBUF_88XX +
601*4882a593Smuzhiyun src + desc_size,
602*4882a593Smuzhiyun dst + mem_offset, pkt_size,
603*4882a593Smuzhiyun first_part);
604*4882a593Smuzhiyun if (ret)
605*4882a593Smuzhiyun return ret;
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun first_part = 0;
608*4882a593Smuzhiyun mem_offset += pkt_size;
609*4882a593Smuzhiyun residue_size -= pkt_size;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun if (!check_fw_checksum(rtwdev, dst))
613*4882a593Smuzhiyun return -EINVAL;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun return 0;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun static int
start_download_firmware(struct rtw_dev * rtwdev,const u8 * data,u32 size)619*4882a593Smuzhiyun start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data;
622*4882a593Smuzhiyun const u8 *cur_fw;
623*4882a593Smuzhiyun u16 val;
624*4882a593Smuzhiyun u32 imem_size;
625*4882a593Smuzhiyun u32 dmem_size;
626*4882a593Smuzhiyun u32 emem_size;
627*4882a593Smuzhiyun u32 addr;
628*4882a593Smuzhiyun int ret;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun dmem_size = le32_to_cpu(fw_hdr->dmem_size);
631*4882a593Smuzhiyun imem_size = le32_to_cpu(fw_hdr->imem_size);
632*4882a593Smuzhiyun emem_size = (fw_hdr->mem_usage & BIT(4)) ?
633*4882a593Smuzhiyun le32_to_cpu(fw_hdr->emem_size) : 0;
634*4882a593Smuzhiyun dmem_size += FW_HDR_CHKSUM_SIZE;
635*4882a593Smuzhiyun imem_size += FW_HDR_CHKSUM_SIZE;
636*4882a593Smuzhiyun emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun val = (u16)(rtw_read16(rtwdev, REG_MCUFW_CTRL) & 0x3800);
639*4882a593Smuzhiyun val |= BIT_MCUFWDL_EN;
640*4882a593Smuzhiyun rtw_write16(rtwdev, REG_MCUFW_CTRL, val);
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun cur_fw = data + FW_HDR_SIZE;
643*4882a593Smuzhiyun addr = le32_to_cpu(fw_hdr->dmem_addr);
644*4882a593Smuzhiyun addr &= ~BIT(31);
645*4882a593Smuzhiyun ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, dmem_size);
646*4882a593Smuzhiyun if (ret)
647*4882a593Smuzhiyun return ret;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun cur_fw = data + FW_HDR_SIZE + dmem_size;
650*4882a593Smuzhiyun addr = le32_to_cpu(fw_hdr->imem_addr);
651*4882a593Smuzhiyun addr &= ~BIT(31);
652*4882a593Smuzhiyun ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, imem_size);
653*4882a593Smuzhiyun if (ret)
654*4882a593Smuzhiyun return ret;
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun if (emem_size) {
657*4882a593Smuzhiyun cur_fw = data + FW_HDR_SIZE + dmem_size + imem_size;
658*4882a593Smuzhiyun addr = le32_to_cpu(fw_hdr->emem_addr);
659*4882a593Smuzhiyun addr &= ~BIT(31);
660*4882a593Smuzhiyun ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr,
661*4882a593Smuzhiyun emem_size);
662*4882a593Smuzhiyun if (ret)
663*4882a593Smuzhiyun return ret;
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun return 0;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
download_firmware_validate(struct rtw_dev * rtwdev)669*4882a593Smuzhiyun static int download_firmware_validate(struct rtw_dev *rtwdev)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun u32 fw_key;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, FW_READY_MASK, FW_READY)) {
674*4882a593Smuzhiyun fw_key = rtw_read32(rtwdev, REG_FW_DBG7) & FW_KEY_MASK;
675*4882a593Smuzhiyun if (fw_key == ILLEGAL_KEY_GROUP)
676*4882a593Smuzhiyun rtw_err(rtwdev, "invalid fw key\n");
677*4882a593Smuzhiyun return -EINVAL;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun return 0;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
download_firmware_end_flow(struct rtw_dev * rtwdev)683*4882a593Smuzhiyun static void download_firmware_end_flow(struct rtw_dev *rtwdev)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun u16 fw_ctrl;
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun rtw_write32(rtwdev, REG_TXDMA_STATUS, BTI_PAGE_OVF);
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun /* Check IMEM & DMEM checksum is OK or not */
690*4882a593Smuzhiyun fw_ctrl = rtw_read16(rtwdev, REG_MCUFW_CTRL);
691*4882a593Smuzhiyun if ((fw_ctrl & BIT_CHECK_SUM_OK) != BIT_CHECK_SUM_OK)
692*4882a593Smuzhiyun return;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun fw_ctrl = (fw_ctrl | BIT_FW_DW_RDY) & ~BIT_MCUFWDL_EN;
695*4882a593Smuzhiyun rtw_write16(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
__rtw_download_firmware(struct rtw_dev * rtwdev,struct rtw_fw_state * fw)698*4882a593Smuzhiyun static int __rtw_download_firmware(struct rtw_dev *rtwdev,
699*4882a593Smuzhiyun struct rtw_fw_state *fw)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun struct rtw_backup_info bckp[DLFW_RESTORE_REG_NUM];
702*4882a593Smuzhiyun const u8 *data = fw->firmware->data;
703*4882a593Smuzhiyun u32 size = fw->firmware->size;
704*4882a593Smuzhiyun u32 ltecoex_bckp;
705*4882a593Smuzhiyun int ret;
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun if (!check_firmware_size(data, size))
708*4882a593Smuzhiyun return -EINVAL;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun if (!ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp))
711*4882a593Smuzhiyun return -EBUSY;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun wlan_cpu_enable(rtwdev, false);
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun download_firmware_reg_backup(rtwdev, bckp);
716*4882a593Smuzhiyun download_firmware_reset_platform(rtwdev);
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun ret = start_download_firmware(rtwdev, data, size);
719*4882a593Smuzhiyun if (ret)
720*4882a593Smuzhiyun goto dlfw_fail;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun download_firmware_reg_restore(rtwdev, bckp, DLFW_RESTORE_REG_NUM);
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun download_firmware_end_flow(rtwdev);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun wlan_cpu_enable(rtwdev, true);
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp))
729*4882a593Smuzhiyun return -EBUSY;
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun ret = download_firmware_validate(rtwdev);
732*4882a593Smuzhiyun if (ret)
733*4882a593Smuzhiyun goto dlfw_fail;
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun /* reset desc and index */
736*4882a593Smuzhiyun rtw_hci_setup(rtwdev);
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun rtwdev->h2c.last_box_num = 0;
739*4882a593Smuzhiyun rtwdev->h2c.seq = 0;
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags);
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun return 0;
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun dlfw_fail:
746*4882a593Smuzhiyun /* Disable FWDL_EN */
747*4882a593Smuzhiyun rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN);
748*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN);
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun return ret;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun
en_download_firmware_legacy(struct rtw_dev * rtwdev,bool en)753*4882a593Smuzhiyun static void en_download_firmware_legacy(struct rtw_dev *rtwdev, bool en)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun int try;
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun if (en) {
758*4882a593Smuzhiyun wlan_cpu_enable(rtwdev, false);
759*4882a593Smuzhiyun wlan_cpu_enable(rtwdev, true);
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN);
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun for (try = 0; try < 10; try++) {
764*4882a593Smuzhiyun if (rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_MCUFWDL_EN)
765*4882a593Smuzhiyun goto fwdl_ready;
766*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN);
767*4882a593Smuzhiyun msleep(20);
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun rtw_err(rtwdev, "failed to check fw download ready\n");
770*4882a593Smuzhiyun fwdl_ready:
771*4882a593Smuzhiyun rtw_write32_clr(rtwdev, REG_MCUFW_CTRL, BIT_ROM_DLEN);
772*4882a593Smuzhiyun } else {
773*4882a593Smuzhiyun rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN);
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun static void
write_firmware_page(struct rtw_dev * rtwdev,u32 page,const u8 * data,u32 size)778*4882a593Smuzhiyun write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun u32 val32;
781*4882a593Smuzhiyun u32 block_nr;
782*4882a593Smuzhiyun u32 remain_size;
783*4882a593Smuzhiyun u32 write_addr = FW_START_ADDR_LEGACY;
784*4882a593Smuzhiyun const __le32 *ptr = (const __le32 *)data;
785*4882a593Smuzhiyun u32 block;
786*4882a593Smuzhiyun __le32 remain_data = 0;
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun block_nr = size >> DLFW_BLK_SIZE_SHIFT_LEGACY;
789*4882a593Smuzhiyun remain_size = size & (DLFW_BLK_SIZE_LEGACY - 1);
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL);
792*4882a593Smuzhiyun val32 &= ~BIT_ROM_PGE;
793*4882a593Smuzhiyun val32 |= (page << BIT_SHIFT_ROM_PGE) & BIT_ROM_PGE;
794*4882a593Smuzhiyun rtw_write32(rtwdev, REG_MCUFW_CTRL, val32);
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun for (block = 0; block < block_nr; block++) {
797*4882a593Smuzhiyun rtw_write32(rtwdev, write_addr, le32_to_cpu(*ptr));
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun write_addr += DLFW_BLK_SIZE_LEGACY;
800*4882a593Smuzhiyun ptr++;
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun if (remain_size) {
804*4882a593Smuzhiyun memcpy(&remain_data, ptr, remain_size);
805*4882a593Smuzhiyun rtw_write32(rtwdev, write_addr, le32_to_cpu(remain_data));
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun static int
download_firmware_legacy(struct rtw_dev * rtwdev,const u8 * data,u32 size)810*4882a593Smuzhiyun download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun u32 page;
813*4882a593Smuzhiyun u32 total_page;
814*4882a593Smuzhiyun u32 last_page_size;
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun data += sizeof(struct rtw_fw_hdr_legacy);
817*4882a593Smuzhiyun size -= sizeof(struct rtw_fw_hdr_legacy);
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun total_page = size >> DLFW_PAGE_SIZE_SHIFT_LEGACY;
820*4882a593Smuzhiyun last_page_size = size & (DLFW_PAGE_SIZE_LEGACY - 1);
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT);
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun for (page = 0; page < total_page; page++) {
825*4882a593Smuzhiyun write_firmware_page(rtwdev, page, data, DLFW_PAGE_SIZE_LEGACY);
826*4882a593Smuzhiyun data += DLFW_PAGE_SIZE_LEGACY;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun if (last_page_size)
829*4882a593Smuzhiyun write_firmware_page(rtwdev, page, data, last_page_size);
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT, 1)) {
832*4882a593Smuzhiyun rtw_err(rtwdev, "failed to check download firmware report\n");
833*4882a593Smuzhiyun return -EINVAL;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun return 0;
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun
download_firmware_validate_legacy(struct rtw_dev * rtwdev)839*4882a593Smuzhiyun static int download_firmware_validate_legacy(struct rtw_dev *rtwdev)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun u32 val32;
842*4882a593Smuzhiyun int try;
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL);
845*4882a593Smuzhiyun val32 |= BIT_MCUFWDL_RDY;
846*4882a593Smuzhiyun val32 &= ~BIT_WINTINI_RDY;
847*4882a593Smuzhiyun rtw_write32(rtwdev, REG_MCUFW_CTRL, val32);
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun wlan_cpu_enable(rtwdev, false);
850*4882a593Smuzhiyun wlan_cpu_enable(rtwdev, true);
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun for (try = 0; try < 10; try++) {
853*4882a593Smuzhiyun val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL);
854*4882a593Smuzhiyun if ((val32 & FW_READY_LEGACY) == FW_READY_LEGACY)
855*4882a593Smuzhiyun return 0;
856*4882a593Smuzhiyun msleep(20);
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun rtw_err(rtwdev, "failed to validate firmware\n");
860*4882a593Smuzhiyun return -EINVAL;
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun
__rtw_download_firmware_legacy(struct rtw_dev * rtwdev,struct rtw_fw_state * fw)863*4882a593Smuzhiyun static int __rtw_download_firmware_legacy(struct rtw_dev *rtwdev,
864*4882a593Smuzhiyun struct rtw_fw_state *fw)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun int ret = 0;
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun en_download_firmware_legacy(rtwdev, true);
869*4882a593Smuzhiyun ret = download_firmware_legacy(rtwdev, fw->firmware->data, fw->firmware->size);
870*4882a593Smuzhiyun en_download_firmware_legacy(rtwdev, false);
871*4882a593Smuzhiyun if (ret)
872*4882a593Smuzhiyun goto out;
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun ret = download_firmware_validate_legacy(rtwdev);
875*4882a593Smuzhiyun if (ret)
876*4882a593Smuzhiyun goto out;
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun /* reset desc and index */
879*4882a593Smuzhiyun rtw_hci_setup(rtwdev);
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun rtwdev->h2c.last_box_num = 0;
882*4882a593Smuzhiyun rtwdev->h2c.seq = 0;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags);
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun out:
887*4882a593Smuzhiyun return ret;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun
rtw_download_firmware(struct rtw_dev * rtwdev,struct rtw_fw_state * fw)890*4882a593Smuzhiyun int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw)
891*4882a593Smuzhiyun {
892*4882a593Smuzhiyun if (rtw_chip_wcpu_11n(rtwdev))
893*4882a593Smuzhiyun return __rtw_download_firmware_legacy(rtwdev, fw);
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun return __rtw_download_firmware(rtwdev, fw);
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun
get_priority_queues(struct rtw_dev * rtwdev,u32 queues)898*4882a593Smuzhiyun static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun const struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn;
901*4882a593Smuzhiyun u32 prio_queues = 0;
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun if (queues & BIT(IEEE80211_AC_VO))
904*4882a593Smuzhiyun prio_queues |= BIT(rqpn->dma_map_vo);
905*4882a593Smuzhiyun if (queues & BIT(IEEE80211_AC_VI))
906*4882a593Smuzhiyun prio_queues |= BIT(rqpn->dma_map_vi);
907*4882a593Smuzhiyun if (queues & BIT(IEEE80211_AC_BE))
908*4882a593Smuzhiyun prio_queues |= BIT(rqpn->dma_map_be);
909*4882a593Smuzhiyun if (queues & BIT(IEEE80211_AC_BK))
910*4882a593Smuzhiyun prio_queues |= BIT(rqpn->dma_map_bk);
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun return prio_queues;
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
__rtw_mac_flush_prio_queue(struct rtw_dev * rtwdev,u32 prio_queue,bool drop)915*4882a593Smuzhiyun static void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev,
916*4882a593Smuzhiyun u32 prio_queue, bool drop)
917*4882a593Smuzhiyun {
918*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
919*4882a593Smuzhiyun const struct rtw_prioq_addr *addr;
920*4882a593Smuzhiyun bool wsize;
921*4882a593Smuzhiyun u16 avail_page, rsvd_page;
922*4882a593Smuzhiyun int i;
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun if (prio_queue >= RTW_DMA_MAPPING_MAX)
925*4882a593Smuzhiyun return;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun addr = &chip->prioq_addrs->prio[prio_queue];
928*4882a593Smuzhiyun wsize = chip->prioq_addrs->wsize;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun /* check if all of the reserved pages are available for 100 msecs */
931*4882a593Smuzhiyun for (i = 0; i < 5; i++) {
932*4882a593Smuzhiyun rsvd_page = wsize ? rtw_read16(rtwdev, addr->rsvd) :
933*4882a593Smuzhiyun rtw_read8(rtwdev, addr->rsvd);
934*4882a593Smuzhiyun avail_page = wsize ? rtw_read16(rtwdev, addr->avail) :
935*4882a593Smuzhiyun rtw_read8(rtwdev, addr->avail);
936*4882a593Smuzhiyun if (rsvd_page == avail_page)
937*4882a593Smuzhiyun return;
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun msleep(20);
940*4882a593Smuzhiyun }
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun /* priority queue is still not empty, throw a warning,
943*4882a593Smuzhiyun *
944*4882a593Smuzhiyun * Note that if we want to flush the tx queue when having a lot of
945*4882a593Smuzhiyun * traffic (ex, 100Mbps up), some of the packets could be dropped.
946*4882a593Smuzhiyun * And it requires like ~2secs to flush the full priority queue.
947*4882a593Smuzhiyun */
948*4882a593Smuzhiyun if (!drop)
949*4882a593Smuzhiyun rtw_warn(rtwdev, "timed out to flush queue %d\n", prio_queue);
950*4882a593Smuzhiyun }
951*4882a593Smuzhiyun
rtw_mac_flush_prio_queues(struct rtw_dev * rtwdev,u32 prio_queues,bool drop)952*4882a593Smuzhiyun static void rtw_mac_flush_prio_queues(struct rtw_dev *rtwdev,
953*4882a593Smuzhiyun u32 prio_queues, bool drop)
954*4882a593Smuzhiyun {
955*4882a593Smuzhiyun u32 q;
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun for (q = 0; q < RTW_DMA_MAPPING_MAX; q++)
958*4882a593Smuzhiyun if (prio_queues & BIT(q))
959*4882a593Smuzhiyun __rtw_mac_flush_prio_queue(rtwdev, q, drop);
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun
rtw_mac_flush_queues(struct rtw_dev * rtwdev,u32 queues,bool drop)962*4882a593Smuzhiyun void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun u32 prio_queues = 0;
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun /* If all of the hardware queues are requested to flush,
967*4882a593Smuzhiyun * or the priority queues are not mapped yet,
968*4882a593Smuzhiyun * flush all of the priority queues
969*4882a593Smuzhiyun */
970*4882a593Smuzhiyun if (queues == BIT(rtwdev->hw->queues) - 1 || !rtwdev->fifo.rqpn)
971*4882a593Smuzhiyun prio_queues = BIT(RTW_DMA_MAPPING_MAX) - 1;
972*4882a593Smuzhiyun else
973*4882a593Smuzhiyun prio_queues = get_priority_queues(rtwdev, queues);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun rtw_mac_flush_prio_queues(rtwdev, prio_queues, drop);
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun
txdma_queue_mapping(struct rtw_dev * rtwdev)978*4882a593Smuzhiyun static int txdma_queue_mapping(struct rtw_dev *rtwdev)
979*4882a593Smuzhiyun {
980*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
981*4882a593Smuzhiyun const struct rtw_rqpn *rqpn = NULL;
982*4882a593Smuzhiyun u16 txdma_pq_map = 0;
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun switch (rtw_hci_type(rtwdev)) {
985*4882a593Smuzhiyun case RTW_HCI_TYPE_PCIE:
986*4882a593Smuzhiyun rqpn = &chip->rqpn_table[1];
987*4882a593Smuzhiyun break;
988*4882a593Smuzhiyun case RTW_HCI_TYPE_USB:
989*4882a593Smuzhiyun if (rtwdev->hci.bulkout_num == 2)
990*4882a593Smuzhiyun rqpn = &chip->rqpn_table[2];
991*4882a593Smuzhiyun else if (rtwdev->hci.bulkout_num == 3)
992*4882a593Smuzhiyun rqpn = &chip->rqpn_table[3];
993*4882a593Smuzhiyun else if (rtwdev->hci.bulkout_num == 4)
994*4882a593Smuzhiyun rqpn = &chip->rqpn_table[4];
995*4882a593Smuzhiyun else
996*4882a593Smuzhiyun return -EINVAL;
997*4882a593Smuzhiyun break;
998*4882a593Smuzhiyun default:
999*4882a593Smuzhiyun return -EINVAL;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun rtwdev->fifo.rqpn = rqpn;
1003*4882a593Smuzhiyun txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi);
1004*4882a593Smuzhiyun txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg);
1005*4882a593Smuzhiyun txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk);
1006*4882a593Smuzhiyun txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be);
1007*4882a593Smuzhiyun txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi);
1008*4882a593Smuzhiyun txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo);
1009*4882a593Smuzhiyun rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map);
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun rtw_write8(rtwdev, REG_CR, 0);
1012*4882a593Smuzhiyun rtw_write8(rtwdev, REG_CR, MAC_TRX_ENABLE);
1013*4882a593Smuzhiyun if (rtw_chip_wcpu_11ac(rtwdev))
1014*4882a593Smuzhiyun rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL);
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun return 0;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun
set_trx_fifo_info(struct rtw_dev * rtwdev)1019*4882a593Smuzhiyun static int set_trx_fifo_info(struct rtw_dev *rtwdev)
1020*4882a593Smuzhiyun {
1021*4882a593Smuzhiyun struct rtw_fifo_conf *fifo = &rtwdev->fifo;
1022*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
1023*4882a593Smuzhiyun u16 cur_pg_addr;
1024*4882a593Smuzhiyun u8 csi_buf_pg_num = chip->csi_buf_pg_num;
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun /* config rsvd page num */
1027*4882a593Smuzhiyun fifo->rsvd_drv_pg_num = 8;
1028*4882a593Smuzhiyun fifo->txff_pg_num = chip->txff_size >> 7;
1029*4882a593Smuzhiyun if (rtw_chip_wcpu_11n(rtwdev))
1030*4882a593Smuzhiyun fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num;
1031*4882a593Smuzhiyun else
1032*4882a593Smuzhiyun fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num +
1033*4882a593Smuzhiyun RSVD_PG_H2C_EXTRAINFO_NUM +
1034*4882a593Smuzhiyun RSVD_PG_H2C_STATICINFO_NUM +
1035*4882a593Smuzhiyun RSVD_PG_H2CQ_NUM +
1036*4882a593Smuzhiyun RSVD_PG_CPU_INSTRUCTION_NUM +
1037*4882a593Smuzhiyun RSVD_PG_FW_TXBUF_NUM +
1038*4882a593Smuzhiyun csi_buf_pg_num;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun if (fifo->rsvd_pg_num > fifo->txff_pg_num)
1041*4882a593Smuzhiyun return -ENOMEM;
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun fifo->acq_pg_num = fifo->txff_pg_num - fifo->rsvd_pg_num;
1044*4882a593Smuzhiyun fifo->rsvd_boundary = fifo->txff_pg_num - fifo->rsvd_pg_num;
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun cur_pg_addr = fifo->txff_pg_num;
1047*4882a593Smuzhiyun if (rtw_chip_wcpu_11ac(rtwdev)) {
1048*4882a593Smuzhiyun cur_pg_addr -= csi_buf_pg_num;
1049*4882a593Smuzhiyun fifo->rsvd_csibuf_addr = cur_pg_addr;
1050*4882a593Smuzhiyun cur_pg_addr -= RSVD_PG_FW_TXBUF_NUM;
1051*4882a593Smuzhiyun fifo->rsvd_fw_txbuf_addr = cur_pg_addr;
1052*4882a593Smuzhiyun cur_pg_addr -= RSVD_PG_CPU_INSTRUCTION_NUM;
1053*4882a593Smuzhiyun fifo->rsvd_cpu_instr_addr = cur_pg_addr;
1054*4882a593Smuzhiyun cur_pg_addr -= RSVD_PG_H2CQ_NUM;
1055*4882a593Smuzhiyun fifo->rsvd_h2cq_addr = cur_pg_addr;
1056*4882a593Smuzhiyun cur_pg_addr -= RSVD_PG_H2C_STATICINFO_NUM;
1057*4882a593Smuzhiyun fifo->rsvd_h2c_sta_info_addr = cur_pg_addr;
1058*4882a593Smuzhiyun cur_pg_addr -= RSVD_PG_H2C_EXTRAINFO_NUM;
1059*4882a593Smuzhiyun fifo->rsvd_h2c_info_addr = cur_pg_addr;
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun cur_pg_addr -= fifo->rsvd_drv_pg_num;
1062*4882a593Smuzhiyun fifo->rsvd_drv_addr = cur_pg_addr;
1063*4882a593Smuzhiyun
1064*4882a593Smuzhiyun if (fifo->rsvd_boundary != fifo->rsvd_drv_addr) {
1065*4882a593Smuzhiyun rtw_err(rtwdev, "wrong rsvd driver address\n");
1066*4882a593Smuzhiyun return -EINVAL;
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun return 0;
1070*4882a593Smuzhiyun }
1071*4882a593Smuzhiyun
__priority_queue_cfg(struct rtw_dev * rtwdev,const struct rtw_page_table * pg_tbl,u16 pubq_num)1072*4882a593Smuzhiyun static int __priority_queue_cfg(struct rtw_dev *rtwdev,
1073*4882a593Smuzhiyun const struct rtw_page_table *pg_tbl,
1074*4882a593Smuzhiyun u16 pubq_num)
1075*4882a593Smuzhiyun {
1076*4882a593Smuzhiyun struct rtw_fifo_conf *fifo = &rtwdev->fifo;
1077*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, pg_tbl->hq_num);
1080*4882a593Smuzhiyun rtw_write16(rtwdev, REG_FIFOPAGE_INFO_2, pg_tbl->lq_num);
1081*4882a593Smuzhiyun rtw_write16(rtwdev, REG_FIFOPAGE_INFO_3, pg_tbl->nq_num);
1082*4882a593Smuzhiyun rtw_write16(rtwdev, REG_FIFOPAGE_INFO_4, pg_tbl->exq_num);
1083*4882a593Smuzhiyun rtw_write16(rtwdev, REG_FIFOPAGE_INFO_5, pubq_num);
1084*4882a593Smuzhiyun rtw_write32_set(rtwdev, REG_RQPN_CTRL_2, BIT_LD_RQPN);
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2, fifo->rsvd_boundary);
1087*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL + 2, BIT_EN_WR_FREE_TAIL >> 16);
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun rtw_write16(rtwdev, REG_BCNQ_BDNY_V1, fifo->rsvd_boundary);
1090*4882a593Smuzhiyun rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2 + 2, fifo->rsvd_boundary);
1091*4882a593Smuzhiyun rtw_write16(rtwdev, REG_BCNQ1_BDNY_V1, fifo->rsvd_boundary);
1092*4882a593Smuzhiyun rtw_write32(rtwdev, REG_RXFF_BNDY, chip->rxff_size - C2H_PKT_BUF - 1);
1093*4882a593Smuzhiyun rtw_write8_set(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1);
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun if (!check_hw_ready(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1, 0))
1096*4882a593Smuzhiyun return -EBUSY;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun rtw_write8(rtwdev, REG_CR + 3, 0);
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun return 0;
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun
__priority_queue_cfg_legacy(struct rtw_dev * rtwdev,const struct rtw_page_table * pg_tbl,u16 pubq_num)1103*4882a593Smuzhiyun static int __priority_queue_cfg_legacy(struct rtw_dev *rtwdev,
1104*4882a593Smuzhiyun const struct rtw_page_table *pg_tbl,
1105*4882a593Smuzhiyun u16 pubq_num)
1106*4882a593Smuzhiyun {
1107*4882a593Smuzhiyun struct rtw_fifo_conf *fifo = &rtwdev->fifo;
1108*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
1109*4882a593Smuzhiyun u32 val32;
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num);
1112*4882a593Smuzhiyun rtw_write32(rtwdev, REG_RQPN_NPQ, val32);
1113*4882a593Smuzhiyun val32 = BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num);
1114*4882a593Smuzhiyun rtw_write32(rtwdev, REG_RQPN, val32);
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun rtw_write8(rtwdev, REG_TRXFF_BNDY, fifo->rsvd_boundary);
1117*4882a593Smuzhiyun rtw_write16(rtwdev, REG_TRXFF_BNDY + 2, chip->rxff_size - REPORT_BUF - 1);
1118*4882a593Smuzhiyun rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1, fifo->rsvd_boundary);
1119*4882a593Smuzhiyun rtw_write8(rtwdev, REG_BCNQ_BDNY, fifo->rsvd_boundary);
1120*4882a593Smuzhiyun rtw_write8(rtwdev, REG_MGQ_BDNY, fifo->rsvd_boundary);
1121*4882a593Smuzhiyun rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, fifo->rsvd_boundary);
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun rtw_write32_set(rtwdev, REG_AUTO_LLT, BIT_AUTO_INIT_LLT);
1124*4882a593Smuzhiyun
1125*4882a593Smuzhiyun if (!check_hw_ready(rtwdev, REG_AUTO_LLT, BIT_AUTO_INIT_LLT, 0))
1126*4882a593Smuzhiyun return -EBUSY;
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun return 0;
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun
priority_queue_cfg(struct rtw_dev * rtwdev)1131*4882a593Smuzhiyun static int priority_queue_cfg(struct rtw_dev *rtwdev)
1132*4882a593Smuzhiyun {
1133*4882a593Smuzhiyun struct rtw_fifo_conf *fifo = &rtwdev->fifo;
1134*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
1135*4882a593Smuzhiyun const struct rtw_page_table *pg_tbl = NULL;
1136*4882a593Smuzhiyun u16 pubq_num;
1137*4882a593Smuzhiyun int ret;
1138*4882a593Smuzhiyun
1139*4882a593Smuzhiyun ret = set_trx_fifo_info(rtwdev);
1140*4882a593Smuzhiyun if (ret)
1141*4882a593Smuzhiyun return ret;
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun switch (rtw_hci_type(rtwdev)) {
1144*4882a593Smuzhiyun case RTW_HCI_TYPE_PCIE:
1145*4882a593Smuzhiyun pg_tbl = &chip->page_table[1];
1146*4882a593Smuzhiyun break;
1147*4882a593Smuzhiyun case RTW_HCI_TYPE_USB:
1148*4882a593Smuzhiyun if (rtwdev->hci.bulkout_num == 2)
1149*4882a593Smuzhiyun pg_tbl = &chip->page_table[2];
1150*4882a593Smuzhiyun else if (rtwdev->hci.bulkout_num == 3)
1151*4882a593Smuzhiyun pg_tbl = &chip->page_table[3];
1152*4882a593Smuzhiyun else if (rtwdev->hci.bulkout_num == 4)
1153*4882a593Smuzhiyun pg_tbl = &chip->page_table[4];
1154*4882a593Smuzhiyun else
1155*4882a593Smuzhiyun return -EINVAL;
1156*4882a593Smuzhiyun break;
1157*4882a593Smuzhiyun default:
1158*4882a593Smuzhiyun return -EINVAL;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num -
1162*4882a593Smuzhiyun pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num;
1163*4882a593Smuzhiyun if (rtw_chip_wcpu_11n(rtwdev))
1164*4882a593Smuzhiyun return __priority_queue_cfg_legacy(rtwdev, pg_tbl, pubq_num);
1165*4882a593Smuzhiyun else
1166*4882a593Smuzhiyun return __priority_queue_cfg(rtwdev, pg_tbl, pubq_num);
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun
init_h2c(struct rtw_dev * rtwdev)1169*4882a593Smuzhiyun static int init_h2c(struct rtw_dev *rtwdev)
1170*4882a593Smuzhiyun {
1171*4882a593Smuzhiyun struct rtw_fifo_conf *fifo = &rtwdev->fifo;
1172*4882a593Smuzhiyun u8 value8;
1173*4882a593Smuzhiyun u32 value32;
1174*4882a593Smuzhiyun u32 h2cq_addr;
1175*4882a593Smuzhiyun u32 h2cq_size;
1176*4882a593Smuzhiyun u32 h2cq_free;
1177*4882a593Smuzhiyun u32 wp, rp;
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun if (rtw_chip_wcpu_11n(rtwdev))
1180*4882a593Smuzhiyun return 0;
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun h2cq_addr = fifo->rsvd_h2cq_addr << TX_PAGE_SIZE_SHIFT;
1183*4882a593Smuzhiyun h2cq_size = RSVD_PG_H2CQ_NUM << TX_PAGE_SIZE_SHIFT;
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_H2C_HEAD);
1186*4882a593Smuzhiyun value32 = (value32 & 0xFFFC0000) | h2cq_addr;
1187*4882a593Smuzhiyun rtw_write32(rtwdev, REG_H2C_HEAD, value32);
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_H2C_READ_ADDR);
1190*4882a593Smuzhiyun value32 = (value32 & 0xFFFC0000) | h2cq_addr;
1191*4882a593Smuzhiyun rtw_write32(rtwdev, REG_H2C_READ_ADDR, value32);
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun value32 = rtw_read32(rtwdev, REG_H2C_TAIL);
1194*4882a593Smuzhiyun value32 &= 0xFFFC0000;
1195*4882a593Smuzhiyun value32 |= (h2cq_addr + h2cq_size);
1196*4882a593Smuzhiyun rtw_write32(rtwdev, REG_H2C_TAIL, value32);
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun value8 = rtw_read8(rtwdev, REG_H2C_INFO);
1199*4882a593Smuzhiyun value8 = (u8)((value8 & 0xFC) | 0x01);
1200*4882a593Smuzhiyun rtw_write8(rtwdev, REG_H2C_INFO, value8);
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun value8 = rtw_read8(rtwdev, REG_H2C_INFO);
1203*4882a593Smuzhiyun value8 = (u8)((value8 & 0xFB) | 0x04);
1204*4882a593Smuzhiyun rtw_write8(rtwdev, REG_H2C_INFO, value8);
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun value8 = rtw_read8(rtwdev, REG_TXDMA_OFFSET_CHK + 1);
1207*4882a593Smuzhiyun value8 = (u8)((value8 & 0x7f) | 0x80);
1208*4882a593Smuzhiyun rtw_write8(rtwdev, REG_TXDMA_OFFSET_CHK + 1, value8);
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun wp = rtw_read32(rtwdev, REG_H2C_PKT_WRITEADDR) & 0x3FFFF;
1211*4882a593Smuzhiyun rp = rtw_read32(rtwdev, REG_H2C_PKT_READADDR) & 0x3FFFF;
1212*4882a593Smuzhiyun h2cq_free = wp >= rp ? h2cq_size - (wp - rp) : rp - wp;
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun if (h2cq_size != h2cq_free) {
1215*4882a593Smuzhiyun rtw_err(rtwdev, "H2C queue mismatch\n");
1216*4882a593Smuzhiyun return -EINVAL;
1217*4882a593Smuzhiyun }
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun return 0;
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun
rtw_init_trx_cfg(struct rtw_dev * rtwdev)1222*4882a593Smuzhiyun static int rtw_init_trx_cfg(struct rtw_dev *rtwdev)
1223*4882a593Smuzhiyun {
1224*4882a593Smuzhiyun int ret;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun ret = txdma_queue_mapping(rtwdev);
1227*4882a593Smuzhiyun if (ret)
1228*4882a593Smuzhiyun return ret;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun ret = priority_queue_cfg(rtwdev);
1231*4882a593Smuzhiyun if (ret)
1232*4882a593Smuzhiyun return ret;
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun ret = init_h2c(rtwdev);
1235*4882a593Smuzhiyun if (ret)
1236*4882a593Smuzhiyun return ret;
1237*4882a593Smuzhiyun
1238*4882a593Smuzhiyun return 0;
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun
rtw_drv_info_cfg(struct rtw_dev * rtwdev)1241*4882a593Smuzhiyun static int rtw_drv_info_cfg(struct rtw_dev *rtwdev)
1242*4882a593Smuzhiyun {
1243*4882a593Smuzhiyun u8 value8;
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE);
1246*4882a593Smuzhiyun if (rtw_chip_wcpu_11ac(rtwdev)) {
1247*4882a593Smuzhiyun value8 = rtw_read8(rtwdev, REG_TRXFF_BNDY + 1);
1248*4882a593Smuzhiyun value8 &= 0xF0;
1249*4882a593Smuzhiyun /* For rxdesc len = 0 issue */
1250*4882a593Smuzhiyun value8 |= 0xF;
1251*4882a593Smuzhiyun rtw_write8(rtwdev, REG_TRXFF_BNDY + 1, value8);
1252*4882a593Smuzhiyun }
1253*4882a593Smuzhiyun rtw_write32_set(rtwdev, REG_RCR, BIT_APP_PHYSTS);
1254*4882a593Smuzhiyun rtw_write32_clr(rtwdev, REG_WMAC_OPTION_FUNCTION + 4, BIT(8) | BIT(9));
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun return 0;
1257*4882a593Smuzhiyun }
1258*4882a593Smuzhiyun
rtw_mac_init(struct rtw_dev * rtwdev)1259*4882a593Smuzhiyun int rtw_mac_init(struct rtw_dev *rtwdev)
1260*4882a593Smuzhiyun {
1261*4882a593Smuzhiyun struct rtw_chip_info *chip = rtwdev->chip;
1262*4882a593Smuzhiyun int ret;
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun ret = rtw_init_trx_cfg(rtwdev);
1265*4882a593Smuzhiyun if (ret)
1266*4882a593Smuzhiyun return ret;
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun ret = chip->ops->mac_init(rtwdev);
1269*4882a593Smuzhiyun if (ret)
1270*4882a593Smuzhiyun return ret;
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun ret = rtw_drv_info_cfg(rtwdev);
1273*4882a593Smuzhiyun if (ret)
1274*4882a593Smuzhiyun return ret;
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun rtw_hci_interface_cfg(rtwdev);
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun return 0;
1279*4882a593Smuzhiyun }
1280