/****************************************************************************** * * Copyright(c) 2015 - 2017 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #define _RTL8822ES_OPS_C_ #include /* PADAPTER, basic_types.h and etc. */ #include /* HAL_DATA_TYPE, GET_HAL_DATA() and etc. */ #include /* struct hal_ops */ #include "../rtl8822e.h" /* rtl8822e_sethwreg() and etc. */ #include "rtl8822es.h" /* rtl8822es_hal_init() */ static void intf_chip_configure(PADAPTER adapter) { PHAL_DATA_TYPE phal; phal = GET_HAL_DATA(adapter); #ifdef RTW_RX_AGGREGATION phal->rxagg_mode = RX_AGG_DMA; phal->rxagg_dma_size = 0xff; phal->rxagg_dma_timeout= 0x20; #endif } /* * Description: * Collect all hardware information, fill "HAL_DATA_TYPE". * Sometimes this would be used to read MAC address. * This function will do * 1. Read Efuse/EEPROM to initialize * 2. Read registers to initialize * 3. Other vaiables initialization */ static u8 read_adapter_info(PADAPTER adapter) { u8 ret = _FAIL; /* * 1. Read Efuse/EEPROM to initialize */ if (rtl8822e_read_efuse(adapter) != _SUCCESS) goto exit; /* * 2. Read registers to initialize */ /* * 3. Other Initialization */ ret = _SUCCESS; exit: return ret; } void rtl8822es_get_interrupt(PADAPTER adapter, u32 *hisr, u32 *rx_len) { u8 data[8] = {0}; rtw_read_mem(adapter, REG_SDIO_HISR_8822E, 8, data); if (hisr) *hisr = le32_to_cpu(*(u32 *)data); if (rx_len) *rx_len = le32_to_cpu(*(u32 *)&data[4]); } void rtl8822es_clear_interrupt(PADAPTER adapter, u32 hisr) { /* Perform write one clear operation */ if (hisr) rtw_write32(adapter, REG_SDIO_HISR_8822E, hisr); } static void update_himr(PADAPTER adapter, u32 himr) { rtw_write32(adapter, REG_SDIO_HIMR_8822E, himr); } /* * Description: * Initialize SDIO Host Interrupt Mask configuration variables for future use. * */ static void init_interrupt(PADAPTER adapter) { struct hal_com_data *hal; hal = GET_HAL_DATA(adapter); hal->sdio_himr = (u32)( BIT_RX_REQUEST_MSK_8822E | #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT BIT_SDIO_AVAL_MSK_8822E | #endif /* CONFIG_SDIO_TX_ENABLE_AVAL_INT */ #if 0 BIT_SDIO_TXERR_MSK_8822E | BIT_SDIO_RXERR_MSK_8822E | BIT_SDIO_TXFOVW_MSK_8822E | BIT_SDIO_RXFOVW_MSK_8822E | BIT_SDIO_TXBCNOK_MSK_8822E | BIT_SDIO_TXBCNERR_MSK_8822E | BIT_SDIO_BCNERLY_INT_MSK_8822E | BIT_SDIO_C2HCMD_INT_MSK_8822E | #endif #if defined(CONFIG_LPS_LCLK) && !defined(CONFIG_DETECT_CPWM_BY_POLLING) BIT_SDIO_CPWM1_MSK_8822E | #if 0 BIT_SDIO_CPWM2_MSK_8822E | #endif #endif /* CONFIG_LPS_LCLK && !CONFIG_DETECT_CPWM_BY_POLLING */ #if 0 BIT_SDIO_HSISR_IND_MSK_8822E | BIT_SDIO_GTINT3_MSK_8822E | BIT_SDIO_GTINT4_MSK_8822E | BIT_SDIO_PSTIMEOUT_MSK_8822E | BIT_SDIO_OCPINT_MSK_8822E | BIT_SDIIO_ATIMend_MSK_8822E | BIT_SDIO_ATIMend_E_MSK_8822E | BIT_SDIO_CTWend_MSK_8822E | BIT_SDIO_CRCERR_MSK_8822E | #endif 0); #ifdef CONFIG_SDIO_MULTI_FUNCTION_COEX if (sdio_get_num_of_func(adapter_to_dvobj(adapter)) > 1) hal->sdio_himr |= BIT_BT_INT_MASK_8822E; #endif } /* * Description: * Clear corresponding SDIO Host ISR interrupt service. * * Assumption: * Using SDIO Local register ONLY for configuration. */ #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) static void clear_interrupt_all(PADAPTER adapter) { PHAL_DATA_TYPE hal; if (rtw_is_surprise_removed(adapter)) return; hal = GET_HAL_DATA(adapter); rtl8822es_clear_interrupt(adapter, 0xFFFFFFFF); } #endif /*#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)*/ /* * Description: * Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. * * Assumption: * 1. Using SDIO Local register ONLY for configuration. * 2. PASSIVE LEVEL */ static void enable_interrupt(PADAPTER adapter) { PHAL_DATA_TYPE hal; hal = GET_HAL_DATA(adapter); update_himr(adapter, hal->sdio_himr); RTW_INFO(FUNC_ADPT_FMT ": update SDIO HIMR=0x%08X\n", FUNC_ADPT_ARG(adapter), hal->sdio_himr); } /* * Description: * Disable SDIO Host IMR configuration to mask unnecessary interrupt service. * * Assumption: * Using SDIO Local register ONLY for configuration. */ static void disable_interrupt(PADAPTER adapter) { update_himr(adapter, 0); RTW_INFO("%s: update SDIO HIMR=0\n", __FUNCTION__); } static void _run_thread(PADAPTER adapter) { #ifndef CONFIG_SDIO_TX_TASKLET struct xmit_priv *xmitpriv = &adapter->xmitpriv; if (xmitpriv->SdioXmitThread == NULL) { RTW_INFO(FUNC_ADPT_FMT " start RTWHALXT\n", FUNC_ADPT_ARG(adapter)); xmitpriv->SdioXmitThread = kthread_run(rtl8822es_xmit_thread, adapter, "RTWHALXT"); if (IS_ERR(xmitpriv->SdioXmitThread)) { RTW_ERR("%s: start rtl8822es_xmit_thread FAIL!!\n", __FUNCTION__); xmitpriv->SdioXmitThread = NULL; } } #endif /* !CONFIG_SDIO_TX_TASKLET */ } static void run_thread(PADAPTER adapter) { _run_thread(adapter); rtl8822e_run_thread(adapter); } static void _cancel_thread(PADAPTER adapter) { #ifndef CONFIG_SDIO_TX_TASKLET struct xmit_priv *xmitpriv = &adapter->xmitpriv; /* stop xmit_buf_thread */ if (xmitpriv->SdioXmitThread) { _rtw_up_sema(&xmitpriv->SdioXmitSema); #ifdef SDIO_FREE_XMIT_BUF_SEMA rtw_sdio_free_xmitbuf_sema_up(xmitpriv); rtw_sdio_free_xmitbuf_sema_down(xmitpriv); #endif rtw_thread_stop(xmitpriv->SdioXmitThread); xmitpriv->SdioXmitThread = NULL; } #endif /* !CONFIG_SDIO_TX_TASKLET */ } static void cancel_thread(PADAPTER adapter) { rtl8822e_cancel_thread(adapter); _cancel_thread(adapter); } /* * If variable not handled here, * some variables will be processed in rtl8822e_sethwreg() */ static u8 sethwreg(PADAPTER adapter, u8 variable, u8 *val) { u8 ret = _SUCCESS; u8 val8; switch (variable) { case HW_VAR_SET_RPWM: /* * RPWM use follwoing bits: * BIT0 - 1: 32K, 0: Normal Clock * BIT4 - Power Gated * BIT6 - Ack Bit * BIT7 - Toggling Bit */ val8 = PS_STATE(*val); /* * PS_STATE == 0 is special case for initializing, * and keep the value to be 0 */ if (val8 && (val8 < PS_STATE_S2)) { #ifdef CONFIG_LPS_PG if (adapter_to_pwrctl(adapter)->lps_level == LPS_PG) val8 = BIT_REQ_PS_8822E | BIT4; else #endif val8 = BIT_REQ_PS_8822E; } else val8 = 0; if (*val & PS_ACK) val8 |= BIT_ACK_8822E; if (*val & PS_TOGGLE) val8 |= BIT_TOGGLE_8822E; rtw_write8(adapter, REG_SDIO_HRPWM1_8822E, val8); break; case HW_VAR_SET_REQ_FW_PS: /* * 1. driver write 0x8f[4]=1 * request fw ps state (only can write bit4) */ { u8 req_fw_ps = 0; req_fw_ps = rtw_read8(adapter, 0x8f); req_fw_ps |= 0x10; rtw_write8(adapter, 0x8f, req_fw_ps); } break; case HW_VAR_SET_DRV_ERLY_INT: switch (*val) { #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_CH_SW case TDLS_BCN_ERLY_ON: adapter->tdlsinfo.chsw_info.bcn_early_reg_bkp = rtw_read8(adapter, REG_DRVERLYINT); rtw_write8(adapter, REG_DRVERLYINT, 20); break; case TDLS_BCN_ERLY_OFF: rtw_write8(adapter, REG_DRVERLYINT, adapter->tdlsinfo.chsw_info.bcn_early_reg_bkp); break; #endif #endif } break; default: ret = rtl8822e_sethwreg(adapter, variable, val); break; } return ret; } /* * If variable not handled here, * some variables will be processed in GetHwReg8723B() */ static void gethwreg(PADAPTER adapter, u8 variable, u8 *val) { u8 val8; switch (variable) { case HW_VAR_CPWM: val8 = rtw_read8(adapter, REG_SDIO_HCPWM1_V2_8822E); if (val8 & BIT_CUR_PS_8822E) *val = PS_STATE_S0; else *val = PS_STATE_S4; if (val8 & BIT_TOGGLE_8822E) *val |= PS_TOGGLE; break; #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) || defined(CONFIG_FWLPS_IN_IPS) case HW_VAR_RPWM_TOG: *val = rtw_read8(adapter, REG_SDIO_HRPWM1_8822E); *val &= BIT_TOGGLE_8822E; break; #endif case HW_VAR_FW_PS_STATE: /* driver read dword 0x88 to get fw ps state */ *((u16 *)val) = rtw_read16(adapter, 0x88); break; default: rtl8822e_gethwreg(adapter, variable, val); break; } } /* * Description: * Query setting of specified variable. */ static u8 gethaldefvar(PADAPTER adapter, HAL_DEF_VARIABLE eVariable, void *pval) { u8 bResult = _SUCCESS; switch (eVariable) { case HW_VAR_MAX_RX_AMPDU_FACTOR: /* Default use MAX size */ *(HT_CAP_AMPDU_FACTOR *)pval = MAX_AMPDU_FACTOR_64K; break; default: bResult = rtl8822e_gethaldefvar(adapter, eVariable, pval); break; } return bResult; } /* * Description: * Change default setting of specified variable. */ static u8 sethaldefvar(PADAPTER adapter, HAL_DEF_VARIABLE eVariable, void *pval) { u8 bResult = _SUCCESS; switch (eVariable) { default: bResult = rtl8822e_sethaldefvar(adapter, eVariable, pval); break; } return bResult; } void rtl8822es_set_hal_ops(PADAPTER adapter) { struct hal_ops *ops; int err; err = rtl8822es_halmac_init_adapter(adapter); if (err) { RTW_INFO("%s: [ERROR]HALMAC initialize FAIL!\n", __FUNCTION__); return; } rtl8822e_set_hal_ops(adapter); init_interrupt(adapter); ops = &adapter->hal_func; ops->init_default_value = rtl8822es_init_default_value; ops->intf_chip_configure = intf_chip_configure; ops->read_adapter_info = read_adapter_info; ops->hal_init = rtl8822es_init; ops->hal_deinit = rtl8822es_deinit; ops->init_xmit_priv = rtl8822es_init_xmit_priv; ops->free_xmit_priv = rtl8822es_free_xmit_priv; ops->hal_xmit = rtl8822es_hal_xmit; ops->mgnt_xmit = rtl8822es_mgnt_xmit; #ifdef CONFIG_RTW_MGMT_QUEUE ops->hal_mgmt_xmitframe_enqueue = rtl8822es_hal_mgmt_xmit_enqueue; #endif ops->hal_xmitframe_enqueue = rtl8822es_hal_xmit_enqueue; #ifdef CONFIG_XMIT_THREAD_MODE ops->xmit_thread_handler = rtl8822es_xmit_buf_handler; #endif ops->run_thread = run_thread; ops->cancel_thread = cancel_thread; ops->init_recv_priv = rtl8822es_init_recv_priv; ops->free_recv_priv = rtl8822es_free_recv_priv; #ifdef CONFIG_RECV_THREAD_MODE ops->recv_hdl = rtl8822es_recv_hdl; #endif ops->enable_interrupt = enable_interrupt; ops->disable_interrupt = disable_interrupt; #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ops->clear_interrupt = clear_interrupt_all; #endif #ifdef CONFIG_RTW_SW_LED ops->InitSwLeds = rtl8822es_initswleds; ops->DeInitSwLeds = rtl8822es_deinitswleds; #endif ops->set_hw_reg_handler = sethwreg; ops->GetHwRegHandler = gethwreg; ops->get_hal_def_var_handler = gethaldefvar; ops->SetHalDefVarHandler = sethaldefvar; } #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) void rtl8822es_disable_interrupt_but_cpwm2(PADAPTER adapter) { u32 himr, tmp; tmp = rtw_read32(adapter, REG_SDIO_HIMR); RTW_INFO("%s: Read SDIO_REG_HIMR: 0x%08x\n", __FUNCTION__, tmp); himr = BIT_SDIO_CPWM2_MSK; update_himr(adapter, himr); tmp = rtw_read32(adapter, REG_SDIO_HIMR); RTW_INFO("%s: Read again SDIO_REG_HIMR: 0x%08x\n", __FUNCTION__, tmp); } #endif /* CONFIG_WOWLAN */