// SPDX-License-Identifier: GPL-2.0 /****************************************************************************** * * Copyright(c) 2016 Realtek Corporation. * * Contact Information: * wlanfae * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * * Larry Finger * *****************************************************************************/ #include "halmac_2_platform.h" #include "halmac_type.h" #include "halmac_88xx/halmac_api_88xx.h" #include "halmac_88xx/halmac_88xx_cfg.h" #include "halmac_88xx/halmac_8822b/halmac_8822b_cfg.h" static enum halmac_ret_status halmac_check_platform_api(void *driver_adapter, enum halmac_interface halmac_interface, struct halmac_platform_api *halmac_platform_api) { void *adapter_local = NULL; adapter_local = driver_adapter; if (!halmac_platform_api) return HALMAC_RET_PLATFORM_API_NULL; if (halmac_interface == HALMAC_INTERFACE_SDIO) { if (!halmac_platform_api->SDIO_CMD52_READ) { pr_err("(!halmac_platform_api->SDIO_CMD52_READ)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->SDIO_CMD53_READ_8) { pr_err("(!halmac_platform_api->SDIO_CMD53_READ_8)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->SDIO_CMD53_READ_16) { pr_err("(!halmac_platform_api->SDIO_CMD53_READ_16)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->SDIO_CMD53_READ_32) { pr_err("(!halmac_platform_api->SDIO_CMD53_READ_32)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->SDIO_CMD53_READ_N) { pr_err("(!halmac_platform_api->SDIO_CMD53_READ_N)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->SDIO_CMD52_WRITE) { pr_err("(!halmac_platform_api->SDIO_CMD52_WRITE)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->SDIO_CMD53_WRITE_8) { pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_8)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->SDIO_CMD53_WRITE_16) { pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_16)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->SDIO_CMD53_WRITE_32) { pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_32)\n"); return HALMAC_RET_PLATFORM_API_NULL; } } if (halmac_interface == HALMAC_INTERFACE_USB || halmac_interface == HALMAC_INTERFACE_PCIE) { if (!halmac_platform_api->REG_READ_8) { pr_err("(!halmac_platform_api->REG_READ_8)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->REG_READ_16) { pr_err("(!halmac_platform_api->REG_READ_16)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->REG_READ_32) { pr_err("(!halmac_platform_api->REG_READ_32)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->REG_WRITE_8) { pr_err("(!halmac_platform_api->REG_WRITE_8)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->REG_WRITE_16) { pr_err("(!halmac_platform_api->REG_WRITE_16)\n"); return HALMAC_RET_PLATFORM_API_NULL; } if (!halmac_platform_api->REG_WRITE_32) { pr_err("(!halmac_platform_api->REG_WRITE_32)\n"); return HALMAC_RET_PLATFORM_API_NULL; } } if (!halmac_platform_api->EVENT_INDICATION) { pr_err("(!halmac_platform_api->EVENT_INDICATION)\n"); return HALMAC_RET_PLATFORM_API_NULL; } HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "%s ==========>\n", __func__); return HALMAC_RET_SUCCESS; } static enum halmac_ret_status halmac_convert_to_sdio_bus_offset(u32 *halmac_offset) { switch ((*halmac_offset) & 0xFFFF0000) { case WLAN_IOREG_OFFSET: *halmac_offset = (HALMAC_SDIO_CMD_ADDR_MAC_REG << 13) | (*halmac_offset & HALMAC_WLAN_MAC_REG_MSK); break; case SDIO_LOCAL_OFFSET: *halmac_offset = (HALMAC_SDIO_CMD_ADDR_SDIO_REG << 13) | (*halmac_offset & HALMAC_SDIO_LOCAL_MSK); break; default: *halmac_offset = 0xFFFFFFFF; return HALMAC_RET_CONVERT_SDIO_OFFSET_FAIL; } return HALMAC_RET_SUCCESS; } static u8 platform_reg_read_8_sdio(void *driver_adapter, struct halmac_platform_api *halmac_platform_api, u32 offset) { u8 value8; u32 halmac_offset = offset; enum halmac_ret_status status = HALMAC_RET_SUCCESS; if ((halmac_offset & 0xFFFF0000) == 0) halmac_offset |= WLAN_IOREG_OFFSET; status = halmac_convert_to_sdio_bus_offset(&halmac_offset); if (status != HALMAC_RET_SUCCESS) { pr_err("%s error = %x\n", __func__, status); return status; } value8 = halmac_platform_api->SDIO_CMD52_READ(driver_adapter, halmac_offset); return value8; } static enum halmac_ret_status platform_reg_write_8_sdio(void *driver_adapter, struct halmac_platform_api *halmac_platform_api, u32 offset, u8 data) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; u32 halmac_offset = offset; if ((halmac_offset & 0xFFFF0000) == 0) halmac_offset |= WLAN_IOREG_OFFSET; status = halmac_convert_to_sdio_bus_offset(&halmac_offset); if (status != HALMAC_RET_SUCCESS) { pr_err("halmac_reg_write_8_sdio_88xx error = %x\n", status); return status; } halmac_platform_api->SDIO_CMD52_WRITE(driver_adapter, halmac_offset, data); return HALMAC_RET_SUCCESS; } static enum halmac_ret_status halmac_get_chip_info(void *driver_adapter, struct halmac_platform_api *halmac_platform_api, enum halmac_interface halmac_interface, struct halmac_adapter *halmac_adapter) { struct halmac_api *halmac_api = (struct halmac_api *)NULL; u8 chip_id, chip_version; u32 polling_count; halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; /* Get Chip_id and Chip_version */ if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) { platform_reg_write_8_sdio( driver_adapter, halmac_platform_api, REG_SDIO_HSUS_CTRL, platform_reg_read_8_sdio(driver_adapter, halmac_platform_api, REG_SDIO_HSUS_CTRL) & ~(BIT(0))); polling_count = 10000; while (!(platform_reg_read_8_sdio(driver_adapter, halmac_platform_api, REG_SDIO_HSUS_CTRL) & 0x02)) { polling_count--; if (polling_count == 0) return HALMAC_RET_SDIO_LEAVE_SUSPEND_FAIL; } chip_id = platform_reg_read_8_sdio( driver_adapter, halmac_platform_api, REG_SYS_CFG2); chip_version = platform_reg_read_8_sdio(driver_adapter, halmac_platform_api, REG_SYS_CFG1 + 1) >> 4; } else { chip_id = halmac_platform_api->REG_READ_8(driver_adapter, REG_SYS_CFG2); chip_version = halmac_platform_api->REG_READ_8( driver_adapter, REG_SYS_CFG1 + 1) >> 4; } HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "[TRACE]Chip id : 0x%X\n", chip_id); HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "[TRACE]Chip version : 0x%X\n", chip_version); halmac_adapter->chip_version = (enum halmac_chip_ver)chip_version; if (chip_id == HALMAC_CHIP_ID_HW_DEF_8822B) halmac_adapter->chip_id = HALMAC_CHIP_ID_8822B; else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8821C) halmac_adapter->chip_id = HALMAC_CHIP_ID_8821C; else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8814B) halmac_adapter->chip_id = HALMAC_CHIP_ID_8814B; else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8197F) halmac_adapter->chip_id = HALMAC_CHIP_ID_8197F; else halmac_adapter->chip_id = HALMAC_CHIP_ID_UNDEFINE; if (halmac_adapter->chip_id == HALMAC_CHIP_ID_UNDEFINE) return HALMAC_RET_CHIP_NOT_SUPPORT; return HALMAC_RET_SUCCESS; } /** * halmac_init_adapter() - init halmac_adapter * @driver_adapter : the adapter of caller * @halmac_platform_api : the platform APIs which is used in halmac APIs * @halmac_interface : bus interface * @pp_halmac_adapter : the adapter of halmac * @pp_halmac_api : the function pointer of APIs, caller shall call APIs by * function pointer * 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 halmac_init_adapter(void *driver_adapter, struct halmac_platform_api *halmac_platform_api, enum halmac_interface halmac_interface, struct halmac_adapter **pp_halmac_adapter, struct halmac_api **pp_halmac_api) { struct halmac_adapter *halmac_adapter = (struct halmac_adapter *)NULL; enum halmac_ret_status status = HALMAC_RET_SUCCESS; union { u32 i; u8 x[4]; } ENDIAN_CHECK = {0x01000000}; status = halmac_check_platform_api(driver_adapter, halmac_interface, halmac_platform_api); if (status != HALMAC_RET_SUCCESS) return status; HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, HALMAC_SVN_VER "\n"); HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "HALMAC_MAJOR_VER = %x\n", HALMAC_MAJOR_VER); HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "HALMAC_PROTOTYPE_VER = %x\n", HALMAC_PROTOTYPE_VER); HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "HALMAC_MINOR_VER = %x\n", HALMAC_MINOR_VER); HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "HALMAC_PATCH_VER = %x\n", HALMAC_PATCH_VER); HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "halmac_init_adapter_88xx ==========>\n"); /* Check endian setting - Little endian : 1, Big endian : 0*/ if (ENDIAN_CHECK.x[0] == HALMAC_SYSTEM_ENDIAN) { pr_err("Endian setting Err!!\n"); return HALMAC_RET_ENDIAN_ERR; } halmac_adapter = kzalloc(sizeof(*halmac_adapter), GFP_KERNEL); if (!halmac_adapter) { /* out of memory */ return HALMAC_RET_MALLOC_FAIL; } /* return halmac adapter address to caller */ *pp_halmac_adapter = halmac_adapter; /* Record caller info */ halmac_adapter->halmac_platform_api = halmac_platform_api; halmac_adapter->driver_adapter = driver_adapter; halmac_interface = halmac_interface == HALMAC_INTERFACE_AXI ? HALMAC_INTERFACE_PCIE : halmac_interface; halmac_adapter->halmac_interface = halmac_interface; spin_lock_init(&halmac_adapter->efuse_lock); spin_lock_init(&halmac_adapter->h2c_seq_lock); /*Get Chip*/ if (halmac_get_chip_info(driver_adapter, halmac_platform_api, halmac_interface, halmac_adapter) != HALMAC_RET_SUCCESS) { pr_err("HALMAC_RET_CHIP_NOT_SUPPORT\n"); return HALMAC_RET_CHIP_NOT_SUPPORT; } /* Assign function pointer to halmac API */ halmac_init_adapter_para_88xx(halmac_adapter); status = halmac_mount_api_88xx(halmac_adapter); /* Return halmac API function pointer */ *pp_halmac_api = (struct halmac_api *)halmac_adapter->halmac_api; HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "halmac_init_adapter_88xx <==========\n"); return status; } /** * halmac_halt_api() - stop halmac_api action * @halmac_adapter : the adapter of halmac * Author : Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status halmac_halt_api(struct halmac_adapter *halmac_adapter) { void *driver_adapter = NULL; struct halmac_platform_api *halmac_platform_api = (struct halmac_platform_api *)NULL; if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) return HALMAC_RET_ADAPTER_INVALID; driver_adapter = halmac_adapter->driver_adapter; halmac_platform_api = halmac_adapter->halmac_platform_api; HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "%s ==========>\n", __func__); halmac_adapter->halmac_state.api_state = HALMAC_API_STATE_HALT; HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "%s ==========>\n", __func__); return HALMAC_RET_SUCCESS; } /** * halmac_deinit_adapter() - deinit halmac adapter * @halmac_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 halmac_deinit_adapter(struct halmac_adapter *halmac_adapter) { void *driver_adapter = NULL; if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS) return HALMAC_RET_ADAPTER_INVALID; driver_adapter = halmac_adapter->driver_adapter; HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG, "[TRACE]halmac_deinit_adapter_88xx ==========>\n"); kfree(halmac_adapter->hal_efuse_map); halmac_adapter->hal_efuse_map = (u8 *)NULL; kfree(halmac_adapter->halmac_state.psd_set.data); halmac_adapter->halmac_state.psd_set.data = (u8 *)NULL; kfree(halmac_adapter->halmac_api); halmac_adapter->halmac_api = NULL; halmac_adapter->hal_adapter_backup = NULL; kfree(halmac_adapter); return HALMAC_RET_SUCCESS; } /** * halmac_get_version() - get HALMAC version * @version : return version of major, prototype and minor information * 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 halmac_get_version(struct halmac_ver *version) { version->major_ver = (u8)HALMAC_MAJOR_VER; version->prototype_ver = (u8)HALMAC_PROTOTYPE_VER; version->minor_ver = (u8)HALMAC_MINOR_VER; return HALMAC_RET_SUCCESS; }