mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-20 14:16:02 +00:00
![Ping-Ke Shih](/assets/img/avatar_default.png)
The RTL8822BE, an 802.11ac wireless network card, is now appearing in new computers. Its driver is being placed in staging to reduce the time that users of this new card will have access to in-kernel drivers. New Realtek devices implement a common sub-driver to control the MAC layer. The RTL8822BE is the first of these devices, thus its introduction involves some extra code. In the wireless tree, this will be a separate module; however, it is compiled into the 8822be driver here. Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Cc: Yan-Hsuan Chuang <yhchuang@realtek.com> Cc: Birming Chiu <birming@realtek.com> Cc: Shaofu <shaofu@realtek.com> Cc: Steven Ting <steventing@realtek.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
426 lines
13 KiB
C
426 lines
13 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright(c) 2016 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.
|
|
*
|
|
* The full GNU General Public License is included in this distribution in the
|
|
* file called LICENSE.
|
|
*
|
|
* 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;
|
|
}
|