// SPDX-License-Identifier: GPL-2.0
|
/******************************************************************************
|
*
|
* Copyright(c) 2016 Realtek Corporation.
|
*
|
* Contact Information:
|
* wlanfae <wlanfae@realtek.com>
|
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
|
* Hsinchu 300, Taiwan.
|
*
|
* Larry Finger <Larry.Finger@lwfinger.net>
|
*
|
*****************************************************************************/
|
#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;
|
}
|