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; 19e3037485SYan-Hsuan Chuang if (txsc20 == 1 || txsc20 == 3) 20e3037485SYan-Hsuan Chuang txsc40 = 9; 21e3037485SYan-Hsuan Chuang else 22e3037485SYan-Hsuan Chuang txsc40 = 10; 23e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_DATA_SC, 24e3037485SYan-Hsuan Chuang BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40)); 25e3037485SYan-Hsuan Chuang 26e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_WMAC_TRXPTCL_CTL); 27e3037485SYan-Hsuan Chuang value32 &= ~BIT_RFMOD; 28e3037485SYan-Hsuan Chuang switch (bw) { 29e3037485SYan-Hsuan Chuang case RTW_CHANNEL_WIDTH_80: 30e3037485SYan-Hsuan Chuang value32 |= BIT_RFMOD_80M; 31e3037485SYan-Hsuan Chuang break; 32e3037485SYan-Hsuan Chuang case RTW_CHANNEL_WIDTH_40: 33e3037485SYan-Hsuan Chuang value32 |= BIT_RFMOD_40M; 34e3037485SYan-Hsuan Chuang break; 35e3037485SYan-Hsuan Chuang case RTW_CHANNEL_WIDTH_20: 36e3037485SYan-Hsuan Chuang default: 37e3037485SYan-Hsuan Chuang break; 38e3037485SYan-Hsuan Chuang } 39e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_WMAC_TRXPTCL_CTL, value32); 40e3037485SYan-Hsuan Chuang 41e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_AFE_CTRL1) & ~(BIT_MAC_CLK_SEL); 42e3037485SYan-Hsuan Chuang value32 |= (MAC_CLK_HW_DEF_80M << BIT_SHIFT_MAC_CLK_SEL); 43e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_AFE_CTRL1, value32); 44e3037485SYan-Hsuan Chuang 45e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_USTIME_TSF, MAC_CLK_SPEED); 46e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_USTIME_EDCA, MAC_CLK_SPEED); 47e3037485SYan-Hsuan Chuang 48e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_CCK_CHECK); 49e3037485SYan-Hsuan Chuang value8 = value8 & ~BIT_CHECK_CCK_EN; 50e3037485SYan-Hsuan Chuang if (channel > 35) 51e3037485SYan-Hsuan Chuang value8 |= BIT_CHECK_CCK_EN; 52e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CCK_CHECK, value8); 53e3037485SYan-Hsuan Chuang } 54e3037485SYan-Hsuan Chuang 55e3037485SYan-Hsuan Chuang static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev) 56e3037485SYan-Hsuan Chuang { 57e3037485SYan-Hsuan Chuang u32 value32; 58e3037485SYan-Hsuan Chuang u8 value8; 59e3037485SYan-Hsuan Chuang 60e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_RSV_CTRL, 0); 61e3037485SYan-Hsuan Chuang 62e3037485SYan-Hsuan Chuang switch (rtw_hci_type(rtwdev)) { 63e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_PCIE: 64e3037485SYan-Hsuan Chuang rtw_write32_set(rtwdev, REG_HCI_OPT_CTRL, BIT_BT_DIG_CLK_EN); 65e3037485SYan-Hsuan Chuang break; 66e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_USB: 67e3037485SYan-Hsuan Chuang break; 68e3037485SYan-Hsuan Chuang default: 69e3037485SYan-Hsuan Chuang return -EINVAL; 70e3037485SYan-Hsuan Chuang } 71e3037485SYan-Hsuan Chuang 72e3037485SYan-Hsuan Chuang /* config PIN Mux */ 73e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_PAD_CTRL1); 74e3037485SYan-Hsuan Chuang value32 |= BIT_PAPE_WLBT_SEL | BIT_LNAON_WLBT_SEL; 75e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_PAD_CTRL1, value32); 76e3037485SYan-Hsuan Chuang 77e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_LED_CFG); 78e3037485SYan-Hsuan Chuang value32 &= ~(BIT_PAPE_SEL_EN | BIT_LNAON_SEL_EN); 79e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_LED_CFG, value32); 80e3037485SYan-Hsuan Chuang 81e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_GPIO_MUXCFG); 82e3037485SYan-Hsuan Chuang value32 |= BIT_WLRFE_4_5_EN; 83e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_GPIO_MUXCFG, value32); 84e3037485SYan-Hsuan Chuang 85e3037485SYan-Hsuan Chuang /* disable BB/RF */ 86e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN); 87e3037485SYan-Hsuan Chuang value8 &= ~(BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST); 88e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_SYS_FUNC_EN, value8); 89e3037485SYan-Hsuan Chuang 90e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_RF_CTRL); 91e3037485SYan-Hsuan Chuang value8 &= ~(BIT_RF_SDM_RSTB | BIT_RF_RSTB | BIT_RF_EN); 92e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_RF_CTRL, value8); 93e3037485SYan-Hsuan Chuang 94e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_WLRF1); 95e3037485SYan-Hsuan Chuang value32 &= ~BIT_WLRF1_BBRF_EN; 96e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_WLRF1, value32); 97e3037485SYan-Hsuan Chuang 98e3037485SYan-Hsuan Chuang return 0; 99e3037485SYan-Hsuan Chuang } 100e3037485SYan-Hsuan Chuang 101e3037485SYan-Hsuan Chuang static int rtw_pwr_cmd_polling(struct rtw_dev *rtwdev, 102e3037485SYan-Hsuan Chuang struct rtw_pwr_seq_cmd *cmd) 103e3037485SYan-Hsuan Chuang { 104e3037485SYan-Hsuan Chuang u8 value; 105e3037485SYan-Hsuan Chuang u8 flag = 0; 106e3037485SYan-Hsuan Chuang u32 offset; 107e3037485SYan-Hsuan Chuang u32 cnt = RTW_PWR_POLLING_CNT; 108e3037485SYan-Hsuan Chuang 109e3037485SYan-Hsuan Chuang if (cmd->base == RTW_PWR_ADDR_SDIO) 110e3037485SYan-Hsuan Chuang offset = cmd->offset | SDIO_LOCAL_OFFSET; 111e3037485SYan-Hsuan Chuang else 112e3037485SYan-Hsuan Chuang offset = cmd->offset; 113e3037485SYan-Hsuan Chuang 114e3037485SYan-Hsuan Chuang do { 115e3037485SYan-Hsuan Chuang cnt--; 116e3037485SYan-Hsuan Chuang value = rtw_read8(rtwdev, offset); 117e3037485SYan-Hsuan Chuang value &= cmd->mask; 118e3037485SYan-Hsuan Chuang if (value == (cmd->value & cmd->mask)) 119e3037485SYan-Hsuan Chuang return 0; 120e3037485SYan-Hsuan Chuang if (cnt == 0) { 121e3037485SYan-Hsuan Chuang if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE && 122e3037485SYan-Hsuan Chuang flag == 0) { 123e3037485SYan-Hsuan Chuang value = rtw_read8(rtwdev, REG_SYS_PW_CTRL); 124e3037485SYan-Hsuan Chuang value |= BIT(3); 125e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_SYS_PW_CTRL, value); 126e3037485SYan-Hsuan Chuang value &= ~BIT(3); 127e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_SYS_PW_CTRL, value); 128e3037485SYan-Hsuan Chuang cnt = RTW_PWR_POLLING_CNT; 129e3037485SYan-Hsuan Chuang flag = 1; 130e3037485SYan-Hsuan Chuang } else { 131e3037485SYan-Hsuan Chuang return -EBUSY; 132e3037485SYan-Hsuan Chuang } 133e3037485SYan-Hsuan Chuang } else { 134e3037485SYan-Hsuan Chuang udelay(50); 135e3037485SYan-Hsuan Chuang } 136e3037485SYan-Hsuan Chuang } while (1); 137e3037485SYan-Hsuan Chuang } 138e3037485SYan-Hsuan Chuang 139e3037485SYan-Hsuan Chuang static int rtw_sub_pwr_seq_parser(struct rtw_dev *rtwdev, u8 intf_mask, 140e3037485SYan-Hsuan Chuang u8 cut_mask, struct rtw_pwr_seq_cmd *cmd) 141e3037485SYan-Hsuan Chuang { 142e3037485SYan-Hsuan Chuang struct rtw_pwr_seq_cmd *cur_cmd; 143e3037485SYan-Hsuan Chuang u32 offset; 144e3037485SYan-Hsuan Chuang u8 value; 145e3037485SYan-Hsuan Chuang 146e3037485SYan-Hsuan Chuang for (cur_cmd = cmd; cur_cmd->cmd != RTW_PWR_CMD_END; cur_cmd++) { 147e3037485SYan-Hsuan Chuang if (!(cur_cmd->intf_mask & intf_mask) || 148e3037485SYan-Hsuan Chuang !(cur_cmd->cut_mask & cut_mask)) 149e3037485SYan-Hsuan Chuang continue; 150e3037485SYan-Hsuan Chuang 151e3037485SYan-Hsuan Chuang switch (cur_cmd->cmd) { 152e3037485SYan-Hsuan Chuang case RTW_PWR_CMD_WRITE: 153e3037485SYan-Hsuan Chuang offset = cur_cmd->offset; 154e3037485SYan-Hsuan Chuang 155e3037485SYan-Hsuan Chuang if (cur_cmd->base == RTW_PWR_ADDR_SDIO) 156e3037485SYan-Hsuan Chuang offset |= SDIO_LOCAL_OFFSET; 157e3037485SYan-Hsuan Chuang 158e3037485SYan-Hsuan Chuang value = rtw_read8(rtwdev, offset); 159e3037485SYan-Hsuan Chuang value &= ~cur_cmd->mask; 160e3037485SYan-Hsuan Chuang value |= (cur_cmd->value & cur_cmd->mask); 161e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, offset, value); 162e3037485SYan-Hsuan Chuang break; 163e3037485SYan-Hsuan Chuang case RTW_PWR_CMD_POLLING: 164e3037485SYan-Hsuan Chuang if (rtw_pwr_cmd_polling(rtwdev, cur_cmd)) 165e3037485SYan-Hsuan Chuang return -EBUSY; 166e3037485SYan-Hsuan Chuang break; 167e3037485SYan-Hsuan Chuang case RTW_PWR_CMD_DELAY: 168e3037485SYan-Hsuan Chuang if (cur_cmd->value == RTW_PWR_DELAY_US) 169e3037485SYan-Hsuan Chuang udelay(cur_cmd->offset); 170e3037485SYan-Hsuan Chuang else 171e3037485SYan-Hsuan Chuang mdelay(cur_cmd->offset); 172e3037485SYan-Hsuan Chuang break; 173e3037485SYan-Hsuan Chuang case RTW_PWR_CMD_READ: 174e3037485SYan-Hsuan Chuang break; 175e3037485SYan-Hsuan Chuang default: 176e3037485SYan-Hsuan Chuang return -EINVAL; 177e3037485SYan-Hsuan Chuang } 178e3037485SYan-Hsuan Chuang } 179e3037485SYan-Hsuan Chuang 180e3037485SYan-Hsuan Chuang return 0; 181e3037485SYan-Hsuan Chuang } 182e3037485SYan-Hsuan Chuang 183e3037485SYan-Hsuan Chuang static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, 184e3037485SYan-Hsuan Chuang struct rtw_pwr_seq_cmd **cmd_seq) 185e3037485SYan-Hsuan Chuang { 186e3037485SYan-Hsuan Chuang u8 cut_mask; 187e3037485SYan-Hsuan Chuang u8 intf_mask; 188e3037485SYan-Hsuan Chuang u8 cut; 189e3037485SYan-Hsuan Chuang u32 idx = 0; 190e3037485SYan-Hsuan Chuang struct rtw_pwr_seq_cmd *cmd; 191e3037485SYan-Hsuan Chuang int ret; 192e3037485SYan-Hsuan Chuang 193e3037485SYan-Hsuan Chuang cut = rtwdev->hal.cut_version; 194e3037485SYan-Hsuan Chuang cut_mask = cut_version_to_mask(cut); 195e3037485SYan-Hsuan Chuang switch (rtw_hci_type(rtwdev)) { 196e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_PCIE: 197e3037485SYan-Hsuan Chuang intf_mask = BIT(2); 198e3037485SYan-Hsuan Chuang break; 199e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_USB: 200e3037485SYan-Hsuan Chuang intf_mask = BIT(1); 201e3037485SYan-Hsuan Chuang break; 202e3037485SYan-Hsuan Chuang default: 203e3037485SYan-Hsuan Chuang return -EINVAL; 204e3037485SYan-Hsuan Chuang } 205e3037485SYan-Hsuan Chuang 206e3037485SYan-Hsuan Chuang do { 207e3037485SYan-Hsuan Chuang cmd = cmd_seq[idx]; 208e3037485SYan-Hsuan Chuang if (!cmd) 209e3037485SYan-Hsuan Chuang break; 210e3037485SYan-Hsuan Chuang 211e3037485SYan-Hsuan Chuang ret = rtw_sub_pwr_seq_parser(rtwdev, intf_mask, cut_mask, cmd); 212e3037485SYan-Hsuan Chuang if (ret) 213e3037485SYan-Hsuan Chuang return -EBUSY; 214e3037485SYan-Hsuan Chuang 215e3037485SYan-Hsuan Chuang idx++; 216e3037485SYan-Hsuan Chuang } while (1); 217e3037485SYan-Hsuan Chuang 218e3037485SYan-Hsuan Chuang return 0; 219e3037485SYan-Hsuan Chuang } 220e3037485SYan-Hsuan Chuang 221e3037485SYan-Hsuan Chuang static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) 222e3037485SYan-Hsuan Chuang { 223e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 224e3037485SYan-Hsuan Chuang struct rtw_pwr_seq_cmd **pwr_seq; 225e3037485SYan-Hsuan Chuang u8 rpwm; 226e3037485SYan-Hsuan Chuang bool cur_pwr; 227e3037485SYan-Hsuan Chuang 228e3037485SYan-Hsuan Chuang rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); 229e3037485SYan-Hsuan Chuang 230e3037485SYan-Hsuan Chuang /* Check FW still exist or not */ 231e3037485SYan-Hsuan Chuang if (rtw_read16(rtwdev, REG_MCUFW_CTRL) == 0xC078) { 232e3037485SYan-Hsuan Chuang rpwm = (rpwm ^ BIT_RPWM_TOGGLE) & BIT_RPWM_TOGGLE; 233e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, rpwm); 234e3037485SYan-Hsuan Chuang } 235e3037485SYan-Hsuan Chuang 236e3037485SYan-Hsuan Chuang if (rtw_read8(rtwdev, REG_CR) == 0xea) 237e3037485SYan-Hsuan Chuang cur_pwr = false; 238e3037485SYan-Hsuan Chuang else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && 239e3037485SYan-Hsuan Chuang (rtw_read8(rtwdev, REG_SYS_STATUS1 + 1) & BIT(0))) 240e3037485SYan-Hsuan Chuang cur_pwr = false; 241e3037485SYan-Hsuan Chuang else 242e3037485SYan-Hsuan Chuang cur_pwr = true; 243e3037485SYan-Hsuan Chuang 244e3037485SYan-Hsuan Chuang if (pwr_on && cur_pwr) 245e3037485SYan-Hsuan Chuang return -EALREADY; 246e3037485SYan-Hsuan Chuang 247e3037485SYan-Hsuan Chuang pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq; 248e3037485SYan-Hsuan Chuang if (rtw_pwr_seq_parser(rtwdev, pwr_seq)) 249e3037485SYan-Hsuan Chuang return -EINVAL; 250e3037485SYan-Hsuan Chuang 251e3037485SYan-Hsuan Chuang return 0; 252e3037485SYan-Hsuan Chuang } 253e3037485SYan-Hsuan Chuang 254e3037485SYan-Hsuan Chuang static int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) 255e3037485SYan-Hsuan Chuang { 256e3037485SYan-Hsuan Chuang u8 sys_func_en = rtwdev->chip->sys_func_en; 257e3037485SYan-Hsuan Chuang u8 value8; 258e3037485SYan-Hsuan Chuang u32 value, tmp; 259e3037485SYan-Hsuan Chuang 260e3037485SYan-Hsuan Chuang value = rtw_read32(rtwdev, REG_CPU_DMEM_CON); 261e3037485SYan-Hsuan Chuang value |= BIT_WL_PLATFORM_RST | BIT_DDMA_EN; 262e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_CPU_DMEM_CON, value); 263e3037485SYan-Hsuan Chuang 264e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en); 265e3037485SYan-Hsuan Chuang value8 = (rtw_read8(rtwdev, REG_CR_EXT + 3) & 0xF0) | 0x0C; 266e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR_EXT + 3, value8); 267e3037485SYan-Hsuan Chuang 268e3037485SYan-Hsuan Chuang /* disable boot-from-flash for driver's DL FW */ 269e3037485SYan-Hsuan Chuang tmp = rtw_read32(rtwdev, REG_MCUFW_CTRL); 270e3037485SYan-Hsuan Chuang if (tmp & BIT_BOOT_FSPI_EN) { 271e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_MCUFW_CTRL, tmp & (~BIT_BOOT_FSPI_EN)); 272e3037485SYan-Hsuan Chuang value = rtw_read32(rtwdev, REG_GPIO_MUXCFG) & (~BIT_FSPI_EN); 273e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_GPIO_MUXCFG, value); 274e3037485SYan-Hsuan Chuang } 275e3037485SYan-Hsuan Chuang 276e3037485SYan-Hsuan Chuang return 0; 277e3037485SYan-Hsuan Chuang } 278e3037485SYan-Hsuan Chuang 279e3037485SYan-Hsuan Chuang int rtw_mac_power_on(struct rtw_dev *rtwdev) 280e3037485SYan-Hsuan Chuang { 281e3037485SYan-Hsuan Chuang int ret = 0; 282e3037485SYan-Hsuan Chuang 283e3037485SYan-Hsuan Chuang ret = rtw_mac_pre_system_cfg(rtwdev); 284e3037485SYan-Hsuan Chuang if (ret) 285e3037485SYan-Hsuan Chuang goto err; 286e3037485SYan-Hsuan Chuang 287e3037485SYan-Hsuan Chuang ret = rtw_mac_power_switch(rtwdev, true); 288e3037485SYan-Hsuan Chuang if (ret) 289e3037485SYan-Hsuan Chuang goto err; 290e3037485SYan-Hsuan Chuang 291e3037485SYan-Hsuan Chuang ret = rtw_mac_init_system_cfg(rtwdev); 292e3037485SYan-Hsuan Chuang if (ret) 293e3037485SYan-Hsuan Chuang goto err; 294e3037485SYan-Hsuan Chuang 295e3037485SYan-Hsuan Chuang return 0; 296e3037485SYan-Hsuan Chuang 297e3037485SYan-Hsuan Chuang err: 298e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "mac power on failed"); 299e3037485SYan-Hsuan Chuang return ret; 300e3037485SYan-Hsuan Chuang } 301e3037485SYan-Hsuan Chuang 302e3037485SYan-Hsuan Chuang void rtw_mac_power_off(struct rtw_dev *rtwdev) 303e3037485SYan-Hsuan Chuang { 304e3037485SYan-Hsuan Chuang rtw_mac_power_switch(rtwdev, false); 305e3037485SYan-Hsuan Chuang } 306e3037485SYan-Hsuan Chuang 307e3037485SYan-Hsuan Chuang static bool check_firmware_size(const u8 *data, u32 size) 308e3037485SYan-Hsuan Chuang { 309e3037485SYan-Hsuan Chuang u32 dmem_size; 310e3037485SYan-Hsuan Chuang u32 imem_size; 311e3037485SYan-Hsuan Chuang u32 emem_size; 312e3037485SYan-Hsuan Chuang u32 real_size; 313e3037485SYan-Hsuan Chuang 314e3037485SYan-Hsuan Chuang dmem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_SIZE))); 315e3037485SYan-Hsuan Chuang imem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_SIZE))); 316e3037485SYan-Hsuan Chuang emem_size = ((*(data + FW_HDR_MEM_USAGE)) & BIT(4)) ? 317e3037485SYan-Hsuan Chuang le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_SIZE))) : 0; 318e3037485SYan-Hsuan Chuang 319e3037485SYan-Hsuan Chuang dmem_size += FW_HDR_CHKSUM_SIZE; 320e3037485SYan-Hsuan Chuang imem_size += FW_HDR_CHKSUM_SIZE; 321e3037485SYan-Hsuan Chuang emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0; 322e3037485SYan-Hsuan Chuang real_size = FW_HDR_SIZE + dmem_size + imem_size + emem_size; 323e3037485SYan-Hsuan Chuang if (real_size != size) 324e3037485SYan-Hsuan Chuang return false; 325e3037485SYan-Hsuan Chuang 326e3037485SYan-Hsuan Chuang return true; 327e3037485SYan-Hsuan Chuang } 328e3037485SYan-Hsuan Chuang 329e3037485SYan-Hsuan Chuang static void wlan_cpu_enable(struct rtw_dev *rtwdev, bool enable) 330e3037485SYan-Hsuan Chuang { 331e3037485SYan-Hsuan Chuang if (enable) { 332e3037485SYan-Hsuan Chuang /* cpu io interface enable */ 333e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF); 334e3037485SYan-Hsuan Chuang 335e3037485SYan-Hsuan Chuang /* cpu enable */ 336e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 337e3037485SYan-Hsuan Chuang } else { 338e3037485SYan-Hsuan Chuang /* cpu io interface disable */ 339e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 340e3037485SYan-Hsuan Chuang 341e3037485SYan-Hsuan Chuang /* cpu disable */ 342e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF); 343e3037485SYan-Hsuan Chuang } 344e3037485SYan-Hsuan Chuang } 345e3037485SYan-Hsuan Chuang 346e3037485SYan-Hsuan Chuang #define DLFW_RESTORE_REG_NUM 6 347e3037485SYan-Hsuan Chuang 348e3037485SYan-Hsuan Chuang static void download_firmware_reg_backup(struct rtw_dev *rtwdev, 349e3037485SYan-Hsuan Chuang struct rtw_backup_info *bckp) 350e3037485SYan-Hsuan Chuang { 351e3037485SYan-Hsuan Chuang u8 tmp; 352e3037485SYan-Hsuan Chuang u8 bckp_idx = 0; 353e3037485SYan-Hsuan Chuang 354e3037485SYan-Hsuan Chuang /* set HIQ to hi priority */ 355e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 1; 356e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_TXDMA_PQ_MAP + 1; 357e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = rtw_read8(rtwdev, REG_TXDMA_PQ_MAP + 1); 358e3037485SYan-Hsuan Chuang bckp_idx++; 359e3037485SYan-Hsuan Chuang tmp = RTW_DMA_MAPPING_HIGH << 6; 360e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_TXDMA_PQ_MAP + 1, tmp); 361e3037485SYan-Hsuan Chuang 362e3037485SYan-Hsuan Chuang /* DLFW only use HIQ, map HIQ to hi priority */ 363e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 1; 364e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_CR; 365e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = rtw_read8(rtwdev, REG_CR); 366e3037485SYan-Hsuan Chuang bckp_idx++; 367e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 4; 368e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_H2CQ_CSR; 369e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = BIT_H2CQ_FULL; 370e3037485SYan-Hsuan Chuang bckp_idx++; 371e3037485SYan-Hsuan Chuang tmp = BIT_HCI_TXDMA_EN | BIT_TXDMA_EN; 372e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR, tmp); 373e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); 374e3037485SYan-Hsuan Chuang 375e3037485SYan-Hsuan Chuang /* Config hi priority queue and public priority queue page number */ 376e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 2; 377e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_FIFOPAGE_INFO_1; 378e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = rtw_read16(rtwdev, REG_FIFOPAGE_INFO_1); 379e3037485SYan-Hsuan Chuang bckp_idx++; 380e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 4; 381e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_RQPN_CTRL_2; 382e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = rtw_read32(rtwdev, REG_RQPN_CTRL_2) | BIT_LD_RQPN; 383e3037485SYan-Hsuan Chuang bckp_idx++; 384e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, 0x200); 385e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_RQPN_CTRL_2, bckp[bckp_idx - 1].val); 386e3037485SYan-Hsuan Chuang 387e3037485SYan-Hsuan Chuang /* Disable beacon related functions */ 388e3037485SYan-Hsuan Chuang tmp = rtw_read8(rtwdev, REG_BCN_CTRL); 389e3037485SYan-Hsuan Chuang bckp[bckp_idx].len = 1; 390e3037485SYan-Hsuan Chuang bckp[bckp_idx].reg = REG_BCN_CTRL; 391e3037485SYan-Hsuan Chuang bckp[bckp_idx].val = tmp; 392e3037485SYan-Hsuan Chuang bckp_idx++; 393e3037485SYan-Hsuan Chuang tmp = (u8)((tmp & (~BIT_EN_BCN_FUNCTION)) | BIT_DIS_TSF_UDT); 394e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_BCN_CTRL, tmp); 395e3037485SYan-Hsuan Chuang 396e3037485SYan-Hsuan Chuang WARN(bckp_idx != DLFW_RESTORE_REG_NUM, "wrong backup number\n"); 397e3037485SYan-Hsuan Chuang } 398e3037485SYan-Hsuan Chuang 399e3037485SYan-Hsuan Chuang static void download_firmware_reset_platform(struct rtw_dev *rtwdev) 400e3037485SYan-Hsuan Chuang { 401e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16); 402e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8); 403e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16); 404e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8); 405e3037485SYan-Hsuan Chuang } 406e3037485SYan-Hsuan Chuang 407e3037485SYan-Hsuan Chuang static void download_firmware_reg_restore(struct rtw_dev *rtwdev, 408e3037485SYan-Hsuan Chuang struct rtw_backup_info *bckp, 409e3037485SYan-Hsuan Chuang u8 bckp_num) 410e3037485SYan-Hsuan Chuang { 411e3037485SYan-Hsuan Chuang rtw_restore_reg(rtwdev, bckp, bckp_num); 412e3037485SYan-Hsuan Chuang } 413e3037485SYan-Hsuan Chuang 414e3037485SYan-Hsuan Chuang #define TX_DESC_SIZE 48 415e3037485SYan-Hsuan Chuang 416e3037485SYan-Hsuan Chuang static int send_firmware_pkt_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, 417e3037485SYan-Hsuan Chuang const u8 *data, u32 size) 418e3037485SYan-Hsuan Chuang { 419e3037485SYan-Hsuan Chuang u8 *buf; 420e3037485SYan-Hsuan Chuang int ret; 421e3037485SYan-Hsuan Chuang 422e3037485SYan-Hsuan Chuang buf = kmemdup(data, size, GFP_KERNEL); 423e3037485SYan-Hsuan Chuang if (!buf) 424e3037485SYan-Hsuan Chuang return -ENOMEM; 425e3037485SYan-Hsuan Chuang 426e3037485SYan-Hsuan Chuang ret = rtw_fw_write_data_rsvd_page(rtwdev, pg_addr, buf, size); 427e3037485SYan-Hsuan Chuang kfree(buf); 428e3037485SYan-Hsuan Chuang return ret; 429e3037485SYan-Hsuan Chuang } 430e3037485SYan-Hsuan Chuang 431e3037485SYan-Hsuan Chuang static int 432e3037485SYan-Hsuan Chuang send_firmware_pkt(struct rtw_dev *rtwdev, u16 pg_addr, const u8 *data, u32 size) 433e3037485SYan-Hsuan Chuang { 434e3037485SYan-Hsuan Chuang int ret; 435e3037485SYan-Hsuan Chuang 436e3037485SYan-Hsuan Chuang if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && 437e3037485SYan-Hsuan Chuang !((size + TX_DESC_SIZE) & (512 - 1))) 438e3037485SYan-Hsuan Chuang size += 1; 439e3037485SYan-Hsuan Chuang 440e3037485SYan-Hsuan Chuang ret = send_firmware_pkt_rsvd_page(rtwdev, pg_addr, data, size); 441e3037485SYan-Hsuan Chuang if (ret) 442e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "failed to download rsvd page\n"); 443e3037485SYan-Hsuan Chuang 444e3037485SYan-Hsuan Chuang return ret; 445e3037485SYan-Hsuan Chuang } 446e3037485SYan-Hsuan Chuang 447e3037485SYan-Hsuan Chuang static int 448e3037485SYan-Hsuan Chuang iddma_enable(struct rtw_dev *rtwdev, u32 src, u32 dst, u32 ctrl) 449e3037485SYan-Hsuan Chuang { 450e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_DDMA_CH0SA, src); 451e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_DDMA_CH0DA, dst); 452e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_DDMA_CH0CTRL, ctrl); 453e3037485SYan-Hsuan Chuang 454e3037485SYan-Hsuan Chuang if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) 455e3037485SYan-Hsuan Chuang return -EBUSY; 456e3037485SYan-Hsuan Chuang 457e3037485SYan-Hsuan Chuang return 0; 458e3037485SYan-Hsuan Chuang } 459e3037485SYan-Hsuan Chuang 460e3037485SYan-Hsuan Chuang static int iddma_download_firmware(struct rtw_dev *rtwdev, u32 src, u32 dst, 461e3037485SYan-Hsuan Chuang u32 len, u8 first) 462e3037485SYan-Hsuan Chuang { 463e3037485SYan-Hsuan Chuang u32 ch0_ctrl = BIT_DDMACH0_CHKSUM_EN | BIT_DDMACH0_OWN; 464e3037485SYan-Hsuan Chuang 465e3037485SYan-Hsuan Chuang if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) 466e3037485SYan-Hsuan Chuang return -EBUSY; 467e3037485SYan-Hsuan Chuang 468e3037485SYan-Hsuan Chuang ch0_ctrl |= len & BIT_MASK_DDMACH0_DLEN; 469e3037485SYan-Hsuan Chuang if (!first) 470e3037485SYan-Hsuan Chuang ch0_ctrl |= BIT_DDMACH0_CHKSUM_CONT; 471e3037485SYan-Hsuan Chuang 472e3037485SYan-Hsuan Chuang if (iddma_enable(rtwdev, src, dst, ch0_ctrl)) 473e3037485SYan-Hsuan Chuang return -EBUSY; 474e3037485SYan-Hsuan Chuang 475e3037485SYan-Hsuan Chuang return 0; 476e3037485SYan-Hsuan Chuang } 477e3037485SYan-Hsuan Chuang 478e3037485SYan-Hsuan Chuang static bool 479e3037485SYan-Hsuan Chuang check_fw_checksum(struct rtw_dev *rtwdev, u32 addr) 480e3037485SYan-Hsuan Chuang { 481e3037485SYan-Hsuan Chuang u8 fw_ctrl; 482e3037485SYan-Hsuan Chuang 483e3037485SYan-Hsuan Chuang fw_ctrl = rtw_read8(rtwdev, REG_MCUFW_CTRL); 484e3037485SYan-Hsuan Chuang 485e3037485SYan-Hsuan Chuang if (rtw_read32(rtwdev, REG_DDMA_CH0CTRL) & BIT_DDMACH0_CHKSUM_STS) { 486e3037485SYan-Hsuan Chuang if (addr < OCPBASE_DMEM_88XX) { 487e3037485SYan-Hsuan Chuang fw_ctrl |= BIT_IMEM_DW_OK; 488e3037485SYan-Hsuan Chuang fw_ctrl &= ~BIT_IMEM_CHKSUM_OK; 489e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 490e3037485SYan-Hsuan Chuang } else { 491e3037485SYan-Hsuan Chuang fw_ctrl |= BIT_DMEM_DW_OK; 492e3037485SYan-Hsuan Chuang fw_ctrl &= ~BIT_DMEM_CHKSUM_OK; 493e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 494e3037485SYan-Hsuan Chuang } 495e3037485SYan-Hsuan Chuang 496e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "invalid fw checksum\n"); 497e3037485SYan-Hsuan Chuang 498e3037485SYan-Hsuan Chuang return false; 499e3037485SYan-Hsuan Chuang } 500e3037485SYan-Hsuan Chuang 501e3037485SYan-Hsuan Chuang if (addr < OCPBASE_DMEM_88XX) { 502e3037485SYan-Hsuan Chuang fw_ctrl |= (BIT_IMEM_DW_OK | BIT_IMEM_CHKSUM_OK); 503e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 504e3037485SYan-Hsuan Chuang } else { 505e3037485SYan-Hsuan Chuang fw_ctrl |= (BIT_DMEM_DW_OK | BIT_DMEM_CHKSUM_OK); 506e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 507e3037485SYan-Hsuan Chuang } 508e3037485SYan-Hsuan Chuang 509e3037485SYan-Hsuan Chuang return true; 510e3037485SYan-Hsuan Chuang } 511e3037485SYan-Hsuan Chuang 512e3037485SYan-Hsuan Chuang static int 513e3037485SYan-Hsuan Chuang download_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data, 514e3037485SYan-Hsuan Chuang u32 src, u32 dst, u32 size) 515e3037485SYan-Hsuan Chuang { 516e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 517e3037485SYan-Hsuan Chuang u32 desc_size = chip->tx_pkt_desc_sz; 518e3037485SYan-Hsuan Chuang u8 first_part; 519e3037485SYan-Hsuan Chuang u32 mem_offset; 520e3037485SYan-Hsuan Chuang u32 residue_size; 521e3037485SYan-Hsuan Chuang u32 pkt_size; 522e3037485SYan-Hsuan Chuang u32 max_size = 0x1000; 523e3037485SYan-Hsuan Chuang u32 val; 524e3037485SYan-Hsuan Chuang int ret; 525e3037485SYan-Hsuan Chuang 526e3037485SYan-Hsuan Chuang mem_offset = 0; 527e3037485SYan-Hsuan Chuang first_part = 1; 528e3037485SYan-Hsuan Chuang residue_size = size; 529e3037485SYan-Hsuan Chuang 530e3037485SYan-Hsuan Chuang val = rtw_read32(rtwdev, REG_DDMA_CH0CTRL); 531e3037485SYan-Hsuan Chuang val |= BIT_DDMACH0_RESET_CHKSUM_STS; 532e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_DDMA_CH0CTRL, val); 533e3037485SYan-Hsuan Chuang 534e3037485SYan-Hsuan Chuang while (residue_size) { 535e3037485SYan-Hsuan Chuang if (residue_size >= max_size) 536e3037485SYan-Hsuan Chuang pkt_size = max_size; 537e3037485SYan-Hsuan Chuang else 538e3037485SYan-Hsuan Chuang pkt_size = residue_size; 539e3037485SYan-Hsuan Chuang 540e3037485SYan-Hsuan Chuang ret = send_firmware_pkt(rtwdev, (u16)(src >> 7), 541e3037485SYan-Hsuan Chuang data + mem_offset, pkt_size); 542e3037485SYan-Hsuan Chuang if (ret) 543e3037485SYan-Hsuan Chuang return ret; 544e3037485SYan-Hsuan Chuang 545e3037485SYan-Hsuan Chuang ret = iddma_download_firmware(rtwdev, OCPBASE_TXBUF_88XX + 546e3037485SYan-Hsuan Chuang src + desc_size, 547e3037485SYan-Hsuan Chuang dst + mem_offset, pkt_size, 548e3037485SYan-Hsuan Chuang first_part); 549e3037485SYan-Hsuan Chuang if (ret) 550e3037485SYan-Hsuan Chuang return ret; 551e3037485SYan-Hsuan Chuang 552e3037485SYan-Hsuan Chuang first_part = 0; 553e3037485SYan-Hsuan Chuang mem_offset += pkt_size; 554e3037485SYan-Hsuan Chuang residue_size -= pkt_size; 555e3037485SYan-Hsuan Chuang } 556e3037485SYan-Hsuan Chuang 557e3037485SYan-Hsuan Chuang if (!check_fw_checksum(rtwdev, dst)) 558e3037485SYan-Hsuan Chuang return -EINVAL; 559e3037485SYan-Hsuan Chuang 560e3037485SYan-Hsuan Chuang return 0; 561e3037485SYan-Hsuan Chuang } 562e3037485SYan-Hsuan Chuang 563e3037485SYan-Hsuan Chuang static void update_firmware_info(struct rtw_dev *rtwdev, 564e3037485SYan-Hsuan Chuang struct rtw_fw_state *fw) 565e3037485SYan-Hsuan Chuang { 566e3037485SYan-Hsuan Chuang const u8 *data = fw->firmware->data; 567e3037485SYan-Hsuan Chuang 568e3037485SYan-Hsuan Chuang fw->h2c_version = 569e3037485SYan-Hsuan Chuang le16_to_cpu(*((__le16 *)(data + FW_HDR_H2C_FMT_VER))); 570e3037485SYan-Hsuan Chuang fw->version = 571e3037485SYan-Hsuan Chuang le16_to_cpu(*((__le16 *)(data + FW_HDR_VERSION))); 572e3037485SYan-Hsuan Chuang fw->sub_version = *(data + FW_HDR_SUBVERSION); 573e3037485SYan-Hsuan Chuang fw->sub_index = *(data + FW_HDR_SUBINDEX); 574e3037485SYan-Hsuan Chuang 575e3037485SYan-Hsuan Chuang rtw_dbg(rtwdev, RTW_DBG_FW, "fw h2c version: %x\n", fw->h2c_version); 576e3037485SYan-Hsuan Chuang rtw_dbg(rtwdev, RTW_DBG_FW, "fw version: %x\n", fw->version); 577e3037485SYan-Hsuan Chuang rtw_dbg(rtwdev, RTW_DBG_FW, "fw sub version: %x\n", fw->sub_version); 578e3037485SYan-Hsuan Chuang rtw_dbg(rtwdev, RTW_DBG_FW, "fw sub index: %x\n", fw->sub_index); 579e3037485SYan-Hsuan Chuang } 580e3037485SYan-Hsuan Chuang 581e3037485SYan-Hsuan Chuang static int 582e3037485SYan-Hsuan Chuang start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) 583e3037485SYan-Hsuan Chuang { 584e3037485SYan-Hsuan Chuang const u8 *cur_fw; 585e3037485SYan-Hsuan Chuang u16 val; 586e3037485SYan-Hsuan Chuang u32 imem_size; 587e3037485SYan-Hsuan Chuang u32 dmem_size; 588e3037485SYan-Hsuan Chuang u32 emem_size; 589e3037485SYan-Hsuan Chuang u32 addr; 590e3037485SYan-Hsuan Chuang int ret; 591e3037485SYan-Hsuan Chuang 592e3037485SYan-Hsuan Chuang dmem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_SIZE))); 593e3037485SYan-Hsuan Chuang imem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_SIZE))); 594e3037485SYan-Hsuan Chuang emem_size = ((*(data + FW_HDR_MEM_USAGE)) & BIT(4)) ? 595e3037485SYan-Hsuan Chuang le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_SIZE))) : 0; 596e3037485SYan-Hsuan Chuang dmem_size += FW_HDR_CHKSUM_SIZE; 597e3037485SYan-Hsuan Chuang imem_size += FW_HDR_CHKSUM_SIZE; 598e3037485SYan-Hsuan Chuang emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0; 599e3037485SYan-Hsuan Chuang 600e3037485SYan-Hsuan Chuang val = (u16)(rtw_read16(rtwdev, REG_MCUFW_CTRL) & 0x3800); 601e3037485SYan-Hsuan Chuang val |= BIT_MCUFWDL_EN; 602e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_MCUFW_CTRL, val); 603e3037485SYan-Hsuan Chuang 604e3037485SYan-Hsuan Chuang cur_fw = data + FW_HDR_SIZE; 605e3037485SYan-Hsuan Chuang addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_ADDR))); 606e3037485SYan-Hsuan Chuang addr &= ~BIT(31); 607e3037485SYan-Hsuan Chuang ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, dmem_size); 608e3037485SYan-Hsuan Chuang if (ret) 609e3037485SYan-Hsuan Chuang return ret; 610e3037485SYan-Hsuan Chuang 611e3037485SYan-Hsuan Chuang cur_fw = data + FW_HDR_SIZE + dmem_size; 612e3037485SYan-Hsuan Chuang addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_ADDR))); 613e3037485SYan-Hsuan Chuang addr &= ~BIT(31); 614e3037485SYan-Hsuan Chuang ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, imem_size); 615e3037485SYan-Hsuan Chuang if (ret) 616e3037485SYan-Hsuan Chuang return ret; 617e3037485SYan-Hsuan Chuang 618e3037485SYan-Hsuan Chuang if (emem_size) { 619e3037485SYan-Hsuan Chuang cur_fw = data + FW_HDR_SIZE + dmem_size + imem_size; 620e3037485SYan-Hsuan Chuang addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_ADDR))); 621e3037485SYan-Hsuan Chuang addr &= ~BIT(31); 622e3037485SYan-Hsuan Chuang ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, 623e3037485SYan-Hsuan Chuang emem_size); 624e3037485SYan-Hsuan Chuang if (ret) 625e3037485SYan-Hsuan Chuang return ret; 626e3037485SYan-Hsuan Chuang } 627e3037485SYan-Hsuan Chuang 628e3037485SYan-Hsuan Chuang return 0; 629e3037485SYan-Hsuan Chuang } 630e3037485SYan-Hsuan Chuang 631e3037485SYan-Hsuan Chuang static int download_firmware_validate(struct rtw_dev *rtwdev) 632e3037485SYan-Hsuan Chuang { 633e3037485SYan-Hsuan Chuang u32 fw_key; 634e3037485SYan-Hsuan Chuang 635e3037485SYan-Hsuan Chuang if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, FW_READY_MASK, FW_READY)) { 636e3037485SYan-Hsuan Chuang fw_key = rtw_read32(rtwdev, REG_FW_DBG7) & FW_KEY_MASK; 637e3037485SYan-Hsuan Chuang if (fw_key == ILLEGAL_KEY_GROUP) 638e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "invalid fw key\n"); 639e3037485SYan-Hsuan Chuang return -EINVAL; 640e3037485SYan-Hsuan Chuang } 641e3037485SYan-Hsuan Chuang 642e3037485SYan-Hsuan Chuang return 0; 643e3037485SYan-Hsuan Chuang } 644e3037485SYan-Hsuan Chuang 645e3037485SYan-Hsuan Chuang static void download_firmware_end_flow(struct rtw_dev *rtwdev) 646e3037485SYan-Hsuan Chuang { 647e3037485SYan-Hsuan Chuang u16 fw_ctrl; 648e3037485SYan-Hsuan Chuang 649e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_TXDMA_STATUS, BTI_PAGE_OVF); 650e3037485SYan-Hsuan Chuang 651e3037485SYan-Hsuan Chuang /* Check IMEM & DMEM checksum is OK or not */ 652e3037485SYan-Hsuan Chuang fw_ctrl = rtw_read16(rtwdev, REG_MCUFW_CTRL); 653e3037485SYan-Hsuan Chuang if ((fw_ctrl & BIT_CHECK_SUM_OK) != BIT_CHECK_SUM_OK) 654e3037485SYan-Hsuan Chuang return; 655e3037485SYan-Hsuan Chuang 656e3037485SYan-Hsuan Chuang fw_ctrl = (fw_ctrl | BIT_FW_DW_RDY) & ~BIT_MCUFWDL_EN; 657e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 658e3037485SYan-Hsuan Chuang } 659e3037485SYan-Hsuan Chuang 660e3037485SYan-Hsuan Chuang int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) 661e3037485SYan-Hsuan Chuang { 662e3037485SYan-Hsuan Chuang struct rtw_backup_info bckp[DLFW_RESTORE_REG_NUM]; 663e3037485SYan-Hsuan Chuang const u8 *data = fw->firmware->data; 664e3037485SYan-Hsuan Chuang u32 size = fw->firmware->size; 665e3037485SYan-Hsuan Chuang u32 ltecoex_bckp; 666e3037485SYan-Hsuan Chuang int ret; 667e3037485SYan-Hsuan Chuang 668e3037485SYan-Hsuan Chuang if (!check_firmware_size(data, size)) 669e3037485SYan-Hsuan Chuang return -EINVAL; 670e3037485SYan-Hsuan Chuang 671e3037485SYan-Hsuan Chuang if (!ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp)) 672e3037485SYan-Hsuan Chuang return -EBUSY; 673e3037485SYan-Hsuan Chuang 674e3037485SYan-Hsuan Chuang wlan_cpu_enable(rtwdev, false); 675e3037485SYan-Hsuan Chuang 676e3037485SYan-Hsuan Chuang download_firmware_reg_backup(rtwdev, bckp); 677e3037485SYan-Hsuan Chuang download_firmware_reset_platform(rtwdev); 678e3037485SYan-Hsuan Chuang 679e3037485SYan-Hsuan Chuang ret = start_download_firmware(rtwdev, data, size); 680e3037485SYan-Hsuan Chuang if (ret) 681e3037485SYan-Hsuan Chuang goto dlfw_fail; 682e3037485SYan-Hsuan Chuang 683e3037485SYan-Hsuan Chuang download_firmware_reg_restore(rtwdev, bckp, DLFW_RESTORE_REG_NUM); 684e3037485SYan-Hsuan Chuang 685e3037485SYan-Hsuan Chuang download_firmware_end_flow(rtwdev); 686e3037485SYan-Hsuan Chuang 687e3037485SYan-Hsuan Chuang wlan_cpu_enable(rtwdev, true); 688e3037485SYan-Hsuan Chuang 689e3037485SYan-Hsuan Chuang if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) 690e3037485SYan-Hsuan Chuang return -EBUSY; 691e3037485SYan-Hsuan Chuang 692e3037485SYan-Hsuan Chuang ret = download_firmware_validate(rtwdev); 693e3037485SYan-Hsuan Chuang if (ret) 694e3037485SYan-Hsuan Chuang goto dlfw_fail; 695e3037485SYan-Hsuan Chuang 696e3037485SYan-Hsuan Chuang update_firmware_info(rtwdev, fw); 697e3037485SYan-Hsuan Chuang 698e3037485SYan-Hsuan Chuang /* reset desc and index */ 699e3037485SYan-Hsuan Chuang rtw_hci_setup(rtwdev); 700e3037485SYan-Hsuan Chuang 701e3037485SYan-Hsuan Chuang rtwdev->h2c.last_box_num = 0; 702e3037485SYan-Hsuan Chuang rtwdev->h2c.seq = 0; 703e3037485SYan-Hsuan Chuang 704e3037485SYan-Hsuan Chuang rtw_fw_send_general_info(rtwdev); 705e3037485SYan-Hsuan Chuang rtw_fw_send_phydm_info(rtwdev); 706e3037485SYan-Hsuan Chuang 707e3037485SYan-Hsuan Chuang rtw_flag_set(rtwdev, RTW_FLAG_FW_RUNNING); 708e3037485SYan-Hsuan Chuang 709e3037485SYan-Hsuan Chuang return 0; 710e3037485SYan-Hsuan Chuang 711e3037485SYan-Hsuan Chuang dlfw_fail: 712e3037485SYan-Hsuan Chuang /* Disable FWDL_EN */ 713e3037485SYan-Hsuan Chuang rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 714e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 715e3037485SYan-Hsuan Chuang 716e3037485SYan-Hsuan Chuang return ret; 717e3037485SYan-Hsuan Chuang } 718e3037485SYan-Hsuan Chuang 719e3037485SYan-Hsuan Chuang static int txdma_queue_mapping(struct rtw_dev *rtwdev) 720e3037485SYan-Hsuan Chuang { 721e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 722e3037485SYan-Hsuan Chuang struct rtw_rqpn *rqpn = NULL; 723e3037485SYan-Hsuan Chuang u16 txdma_pq_map = 0; 724e3037485SYan-Hsuan Chuang 725e3037485SYan-Hsuan Chuang switch (rtw_hci_type(rtwdev)) { 726e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_PCIE: 727e3037485SYan-Hsuan Chuang rqpn = &chip->rqpn_table[1]; 728e3037485SYan-Hsuan Chuang break; 729e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_USB: 730e3037485SYan-Hsuan Chuang if (rtwdev->hci.bulkout_num == 2) 731e3037485SYan-Hsuan Chuang rqpn = &chip->rqpn_table[2]; 732e3037485SYan-Hsuan Chuang else if (rtwdev->hci.bulkout_num == 3) 733e3037485SYan-Hsuan Chuang rqpn = &chip->rqpn_table[3]; 734e3037485SYan-Hsuan Chuang else if (rtwdev->hci.bulkout_num == 4) 735e3037485SYan-Hsuan Chuang rqpn = &chip->rqpn_table[4]; 736e3037485SYan-Hsuan Chuang else 737e3037485SYan-Hsuan Chuang return -EINVAL; 738e3037485SYan-Hsuan Chuang break; 739e3037485SYan-Hsuan Chuang default: 740e3037485SYan-Hsuan Chuang return -EINVAL; 741e3037485SYan-Hsuan Chuang } 742e3037485SYan-Hsuan Chuang 743e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi); 744e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg); 745e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk); 746e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be); 747e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi); 748e3037485SYan-Hsuan Chuang txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo); 749e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map); 750e3037485SYan-Hsuan Chuang 751e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR, 0); 752e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR, MAC_TRX_ENABLE); 753e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); 754e3037485SYan-Hsuan Chuang 755e3037485SYan-Hsuan Chuang return 0; 756e3037485SYan-Hsuan Chuang } 757e3037485SYan-Hsuan Chuang 758e3037485SYan-Hsuan Chuang static int set_trx_fifo_info(struct rtw_dev *rtwdev) 759e3037485SYan-Hsuan Chuang { 760e3037485SYan-Hsuan Chuang struct rtw_fifo_conf *fifo = &rtwdev->fifo; 761e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 762e3037485SYan-Hsuan Chuang u16 cur_pg_addr; 763e3037485SYan-Hsuan Chuang u8 csi_buf_pg_num = chip->csi_buf_pg_num; 764e3037485SYan-Hsuan Chuang 765e3037485SYan-Hsuan Chuang /* config rsvd page num */ 766e3037485SYan-Hsuan Chuang fifo->rsvd_drv_pg_num = 8; 767e3037485SYan-Hsuan Chuang fifo->txff_pg_num = chip->txff_size >> 7; 768e3037485SYan-Hsuan Chuang fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num + 769e3037485SYan-Hsuan Chuang RSVD_PG_H2C_EXTRAINFO_NUM + 770e3037485SYan-Hsuan Chuang RSVD_PG_H2C_STATICINFO_NUM + 771e3037485SYan-Hsuan Chuang RSVD_PG_H2CQ_NUM + 772e3037485SYan-Hsuan Chuang RSVD_PG_CPU_INSTRUCTION_NUM + 773e3037485SYan-Hsuan Chuang RSVD_PG_FW_TXBUF_NUM + 774e3037485SYan-Hsuan Chuang csi_buf_pg_num; 775e3037485SYan-Hsuan Chuang 776e3037485SYan-Hsuan Chuang if (fifo->rsvd_pg_num > fifo->txff_pg_num) 777e3037485SYan-Hsuan Chuang return -ENOMEM; 778e3037485SYan-Hsuan Chuang 779e3037485SYan-Hsuan Chuang fifo->acq_pg_num = fifo->txff_pg_num - fifo->rsvd_pg_num; 780e3037485SYan-Hsuan Chuang fifo->rsvd_boundary = fifo->txff_pg_num - fifo->rsvd_pg_num; 781e3037485SYan-Hsuan Chuang 782e3037485SYan-Hsuan Chuang cur_pg_addr = fifo->txff_pg_num; 783e3037485SYan-Hsuan Chuang cur_pg_addr -= csi_buf_pg_num; 784e3037485SYan-Hsuan Chuang fifo->rsvd_csibuf_addr = cur_pg_addr; 785e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_FW_TXBUF_NUM; 786e3037485SYan-Hsuan Chuang fifo->rsvd_fw_txbuf_addr = cur_pg_addr; 787e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_CPU_INSTRUCTION_NUM; 788e3037485SYan-Hsuan Chuang fifo->rsvd_cpu_instr_addr = cur_pg_addr; 789e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_H2CQ_NUM; 790e3037485SYan-Hsuan Chuang fifo->rsvd_h2cq_addr = cur_pg_addr; 791e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_H2C_STATICINFO_NUM; 792e3037485SYan-Hsuan Chuang fifo->rsvd_h2c_sta_info_addr = cur_pg_addr; 793e3037485SYan-Hsuan Chuang cur_pg_addr -= RSVD_PG_H2C_EXTRAINFO_NUM; 794e3037485SYan-Hsuan Chuang fifo->rsvd_h2c_info_addr = cur_pg_addr; 795e3037485SYan-Hsuan Chuang cur_pg_addr -= fifo->rsvd_drv_pg_num; 796e3037485SYan-Hsuan Chuang fifo->rsvd_drv_addr = cur_pg_addr; 797e3037485SYan-Hsuan Chuang 798e3037485SYan-Hsuan Chuang if (fifo->rsvd_boundary != fifo->rsvd_drv_addr) { 799e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "wrong rsvd driver address\n"); 800e3037485SYan-Hsuan Chuang return -EINVAL; 801e3037485SYan-Hsuan Chuang } 802e3037485SYan-Hsuan Chuang 803e3037485SYan-Hsuan Chuang return 0; 804e3037485SYan-Hsuan Chuang } 805e3037485SYan-Hsuan Chuang 806e3037485SYan-Hsuan Chuang static int priority_queue_cfg(struct rtw_dev *rtwdev) 807e3037485SYan-Hsuan Chuang { 808e3037485SYan-Hsuan Chuang struct rtw_fifo_conf *fifo = &rtwdev->fifo; 809e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 810e3037485SYan-Hsuan Chuang struct rtw_page_table *pg_tbl = NULL; 811e3037485SYan-Hsuan Chuang u16 pubq_num; 812e3037485SYan-Hsuan Chuang int ret; 813e3037485SYan-Hsuan Chuang 814e3037485SYan-Hsuan Chuang ret = set_trx_fifo_info(rtwdev); 815e3037485SYan-Hsuan Chuang if (ret) 816e3037485SYan-Hsuan Chuang return ret; 817e3037485SYan-Hsuan Chuang 818e3037485SYan-Hsuan Chuang switch (rtw_hci_type(rtwdev)) { 819e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_PCIE: 820e3037485SYan-Hsuan Chuang pg_tbl = &chip->page_table[1]; 821e3037485SYan-Hsuan Chuang break; 822e3037485SYan-Hsuan Chuang case RTW_HCI_TYPE_USB: 823e3037485SYan-Hsuan Chuang if (rtwdev->hci.bulkout_num == 2) 824e3037485SYan-Hsuan Chuang pg_tbl = &chip->page_table[2]; 825e3037485SYan-Hsuan Chuang else if (rtwdev->hci.bulkout_num == 3) 826e3037485SYan-Hsuan Chuang pg_tbl = &chip->page_table[3]; 827e3037485SYan-Hsuan Chuang else if (rtwdev->hci.bulkout_num == 4) 828e3037485SYan-Hsuan Chuang pg_tbl = &chip->page_table[4]; 829e3037485SYan-Hsuan Chuang else 830e3037485SYan-Hsuan Chuang return -EINVAL; 831e3037485SYan-Hsuan Chuang break; 832e3037485SYan-Hsuan Chuang default: 833e3037485SYan-Hsuan Chuang return -EINVAL; 834e3037485SYan-Hsuan Chuang } 835e3037485SYan-Hsuan Chuang 836e3037485SYan-Hsuan Chuang pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - 837e3037485SYan-Hsuan Chuang pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; 838e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, pg_tbl->hq_num); 839e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_INFO_2, pg_tbl->lq_num); 840e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_INFO_3, pg_tbl->nq_num); 841e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_INFO_4, pg_tbl->exq_num); 842e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_INFO_5, pubq_num); 843e3037485SYan-Hsuan Chuang rtw_write32_set(rtwdev, REG_RQPN_CTRL_2, BIT_LD_RQPN); 844e3037485SYan-Hsuan Chuang 845e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2, fifo->rsvd_boundary); 846e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL + 2, BIT_EN_WR_FREE_TAIL >> 16); 847e3037485SYan-Hsuan Chuang 848e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_BCNQ_BDNY_V1, fifo->rsvd_boundary); 849e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2 + 2, fifo->rsvd_boundary); 850e3037485SYan-Hsuan Chuang rtw_write16(rtwdev, REG_BCNQ1_BDNY_V1, fifo->rsvd_boundary); 851e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_RXFF_BNDY, chip->rxff_size - C2H_PKT_BUF - 1); 852e3037485SYan-Hsuan Chuang rtw_write8_set(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1); 853e3037485SYan-Hsuan Chuang 854e3037485SYan-Hsuan Chuang if (!check_hw_ready(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1, 0)) 855e3037485SYan-Hsuan Chuang return -EBUSY; 856e3037485SYan-Hsuan Chuang 857e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_CR + 3, 0); 858e3037485SYan-Hsuan Chuang 859e3037485SYan-Hsuan Chuang return 0; 860e3037485SYan-Hsuan Chuang } 861e3037485SYan-Hsuan Chuang 862e3037485SYan-Hsuan Chuang static int init_h2c(struct rtw_dev *rtwdev) 863e3037485SYan-Hsuan Chuang { 864e3037485SYan-Hsuan Chuang struct rtw_fifo_conf *fifo = &rtwdev->fifo; 865e3037485SYan-Hsuan Chuang u8 value8; 866e3037485SYan-Hsuan Chuang u32 value32; 867e3037485SYan-Hsuan Chuang u32 h2cq_addr; 868e3037485SYan-Hsuan Chuang u32 h2cq_size; 869e3037485SYan-Hsuan Chuang u32 h2cq_free; 870e3037485SYan-Hsuan Chuang u32 wp, rp; 871e3037485SYan-Hsuan Chuang 872e3037485SYan-Hsuan Chuang h2cq_addr = fifo->rsvd_h2cq_addr << TX_PAGE_SIZE_SHIFT; 873e3037485SYan-Hsuan Chuang h2cq_size = RSVD_PG_H2CQ_NUM << TX_PAGE_SIZE_SHIFT; 874e3037485SYan-Hsuan Chuang 875e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_H2C_HEAD); 876e3037485SYan-Hsuan Chuang value32 = (value32 & 0xFFFC0000) | h2cq_addr; 877e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2C_HEAD, value32); 878e3037485SYan-Hsuan Chuang 879e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_H2C_READ_ADDR); 880e3037485SYan-Hsuan Chuang value32 = (value32 & 0xFFFC0000) | h2cq_addr; 881e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2C_READ_ADDR, value32); 882e3037485SYan-Hsuan Chuang 883e3037485SYan-Hsuan Chuang value32 = rtw_read32(rtwdev, REG_H2C_TAIL); 884e3037485SYan-Hsuan Chuang value32 &= 0xFFFC0000; 885e3037485SYan-Hsuan Chuang value32 |= (h2cq_addr + h2cq_size); 886e3037485SYan-Hsuan Chuang rtw_write32(rtwdev, REG_H2C_TAIL, value32); 887e3037485SYan-Hsuan Chuang 888e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_H2C_INFO); 889e3037485SYan-Hsuan Chuang value8 = (u8)((value8 & 0xFC) | 0x01); 890e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_H2C_INFO, value8); 891e3037485SYan-Hsuan Chuang 892e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_H2C_INFO); 893e3037485SYan-Hsuan Chuang value8 = (u8)((value8 & 0xFB) | 0x04); 894e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_H2C_INFO, value8); 895e3037485SYan-Hsuan Chuang 896e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_TXDMA_OFFSET_CHK + 1); 897e3037485SYan-Hsuan Chuang value8 = (u8)((value8 & 0x7f) | 0x80); 898e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_TXDMA_OFFSET_CHK + 1, value8); 899e3037485SYan-Hsuan Chuang 900e3037485SYan-Hsuan Chuang wp = rtw_read32(rtwdev, REG_H2C_PKT_WRITEADDR) & 0x3FFFF; 901e3037485SYan-Hsuan Chuang rp = rtw_read32(rtwdev, REG_H2C_PKT_READADDR) & 0x3FFFF; 902e3037485SYan-Hsuan Chuang h2cq_free = wp >= rp ? h2cq_size - (wp - rp) : rp - wp; 903e3037485SYan-Hsuan Chuang 904e3037485SYan-Hsuan Chuang if (h2cq_size != h2cq_free) { 905e3037485SYan-Hsuan Chuang rtw_err(rtwdev, "H2C queue mismatch\n"); 906e3037485SYan-Hsuan Chuang return -EINVAL; 907e3037485SYan-Hsuan Chuang } 908e3037485SYan-Hsuan Chuang 909e3037485SYan-Hsuan Chuang return 0; 910e3037485SYan-Hsuan Chuang } 911e3037485SYan-Hsuan Chuang 912e3037485SYan-Hsuan Chuang static int rtw_init_trx_cfg(struct rtw_dev *rtwdev) 913e3037485SYan-Hsuan Chuang { 914e3037485SYan-Hsuan Chuang int ret; 915e3037485SYan-Hsuan Chuang 916e3037485SYan-Hsuan Chuang ret = txdma_queue_mapping(rtwdev); 917e3037485SYan-Hsuan Chuang if (ret) 918e3037485SYan-Hsuan Chuang return ret; 919e3037485SYan-Hsuan Chuang 920e3037485SYan-Hsuan Chuang ret = priority_queue_cfg(rtwdev); 921e3037485SYan-Hsuan Chuang if (ret) 922e3037485SYan-Hsuan Chuang return ret; 923e3037485SYan-Hsuan Chuang 924e3037485SYan-Hsuan Chuang ret = init_h2c(rtwdev); 925e3037485SYan-Hsuan Chuang if (ret) 926e3037485SYan-Hsuan Chuang return ret; 927e3037485SYan-Hsuan Chuang 928e3037485SYan-Hsuan Chuang return 0; 929e3037485SYan-Hsuan Chuang } 930e3037485SYan-Hsuan Chuang 931e3037485SYan-Hsuan Chuang static int rtw_drv_info_cfg(struct rtw_dev *rtwdev) 932e3037485SYan-Hsuan Chuang { 933e3037485SYan-Hsuan Chuang u8 value8; 934e3037485SYan-Hsuan Chuang 935e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE); 936e3037485SYan-Hsuan Chuang value8 = rtw_read8(rtwdev, REG_TRXFF_BNDY + 1); 937e3037485SYan-Hsuan Chuang value8 &= 0xF0; 938e3037485SYan-Hsuan Chuang /* For rxdesc len = 0 issue */ 939e3037485SYan-Hsuan Chuang value8 |= 0xF; 940e3037485SYan-Hsuan Chuang rtw_write8(rtwdev, REG_TRXFF_BNDY + 1, value8); 941e3037485SYan-Hsuan Chuang rtw_write32_set(rtwdev, REG_RCR, BIT_APP_PHYSTS); 942e3037485SYan-Hsuan Chuang rtw_write32_clr(rtwdev, REG_WMAC_OPTION_FUNCTION + 4, BIT(8) | BIT(9)); 943e3037485SYan-Hsuan Chuang 944e3037485SYan-Hsuan Chuang return 0; 945e3037485SYan-Hsuan Chuang } 946e3037485SYan-Hsuan Chuang 947e3037485SYan-Hsuan Chuang int rtw_mac_init(struct rtw_dev *rtwdev) 948e3037485SYan-Hsuan Chuang { 949e3037485SYan-Hsuan Chuang struct rtw_chip_info *chip = rtwdev->chip; 950e3037485SYan-Hsuan Chuang int ret; 951e3037485SYan-Hsuan Chuang 952e3037485SYan-Hsuan Chuang ret = rtw_init_trx_cfg(rtwdev); 953e3037485SYan-Hsuan Chuang if (ret) 954e3037485SYan-Hsuan Chuang return ret; 955e3037485SYan-Hsuan Chuang 956e3037485SYan-Hsuan Chuang ret = chip->ops->mac_init(rtwdev); 957e3037485SYan-Hsuan Chuang if (ret) 958e3037485SYan-Hsuan Chuang return ret; 959e3037485SYan-Hsuan Chuang 960e3037485SYan-Hsuan Chuang ret = rtw_drv_info_cfg(rtwdev); 961e3037485SYan-Hsuan Chuang if (ret) 962e3037485SYan-Hsuan Chuang return ret; 963e3037485SYan-Hsuan Chuang 964e3037485SYan-Hsuan Chuang return 0; 965e3037485SYan-Hsuan Chuang } 966