162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2018-2019 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "main.h" 662306a36Sopenharmony_ci#include "mac.h" 762306a36Sopenharmony_ci#include "reg.h" 862306a36Sopenharmony_ci#include "fw.h" 962306a36Sopenharmony_ci#include "debug.h" 1062306a36Sopenharmony_ci#include "sdio.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_civoid rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, 1362306a36Sopenharmony_ci u8 primary_ch_idx) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci u8 txsc40 = 0, txsc20 = 0; 1662306a36Sopenharmony_ci u32 value32; 1762306a36Sopenharmony_ci u8 value8; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci txsc20 = primary_ch_idx; 2062306a36Sopenharmony_ci if (bw == RTW_CHANNEL_WIDTH_80) { 2162306a36Sopenharmony_ci if (txsc20 == RTW_SC_20_UPPER || txsc20 == RTW_SC_20_UPMOST) 2262306a36Sopenharmony_ci txsc40 = RTW_SC_40_UPPER; 2362306a36Sopenharmony_ci else 2462306a36Sopenharmony_ci txsc40 = RTW_SC_40_LOWER; 2562306a36Sopenharmony_ci } 2662306a36Sopenharmony_ci rtw_write8(rtwdev, REG_DATA_SC, 2762306a36Sopenharmony_ci BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40)); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_WMAC_TRXPTCL_CTL); 3062306a36Sopenharmony_ci value32 &= ~BIT_RFMOD; 3162306a36Sopenharmony_ci switch (bw) { 3262306a36Sopenharmony_ci case RTW_CHANNEL_WIDTH_80: 3362306a36Sopenharmony_ci value32 |= BIT_RFMOD_80M; 3462306a36Sopenharmony_ci break; 3562306a36Sopenharmony_ci case RTW_CHANNEL_WIDTH_40: 3662306a36Sopenharmony_ci value32 |= BIT_RFMOD_40M; 3762306a36Sopenharmony_ci break; 3862306a36Sopenharmony_ci case RTW_CHANNEL_WIDTH_20: 3962306a36Sopenharmony_ci default: 4062306a36Sopenharmony_ci break; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci rtw_write32(rtwdev, REG_WMAC_TRXPTCL_CTL, value32); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (rtw_chip_wcpu_11n(rtwdev)) 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_AFE_CTRL1) & ~(BIT_MAC_CLK_SEL); 4862306a36Sopenharmony_ci value32 |= (MAC_CLK_HW_DEF_80M << BIT_SHIFT_MAC_CLK_SEL); 4962306a36Sopenharmony_ci rtw_write32(rtwdev, REG_AFE_CTRL1, value32); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci rtw_write8(rtwdev, REG_USTIME_TSF, MAC_CLK_SPEED); 5262306a36Sopenharmony_ci rtw_write8(rtwdev, REG_USTIME_EDCA, MAC_CLK_SPEED); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci value8 = rtw_read8(rtwdev, REG_CCK_CHECK); 5562306a36Sopenharmony_ci value8 = value8 & ~BIT_CHECK_CCK_EN; 5662306a36Sopenharmony_ci if (IS_CH_5G_BAND(channel)) 5762306a36Sopenharmony_ci value8 |= BIT_CHECK_CCK_EN; 5862306a36Sopenharmony_ci rtw_write8(rtwdev, REG_CCK_CHECK, value8); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_set_channel_mac); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci unsigned int retry; 6562306a36Sopenharmony_ci u32 value32; 6662306a36Sopenharmony_ci u8 value8; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci rtw_write8(rtwdev, REG_RSV_CTRL, 0); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (rtw_chip_wcpu_11n(rtwdev)) { 7162306a36Sopenharmony_ci if (rtw_read32(rtwdev, REG_SYS_CFG1) & BIT_LDO) 7262306a36Sopenharmony_ci rtw_write8(rtwdev, REG_LDO_SWR_CTRL, LDO_SEL); 7362306a36Sopenharmony_ci else 7462306a36Sopenharmony_ci rtw_write8(rtwdev, REG_LDO_SWR_CTRL, SPS_SEL); 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci switch (rtw_hci_type(rtwdev)) { 7962306a36Sopenharmony_ci case RTW_HCI_TYPE_PCIE: 8062306a36Sopenharmony_ci rtw_write32_set(rtwdev, REG_HCI_OPT_CTRL, BIT_USB_SUS_DIS); 8162306a36Sopenharmony_ci break; 8262306a36Sopenharmony_ci case RTW_HCI_TYPE_SDIO: 8362306a36Sopenharmony_ci rtw_write8_clr(rtwdev, REG_SDIO_HSUS_CTRL, BIT_HCI_SUS_REQ); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci for (retry = 0; retry < RTW_PWR_POLLING_CNT; retry++) { 8662306a36Sopenharmony_ci if (rtw_read8(rtwdev, REG_SDIO_HSUS_CTRL) & BIT_HCI_RESUME_RDY) 8762306a36Sopenharmony_ci break; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci usleep_range(10, 50); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (retry == RTW_PWR_POLLING_CNT) { 9362306a36Sopenharmony_ci rtw_err(rtwdev, "failed to poll REG_SDIO_HSUS_CTRL[1]"); 9462306a36Sopenharmony_ci return -ETIMEDOUT; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (rtw_sdio_is_sdio30_supported(rtwdev)) 9862306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_HCI_OPT_CTRL + 2, 9962306a36Sopenharmony_ci BIT_SDIO_PAD_E5 >> 16); 10062306a36Sopenharmony_ci else 10162306a36Sopenharmony_ci rtw_write8_clr(rtwdev, REG_HCI_OPT_CTRL + 2, 10262306a36Sopenharmony_ci BIT_SDIO_PAD_E5 >> 16); 10362306a36Sopenharmony_ci break; 10462306a36Sopenharmony_ci case RTW_HCI_TYPE_USB: 10562306a36Sopenharmony_ci break; 10662306a36Sopenharmony_ci default: 10762306a36Sopenharmony_ci return -EINVAL; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* config PIN Mux */ 11162306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_PAD_CTRL1); 11262306a36Sopenharmony_ci value32 |= BIT_PAPE_WLBT_SEL | BIT_LNAON_WLBT_SEL; 11362306a36Sopenharmony_ci rtw_write32(rtwdev, REG_PAD_CTRL1, value32); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_LED_CFG); 11662306a36Sopenharmony_ci value32 &= ~(BIT_PAPE_SEL_EN | BIT_LNAON_SEL_EN); 11762306a36Sopenharmony_ci rtw_write32(rtwdev, REG_LED_CFG, value32); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_GPIO_MUXCFG); 12062306a36Sopenharmony_ci value32 |= BIT_WLRFE_4_5_EN; 12162306a36Sopenharmony_ci rtw_write32(rtwdev, REG_GPIO_MUXCFG, value32); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* disable BB/RF */ 12462306a36Sopenharmony_ci value8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN); 12562306a36Sopenharmony_ci value8 &= ~(BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST); 12662306a36Sopenharmony_ci rtw_write8(rtwdev, REG_SYS_FUNC_EN, value8); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci value8 = rtw_read8(rtwdev, REG_RF_CTRL); 12962306a36Sopenharmony_ci value8 &= ~(BIT_RF_SDM_RSTB | BIT_RF_RSTB | BIT_RF_EN); 13062306a36Sopenharmony_ci rtw_write8(rtwdev, REG_RF_CTRL, value8); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_WLRF1); 13362306a36Sopenharmony_ci value32 &= ~BIT_WLRF1_BBRF_EN; 13462306a36Sopenharmony_ci rtw_write32(rtwdev, REG_WLRF1, value32); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic bool do_pwr_poll_cmd(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci u32 val; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci target &= mask; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return read_poll_timeout_atomic(rtw_read8, val, (val & mask) == target, 14662306a36Sopenharmony_ci 50, 50 * RTW_PWR_POLLING_CNT, false, 14762306a36Sopenharmony_ci rtwdev, addr) == 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int rtw_pwr_cmd_polling(struct rtw_dev *rtwdev, 15162306a36Sopenharmony_ci const struct rtw_pwr_seq_cmd *cmd) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci u8 value; 15462306a36Sopenharmony_ci u32 offset; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (cmd->base == RTW_PWR_ADDR_SDIO) 15762306a36Sopenharmony_ci offset = cmd->offset | SDIO_LOCAL_OFFSET; 15862306a36Sopenharmony_ci else 15962306a36Sopenharmony_ci offset = cmd->offset; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (do_pwr_poll_cmd(rtwdev, offset, cmd->mask, cmd->value)) 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (rtw_hci_type(rtwdev) != RTW_HCI_TYPE_PCIE) 16562306a36Sopenharmony_ci goto err; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* if PCIE, toggle BIT_PFM_WOWL and try again */ 16862306a36Sopenharmony_ci value = rtw_read8(rtwdev, REG_SYS_PW_CTRL); 16962306a36Sopenharmony_ci if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D) 17062306a36Sopenharmony_ci rtw_write8(rtwdev, REG_SYS_PW_CTRL, value & ~BIT_PFM_WOWL); 17162306a36Sopenharmony_ci rtw_write8(rtwdev, REG_SYS_PW_CTRL, value | BIT_PFM_WOWL); 17262306a36Sopenharmony_ci rtw_write8(rtwdev, REG_SYS_PW_CTRL, value & ~BIT_PFM_WOWL); 17362306a36Sopenharmony_ci if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D) 17462306a36Sopenharmony_ci rtw_write8(rtwdev, REG_SYS_PW_CTRL, value | BIT_PFM_WOWL); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (do_pwr_poll_cmd(rtwdev, offset, cmd->mask, cmd->value)) 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cierr: 18062306a36Sopenharmony_ci rtw_err(rtwdev, "failed to poll offset=0x%x mask=0x%x value=0x%x\n", 18162306a36Sopenharmony_ci offset, cmd->mask, cmd->value); 18262306a36Sopenharmony_ci return -EBUSY; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int rtw_sub_pwr_seq_parser(struct rtw_dev *rtwdev, u8 intf_mask, 18662306a36Sopenharmony_ci u8 cut_mask, 18762306a36Sopenharmony_ci const struct rtw_pwr_seq_cmd *cmd) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci const struct rtw_pwr_seq_cmd *cur_cmd; 19062306a36Sopenharmony_ci u32 offset; 19162306a36Sopenharmony_ci u8 value; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci for (cur_cmd = cmd; cur_cmd->cmd != RTW_PWR_CMD_END; cur_cmd++) { 19462306a36Sopenharmony_ci if (!(cur_cmd->intf_mask & intf_mask) || 19562306a36Sopenharmony_ci !(cur_cmd->cut_mask & cut_mask)) 19662306a36Sopenharmony_ci continue; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci switch (cur_cmd->cmd) { 19962306a36Sopenharmony_ci case RTW_PWR_CMD_WRITE: 20062306a36Sopenharmony_ci offset = cur_cmd->offset; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (cur_cmd->base == RTW_PWR_ADDR_SDIO) 20362306a36Sopenharmony_ci offset |= SDIO_LOCAL_OFFSET; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci value = rtw_read8(rtwdev, offset); 20662306a36Sopenharmony_ci value &= ~cur_cmd->mask; 20762306a36Sopenharmony_ci value |= (cur_cmd->value & cur_cmd->mask); 20862306a36Sopenharmony_ci rtw_write8(rtwdev, offset, value); 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci case RTW_PWR_CMD_POLLING: 21162306a36Sopenharmony_ci if (rtw_pwr_cmd_polling(rtwdev, cur_cmd)) 21262306a36Sopenharmony_ci return -EBUSY; 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci case RTW_PWR_CMD_DELAY: 21562306a36Sopenharmony_ci if (cur_cmd->value == RTW_PWR_DELAY_US) 21662306a36Sopenharmony_ci udelay(cur_cmd->offset); 21762306a36Sopenharmony_ci else 21862306a36Sopenharmony_ci mdelay(cur_cmd->offset); 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci case RTW_PWR_CMD_READ: 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci default: 22362306a36Sopenharmony_ci return -EINVAL; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, 23162306a36Sopenharmony_ci const struct rtw_pwr_seq_cmd **cmd_seq) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci u8 cut_mask; 23462306a36Sopenharmony_ci u8 intf_mask; 23562306a36Sopenharmony_ci u8 cut; 23662306a36Sopenharmony_ci u32 idx = 0; 23762306a36Sopenharmony_ci const struct rtw_pwr_seq_cmd *cmd; 23862306a36Sopenharmony_ci int ret; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci cut = rtwdev->hal.cut_version; 24162306a36Sopenharmony_ci cut_mask = cut_version_to_mask(cut); 24262306a36Sopenharmony_ci switch (rtw_hci_type(rtwdev)) { 24362306a36Sopenharmony_ci case RTW_HCI_TYPE_PCIE: 24462306a36Sopenharmony_ci intf_mask = RTW_PWR_INTF_PCI_MSK; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case RTW_HCI_TYPE_USB: 24762306a36Sopenharmony_ci intf_mask = RTW_PWR_INTF_USB_MSK; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case RTW_HCI_TYPE_SDIO: 25062306a36Sopenharmony_ci intf_mask = RTW_PWR_INTF_SDIO_MSK; 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci default: 25362306a36Sopenharmony_ci return -EINVAL; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci do { 25762306a36Sopenharmony_ci cmd = cmd_seq[idx]; 25862306a36Sopenharmony_ci if (!cmd) 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci ret = rtw_sub_pwr_seq_parser(rtwdev, intf_mask, cut_mask, cmd); 26262306a36Sopenharmony_ci if (ret) 26362306a36Sopenharmony_ci return ret; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci idx++; 26662306a36Sopenharmony_ci } while (1); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 27462306a36Sopenharmony_ci const struct rtw_pwr_seq_cmd **pwr_seq; 27562306a36Sopenharmony_ci u32 imr = 0; 27662306a36Sopenharmony_ci u8 rpwm; 27762306a36Sopenharmony_ci bool cur_pwr; 27862306a36Sopenharmony_ci int ret; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (rtw_chip_wcpu_11ac(rtwdev)) { 28162306a36Sopenharmony_ci rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Check FW still exist or not */ 28462306a36Sopenharmony_ci if (rtw_read16(rtwdev, REG_MCUFW_CTRL) == 0xC078) { 28562306a36Sopenharmony_ci rpwm = (rpwm ^ BIT_RPWM_TOGGLE) & BIT_RPWM_TOGGLE; 28662306a36Sopenharmony_ci rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, rpwm); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (rtw_read8(rtwdev, REG_CR) == 0xea) 29162306a36Sopenharmony_ci cur_pwr = false; 29262306a36Sopenharmony_ci else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && 29362306a36Sopenharmony_ci (rtw_read8(rtwdev, REG_SYS_STATUS1 + 1) & BIT(0))) 29462306a36Sopenharmony_ci cur_pwr = false; 29562306a36Sopenharmony_ci else 29662306a36Sopenharmony_ci cur_pwr = true; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (pwr_on == cur_pwr) 29962306a36Sopenharmony_ci return -EALREADY; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) { 30262306a36Sopenharmony_ci imr = rtw_read32(rtwdev, REG_SDIO_HIMR); 30362306a36Sopenharmony_ci rtw_write32(rtwdev, REG_SDIO_HIMR, 0); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!pwr_on) 30762306a36Sopenharmony_ci clear_bit(RTW_FLAG_POWERON, rtwdev->flags); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq; 31062306a36Sopenharmony_ci ret = rtw_pwr_seq_parser(rtwdev, pwr_seq); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) 31362306a36Sopenharmony_ci rtw_write32(rtwdev, REG_SDIO_HIMR, imr); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!ret && pwr_on) 31662306a36Sopenharmony_ci set_bit(RTW_FLAG_POWERON, rtwdev->flags); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return ret; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int __rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci u8 sys_func_en = rtwdev->chip->sys_func_en; 32462306a36Sopenharmony_ci u8 value8; 32562306a36Sopenharmony_ci u32 value, tmp; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci value = rtw_read32(rtwdev, REG_CPU_DMEM_CON); 32862306a36Sopenharmony_ci value |= BIT_WL_PLATFORM_RST | BIT_DDMA_EN; 32962306a36Sopenharmony_ci rtw_write32(rtwdev, REG_CPU_DMEM_CON, value); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en); 33262306a36Sopenharmony_ci value8 = (rtw_read8(rtwdev, REG_CR_EXT + 3) & 0xF0) | 0x0C; 33362306a36Sopenharmony_ci rtw_write8(rtwdev, REG_CR_EXT + 3, value8); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* disable boot-from-flash for driver's DL FW */ 33662306a36Sopenharmony_ci tmp = rtw_read32(rtwdev, REG_MCUFW_CTRL); 33762306a36Sopenharmony_ci if (tmp & BIT_BOOT_FSPI_EN) { 33862306a36Sopenharmony_ci rtw_write32(rtwdev, REG_MCUFW_CTRL, tmp & (~BIT_BOOT_FSPI_EN)); 33962306a36Sopenharmony_ci value = rtw_read32(rtwdev, REG_GPIO_MUXCFG) & (~BIT_FSPI_EN); 34062306a36Sopenharmony_ci rtw_write32(rtwdev, REG_GPIO_MUXCFG, value); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int __rtw_mac_init_system_cfg_legacy(struct rtw_dev *rtwdev) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci rtw_write8(rtwdev, REG_CR, 0xff); 34962306a36Sopenharmony_ci mdelay(2); 35062306a36Sopenharmony_ci rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0x7f); 35162306a36Sopenharmony_ci mdelay(2); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_SYS_CLKR, BIT_WAKEPAD_EN); 35462306a36Sopenharmony_ci rtw_write16_clr(rtwdev, REG_GPIO_MUXCFG, BIT_EN_SIC); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci rtw_write16(rtwdev, REG_CR, 0x2ff); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci if (rtw_chip_wcpu_11n(rtwdev)) 36462306a36Sopenharmony_ci return __rtw_mac_init_system_cfg_legacy(rtwdev); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return __rtw_mac_init_system_cfg(rtwdev); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ciint rtw_mac_power_on(struct rtw_dev *rtwdev) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci int ret = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci ret = rtw_mac_pre_system_cfg(rtwdev); 37462306a36Sopenharmony_ci if (ret) 37562306a36Sopenharmony_ci goto err; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci ret = rtw_mac_power_switch(rtwdev, true); 37862306a36Sopenharmony_ci if (ret == -EALREADY) { 37962306a36Sopenharmony_ci rtw_mac_power_switch(rtwdev, false); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci ret = rtw_mac_pre_system_cfg(rtwdev); 38262306a36Sopenharmony_ci if (ret) 38362306a36Sopenharmony_ci goto err; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ret = rtw_mac_power_switch(rtwdev, true); 38662306a36Sopenharmony_ci if (ret) 38762306a36Sopenharmony_ci goto err; 38862306a36Sopenharmony_ci } else if (ret) { 38962306a36Sopenharmony_ci goto err; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci ret = rtw_mac_init_system_cfg(rtwdev); 39362306a36Sopenharmony_ci if (ret) 39462306a36Sopenharmony_ci goto err; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cierr: 39962306a36Sopenharmony_ci rtw_err(rtwdev, "mac power on failed"); 40062306a36Sopenharmony_ci return ret; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_civoid rtw_mac_power_off(struct rtw_dev *rtwdev) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci rtw_mac_power_switch(rtwdev, false); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic bool check_firmware_size(const u8 *data, u32 size) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data; 41162306a36Sopenharmony_ci u32 dmem_size; 41262306a36Sopenharmony_ci u32 imem_size; 41362306a36Sopenharmony_ci u32 emem_size; 41462306a36Sopenharmony_ci u32 real_size; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci dmem_size = le32_to_cpu(fw_hdr->dmem_size); 41762306a36Sopenharmony_ci imem_size = le32_to_cpu(fw_hdr->imem_size); 41862306a36Sopenharmony_ci emem_size = (fw_hdr->mem_usage & BIT(4)) ? 41962306a36Sopenharmony_ci le32_to_cpu(fw_hdr->emem_size) : 0; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci dmem_size += FW_HDR_CHKSUM_SIZE; 42262306a36Sopenharmony_ci imem_size += FW_HDR_CHKSUM_SIZE; 42362306a36Sopenharmony_ci emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0; 42462306a36Sopenharmony_ci real_size = FW_HDR_SIZE + dmem_size + imem_size + emem_size; 42562306a36Sopenharmony_ci if (real_size != size) 42662306a36Sopenharmony_ci return false; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return true; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void wlan_cpu_enable(struct rtw_dev *rtwdev, bool enable) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci if (enable) { 43462306a36Sopenharmony_ci /* cpu io interface enable */ 43562306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* cpu enable */ 43862306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 43962306a36Sopenharmony_ci } else { 44062306a36Sopenharmony_ci /* cpu io interface disable */ 44162306a36Sopenharmony_ci rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* cpu disable */ 44462306a36Sopenharmony_ci rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci#define DLFW_RESTORE_REG_NUM 6 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void download_firmware_reg_backup(struct rtw_dev *rtwdev, 45162306a36Sopenharmony_ci struct rtw_backup_info *bckp) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci u8 tmp; 45462306a36Sopenharmony_ci u8 bckp_idx = 0; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* set HIQ to hi priority */ 45762306a36Sopenharmony_ci bckp[bckp_idx].len = 1; 45862306a36Sopenharmony_ci bckp[bckp_idx].reg = REG_TXDMA_PQ_MAP + 1; 45962306a36Sopenharmony_ci bckp[bckp_idx].val = rtw_read8(rtwdev, REG_TXDMA_PQ_MAP + 1); 46062306a36Sopenharmony_ci bckp_idx++; 46162306a36Sopenharmony_ci tmp = RTW_DMA_MAPPING_HIGH << 6; 46262306a36Sopenharmony_ci rtw_write8(rtwdev, REG_TXDMA_PQ_MAP + 1, tmp); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* DLFW only use HIQ, map HIQ to hi priority */ 46562306a36Sopenharmony_ci bckp[bckp_idx].len = 1; 46662306a36Sopenharmony_ci bckp[bckp_idx].reg = REG_CR; 46762306a36Sopenharmony_ci bckp[bckp_idx].val = rtw_read8(rtwdev, REG_CR); 46862306a36Sopenharmony_ci bckp_idx++; 46962306a36Sopenharmony_ci bckp[bckp_idx].len = 4; 47062306a36Sopenharmony_ci bckp[bckp_idx].reg = REG_H2CQ_CSR; 47162306a36Sopenharmony_ci bckp[bckp_idx].val = BIT_H2CQ_FULL; 47262306a36Sopenharmony_ci bckp_idx++; 47362306a36Sopenharmony_ci tmp = BIT_HCI_TXDMA_EN | BIT_TXDMA_EN; 47462306a36Sopenharmony_ci rtw_write8(rtwdev, REG_CR, tmp); 47562306a36Sopenharmony_ci rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* Config hi priority queue and public priority queue page number */ 47862306a36Sopenharmony_ci bckp[bckp_idx].len = 2; 47962306a36Sopenharmony_ci bckp[bckp_idx].reg = REG_FIFOPAGE_INFO_1; 48062306a36Sopenharmony_ci bckp[bckp_idx].val = rtw_read16(rtwdev, REG_FIFOPAGE_INFO_1); 48162306a36Sopenharmony_ci bckp_idx++; 48262306a36Sopenharmony_ci bckp[bckp_idx].len = 4; 48362306a36Sopenharmony_ci bckp[bckp_idx].reg = REG_RQPN_CTRL_2; 48462306a36Sopenharmony_ci bckp[bckp_idx].val = rtw_read32(rtwdev, REG_RQPN_CTRL_2) | BIT_LD_RQPN; 48562306a36Sopenharmony_ci bckp_idx++; 48662306a36Sopenharmony_ci rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, 0x200); 48762306a36Sopenharmony_ci rtw_write32(rtwdev, REG_RQPN_CTRL_2, bckp[bckp_idx - 1].val); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) 49062306a36Sopenharmony_ci rtw_read32(rtwdev, REG_SDIO_FREE_TXPG); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Disable beacon related functions */ 49362306a36Sopenharmony_ci tmp = rtw_read8(rtwdev, REG_BCN_CTRL); 49462306a36Sopenharmony_ci bckp[bckp_idx].len = 1; 49562306a36Sopenharmony_ci bckp[bckp_idx].reg = REG_BCN_CTRL; 49662306a36Sopenharmony_ci bckp[bckp_idx].val = tmp; 49762306a36Sopenharmony_ci bckp_idx++; 49862306a36Sopenharmony_ci tmp = (u8)((tmp & (~BIT_EN_BCN_FUNCTION)) | BIT_DIS_TSF_UDT); 49962306a36Sopenharmony_ci rtw_write8(rtwdev, REG_BCN_CTRL, tmp); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci WARN(bckp_idx != DLFW_RESTORE_REG_NUM, "wrong backup number\n"); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic void download_firmware_reset_platform(struct rtw_dev *rtwdev) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci rtw_write8_clr(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16); 50762306a36Sopenharmony_ci rtw_write8_clr(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8); 50862306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16); 50962306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic void download_firmware_reg_restore(struct rtw_dev *rtwdev, 51362306a36Sopenharmony_ci struct rtw_backup_info *bckp, 51462306a36Sopenharmony_ci u8 bckp_num) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci rtw_restore_reg(rtwdev, bckp, bckp_num); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci#define TX_DESC_SIZE 48 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int send_firmware_pkt_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, 52262306a36Sopenharmony_ci const u8 *data, u32 size) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci u8 *buf; 52562306a36Sopenharmony_ci int ret; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci buf = kmemdup(data, size, GFP_KERNEL); 52862306a36Sopenharmony_ci if (!buf) 52962306a36Sopenharmony_ci return -ENOMEM; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci ret = rtw_fw_write_data_rsvd_page(rtwdev, pg_addr, buf, size); 53262306a36Sopenharmony_ci kfree(buf); 53362306a36Sopenharmony_ci return ret; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic int 53762306a36Sopenharmony_cisend_firmware_pkt(struct rtw_dev *rtwdev, u16 pg_addr, const u8 *data, u32 size) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci int ret; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && 54262306a36Sopenharmony_ci !((size + TX_DESC_SIZE) & (512 - 1))) 54362306a36Sopenharmony_ci size += 1; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ret = send_firmware_pkt_rsvd_page(rtwdev, pg_addr, data, size); 54662306a36Sopenharmony_ci if (ret) 54762306a36Sopenharmony_ci rtw_err(rtwdev, "failed to download rsvd page\n"); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return ret; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic int 55362306a36Sopenharmony_ciiddma_enable(struct rtw_dev *rtwdev, u32 src, u32 dst, u32 ctrl) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci rtw_write32(rtwdev, REG_DDMA_CH0SA, src); 55662306a36Sopenharmony_ci rtw_write32(rtwdev, REG_DDMA_CH0DA, dst); 55762306a36Sopenharmony_ci rtw_write32(rtwdev, REG_DDMA_CH0CTRL, ctrl); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) 56062306a36Sopenharmony_ci return -EBUSY; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic int iddma_download_firmware(struct rtw_dev *rtwdev, u32 src, u32 dst, 56662306a36Sopenharmony_ci u32 len, u8 first) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci u32 ch0_ctrl = BIT_DDMACH0_CHKSUM_EN | BIT_DDMACH0_OWN; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) 57162306a36Sopenharmony_ci return -EBUSY; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci ch0_ctrl |= len & BIT_MASK_DDMACH0_DLEN; 57462306a36Sopenharmony_ci if (!first) 57562306a36Sopenharmony_ci ch0_ctrl |= BIT_DDMACH0_CHKSUM_CONT; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (iddma_enable(rtwdev, src, dst, ch0_ctrl)) 57862306a36Sopenharmony_ci return -EBUSY; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci return 0; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ciint rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci u32 ch0_ctrl = BIT_DDMACH0_OWN | BIT_DDMACH0_DDMA_MODE; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) { 58862306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, "busy to start ddma\n"); 58962306a36Sopenharmony_ci return -EBUSY; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci ch0_ctrl |= size & BIT_MASK_DDMACH0_DLEN; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (iddma_enable(rtwdev, ocp_src, OCPBASE_RXBUF_FW_88XX, ch0_ctrl)) { 59562306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, "busy to complete ddma\n"); 59662306a36Sopenharmony_ci return -EBUSY; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic bool 60362306a36Sopenharmony_cicheck_fw_checksum(struct rtw_dev *rtwdev, u32 addr) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci u8 fw_ctrl; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci fw_ctrl = rtw_read8(rtwdev, REG_MCUFW_CTRL); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (rtw_read32(rtwdev, REG_DDMA_CH0CTRL) & BIT_DDMACH0_CHKSUM_STS) { 61062306a36Sopenharmony_ci if (addr < OCPBASE_DMEM_88XX) { 61162306a36Sopenharmony_ci fw_ctrl |= BIT_IMEM_DW_OK; 61262306a36Sopenharmony_ci fw_ctrl &= ~BIT_IMEM_CHKSUM_OK; 61362306a36Sopenharmony_ci rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 61462306a36Sopenharmony_ci } else { 61562306a36Sopenharmony_ci fw_ctrl |= BIT_DMEM_DW_OK; 61662306a36Sopenharmony_ci fw_ctrl &= ~BIT_DMEM_CHKSUM_OK; 61762306a36Sopenharmony_ci rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci rtw_err(rtwdev, "invalid fw checksum\n"); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return false; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (addr < OCPBASE_DMEM_88XX) { 62662306a36Sopenharmony_ci fw_ctrl |= (BIT_IMEM_DW_OK | BIT_IMEM_CHKSUM_OK); 62762306a36Sopenharmony_ci rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 62862306a36Sopenharmony_ci } else { 62962306a36Sopenharmony_ci fw_ctrl |= (BIT_DMEM_DW_OK | BIT_DMEM_CHKSUM_OK); 63062306a36Sopenharmony_ci rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return true; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic int 63762306a36Sopenharmony_cidownload_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data, 63862306a36Sopenharmony_ci u32 src, u32 dst, u32 size) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 64162306a36Sopenharmony_ci u32 desc_size = chip->tx_pkt_desc_sz; 64262306a36Sopenharmony_ci u8 first_part; 64362306a36Sopenharmony_ci u32 mem_offset; 64462306a36Sopenharmony_ci u32 residue_size; 64562306a36Sopenharmony_ci u32 pkt_size; 64662306a36Sopenharmony_ci u32 max_size = 0x1000; 64762306a36Sopenharmony_ci u32 val; 64862306a36Sopenharmony_ci int ret; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci mem_offset = 0; 65162306a36Sopenharmony_ci first_part = 1; 65262306a36Sopenharmony_ci residue_size = size; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci val = rtw_read32(rtwdev, REG_DDMA_CH0CTRL); 65562306a36Sopenharmony_ci val |= BIT_DDMACH0_RESET_CHKSUM_STS; 65662306a36Sopenharmony_ci rtw_write32(rtwdev, REG_DDMA_CH0CTRL, val); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci while (residue_size) { 65962306a36Sopenharmony_ci if (residue_size >= max_size) 66062306a36Sopenharmony_ci pkt_size = max_size; 66162306a36Sopenharmony_ci else 66262306a36Sopenharmony_ci pkt_size = residue_size; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci ret = send_firmware_pkt(rtwdev, (u16)(src >> 7), 66562306a36Sopenharmony_ci data + mem_offset, pkt_size); 66662306a36Sopenharmony_ci if (ret) 66762306a36Sopenharmony_ci return ret; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci ret = iddma_download_firmware(rtwdev, OCPBASE_TXBUF_88XX + 67062306a36Sopenharmony_ci src + desc_size, 67162306a36Sopenharmony_ci dst + mem_offset, pkt_size, 67262306a36Sopenharmony_ci first_part); 67362306a36Sopenharmony_ci if (ret) 67462306a36Sopenharmony_ci return ret; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci first_part = 0; 67762306a36Sopenharmony_ci mem_offset += pkt_size; 67862306a36Sopenharmony_ci residue_size -= pkt_size; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (!check_fw_checksum(rtwdev, dst)) 68262306a36Sopenharmony_ci return -EINVAL; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return 0; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic int 68862306a36Sopenharmony_cistart_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data; 69162306a36Sopenharmony_ci const u8 *cur_fw; 69262306a36Sopenharmony_ci u16 val; 69362306a36Sopenharmony_ci u32 imem_size; 69462306a36Sopenharmony_ci u32 dmem_size; 69562306a36Sopenharmony_ci u32 emem_size; 69662306a36Sopenharmony_ci u32 addr; 69762306a36Sopenharmony_ci int ret; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci dmem_size = le32_to_cpu(fw_hdr->dmem_size); 70062306a36Sopenharmony_ci imem_size = le32_to_cpu(fw_hdr->imem_size); 70162306a36Sopenharmony_ci emem_size = (fw_hdr->mem_usage & BIT(4)) ? 70262306a36Sopenharmony_ci le32_to_cpu(fw_hdr->emem_size) : 0; 70362306a36Sopenharmony_ci dmem_size += FW_HDR_CHKSUM_SIZE; 70462306a36Sopenharmony_ci imem_size += FW_HDR_CHKSUM_SIZE; 70562306a36Sopenharmony_ci emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci val = (u16)(rtw_read16(rtwdev, REG_MCUFW_CTRL) & 0x3800); 70862306a36Sopenharmony_ci val |= BIT_MCUFWDL_EN; 70962306a36Sopenharmony_ci rtw_write16(rtwdev, REG_MCUFW_CTRL, val); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci cur_fw = data + FW_HDR_SIZE; 71262306a36Sopenharmony_ci addr = le32_to_cpu(fw_hdr->dmem_addr); 71362306a36Sopenharmony_ci addr &= ~BIT(31); 71462306a36Sopenharmony_ci ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, dmem_size); 71562306a36Sopenharmony_ci if (ret) 71662306a36Sopenharmony_ci return ret; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci cur_fw = data + FW_HDR_SIZE + dmem_size; 71962306a36Sopenharmony_ci addr = le32_to_cpu(fw_hdr->imem_addr); 72062306a36Sopenharmony_ci addr &= ~BIT(31); 72162306a36Sopenharmony_ci ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, imem_size); 72262306a36Sopenharmony_ci if (ret) 72362306a36Sopenharmony_ci return ret; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (emem_size) { 72662306a36Sopenharmony_ci cur_fw = data + FW_HDR_SIZE + dmem_size + imem_size; 72762306a36Sopenharmony_ci addr = le32_to_cpu(fw_hdr->emem_addr); 72862306a36Sopenharmony_ci addr &= ~BIT(31); 72962306a36Sopenharmony_ci ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, 73062306a36Sopenharmony_ci emem_size); 73162306a36Sopenharmony_ci if (ret) 73262306a36Sopenharmony_ci return ret; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic int download_firmware_validate(struct rtw_dev *rtwdev) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci u32 fw_key; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, FW_READY_MASK, FW_READY)) { 74362306a36Sopenharmony_ci fw_key = rtw_read32(rtwdev, REG_FW_DBG7) & FW_KEY_MASK; 74462306a36Sopenharmony_ci if (fw_key == ILLEGAL_KEY_GROUP) 74562306a36Sopenharmony_ci rtw_err(rtwdev, "invalid fw key\n"); 74662306a36Sopenharmony_ci return -EINVAL; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return 0; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic void download_firmware_end_flow(struct rtw_dev *rtwdev) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci u16 fw_ctrl; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci rtw_write32(rtwdev, REG_TXDMA_STATUS, BTI_PAGE_OVF); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* Check IMEM & DMEM checksum is OK or not */ 75962306a36Sopenharmony_ci fw_ctrl = rtw_read16(rtwdev, REG_MCUFW_CTRL); 76062306a36Sopenharmony_ci if ((fw_ctrl & BIT_CHECK_SUM_OK) != BIT_CHECK_SUM_OK) 76162306a36Sopenharmony_ci return; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci fw_ctrl = (fw_ctrl | BIT_FW_DW_RDY) & ~BIT_MCUFWDL_EN; 76462306a36Sopenharmony_ci rtw_write16(rtwdev, REG_MCUFW_CTRL, fw_ctrl); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int __rtw_download_firmware(struct rtw_dev *rtwdev, 76862306a36Sopenharmony_ci struct rtw_fw_state *fw) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci struct rtw_backup_info bckp[DLFW_RESTORE_REG_NUM]; 77162306a36Sopenharmony_ci const u8 *data = fw->firmware->data; 77262306a36Sopenharmony_ci u32 size = fw->firmware->size; 77362306a36Sopenharmony_ci u32 ltecoex_bckp; 77462306a36Sopenharmony_ci int ret; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (!check_firmware_size(data, size)) 77762306a36Sopenharmony_ci return -EINVAL; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (!ltecoex_read_reg(rtwdev, 0x38, <ecoex_bckp)) 78062306a36Sopenharmony_ci return -EBUSY; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci wlan_cpu_enable(rtwdev, false); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci download_firmware_reg_backup(rtwdev, bckp); 78562306a36Sopenharmony_ci download_firmware_reset_platform(rtwdev); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci ret = start_download_firmware(rtwdev, data, size); 78862306a36Sopenharmony_ci if (ret) 78962306a36Sopenharmony_ci goto dlfw_fail; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci download_firmware_reg_restore(rtwdev, bckp, DLFW_RESTORE_REG_NUM); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci download_firmware_end_flow(rtwdev); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci wlan_cpu_enable(rtwdev, true); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) { 79862306a36Sopenharmony_ci ret = -EBUSY; 79962306a36Sopenharmony_ci goto dlfw_fail; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci ret = download_firmware_validate(rtwdev); 80362306a36Sopenharmony_ci if (ret) 80462306a36Sopenharmony_ci goto dlfw_fail; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* reset desc and index */ 80762306a36Sopenharmony_ci rtw_hci_setup(rtwdev); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci rtwdev->h2c.last_box_num = 0; 81062306a36Sopenharmony_ci rtwdev->h2c.seq = 0; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return 0; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cidlfw_fail: 81762306a36Sopenharmony_ci /* Disable FWDL_EN */ 81862306a36Sopenharmony_ci rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 81962306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return ret; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic void en_download_firmware_legacy(struct rtw_dev *rtwdev, bool en) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci int try; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (en) { 82962306a36Sopenharmony_ci wlan_cpu_enable(rtwdev, false); 83062306a36Sopenharmony_ci wlan_cpu_enable(rtwdev, true); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci for (try = 0; try < 10; try++) { 83562306a36Sopenharmony_ci if (rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_MCUFWDL_EN) 83662306a36Sopenharmony_ci goto fwdl_ready; 83762306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 83862306a36Sopenharmony_ci msleep(20); 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci rtw_err(rtwdev, "failed to check fw download ready\n"); 84162306a36Sopenharmony_cifwdl_ready: 84262306a36Sopenharmony_ci rtw_write32_clr(rtwdev, REG_MCUFW_CTRL, BIT_ROM_DLEN); 84362306a36Sopenharmony_ci } else { 84462306a36Sopenharmony_ci rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN); 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic void 84962306a36Sopenharmony_ciwrite_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci u32 val32; 85262306a36Sopenharmony_ci u32 block_nr; 85362306a36Sopenharmony_ci u32 remain_size; 85462306a36Sopenharmony_ci u32 write_addr = FW_START_ADDR_LEGACY; 85562306a36Sopenharmony_ci const __le32 *ptr = (const __le32 *)data; 85662306a36Sopenharmony_ci u32 block; 85762306a36Sopenharmony_ci __le32 remain_data = 0; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci block_nr = size >> DLFW_BLK_SIZE_SHIFT_LEGACY; 86062306a36Sopenharmony_ci remain_size = size & (DLFW_BLK_SIZE_LEGACY - 1); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL); 86362306a36Sopenharmony_ci val32 &= ~BIT_ROM_PGE; 86462306a36Sopenharmony_ci val32 |= (page << BIT_SHIFT_ROM_PGE) & BIT_ROM_PGE; 86562306a36Sopenharmony_ci rtw_write32(rtwdev, REG_MCUFW_CTRL, val32); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci for (block = 0; block < block_nr; block++) { 86862306a36Sopenharmony_ci rtw_write32(rtwdev, write_addr, le32_to_cpu(*ptr)); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci write_addr += DLFW_BLK_SIZE_LEGACY; 87162306a36Sopenharmony_ci ptr++; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (remain_size) { 87562306a36Sopenharmony_ci memcpy(&remain_data, ptr, remain_size); 87662306a36Sopenharmony_ci rtw_write32(rtwdev, write_addr, le32_to_cpu(remain_data)); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic int 88162306a36Sopenharmony_cidownload_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci u32 page; 88462306a36Sopenharmony_ci u32 total_page; 88562306a36Sopenharmony_ci u32 last_page_size; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci data += sizeof(struct rtw_fw_hdr_legacy); 88862306a36Sopenharmony_ci size -= sizeof(struct rtw_fw_hdr_legacy); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci total_page = size >> DLFW_PAGE_SIZE_SHIFT_LEGACY; 89162306a36Sopenharmony_ci last_page_size = size & (DLFW_PAGE_SIZE_LEGACY - 1); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci for (page = 0; page < total_page; page++) { 89662306a36Sopenharmony_ci write_firmware_page(rtwdev, page, data, DLFW_PAGE_SIZE_LEGACY); 89762306a36Sopenharmony_ci data += DLFW_PAGE_SIZE_LEGACY; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci if (last_page_size) 90062306a36Sopenharmony_ci write_firmware_page(rtwdev, page, data, last_page_size); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT, 1)) { 90362306a36Sopenharmony_ci rtw_err(rtwdev, "failed to check download firmware report\n"); 90462306a36Sopenharmony_ci return -EINVAL; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci return 0; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic int download_firmware_validate_legacy(struct rtw_dev *rtwdev) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci u32 val32; 91362306a36Sopenharmony_ci int try; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL); 91662306a36Sopenharmony_ci val32 |= BIT_MCUFWDL_RDY; 91762306a36Sopenharmony_ci val32 &= ~BIT_WINTINI_RDY; 91862306a36Sopenharmony_ci rtw_write32(rtwdev, REG_MCUFW_CTRL, val32); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci wlan_cpu_enable(rtwdev, false); 92162306a36Sopenharmony_ci wlan_cpu_enable(rtwdev, true); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci for (try = 0; try < 10; try++) { 92462306a36Sopenharmony_ci val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL); 92562306a36Sopenharmony_ci if ((val32 & FW_READY_LEGACY) == FW_READY_LEGACY) 92662306a36Sopenharmony_ci return 0; 92762306a36Sopenharmony_ci msleep(20); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci rtw_err(rtwdev, "failed to validate firmware\n"); 93162306a36Sopenharmony_ci return -EINVAL; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic int __rtw_download_firmware_legacy(struct rtw_dev *rtwdev, 93562306a36Sopenharmony_ci struct rtw_fw_state *fw) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci int ret = 0; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci en_download_firmware_legacy(rtwdev, true); 94062306a36Sopenharmony_ci ret = download_firmware_legacy(rtwdev, fw->firmware->data, fw->firmware->size); 94162306a36Sopenharmony_ci en_download_firmware_legacy(rtwdev, false); 94262306a36Sopenharmony_ci if (ret) 94362306a36Sopenharmony_ci goto out; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci ret = download_firmware_validate_legacy(rtwdev); 94662306a36Sopenharmony_ci if (ret) 94762306a36Sopenharmony_ci goto out; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* reset desc and index */ 95062306a36Sopenharmony_ci rtw_hci_setup(rtwdev); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci rtwdev->h2c.last_box_num = 0; 95362306a36Sopenharmony_ci rtwdev->h2c.seq = 0; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ciout: 95862306a36Sopenharmony_ci return ret; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic 96262306a36Sopenharmony_ciint _rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci if (rtw_chip_wcpu_11n(rtwdev)) 96562306a36Sopenharmony_ci return __rtw_download_firmware_legacy(rtwdev, fw); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci return __rtw_download_firmware(rtwdev, fw); 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ciint rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci int ret; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci ret = _rtw_download_firmware(rtwdev, fw); 97562306a36Sopenharmony_ci if (ret) 97662306a36Sopenharmony_ci return ret; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE && 97962306a36Sopenharmony_ci rtwdev->chip->id == RTW_CHIP_TYPE_8821C) 98062306a36Sopenharmony_ci rtw_fw_set_recover_bt_device(rtwdev); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci return 0; 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_cistatic u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci const struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn; 98862306a36Sopenharmony_ci u32 prio_queues = 0; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (queues & BIT(IEEE80211_AC_VO)) 99162306a36Sopenharmony_ci prio_queues |= BIT(rqpn->dma_map_vo); 99262306a36Sopenharmony_ci if (queues & BIT(IEEE80211_AC_VI)) 99362306a36Sopenharmony_ci prio_queues |= BIT(rqpn->dma_map_vi); 99462306a36Sopenharmony_ci if (queues & BIT(IEEE80211_AC_BE)) 99562306a36Sopenharmony_ci prio_queues |= BIT(rqpn->dma_map_be); 99662306a36Sopenharmony_ci if (queues & BIT(IEEE80211_AC_BK)) 99762306a36Sopenharmony_ci prio_queues |= BIT(rqpn->dma_map_bk); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci return prio_queues; 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev, 100362306a36Sopenharmony_ci u32 prio_queue, bool drop) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 100662306a36Sopenharmony_ci const struct rtw_prioq_addr *addr; 100762306a36Sopenharmony_ci bool wsize; 100862306a36Sopenharmony_ci u16 avail_page, rsvd_page; 100962306a36Sopenharmony_ci int i; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (prio_queue >= RTW_DMA_MAPPING_MAX) 101262306a36Sopenharmony_ci return; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci addr = &chip->prioq_addrs->prio[prio_queue]; 101562306a36Sopenharmony_ci wsize = chip->prioq_addrs->wsize; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* check if all of the reserved pages are available for 100 msecs */ 101862306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 101962306a36Sopenharmony_ci rsvd_page = wsize ? rtw_read16(rtwdev, addr->rsvd) : 102062306a36Sopenharmony_ci rtw_read8(rtwdev, addr->rsvd); 102162306a36Sopenharmony_ci avail_page = wsize ? rtw_read16(rtwdev, addr->avail) : 102262306a36Sopenharmony_ci rtw_read8(rtwdev, addr->avail); 102362306a36Sopenharmony_ci if (rsvd_page == avail_page) 102462306a36Sopenharmony_ci return; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci msleep(20); 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* priority queue is still not empty, throw a warning, 103062306a36Sopenharmony_ci * 103162306a36Sopenharmony_ci * Note that if we want to flush the tx queue when having a lot of 103262306a36Sopenharmony_ci * traffic (ex, 100Mbps up), some of the packets could be dropped. 103362306a36Sopenharmony_ci * And it requires like ~2secs to flush the full priority queue. 103462306a36Sopenharmony_ci */ 103562306a36Sopenharmony_ci if (!drop) 103662306a36Sopenharmony_ci rtw_warn(rtwdev, "timed out to flush queue %d\n", prio_queue); 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic void rtw_mac_flush_prio_queues(struct rtw_dev *rtwdev, 104062306a36Sopenharmony_ci u32 prio_queues, bool drop) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci u32 q; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci for (q = 0; q < RTW_DMA_MAPPING_MAX; q++) 104562306a36Sopenharmony_ci if (prio_queues & BIT(q)) 104662306a36Sopenharmony_ci __rtw_mac_flush_prio_queue(rtwdev, q, drop); 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_civoid rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci u32 prio_queues = 0; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* If all of the hardware queues are requested to flush, 105462306a36Sopenharmony_ci * or the priority queues are not mapped yet, 105562306a36Sopenharmony_ci * flush all of the priority queues 105662306a36Sopenharmony_ci */ 105762306a36Sopenharmony_ci if (queues == BIT(rtwdev->hw->queues) - 1 || !rtwdev->fifo.rqpn) 105862306a36Sopenharmony_ci prio_queues = BIT(RTW_DMA_MAPPING_MAX) - 1; 105962306a36Sopenharmony_ci else 106062306a36Sopenharmony_ci prio_queues = get_priority_queues(rtwdev, queues); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci rtw_mac_flush_prio_queues(rtwdev, prio_queues, drop); 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_cistatic int txdma_queue_mapping(struct rtw_dev *rtwdev) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 106862306a36Sopenharmony_ci const struct rtw_rqpn *rqpn = NULL; 106962306a36Sopenharmony_ci u16 txdma_pq_map = 0; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci switch (rtw_hci_type(rtwdev)) { 107262306a36Sopenharmony_ci case RTW_HCI_TYPE_PCIE: 107362306a36Sopenharmony_ci rqpn = &chip->rqpn_table[1]; 107462306a36Sopenharmony_ci break; 107562306a36Sopenharmony_ci case RTW_HCI_TYPE_USB: 107662306a36Sopenharmony_ci if (rtwdev->hci.bulkout_num == 2) 107762306a36Sopenharmony_ci rqpn = &chip->rqpn_table[2]; 107862306a36Sopenharmony_ci else if (rtwdev->hci.bulkout_num == 3) 107962306a36Sopenharmony_ci rqpn = &chip->rqpn_table[3]; 108062306a36Sopenharmony_ci else if (rtwdev->hci.bulkout_num == 4) 108162306a36Sopenharmony_ci rqpn = &chip->rqpn_table[4]; 108262306a36Sopenharmony_ci else 108362306a36Sopenharmony_ci return -EINVAL; 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci case RTW_HCI_TYPE_SDIO: 108662306a36Sopenharmony_ci rqpn = &chip->rqpn_table[0]; 108762306a36Sopenharmony_ci break; 108862306a36Sopenharmony_ci default: 108962306a36Sopenharmony_ci return -EINVAL; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci rtwdev->fifo.rqpn = rqpn; 109362306a36Sopenharmony_ci txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi); 109462306a36Sopenharmony_ci txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg); 109562306a36Sopenharmony_ci txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk); 109662306a36Sopenharmony_ci txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be); 109762306a36Sopenharmony_ci txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi); 109862306a36Sopenharmony_ci txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo); 109962306a36Sopenharmony_ci rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci rtw_write8(rtwdev, REG_CR, 0); 110262306a36Sopenharmony_ci rtw_write8(rtwdev, REG_CR, MAC_TRX_ENABLE); 110362306a36Sopenharmony_ci if (rtw_chip_wcpu_11ac(rtwdev)) 110462306a36Sopenharmony_ci rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) { 110762306a36Sopenharmony_ci rtw_read32(rtwdev, REG_SDIO_FREE_TXPG); 110862306a36Sopenharmony_ci rtw_write32(rtwdev, REG_SDIO_TX_CTRL, 0); 110962306a36Sopenharmony_ci } else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB) { 111062306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_TXDMA_PQ_MAP, BIT_RXDMA_ARBBW_EN); 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci return 0; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic int set_trx_fifo_info(struct rtw_dev *rtwdev) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 111962306a36Sopenharmony_ci struct rtw_fifo_conf *fifo = &rtwdev->fifo; 112062306a36Sopenharmony_ci u16 cur_pg_addr; 112162306a36Sopenharmony_ci u8 csi_buf_pg_num = chip->csi_buf_pg_num; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* config rsvd page num */ 112462306a36Sopenharmony_ci fifo->rsvd_drv_pg_num = chip->rsvd_drv_pg_num; 112562306a36Sopenharmony_ci fifo->txff_pg_num = chip->txff_size >> 7; 112662306a36Sopenharmony_ci if (rtw_chip_wcpu_11n(rtwdev)) 112762306a36Sopenharmony_ci fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num; 112862306a36Sopenharmony_ci else 112962306a36Sopenharmony_ci fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num + 113062306a36Sopenharmony_ci RSVD_PG_H2C_EXTRAINFO_NUM + 113162306a36Sopenharmony_ci RSVD_PG_H2C_STATICINFO_NUM + 113262306a36Sopenharmony_ci RSVD_PG_H2CQ_NUM + 113362306a36Sopenharmony_ci RSVD_PG_CPU_INSTRUCTION_NUM + 113462306a36Sopenharmony_ci RSVD_PG_FW_TXBUF_NUM + 113562306a36Sopenharmony_ci csi_buf_pg_num; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (fifo->rsvd_pg_num > fifo->txff_pg_num) 113862306a36Sopenharmony_ci return -ENOMEM; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci fifo->acq_pg_num = fifo->txff_pg_num - fifo->rsvd_pg_num; 114162306a36Sopenharmony_ci fifo->rsvd_boundary = fifo->txff_pg_num - fifo->rsvd_pg_num; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci cur_pg_addr = fifo->txff_pg_num; 114462306a36Sopenharmony_ci if (rtw_chip_wcpu_11ac(rtwdev)) { 114562306a36Sopenharmony_ci cur_pg_addr -= csi_buf_pg_num; 114662306a36Sopenharmony_ci fifo->rsvd_csibuf_addr = cur_pg_addr; 114762306a36Sopenharmony_ci cur_pg_addr -= RSVD_PG_FW_TXBUF_NUM; 114862306a36Sopenharmony_ci fifo->rsvd_fw_txbuf_addr = cur_pg_addr; 114962306a36Sopenharmony_ci cur_pg_addr -= RSVD_PG_CPU_INSTRUCTION_NUM; 115062306a36Sopenharmony_ci fifo->rsvd_cpu_instr_addr = cur_pg_addr; 115162306a36Sopenharmony_ci cur_pg_addr -= RSVD_PG_H2CQ_NUM; 115262306a36Sopenharmony_ci fifo->rsvd_h2cq_addr = cur_pg_addr; 115362306a36Sopenharmony_ci cur_pg_addr -= RSVD_PG_H2C_STATICINFO_NUM; 115462306a36Sopenharmony_ci fifo->rsvd_h2c_sta_info_addr = cur_pg_addr; 115562306a36Sopenharmony_ci cur_pg_addr -= RSVD_PG_H2C_EXTRAINFO_NUM; 115662306a36Sopenharmony_ci fifo->rsvd_h2c_info_addr = cur_pg_addr; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci cur_pg_addr -= fifo->rsvd_drv_pg_num; 115962306a36Sopenharmony_ci fifo->rsvd_drv_addr = cur_pg_addr; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (fifo->rsvd_boundary != fifo->rsvd_drv_addr) { 116262306a36Sopenharmony_ci rtw_err(rtwdev, "wrong rsvd driver address\n"); 116362306a36Sopenharmony_ci return -EINVAL; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci return 0; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistatic int __priority_queue_cfg(struct rtw_dev *rtwdev, 117062306a36Sopenharmony_ci const struct rtw_page_table *pg_tbl, 117162306a36Sopenharmony_ci u16 pubq_num) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 117462306a36Sopenharmony_ci struct rtw_fifo_conf *fifo = &rtwdev->fifo; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, pg_tbl->hq_num); 117762306a36Sopenharmony_ci rtw_write16(rtwdev, REG_FIFOPAGE_INFO_2, pg_tbl->lq_num); 117862306a36Sopenharmony_ci rtw_write16(rtwdev, REG_FIFOPAGE_INFO_3, pg_tbl->nq_num); 117962306a36Sopenharmony_ci rtw_write16(rtwdev, REG_FIFOPAGE_INFO_4, pg_tbl->exq_num); 118062306a36Sopenharmony_ci rtw_write16(rtwdev, REG_FIFOPAGE_INFO_5, pubq_num); 118162306a36Sopenharmony_ci rtw_write32_set(rtwdev, REG_RQPN_CTRL_2, BIT_LD_RQPN); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2, fifo->rsvd_boundary); 118462306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL + 2, BIT_EN_WR_FREE_TAIL >> 16); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci rtw_write16(rtwdev, REG_BCNQ_BDNY_V1, fifo->rsvd_boundary); 118762306a36Sopenharmony_ci rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2 + 2, fifo->rsvd_boundary); 118862306a36Sopenharmony_ci rtw_write16(rtwdev, REG_BCNQ1_BDNY_V1, fifo->rsvd_boundary); 118962306a36Sopenharmony_ci rtw_write32(rtwdev, REG_RXFF_BNDY, chip->rxff_size - C2H_PKT_BUF - 1); 119062306a36Sopenharmony_ci rtw_write8_set(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (!check_hw_ready(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1, 0)) 119362306a36Sopenharmony_ci return -EBUSY; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci rtw_write8(rtwdev, REG_CR + 3, 0); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci return 0; 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic int __priority_queue_cfg_legacy(struct rtw_dev *rtwdev, 120162306a36Sopenharmony_ci const struct rtw_page_table *pg_tbl, 120262306a36Sopenharmony_ci u16 pubq_num) 120362306a36Sopenharmony_ci{ 120462306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 120562306a36Sopenharmony_ci struct rtw_fifo_conf *fifo = &rtwdev->fifo; 120662306a36Sopenharmony_ci u32 val32; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num); 120962306a36Sopenharmony_ci rtw_write32(rtwdev, REG_RQPN_NPQ, val32); 121062306a36Sopenharmony_ci val32 = BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num); 121162306a36Sopenharmony_ci rtw_write32(rtwdev, REG_RQPN, val32); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci rtw_write8(rtwdev, REG_TRXFF_BNDY, fifo->rsvd_boundary); 121462306a36Sopenharmony_ci rtw_write16(rtwdev, REG_TRXFF_BNDY + 2, chip->rxff_size - REPORT_BUF - 1); 121562306a36Sopenharmony_ci rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1, fifo->rsvd_boundary); 121662306a36Sopenharmony_ci rtw_write8(rtwdev, REG_BCNQ_BDNY, fifo->rsvd_boundary); 121762306a36Sopenharmony_ci rtw_write8(rtwdev, REG_MGQ_BDNY, fifo->rsvd_boundary); 121862306a36Sopenharmony_ci rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, fifo->rsvd_boundary); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci rtw_write32_set(rtwdev, REG_AUTO_LLT, BIT_AUTO_INIT_LLT); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if (!check_hw_ready(rtwdev, REG_AUTO_LLT, BIT_AUTO_INIT_LLT, 0)) 122362306a36Sopenharmony_ci return -EBUSY; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci return 0; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int priority_queue_cfg(struct rtw_dev *rtwdev) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 123162306a36Sopenharmony_ci struct rtw_fifo_conf *fifo = &rtwdev->fifo; 123262306a36Sopenharmony_ci const struct rtw_page_table *pg_tbl = NULL; 123362306a36Sopenharmony_ci u16 pubq_num; 123462306a36Sopenharmony_ci int ret; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci ret = set_trx_fifo_info(rtwdev); 123762306a36Sopenharmony_ci if (ret) 123862306a36Sopenharmony_ci return ret; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci switch (rtw_hci_type(rtwdev)) { 124162306a36Sopenharmony_ci case RTW_HCI_TYPE_PCIE: 124262306a36Sopenharmony_ci pg_tbl = &chip->page_table[1]; 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci case RTW_HCI_TYPE_USB: 124562306a36Sopenharmony_ci if (rtwdev->hci.bulkout_num == 2) 124662306a36Sopenharmony_ci pg_tbl = &chip->page_table[2]; 124762306a36Sopenharmony_ci else if (rtwdev->hci.bulkout_num == 3) 124862306a36Sopenharmony_ci pg_tbl = &chip->page_table[3]; 124962306a36Sopenharmony_ci else if (rtwdev->hci.bulkout_num == 4) 125062306a36Sopenharmony_ci pg_tbl = &chip->page_table[4]; 125162306a36Sopenharmony_ci else 125262306a36Sopenharmony_ci return -EINVAL; 125362306a36Sopenharmony_ci break; 125462306a36Sopenharmony_ci case RTW_HCI_TYPE_SDIO: 125562306a36Sopenharmony_ci pg_tbl = &chip->page_table[0]; 125662306a36Sopenharmony_ci break; 125762306a36Sopenharmony_ci default: 125862306a36Sopenharmony_ci return -EINVAL; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - 126262306a36Sopenharmony_ci pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; 126362306a36Sopenharmony_ci if (rtw_chip_wcpu_11n(rtwdev)) 126462306a36Sopenharmony_ci return __priority_queue_cfg_legacy(rtwdev, pg_tbl, pubq_num); 126562306a36Sopenharmony_ci else 126662306a36Sopenharmony_ci return __priority_queue_cfg(rtwdev, pg_tbl, pubq_num); 126762306a36Sopenharmony_ci} 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cistatic int init_h2c(struct rtw_dev *rtwdev) 127062306a36Sopenharmony_ci{ 127162306a36Sopenharmony_ci struct rtw_fifo_conf *fifo = &rtwdev->fifo; 127262306a36Sopenharmony_ci u8 value8; 127362306a36Sopenharmony_ci u32 value32; 127462306a36Sopenharmony_ci u32 h2cq_addr; 127562306a36Sopenharmony_ci u32 h2cq_size; 127662306a36Sopenharmony_ci u32 h2cq_free; 127762306a36Sopenharmony_ci u32 wp, rp; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci if (rtw_chip_wcpu_11n(rtwdev)) 128062306a36Sopenharmony_ci return 0; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci h2cq_addr = fifo->rsvd_h2cq_addr << TX_PAGE_SIZE_SHIFT; 128362306a36Sopenharmony_ci h2cq_size = RSVD_PG_H2CQ_NUM << TX_PAGE_SIZE_SHIFT; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_H2C_HEAD); 128662306a36Sopenharmony_ci value32 = (value32 & 0xFFFC0000) | h2cq_addr; 128762306a36Sopenharmony_ci rtw_write32(rtwdev, REG_H2C_HEAD, value32); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_H2C_READ_ADDR); 129062306a36Sopenharmony_ci value32 = (value32 & 0xFFFC0000) | h2cq_addr; 129162306a36Sopenharmony_ci rtw_write32(rtwdev, REG_H2C_READ_ADDR, value32); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci value32 = rtw_read32(rtwdev, REG_H2C_TAIL); 129462306a36Sopenharmony_ci value32 &= 0xFFFC0000; 129562306a36Sopenharmony_ci value32 |= (h2cq_addr + h2cq_size); 129662306a36Sopenharmony_ci rtw_write32(rtwdev, REG_H2C_TAIL, value32); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci value8 = rtw_read8(rtwdev, REG_H2C_INFO); 129962306a36Sopenharmony_ci value8 = (u8)((value8 & 0xFC) | 0x01); 130062306a36Sopenharmony_ci rtw_write8(rtwdev, REG_H2C_INFO, value8); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci value8 = rtw_read8(rtwdev, REG_H2C_INFO); 130362306a36Sopenharmony_ci value8 = (u8)((value8 & 0xFB) | 0x04); 130462306a36Sopenharmony_ci rtw_write8(rtwdev, REG_H2C_INFO, value8); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci value8 = rtw_read8(rtwdev, REG_TXDMA_OFFSET_CHK + 1); 130762306a36Sopenharmony_ci value8 = (u8)((value8 & 0x7f) | 0x80); 130862306a36Sopenharmony_ci rtw_write8(rtwdev, REG_TXDMA_OFFSET_CHK + 1, value8); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci wp = rtw_read32(rtwdev, REG_H2C_PKT_WRITEADDR) & 0x3FFFF; 131162306a36Sopenharmony_ci rp = rtw_read32(rtwdev, REG_H2C_PKT_READADDR) & 0x3FFFF; 131262306a36Sopenharmony_ci h2cq_free = wp >= rp ? h2cq_size - (wp - rp) : rp - wp; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci if (h2cq_size != h2cq_free) { 131562306a36Sopenharmony_ci rtw_err(rtwdev, "H2C queue mismatch\n"); 131662306a36Sopenharmony_ci return -EINVAL; 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci return 0; 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_cistatic int rtw_init_trx_cfg(struct rtw_dev *rtwdev) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci int ret; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci ret = txdma_queue_mapping(rtwdev); 132762306a36Sopenharmony_ci if (ret) 132862306a36Sopenharmony_ci return ret; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci ret = priority_queue_cfg(rtwdev); 133162306a36Sopenharmony_ci if (ret) 133262306a36Sopenharmony_ci return ret; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci ret = init_h2c(rtwdev); 133562306a36Sopenharmony_ci if (ret) 133662306a36Sopenharmony_ci return ret; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci return 0; 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic int rtw_drv_info_cfg(struct rtw_dev *rtwdev) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci u8 value8; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE); 134662306a36Sopenharmony_ci if (rtw_chip_wcpu_11ac(rtwdev)) { 134762306a36Sopenharmony_ci value8 = rtw_read8(rtwdev, REG_TRXFF_BNDY + 1); 134862306a36Sopenharmony_ci value8 &= 0xF0; 134962306a36Sopenharmony_ci /* For rxdesc len = 0 issue */ 135062306a36Sopenharmony_ci value8 |= 0xF; 135162306a36Sopenharmony_ci rtw_write8(rtwdev, REG_TRXFF_BNDY + 1, value8); 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci rtw_write32_set(rtwdev, REG_RCR, BIT_APP_PHYSTS); 135462306a36Sopenharmony_ci rtw_write32_clr(rtwdev, REG_WMAC_OPTION_FUNCTION + 4, BIT(8) | BIT(9)); 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci return 0; 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ciint rtw_mac_init(struct rtw_dev *rtwdev) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 136262306a36Sopenharmony_ci int ret; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci ret = rtw_init_trx_cfg(rtwdev); 136562306a36Sopenharmony_ci if (ret) 136662306a36Sopenharmony_ci return ret; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci ret = chip->ops->mac_init(rtwdev); 136962306a36Sopenharmony_ci if (ret) 137062306a36Sopenharmony_ci return ret; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci ret = rtw_drv_info_cfg(rtwdev); 137362306a36Sopenharmony_ci if (ret) 137462306a36Sopenharmony_ci return ret; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci rtw_hci_interface_cfg(rtwdev); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci return 0; 137962306a36Sopenharmony_ci} 1380