// SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2024 Realtek Corporation.*/ #include "../wifi.h" #include "../cam.h" #include "../usb.h" #include "../rtl8192d/reg.h" #include "../rtl8192d/def.h" #include "../rtl8192d/dm_common.h" #include "../rtl8192d/fw_common.h" #include "../rtl8192d/hw_common.h" #include "../rtl8192d/phy_common.h" #include "phy.h" #include "dm.h" #include "fw.h" #include "hw.h" #include "trx.h" static void _rtl92du_set_bcn_ctrl_reg(struct ieee80211_hw *hw, u8 set_bits, u8 clear_bits) { struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); rtlusb->reg_bcn_ctrl_val |= set_bits; rtlusb->reg_bcn_ctrl_val &= ~clear_bits; rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlusb->reg_bcn_ctrl_val); } static void _rtl92du_enable_bcn_sub_func(struct ieee80211_hw *hw) { _rtl92du_set_bcn_ctrl_reg(hw, 0, BIT(1)); } static void _rtl92du_disable_bcn_sub_func(struct ieee80211_hw *hw) { _rtl92du_set_bcn_ctrl_reg(hw, BIT(1), 0); } void rtl92du_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); switch (variable) { case HW_VAR_RCR: *((u32 *)val) = mac->rx_conf; break; default: rtl92d_get_hw_reg(hw, variable, val); break; } } void rtl92du_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtlpriv); switch (variable) { case HW_VAR_AC_PARAM: rtl92d_dm_init_edca_turbo(hw); break; case HW_VAR_ACM_CTRL: { u8 e_aci = *val; union aci_aifsn *p_aci_aifsn = (union aci_aifsn *)(&mac->ac[0].aifs); u8 acm = p_aci_aifsn->f.acm; u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); if (acm) { switch (e_aci) { case AC0_BE: acm_ctrl |= ACMHW_BEQEN; break; case AC2_VI: acm_ctrl |= ACMHW_VIQEN; break; case AC3_VO: acm_ctrl |= ACMHW_VOQEN; break; default: rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING, "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n", acm); break; } } else { switch (e_aci) { case AC0_BE: acm_ctrl &= (~ACMHW_BEQEN); break; case AC2_VI: acm_ctrl &= (~ACMHW_VIQEN); break; case AC3_VO: acm_ctrl &= (~ACMHW_VOQEN); break; default: pr_err("%s:%d switch case %#x not processed\n", __func__, __LINE__, e_aci); break; } } rtl_dbg(rtlpriv, COMP_QOS, DBG_TRACE, "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", acm_ctrl); rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl); break; } case HW_VAR_RCR: mac->rx_conf = ((u32 *)val)[0]; rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); break; case HW_VAR_H2C_FW_JOINBSSRPT: { u8 tmp_regcr, tmp_reg422; bool recover = false; u8 mstatus = *val; if (mstatus == RT_MEDIA_CONNECT) { rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL); tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); rtl_write_byte(rtlpriv, REG_CR + 1, tmp_regcr | ENSWBCN); _rtl92du_set_bcn_ctrl_reg(hw, 0, EN_BCN_FUNCTION); _rtl92du_set_bcn_ctrl_reg(hw, DIS_TSF_UDT, 0); tmp_reg422 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); if (tmp_reg422 & (EN_BCNQ_DL >> 16)) recover = true; rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422 & ~(EN_BCNQ_DL >> 16)); /* We don't implement FW LPS so this is not needed. */ /* rtl92d_set_fw_rsvdpagepkt(hw, 0); */ _rtl92du_set_bcn_ctrl_reg(hw, EN_BCN_FUNCTION, 0); _rtl92du_set_bcn_ctrl_reg(hw, 0, DIS_TSF_UDT); if (recover) rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422); rtl_write_byte(rtlpriv, REG_CR + 1, tmp_regcr & ~ENSWBCN); } rtl92d_set_fw_joinbss_report_cmd(hw, (*val)); break; } case HW_VAR_CORRECT_TSF: { u8 btype_ibss = val[0]; if (btype_ibss) rtl92d_stop_tx_beacon(hw); _rtl92du_set_bcn_ctrl_reg(hw, 0, EN_BCN_FUNCTION); rtl_write_dword(rtlpriv, REG_TSFTR, (u32)(mac->tsf & 0xffffffff)); rtl_write_dword(rtlpriv, REG_TSFTR + 4, (u32)((mac->tsf >> 32) & 0xffffffff)); _rtl92du_set_bcn_ctrl_reg(hw, EN_BCN_FUNCTION, 0); if (btype_ibss) rtl92d_resume_tx_beacon(hw); break; } case HW_VAR_KEEP_ALIVE: /* Avoid "switch case not processed" error. RTL8192DU doesn't * need to do anything here, maybe. */ break; default: rtl92d_set_hw_reg(hw, variable, val); break; } } static void _rtl92du_init_queue_reserved_page(struct ieee80211_hw *hw, u8 out_ep_num, u8 queue_sel) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u32 txqpagenum, txqpageunit; u32 txqremainingpage; u32 numhq = 0; u32 numlq = 0; u32 numnq = 0; u32 numpubq; u32 value32; if (rtlhal->macphymode != SINGLEMAC_SINGLEPHY) { numpubq = NORMAL_PAGE_NUM_PUBQ_92D_DUAL_MAC; txqpagenum = TX_TOTAL_PAGE_NUMBER_92D_DUAL_MAC - numpubq; } else { numpubq = TEST_PAGE_NUM_PUBQ_92DU; txqpagenum = TX_TOTAL_PAGE_NUMBER_92DU - numpubq; } if (rtlhal->macphymode != SINGLEMAC_SINGLEPHY && out_ep_num == 3) { numhq = NORMAL_PAGE_NUM_HPQ_92D_DUAL_MAC; numlq = NORMAL_PAGE_NUM_LPQ_92D_DUAL_MAC; numnq = NORMAL_PAGE_NUM_NORMALQ_92D_DUAL_MAC; } else { txqpageunit = txqpagenum / out_ep_num; txqremainingpage = txqpagenum % out_ep_num; if (queue_sel & TX_SELE_HQ) numhq = txqpageunit; if (queue_sel & TX_SELE_LQ) numlq = txqpageunit; if (queue_sel & TX_SELE_NQ) numnq = txqpageunit; /* HIGH priority queue always present in the * configuration of 2 or 3 out-ep. Remainder pages * assigned to High queue */ if (out_ep_num > 1 && txqremainingpage) numhq += txqremainingpage; } /* NOTE: This step done before writing REG_RQPN. */ rtl_write_byte(rtlpriv, REG_RQPN_NPQ, (u8)numnq); /* TX DMA */ u32p_replace_bits(&value32, numhq, HPQ_MASK); u32p_replace_bits(&value32, numlq, LPQ_MASK); u32p_replace_bits(&value32, numpubq, PUBQ_MASK); value32 |= LD_RQPN; rtl_write_dword(rtlpriv, REG_RQPN, value32); } static void _rtl92du_init_tx_buffer_boundary(struct ieee80211_hw *hw, u8 txpktbuf_bndy) { struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); rtl_write_byte(rtlpriv, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy); /* TXRKTBUG_PG_BNDY */ rtl_write_byte(rtlpriv, REG_TRXFF_BNDY, txpktbuf_bndy); /* Beacon Head for TXDMA */ rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy); } static bool _rtl92du_llt_table_init(struct ieee80211_hw *hw, u8 txpktbuf_bndy) { struct rtl_priv *rtlpriv = rtl_priv(hw); unsigned short i; bool status; u8 maxpage; if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) maxpage = 255; else maxpage = 127; for (i = 0; i < (txpktbuf_bndy - 1); i++) { status = rtl92d_llt_write(hw, i, i + 1); if (!status) return status; } /* end of list */ status = rtl92d_llt_write(hw, txpktbuf_bndy - 1, 0xFF); if (!status) return status; /* Make the other pages as ring buffer * This ring buffer is used as beacon buffer if we * config this MAC as two MAC transfer. * Otherwise used as local loopback buffer. */ for (i = txpktbuf_bndy; i < maxpage; i++) { status = rtl92d_llt_write(hw, i, i + 1); if (!status) return status; } /* Let last entry point to the start entry of ring buffer */ status = rtl92d_llt_write(hw, maxpage, txpktbuf_bndy); if (!status) return status; return true; } static void _rtl92du_init_chipn_reg_priority(struct ieee80211_hw *hw, u16 beq, u16 bkq, u16 viq, u16 voq, u16 mgtq, u16 hiq) { struct rtl_priv *rtlpriv = rtl_priv(hw); u16 value16; value16 = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL) & 0x7; u16p_replace_bits(&value16, beq, TXDMA_BEQ_MAP); u16p_replace_bits(&value16, bkq, TXDMA_BKQ_MAP); u16p_replace_bits(&value16, viq, TXDMA_VIQ_MAP); u16p_replace_bits(&value16, voq, TXDMA_VOQ_MAP); u16p_replace_bits(&value16, mgtq, TXDMA_MGQ_MAP); u16p_replace_bits(&value16, hiq, TXDMA_HIQ_MAP); rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, value16); } static void _rtl92du_init_chipn_one_out_ep_priority(struct ieee80211_hw *hw, u8 queue_sel) { struct rtl_priv *rtlpriv = rtl_priv(hw); u16 value; switch (queue_sel) { case TX_SELE_HQ: value = QUEUE_HIGH; break; case TX_SELE_LQ: value = QUEUE_LOW; break; case TX_SELE_NQ: value = QUEUE_NORMAL; break; default: WARN_ON(1); /* Shall not reach here! */ return; } _rtl92du_init_chipn_reg_priority(hw, value, value, value, value, value, value); rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "Tx queue select: 0x%02x\n", queue_sel); } static void _rtl92du_init_chipn_two_out_ep_priority(struct ieee80211_hw *hw, u8 queue_sel) { struct rtl_priv *rtlpriv = rtl_priv(hw); u16 beq, bkq, viq, voq, mgtq, hiq; u16 valuehi, valuelow; switch (queue_sel) { default: WARN_ON(1); fallthrough; case (TX_SELE_HQ | TX_SELE_LQ): valuehi = QUEUE_HIGH; valuelow = QUEUE_LOW; break; case (TX_SELE_NQ | TX_SELE_LQ): valuehi = QUEUE_NORMAL; valuelow = QUEUE_LOW; break; case (TX_SELE_HQ | TX_SELE_NQ): valuehi = QUEUE_HIGH; valuelow = QUEUE_NORMAL; break; } beq = valuelow; bkq = valuelow; viq = valuehi; voq = valuehi; mgtq = valuehi; hiq = valuehi; _rtl92du_init_chipn_reg_priority(hw, beq, bkq, viq, voq, mgtq, hiq); rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "Tx queue select: 0x%02x\n", queue_sel); } static void _rtl92du_init_chipn_three_out_ep_priority(struct ieee80211_hw *hw, u8 queue_sel) { struct rtl_priv *rtlpriv = rtl_priv(hw); u16 beq, bkq, viq, voq, mgtq, hiq; beq = QUEUE_LOW; bkq = QUEUE_LOW; viq = QUEUE_NORMAL; voq = QUEUE_HIGH; mgtq = QUEUE_HIGH; hiq = QUEUE_HIGH; _rtl92du_init_chipn_reg_priority(hw, beq, bkq, viq, voq, mgtq, hiq); rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "Tx queue select: 0x%02x\n", queue_sel); } static void _rtl92du_init_queue_priority(struct ieee80211_hw *hw, u8 out_ep_num, u8 queue_sel) { switch (out_ep_num) { case 1: _rtl92du_init_chipn_one_out_ep_priority(hw, queue_sel); break; case 2: _rtl92du_init_chipn_two_out_ep_priority(hw, queue_sel); break; case 3: _rtl92du_init_chipn_three_out_ep_priority(hw, queue_sel); break; default: WARN_ON(1); /* Shall not reach here! */ break; } } static void _rtl92du_init_wmac_setting(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtlpriv); mac->rx_conf = RCR_APM | RCR_AM | RCR_AB | RCR_ADF | RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | RCR_APP_MIC | RCR_APP_PHYST_RXFF | RCR_APPFCS; rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); /* Set Multicast Address. */ rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff); rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff); } static void _rtl92du_init_adaptive_ctrl(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 val32; val32 = rtl_read_dword(rtlpriv, REG_RRSR); val32 &= ~0xfffff; if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) val32 |= 0xffff0; /* No CCK */ else val32 |= 0xffff1; rtl_write_dword(rtlpriv, REG_RRSR, val32); /* Set Spec SIFS (used in NAV) */ rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x1010); /* Retry limit 0x30 */ rtl_write_word(rtlpriv, REG_RL, 0x3030); } static void _rtl92du_init_edca(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); u16 val16; /* Disable EDCCA count down, to reduce collison and retry */ val16 = rtl_read_word(rtlpriv, REG_RD_CTRL); val16 |= DIS_EDCA_CNT_DWN; rtl_write_word(rtlpriv, REG_RD_CTRL, val16); /* CCK SIFS shall always be 10us. */ rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x0a0a); /* Set SIFS for OFDM */ rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x1010); rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0204); rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x014004); /* TXOP */ rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, 0x005EA42B); rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0x0000A44F); rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x005EA324); rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x002FA226); rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0040); rtl_write_byte(rtlpriv, REG_BCNDMATIM, 0x2); rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); } static void _rtl92du_init_retry_function(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 val8; val8 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL); val8 |= EN_AMPDU_RTY_NEW; rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL, val8); rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); } static void _rtl92du_init_operation_mode(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); rtl_write_byte(rtlpriv, REG_BWOPMODE, BW_OPMODE_20MHZ); switch (rtlpriv->phy.rf_type) { case RF_1T2R: case RF_1T1R: rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3); break; case RF_2T2R: case RF_2T2R_GREEN: rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3); break; } rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, rtlhal->minspace_cfg); } static void _rtl92du_init_beacon_parameters(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1010); rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x3c02); rtl_write_byte(rtlpriv, REG_DRVERLYINT, 0x05); rtl_write_byte(rtlpriv, REG_BCNDMATIM, 0x03); rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); } static void _rtl92du_init_ampdu_aggregation(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); /* Aggregation threshold */ if (rtlhal->macphymode == DUALMAC_DUALPHY) rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x66525541); else if (rtlhal->macphymode == DUALMAC_SINGLEPHY) rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x44444441); else rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x88728841); rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); } static bool _rtl92du_init_power_on(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); unsigned short wordtmp; unsigned char bytetmp; u16 retry = 0; do { if (rtl_read_byte(rtlpriv, REG_APS_FSMCO) & PFM_ALDN) break; if (retry++ > 1000) return false; } while (true); /* Unlock ISO/CLK/Power control register */ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); /* SPS0_CTRL 0x11[7:0] = 0x2b enable SPS into PWM mode */ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); msleep(1); bytetmp = rtl_read_byte(rtlpriv, REG_LDOV12D_CTRL); if ((bytetmp & LDV12_EN) == 0) { bytetmp |= LDV12_EN; rtl_write_byte(rtlpriv, REG_LDOV12D_CTRL, bytetmp); msleep(1); bytetmp = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL); bytetmp &= ~ISO_MD2PP; rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, bytetmp); } /* Auto enable WLAN */ wordtmp = rtl_read_word(rtlpriv, REG_APS_FSMCO); wordtmp |= APFM_ONMAC; rtl_write_word(rtlpriv, REG_APS_FSMCO, wordtmp); wordtmp = rtl_read_word(rtlpriv, REG_APS_FSMCO); retry = 0; while ((wordtmp & APFM_ONMAC) && retry < 1000) { retry++; wordtmp = rtl_read_word(rtlpriv, REG_APS_FSMCO); } /* Release RF digital isolation */ wordtmp = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL); wordtmp &= ~ISO_DIOR; rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, wordtmp); /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ wordtmp = rtl_read_word(rtlpriv, REG_CR); wordtmp |= HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN | PROTOCOL_EN | SCHEDULE_EN | MACTXEN | MACRXEN | ENSEC; rtl_write_word(rtlpriv, REG_CR, wordtmp); return true; } static bool _rtl92du_init_mac(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 val8; rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); val8 = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); val8 &= ~(FEN_MREGEN >> 8); rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, val8); /* For s3/s4 may reset mac, Reg0xf8 may be set to 0, * so reset macphy control reg here. */ rtl92d_phy_config_macphymode(hw); rtl92du_phy_set_poweron(hw); if (!_rtl92du_init_power_on(hw)) { pr_err("Failed to init power on!\n"); return false; } rtl92d_phy_config_maccoexist_rfpage(hw); return true; } int rtl92du_hw_init(struct ieee80211_hw *hw) { struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_mac *mac = rtl_mac(rtlpriv); struct rtl_phy *rtlphy = &rtlpriv->phy; u8 val8, txpktbuf_bndy; int err, i; u32 val32; u16 val16; mutex_lock(rtlpriv->mutex_for_hw_init); /* we should do iqk after disable/enable */ rtl92d_phy_reset_iqk_result(hw); if (!_rtl92du_init_mac(hw)) { pr_err("Init MAC failed\n"); mutex_unlock(rtlpriv->mutex_for_hw_init); return 1; } if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY) txpktbuf_bndy = 249; else txpktbuf_bndy = 123; if (!_rtl92du_llt_table_init(hw, txpktbuf_bndy)) { pr_err("Init LLT failed\n"); mutex_unlock(rtlpriv->mutex_for_hw_init); return 1; } err = rtl92du_download_fw(hw); /* return fail only when part number check fail */ if (err && rtl_read_byte(rtlpriv, 0x1c5) == 0xe0) { rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW..\n"); mutex_unlock(rtlpriv->mutex_for_hw_init); return 1; } rtlhal->last_hmeboxnum = 0; rtlpriv->psc.fw_current_inpsmode = false; rtl92du_phy_mac_config(hw); /* Set reserved page for each queue */ _rtl92du_init_queue_reserved_page(hw, rtlusb->out_ep_nums, rtlusb->out_queue_sel); _rtl92du_init_tx_buffer_boundary(hw, txpktbuf_bndy); _rtl92du_init_queue_priority(hw, rtlusb->out_ep_nums, rtlusb->out_queue_sel); /* Set Tx/Rx page size (Tx must be 128 Bytes, * Rx can be 64, 128, 256, 512, 1024 bytes) */ rtl_write_byte(rtlpriv, REG_PBP, 0x11); /* Get Rx PHY status in order to report RSSI and others. */ rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); rtl_write_dword(rtlpriv, REG_HIMR, 0xffffffff); val8 = rtl_read_byte(rtlpriv, MSR); val8 &= ~MSR_MASK; val8 |= MSR_INFRA; rtl_write_byte(rtlpriv, MSR, val8); _rtl92du_init_wmac_setting(hw); _rtl92du_init_adaptive_ctrl(hw); _rtl92du_init_edca(hw); rtl_write_dword(rtlpriv, REG_DARFRC, 0x00000000); rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x10080404); rtl_write_dword(rtlpriv, REG_RARFRC, 0x04030201); rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x08070605); _rtl92du_init_retry_function(hw); /* _InitUsbAggregationSetting(padapter); no aggregation for now */ _rtl92du_init_operation_mode(hw); _rtl92du_init_beacon_parameters(hw); _rtl92du_init_ampdu_aggregation(hw); rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff); /* unit: 256us. 256ms */ rtl_write_word(rtlpriv, REG_PKT_VO_VI_LIFE_TIME, 0x0400); rtl_write_word(rtlpriv, REG_PKT_BE_BK_LIFE_TIME, 0x0400); /* Hardware-controlled blinking. */ rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8282); rtl_write_byte(rtlpriv, REG_LEDCFG2, 0x82); val32 = rtl_read_dword(rtlpriv, REG_TXDMA_OFFSET_CHK); val32 |= DROP_DATA_EN; rtl_write_dword(rtlpriv, REG_TXDMA_OFFSET_CHK, val32); if (mac->rdg_en) { rtl_write_byte(rtlpriv, REG_RD_CTRL, 0xff); rtl_write_word(rtlpriv, REG_RD_NAV_NXT, 0x200); rtl_write_byte(rtlpriv, REG_RD_RESP_PKT_TH, 0x05); } for (i = 0; i < 4; i++) rtl_write_dword(rtlpriv, REG_ARFR0 + i * 4, 0x1f8ffff0); if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY) { if (rtlusb->out_ep_nums == 2) rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03066666); else rtl_write_word(rtlpriv, REG_FAST_EDCA_CTRL, 0x8888); } else { rtl_write_word(rtlpriv, REG_FAST_EDCA_CTRL, 0x5555); } val8 = rtl_read_byte(rtlpriv, 0x605); val8 |= 0xf0; rtl_write_byte(rtlpriv, 0x605, val8); rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x30); rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x30); rtl_write_byte(rtlpriv, 0x606, 0x30); /* temp for high queue and mgnt Queue corrupt in time; it may * cause hang when sw beacon use high_Q, other frame use mgnt_Q; * or, sw beacon use mgnt_Q, other frame use high_Q; */ rtl_write_byte(rtlpriv, REG_DIS_TXREQ_CLR, 0x10); val16 = rtl_read_word(rtlpriv, REG_RD_CTRL); val16 |= BIT(12); rtl_write_word(rtlpriv, REG_RD_CTRL, val16); rtl_write_byte(rtlpriv, REG_TXPAUSE, 0); /* usb suspend idle time count for bitfile0927 */ val8 = rtl_read_byte(rtlpriv, 0xfe56); val8 |= BIT(0) | BIT(1); rtl_write_byte(rtlpriv, 0xfe56, val8); if (rtlhal->earlymode_enable) { rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "EarlyMode Enabled!!!\n"); val8 = rtl_read_byte(rtlpriv, REG_EARLY_MODE_CONTROL); val8 |= 0x1f; rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, val8); rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL + 3, 0x80); val8 = rtl_read_byte(rtlpriv, 0x605); val8 |= 0x40; rtl_write_byte(rtlpriv, 0x605, val8); } else { rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0); } rtl92du_phy_bb_config(hw); rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; /* set before initialize RF */ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); /* config RF */ rtl92du_phy_rf_config(hw); /* set default value after initialize RF */ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0); /* After load BB, RF params, we need to do more for 92D. */ rtl92du_update_bbrf_configuration(hw); rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK); rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, RF90_PATH_B, RF_CHNLBW, RFREG_OFFSET_MASK); /*---- Set CCK and OFDM Block "ON"----*/ if (rtlhal->current_bandtype == BAND_ON_2_4G) rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); /* reset hw sec */ rtl_cam_reset_all_entry(hw); rtl92d_enable_hw_security_config(hw); rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF); /* schmitt trigger, improve tx evm for 92du */ val8 = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL); val8 |= BIT(1); rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, val8); /* Disable bar */ rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0xffff); /* Nav limit */ rtl_write_byte(rtlpriv, REG_NAV_CTRL + 2, 0); rtl_write_byte(rtlpriv, ROFDM0_XATXAFE + 3, 0x50); /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct * TX power index for different rate set. */ rtl92d_phy_get_hw_reg_originalvalue(hw); ppsc->rfpwr_state = ERFON; /* do IQK for 2.4G for better scan result */ if (rtlhal->current_bandtype == BAND_ON_2_4G) rtl92du_phy_iq_calibrate(hw); rtl92du_phy_lc_calibrate(hw, IS_92D_SINGLEPHY(rtlhal->version)); rtl92du_phy_init_pa_bias(hw); mutex_unlock(rtlpriv->mutex_for_hw_init); rtl92du_dm_init(hw); /* For 2 PORT TSF SYNC */ rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1818); rtlusb->reg_bcn_ctrl_val = 0x18; udelay(500); if (rtlhal->macphymode != DUALMAC_DUALPHY) { rtl_write_dword(rtlpriv, RFPGA1_TXINFO, rtl_read_dword(rtlpriv, RFPGA1_TXINFO) & ~BIT(30)); rtl_write_dword(rtlpriv, RFPGA0_TXGAINSTAGE, rtl_read_dword(rtlpriv, RFPGA0_TXGAINSTAGE) & ~BIT(31)); rtl_write_dword(rtlpriv, ROFDM0_XBTXAFE, 0xa0e40000); } val32 = rtl_read_dword(rtlpriv, REG_FWHW_TXQ_CTRL); val32 |= BIT(12); rtl_write_dword(rtlpriv, REG_FWHW_TXQ_CTRL, val32); return err; } static int _rtl92du_set_media_status(struct ieee80211_hw *hw, enum nl80211_iftype type) { struct rtl_priv *rtlpriv = rtl_priv(hw); enum led_ctl_mode ledaction = LED_CTL_NO_LINK; u8 bt_msr = rtl_read_byte(rtlpriv, MSR); bt_msr &= 0xfc; if (type == NL80211_IFTYPE_UNSPECIFIED || type == NL80211_IFTYPE_STATION) { rtl92d_stop_tx_beacon(hw); _rtl92du_enable_bcn_sub_func(hw); } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) { rtl92d_resume_tx_beacon(hw); _rtl92du_disable_bcn_sub_func(hw); } else { rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING, "Set HW_VAR_MEDIA_STATUS: No such media status(%x)\n", type); } switch (type) { case NL80211_IFTYPE_UNSPECIFIED: bt_msr |= MSR_NOLINK; ledaction = LED_CTL_LINK; rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to NO LINK!\n"); break; case NL80211_IFTYPE_ADHOC: bt_msr |= MSR_ADHOC; rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to Ad Hoc!\n"); break; case NL80211_IFTYPE_STATION: bt_msr |= MSR_INFRA; ledaction = LED_CTL_LINK; rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to STA!\n"); break; case NL80211_IFTYPE_AP: bt_msr |= MSR_AP; rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to AP!\n"); break; default: pr_err("Network type %d not supported!\n", type); return 1; } rtl_write_byte(rtlpriv, MSR, bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); return 0; } void rtl92du_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 reg_rcr; if (rtlpriv->psc.rfpwr_state != ERFON) return; rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); if (check_bssid) { reg_rcr |= RCR_CBSSID_DATA | RCR_CBSSID_BCN; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)®_rcr); _rtl92du_set_bcn_ctrl_reg(hw, 0, DIS_TSF_UDT); } else if (!check_bssid) { reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); _rtl92du_set_bcn_ctrl_reg(hw, DIS_TSF_UDT, 0); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)®_rcr); } } int rtl92du_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) { struct rtl_priv *rtlpriv = rtl_priv(hw); if (_rtl92du_set_media_status(hw, type)) return -EOPNOTSUPP; /* check bssid */ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { if (type != NL80211_IFTYPE_AP) rtl92du_set_check_bssid(hw, true); } else { rtl92du_set_check_bssid(hw, false); } return 0; } /* do iqk or reload iqk */ /* windows just rtl92d_phy_reload_iqk_setting in set channel, * but it's very strict for time sequence so we add * rtl92d_phy_reload_iqk_setting here */ void rtl92du_linked_set_reg(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; u8 channel = rtlphy->current_channel; u8 indexforchannel; indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel); if (!rtlphy->iqk_matrix[indexforchannel].iqk_done) { rtl_dbg(rtlpriv, COMP_SCAN | COMP_INIT, DBG_DMESG, "Do IQK for channel:%d\n", channel); rtl92du_phy_iq_calibrate(hw); } } void rtl92du_enable_interrupt(struct ieee80211_hw *hw) { /* Nothing to do. */ } void rtl92du_disable_interrupt(struct ieee80211_hw *hw) { /* Nothing to do. */ } static void _rtl92du_poweroff_adapter(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 retry = 100; u8 u1b_tmp; u16 val16; u32 val32; rtl_write_byte(rtlpriv, REG_LDOA15_CTRL, 0x04); rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); /* IF fw in RAM code, do reset */ if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) { rtl_write_byte(rtlpriv, REG_FSIMR, 0); /* We need to disable other HRCV INT to influence 8051 reset. */ rtl_write_byte(rtlpriv, REG_FWIMR, 0x20); /* Close mask to prevent incorrect FW write operation. */ rtl_write_byte(rtlpriv, REG_FTIMR, 0); rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); /* Set (REG_HMETFR + 3) to 0x20 is reset 8051 */ rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); val16 = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); while (val16 & FEN_CPUEN) { retry--; if (retry == 0) break; udelay(50); val16 = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); } if (retry == 0) { rtl_write_byte(rtlpriv, REG_FWIMR, 0); /* if 8051 reset fail, reset MAC directly. */ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x50); mdelay(10); } } /* reset MCU, MAC register, DCORE */ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x54); /* reset MCU ready status */ rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); /* Pull GPIO PIN to balance level and LED control */ /* Disable GPIO[7:0] */ rtl_write_word(rtlpriv, REG_GPIO_PIN_CTRL + 2, 0x0000); val32 = rtl_read_dword(rtlpriv, REG_GPIO_PIN_CTRL); u32p_replace_bits(&val32, val32 & 0xff, 0x0000ff00); u32p_replace_bits(&val32, 0xff, 0x00ff0000); rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, val32); /* Disable GPIO[10:8] */ rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, 0); val16 = rtl_read_word(rtlpriv, REG_GPIO_IO_SEL); u16p_replace_bits(&val16, val16 & 0xf, 0x00f0); u16p_replace_bits(&val16, 0xf, 0x0780); rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, val16); /* Disable LED 0, 1, and 2 */ rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8888); rtl_write_byte(rtlpriv, REG_LEDCFG2, 0x88); /* Disable analog sequence */ /* enter PFM mode */ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); rtl_write_word(rtlpriv, REG_APS_FSMCO, APDM_HOST | AFSM_HSUS | PFM_ALDN); /* lock ISO/CLK/Power control register */ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "In PowerOff,reg0x%x=%X\n", REG_SPS0_CTRL, rtl_read_byte(rtlpriv, REG_SPS0_CTRL)); /* 0x17[7] 1b': power off in process 0b' : power off over */ if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { mutex_lock(rtlpriv->mutex_for_power_on_off); u1b_tmp = rtl_read_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS); u1b_tmp &= ~BIT(7); rtl_write_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS, u1b_tmp); mutex_unlock(rtlpriv->mutex_for_power_on_off); } rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "<=======\n"); } void rtl92du_card_disable(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); enum nl80211_iftype opmode; u32 val32; u16 val16; u8 val8; mac->link_state = MAC80211_NOLINK; opmode = NL80211_IFTYPE_UNSPECIFIED; _rtl92du_set_media_status(hw, opmode); RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); /* Power sequence for each MAC. */ /* a. stop tx DMA */ /* b. close RF */ /* c. clear rx buf */ /* d. stop rx DMA */ /* e. reset MAC */ val16 = rtl_read_word(rtlpriv, REG_GPIO_MUXCFG); val16 &= ~BIT(12); rtl_write_word(rtlpriv, REG_GPIO_MUXCFG, val16); rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xff); udelay(500); rtl_write_byte(rtlpriv, REG_CR, 0); /* RF OFF sequence */ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); rtl_set_rfreg(hw, RF90_PATH_A, RF_AC, RFREG_OFFSET_MASK, 0x00); rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); val8 = FEN_USBD | FEN_USBA | FEN_BB_GLB_RSTN; rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, val8); /* Mac0 can not do Global reset. Mac1 can do. */ if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY || rtlhal->interfaceindex == 1) { /* before BB reset should do clock gated */ val32 = rtl_read_dword(rtlpriv, RFPGA0_XCD_RFPARAMETER); val32 |= BIT(31); rtl_write_dword(rtlpriv, RFPGA0_XCD_RFPARAMETER, val32); val8 &= ~FEN_BB_GLB_RSTN; rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, val8); } rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "==> Do power off.......\n"); if (!rtl92du_phy_check_poweroff(hw)) return; _rtl92du_poweroff_adapter(hw); } void rtl92du_set_beacon_related_registers(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtlpriv); u16 bcn_interval, atim_window; bcn_interval = mac->beacon_interval; atim_window = 2; rtl92du_disable_interrupt(hw); rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x20); if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x30); else rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x20); rtl_write_byte(rtlpriv, 0x606, 0x30); } void rtl92du_set_beacon_interval(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); u16 bcn_interval = mac->beacon_interval; rtl_dbg(rtlpriv, COMP_BEACON, DBG_DMESG, "beacon_interval:%d\n", bcn_interval); rtl92du_disable_interrupt(hw); rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); rtl92du_enable_interrupt(hw); } void rtl92du_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, u32 rm_msr) { /* Nothing to do here. */ } void rtl92du_read_chip_version(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); /* Chip version reading is done in rtl92d_read_eeprom_info. */ rtlpriv->rtlhal.hw_type = HARDWARE_TYPE_RTL8192DU; }