diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:27:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:27:49 +0000 |
commit | ace9429bb58fd418f0c81d4c2835699bddf6bde6 (patch) | |
tree | b2d64bc10158fdd5497876388cd68142ca374ed3 /drivers/staging/rtl8723bs/hal/sdio_ops.c | |
parent | Initial commit. (diff) | |
download | linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.tar.xz linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.zip |
Adding upstream version 6.6.15.upstream/6.6.15
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/staging/rtl8723bs/hal/sdio_ops.c')
-rw-r--r-- | drivers/staging/rtl8723bs/hal/sdio_ops.c | 1012 |
1 files changed, 1012 insertions, 0 deletions
diff --git a/drivers/staging/rtl8723bs/hal/sdio_ops.c b/drivers/staging/rtl8723bs/hal/sdio_ops.c new file mode 100644 index 0000000000..107f427ee4 --- /dev/null +++ b/drivers/staging/rtl8723bs/hal/sdio_ops.c @@ -0,0 +1,1012 @@ +// SPDX-License-Identifier: GPL-2.0 +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + *******************************************************************************/ +#include <drv_types.h> +#include <rtw_debug.h> +#include <rtl8723b_hal.h> + +/* */ +/* Description: */ +/* The following mapping is for SDIO host local register space. */ +/* */ +/* Creadted by Roger, 2011.01.31. */ +/* */ +static void hal_sdio_get_cmd_addr_8723b( + struct adapter *adapter, + u8 device_id, + u32 addr, + u32 *cmdaddr +) +{ + switch (device_id) { + case SDIO_LOCAL_DEVICE_ID: + *cmdaddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (addr & SDIO_LOCAL_MSK)); + break; + + case WLAN_IOREG_DEVICE_ID: + *cmdaddr = ((WLAN_IOREG_DEVICE_ID << 13) | (addr & WLAN_IOREG_MSK)); + break; + + case WLAN_TX_HIQ_DEVICE_ID: + *cmdaddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); + break; + + case WLAN_TX_MIQ_DEVICE_ID: + *cmdaddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); + break; + + case WLAN_TX_LOQ_DEVICE_ID: + *cmdaddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); + break; + + case WLAN_RX0FF_DEVICE_ID: + *cmdaddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (addr & WLAN_RX0FF_MSK)); + break; + + default: + break; + } +} + +static u8 get_deviceid(u32 addr) +{ + u8 devide_id; + u16 pseudo_id; + + pseudo_id = (u16)(addr >> 16); + switch (pseudo_id) { + case 0x1025: + devide_id = SDIO_LOCAL_DEVICE_ID; + break; + + case 0x1026: + devide_id = WLAN_IOREG_DEVICE_ID; + break; + + case 0x1031: + devide_id = WLAN_TX_HIQ_DEVICE_ID; + break; + + case 0x1032: + devide_id = WLAN_TX_MIQ_DEVICE_ID; + break; + + case 0x1033: + devide_id = WLAN_TX_LOQ_DEVICE_ID; + break; + + case 0x1034: + devide_id = WLAN_RX0FF_DEVICE_ID; + break; + + default: + devide_id = WLAN_IOREG_DEVICE_ID; + break; + } + + return devide_id; +} + +static u32 _cvrt2ftaddr(const u32 addr, u8 *pdevice_id, u16 *poffset) +{ + u8 device_id; + u16 offset; + u32 ftaddr; + + device_id = get_deviceid(addr); + offset = 0; + + switch (device_id) { + case SDIO_LOCAL_DEVICE_ID: + offset = addr & SDIO_LOCAL_MSK; + break; + + case WLAN_TX_HIQ_DEVICE_ID: + case WLAN_TX_MIQ_DEVICE_ID: + case WLAN_TX_LOQ_DEVICE_ID: + offset = addr & WLAN_FIFO_MSK; + break; + + case WLAN_RX0FF_DEVICE_ID: + offset = addr & WLAN_RX0FF_MSK; + break; + + case WLAN_IOREG_DEVICE_ID: + default: + device_id = WLAN_IOREG_DEVICE_ID; + offset = addr & WLAN_IOREG_MSK; + break; + } + ftaddr = (device_id << 13) | offset; + + if (pdevice_id) + *pdevice_id = device_id; + if (poffset) + *poffset = offset; + + return ftaddr; +} + +static u8 sdio_read8(struct intf_hdl *intfhdl, u32 addr) +{ + u32 ftaddr; + ftaddr = _cvrt2ftaddr(addr, NULL, NULL); + + return sd_read8(intfhdl, ftaddr, NULL); +} + +static u16 sdio_read16(struct intf_hdl *intfhdl, u32 addr) +{ + u32 ftaddr; + __le16 le_tmp; + + ftaddr = _cvrt2ftaddr(addr, NULL, NULL); + sd_cmd52_read(intfhdl, ftaddr, 2, (u8 *)&le_tmp); + + return le16_to_cpu(le_tmp); +} + +static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr) +{ + struct adapter *adapter; + u8 mac_pwr_ctrl_on; + u8 device_id; + u16 offset; + u32 ftaddr; + u8 shift; + u32 val; + s32 __maybe_unused err; + __le32 le_tmp; + + adapter = intfhdl->padapter; + ftaddr = _cvrt2ftaddr(addr, &device_id, &offset); + + rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); + if ( + ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || + (!mac_pwr_ctrl_on) || + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) + ) { + err = sd_cmd52_read(intfhdl, ftaddr, 4, (u8 *)&le_tmp); + return le32_to_cpu(le_tmp); + } + + /* 4 bytes alignment */ + shift = ftaddr & 0x3; + if (shift == 0) { + val = sd_read32(intfhdl, ftaddr, NULL); + } else { + u8 *tmpbuf; + + tmpbuf = rtw_malloc(8); + if (!tmpbuf) + return SDIO_ERR_VAL32; + + ftaddr &= ~(u16)0x3; + sd_read(intfhdl, ftaddr, 8, tmpbuf); + memcpy(&le_tmp, tmpbuf + shift, 4); + val = le32_to_cpu(le_tmp); + + kfree(tmpbuf); + } + return val; +} + +static s32 sdio_readN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf) +{ + struct adapter *adapter; + u8 mac_pwr_ctrl_on; + u8 device_id; + u16 offset; + u32 ftaddr; + u8 shift; + s32 err; + + adapter = intfhdl->padapter; + err = 0; + + ftaddr = _cvrt2ftaddr(addr, &device_id, &offset); + + rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); + if ( + ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || + (!mac_pwr_ctrl_on) || + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) + ) + return sd_cmd52_read(intfhdl, ftaddr, cnt, buf); + + /* 4 bytes alignment */ + shift = ftaddr & 0x3; + if (shift == 0) { + err = sd_read(intfhdl, ftaddr, cnt, buf); + } else { + u8 *tmpbuf; + u32 n; + + ftaddr &= ~(u16)0x3; + n = cnt + shift; + tmpbuf = rtw_malloc(n); + if (!tmpbuf) + return -1; + + err = sd_read(intfhdl, ftaddr, n, tmpbuf); + if (!err) + memcpy(buf, tmpbuf + shift, cnt); + kfree(tmpbuf); + } + return err; +} + +static s32 sdio_write8(struct intf_hdl *intfhdl, u32 addr, u8 val) +{ + u32 ftaddr; + s32 err; + + ftaddr = _cvrt2ftaddr(addr, NULL, NULL); + sd_write8(intfhdl, ftaddr, val, &err); + + return err; +} + +static s32 sdio_write16(struct intf_hdl *intfhdl, u32 addr, u16 val) +{ + u32 ftaddr; + __le16 le_tmp; + + ftaddr = _cvrt2ftaddr(addr, NULL, NULL); + le_tmp = cpu_to_le16(val); + return sd_cmd52_write(intfhdl, ftaddr, 2, (u8 *)&le_tmp); +} + +static s32 sdio_write32(struct intf_hdl *intfhdl, u32 addr, u32 val) +{ + struct adapter *adapter; + u8 mac_pwr_ctrl_on; + u8 device_id; + u16 offset; + u32 ftaddr; + u8 shift; + s32 err; + __le32 le_tmp; + + adapter = intfhdl->padapter; + err = 0; + + ftaddr = _cvrt2ftaddr(addr, &device_id, &offset); + + rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); + if ( + ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || + (!mac_pwr_ctrl_on) || + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) + ) { + le_tmp = cpu_to_le32(val); + + return sd_cmd52_write(intfhdl, ftaddr, 4, (u8 *)&le_tmp); + } + + /* 4 bytes alignment */ + shift = ftaddr & 0x3; + if (shift == 0) { + sd_write32(intfhdl, ftaddr, val, &err); + } else { + le_tmp = cpu_to_le32(val); + err = sd_cmd52_write(intfhdl, ftaddr, 4, (u8 *)&le_tmp); + } + return err; +} + +static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf) +{ + struct adapter *adapter; + u8 mac_pwr_ctrl_on; + u8 device_id; + u16 offset; + u32 ftaddr; + u8 shift; + s32 err; + + adapter = intfhdl->padapter; + err = 0; + + ftaddr = _cvrt2ftaddr(addr, &device_id, &offset); + + rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); + if ( + ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || + (!mac_pwr_ctrl_on) || + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) + ) + return sd_cmd52_write(intfhdl, ftaddr, cnt, buf); + + shift = ftaddr & 0x3; + if (shift == 0) { + err = sd_write(intfhdl, ftaddr, cnt, buf); + } else { + u8 *tmpbuf; + u32 n; + + ftaddr &= ~(u16)0x3; + n = cnt + shift; + tmpbuf = rtw_malloc(n); + if (!tmpbuf) + return -1; + err = sd_read(intfhdl, ftaddr, 4, tmpbuf); + if (err) { + kfree(tmpbuf); + return err; + } + memcpy(tmpbuf + shift, buf, cnt); + err = sd_write(intfhdl, ftaddr, n, tmpbuf); + kfree(tmpbuf); + } + return err; +} + +static void sdio_read_mem( + struct intf_hdl *intfhdl, + u32 addr, + u32 cnt, + u8 *rmem +) +{ + sdio_readN(intfhdl, addr, cnt, rmem); +} + +static void sdio_write_mem( + struct intf_hdl *intfhdl, + u32 addr, + u32 cnt, + u8 *wmem +) +{ + sdio_writeN(intfhdl, addr, cnt, wmem); +} + +/* + * Description: + *Read from RX FIFO + *Round read size to block size, + *and make sure data transfer will be done in one command. + * + * Parameters: + *intfhdl a pointer of intf_hdl + *addr port ID + *cnt size to read + *rmem address to put data + * + * Return: + *_SUCCESS(1) Success + *_FAIL(0) Fail + */ +static u32 sdio_read_port( + struct intf_hdl *intfhdl, + u32 addr, + u32 cnt, + u8 *mem +) +{ + struct adapter *adapter; + struct sdio_data *psdio; + struct hal_com_data *hal; + s32 err; + + adapter = intfhdl->padapter; + psdio = &adapter_to_dvobj(adapter)->intf_data; + hal = GET_HAL_DATA(adapter); + + hal_sdio_get_cmd_addr_8723b(adapter, addr, hal->SdioRxFIFOCnt++, &addr); + + if (cnt > psdio->block_transfer_len) + cnt = _RND(cnt, psdio->block_transfer_len); + + err = _sd_read(intfhdl, addr, cnt, mem); + + if (err) + return _FAIL; + return _SUCCESS; +} + +/* + * Description: + *Write to TX FIFO + *Align write size block size, + *and make sure data could be written in one command. + * + * Parameters: + *intfhdl a pointer of intf_hdl + *addr port ID + *cnt size to write + *wmem data pointer to write + * + * Return: + *_SUCCESS(1) Success + *_FAIL(0) Fail + */ +static u32 sdio_write_port( + struct intf_hdl *intfhdl, + u32 addr, + u32 cnt, + u8 *mem +) +{ + struct adapter *adapter; + struct sdio_data *psdio; + s32 err; + struct xmit_buf *xmitbuf = (struct xmit_buf *)mem; + + adapter = intfhdl->padapter; + psdio = &adapter_to_dvobj(adapter)->intf_data; + + if (!adapter->hw_init_completed) + return _FAIL; + + cnt = round_up(cnt, 4); + hal_sdio_get_cmd_addr_8723b(adapter, addr, cnt >> 2, &addr); + + if (cnt > psdio->block_transfer_len) + cnt = _RND(cnt, psdio->block_transfer_len); + + err = sd_write(intfhdl, addr, cnt, xmitbuf->pdata); + + rtw_sctx_done_err( + &xmitbuf->sctx, + err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS + ); + + if (err) + return _FAIL; + return _SUCCESS; +} + +void sdio_set_intf_ops(struct adapter *adapter, struct _io_ops *ops) +{ + ops->_read8 = &sdio_read8; + ops->_read16 = &sdio_read16; + ops->_read32 = &sdio_read32; + ops->_read_mem = &sdio_read_mem; + ops->_read_port = &sdio_read_port; + + ops->_write8 = &sdio_write8; + ops->_write16 = &sdio_write16; + ops->_write32 = &sdio_write32; + ops->_writeN = &sdio_writeN; + ops->_write_mem = &sdio_write_mem; + ops->_write_port = &sdio_write_port; +} + +/* + * Todo: align address to 4 bytes. + */ +static s32 _sdio_local_read( + struct adapter *adapter, + u32 addr, + u32 cnt, + u8 *buf +) +{ + struct intf_hdl *intfhdl; + u8 mac_pwr_ctrl_on; + s32 err; + u8 *tmpbuf; + u32 n; + + intfhdl = &adapter->iopriv.intf; + + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + + rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); + if (!mac_pwr_ctrl_on) + return _sd_cmd52_read(intfhdl, addr, cnt, buf); + + n = round_up(cnt, 4); + tmpbuf = rtw_malloc(n); + if (!tmpbuf) + return -1; + + err = _sd_read(intfhdl, addr, n, tmpbuf); + if (!err) + memcpy(buf, tmpbuf, cnt); + + kfree(tmpbuf); + + return err; +} + +/* + * Todo: align address to 4 bytes. + */ +s32 sdio_local_read( + struct adapter *adapter, + u32 addr, + u32 cnt, + u8 *buf +) +{ + struct intf_hdl *intfhdl; + u8 mac_pwr_ctrl_on; + s32 err; + u8 *tmpbuf; + u32 n; + + intfhdl = &adapter->iopriv.intf; + + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + + rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); + if ( + (!mac_pwr_ctrl_on) || + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) + ) + return sd_cmd52_read(intfhdl, addr, cnt, buf); + + n = round_up(cnt, 4); + tmpbuf = rtw_malloc(n); + if (!tmpbuf) + return -1; + + err = sd_read(intfhdl, addr, n, tmpbuf); + if (!err) + memcpy(buf, tmpbuf, cnt); + + kfree(tmpbuf); + + return err; +} + +/* + * Todo: align address to 4 bytes. + */ +s32 sdio_local_write( + struct adapter *adapter, + u32 addr, + u32 cnt, + u8 *buf +) +{ + struct intf_hdl *intfhdl; + u8 mac_pwr_ctrl_on; + s32 err; + u8 *tmpbuf; + + intfhdl = &adapter->iopriv.intf; + + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + + rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); + if ( + (!mac_pwr_ctrl_on) || + (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) + ) + return sd_cmd52_write(intfhdl, addr, cnt, buf); + + tmpbuf = rtw_malloc(cnt); + if (!tmpbuf) + return -1; + + memcpy(tmpbuf, buf, cnt); + + err = sd_write(intfhdl, addr, cnt, tmpbuf); + + kfree(tmpbuf); + + return err; +} + +u8 SdioLocalCmd52Read1Byte(struct adapter *adapter, u32 addr) +{ + u8 val = 0; + struct intf_hdl *intfhdl = &adapter->iopriv.intf; + + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + sd_cmd52_read(intfhdl, addr, 1, &val); + + return val; +} + +static u16 sdio_local_cmd52_read2byte(struct adapter *adapter, u32 addr) +{ + __le16 val = 0; + struct intf_hdl *intfhdl = &adapter->iopriv.intf; + + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + sd_cmd52_read(intfhdl, addr, 2, (u8 *)&val); + + return le16_to_cpu(val); +} + +static u32 sdio_local_cmd53_read4byte(struct adapter *adapter, u32 addr) +{ + + u8 mac_pwr_ctrl_on; + u32 val = 0; + struct intf_hdl *intfhdl = &adapter->iopriv.intf; + __le32 le_tmp; + + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); + if (!mac_pwr_ctrl_on || adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) { + sd_cmd52_read(intfhdl, addr, 4, (u8 *)&le_tmp); + val = le32_to_cpu(le_tmp); + } else { + val = sd_read32(intfhdl, addr, NULL); + } + return val; +} + +void SdioLocalCmd52Write1Byte(struct adapter *adapter, u32 addr, u8 v) +{ + struct intf_hdl *intfhdl = &adapter->iopriv.intf; + + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + sd_cmd52_write(intfhdl, addr, 1, &v); +} + +static void sdio_local_cmd52_write4byte(struct adapter *adapter, u32 addr, u32 v) +{ + struct intf_hdl *intfhdl = &adapter->iopriv.intf; + __le32 le_tmp; + + hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); + le_tmp = cpu_to_le32(v); + sd_cmd52_write(intfhdl, addr, 4, (u8 *)&le_tmp); +} + +static s32 read_interrupt_8723b_sdio(struct adapter *adapter, u32 *phisr) +{ + u32 hisr, himr; + u8 val8, hisr_len; + + if (!phisr) + return false; + + himr = GET_HAL_DATA(adapter)->sdio_himr; + + /* decide how many bytes need to be read */ + hisr_len = 0; + while (himr) { + hisr_len++; + himr >>= 8; + } + + hisr = 0; + while (hisr_len != 0) { + hisr_len--; + val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR + hisr_len); + hisr |= (val8 << (8 * hisr_len)); + } + + *phisr = hisr; + + return true; +} + +/* */ +/* Description: */ +/* Initialize SDIO Host Interrupt Mask configuration variables for future use. */ +/* */ +/* Assumption: */ +/* Using SDIO Local register ONLY for configuration. */ +/* */ +/* Created by Roger, 2011.02.11. */ +/* */ +void InitInterrupt8723BSdio(struct adapter *adapter) +{ + struct hal_com_data *haldata; + + haldata = GET_HAL_DATA(adapter); + haldata->sdio_himr = (u32)(SDIO_HIMR_RX_REQUEST_MSK | + SDIO_HIMR_AVAL_MSK | + 0); +} + +/* */ +/* Description: */ +/* Initialize System Host Interrupt Mask configuration variables for future use. */ +/* */ +/* Created by Roger, 2011.08.03. */ +/* */ +void InitSysInterrupt8723BSdio(struct adapter *adapter) +{ + struct hal_com_data *haldata; + + haldata = GET_HAL_DATA(adapter); + + haldata->SysIntrMask = (0); +} + +/* */ +/* Description: */ +/* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */ +/* */ +/* Assumption: */ +/* 1. Using SDIO Local register ONLY for configuration. */ +/* 2. PASSIVE LEVEL */ +/* */ +/* Created by Roger, 2011.02.11. */ +/* */ +void EnableInterrupt8723BSdio(struct adapter *adapter) +{ + struct hal_com_data *haldata; + __le32 himr; + u32 tmp; + + haldata = GET_HAL_DATA(adapter); + + himr = cpu_to_le32(haldata->sdio_himr); + sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr); + + /* Update current system IMR settings */ + tmp = rtw_read32(adapter, REG_HSIMR); + rtw_write32(adapter, REG_HSIMR, tmp | haldata->SysIntrMask); + + /* */ + /* <Roger_Notes> There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */ + /* So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */ + /* 2011.10.19. */ + /* */ + rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); +} + +/* */ +/* Description: */ +/* Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */ +/* */ +/* Assumption: */ +/* Using SDIO Local register ONLY for configuration. */ +/* */ +/* Created by Roger, 2011.02.11. */ +/* */ +void DisableInterrupt8723BSdio(struct adapter *adapter) +{ + __le32 himr; + + himr = cpu_to_le32(SDIO_HIMR_DISABLED); + sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr); +} + +/* */ +/* Description: */ +/* Using 0x100 to check the power status of FW. */ +/* */ +/* Assumption: */ +/* Using SDIO Local register ONLY for configuration. */ +/* */ +/* Created by Isaac, 2013.09.10. */ +/* */ +u8 CheckIPSStatus(struct adapter *adapter) +{ + if (rtw_read8(adapter, 0x100) == 0xEA) + return true; + else + return false; +} + +static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size) +{ + u32 readsize, ret; + u8 *readbuf; + struct recv_priv *recv_priv; + struct recv_buf *recvbuf; + + /* Patch for some SDIO Host 4 bytes issue */ + /* ex. RK3188 */ + readsize = round_up(size, 4); + + /* 3 1. alloc recvbuf */ + recv_priv = &adapter->recvpriv; + recvbuf = rtw_dequeue_recvbuf(&recv_priv->free_recv_buf_queue); + if (!recvbuf) { + netdev_err(adapter->pnetdev, "%s: alloc recvbuf FAIL!\n", + __func__); + return NULL; + } + + /* 3 2. alloc skb */ + if (!recvbuf->pskb) { + SIZE_PTR tmpaddr = 0; + SIZE_PTR alignment = 0; + + recvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); + if (!recvbuf->pskb) + return NULL; + + recvbuf->pskb->dev = adapter->pnetdev; + + tmpaddr = (SIZE_PTR)recvbuf->pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1); + skb_reserve(recvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); + } + + /* 3 3. read data from rxfifo */ + readbuf = recvbuf->pskb->data; + ret = sdio_read_port(&adapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, readbuf); + if (ret == _FAIL) + return NULL; + + /* 3 4. init recvbuf */ + recvbuf->len = size; + recvbuf->phead = recvbuf->pskb->head; + recvbuf->pdata = recvbuf->pskb->data; + skb_set_tail_pointer(recvbuf->pskb, size); + recvbuf->ptail = skb_tail_pointer(recvbuf->pskb); + recvbuf->pend = skb_end_pointer(recvbuf->pskb); + + return recvbuf; +} + +static void sd_rxhandler(struct adapter *adapter, struct recv_buf *recvbuf) +{ + struct recv_priv *recv_priv; + struct __queue *pending_queue; + + recv_priv = &adapter->recvpriv; + pending_queue = &recv_priv->recv_buf_pending_queue; + + /* 3 1. enqueue recvbuf */ + rtw_enqueue_recvbuf(recvbuf, pending_queue); + + /* 3 2. schedule tasklet */ + tasklet_schedule(&recv_priv->recv_tasklet); +} + +void sd_int_dpc(struct adapter *adapter) +{ + struct hal_com_data *hal; + struct dvobj_priv *dvobj; + struct intf_hdl *intfhdl = &adapter->iopriv.intf; + struct pwrctrl_priv *pwrctl; + + hal = GET_HAL_DATA(adapter); + dvobj = adapter_to_dvobj(adapter); + pwrctl = dvobj_to_pwrctl(dvobj); + + if (hal->sdio_hisr & SDIO_HISR_AVAL) { + u8 freepage[4]; + + _sdio_local_read(adapter, SDIO_REG_FREE_TXPG, 4, freepage); + complete(&(adapter->xmitpriv.xmit_comp)); + } + + if (hal->sdio_hisr & SDIO_HISR_CPWM1) { + del_timer_sync(&(pwrctl->pwr_rpwm_timer)); + + SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HCPWM1_8723B); + + _set_workitem(&(pwrctl->cpwm_event)); + } + + if (hal->sdio_hisr & SDIO_HISR_TXERR) { + u8 *status; + u32 addr; + + status = rtw_malloc(4); + if (status) { + addr = REG_TXDMA_STATUS; + hal_sdio_get_cmd_addr_8723b(adapter, WLAN_IOREG_DEVICE_ID, addr, &addr); + _sd_read(intfhdl, addr, 4, status); + _sd_write(intfhdl, addr, 4, status); + kfree(status); + } + } + + if (hal->sdio_hisr & SDIO_HISR_C2HCMD) { + struct c2h_evt_hdr_88xx *c2h_evt; + + c2h_evt = rtw_zmalloc(16); + if (c2h_evt) { + if (c2h_evt_read_88xx(adapter, (u8 *)c2h_evt) == _SUCCESS) { + if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) { + /* Handle CCX report here */ + rtw_hal_c2h_handler(adapter, (u8 *)c2h_evt); + kfree(c2h_evt); + } else { + rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt); + } + } else { + kfree(c2h_evt); + } + } else { + /* Error handling for malloc fail */ + rtw_cbuf_push(adapter->evtpriv.c2h_queue, NULL); + _set_workitem(&adapter->evtpriv.c2h_wk); + } + } + + if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) { + struct recv_buf *recvbuf; + int alloc_fail_time = 0; + u32 hisr; + + hal->sdio_hisr ^= SDIO_HISR_RX_REQUEST; + do { + hal->SdioRxFIFOSize = sdio_local_cmd52_read2byte(adapter, SDIO_REG_RX0_REQ_LEN); + if (hal->SdioRxFIFOSize != 0) { + recvbuf = sd_recv_rxfifo(adapter, hal->SdioRxFIFOSize); + if (recvbuf) + sd_rxhandler(adapter, recvbuf); + else { + alloc_fail_time++; + if (alloc_fail_time >= 10) + break; + } + hal->SdioRxFIFOSize = 0; + } else + break; + + hisr = 0; + read_interrupt_8723b_sdio(adapter, &hisr); + hisr &= SDIO_HISR_RX_REQUEST; + if (!hisr) + break; + } while (1); + } +} + +void sd_int_hdl(struct adapter *adapter) +{ + struct hal_com_data *hal; + + if ( + (adapter->bDriverStopped) || (adapter->bSurpriseRemoved) + ) + return; + + hal = GET_HAL_DATA(adapter); + + hal->sdio_hisr = 0; + read_interrupt_8723b_sdio(adapter, &hal->sdio_hisr); + + if (hal->sdio_hisr & hal->sdio_himr) { + u32 v32; + + hal->sdio_hisr &= hal->sdio_himr; + + /* clear HISR */ + v32 = hal->sdio_hisr & MASK_SDIO_HISR_CLEAR; + if (v32) + sdio_local_cmd52_write4byte(adapter, SDIO_REG_HISR, v32); + + sd_int_dpc(adapter); + } +} + +/* */ +/* Description: */ +/* Query SDIO Local register to query current the number of Free TxPacketBuffer page. */ +/* */ +/* Assumption: */ +/* 1. Running at PASSIVE_LEVEL */ +/* 2. RT_TX_SPINLOCK is NOT acquired. */ +/* */ +/* Created by Roger, 2011.01.28. */ +/* */ +u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter) +{ + struct hal_com_data *hal; + u32 numof_free_page; + + hal = GET_HAL_DATA(adapter); + + numof_free_page = sdio_local_cmd53_read4byte(adapter, SDIO_REG_FREE_TXPG); + + memcpy(hal->SdioTxFIFOFreePage, &numof_free_page, 4); + + return true; +} + +/* */ +/* Description: */ +/* Query SDIO Local register to get the current number of TX OQT Free Space. */ +/* */ +void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter) +{ + struct hal_com_data *haldata = GET_HAL_DATA(adapter); + + haldata->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_OQT_FREE_PG); +} + + |