/****************************************************************************** * * Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved. * * 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. * ******************************************************************************/ #include "halmac_sdio_88xx.h" #include "halmac_88xx_cfg.h" #if HALMAC_88XX_SUPPORT /* define the SDIO Bus CLK threshold */ /* for avoiding CMD53 fails that result from SDIO CLK sync to ana_clk fail */ #define SDIO_CLK_HIGH_SPEED_TH 50 /* 50MHz */ #define SDIO_CLK_SPEED_MAX 208 /* 208MHz */ /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u8 r_indir_cmd52_88xx(struct halmac_adapter *adapter, u32 offset); /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u32 r_indir_cmd53_88xx(struct halmac_adapter *adapter, u32 offset); /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u32 r8_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr); /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u32 r16_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr); /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u32 r32_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr); /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w_indir_cmd52_88xx(struct halmac_adapter *adapter, u32 adr, u32 val, enum halmac_io_size size); /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w_indir_cmd53_88xx(struct halmac_adapter *adapter, u32 adr, u32 val, enum halmac_io_size size); /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w8_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr, u32 val); /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w16_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr, u32 val); /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w32_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr, u32 val); /** * init_sdio_cfg_88xx() - init SDIO * @adapter : the adapter of halmac * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status init_sdio_cfg_88xx(struct halmac_adapter *adapter) { u32 value32; struct halmac_api *api = (struct halmac_api *)adapter->halmac_api; if (adapter->intf != HALMAC_INTERFACE_SDIO) return HALMAC_RET_WRONG_INTF; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); HALMAC_REG_R32(REG_SDIO_FREE_TXPG); value32 = HALMAC_REG_R32(REG_SDIO_TX_CTRL) & 0xFFFF; value32 &= ~(BIT_CMD_ERR_STOP_INT_EN | BIT_EN_MASK_TIMER | BIT_EN_RXDMA_MASK_INT); HALMAC_REG_W32(REG_SDIO_TX_CTRL, value32); PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } /** * deinit_sdio_cfg_88xx() - deinit SDIO * @adapter : the adapter of halmac * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status deinit_sdio_cfg_88xx(struct halmac_adapter *adapter) { if (adapter->intf != HALMAC_INTERFACE_SDIO) return HALMAC_RET_WRONG_INTF; return HALMAC_RET_SUCCESS; } /** * cfg_sdio_rx_agg_88xx() - config rx aggregation * @adapter : the adapter of halmac * @halmac_rx_agg_mode * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status cfg_sdio_rx_agg_88xx(struct halmac_adapter *adapter, struct halmac_rxagg_cfg *cfg) { u8 value8; u8 size; u8 timeout; u8 agg_enable; u32 value32; struct halmac_api *api = (struct halmac_api *)adapter->halmac_api; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); agg_enable = HALMAC_REG_R8(REG_TXDMA_PQ_MAP); switch (cfg->mode) { case HALMAC_RX_AGG_MODE_NONE: agg_enable &= ~(BIT_RXDMA_AGG_EN); break; case HALMAC_RX_AGG_MODE_DMA: case HALMAC_RX_AGG_MODE_USB: agg_enable |= BIT_RXDMA_AGG_EN; break; default: PLTFM_MSG_ERR("[ERR]unsupported mode\n"); agg_enable &= ~BIT_RXDMA_AGG_EN; break; } if (cfg->threshold.drv_define == _FALSE) { size = 0xFF; timeout = 0x01; } else { size = cfg->threshold.size; timeout = cfg->threshold.timeout; } value32 = HALMAC_REG_R32(REG_RXDMA_AGG_PG_TH); if (cfg->threshold.size_limit_en == _FALSE) HALMAC_REG_W32(REG_RXDMA_AGG_PG_TH, value32 & ~BIT_EN_PRE_CALC); else HALMAC_REG_W32(REG_RXDMA_AGG_PG_TH, value32 | BIT_EN_PRE_CALC); HALMAC_REG_W8(REG_TXDMA_PQ_MAP, agg_enable); HALMAC_REG_W16(REG_RXDMA_AGG_PG_TH, (u16)(size | (timeout << BIT_SHIFT_DMA_AGG_TO_V1))); value8 = HALMAC_REG_R8(REG_RXDMA_MODE); if (0 != (agg_enable & BIT_RXDMA_AGG_EN)) HALMAC_REG_W8(REG_RXDMA_MODE, value8 | BIT_DMA_MODE); else HALMAC_REG_W8(REG_RXDMA_MODE, value8 & ~(BIT_DMA_MODE)); PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } /** * sdio_reg_rn_88xx() - read n byte register * @adapter : the adapter of halmac * @offset : register offset * @halmac_size : register value size * @value : register value * Author : Soar * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status sdio_reg_rn_88xx(struct halmac_adapter *adapter, u32 offset, u32 size, u8 *value) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; if (0 == (offset & 0xFFFF0000)) { PLTFM_MSG_ERR("[ERR]offset 0x%x\n", offset); return HALMAC_RET_FAIL; } status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF) { PLTFM_MSG_ERR("[ERR]power off\n"); return HALMAC_RET_FAIL; } PLTFM_SDIO_CMD53_RN(offset, size, value); return HALMAC_RET_SUCCESS; } /** * cfg_txagg_sdio_align_88xx() -config sdio bus tx agg alignment * @adapter : the adapter of halmac * @enable : function enable(1)/disable(0) * @align_size : sdio bus tx agg alignment size (2^n, n = 3~11) * Author : Soar Tu * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status cfg_txagg_sdio_align_88xx(struct halmac_adapter *adapter, u8 enable, u16 align_size) { u8 i; u8 flag = 0; struct halmac_api *api = (struct halmac_api *)adapter->halmac_api; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); if (adapter->chip_id == HALMAC_CHIP_ID_8822B) return HALMAC_RET_NOT_SUPPORT; if ((align_size & 0xF000) != 0) { PLTFM_MSG_ERR("[ERR]out of range\n"); return HALMAC_RET_FAIL; } for (i = 3; i <= 11; i++) { if (align_size == 1 << i) { flag = 1; break; } } if (flag == 0) { PLTFM_MSG_ERR("[ERR]not 2^3 ~ 2^11\n"); return HALMAC_RET_FAIL; } adapter->hw_cfg_info.tx_align_size = align_size; if (enable) HALMAC_REG_W16(REG_RQPN_CTRL_2, 0x8000 | align_size); else HALMAC_REG_W16(REG_RQPN_CTRL_2, align_size); PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } /** * sdio_indirect_reg_r32_88xx() - read MAC reg by SDIO reg * @adapter : the adapter of halmac * @offset : register offset * Author : Soar * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ u32 sdio_indirect_reg_r32_88xx(struct halmac_adapter *adapter, u32 offset) { return r_indir_sdio_88xx(adapter, offset, HALMAC_IO_DWORD); } /** * set_sdio_bulkout_num_88xx() - inform bulk-out num * @adapter : the adapter of halmac * @bulkout_num : usb bulk-out number * Author : KaiYuan Chang * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status set_sdio_bulkout_num_88xx(struct halmac_adapter *adapter, u8 num) { return HALMAC_RET_NOT_SUPPORT; } /** * get_sdio_bulkout_id_88xx() - get bulk out id for the TX packet * @adapter : the adapter of halmac * @halmac_buf : tx packet, include txdesc * @halmac_size : tx packet size * @bulkout_id : usb bulk-out id * Author : KaiYuan Chang * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status get_sdio_bulkout_id_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size, u8 *id) { return HALMAC_RET_NOT_SUPPORT; } /** * sdio_cmd53_4byte_88xx() - cmd53 only for 4byte len register IO * @adapter : the adapter of halmac * @enable : 1->CMD53 only use in 4byte reg, 0 : No limitation * Author : Ivan Lin/KaiYuan Chang * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status sdio_cmd53_4byte_88xx(struct halmac_adapter *adapter, enum halmac_sdio_cmd53_4byte_mode mode) { if (adapter->intf != HALMAC_INTERFACE_SDIO) return HALMAC_RET_WRONG_INTF; if (adapter->api_registry.sdio_cmd53_4byte_en == 0) return HALMAC_RET_NOT_SUPPORT; adapter->sdio_cmd53_4byte = mode; return HALMAC_RET_SUCCESS; } /** * sdio_hw_info_88xx() - info sdio hw info * @adapter : the adapter of halmac * @HALMAC_SDIO_CMD53_4BYTE_MODE : * clock_speed : sdio bus clock. Unit -> MHz * spec_ver : sdio spec version * Author : Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status sdio_hw_info_88xx(struct halmac_adapter *adapter, struct halmac_sdio_hw_info *info) { PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); if (adapter->intf != HALMAC_INTERFACE_SDIO) return HALMAC_RET_WRONG_INTF; PLTFM_MSG_TRACE("[TRACE]SDIO clock:%d, spec:%d\n", info->clock_speed, info->spec_ver); if (info->clock_speed > SDIO_CLK_SPEED_MAX) return HALMAC_RET_SDIO_CLOCK_ERR; if (info->clock_speed > SDIO_CLK_HIGH_SPEED_TH) adapter->sdio_hw_info.io_hi_speed_flag = 1; adapter->sdio_hw_info.io_indir_flag = info->io_indir_flag; if (info->clock_speed > SDIO_CLK_HIGH_SPEED_TH && adapter->sdio_hw_info.io_indir_flag == 0) PLTFM_MSG_WARN("[WARN]SDIO clock:%d, indir access is better\n", info->clock_speed); adapter->sdio_hw_info.clock_speed = info->clock_speed; adapter->sdio_hw_info.spec_ver = info->spec_ver; adapter->sdio_hw_info.block_size = info->block_size; PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } void cfg_sdio_tx_page_threshold_88xx(struct halmac_adapter *adapter, struct halmac_tx_page_threshold_info *info) { struct halmac_api *api = (struct halmac_api *)adapter->halmac_api; u32 threshold = info->threshold; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); if (info->enable == 1) { threshold = BIT(31) | threshold; PLTFM_MSG_TRACE("[TRACE]enable\n"); } else { threshold = ~(BIT(31)) & threshold; PLTFM_MSG_TRACE("[TRACE]disable\n"); } switch (info->dma_queue_sel) { case HALMAC_MAP2_HQ: HALMAC_REG_W32(REG_TQPNT1, threshold); break; case HALMAC_MAP2_NQ: HALMAC_REG_W32(REG_TQPNT2, threshold); break; case HALMAC_MAP2_LQ: HALMAC_REG_W32(REG_TQPNT3, threshold); break; case HALMAC_MAP2_EXQ: HALMAC_REG_W32(REG_TQPNT4, threshold); break; default: break; } PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); } enum halmac_ret_status cnv_to_sdio_bus_offset_88xx(struct halmac_adapter *adapter, u32 *offset) { switch ((*offset) & 0xFFFF0000) { case WLAN_IOREG_OFFSET: *offset &= HALMAC_WLAN_MAC_REG_MSK; *offset |= HALMAC_SDIO_CMD_ADDR_MAC_REG << 13; break; case SDIO_LOCAL_OFFSET: *offset &= HALMAC_SDIO_LOCAL_MSK; *offset |= HALMAC_SDIO_CMD_ADDR_SDIO_REG << 13; break; default: *offset = 0xFFFFFFFF; PLTFM_MSG_ERR("[ERR]base address!!\n"); return HALMAC_RET_CONVERT_SDIO_OFFSET_FAIL; } return HALMAC_RET_SUCCESS; } enum halmac_ret_status leave_sdio_suspend_88xx(struct halmac_adapter *adapter) { u8 value8; u32 cnt; struct halmac_api *api = (struct halmac_api *)adapter->halmac_api; value8 = HALMAC_REG_R8(REG_SDIO_HSUS_CTRL); HALMAC_REG_W8(REG_SDIO_HSUS_CTRL, value8 & ~(BIT(0))); cnt = 10000; while (!(HALMAC_REG_R8(REG_SDIO_HSUS_CTRL) & 0x02)) { cnt--; if (cnt == 0) return HALMAC_RET_SDIO_LEAVE_SUSPEND_FAIL; } value8 = HALMAC_REG_R8(REG_HCI_OPT_CTRL + 2); if (adapter->sdio_hw_info.spec_ver == HALMAC_SDIO_SPEC_VER_3_00) HALMAC_REG_W8(REG_HCI_OPT_CTRL + 2, value8 | BIT(2)); else HALMAC_REG_W8(REG_HCI_OPT_CTRL + 2, value8 & ~(BIT(2))); return HALMAC_RET_SUCCESS; } /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u8 r_indir_cmd52_88xx(struct halmac_adapter *adapter, u32 offset) { u8 value8, tmp, cnt = 50; u32 reg_cfg = REG_SDIO_INDIRECT_REG_CFG; u32 reg_data = REG_SDIO_INDIRECT_REG_DATA; enum halmac_ret_status status = HALMAC_RET_SUCCESS; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_cfg); if (status != HALMAC_RET_SUCCESS) return status; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_data); if (status != HALMAC_RET_SUCCESS) return status; PLTFM_SDIO_CMD52_W(reg_cfg, (u8)offset); PLTFM_SDIO_CMD52_W(reg_cfg + 1, (u8)(offset >> 8)); PLTFM_SDIO_CMD52_W(reg_cfg + 2, (u8)(BIT(3) | BIT(4))); do { tmp = PLTFM_SDIO_CMD52_R(reg_cfg + 2); cnt--; } while (((tmp & BIT(4)) == 0) && (cnt > 0)); if (((cnt & BIT(4)) == 0) && cnt == 0) PLTFM_MSG_ERR("[ERR]sdio indirect CMD52 read\n"); value8 = PLTFM_SDIO_CMD52_R(reg_data); return value8; } /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u32 r_indir_cmd53_88xx(struct halmac_adapter *adapter, u32 offset) { u8 tmp, cnt = 50; u32 reg_cfg = REG_SDIO_INDIRECT_REG_CFG; u32 reg_data = REG_SDIO_INDIRECT_REG_DATA; enum halmac_ret_status status = HALMAC_RET_SUCCESS; union { u32 dword; u8 byte[4]; } value32 = { 0x00000000 }; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_cfg); if (status != HALMAC_RET_SUCCESS) return status; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_data); if (status != HALMAC_RET_SUCCESS) return status; PLTFM_SDIO_CMD53_W32(reg_cfg, offset | BIT(19) | BIT(20)); do { tmp = PLTFM_SDIO_CMD52_R(reg_cfg + 2); cnt--; } while (((tmp & BIT(4)) == 0) && (cnt > 0)); if (((cnt & BIT(4)) == 0) && cnt == 0) PLTFM_MSG_ERR("[ERR]sdio indirect CMD53 read\n"); value32.dword = PLTFM_SDIO_CMD53_R32(reg_data); return value32.dword; } /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u32 r8_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr) { union { u32 dword; u8 byte[4]; } val = { 0x00000000 }; if (adapter->pwr_off_flow_flag == 1 || adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF) { val.byte[0] = r_indir_cmd52_88xx(adapter, adr); val.dword = rtk_le32_to_cpu(val.dword); } else { val.dword = r_indir_cmd53_88xx(adapter, adr); } return val.dword; } /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u32 r16_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr) { u32 reg_data = REG_SDIO_INDIRECT_REG_DATA; enum halmac_ret_status status = HALMAC_RET_SUCCESS; union { u32 dword; u8 byte[4]; } val = { 0x00000000 }; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_data); if (status != HALMAC_RET_SUCCESS) return status; if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF) { if (0 != (adr & (2 - 1))) { val.byte[0] = r_indir_cmd52_88xx(adapter, adr); val.byte[1] = r_indir_cmd52_88xx(adapter, adr + 1); } else { val.byte[0] = r_indir_cmd52_88xx(adapter, adr); val.byte[1] = PLTFM_SDIO_CMD52_R(reg_data + 1); } val.dword = rtk_le32_to_cpu(val.dword); } else { if (0 != (adr & (2 - 1))) { val.byte[0] = (u8)r_indir_cmd53_88xx(adapter, adr); val.byte[1] = (u8)r_indir_cmd53_88xx(adapter, adr + 1); val.dword = rtk_le32_to_cpu(val.dword); } else { val.dword = r_indir_cmd53_88xx(adapter, adr); } } return val.dword; } /*only for r_indir_sdio_88xx !!, Soar 20171222*/ static u32 r32_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr) { u32 reg_data = REG_SDIO_INDIRECT_REG_DATA; enum halmac_ret_status status = HALMAC_RET_SUCCESS; union { u32 dword; u8 byte[4]; } val = { 0x00000000 }; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_data); if (status != HALMAC_RET_SUCCESS) return status; if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF) { if (0 != (adr & (4 - 1))) { val.byte[0] = r_indir_cmd52_88xx(adapter, adr); val.byte[1] = r_indir_cmd52_88xx(adapter, adr + 1); val.byte[2] = r_indir_cmd52_88xx(adapter, adr + 2); val.byte[3] = r_indir_cmd52_88xx(adapter, adr + 3); } else { val.byte[0] = r_indir_cmd52_88xx(adapter, adr); val.byte[1] = PLTFM_SDIO_CMD52_R(reg_data + 1); val.byte[2] = PLTFM_SDIO_CMD52_R(reg_data + 2); val.byte[3] = PLTFM_SDIO_CMD52_R(reg_data + 3); } val.dword = rtk_le32_to_cpu(val.dword); } else { if (0 != (adr & (4 - 1))) { val.byte[0] = (u8)r_indir_cmd53_88xx(adapter, adr); val.byte[1] = (u8)r_indir_cmd53_88xx(adapter, adr + 1); val.byte[2] = (u8)r_indir_cmd53_88xx(adapter, adr + 2); val.byte[3] = (u8)r_indir_cmd53_88xx(adapter, adr + 3); val.dword = rtk_le32_to_cpu(val.dword); } else { val.dword = r_indir_cmd53_88xx(adapter, adr); } } return val.dword; } u32 r_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr, enum halmac_io_size size) { u32 reg_data = REG_SDIO_INDIRECT_REG_DATA; enum halmac_ret_status status = HALMAC_RET_SUCCESS; union { u32 dword; u8 byte[4]; } val = { 0x00000000 }; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_data); if (status != HALMAC_RET_SUCCESS) return status; PLTFM_MUTEX_LOCK(&adapter->sdio_indir_mutex); switch (size) { case HALMAC_IO_BYTE: val.dword = r8_indir_sdio_88xx(adapter, adr); break; case HALMAC_IO_WORD: val.dword = r16_indir_sdio_88xx(adapter, adr); break; case HALMAC_IO_DWORD: val.dword = r32_indir_sdio_88xx(adapter, adr); break; default: break; } PLTFM_MUTEX_UNLOCK(&adapter->sdio_indir_mutex); return val.dword; } /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w_indir_cmd52_88xx(struct halmac_adapter *adapter, u32 adr, u32 val, enum halmac_io_size size) { u8 tmp, cnt = 50; u32 reg_cfg = REG_SDIO_INDIRECT_REG_CFG; u32 reg_data = REG_SDIO_INDIRECT_REG_DATA; enum halmac_ret_status status = HALMAC_RET_SUCCESS; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_cfg); if (status != HALMAC_RET_SUCCESS) return status; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_data); if (status != HALMAC_RET_SUCCESS) return status; PLTFM_SDIO_CMD52_W(reg_cfg, (u8)adr); PLTFM_SDIO_CMD52_W(reg_cfg + 1, (u8)(adr >> 8)); switch (size) { case HALMAC_IO_BYTE: PLTFM_SDIO_CMD52_W(reg_data, (u8)val); PLTFM_SDIO_CMD52_W(reg_cfg + 2, (u8)(BIT(2) | BIT(4))); break; case HALMAC_IO_WORD: PLTFM_SDIO_CMD52_W(reg_data, (u8)val); PLTFM_SDIO_CMD52_W(reg_data + 1, (u8)(val >> 8)); PLTFM_SDIO_CMD52_W(reg_cfg + 2, (u8)(BIT(0) | BIT(2) | BIT(4))); break; case HALMAC_IO_DWORD: PLTFM_SDIO_CMD52_W(reg_data, (u8)val); PLTFM_SDIO_CMD52_W(reg_data + 1, (u8)(val >> 8)); PLTFM_SDIO_CMD52_W(reg_data + 2, (u8)(val >> 16)); PLTFM_SDIO_CMD52_W(reg_data + 3, (u8)(val >> 24)); PLTFM_SDIO_CMD52_W(reg_cfg + 2, (u8)(BIT(1) | BIT(2) | BIT(4))); break; default: break; } do { tmp = PLTFM_SDIO_CMD52_R(reg_cfg + 2); cnt--; } while (((tmp & BIT(4)) == 0) && (cnt > 0)); if (((cnt & BIT(4)) == 0) && cnt == 0) PLTFM_MSG_ERR("[ERR]sdio indirect CMD52 write\n"); return status; } /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w_indir_cmd53_88xx(struct halmac_adapter *adapter, u32 adr, u32 val, enum halmac_io_size size) { u8 tmp, cnt = 50; u32 reg_cfg = REG_SDIO_INDIRECT_REG_CFG; u32 reg_data = REG_SDIO_INDIRECT_REG_DATA; u32 value32 = 0; enum halmac_ret_status status = HALMAC_RET_SUCCESS; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_cfg); if (status != HALMAC_RET_SUCCESS) return status; status = cnv_to_sdio_bus_offset_88xx(adapter, ®_data); if (status != HALMAC_RET_SUCCESS) return status; switch (size) { case HALMAC_IO_BYTE: value32 = adr | BIT(18) | BIT(20); break; case HALMAC_IO_WORD: value32 = adr | BIT(16) | BIT(18) | BIT(20); break; case HALMAC_IO_DWORD: value32 = adr | BIT(17) | BIT(18) | BIT(20); break; default: return HALMAC_RET_FAIL; } PLTFM_SDIO_CMD53_W32(reg_data, val); PLTFM_SDIO_CMD53_W32(reg_cfg, value32); do { tmp = PLTFM_SDIO_CMD52_R(reg_cfg + 2); cnt--; } while (((tmp & BIT(4)) == 0) && (cnt > 0)); if (((cnt & BIT(4)) == 0) && cnt == 0) PLTFM_MSG_ERR("[ERR]sdio indirect CMD53 read\n"); return status; } /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w8_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr, u32 val) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; if (adapter->pwr_off_flow_flag == 1 || adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF) status = w_indir_cmd52_88xx(adapter, adr, val, HALMAC_IO_BYTE); else status = w_indir_cmd53_88xx(adapter, adr, val, HALMAC_IO_BYTE); return status; } /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w16_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr, u32 val) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF) { if (0 != (adr & (2 - 1))) { status = w_indir_cmd52_88xx(adapter, adr, val, HALMAC_IO_BYTE); if (status != HALMAC_RET_SUCCESS) return status; status = w_indir_cmd52_88xx(adapter, adr + 1, val >> 8, HALMAC_IO_BYTE); } else { status = w_indir_cmd52_88xx(adapter, adr, val, HALMAC_IO_WORD); } } else { if (0 != (adr & (2 - 1))) { status = w_indir_cmd53_88xx(adapter, adr, val, HALMAC_IO_BYTE); if (status != HALMAC_RET_SUCCESS) return status; status = w_indir_cmd53_88xx(adapter, adr + 1, val >> 8, HALMAC_IO_BYTE); } else { status = w_indir_cmd53_88xx(adapter, adr, val, HALMAC_IO_WORD); } } return status; } /*only for w_indir_sdio_88xx !!, Soar 20171222*/ static enum halmac_ret_status w32_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr, u32 val) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF) { if (0 != (adr & (4 - 1))) { status = w_indir_cmd52_88xx(adapter, adr, val, HALMAC_IO_BYTE); if (status != HALMAC_RET_SUCCESS) return status; status = w_indir_cmd52_88xx(adapter, adr + 1, val >> 8, HALMAC_IO_BYTE); if (status != HALMAC_RET_SUCCESS) return status; status = w_indir_cmd52_88xx(adapter, adr + 2, val >> 16, HALMAC_IO_BYTE); if (status != HALMAC_RET_SUCCESS) return status; status = w_indir_cmd52_88xx(adapter, adr + 3, val >> 24, HALMAC_IO_BYTE); } else { status = w_indir_cmd52_88xx(adapter, adr, val, HALMAC_IO_DWORD); } } else { if (0 != (adr & (4 - 1))) { status = w_indir_cmd53_88xx(adapter, adr, val, HALMAC_IO_BYTE); if (status != HALMAC_RET_SUCCESS) return status; status = w_indir_cmd53_88xx(adapter, adr + 1, val >> 8, HALMAC_IO_BYTE); if (status != HALMAC_RET_SUCCESS) return status; status = w_indir_cmd53_88xx(adapter, adr + 2, val >> 16, HALMAC_IO_BYTE); if (status != HALMAC_RET_SUCCESS) return status; status = w_indir_cmd53_88xx(adapter, adr + 3, val >> 24, HALMAC_IO_BYTE); } else { status = w_indir_cmd53_88xx(adapter, adr, val, HALMAC_IO_DWORD); } } return status; } enum halmac_ret_status w_indir_sdio_88xx(struct halmac_adapter *adapter, u32 adr, u32 val, enum halmac_io_size size) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; PLTFM_MUTEX_LOCK(&adapter->sdio_indir_mutex); switch (size) { case HALMAC_IO_BYTE: status = w8_indir_sdio_88xx(adapter, adr, val); break; case HALMAC_IO_WORD: status = w16_indir_sdio_88xx(adapter, adr, val); break; case HALMAC_IO_DWORD: status = w32_indir_sdio_88xx(adapter, adr, val); break; default: break; } PLTFM_MUTEX_UNLOCK(&adapter->sdio_indir_mutex); return status; } #endif /* HALMAC_88XX_SUPPORT */