1e3037485SYan-Hsuan Chuang // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2e3037485SYan-Hsuan Chuang /* Copyright(c) 2018-2019 Realtek Corporation 3e3037485SYan-Hsuan Chuang */ 4e3037485SYan-Hsuan Chuang 5e3037485SYan-Hsuan Chuang #include "main.h" 6e3037485SYan-Hsuan Chuang #include "mac.h" 7e3037485SYan-Hsuan Chuang #include "reg.h" 8e3037485SYan-Hsuan Chuang #include "fw.h" 9e3037485SYan-Hsuan Chuang #include "debug.h" 10e3037485SYan-Hsuan Chuang 11e3037485SYan-Hsuan Chuang void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, 12e3037485SYan-Hsuan Chuang u8 primary_ch_idx) 13e3037485SYan-Hsuan Chuang { 14e3037485SYan-Hsuan Chuang u8 txsc40 = 0, txsc20 = 0; 15e3037485SYan-Hsuan Chuang u32 value32; 16e3037485SYan-Hsuan Chuang u8 value8; 17e3037485SYan-Hsuan Chuang 18e3037485SYan-Hsuan Chuang txsc20 = primary_ch_idx; 1973a2d0b8SPing-Ke Shih if (bw == RTW_CHANNEL_WIDTH_80) { 2040fb04b2SPing-Ke Shih if (txsc20 == RTW_SC_20_UPPER || txsc20 == RTW_SC_20_UPMOST) 2140fb04b2SPing-Ke Shih txsc40 = RTW_SC_40_UPPER; 22e3037485SYan-Hsuan Chuang else 2340fb04b2SPing-Ke Shih txsc40 = RTW_SC_40_LOWER; 2473a2d0b8SPing-Ke Shih } 25e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_DATA_SC, 26e3037485SYan-Hsuan Chuang BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40)); 27e3037485SYan-Hsuan Chuang 28e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_WMAC_TRXPTCL_CTL); 29e3037485SYan-Hsuan Chuang value32 &= ~BIT_RFMOD; 30e3037485SYan-Hsuan Chuang switch (bw) { 31e3037485SYan-Hsuan Chuang case RTW_CHANNEL_WIDTH_80: 32e3037485SYan-Hsuan Chuang value32 |= BIT_RFMOD_80M; 33e3037485SYan-Hsuan Chuang break; 34e3037485SYan-Hsuan Chuang case RTW_CHANNEL_WIDTH_40: 35e3037485SYan-Hsuan Chuang value32 |= BIT_RFMOD_40M; 36e3037485SYan-Hsuan Chuang break; 37e3037485SYan-Hsuan Chuang case RTW_CHANNEL_WIDTH_20: 38e3037485SYan-Hsuan Chuang default: 39e3037485SYan-Hsuan Chuang break; 40e3037485SYan-Hsuan Chuang } 41e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_WMAC_TRXPTCL_CTL, value32); 42e3037485SYan-Hsuan Chuang 435f028a9cSPing-Ke Shih if (rtw_chip_wcpu_11n(rtwdev)) 445f028a9cSPing-Ke Shih return; 455f028a9cSPing-Ke Shih 46e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_AFE_CTRL1) & ~(BIT_MAC_CLK_SEL); 47e3037485SYan-Hsuan Chuang value32 |= (MAC_CLK_HW_DEF_80M << BIT_SHIFT_MAC_CLK_SEL); 48e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_AFE_CTRL1, value32); 49e3037485SYan-Hsuan Chuang 50e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_USTIME_TSF, MAC_CLK_SPEED); 51e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_USTIME_EDCA, MAC_CLK_SPEED); 52e3037485SYan-Hsuan Chuang 53e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_CCK_CHECK); 54e3037485SYan-Hsuan Chuang value8 = value8 & ~BIT_CHECK_CCK_EN; 558575b534SYan-Hsuan Chuang if (IS_CH_5G_BAND(channel)) 56e3037485SYan-Hsuan Chuang value8 |= BIT_CHECK_CCK_EN; 57e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CCK_CHECK, value8); 58e3037485SYan-Hsuan Chuang } 59449be866SZong-Zhe Yang EXPORT_SYMBOL(rtw_set_channel_mac); 60e3037485SYan-Hsuan Chuang 61e3037485SYan-Hsuan Chuang static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev) 62e3037485SYan-Hsuan Chuang { 63e3037485SYan-Hsuan Chuang u32 value32; 64e3037485SYan-Hsuan Chuang u8 value8; 65e3037485SYan-Hsuan Chuang 66e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_RSV_CTRL, 0); 67e3037485SYan-Hsuan Chuang 684e223a5fSPing-Ke Shih if (rtw_chip_wcpu_11n(rtwdev)) { 694e223a5fSPing-Ke Shih if (rtw_read32(rtwdev, REG_SYS_CFG1) & BIT_LDO) 704e223a5fSPing-Ke Shih rtw_write8(rtwdev, REG_LDO_SWR_CTRL, LDO_SEL); 714e223a5fSPing-Ke Shih else 724e223a5fSPing-Ke Shih rtw_write8(rtwdev, REG_LDO_SWR_CTRL, SPS_SEL); 734e223a5fSPing-Ke Shih return 0; 744e223a5fSPing-Ke Shih } 754e223a5fSPing-Ke Shih 76e3037485SYan-Hsuan Chuang switch (rtw_hci_type(rtwdev)) { 77e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_PCIE: 78*fc6234d7SKevin Lo rtw_write32_set(rtwdev, REG_HCI_OPT_CTRL, BIT_USB_SUS_DIS); 79e3037485SYan-Hsuan Chuang break; 80e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_USB: 81e3037485SYan-Hsuan Chuang break; 82e3037485SYan-Hsuan Chuang default: 83e3037485SYan-Hsuan Chuang return -EINVAL; 84e3037485SYan-Hsuan Chuang } 85e3037485SYan-Hsuan Chuang 86e3037485SYan-Hsuan Chuang /* config PIN Mux */ 87e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_PAD_CTRL1); 88e3037485SYan-Hsuan Chuang value32 |= BIT_PAPE_WLBT_SEL | BIT_LNAON_WLBT_SEL; 89e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_PAD_CTRL1, value32); 90e3037485SYan-Hsuan Chuang 91e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_LED_CFG); 92e3037485SYan-Hsuan Chuang value32 &= ~(BIT_PAPE_SEL_EN | BIT_LNAON_SEL_EN); 93e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_LED_CFG, value32); 94e3037485SYan-Hsuan Chuang 95e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_GPIO_MUXCFG); 96e3037485SYan-Hsuan Chuang value32 |= BIT_WLRFE_4_5_EN; 97e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_GPIO_MUXCFG, value32); 98e3037485SYan-Hsuan Chuang 99e3037485SYan-Hsuan Chuang /* disable BB/RF */ 100e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN); 101e3037485SYan-Hsuan Chuang value8 &= ~(BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST); 102e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_SYS_FUNC_EN, value8); 103e3037485SYan-Hsuan Chuang 104e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_RF_CTRL); 105e3037485SYan-Hsuan Chuang value8 &= ~(BIT_RF_SDM_RSTB | BIT_RF_RSTB | BIT_RF_EN); 106e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_RF_CTRL, value8); 107e3037485SYan-Hsuan Chuang 108e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_WLRF1); 109e3037485SYan-Hsuan Chuang value32 &= ~BIT_WLRF1_BBRF_EN; 110e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_WLRF1, value32); 111e3037485SYan-Hsuan Chuang 112e3037485SYan-Hsuan Chuang return 0; 113e3037485SYan-Hsuan Chuang } 114e3037485SYan-Hsuan Chuang 115fd9ead38SPing-Ke Shih static bool do_pwr_poll_cmd(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target) 116fd9ead38SPing-Ke Shih { 11786fbf264SBrian Norris u32 val; 118fd9ead38SPing-Ke Shih 119fd9ead38SPing-Ke Shih target &= mask; 120fd9ead38SPing-Ke Shih 12186fbf264SBrian Norris return read_poll_timeout_atomic(rtw_read8, val, (val & mask) == target, 12286fbf264SBrian Norris 50, 50 * RTW_PWR_POLLING_CNT, false, 12386fbf264SBrian Norris rtwdev, addr) == 0; 124fd9ead38SPing-Ke Shih } 125fd9ead38SPing-Ke Shih 126e3037485SYan-Hsuan Chuang static int rtw_pwr_cmd_polling(struct rtw_dev *rtwdev, 127d49f2c50SJoe Perches const struct rtw_pwr_seq_cmd *cmd) 128e3037485SYan-Hsuan Chuang { 129e3037485SYan-Hsuan Chuang u8 value; 130e3037485SYan-Hsuan Chuang u32 offset; 131e3037485SYan-Hsuan Chuang 132e3037485SYan-Hsuan Chuang if (cmd->base == RTW_PWR_ADDR_SDIO) 133e3037485SYan-Hsuan Chuang offset = cmd->offset | SDIO_LOCAL_OFFSET; 134e3037485SYan-Hsuan Chuang else 135e3037485SYan-Hsuan Chuang offset = cmd->offset; 136e3037485SYan-Hsuan Chuang 137fd9ead38SPing-Ke Shih if (do_pwr_poll_cmd(rtwdev, offset, cmd->mask, cmd->value)) 138e3037485SYan-Hsuan Chuang return 0; 1394e223a5fSPing-Ke Shih 140fd9ead38SPing-Ke Shih if (rtw_hci_type(rtwdev) != RTW_HCI_TYPE_PCIE) 141fd9ead38SPing-Ke Shih goto err; 142fd9ead38SPing-Ke Shih 143fd9ead38SPing-Ke Shih /* if PCIE, toggle BIT_PFM_WOWL and try again */ 144fd9ead38SPing-Ke Shih value = rtw_read8(rtwdev, REG_SYS_PW_CTRL); 145fd9ead38SPing-Ke Shih if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D) 146fd9ead38SPing-Ke Shih rtw_write8(rtwdev, REG_SYS_PW_CTRL, value & ~BIT_PFM_WOWL); 147fd9ead38SPing-Ke Shih rtw_write8(rtwdev, REG_SYS_PW_CTRL, value | BIT_PFM_WOWL); 148fd9ead38SPing-Ke Shih rtw_write8(rtwdev, REG_SYS_PW_CTRL, value & ~BIT_PFM_WOWL); 149fd9ead38SPing-Ke Shih if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D) 150fd9ead38SPing-Ke Shih rtw_write8(rtwdev, REG_SYS_PW_CTRL, value | BIT_PFM_WOWL); 151fd9ead38SPing-Ke Shih 152fd9ead38SPing-Ke Shih if (do_pwr_poll_cmd(rtwdev, offset, cmd->mask, cmd->value)) 153fd9ead38SPing-Ke Shih return 0; 154fd9ead38SPing-Ke Shih 155fd9ead38SPing-Ke Shih err: 156fd9ead38SPing-Ke Shih rtw_err(rtwdev, "failed to poll offset=0x%x mask=0x%x value=0x%x\n", 157fd9ead38SPing-Ke Shih offset, cmd->mask, cmd->value); 158e3037485SYan-Hsuan Chuang return -EBUSY; 159e3037485SYan-Hsuan Chuang } 160e3037485SYan-Hsuan Chuang 161e3037485SYan-Hsuan Chuang static int rtw_sub_pwr_seq_parser(struct rtw_dev *rtwdev, u8 intf_mask, 162d49f2c50SJoe Perches u8 cut_mask, 163d49f2c50SJoe Perches const struct rtw_pwr_seq_cmd *cmd) 164e3037485SYan-Hsuan Chuang { 165d49f2c50SJoe Perches const struct rtw_pwr_seq_cmd *cur_cmd; 166e3037485SYan-Hsuan Chuang u32 offset; 167e3037485SYan-Hsuan Chuang u8 value; 168e3037485SYan-Hsuan Chuang 169e3037485SYan-Hsuan Chuang for (cur_cmd = cmd; cur_cmd->cmd != RTW_PWR_CMD_END; cur_cmd++) { 170e3037485SYan-Hsuan Chuang if (!(cur_cmd->intf_mask & intf_mask) || 171e3037485SYan-Hsuan Chuang !(cur_cmd->cut_mask & cut_mask)) 172e3037485SYan-Hsuan Chuang continue; 173e3037485SYan-Hsuan Chuang 174e3037485SYan-Hsuan Chuang switch (cur_cmd->cmd) { 175e3037485SYan-Hsuan Chuang case RTW_PWR_CMD_WRITE: 176e3037485SYan-Hsuan Chuang offset = cur_cmd->offset; 177e3037485SYan-Hsuan Chuang 178e3037485SYan-Hsuan Chuang if (cur_cmd->base == RTW_PWR_ADDR_SDIO) 179e3037485SYan-Hsuan Chuang offset |= SDIO_LOCAL_OFFSET; 180e3037485SYan-Hsuan Chuang 181e3037485SYan-Hsuan Chuang value = rtw_read8(rtwdev, offset); 182e3037485SYan-Hsuan Chuang value &= ~cur_cmd->mask; 183e3037485SYan-Hsuan Chuang value |= (cur_cmd->value & cur_cmd->mask); 184e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, offset, value); 185e3037485SYan-Hsuan Chuang break; 186e3037485SYan-Hsuan Chuang case RTW_PWR_CMD_POLLING: 187e3037485SYan-Hsuan Chuang if (rtw_pwr_cmd_polling(rtwdev, cur_cmd)) 188e3037485SYan-Hsuan Chuang return -EBUSY; 189e3037485SYan-Hsuan Chuang break; 190e3037485SYan-Hsuan Chuang case RTW_PWR_CMD_DELAY: 191e3037485SYan-Hsuan Chuang if (cur_cmd->value == RTW_PWR_DELAY_US) 192e3037485SYan-Hsuan Chuang udelay(cur_cmd->offset); 193e3037485SYan-Hsuan Chuang else 194e3037485SYan-Hsuan Chuang mdelay(cur_cmd->offset); 195e3037485SYan-Hsuan Chuang break; 196e3037485SYan-Hsuan Chuang case RTW_PWR_CMD_READ: 197e3037485SYan-Hsuan Chuang break; 198e3037485SYan-Hsuan Chuang default: 199e3037485SYan-Hsuan Chuang return -EINVAL; 200e3037485SYan-Hsuan Chuang } 201e3037485SYan-Hsuan Chuang } 202e3037485SYan-Hsuan Chuang 203e3037485SYan-Hsuan Chuang return 0; 204e3037485SYan-Hsuan Chuang } 205e3037485SYan-Hsuan Chuang 206e3037485SYan-Hsuan Chuang static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, 207d49f2c50SJoe Perches const struct rtw_pwr_seq_cmd **cmd_seq) 208e3037485SYan-Hsuan Chuang { 209e3037485SYan-Hsuan Chuang u8 cut_mask; 210e3037485SYan-Hsuan Chuang u8 intf_mask; 211e3037485SYan-Hsuan Chuang u8 cut; 212e3037485SYan-Hsuan Chuang u32 idx = 0; 213d49f2c50SJoe Perches const struct rtw_pwr_seq_cmd *cmd; 214e3037485SYan-Hsuan Chuang int ret; 215e3037485SYan-Hsuan Chuang 216e3037485SYan-Hsuan Chuang cut = rtwdev->hal.cut_version; 217e3037485SYan-Hsuan Chuang cut_mask = cut_version_to_mask(cut); 218e3037485SYan-Hsuan Chuang switch (rtw_hci_type(rtwdev)) { 219e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_PCIE: 220e3037485SYan-Hsuan Chuang intf_mask = BIT(2); 221e3037485SYan-Hsuan Chuang break; 222e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_USB: 223e3037485SYan-Hsuan Chuang intf_mask = BIT(1); 224e3037485SYan-Hsuan Chuang break; 225e3037485SYan-Hsuan Chuang default: 226e3037485SYan-Hsuan Chuang return -EINVAL; 227e3037485SYan-Hsuan Chuang } 228e3037485SYan-Hsuan Chuang 229e3037485SYan-Hsuan Chuang do { 230e3037485SYan-Hsuan Chuang cmd = cmd_seq[idx]; 231e3037485SYan-Hsuan Chuang if (!cmd) 232e3037485SYan-Hsuan Chuang break; 233e3037485SYan-Hsuan Chuang 234e3037485SYan-Hsuan Chuang ret = rtw_sub_pwr_seq_parser(rtwdev, intf_mask, cut_mask, cmd); 235e3037485SYan-Hsuan Chuang if (ret) 236e3037485SYan-Hsuan Chuang return -EBUSY; 237e3037485SYan-Hsuan Chuang 238e3037485SYan-Hsuan Chuang idx++; 239e3037485SYan-Hsuan Chuang } while (1); 240e3037485SYan-Hsuan Chuang 241e3037485SYan-Hsuan Chuang return 0; 242e3037485SYan-Hsuan Chuang } 243e3037485SYan-Hsuan Chuang 244e3037485SYan-Hsuan Chuang static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) 245e3037485SYan-Hsuan Chuang { 246e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 247d49f2c50SJoe Perches const struct rtw_pwr_seq_cmd **pwr_seq; 248e3037485SYan-Hsuan Chuang u8 rpwm; 249e3037485SYan-Hsuan Chuang bool cur_pwr; 250e3037485SYan-Hsuan Chuang 2514e223a5fSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev)) { 252e3037485SYan-Hsuan Chuang rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); 253e3037485SYan-Hsuan Chuang 254e3037485SYan-Hsuan Chuang /* Check FW still exist or not */ 255e3037485SYan-Hsuan Chuang if (rtw_read16(rtwdev, REG_MCUFW_CTRL) == 0xC078) { 256e3037485SYan-Hsuan Chuang rpwm = (rpwm ^ BIT_RPWM_TOGGLE) & BIT_RPWM_TOGGLE; 257e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, rpwm); 258e3037485SYan-Hsuan Chuang } 2594e223a5fSPing-Ke Shih } 260e3037485SYan-Hsuan Chuang 261e3037485SYan-Hsuan Chuang if (rtw_read8(rtwdev, REG_CR) == 0xea) 262e3037485SYan-Hsuan Chuang cur_pwr = false; 263e3037485SYan-Hsuan Chuang else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && 264e3037485SYan-Hsuan Chuang (rtw_read8(rtwdev, REG_SYS_STATUS1 + 1) & BIT(0))) 265e3037485SYan-Hsuan Chuang cur_pwr = false; 266e3037485SYan-Hsuan Chuang else 267e3037485SYan-Hsuan Chuang cur_pwr = true; 268e3037485SYan-Hsuan Chuang 2694e223a5fSPing-Ke Shih if (pwr_on == cur_pwr) 270e3037485SYan-Hsuan Chuang return -EALREADY; 271e3037485SYan-Hsuan Chuang 272e3037485SYan-Hsuan Chuang pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq; 273e3037485SYan-Hsuan Chuang if (rtw_pwr_seq_parser(rtwdev, pwr_seq)) 274e3037485SYan-Hsuan Chuang return -EINVAL; 275e3037485SYan-Hsuan Chuang 276e3037485SYan-Hsuan Chuang return 0; 277e3037485SYan-Hsuan Chuang } 278e3037485SYan-Hsuan Chuang 2794e223a5fSPing-Ke Shih static int __rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) 280e3037485SYan-Hsuan Chuang { 281e3037485SYan-Hsuan Chuang u8 sys_func_en = rtwdev->chip->sys_func_en; 282e3037485SYan-Hsuan Chuang u8 value8; 283e3037485SYan-Hsuan Chuang u32 value, tmp; 284e3037485SYan-Hsuan Chuang 285e3037485SYan-Hsuan Chuang value = rtw_read32(rtwdev, REG_CPU_DMEM_CON); 286e3037485SYan-Hsuan Chuang value |= BIT_WL_PLATFORM_RST | BIT_DDMA_EN; 287e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_CPU_DMEM_CON, value); 288e3037485SYan-Hsuan Chuang 289a4835410SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en); 290e3037485SYan-Hsuan Chuang value8 = (rtw_read8(rtwdev, REG_CR_EXT + 3) & 0xF0) | 0x0C; 291e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR_EXT + 3, value8); 292e3037485SYan-Hsuan Chuang 293e3037485SYan-Hsuan Chuang /* disable boot-from-flash for driver's DL FW */ 294e3037485SYan-Hsuan Chuang tmp = rtw_read32(rtwdev, REG_MCUFW_CTRL); 295e3037485SYan-Hsuan Chuang if (tmp & BIT_BOOT_FSPI_EN) { 296e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_MCUFW_CTRL, tmp & (~BIT_BOOT_FSPI_EN)); 297e3037485SYan-Hsuan Chuang value = rtw_read32(rtwdev, REG_GPIO_MUXCFG) & (~BIT_FSPI_EN); 298e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_GPIO_MUXCFG, value); 299e3037485SYan-Hsuan Chuang } 300e3037485SYan-Hsuan Chuang 301e3037485SYan-Hsuan Chuang return 0; 302e3037485SYan-Hsuan Chuang } 303e3037485SYan-Hsuan Chuang 3044e223a5fSPing-Ke Shih static int __rtw_mac_init_system_cfg_legacy(struct rtw_dev *rtwdev) 3054e223a5fSPing-Ke Shih { 3064e223a5fSPing-Ke Shih rtw_write8(rtwdev, REG_CR, 0xff); 3074e223a5fSPing-Ke Shih mdelay(2); 3084e223a5fSPing-Ke Shih rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0x7f); 3094e223a5fSPing-Ke Shih mdelay(2); 3104e223a5fSPing-Ke Shih 3114e223a5fSPing-Ke Shih rtw_write8_set(rtwdev, REG_SYS_CLKR, BIT_WAKEPAD_EN); 3124e223a5fSPing-Ke Shih rtw_write16_clr(rtwdev, REG_GPIO_MUXCFG, BIT_EN_SIC); 3134e223a5fSPing-Ke Shih 3144e223a5fSPing-Ke Shih rtw_write16(rtwdev, REG_CR, 0x2ff); 3154e223a5fSPing-Ke Shih 3164e223a5fSPing-Ke Shih return 0; 3174e223a5fSPing-Ke Shih } 3184e223a5fSPing-Ke Shih 3194e223a5fSPing-Ke Shih static int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) 3204e223a5fSPing-Ke Shih { 3214e223a5fSPing-Ke Shih if (rtw_chip_wcpu_11n(rtwdev)) 3224e223a5fSPing-Ke Shih return __rtw_mac_init_system_cfg_legacy(rtwdev); 3234e223a5fSPing-Ke Shih 3244e223a5fSPing-Ke Shih return __rtw_mac_init_system_cfg(rtwdev); 3254e223a5fSPing-Ke Shih } 3264e223a5fSPing-Ke Shih 327e3037485SYan-Hsuan Chuang int rtw_mac_power_on(struct rtw_dev *rtwdev) 328e3037485SYan-Hsuan Chuang { 329e3037485SYan-Hsuan Chuang int ret = 0; 330e3037485SYan-Hsuan Chuang 331e3037485SYan-Hsuan Chuang ret = rtw_mac_pre_system_cfg(rtwdev); 332e3037485SYan-Hsuan Chuang if (ret) 333e3037485SYan-Hsuan Chuang goto err; 334e3037485SYan-Hsuan Chuang 335e3037485SYan-Hsuan Chuang ret = rtw_mac_power_switch(rtwdev, true); 336d41673b9SYan-Hsuan Chuang if (ret == -EALREADY) { 337d41673b9SYan-Hsuan Chuang rtw_mac_power_switch(rtwdev, false); 338d41673b9SYan-Hsuan Chuang ret = rtw_mac_power_switch(rtwdev, true); 339e3037485SYan-Hsuan Chuang if (ret) 340e3037485SYan-Hsuan Chuang goto err; 341d41673b9SYan-Hsuan Chuang } else if (ret) { 342d41673b9SYan-Hsuan Chuang goto err; 343d41673b9SYan-Hsuan Chuang } 344e3037485SYan-Hsuan Chuang 345e3037485SYan-Hsuan Chuang ret = rtw_mac_init_system_cfg(rtwdev); 346e3037485SYan-Hsuan Chuang if (ret) 347e3037485SYan-Hsuan Chuang goto err; 348e3037485SYan-Hsuan Chuang 349e3037485SYan-Hsuan Chuang return 0; 350e3037485SYan-Hsuan Chuang 351e3037485SYan-Hsuan Chuang err: 352e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "mac power on failed"); 353e3037485SYan-Hsuan Chuang return ret; 354e3037485SYan-Hsuan Chuang } 355e3037485SYan-Hsuan Chuang 356e3037485SYan-Hsuan Chuang void rtw_mac_power_off(struct rtw_dev *rtwdev) 357e3037485SYan-Hsuan Chuang { 358e3037485SYan-Hsuan Chuang rtw_mac_power_switch(rtwdev, false); 359e3037485SYan-Hsuan Chuang } 360e3037485SYan-Hsuan Chuang 361e3037485SYan-Hsuan Chuang static bool check_firmware_size(const u8 *data, u32 size) 362e3037485SYan-Hsuan Chuang { 363cc20a713SPing-Ke Shih const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data; 364e3037485SYan-Hsuan Chuang u32 dmem_size; 365e3037485SYan-Hsuan Chuang u32 imem_size; 366e3037485SYan-Hsuan Chuang u32 emem_size; 367e3037485SYan-Hsuan Chuang u32 real_size; 368e3037485SYan-Hsuan Chuang 369cc20a713SPing-Ke Shih dmem_size = le32_to_cpu(fw_hdr->dmem_size); 370cc20a713SPing-Ke Shih imem_size = le32_to_cpu(fw_hdr->imem_size); 371cc20a713SPing-Ke Shih emem_size = (fw_hdr->mem_usage & BIT(4)) ? 372cc20a713SPing-Ke Shih le32_to_cpu(fw_hdr->emem_size) : 0; 373e3037485SYan-Hsuan Chuang 374e3037485SYan-Hsuan Chuang dmem_size += FW_HDR_CHKSUM_SIZE; 375e3037485SYan-Hsuan Chuang imem_size += FW_HDR_CHKSUM_SIZE; 376e3037485SYan-Hsuan Chuang emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0; 377e3037485SYan-Hsuan Chuang real_size = FW_HDR_SIZE + dmem_size + imem_size + emem_size; 378e3037485SYan-Hsuan Chuang if (real_size != size) 379e3037485SYan-Hsuan Chuang return false; 380e3037485SYan-Hsuan Chuang 381e3037485SYan-Hsuan Chuang return true; 382e3037485SYan-Hsuan Chuang } 383e3037485SYan-Hsuan Chuang 384e3037485SYan-Hsuan Chuang static void wlan_cpu_enable(struct rtw_dev *rtwdev, bool enable) 385e3037485SYan-Hsuan Chuang { 386e3037485SYan-Hsuan Chuang if (enable) { 387e3037485SYan-Hsuan Chuang /* cpu io interface enable */ 388e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF); 389e3037485SYan-Hsuan Chuang 390e3037485SYan-Hsuan Chuang /* cpu enable */ 391e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 392e3037485SYan-Hsuan Chuang } else { 393e3037485SYan-Hsuan Chuang /* cpu io interface disable */ 394e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 395e3037485SYan-Hsuan Chuang 396e3037485SYan-Hsuan Chuang /* cpu disable */ 397e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF); 398e3037485SYan-Hsuan Chuang } 399e3037485SYan-Hsuan Chuang } 400e3037485SYan-Hsuan Chuang 401e3037485SYan-Hsuan Chuang #define DLFW_RESTORE_REG_NUM 6 402e3037485SYan-Hsuan Chuang 403e3037485SYan-Hsuan Chuang static void download_firmware_reg_backup(struct rtw_dev *rtwdev, 404e3037485SYan-Hsuan Chuang struct rtw_backup_info *bckp) 405e3037485SYan-Hsuan Chuang { 406e3037485SYan-Hsuan Chuang u8 tmp; 407e3037485SYan-Hsuan Chuang u8 bckp_idx = 0; 408e3037485SYan-Hsuan Chuang 409e3037485SYan-Hsuan Chuang /* set HIQ to hi priority */ 410e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 1; 411e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_TXDMA_PQ_MAP + 1; 412e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = rtw_read8(rtwdev, REG_TXDMA_PQ_MAP + 1); 413e3037485SYan-Hsuan Chuang bckp_idx++; 414e3037485SYan-Hsuan Chuang tmp = RTW_DMA_MAPPING_HIGH << 6; 415e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_TXDMA_PQ_MAP + 1, tmp); 416e3037485SYan-Hsuan Chuang 417e3037485SYan-Hsuan Chuang /* DLFW only use HIQ, map HIQ to hi priority */ 418e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 1; 419e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_CR; 420e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = rtw_read8(rtwdev, REG_CR); 421e3037485SYan-Hsuan Chuang bckp_idx++; 422e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 4; 423e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_H2CQ_CSR; 424e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = BIT_H2CQ_FULL; 425e3037485SYan-Hsuan Chuang bckp_idx++; 426e3037485SYan-Hsuan Chuang tmp = BIT_HCI_TXDMA_EN | BIT_TXDMA_EN; 427e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR, tmp); 428e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); 429e3037485SYan-Hsuan Chuang 430e3037485SYan-Hsuan Chuang /* Config hi priority queue and public priority queue page number */ 431e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 2; 432e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_FIFOPAGE_INFO_1; 433e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = rtw_read16(rtwdev, REG_FIFOPAGE_INFO_1); 434e3037485SYan-Hsuan Chuang bckp_idx++; 435e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 4; 436e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_RQPN_CTRL_2; 437e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = rtw_read32(rtwdev, REG_RQPN_CTRL_2) | BIT_LD_RQPN; 438e3037485SYan-Hsuan Chuang bckp_idx++; 439e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, 0x200); 440e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_RQPN_CTRL_2, bckp[bckp_idx - 1].val); 441e3037485SYan-Hsuan Chuang 442e3037485SYan-Hsuan Chuang /* Disable beacon related functions */ 443e3037485SYan-Hsuan Chuang tmp = rtw_read8(rtwdev, REG_BCN_CTRL); 444e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 1; 445e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_BCN_CTRL; 446e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = tmp; 447e3037485SYan-Hsuan Chuang bckp_idx++; 448e3037485SYan-Hsuan Chuang tmp = (u8)((tmp & (~BIT_EN_BCN_FUNCTION)) | BIT_DIS_TSF_UDT); 449e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_BCN_CTRL, tmp); 450e3037485SYan-Hsuan Chuang 451e3037485SYan-Hsuan Chuang WARN(bckp_idx != DLFW_RESTORE_REG_NUM, "wrong backup number\n"); 452e3037485SYan-Hsuan Chuang } 453e3037485SYan-Hsuan Chuang 454e3037485SYan-Hsuan Chuang static void download_firmware_reset_platform(struct rtw_dev *rtwdev) 455e3037485SYan-Hsuan Chuang { 456e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16); 457e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8); 458e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16); 459e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8); 460e3037485SYan-Hsuan Chuang } 461e3037485SYan-Hsuan Chuang 462e3037485SYan-Hsuan Chuang static void download_firmware_reg_restore(struct rtw_dev *rtwdev, 463e3037485SYan-Hsuan Chuang struct rtw_backup_info *bckp, 464e3037485SYan-Hsuan Chuang u8 bckp_num) 465e3037485SYan-Hsuan Chuang { 466e3037485SYan-Hsuan Chuang rtw_restore_reg(rtwdev, bckp, bckp_num); 467e3037485SYan-Hsuan Chuang } 468e3037485SYan-Hsuan Chuang 469e3037485SYan-Hsuan Chuang #define TX_DESC_SIZE 48 470e3037485SYan-Hsuan Chuang 471e3037485SYan-Hsuan Chuang static int send_firmware_pkt_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, 472e3037485SYan-Hsuan Chuang const u8 *data, u32 size) 473e3037485SYan-Hsuan Chuang { 474e3037485SYan-Hsuan Chuang u8 *buf; 475e3037485SYan-Hsuan Chuang int ret; 476e3037485SYan-Hsuan Chuang 477e3037485SYan-Hsuan Chuang buf = kmemdup(data, size, GFP_KERNEL); 478e3037485SYan-Hsuan Chuang if (!buf) 479e3037485SYan-Hsuan Chuang return -ENOMEM; 480e3037485SYan-Hsuan Chuang 481e3037485SYan-Hsuan Chuang ret = rtw_fw_write_data_rsvd_page(rtwdev, pg_addr, buf, size); 482e3037485SYan-Hsuan Chuang kfree(buf); 483e3037485SYan-Hsuan Chuang return ret; 484e3037485SYan-Hsuan Chuang } 485e3037485SYan-Hsuan Chuang 486e3037485SYan-Hsuan Chuang static int 487e3037485SYan-Hsuan Chuang send_firmware_pkt(struct rtw_dev *rtwdev, u16 pg_addr, const u8 *data, u32 size) 488e3037485SYan-Hsuan Chuang { 489e3037485SYan-Hsuan Chuang int ret; 490e3037485SYan-Hsuan Chuang 491e3037485SYan-Hsuan Chuang if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && 492e3037485SYan-Hsuan Chuang !((size + TX_DESC_SIZE) & (512 - 1))) 493e3037485SYan-Hsuan Chuang size += 1; 494e3037485SYan-Hsuan Chuang 495e3037485SYan-Hsuan Chuang ret = send_firmware_pkt_rsvd_page(rtwdev, pg_addr, data, size); 496e3037485SYan-Hsuan Chuang if (ret) 497e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to download rsvd page\n"); 498e3037485SYan-Hsuan Chuang 499e3037485SYan-Hsuan Chuang return ret; 500e3037485SYan-Hsuan Chuang } 501e3037485SYan-Hsuan Chuang 502e3037485SYan-Hsuan Chuang static int 503e3037485SYan-Hsuan Chuang iddma_enable(struct rtw_dev *rtwdev, u32 src, u32 dst, u32 ctrl) 504e3037485SYan-Hsuan Chuang { 505e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_DDMA_CH0SA, src); 506e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_DDMA_CH0DA, dst); 507e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_DDMA_CH0CTRL, ctrl); 508e3037485SYan-Hsuan Chuang 509e3037485SYan-Hsuan Chuang if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) 510e3037485SYan-Hsuan Chuang return -EBUSY; 511e3037485SYan-Hsuan Chuang 512e3037485SYan-Hsuan Chuang return 0; 513e3037485SYan-Hsuan Chuang } 514e3037485SYan-Hsuan Chuang 515e3037485SYan-Hsuan Chuang static int iddma_download_firmware(struct rtw_dev *rtwdev, u32 src, u32 dst, 516e3037485SYan-Hsuan Chuang u32 len, u8 first) 517e3037485SYan-Hsuan Chuang { 518e3037485SYan-Hsuan Chuang u32 ch0_ctrl = BIT_DDMACH0_CHKSUM_EN | BIT_DDMACH0_OWN; 519e3037485SYan-Hsuan Chuang 520e3037485SYan-Hsuan Chuang if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) 521e3037485SYan-Hsuan Chuang return -EBUSY; 522e3037485SYan-Hsuan Chuang 523e3037485SYan-Hsuan Chuang ch0_ctrl |= len & BIT_MASK_DDMACH0_DLEN; 524e3037485SYan-Hsuan Chuang if (!first) 525e3037485SYan-Hsuan Chuang ch0_ctrl |= BIT_DDMACH0_CHKSUM_CONT; 526e3037485SYan-Hsuan Chuang 527e3037485SYan-Hsuan Chuang if (iddma_enable(rtwdev, src, dst, ch0_ctrl)) 528e3037485SYan-Hsuan Chuang return -EBUSY; 529e3037485SYan-Hsuan Chuang 530e3037485SYan-Hsuan Chuang return 0; 531e3037485SYan-Hsuan Chuang } 532e3037485SYan-Hsuan Chuang 53313ce240aSZong-Zhe Yang int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size) 53413ce240aSZong-Zhe Yang { 53513ce240aSZong-Zhe Yang u32 ch0_ctrl = BIT_DDMACH0_OWN | BIT_DDMACH0_DDMA_MODE; 53613ce240aSZong-Zhe Yang 53713ce240aSZong-Zhe Yang if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) { 53813ce240aSZong-Zhe Yang rtw_dbg(rtwdev, RTW_DBG_FW, "busy to start ddma\n"); 53913ce240aSZong-Zhe Yang return -EBUSY; 54013ce240aSZong-Zhe Yang } 54113ce240aSZong-Zhe Yang 54213ce240aSZong-Zhe Yang ch0_ctrl |= size & BIT_MASK_DDMACH0_DLEN; 54313ce240aSZong-Zhe Yang 54413ce240aSZong-Zhe Yang if (iddma_enable(rtwdev, ocp_src, OCPBASE_RXBUF_FW_88XX, ch0_ctrl)) { 54513ce240aSZong-Zhe Yang rtw_dbg(rtwdev, RTW_DBG_FW, "busy to complete ddma\n"); 54613ce240aSZong-Zhe Yang return -EBUSY; 54713ce240aSZong-Zhe Yang } 54813ce240aSZong-Zhe Yang 54913ce240aSZong-Zhe Yang return 0; 55013ce240aSZong-Zhe Yang } 55113ce240aSZong-Zhe Yang 552e3037485SYan-Hsuan Chuang static bool 553e3037485SYan-Hsuan Chuang check_fw_checksum(struct rtw_dev *rtwdev, u32 addr) 554e3037485SYan-Hsuan Chuang { 555e3037485SYan-Hsuan Chuang u8 fw_ctrl; 556e3037485SYan-Hsuan Chuang 557e3037485SYan-Hsuan Chuang fw_ctrl = rtw_read8(rtwdev, REG_MCUFW_CTRL); 558e3037485SYan-Hsuan Chuang 559e3037485SYan-Hsuan Chuang if (rtw_read32(rtwdev, REG_DDMA_CH0CTRL) & BIT_DDMACH0_CHKSUM_STS) { 560e3037485SYan-Hsuan Chuang if (addr < OCPBASE_DMEM_88XX) { 561e3037485SYan-Hsuan Chuang fw_ctrl |= BIT_IMEM_DW_OK; 562e3037485SYan-Hsuan Chuang fw_ctrl &= ~BIT_IMEM_CHKSUM_OK; 563e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 564e3037485SYan-Hsuan Chuang } else { 565e3037485SYan-Hsuan Chuang fw_ctrl |= BIT_DMEM_DW_OK; 566e3037485SYan-Hsuan Chuang fw_ctrl &= ~BIT_DMEM_CHKSUM_OK; 567e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 568e3037485SYan-Hsuan Chuang } 569e3037485SYan-Hsuan Chuang 570e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "invalid fw checksum\n"); 571e3037485SYan-Hsuan Chuang 572e3037485SYan-Hsuan Chuang return false; 573e3037485SYan-Hsuan Chuang } 574e3037485SYan-Hsuan Chuang 575e3037485SYan-Hsuan Chuang if (addr < OCPBASE_DMEM_88XX) { 576e3037485SYan-Hsuan Chuang fw_ctrl |= (BIT_IMEM_DW_OK | BIT_IMEM_CHKSUM_OK); 577e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 578e3037485SYan-Hsuan Chuang } else { 579e3037485SYan-Hsuan Chuang fw_ctrl |= (BIT_DMEM_DW_OK | BIT_DMEM_CHKSUM_OK); 580e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 581e3037485SYan-Hsuan Chuang } 582e3037485SYan-Hsuan Chuang 583e3037485SYan-Hsuan Chuang return true; 584e3037485SYan-Hsuan Chuang } 585e3037485SYan-Hsuan Chuang 586e3037485SYan-Hsuan Chuang static int 587e3037485SYan-Hsuan Chuang download_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data, 588e3037485SYan-Hsuan Chuang u32 src, u32 dst, u32 size) 589e3037485SYan-Hsuan Chuang { 590e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 591e3037485SYan-Hsuan Chuang u32 desc_size = chip->tx_pkt_desc_sz; 592e3037485SYan-Hsuan Chuang u8 first_part; 593e3037485SYan-Hsuan Chuang u32 mem_offset; 594e3037485SYan-Hsuan Chuang u32 residue_size; 595e3037485SYan-Hsuan Chuang u32 pkt_size; 596e3037485SYan-Hsuan Chuang u32 max_size = 0x1000; 597e3037485SYan-Hsuan Chuang u32 val; 598e3037485SYan-Hsuan Chuang int ret; 599e3037485SYan-Hsuan Chuang 600e3037485SYan-Hsuan Chuang mem_offset = 0; 601e3037485SYan-Hsuan Chuang first_part = 1; 602e3037485SYan-Hsuan Chuang residue_size = size; 603e3037485SYan-Hsuan Chuang 604e3037485SYan-Hsuan Chuang val = rtw_read32(rtwdev, REG_DDMA_CH0CTRL); 605e3037485SYan-Hsuan Chuang val |= BIT_DDMACH0_RESET_CHKSUM_STS; 606e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_DDMA_CH0CTRL, val); 607e3037485SYan-Hsuan Chuang 608e3037485SYan-Hsuan Chuang while (residue_size) { 609e3037485SYan-Hsuan Chuang if (residue_size >= max_size) 610e3037485SYan-Hsuan Chuang pkt_size = max_size; 611e3037485SYan-Hsuan Chuang else 612e3037485SYan-Hsuan Chuang pkt_size = residue_size; 613e3037485SYan-Hsuan Chuang 614e3037485SYan-Hsuan Chuang ret = send_firmware_pkt(rtwdev, (u16)(src >> 7), 615e3037485SYan-Hsuan Chuang data + mem_offset, pkt_size); 616e3037485SYan-Hsuan Chuang if (ret) 617e3037485SYan-Hsuan Chuang return ret; 618e3037485SYan-Hsuan Chuang 619e3037485SYan-Hsuan Chuang ret = iddma_download_firmware(rtwdev, OCPBASE_TXBUF_88XX + 620e3037485SYan-Hsuan Chuang src + desc_size, 621e3037485SYan-Hsuan Chuang dst + mem_offset, pkt_size, 622e3037485SYan-Hsuan Chuang first_part); 623e3037485SYan-Hsuan Chuang if (ret) 624e3037485SYan-Hsuan Chuang return ret; 625e3037485SYan-Hsuan Chuang 626e3037485SYan-Hsuan Chuang first_part = 0; 627e3037485SYan-Hsuan Chuang mem_offset += pkt_size; 628e3037485SYan-Hsuan Chuang residue_size -= pkt_size; 629e3037485SYan-Hsuan Chuang } 630e3037485SYan-Hsuan Chuang 631e3037485SYan-Hsuan Chuang if (!check_fw_checksum(rtwdev, dst)) 632e3037485SYan-Hsuan Chuang return -EINVAL; 633e3037485SYan-Hsuan Chuang 634e3037485SYan-Hsuan Chuang return 0; 635e3037485SYan-Hsuan Chuang } 636e3037485SYan-Hsuan Chuang 637e3037485SYan-Hsuan Chuang static int 638e3037485SYan-Hsuan Chuang start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) 639e3037485SYan-Hsuan Chuang { 640cc20a713SPing-Ke Shih const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data; 641e3037485SYan-Hsuan Chuang const u8 *cur_fw; 642e3037485SYan-Hsuan Chuang u16 val; 643e3037485SYan-Hsuan Chuang u32 imem_size; 644e3037485SYan-Hsuan Chuang u32 dmem_size; 645e3037485SYan-Hsuan Chuang u32 emem_size; 646e3037485SYan-Hsuan Chuang u32 addr; 647e3037485SYan-Hsuan Chuang int ret; 648e3037485SYan-Hsuan Chuang 649cc20a713SPing-Ke Shih dmem_size = le32_to_cpu(fw_hdr->dmem_size); 650cc20a713SPing-Ke Shih imem_size = le32_to_cpu(fw_hdr->imem_size); 651cc20a713SPing-Ke Shih emem_size = (fw_hdr->mem_usage & BIT(4)) ? 652cc20a713SPing-Ke Shih le32_to_cpu(fw_hdr->emem_size) : 0; 653e3037485SYan-Hsuan Chuang dmem_size += FW_HDR_CHKSUM_SIZE; 654e3037485SYan-Hsuan Chuang imem_size += FW_HDR_CHKSUM_SIZE; 655e3037485SYan-Hsuan Chuang emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0; 656e3037485SYan-Hsuan Chuang 657e3037485SYan-Hsuan Chuang val = (u16)(rtw_read16(rtwdev, REG_MCUFW_CTRL) & 0x3800); 658e3037485SYan-Hsuan Chuang val |= BIT_MCUFWDL_EN; 659e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_MCUFW_CTRL, val); 660e3037485SYan-Hsuan Chuang 661e3037485SYan-Hsuan Chuang cur_fw = data + FW_HDR_SIZE; 662cc20a713SPing-Ke Shih addr = le32_to_cpu(fw_hdr->dmem_addr); 663e3037485SYan-Hsuan Chuang addr &= ~BIT(31); 664e3037485SYan-Hsuan Chuang ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, dmem_size); 665e3037485SYan-Hsuan Chuang if (ret) 666e3037485SYan-Hsuan Chuang return ret; 667e3037485SYan-Hsuan Chuang 668e3037485SYan-Hsuan Chuang cur_fw = data + FW_HDR_SIZE + dmem_size; 669cc20a713SPing-Ke Shih addr = le32_to_cpu(fw_hdr->imem_addr); 670e3037485SYan-Hsuan Chuang addr &= ~BIT(31); 671e3037485SYan-Hsuan Chuang ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, imem_size); 672e3037485SYan-Hsuan Chuang if (ret) 673e3037485SYan-Hsuan Chuang return ret; 674e3037485SYan-Hsuan Chuang 675e3037485SYan-Hsuan Chuang if (emem_size) { 676e3037485SYan-Hsuan Chuang cur_fw = data + FW_HDR_SIZE + dmem_size + imem_size; 677cc20a713SPing-Ke Shih addr = le32_to_cpu(fw_hdr->emem_addr); 678e3037485SYan-Hsuan Chuang addr &= ~BIT(31); 679e3037485SYan-Hsuan Chuang ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, 680e3037485SYan-Hsuan Chuang emem_size); 681e3037485SYan-Hsuan Chuang if (ret) 682e3037485SYan-Hsuan Chuang return ret; 683e3037485SYan-Hsuan Chuang } 684e3037485SYan-Hsuan Chuang 685e3037485SYan-Hsuan Chuang return 0; 686e3037485SYan-Hsuan Chuang } 687e3037485SYan-Hsuan Chuang 688e3037485SYan-Hsuan Chuang static int download_firmware_validate(struct rtw_dev *rtwdev) 689e3037485SYan-Hsuan Chuang { 690e3037485SYan-Hsuan Chuang u32 fw_key; 691e3037485SYan-Hsuan Chuang 692e3037485SYan-Hsuan Chuang if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, FW_READY_MASK, FW_READY)) { 693e3037485SYan-Hsuan Chuang fw_key = rtw_read32(rtwdev, REG_FW_DBG7) & FW_KEY_MASK; 694e3037485SYan-Hsuan Chuang if (fw_key == ILLEGAL_KEY_GROUP) 695e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "invalid fw key\n"); 696e3037485SYan-Hsuan Chuang return -EINVAL; 697e3037485SYan-Hsuan Chuang } 698e3037485SYan-Hsuan Chuang 699e3037485SYan-Hsuan Chuang return 0; 700e3037485SYan-Hsuan Chuang } 701e3037485SYan-Hsuan Chuang 702e3037485SYan-Hsuan Chuang static void download_firmware_end_flow(struct rtw_dev *rtwdev) 703e3037485SYan-Hsuan Chuang { 704e3037485SYan-Hsuan Chuang u16 fw_ctrl; 705e3037485SYan-Hsuan Chuang 706e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_TXDMA_STATUS, BTI_PAGE_OVF); 707e3037485SYan-Hsuan Chuang 708e3037485SYan-Hsuan Chuang /* Check IMEM & DMEM checksum is OK or not */ 709e3037485SYan-Hsuan Chuang fw_ctrl = rtw_read16(rtwdev, REG_MCUFW_CTRL); 710e3037485SYan-Hsuan Chuang if ((fw_ctrl & BIT_CHECK_SUM_OK) != BIT_CHECK_SUM_OK) 711e3037485SYan-Hsuan Chuang return; 712e3037485SYan-Hsuan Chuang 713e3037485SYan-Hsuan Chuang fw_ctrl = (fw_ctrl | BIT_FW_DW_RDY) & ~BIT_MCUFWDL_EN; 714e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 715e3037485SYan-Hsuan Chuang } 716e3037485SYan-Hsuan Chuang 7173d8bf508SYan-Hsuan Chuang static int __rtw_download_firmware(struct rtw_dev *rtwdev, 7183d8bf508SYan-Hsuan Chuang struct rtw_fw_state *fw) 719e3037485SYan-Hsuan Chuang { 720e3037485SYan-Hsuan Chuang struct rtw_backup_info bckp[DLFW_RESTORE_REG_NUM]; 721e3037485SYan-Hsuan Chuang const u8 *data = fw->firmware->data; 722e3037485SYan-Hsuan Chuang u32 size = fw->firmware->size; 723e3037485SYan-Hsuan Chuang u32 ltecoex_bckp; 724e3037485SYan-Hsuan Chuang int ret; 725e3037485SYan-Hsuan Chuang 726e3037485SYan-Hsuan Chuang if (!check_firmware_size(data, size)) 727e3037485SYan-Hsuan Chuang return -EINVAL; 728e3037485SYan-Hsuan Chuang 729e3037485SYan-Hsuan Chuang if (!ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp)) 730e3037485SYan-Hsuan Chuang return -EBUSY; 731e3037485SYan-Hsuan Chuang 732e3037485SYan-Hsuan Chuang wlan_cpu_enable(rtwdev, false); 733e3037485SYan-Hsuan Chuang 734e3037485SYan-Hsuan Chuang download_firmware_reg_backup(rtwdev, bckp); 735e3037485SYan-Hsuan Chuang download_firmware_reset_platform(rtwdev); 736e3037485SYan-Hsuan Chuang 737e3037485SYan-Hsuan Chuang ret = start_download_firmware(rtwdev, data, size); 738e3037485SYan-Hsuan Chuang if (ret) 739e3037485SYan-Hsuan Chuang goto dlfw_fail; 740e3037485SYan-Hsuan Chuang 741e3037485SYan-Hsuan Chuang download_firmware_reg_restore(rtwdev, bckp, DLFW_RESTORE_REG_NUM); 742e3037485SYan-Hsuan Chuang 743e3037485SYan-Hsuan Chuang download_firmware_end_flow(rtwdev); 744e3037485SYan-Hsuan Chuang 745e3037485SYan-Hsuan Chuang wlan_cpu_enable(rtwdev, true); 746e3037485SYan-Hsuan Chuang 747e3037485SYan-Hsuan Chuang if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) 748e3037485SYan-Hsuan Chuang return -EBUSY; 749e3037485SYan-Hsuan Chuang 750e3037485SYan-Hsuan Chuang ret = download_firmware_validate(rtwdev); 751e3037485SYan-Hsuan Chuang if (ret) 752e3037485SYan-Hsuan Chuang goto dlfw_fail; 753e3037485SYan-Hsuan Chuang 754e3037485SYan-Hsuan Chuang /* reset desc and index */ 755e3037485SYan-Hsuan Chuang rtw_hci_setup(rtwdev); 756e3037485SYan-Hsuan Chuang 757e3037485SYan-Hsuan Chuang rtwdev->h2c.last_box_num = 0; 758e3037485SYan-Hsuan Chuang rtwdev->h2c.seq = 0; 759e3037485SYan-Hsuan Chuang 7603c519605SYan-Hsuan Chuang set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); 761e3037485SYan-Hsuan Chuang 762e3037485SYan-Hsuan Chuang return 0; 763e3037485SYan-Hsuan Chuang 764e3037485SYan-Hsuan Chuang dlfw_fail: 765e3037485SYan-Hsuan Chuang /* Disable FWDL_EN */ 766e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 767e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 768e3037485SYan-Hsuan Chuang 769e3037485SYan-Hsuan Chuang return ret; 770e3037485SYan-Hsuan Chuang } 771e3037485SYan-Hsuan Chuang 77215d2fcc6SPing-Ke Shih static void en_download_firmware_legacy(struct rtw_dev *rtwdev, bool en) 77315d2fcc6SPing-Ke Shih { 77415d2fcc6SPing-Ke Shih int try; 77515d2fcc6SPing-Ke Shih 77615d2fcc6SPing-Ke Shih if (en) { 77715d2fcc6SPing-Ke Shih wlan_cpu_enable(rtwdev, false); 77815d2fcc6SPing-Ke Shih wlan_cpu_enable(rtwdev, true); 77915d2fcc6SPing-Ke Shih 78015d2fcc6SPing-Ke Shih rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 78115d2fcc6SPing-Ke Shih 78215d2fcc6SPing-Ke Shih for (try = 0; try < 10; try++) { 78315d2fcc6SPing-Ke Shih if (rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_MCUFWDL_EN) 78415d2fcc6SPing-Ke Shih goto fwdl_ready; 78515d2fcc6SPing-Ke Shih rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 78615d2fcc6SPing-Ke Shih msleep(20); 78715d2fcc6SPing-Ke Shih } 78815d2fcc6SPing-Ke Shih rtw_err(rtwdev, "failed to check fw download ready\n"); 78915d2fcc6SPing-Ke Shih fwdl_ready: 79015d2fcc6SPing-Ke Shih rtw_write32_clr(rtwdev, REG_MCUFW_CTRL, BIT_ROM_DLEN); 79115d2fcc6SPing-Ke Shih } else { 79215d2fcc6SPing-Ke Shih rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 79315d2fcc6SPing-Ke Shih } 79415d2fcc6SPing-Ke Shih } 79515d2fcc6SPing-Ke Shih 79615d2fcc6SPing-Ke Shih static void 79715d2fcc6SPing-Ke Shih write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size) 79815d2fcc6SPing-Ke Shih { 79915d2fcc6SPing-Ke Shih u32 val32; 80015d2fcc6SPing-Ke Shih u32 block_nr; 80115d2fcc6SPing-Ke Shih u32 remain_size; 80215d2fcc6SPing-Ke Shih u32 write_addr = FW_START_ADDR_LEGACY; 80315d2fcc6SPing-Ke Shih const __le32 *ptr = (const __le32 *)data; 80415d2fcc6SPing-Ke Shih u32 block; 80515d2fcc6SPing-Ke Shih __le32 remain_data = 0; 80615d2fcc6SPing-Ke Shih 80715d2fcc6SPing-Ke Shih block_nr = size >> DLFW_BLK_SIZE_SHIFT_LEGACY; 80815d2fcc6SPing-Ke Shih remain_size = size & (DLFW_BLK_SIZE_LEGACY - 1); 80915d2fcc6SPing-Ke Shih 81015d2fcc6SPing-Ke Shih val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL); 81115d2fcc6SPing-Ke Shih val32 &= ~BIT_ROM_PGE; 81215d2fcc6SPing-Ke Shih val32 |= (page << BIT_SHIFT_ROM_PGE) & BIT_ROM_PGE; 81315d2fcc6SPing-Ke Shih rtw_write32(rtwdev, REG_MCUFW_CTRL, val32); 81415d2fcc6SPing-Ke Shih 81515d2fcc6SPing-Ke Shih for (block = 0; block < block_nr; block++) { 81615d2fcc6SPing-Ke Shih rtw_write32(rtwdev, write_addr, le32_to_cpu(*ptr)); 81715d2fcc6SPing-Ke Shih 81815d2fcc6SPing-Ke Shih write_addr += DLFW_BLK_SIZE_LEGACY; 81915d2fcc6SPing-Ke Shih ptr++; 82015d2fcc6SPing-Ke Shih } 82115d2fcc6SPing-Ke Shih 82215d2fcc6SPing-Ke Shih if (remain_size) { 82315d2fcc6SPing-Ke Shih memcpy(&remain_data, ptr, remain_size); 82415d2fcc6SPing-Ke Shih rtw_write32(rtwdev, write_addr, le32_to_cpu(remain_data)); 82515d2fcc6SPing-Ke Shih } 82615d2fcc6SPing-Ke Shih } 82715d2fcc6SPing-Ke Shih 82815d2fcc6SPing-Ke Shih static int 82915d2fcc6SPing-Ke Shih download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size) 83015d2fcc6SPing-Ke Shih { 83115d2fcc6SPing-Ke Shih u32 page; 83215d2fcc6SPing-Ke Shih u32 total_page; 83315d2fcc6SPing-Ke Shih u32 last_page_size; 83415d2fcc6SPing-Ke Shih 83515d2fcc6SPing-Ke Shih data += sizeof(struct rtw_fw_hdr_legacy); 83615d2fcc6SPing-Ke Shih size -= sizeof(struct rtw_fw_hdr_legacy); 83715d2fcc6SPing-Ke Shih 83815d2fcc6SPing-Ke Shih total_page = size >> DLFW_PAGE_SIZE_SHIFT_LEGACY; 83915d2fcc6SPing-Ke Shih last_page_size = size & (DLFW_PAGE_SIZE_LEGACY - 1); 84015d2fcc6SPing-Ke Shih 84115d2fcc6SPing-Ke Shih rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT); 84215d2fcc6SPing-Ke Shih 84315d2fcc6SPing-Ke Shih for (page = 0; page < total_page; page++) { 84415d2fcc6SPing-Ke Shih write_firmware_page(rtwdev, page, data, DLFW_PAGE_SIZE_LEGACY); 84515d2fcc6SPing-Ke Shih data += DLFW_PAGE_SIZE_LEGACY; 84615d2fcc6SPing-Ke Shih } 84715d2fcc6SPing-Ke Shih if (last_page_size) 84815d2fcc6SPing-Ke Shih write_firmware_page(rtwdev, page, data, last_page_size); 84915d2fcc6SPing-Ke Shih 85015d2fcc6SPing-Ke Shih if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT, 1)) { 851a6336094SColin Ian King rtw_err(rtwdev, "failed to check download firmware report\n"); 85215d2fcc6SPing-Ke Shih return -EINVAL; 85315d2fcc6SPing-Ke Shih } 85415d2fcc6SPing-Ke Shih 85515d2fcc6SPing-Ke Shih return 0; 85615d2fcc6SPing-Ke Shih } 85715d2fcc6SPing-Ke Shih 85815d2fcc6SPing-Ke Shih static int download_firmware_validate_legacy(struct rtw_dev *rtwdev) 85915d2fcc6SPing-Ke Shih { 86015d2fcc6SPing-Ke Shih u32 val32; 86115d2fcc6SPing-Ke Shih int try; 86215d2fcc6SPing-Ke Shih 86315d2fcc6SPing-Ke Shih val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL); 86415d2fcc6SPing-Ke Shih val32 |= BIT_MCUFWDL_RDY; 86515d2fcc6SPing-Ke Shih val32 &= ~BIT_WINTINI_RDY; 86615d2fcc6SPing-Ke Shih rtw_write32(rtwdev, REG_MCUFW_CTRL, val32); 86715d2fcc6SPing-Ke Shih 86815d2fcc6SPing-Ke Shih wlan_cpu_enable(rtwdev, false); 86915d2fcc6SPing-Ke Shih wlan_cpu_enable(rtwdev, true); 87015d2fcc6SPing-Ke Shih 87115d2fcc6SPing-Ke Shih for (try = 0; try < 10; try++) { 87215d2fcc6SPing-Ke Shih val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL); 87315d2fcc6SPing-Ke Shih if ((val32 & FW_READY_LEGACY) == FW_READY_LEGACY) 87415d2fcc6SPing-Ke Shih return 0; 87515d2fcc6SPing-Ke Shih msleep(20); 87615d2fcc6SPing-Ke Shih } 87715d2fcc6SPing-Ke Shih 878a6336094SColin Ian King rtw_err(rtwdev, "failed to validate firmware\n"); 87915d2fcc6SPing-Ke Shih return -EINVAL; 88015d2fcc6SPing-Ke Shih } 88115d2fcc6SPing-Ke Shih 8823d8bf508SYan-Hsuan Chuang static int __rtw_download_firmware_legacy(struct rtw_dev *rtwdev, 8833d8bf508SYan-Hsuan Chuang struct rtw_fw_state *fw) 88415d2fcc6SPing-Ke Shih { 88515d2fcc6SPing-Ke Shih int ret = 0; 88615d2fcc6SPing-Ke Shih 88715d2fcc6SPing-Ke Shih en_download_firmware_legacy(rtwdev, true); 88815d2fcc6SPing-Ke Shih ret = download_firmware_legacy(rtwdev, fw->firmware->data, fw->firmware->size); 88915d2fcc6SPing-Ke Shih en_download_firmware_legacy(rtwdev, false); 89015d2fcc6SPing-Ke Shih if (ret) 89115d2fcc6SPing-Ke Shih goto out; 89215d2fcc6SPing-Ke Shih 89315d2fcc6SPing-Ke Shih ret = download_firmware_validate_legacy(rtwdev); 89415d2fcc6SPing-Ke Shih if (ret) 89515d2fcc6SPing-Ke Shih goto out; 89615d2fcc6SPing-Ke Shih 89715d2fcc6SPing-Ke Shih /* reset desc and index */ 89815d2fcc6SPing-Ke Shih rtw_hci_setup(rtwdev); 89915d2fcc6SPing-Ke Shih 90015d2fcc6SPing-Ke Shih rtwdev->h2c.last_box_num = 0; 90115d2fcc6SPing-Ke Shih rtwdev->h2c.seq = 0; 90215d2fcc6SPing-Ke Shih 90315d2fcc6SPing-Ke Shih set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); 90415d2fcc6SPing-Ke Shih 90515d2fcc6SPing-Ke Shih out: 90615d2fcc6SPing-Ke Shih return ret; 90715d2fcc6SPing-Ke Shih } 90815d2fcc6SPing-Ke Shih 90915d2fcc6SPing-Ke Shih int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) 91015d2fcc6SPing-Ke Shih { 91115d2fcc6SPing-Ke Shih if (rtw_chip_wcpu_11n(rtwdev)) 91215d2fcc6SPing-Ke Shih return __rtw_download_firmware_legacy(rtwdev, fw); 91315d2fcc6SPing-Ke Shih 91415d2fcc6SPing-Ke Shih return __rtw_download_firmware(rtwdev, fw); 91515d2fcc6SPing-Ke Shih } 91615d2fcc6SPing-Ke Shih 9171131ad7fSYan-Hsuan Chuang static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) 9181131ad7fSYan-Hsuan Chuang { 919d49f2c50SJoe Perches const struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn; 9201131ad7fSYan-Hsuan Chuang u32 prio_queues = 0; 9211131ad7fSYan-Hsuan Chuang 9221131ad7fSYan-Hsuan Chuang if (queues & BIT(IEEE80211_AC_VO)) 9231131ad7fSYan-Hsuan Chuang prio_queues |= BIT(rqpn->dma_map_vo); 9241131ad7fSYan-Hsuan Chuang if (queues & BIT(IEEE80211_AC_VI)) 9251131ad7fSYan-Hsuan Chuang prio_queues |= BIT(rqpn->dma_map_vi); 9261131ad7fSYan-Hsuan Chuang if (queues & BIT(IEEE80211_AC_BE)) 9271131ad7fSYan-Hsuan Chuang prio_queues |= BIT(rqpn->dma_map_be); 9281131ad7fSYan-Hsuan Chuang if (queues & BIT(IEEE80211_AC_BK)) 9291131ad7fSYan-Hsuan Chuang prio_queues |= BIT(rqpn->dma_map_bk); 9301131ad7fSYan-Hsuan Chuang 9311131ad7fSYan-Hsuan Chuang return prio_queues; 9321131ad7fSYan-Hsuan Chuang } 9331131ad7fSYan-Hsuan Chuang 9341131ad7fSYan-Hsuan Chuang static void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev, 9351131ad7fSYan-Hsuan Chuang u32 prio_queue, bool drop) 9361131ad7fSYan-Hsuan Chuang { 9377d754f97SPing-Ke Shih struct rtw_chip_info *chip = rtwdev->chip; 9387d754f97SPing-Ke Shih const struct rtw_prioq_addr *addr; 9397d754f97SPing-Ke Shih bool wsize; 9401131ad7fSYan-Hsuan Chuang u16 avail_page, rsvd_page; 9411131ad7fSYan-Hsuan Chuang int i; 9421131ad7fSYan-Hsuan Chuang 9437d754f97SPing-Ke Shih if (prio_queue >= RTW_DMA_MAPPING_MAX) 9441131ad7fSYan-Hsuan Chuang return; 9457d754f97SPing-Ke Shih 9467d754f97SPing-Ke Shih addr = &chip->prioq_addrs->prio[prio_queue]; 9477d754f97SPing-Ke Shih wsize = chip->prioq_addrs->wsize; 9481131ad7fSYan-Hsuan Chuang 9491131ad7fSYan-Hsuan Chuang /* check if all of the reserved pages are available for 100 msecs */ 9501131ad7fSYan-Hsuan Chuang for (i = 0; i < 5; i++) { 9517d754f97SPing-Ke Shih rsvd_page = wsize ? rtw_read16(rtwdev, addr->rsvd) : 9527d754f97SPing-Ke Shih rtw_read8(rtwdev, addr->rsvd); 9537d754f97SPing-Ke Shih avail_page = wsize ? rtw_read16(rtwdev, addr->avail) : 9547d754f97SPing-Ke Shih rtw_read8(rtwdev, addr->avail); 9551131ad7fSYan-Hsuan Chuang if (rsvd_page == avail_page) 9561131ad7fSYan-Hsuan Chuang return; 9571131ad7fSYan-Hsuan Chuang 9581131ad7fSYan-Hsuan Chuang msleep(20); 9591131ad7fSYan-Hsuan Chuang } 9601131ad7fSYan-Hsuan Chuang 9611131ad7fSYan-Hsuan Chuang /* priority queue is still not empty, throw a warning, 9621131ad7fSYan-Hsuan Chuang * 9631131ad7fSYan-Hsuan Chuang * Note that if we want to flush the tx queue when having a lot of 9641131ad7fSYan-Hsuan Chuang * traffic (ex, 100Mbps up), some of the packets could be dropped. 9651131ad7fSYan-Hsuan Chuang * And it requires like ~2secs to flush the full priority queue. 9661131ad7fSYan-Hsuan Chuang */ 9671131ad7fSYan-Hsuan Chuang if (!drop) 9681131ad7fSYan-Hsuan Chuang rtw_warn(rtwdev, "timed out to flush queue %d\n", prio_queue); 9691131ad7fSYan-Hsuan Chuang } 9701131ad7fSYan-Hsuan Chuang 9711131ad7fSYan-Hsuan Chuang static void rtw_mac_flush_prio_queues(struct rtw_dev *rtwdev, 9721131ad7fSYan-Hsuan Chuang u32 prio_queues, bool drop) 9731131ad7fSYan-Hsuan Chuang { 9741131ad7fSYan-Hsuan Chuang u32 q; 9751131ad7fSYan-Hsuan Chuang 9761131ad7fSYan-Hsuan Chuang for (q = 0; q < RTW_DMA_MAPPING_MAX; q++) 9771131ad7fSYan-Hsuan Chuang if (prio_queues & BIT(q)) 9781131ad7fSYan-Hsuan Chuang __rtw_mac_flush_prio_queue(rtwdev, q, drop); 9791131ad7fSYan-Hsuan Chuang } 9801131ad7fSYan-Hsuan Chuang 9811131ad7fSYan-Hsuan Chuang void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop) 9821131ad7fSYan-Hsuan Chuang { 9831131ad7fSYan-Hsuan Chuang u32 prio_queues = 0; 9841131ad7fSYan-Hsuan Chuang 9851131ad7fSYan-Hsuan Chuang /* If all of the hardware queues are requested to flush, 9861131ad7fSYan-Hsuan Chuang * or the priority queues are not mapped yet, 9871131ad7fSYan-Hsuan Chuang * flush all of the priority queues 9881131ad7fSYan-Hsuan Chuang */ 9891131ad7fSYan-Hsuan Chuang if (queues == BIT(rtwdev->hw->queues) - 1 || !rtwdev->fifo.rqpn) 9901131ad7fSYan-Hsuan Chuang prio_queues = BIT(RTW_DMA_MAPPING_MAX) - 1; 9911131ad7fSYan-Hsuan Chuang else 9921131ad7fSYan-Hsuan Chuang prio_queues = get_priority_queues(rtwdev, queues); 9931131ad7fSYan-Hsuan Chuang 9941131ad7fSYan-Hsuan Chuang rtw_mac_flush_prio_queues(rtwdev, prio_queues, drop); 9951131ad7fSYan-Hsuan Chuang } 9961131ad7fSYan-Hsuan Chuang 997e3037485SYan-Hsuan Chuang static int txdma_queue_mapping(struct rtw_dev *rtwdev) 998e3037485SYan-Hsuan Chuang { 999e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 1000d49f2c50SJoe Perches const struct rtw_rqpn *rqpn = NULL; 1001e3037485SYan-Hsuan Chuang u16 txdma_pq_map = 0; 1002e3037485SYan-Hsuan Chuang 1003e3037485SYan-Hsuan Chuang switch (rtw_hci_type(rtwdev)) { 1004e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_PCIE: 1005e3037485SYan-Hsuan Chuang rqpn = &chip->rqpn_table[1]; 1006e3037485SYan-Hsuan Chuang break; 1007e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_USB: 1008e3037485SYan-Hsuan Chuang if (rtwdev->hci.bulkout_num == 2) 1009e3037485SYan-Hsuan Chuang rqpn = &chip->rqpn_table[2]; 1010e3037485SYan-Hsuan Chuang else if (rtwdev->hci.bulkout_num == 3) 1011e3037485SYan-Hsuan Chuang rqpn = &chip->rqpn_table[3]; 1012e3037485SYan-Hsuan Chuang else if (rtwdev->hci.bulkout_num == 4) 1013e3037485SYan-Hsuan Chuang rqpn = &chip->rqpn_table[4]; 1014e3037485SYan-Hsuan Chuang else 1015e3037485SYan-Hsuan Chuang return -EINVAL; 1016e3037485SYan-Hsuan Chuang break; 1017e3037485SYan-Hsuan Chuang default: 1018e3037485SYan-Hsuan Chuang return -EINVAL; 1019e3037485SYan-Hsuan Chuang } 1020e3037485SYan-Hsuan Chuang 10211131ad7fSYan-Hsuan Chuang rtwdev->fifo.rqpn = rqpn; 1022e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi); 1023e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg); 1024e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk); 1025e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be); 1026e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi); 1027e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo); 1028e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map); 1029e3037485SYan-Hsuan Chuang 1030e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR, 0); 1031e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR, MAC_TRX_ENABLE); 10327907b52dSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev)) 1033e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); 1034e3037485SYan-Hsuan Chuang 1035e3037485SYan-Hsuan Chuang return 0; 1036e3037485SYan-Hsuan Chuang } 1037e3037485SYan-Hsuan Chuang 1038e3037485SYan-Hsuan Chuang static int set_trx_fifo_info(struct rtw_dev *rtwdev) 1039e3037485SYan-Hsuan Chuang { 1040e3037485SYan-Hsuan Chuang struct rtw_fifo_conf *fifo = &rtwdev->fifo; 1041e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 1042e3037485SYan-Hsuan Chuang u16 cur_pg_addr; 1043e3037485SYan-Hsuan Chuang u8 csi_buf_pg_num = chip->csi_buf_pg_num; 1044e3037485SYan-Hsuan Chuang 1045e3037485SYan-Hsuan Chuang /* config rsvd page num */ 1046e3037485SYan-Hsuan Chuang fifo->rsvd_drv_pg_num = 8; 1047e3037485SYan-Hsuan Chuang fifo->txff_pg_num = chip->txff_size >> 7; 1048d91277deSPing-Ke Shih if (rtw_chip_wcpu_11n(rtwdev)) 1049d91277deSPing-Ke Shih fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num; 1050d91277deSPing-Ke Shih else 1051e3037485SYan-Hsuan Chuang fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num + 1052e3037485SYan-Hsuan Chuang RSVD_PG_H2C_EXTRAINFO_NUM + 1053e3037485SYan-Hsuan Chuang RSVD_PG_H2C_STATICINFO_NUM + 1054e3037485SYan-Hsuan Chuang RSVD_PG_H2CQ_NUM + 1055e3037485SYan-Hsuan Chuang RSVD_PG_CPU_INSTRUCTION_NUM + 1056e3037485SYan-Hsuan Chuang RSVD_PG_FW_TXBUF_NUM + 1057e3037485SYan-Hsuan Chuang csi_buf_pg_num; 1058e3037485SYan-Hsuan Chuang 1059e3037485SYan-Hsuan Chuang if (fifo->rsvd_pg_num > fifo->txff_pg_num) 1060e3037485SYan-Hsuan Chuang return -ENOMEM; 1061e3037485SYan-Hsuan Chuang 1062e3037485SYan-Hsuan Chuang fifo->acq_pg_num = fifo->txff_pg_num - fifo->rsvd_pg_num; 1063e3037485SYan-Hsuan Chuang fifo->rsvd_boundary = fifo->txff_pg_num - fifo->rsvd_pg_num; 1064e3037485SYan-Hsuan Chuang 1065e3037485SYan-Hsuan Chuang cur_pg_addr = fifo->txff_pg_num; 1066d91277deSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev)) { 1067e3037485SYan-Hsuan Chuang cur_pg_addr -= csi_buf_pg_num; 1068e3037485SYan-Hsuan Chuang fifo->rsvd_csibuf_addr = cur_pg_addr; 1069e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_FW_TXBUF_NUM; 1070e3037485SYan-Hsuan Chuang fifo->rsvd_fw_txbuf_addr = cur_pg_addr; 1071e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_CPU_INSTRUCTION_NUM; 1072e3037485SYan-Hsuan Chuang fifo->rsvd_cpu_instr_addr = cur_pg_addr; 1073e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_H2CQ_NUM; 1074e3037485SYan-Hsuan Chuang fifo->rsvd_h2cq_addr = cur_pg_addr; 1075e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_H2C_STATICINFO_NUM; 1076e3037485SYan-Hsuan Chuang fifo->rsvd_h2c_sta_info_addr = cur_pg_addr; 1077e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_H2C_EXTRAINFO_NUM; 1078e3037485SYan-Hsuan Chuang fifo->rsvd_h2c_info_addr = cur_pg_addr; 1079d91277deSPing-Ke Shih } 1080e3037485SYan-Hsuan Chuang cur_pg_addr -= fifo->rsvd_drv_pg_num; 1081e3037485SYan-Hsuan Chuang fifo->rsvd_drv_addr = cur_pg_addr; 1082e3037485SYan-Hsuan Chuang 1083e3037485SYan-Hsuan Chuang if (fifo->rsvd_boundary != fifo->rsvd_drv_addr) { 1084e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "wrong rsvd driver address\n"); 1085e3037485SYan-Hsuan Chuang return -EINVAL; 1086e3037485SYan-Hsuan Chuang } 1087e3037485SYan-Hsuan Chuang 1088e3037485SYan-Hsuan Chuang return 0; 1089e3037485SYan-Hsuan Chuang } 1090e3037485SYan-Hsuan Chuang 1091d91277deSPing-Ke Shih static int __priority_queue_cfg(struct rtw_dev *rtwdev, 1092d91277deSPing-Ke Shih const struct rtw_page_table *pg_tbl, 1093d91277deSPing-Ke Shih u16 pubq_num) 1094d91277deSPing-Ke Shih { 1095d91277deSPing-Ke Shih struct rtw_fifo_conf *fifo = &rtwdev->fifo; 1096d91277deSPing-Ke Shih struct rtw_chip_info *chip = rtwdev->chip; 1097d91277deSPing-Ke Shih 1098d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, pg_tbl->hq_num); 1099d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_FIFOPAGE_INFO_2, pg_tbl->lq_num); 1100d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_FIFOPAGE_INFO_3, pg_tbl->nq_num); 1101d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_FIFOPAGE_INFO_4, pg_tbl->exq_num); 1102d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_FIFOPAGE_INFO_5, pubq_num); 1103d91277deSPing-Ke Shih rtw_write32_set(rtwdev, REG_RQPN_CTRL_2, BIT_LD_RQPN); 1104d91277deSPing-Ke Shih 1105d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2, fifo->rsvd_boundary); 1106d91277deSPing-Ke Shih rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL + 2, BIT_EN_WR_FREE_TAIL >> 16); 1107d91277deSPing-Ke Shih 1108d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_BCNQ_BDNY_V1, fifo->rsvd_boundary); 1109d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2 + 2, fifo->rsvd_boundary); 1110d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_BCNQ1_BDNY_V1, fifo->rsvd_boundary); 1111d91277deSPing-Ke Shih rtw_write32(rtwdev, REG_RXFF_BNDY, chip->rxff_size - C2H_PKT_BUF - 1); 1112d91277deSPing-Ke Shih rtw_write8_set(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1); 1113d91277deSPing-Ke Shih 1114d91277deSPing-Ke Shih if (!check_hw_ready(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1, 0)) 1115d91277deSPing-Ke Shih return -EBUSY; 1116d91277deSPing-Ke Shih 1117d91277deSPing-Ke Shih rtw_write8(rtwdev, REG_CR + 3, 0); 1118d91277deSPing-Ke Shih 1119d91277deSPing-Ke Shih return 0; 1120d91277deSPing-Ke Shih } 1121d91277deSPing-Ke Shih 1122d91277deSPing-Ke Shih static int __priority_queue_cfg_legacy(struct rtw_dev *rtwdev, 1123d91277deSPing-Ke Shih const struct rtw_page_table *pg_tbl, 1124d91277deSPing-Ke Shih u16 pubq_num) 1125d91277deSPing-Ke Shih { 1126d91277deSPing-Ke Shih struct rtw_fifo_conf *fifo = &rtwdev->fifo; 1127d91277deSPing-Ke Shih struct rtw_chip_info *chip = rtwdev->chip; 1128d91277deSPing-Ke Shih u32 val32; 1129d91277deSPing-Ke Shih 1130d91277deSPing-Ke Shih val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num); 1131d91277deSPing-Ke Shih rtw_write32(rtwdev, REG_RQPN_NPQ, val32); 1132d91277deSPing-Ke Shih val32 = BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num); 1133d91277deSPing-Ke Shih rtw_write32(rtwdev, REG_RQPN, val32); 1134d91277deSPing-Ke Shih 1135d91277deSPing-Ke Shih rtw_write8(rtwdev, REG_TRXFF_BNDY, fifo->rsvd_boundary); 1136d91277deSPing-Ke Shih rtw_write16(rtwdev, REG_TRXFF_BNDY + 2, chip->rxff_size - REPORT_BUF - 1); 1137d91277deSPing-Ke Shih rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1, fifo->rsvd_boundary); 1138d91277deSPing-Ke Shih rtw_write8(rtwdev, REG_BCNQ_BDNY, fifo->rsvd_boundary); 1139d91277deSPing-Ke Shih rtw_write8(rtwdev, REG_MGQ_BDNY, fifo->rsvd_boundary); 1140d91277deSPing-Ke Shih rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, fifo->rsvd_boundary); 1141d91277deSPing-Ke Shih 1142d91277deSPing-Ke Shih rtw_write32_set(rtwdev, REG_AUTO_LLT, BIT_AUTO_INIT_LLT); 1143d91277deSPing-Ke Shih 1144d91277deSPing-Ke Shih if (!check_hw_ready(rtwdev, REG_AUTO_LLT, BIT_AUTO_INIT_LLT, 0)) 1145d91277deSPing-Ke Shih return -EBUSY; 1146d91277deSPing-Ke Shih 1147d91277deSPing-Ke Shih return 0; 1148d91277deSPing-Ke Shih } 1149d91277deSPing-Ke Shih 1150e3037485SYan-Hsuan Chuang static int priority_queue_cfg(struct rtw_dev *rtwdev) 1151e3037485SYan-Hsuan Chuang { 1152e3037485SYan-Hsuan Chuang struct rtw_fifo_conf *fifo = &rtwdev->fifo; 1153e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 1154d49f2c50SJoe Perches const struct rtw_page_table *pg_tbl = NULL; 1155e3037485SYan-Hsuan Chuang u16 pubq_num; 1156e3037485SYan-Hsuan Chuang int ret; 1157e3037485SYan-Hsuan Chuang 1158e3037485SYan-Hsuan Chuang ret = set_trx_fifo_info(rtwdev); 1159e3037485SYan-Hsuan Chuang if (ret) 1160e3037485SYan-Hsuan Chuang return ret; 1161e3037485SYan-Hsuan Chuang 1162e3037485SYan-Hsuan Chuang switch (rtw_hci_type(rtwdev)) { 1163e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_PCIE: 1164e3037485SYan-Hsuan Chuang pg_tbl = &chip->page_table[1]; 1165e3037485SYan-Hsuan Chuang break; 1166e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_USB: 1167e3037485SYan-Hsuan Chuang if (rtwdev->hci.bulkout_num == 2) 1168e3037485SYan-Hsuan Chuang pg_tbl = &chip->page_table[2]; 1169e3037485SYan-Hsuan Chuang else if (rtwdev->hci.bulkout_num == 3) 1170e3037485SYan-Hsuan Chuang pg_tbl = &chip->page_table[3]; 1171e3037485SYan-Hsuan Chuang else if (rtwdev->hci.bulkout_num == 4) 1172e3037485SYan-Hsuan Chuang pg_tbl = &chip->page_table[4]; 1173e3037485SYan-Hsuan Chuang else 1174e3037485SYan-Hsuan Chuang return -EINVAL; 1175e3037485SYan-Hsuan Chuang break; 1176e3037485SYan-Hsuan Chuang default: 1177e3037485SYan-Hsuan Chuang return -EINVAL; 1178e3037485SYan-Hsuan Chuang } 1179e3037485SYan-Hsuan Chuang 1180e3037485SYan-Hsuan Chuang pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - 1181e3037485SYan-Hsuan Chuang pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; 1182d91277deSPing-Ke Shih if (rtw_chip_wcpu_11n(rtwdev)) 1183d91277deSPing-Ke Shih return __priority_queue_cfg_legacy(rtwdev, pg_tbl, pubq_num); 1184d91277deSPing-Ke Shih else 1185d91277deSPing-Ke Shih return __priority_queue_cfg(rtwdev, pg_tbl, pubq_num); 1186e3037485SYan-Hsuan Chuang } 1187e3037485SYan-Hsuan Chuang 1188e3037485SYan-Hsuan Chuang static int init_h2c(struct rtw_dev *rtwdev) 1189e3037485SYan-Hsuan Chuang { 1190e3037485SYan-Hsuan Chuang struct rtw_fifo_conf *fifo = &rtwdev->fifo; 1191e3037485SYan-Hsuan Chuang u8 value8; 1192e3037485SYan-Hsuan Chuang u32 value32; 1193e3037485SYan-Hsuan Chuang u32 h2cq_addr; 1194e3037485SYan-Hsuan Chuang u32 h2cq_size; 1195e3037485SYan-Hsuan Chuang u32 h2cq_free; 1196e3037485SYan-Hsuan Chuang u32 wp, rp; 1197e3037485SYan-Hsuan Chuang 11987907b52dSPing-Ke Shih if (rtw_chip_wcpu_11n(rtwdev)) 11997907b52dSPing-Ke Shih return 0; 12007907b52dSPing-Ke Shih 1201e3037485SYan-Hsuan Chuang h2cq_addr = fifo->rsvd_h2cq_addr << TX_PAGE_SIZE_SHIFT; 1202e3037485SYan-Hsuan Chuang h2cq_size = RSVD_PG_H2CQ_NUM << TX_PAGE_SIZE_SHIFT; 1203e3037485SYan-Hsuan Chuang 1204e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_H2C_HEAD); 1205e3037485SYan-Hsuan Chuang value32 = (value32 & 0xFFFC0000) | h2cq_addr; 1206e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2C_HEAD, value32); 1207e3037485SYan-Hsuan Chuang 1208e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_H2C_READ_ADDR); 1209e3037485SYan-Hsuan Chuang value32 = (value32 & 0xFFFC0000) | h2cq_addr; 1210e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2C_READ_ADDR, value32); 1211e3037485SYan-Hsuan Chuang 1212e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_H2C_TAIL); 1213e3037485SYan-Hsuan Chuang value32 &= 0xFFFC0000; 1214e3037485SYan-Hsuan Chuang value32 |= (h2cq_addr + h2cq_size); 1215e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2C_TAIL, value32); 1216e3037485SYan-Hsuan Chuang 1217e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_H2C_INFO); 1218e3037485SYan-Hsuan Chuang value8 = (u8)((value8 & 0xFC) | 0x01); 1219e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_H2C_INFO, value8); 1220e3037485SYan-Hsuan Chuang 1221e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_H2C_INFO); 1222e3037485SYan-Hsuan Chuang value8 = (u8)((value8 & 0xFB) | 0x04); 1223e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_H2C_INFO, value8); 1224e3037485SYan-Hsuan Chuang 1225e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_TXDMA_OFFSET_CHK + 1); 1226e3037485SYan-Hsuan Chuang value8 = (u8)((value8 & 0x7f) | 0x80); 1227e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_TXDMA_OFFSET_CHK + 1, value8); 1228e3037485SYan-Hsuan Chuang 1229e3037485SYan-Hsuan Chuang wp = rtw_read32(rtwdev, REG_H2C_PKT_WRITEADDR) & 0x3FFFF; 1230e3037485SYan-Hsuan Chuang rp = rtw_read32(rtwdev, REG_H2C_PKT_READADDR) & 0x3FFFF; 1231e3037485SYan-Hsuan Chuang h2cq_free = wp >= rp ? h2cq_size - (wp - rp) : rp - wp; 1232e3037485SYan-Hsuan Chuang 1233e3037485SYan-Hsuan Chuang if (h2cq_size != h2cq_free) { 1234e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "H2C queue mismatch\n"); 1235e3037485SYan-Hsuan Chuang return -EINVAL; 1236e3037485SYan-Hsuan Chuang } 1237e3037485SYan-Hsuan Chuang 1238e3037485SYan-Hsuan Chuang return 0; 1239e3037485SYan-Hsuan Chuang } 1240e3037485SYan-Hsuan Chuang 1241e3037485SYan-Hsuan Chuang static int rtw_init_trx_cfg(struct rtw_dev *rtwdev) 1242e3037485SYan-Hsuan Chuang { 1243e3037485SYan-Hsuan Chuang int ret; 1244e3037485SYan-Hsuan Chuang 1245e3037485SYan-Hsuan Chuang ret = txdma_queue_mapping(rtwdev); 1246e3037485SYan-Hsuan Chuang if (ret) 1247e3037485SYan-Hsuan Chuang return ret; 1248e3037485SYan-Hsuan Chuang 1249e3037485SYan-Hsuan Chuang ret = priority_queue_cfg(rtwdev); 1250e3037485SYan-Hsuan Chuang if (ret) 1251e3037485SYan-Hsuan Chuang return ret; 1252e3037485SYan-Hsuan Chuang 1253e3037485SYan-Hsuan Chuang ret = init_h2c(rtwdev); 1254e3037485SYan-Hsuan Chuang if (ret) 1255e3037485SYan-Hsuan Chuang return ret; 1256e3037485SYan-Hsuan Chuang 1257e3037485SYan-Hsuan Chuang return 0; 1258e3037485SYan-Hsuan Chuang } 1259e3037485SYan-Hsuan Chuang 1260e3037485SYan-Hsuan Chuang static int rtw_drv_info_cfg(struct rtw_dev *rtwdev) 1261e3037485SYan-Hsuan Chuang { 1262e3037485SYan-Hsuan Chuang u8 value8; 1263e3037485SYan-Hsuan Chuang 1264e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE); 1265d91277deSPing-Ke Shih if (rtw_chip_wcpu_11ac(rtwdev)) { 1266e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_TRXFF_BNDY + 1); 1267e3037485SYan-Hsuan Chuang value8 &= 0xF0; 1268e3037485SYan-Hsuan Chuang /* For rxdesc len = 0 issue */ 1269e3037485SYan-Hsuan Chuang value8 |= 0xF; 1270e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_TRXFF_BNDY + 1, value8); 1271d91277deSPing-Ke Shih } 1272e3037485SYan-Hsuan Chuang rtw_write32_set(rtwdev, REG_RCR, BIT_APP_PHYSTS); 1273e3037485SYan-Hsuan Chuang rtw_write32_clr(rtwdev, REG_WMAC_OPTION_FUNCTION + 4, BIT(8) | BIT(9)); 1274e3037485SYan-Hsuan Chuang 1275e3037485SYan-Hsuan Chuang return 0; 1276e3037485SYan-Hsuan Chuang } 1277e3037485SYan-Hsuan Chuang 1278e3037485SYan-Hsuan Chuang int rtw_mac_init(struct rtw_dev *rtwdev) 1279e3037485SYan-Hsuan Chuang { 1280e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 1281e3037485SYan-Hsuan Chuang int ret; 1282e3037485SYan-Hsuan Chuang 1283e3037485SYan-Hsuan Chuang ret = rtw_init_trx_cfg(rtwdev); 1284e3037485SYan-Hsuan Chuang if (ret) 1285e3037485SYan-Hsuan Chuang return ret; 1286e3037485SYan-Hsuan Chuang 1287e3037485SYan-Hsuan Chuang ret = chip->ops->mac_init(rtwdev); 1288e3037485SYan-Hsuan Chuang if (ret) 1289e3037485SYan-Hsuan Chuang return ret; 1290e3037485SYan-Hsuan Chuang 1291e3037485SYan-Hsuan Chuang ret = rtw_drv_info_cfg(rtwdev); 1292e3037485SYan-Hsuan Chuang if (ret) 1293e3037485SYan-Hsuan Chuang return ret; 1294e3037485SYan-Hsuan Chuang 129578622104SYan-Hsuan Chuang rtw_hci_interface_cfg(rtwdev); 129678622104SYan-Hsuan Chuang 1297e3037485SYan-Hsuan Chuang return 0; 1298e3037485SYan-Hsuan Chuang } 1299