android13/external/wifi_driver/rtl8822es/hal/rtl8822e/sdio/rtl8822es_ops.c

476 lines
11 KiB
C

/******************************************************************************
*
* 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 <drv_types.h> /* PADAPTER, basic_types.h and etc. */
#include <hal_data.h> /* HAL_DATA_TYPE, GET_HAL_DATA() and etc. */
#include <hal_intf.h> /* 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 */