merge aic800 driver from android

This commit is contained in:
August 2024-06-06 21:28:03 +08:00
parent fce40362dc
commit 9e6beaa2e4
38 changed files with 2554 additions and 689 deletions

View File

@ -10,6 +10,8 @@ obj-m := aic8800_bsp.o
aic8800_bsp-y := \
aic_bsp_main.o \
aic_bsp_driver.o \
aic_bsp_8800d.o \
aic_bsp_8800dc.o \
aicsdio.o \
aicsdio_txrxif.o

View File

@ -0,0 +1,336 @@
/**
******************************************************************************
*
* aic_bsp_8800d.c
*
* Copyright (C) RivieraWaves 2014-2019
*
******************************************************************************
*/
#include <linux/list.h>
#include <linux/version.h>
#include <linux/firmware.h>
#include "aicsdio_txrxif.h"
#include "aicsdio.h"
#include "aic_bsp_driver.h"
#define RAM_FMAC_FW_ADDR 0x00120000
#define FW_RAM_ADID_BASE_ADDR 0x00161928
#define FW_RAM_ADID_BASE_ADDR_U03 0x00161928
#define FW_RAM_PATCH_BASE_ADDR 0x00100000
static u32 patch_tbl[][2] = {
};
static u32 syscfg_tbl_masked[][3] = {
{0x40506024, 0x000000FF, 0x000000DF}, // for clk gate lp_level
};
static u32 rf_tbl_masked[][3] = {
{0x40344058, 0x00800000, 0x00000000},// pll trx
};
static u32 aicbsp_syscfg_tbl[][2] = {
{0x40500014, 0x00000101}, // 1)
{0x40500018, 0x00000109}, // 2)
{0x40500004, 0x00000010}, // 3) the order should not be changed
// def CONFIG_PMIC_SETTING
// U02 bootrom only
{0x40040000, 0x00001AC8}, // 1) fix panic
{0x40040084, 0x00011580},
{0x40040080, 0x00000001},
{0x40100058, 0x00000000},
{0x50000000, 0x03220204}, // 2) pmic interface init
{0x50019150, 0x00000002}, // 3) for 26m xtal, set div1
{0x50017008, 0x00000000}, // 4) stop wdg
};
static const struct aicbsp_firmware fw_u02[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u02)",
.bt_adid = "fw_adid.bin",
.bt_patch = "fw_patch.bin",
.bt_table = "fw_patch_table.bin",
.wl_fw = "fmacfw.bin"
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u02)",
.bt_adid = "fw_adid.bin",
.bt_patch = "fw_patch.bin",
.bt_table = "fw_patch_table.bin",
.wl_fw = "fmacfw_rf.bin"
},
};
static const struct aicbsp_firmware fw_u03[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u03/u04)",
.bt_adid = "fw_adid_u03.bin",
.bt_patch = "fw_patch_u03.bin",
.bt_table = "fw_patch_table_u03.bin",
.wl_fw = "fmacfw.bin"
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u03/u04)",
.bt_adid = "fw_adid_u03.bin",
.bt_patch = "fw_patch_u03.bin",
.bt_table = "fw_patch_table_u03.bin",
.wl_fw = "fmacfw_rf.bin"
},
};
static int aicbt_init(struct aic_sdio_dev *sdiodev)
{
struct aicbt_info_t btcfg = {
.btmode = AICBT_BTMODE_DEFAULT,
.btport = AICBT_BTPORT_DEFAULT,
.uart_baud = AICBT_UART_BAUD_DEFAULT,
.uart_flowctrl = AICBT_UART_FC_DEFAULT,
.lpm_enable = AICBT_LPM_ENABLE_DEFAULT,
.txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT,
};
struct aicbt_patch_table *head = aicbt_patch_table_alloc(aicbsp_firmware_list[aicbsp_info.cpmode].bt_table);
int ret = aicbt_patch_info_unpack(head, &btcfg);
if (head == NULL)
return -1;
if (ret) {
btcfg.addr_adid = FW_RAM_ADID_BASE_ADDR;
btcfg.addr_patch = FW_RAM_PATCH_BASE_ADDR;
if (aicbsp_info.chipinfo->rev != CHIP_REV_U02)
btcfg.addr_adid = FW_RAM_ADID_BASE_ADDR_U03;
}
ret = rwnx_plat_bin_fw_upload_android(sdiodev, btcfg.addr_adid, aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid);
if (ret)
goto err;
ret = rwnx_plat_bin_fw_upload_android(sdiodev, btcfg.addr_patch, aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch);
if (ret)
goto err;
ret = aicbt_patch_table_load(sdiodev, &btcfg, head);
if (ret)
printk("aicbt_patch_table_load fail\n");
err:
aicbt_patch_table_free(&head);
return ret;
}
static int aicwifi_start_from_bootrom(struct aic_sdio_dev *sdiodev)
{
int ret = 0;
/* memory access */
const u32 fw_addr = RAM_FMAC_FW_ADDR;
struct dbg_start_app_cfm start_app_cfm;
/* fw start */
ret = rwnx_send_dbg_start_app_req(sdiodev, fw_addr, HOST_START_APP_AUTO, &start_app_cfm);
if (ret) {
return -1;
}
aicbsp_info.hwinfo_r = start_app_cfm.bootstatus & 0xFF;
return 0;
}
static int aicwifi_sys_config(struct aic_sdio_dev *sdiodev)
{
int ret, cnt;
int syscfg_num = sizeof(syscfg_tbl_masked) / sizeof(u32) / 3;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_mask_write_req(sdiodev,
syscfg_tbl_masked[cnt][0], syscfg_tbl_masked[cnt][1], syscfg_tbl_masked[cnt][2]);
if (ret) {
printk("%x mask write fail: %d\n", syscfg_tbl_masked[cnt][0], ret);
return ret;
}
}
ret = rwnx_send_dbg_mem_mask_write_req(sdiodev,
rf_tbl_masked[0][0], rf_tbl_masked[0][1], rf_tbl_masked[0][2]);
if (ret) {
printk("rf config %x write fail: %d\n", rf_tbl_masked[0][0], ret);
return ret;
}
return 0;
}
static int aicwifi_patch_config(struct aic_sdio_dev *sdiodev)
{
const u32 rd_patch_addr = RAM_FMAC_FW_ADDR + 0x0180;
u32 config_base;
uint32_t start_addr = 0x1e6000;
u32 patch_addr = start_addr;
u32 patch_num = sizeof(patch_tbl)/4;
struct dbg_mem_read_cfm rd_patch_addr_cfm;
int ret = 0;
u16 cnt = 0;
u32 patch_addr_reg = 0x1e5318;
u32 patch_num_reg = 0x1e531c;
if (aicbsp_info.cpmode == AICBSP_CPMODE_TEST) {
patch_addr_reg = 0x1e5304;
patch_num_reg = 0x1e5308;
}
ret = rwnx_send_dbg_mem_read_req(sdiodev, rd_patch_addr, &rd_patch_addr_cfm);
if (ret) {
printk("patch rd fail\n");
return ret;
}
config_base = rd_patch_addr_cfm.memdata;
ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_addr_reg, patch_addr);
if (ret) {
printk("0x%x write fail\n", patch_addr_reg);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_num_reg, patch_num);
if (ret) {
printk("0x%x write fail\n", patch_num_reg);
return ret;
}
for (cnt = 0; cnt < patch_num/2; cnt += 1) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt, patch_tbl[cnt][0]+config_base);
if (ret) {
printk("%x write fail\n", start_addr+8*cnt);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt+4, patch_tbl[cnt][1]);
if (ret) {
printk("%x write fail\n", start_addr+8*cnt+4);
return ret;
}
}
return 0;
}
static int aicwifi_init(struct aic_sdio_dev *sdiodev)
{
if (rwnx_plat_bin_fw_upload_android(sdiodev, RAM_FMAC_FW_ADDR, aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw)) {
printk("download wifi fw fail\n");
return -1;
}
if (aicwifi_patch_config(sdiodev)) {
printk("aicwifi_patch_config fail\n");
return -1;
}
if (aicwifi_sys_config(sdiodev)) {
printk("aicwifi_sys_config fail\n");
return -1;
}
if (aicwifi_start_from_bootrom(sdiodev)) {
printk("wifi start fail\n");
return -1;
}
return 0;
}
static int aicbsp_system_config(struct aic_sdio_dev *sdiodev)
{
int syscfg_num = sizeof(aicbsp_syscfg_tbl) / sizeof(u32) / 2;
int ret, cnt;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, aicbsp_syscfg_tbl[cnt][0], aicbsp_syscfg_tbl[cnt][1]);
if (ret) {
sdio_err("%x write fail: %d\n", aicbsp_syscfg_tbl[cnt][0], ret);
return ret;
}
}
return 0;
}
int aicbsp_8800d_fw_init(struct aic_sdio_dev *sdiodev)
{
const u32 mem_addr = 0x40500000;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
uint8_t binding_status;
uint8_t dout[16];
need_binding_verify = false;
aicbsp_firmware_list = fw_u02;
if (rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm))
return -1;
aicbsp_info.chipinfo->rev = (u8)(rd_mem_addr_cfm.memdata >> 16);
if (aicbsp_info.chipinfo->rev != CHIP_REV_U02 &&
aicbsp_info.chipinfo->rev != CHIP_REV_U03 &&
aicbsp_info.chipinfo->rev != CHIP_REV_U04) {
pr_err("aicbsp: %s, unsupport chip rev: %d\n", __func__, aicbsp_info.chipinfo->rev);
return -1;
}
printk("aicbsp: %s, chip rev: %d\n", __func__, aicbsp_info.chipinfo->rev);
if (aicbsp_info.chipinfo->rev != CHIP_REV_U02)
aicbsp_firmware_list = fw_u03;
if (aicbsp_system_config(sdiodev))
return -1;
if (aicbt_init(sdiodev))
return -1;
if (aicwifi_init(sdiodev))
return -1;
if (need_binding_verify) {
printk("aicbsp: crypto data %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
binding_enc_data[0], binding_enc_data[1], binding_enc_data[2], binding_enc_data[3],
binding_enc_data[4], binding_enc_data[5], binding_enc_data[6], binding_enc_data[7],
binding_enc_data[8], binding_enc_data[9], binding_enc_data[10], binding_enc_data[11],
binding_enc_data[12], binding_enc_data[13], binding_enc_data[14], binding_enc_data[15]);
/* calculate verify data from crypto data */
if (wcn_bind_verify_calculate_verify_data(binding_enc_data, dout)) {
pr_err("aicbsp: %s, binding encrypt data incorrect\n", __func__);
return -1;
}
printk("aicbsp: verify data %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
dout[0], dout[1], dout[2], dout[3],
dout[4], dout[5], dout[6], dout[7],
dout[8], dout[9], dout[10], dout[11],
dout[12], dout[13], dout[14], dout[15]);
if (rwnx_send_dbg_binding_req(sdiodev, dout, &binding_status)) {
pr_err("aicbsp: %s, send binding request failn", __func__);
return -1;
}
if (binding_status) {
pr_err("aicbsp: %s, binding verify fail\n", __func__);
return -1;
}
}
if (aicwf_sdio_writeb(sdiodev->func[0], SDIOWIFI_WAKEUP_REG, 4)) {
sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
return -1;
}
return 0;
}

View File

@ -0,0 +1,791 @@
/**
******************************************************************************
*
* aic_bsp_8800dc.c
*
* Copyright (C) RivieraWaves 2014-2019
*
******************************************************************************
*/
#include <linux/list.h>
#include <linux/version.h>
#include <linux/firmware.h>
#include "aicsdio_txrxif.h"
#include "aicsdio.h"
#include "aic_bsp_driver.h"
#define RAM_LMAC_FW_ADDR 0x00150000
#define RAM_FMAC_FW_ADDR 0x00120000
#define ROM_FMAC_PATCH_ADDR 0x00180000
#define RAM_8800DC_ADID_ADDR 0x001017d8
#define RAM_8800DC_FW_PATCH_ADDR 0x00184000
#define RF_PATCH_NAME_8800DC "aic8800dc/fmacfw_rf_patch.bin"
typedef u32 (*array2_tbl_t)[2];
static u32 syscfg_tbl_masked_8800dc[][3] = {
//#ifdef CONFIG_PMIC_SETTING
#if defined(CONFIG_VRF_DCDC_MODE)
{0x7000216C, (0x3 << 2), (0x1 << 2)}, // pmic_pmu_init
{0x700021BC, (0x3 << 2), (0x1 << 2)},
{0x70002118, ((0x7 << 4) | (0x1 << 7)), ((0x2 << 4) | (0x1 << 7))},
{0x70002104, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6))},
{0x7000210C, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6))},
{0x70002190, (0x3F << 0), (24 << 0)},
{0x700021CC, ((0x7 << 4) | (0x1 << 7)), ((0x0 << 4) | (0x0 << 7))},
{0x700010A0, (0x1 << 11), (0x1 << 11)},
{0x70001038, (0x1 << 8), (0x1 << 8)},
{0x70001094, (0x3 << 2), (0x0 << 2)},
{0x700021D0, ((0x1 << 5) | (0x1 << 6)), ((0x1 << 5) | (0x1 << 6))},
{0x70001000, ((0x1 << 0) | (0x1 << 20) | (0x1 << 22)),
((0x1 << 0) | (0x1 << 20) | (0x0 << 22))},
#endif
//#endif /* CONFIG_PMIC_SETTING */
{0x00000000, 0x00000000, 0x00000000}, // last one
};
static u32 syscfg_tbl_masked_8800dc_u01[][3] = {
//#ifdef CONFIG_PMIC_SETTING
{0x70001000, (0x1 << 16), (0x1 << 16)}, // for low temperature
{0x70001028, (0x1 << 6), (0x1 << 6)},
{0x70001000, (0x1 << 16), (0x0 << 16)},
//#endif /* CONFIG_PMIC_SETTING */
};
static u32 syscfg_tbl_8800dc[][2] = {
{0x40500010, 0x00000004},
{0x40500010, 0x00000006},//160m clk
};
static u32 syscfg_tbl_8800dc_sdio_u01[][2] = {
{0x40030000, 0x00036724}, // loop forever after assert_err
{0x0011E800, 0xE7FE4070},
{0x40030084, 0x0011E800},
{0x40030080, 0x00000001},
{0x4010001C, 0x00000000},
};
static u32 syscfg_tbl_8800dc_sdio_u02[][2] = {
{0x40030000, 0x00036DA4}, // loop forever after assert_err
{0x0011E800, 0xE7FE4070},
{0x40030084, 0x0011E800},
{0x40030080, 0x00000001},
{0x4010001C, 0x00000000},
};
static u32 patch_tbl_wifisetting_8800dc_u01[][2] = {
{0x010c, 0x01001E01}
};
static u32 patch_tbl_wifisetting_8800dc_u02[][2] = {
{0x0124, 0x01001E01}
};
static u32 jump_tbl[][2] = {
#ifndef CONFIG_FOR_IPCOM
{296, 0x180001},
{137, 0x180011},
{303, 0x1810f9},
{168, 0x18186d},
{308, 0x181bbd},
{288, 0x1820c1},
#else
{308, 0x181001},
{288, 0x181031},
{296, 0x18120d},
{137, 0x18121d},
{303, 0x182305},
{168, 0x182a79},
{258, 0x182ae1},
#endif
};
static uint32_t ldpc_cfg_ram[] = {
#ifdef CONFIG_FPGA_VERIFICATION
0x00363638, 0x1DF8F834, 0x1DF8F834, 0x1DF8F834, 0x1DF8F834, 0x002F2F31, 0x1DF8F82C, 0x1DF8F82C,
0x1DF8F82C, 0x1DF8F82C, 0x00363639, 0x1AA5F834, 0x1AA5F834, 0x1ADEF834, 0x1ADEF834, 0x003A3A3E,
0x1578F436, 0x1578F436, 0x1578F436, 0x15B6F436, 0x003B3B40, 0x1DF8F838, 0x1DF8F838, 0x1DF8F838,
0x1DF8F838, 0x003B3B41, 0x1DC4F838, 0x1DC4F838, 0x1DF8F838, 0x1DF8F838, 0x003B3B40, 0x1781F838,
0x1781F838, 0x1781F838, 0x17C4F838, 0x003B3B40, 0x0E81F838, 0x0E81F838, 0x0E81F838, 0x0E82F838,
0x003F3F43, 0x1A92F83D, 0x1A92F83E, 0x1A92F83D, 0x1ADDF83D, 0x00272729, 0x1DF8F824, 0x1DF8F824,
0x1DF8F843, 0x1DF8F843, 0x00272729, 0x1DF8F824, 0x1DF8F824, 0x1DF8F842, 0x1DF8F842, 0x00262628,
0x1DF8F823, 0x1DF8F823, 0x1DF8F823, 0x1DF8F823, 0x00252528, 0x1DF8F823, 0x1DF8F823, 0x1DF8F823,
0x1DF8F823, 0x00262628, 0x1DF8F823, 0x1DF8F823, 0x1DF8F823, 0x1DF8F823, 0x00242427, 0x1DF8F821,
0x1DF8F821, 0x1DF8F821, 0x1DF8F821, 0x00232326, 0x1DF8F821, 0x1DF8F820, 0x1DF8F820, 0x1DF8F820,
0x00262628, 0x1DF8F823, 0x1DF8F823, 0x1DF8F823, 0x1DF8F823, 0x00242427, 0x1DF8F821, 0x1DF8F821,
0x1DF8F821, 0x1DF8F821, 0x001F1F21, 0x1DF8F81D, 0x1DF8F81D, 0x1DF8F81D, 0x1DF8F81D, 0x00262643,
0x1DF8F822, 0x1DF8F821, 0x1DF8F821, 0x1DF8F821, 0x0018182B, 0x1DF8F816, 0x1DBDF815, 0x1DF8F815,
0x1DF8F815, 0x0018182A, 0x1195F836, 0x1195F815, 0x1195F815, 0x1196F815, 0x0028282C, 0x1DF8F824,
0x1DF8F824, 0x1DF8F824, 0x1DF8F824, 0x0027272C, 0x1DF8F824, 0x1DF8F823, 0x1DF8F823, 0x1DF8F823,
0x0082824A, 0x1ADFF841, 0x1ADDF822, 0x1ADEF822, 0x1ADFF822, 0x003E3E40, 0x09D1F81D, 0x095BF81D,
0x095BF81D, 0x095BF81D, 0x0029292D, 0x1DF8F825, 0x1DF8F825, 0x1DF8F825, 0x1DF8F825, 0x0028282C,
0x1DF8F824, 0x1DF8F824, 0x1DF8F824, 0x1DF8F824, 0x0029292D, 0x1DF8F825, 0x1DF8F825, 0x1DF8F825,
0x1DF8F825, 0x0028282E, 0x1DF8F825, 0x1DF8F824, 0x1DF8F824, 0x1DF8F824, 0x0026262C, 0x1DF8F823,
0x1DF8F822, 0x1DF8F822, 0x1DF8F822, 0x0028282D, 0x1DF8F825, 0x1DF8F824, 0x1DF8F824, 0x1DF8F824,
0x00282852, 0x1DF8F827, 0x1DF8F824, 0x1DF8F824, 0x1DF8F824, 0x0029294E, 0x1DF8F823, 0x1DF8F822,
0x1DF8F822, 0x1DF8F822, 0x00212143, 0x1DF8F821, 0x1DECF81D, 0x1DF4F81D, 0x1DF8F81D, 0x0086864D,
0x1CF0F844, 0x1CEDF823, 0x1CEFF822, 0x1CF0F822, 0x0047474D, 0x1BE8F823, 0x1BE8F823, 0x1BE9F822,
0x1BEAF822, 0x0018182F, 0x14B0F83C, 0x14B0F814, 0x14B0F814, 0x14B0F814, 0x00404040, 0x0AE1F81E,
0x0A61F81D, 0x0A61F81D, 0x0A61F81D, 0x002C2C40, 0x09555526, 0x09555512, 0x09555513, 0x09555512,
0x00181840, 0x06333329, 0x06333314, 0x06333314, 0x06333314, 0x002B2B2F, 0x1DF8F828, 0x1DF8F828,
0x1DF8F828, 0x1DF8F828, 0x002B2B32, 0x1DF8F829, 0x1DF8F828, 0x1DF8F828, 0x1DF8F828, 0x002A2A2F,
0x1DF8F827, 0x1DF8F827, 0x1DF8F827, 0x1DF8F827, 0x002A2A57, 0x1DF8F82B, 0x1DF8F827, 0x1DF8F827,
0x1DF8F827, 0x00919152, 0x1DF8F84B, 0x1DF8F825, 0x1DF8F825, 0x1DF8F825, 0x004C4C51, 0x1DF8F826,
0x1DF8F825, 0x1DF8F825, 0x1DF8F825, 0x00444440, 0x0CF8F820, 0x0C6EF81F, 0x0C6EF81F, 0x0C6EF81F,
0x00424240, 0x0D75753E, 0x0D75751E, 0x0D75751E, 0x0D75751E, 0x00191940, 0x0539392E, 0x05393914,
0x05393914, 0x05393914, 0x002F2F32, 0x1AA5F82C, 0x1AA5F82C, 0x1ADEF82C, 0x1ADEF82C, 0x002F2F40,
0x0C6EDE2C, 0x0C6EDE2C, 0x0C6EDE2C, 0x0C6EDE2C, 0x00323240, 0x053BB62E, 0x053BB62E, 0x053BB62E,
0x053BB62E, 0x00333339, 0x1DC4F82F, 0x1DC4F82F, 0x1DF8F82F, 0x1DF8F82F, 0x00333340, 0x0E81F82F,
0x0E81F82F, 0x0E81F82F, 0x0E82F82F, 0x00333340, 0x063FC42F, 0x063FC42F, 0x063FC42F, 0x063FC42F,
0x00404040, 0x063FC42F, 0x063FC42F, 0x063FC42F, 0x063FC42F, 0x00363640, 0x0747DD33, 0x0747DD33,
0x0747DD33, 0x0747DD33, 0x00404040, 0x0747DD33, 0x0747DD33, 0x0747DD33, 0x0747DD33, 0x00292940,
0x07484825, 0x07484812, 0x07484812, 0x07484812, 0x00404040, 0x07343428, 0x07343414, 0x07343414,
0x07343414, 0x00404040, 0x0538382A, 0x05383814, 0x05383814, 0x05383814, 0x00404040, 0x05292914,
0x05292909, 0x05292909, 0x05292909, 0x000B0B40, 0x02111108, 0x0211110E, 0x02111108, 0x02111108,
0x00404040, 0x063E3E2E, 0x063E3E15, 0x063E3E14, 0x063E3E14, 0x00404040, 0x062E2E14, 0x062E2E09,
0x062E2E09, 0x062E2E09, 0x000B0B40, 0x02131308, 0x0213130F, 0x02131308, 0x02131308,
#else
0x00767679, 0x1DF8F870, 0x1DF8F870, 0x1DF8F870, 0x1DF8F870, 0x006E6E72, 0x1DF8F869, 0x1DF8F869,
0x1DF8F869, 0x1DF8F869, 0x0076767B, 0x1DF8F870, 0x1DF8F870, 0x1DF8F870, 0x1DF8F870, 0x007E7E85,
0x1DF4F876, 0x1DF4F876, 0x1DF4F876, 0x1DF8F876, 0x0081818A, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B,
0x1DF8F87B, 0x0081818D, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B, 0x0081818A, 0x1DF8F87B,
0x1DF8F87C, 0x1DF8F87B, 0x1DF8F87B, 0x007E7E40, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B,
0x008B8B92, 0x1DF8F887, 0x1DF8F889, 0x1DF8F887, 0x1DF8F887, 0x00515155, 0x1DF8F84C, 0x1DF8F84C,
0x1DF8F889, 0x1DF8F889, 0x00515154, 0x1DF8F84C, 0x1DF8F84C, 0x1DF8F888, 0x1DF8F888, 0x004F4F53,
0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x004F4F53, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A,
0x1DF8F84A, 0x004F4F53, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x004E4E53, 0x1DF8F849,
0x1DF8F848, 0x1DF8F848, 0x1DF8F848, 0x004D4D52, 0x1DF8F847, 0x1DF8F847, 0x1DF8F847, 0x1DF8F847,
0x004F4F55, 0x1DF8F84B, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x004E4E53, 0x1DF8F849, 0x1DF8F848,
0x1DF8F848, 0x1DF8F848, 0x0049494D, 0x1DF8F844, 0x1DF8F844, 0x1DF8F844, 0x1DF8F844, 0x0051518F,
0x1DF8F849, 0x1DF8F848, 0x1DF8F848, 0x1DF8F848, 0x00424277, 0x1DF8F83F, 0x1DF8F83C, 0x1DF8F83C,
0x1DF8F83C, 0x00424275, 0x1DF8F89E, 0x1DF8F83C, 0x1DF8F83C, 0x1DF8F83C, 0x0055555C, 0x1DF8F84C,
0x1DF8F84C, 0x1DF8F84C, 0x1DF8F84C, 0x0053535C, 0x1DF8F84C, 0x1DF8F84B, 0x1DF8F84B, 0x1DF8F84B,
0x00F8F89E, 0x1DF8F88C, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x00898940, 0x18F8F846, 0x18CFF845,
0x18CFF844, 0x18CFF844, 0x0056565F, 0x1DF8F84F, 0x1DF8F84F, 0x1DF8F84F, 0x1DF8F84F, 0x0055555E,
0x1DF8F84E, 0x1DF8F84E, 0x1DF8F84E, 0x1DF8F84E, 0x0056565F, 0x1DF8F84F, 0x1DF8F84F, 0x1DF8F84F,
0x1DF8F84F, 0x00555561, 0x1DF8F850, 0x1DF8F84E, 0x1DF8F84E, 0x1DF8F84E, 0x0053535F, 0x1DF8F84D,
0x1DF8F84C, 0x1DF8F84C, 0x1DF8F84C, 0x0055555F, 0x1DF8F84F, 0x1DF8F84E, 0x1DF8F84E, 0x1DF8F84E,
0x005555AA, 0x1DF8F854, 0x1DF8F84E, 0x1DF8F84E, 0x1DF8F84E, 0x005959A6, 0x1DF8F84D, 0x1DF8F84C,
0x1DF8F84C, 0x1DF8F84C, 0x004F4F9B, 0x1DF8F84E, 0x1DF8F846, 0x1DF8F846, 0x1DF8F846, 0x00F8F8A5,
0x1DF8F894, 0x1DF8F84C, 0x1DF8F84C, 0x1DF8F84C, 0x009898A4, 0x1DF8F84D, 0x1DF8F84C, 0x1DF8F84C,
0x1DF8F84C, 0x00464686, 0x1DF8F8B3, 0x1DF8F83D, 0x1DF8F83D, 0x1DF8F83D, 0x008E8E40, 0x1AF8F848,
0x1ADFF848, 0x1ADFF846, 0x1ADFF846, 0x007F7F40, 0x18D2D275, 0x18D2D23A, 0x18D2D23A, 0x18D2D239,
0x00454540, 0x0F868664, 0x0F86863E, 0x0F86863D, 0x0F86863D, 0x005C5C64, 0x1DF8F856, 0x1DF8F855,
0x1DF8F855, 0x1DF8F855, 0x005B5B68, 0x1DF8F858, 0x1DF8F855, 0x1DF8F855, 0x1DF8F855, 0x005A5A64,
0x1DF8F855, 0x1DF8F854, 0x1DF8F854, 0x1DF8F854, 0x005A5AB5, 0x1DF8F85B, 0x1DF8F855, 0x1DF8F854,
0x1DF8F854, 0x00F8F8B0, 0x1DF8F8A3, 0x1DF8F852, 0x1DF8F852, 0x1DF8F852, 0x00A4A4AE, 0x1DF8F854,
0x1DF8F852, 0x1DF8F852, 0x1DF8F852, 0x009A9A40, 0x1DF8F84E, 0x1DF8F84D, 0x1DF8F84C, 0x1DF8F84C,
0x009C9C40, 0x1DF8F895, 0x1DF8F849, 0x1DF8F84A, 0x1DF8F84A, 0x00494940, 0x1197976F, 0x11979742,
0x11979741, 0x11979741, 0x006E6E74, 0x1DF8F869, 0x1DF8F869, 0x1DF8F869, 0x1DF8F869, 0x006E6E40,
0x1ADEF869, 0x1ADEF869, 0x1ADEF869, 0x1ADEF869, 0x00757540, 0x0D78F86E, 0x0D78F86E, 0x0D78F86E,
0x0D79F86E, 0x00787885, 0x1DF8F873, 0x1DF8F873, 0x1DF8F873, 0x1DF8F873, 0x00787840, 0x1DF8F873,
0x1DF8F873, 0x1DF8F873, 0x1DF8F873, 0x00787840, 0x0E81F873, 0x0E81F873, 0x0E81F873, 0x0E82F873,
0x00404040, 0x0E82F873, 0x0E82F873, 0x0E82F873, 0x0E82F873, 0x00818140, 0x1092F87E, 0x1092F87E,
0x1092F87E, 0x1092F87E, 0x00404040, 0x1092F87E, 0x1092F87E, 0x1092F87E, 0x1092F87E, 0x00737340,
0x14B2B26B, 0x14B2B235, 0x14B2B235, 0x14B2B235, 0x00404040, 0x0E828260, 0x0E82823D, 0x0E82823C,
0x0E82823C, 0x00404040, 0x0F8B8B66, 0x0F8B8B3F, 0x0F8B8B3D, 0x0F8B8B3D, 0x00404040, 0x0B68683D,
0x0B68681E, 0x0B68681E, 0x0B68681E, 0x00222240, 0x06434318, 0x06434329, 0x06434318, 0x06434318,
0x00404040, 0x129D9D72, 0x129D9D43, 0x129D9D41, 0x129D9D41, 0x00404040, 0x0D757542, 0x0D757520,
0x0D757520, 0x0D757520, 0x00232340, 0x084C4C19, 0x084C4C2C, 0x084C4C19, 0x084C4C19,
#endif
};
static uint32_t agc_cfg_ram[] = {
0x20000000, 0x0400000E, 0x3000200E, 0x5B000000, 0x0400004B, 0x3000008E, 0x32000000, 0x0400007B,
0x40000000, 0xF8000026, 0x04000011, 0x4819008E, 0x9C000020, 0x08000191, 0x38008000, 0x0A000000,
0x08104411, 0x38018000, 0x0C004641, 0x08D00014, 0x30000000, 0x01000000, 0x04000017, 0x30000000,
0x3C000000, 0x0400001A, 0x38020000, 0x40000001, 0x0800001D, 0x3808008E, 0x14000050, 0x08000020,
0x4000008E, 0xA400007B, 0x00000101, 0x3000339F, 0x41000700, 0x04104420, 0x90000000, 0x49000000,
0xF00E842F, 0xEC0E842C, 0xEC0E842C, 0x04000032, 0x30000000, 0x48000101, 0x04000032, 0x30000000,
0x48000202, 0x04000032, 0x30000000, 0x46000000, 0x04000011, 0x58010006, 0x3D040472, 0xDC204439,
0x081DD4D2, 0x480A0006, 0xDC2044DC, 0x081DD43C, 0x38050004, 0x0EF1F1C3, 0x342044DC, 0x30000000,
0x01000000, 0x04000042, 0x30000000, 0x33000000, 0x04104445, 0x38008000, 0x2200109C, 0x08104448,
0x38008000, 0x23D4509C, 0x08104417, 0x9000A000, 0x32000000, 0x18000063, 0x14000060, 0x1C000051,
0x10000057, 0x38028000, 0x0C000001, 0x08D04466, 0x3000200F, 0x00000000, 0x00000000, 0x38030000,
0x0C002601, 0x08D0445A, 0x30000000, 0x3D020230, 0x0400005D, 0x30000000, 0x3E000100, 0x04000066,
0x38028000, 0x0C001601, 0x34204466, 0x38028000, 0x0C000A01, 0x34204466, 0x38008004, 0xFF000000,
0x0800007B, 0x3800802F, 0x26000000, 0x0800006C, 0x380404AF, 0x1F191010, 0x0800006F, 0x20000CAF,
0x04000071, 0x60000CAF, 0x18700079, 0x14000077, 0x10000075, 0x28140CAF, 0x09B00084, 0x280A0CAF,
0x09B00084, 0x28060CAF, 0x09B00084, 0x28048086, 0x0800007D, 0x38000086, 0x22800000, 0x04000080,
0x30000000, 0x0EF1F101, 0x36004883, 0x28020000, 0x08000085, 0x3802008E, 0x3D040431, 0x08000088,
0x3805008E, 0x1F241821, 0x0800008B, 0x3000008E, 0xA0163021, 0x0400008E, 0x3000008E, 0x0EF10012,
0x34000091, 0x300000CC, 0x50000000, 0x04000094, 0x380095FE, 0x32010000, 0x04000097, 0x50001FFE,
0x5A010000, 0x6DC9989B, 0xFC19D4B9, 0x30000186, 0x3D840373, 0x0400009E, 0x3000008E, 0x0A000000,
0x040000A1, 0x3000008E, 0x22C00000, 0x040000A4, 0x9000028E, 0x32010001, 0x8E4000AA, 0xC80000B0,
0x00000000, 0x00000000, 0x3000008E, 0x32010001, 0x040000CB, 0x3000008E, 0x29000000, 0x94045011,
0x300019B6, 0x32010000, 0x040000B3, 0x300019B6, 0x3D040431, 0x040000B6, 0x300019B6, 0x22800000,
0x04000097, 0x30000186, 0x3D840473, 0x040000BC, 0x3000008E, 0x29030000, 0x040000BF, 0x9AEE028E,
0x32010100, 0x7C0000C5, 0xCC0000B0, 0x080000B0, 0x00000000, 0x3000008E, 0x32010100, 0x040000C8,
0x3000028E, 0x29000000, 0x94045011, 0x5000038E, 0x29000000, 0x94045011, 0xC0000035, 0x38010006,
0x3D040472, 0x080000D2, 0x30000004, 0x0EF1F141, 0x340000D5, 0x28040004, 0x080000D7, 0x2808000E,
0x080000D9, 0x3000018E, 0x0EF10052, 0x340000DC, 0x3000038E, 0x29000000, 0x94045011, 0x38020000,
0x32000000, 0x080000E2, 0x60000000, 0xD80000E6, 0xD40000E9, 0x040000EC, 0x30000000, 0x0EF1F121,
0x360048EF, 0x30000000, 0x0C002421, 0x360048EF, 0x30000000, 0x0C000021, 0x360048EF, 0x28020000,
0x0800007B, 0x50001EFE, 0x5A010000, 0x6DC998F5, 0xFC19D4F8, 0x3000028E, 0x32000040, 0x040000FB,
0x3AEE028E, 0x32000080, 0x040000FB, 0x30000000, 0x0EF1F101, 0x360048FE, 0x28020000, 0x08000100,
0x3802008E, 0x3D040431, 0x08000103, 0x3805008E, 0x1F241821, 0x08000106, 0x3000008E, 0xA0163021,
0x04000109, 0x3000008E, 0x0EF10012, 0x3400010C, 0x300014F6, 0x32010000, 0x04000114, 0x20000000,
0x04000111, 0x300000EC, 0x50000000, 0x040000F1, 0x300014F6, 0x32030000, 0x04000117, 0x30001086,
0x3D840473, 0x0400011A, 0x5000108E, 0x22C00000, 0x8E47C0CB, 0xCB30011E, 0x300019B6, 0x32040000,
0x04000121, 0x300019B6, 0x3D040431, 0x04000124, 0x300019B6, 0x22800000, 0x04000111, 0x00000000,
0x00000000, 0x00000000, 0x30000186, 0x3D840473, 0x0400012D, 0x5000038E, 0x29000000, 0x94045011,
0xC0000131, 0x380C800E, 0xFF000000, 0x08000134, 0x30000004, 0x0FF1F103, 0x34000137, 0x28020000,
0x08000139, 0x3000038E, 0x29000000, 0x94045011, 0x00000000, 0x00000000, 0x00000000, 0x58010006,
0x3D040472, 0xDC204543, 0x081DD4D2, 0x480A0006, 0xDC2044DC, 0x081DD546, 0x38050004, 0x0EF1F141,
0x342044DC, 0x2802800E, 0x080000DC, 0x48000035, 0x0400014A, 0x7896638F, 0x4100000F, 0x8C00014F,
0x080450C4, 0x90104574, 0x88C8620F, 0xC000015A, 0x90104574, 0x08104554, 0x94104557, 0x3000628F,
0x29000000, 0x9404517A, 0x3000638F, 0x29000000, 0x0410457A, 0x3800E005, 0x3D010131, 0x0810455D,
0xA832600F, 0x90104574, 0x08000154, 0x94104557, 0xC6104567, 0xC4185563, 0x5802E00F, 0x0FEEEA07,
0x80000174, 0x3420456B, 0x5802E00F, 0x0EEEEA07, 0x80000174, 0x3420456B, 0x30004000, 0x33000001,
0x0400016E, 0x38034005, 0x3D030373, 0x08000171, 0x30006007, 0x33000000, 0x04000174, 0x3000608F,
0x29000000, 0x94045177, 0x4000608F, 0xA010457D, 0x0410457A, 0x3000608F, 0x64000101, 0x04104411,
0x3000608F, 0x64000101, 0x04104580, 0x3000618F, 0x42000001, 0x04000183, 0x38028000, 0x32000000,
0x08104586, 0x280A618F, 0x08000188, 0x480A618F, 0xBC00018B, 0x0800018E, 0x3000618F, 0x34000001,
0x04000005, 0x3000618F, 0x34000000, 0x04000008, 0x3000008F, 0x0EEAED0F, 0x36000194, 0x38038000,
0x34000000, 0x08000197, 0x38028005, 0x29010002, 0x0800019A, 0x3000028F, 0x2200209C, 0x0400019D,
0x3000028F, 0x23D4509C, 0x040001A0, 0x2814028F, 0x080001A2, 0x3000028F, 0x43010201, 0x040001A5,
0x3000128F, 0x32000100, 0x040001A8, 0x5AEE138F, 0x4100000F, 0x7C0001AC, 0x080000F9, 0x592C138F,
0x29000000, 0x8C0001B0, 0x080000F9, 0x2000138F, 0x94045011, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
static uint32_t txgain_map[96] = {
#ifdef CONFIG_FPGA_VERIFICATION
0x20c0c971, 0x20c0c980, 0x20c0c992, 0x20c0c9a6, 0x20c0c9bf, 0x20c0caa5, 0x20c0cabd, 0x20c0cba0,
0x20c0cbb6, 0x20c0cbea, 0x20c0ccc5, 0x20c0cdac, 0x20c0cdd0, 0x20c0ceb2, 0x20c0ceff, 0x20c0cfff,
0x20c0c922, 0x20c0c922, 0x20c0c922, 0x20c0c922, 0x20c0c922, 0x20c0c922, 0x20c0c922, 0x20c0c927,
0x20c0c92c, 0x20c0c931, 0x20c0c937, 0x20c0c93f, 0x20c0c946, 0x20c0c94f, 0x20c0c959, 0x20c0c964,
0x20c0cbee, 0x20c0cce0, 0x20c0ccff, 0x20c0cde2, 0x20c0cdfe, 0x20c0cede, 0x20c0cefc, 0x20c0cfd9,
0x20c0cff8, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff,
0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c98c,
0x20c0ca79, 0x20c0ca89, 0x20c0cb74, 0x20c0cb84, 0x20c0cb94, 0x20c0cba8, 0x20c0cbbb, 0x20c0cbd2,
0x20c0cbee, 0x20c0cce0, 0x20c0ccff, 0x20c0cde2, 0x20c0cdfe, 0x20c0cede, 0x20c0cefc, 0x20c0cfd9,
0x20c0cff8, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff,
0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c98c,
0x20c0ca79, 0x20c0ca89, 0x20c0cb74, 0x20c0cb84, 0x20c0cb94, 0x20c0cba8, 0x20c0cbbb, 0x20c0cbd2,
#else
0x00ffc772, 0x00ffc780, 0x00ffc872, 0x00ffc880, 0x00ffc970, 0x00ffc980, 0x00ffc990, 0x00ffca80,
0x00ffca9a, 0x00ffcb90, 0x00ffcc95, 0x00ffce80, 0x00ffcf80, 0x00ffcf80, 0x00ffcf80, 0x00ffcf80,
0x00ffc05b, 0x00ffc066, 0x00ffc070, 0x00ffc080, 0x00ffc175, 0x00ffc185, 0x00ffc272, 0x00ffc280,
0x00ffc290, 0x00ffc380, 0x00ffc472, 0x00ffc483, 0x00ffc572, 0x00ffc580, 0x00ffc590, 0x00ffc680,
0x00ffc87d, 0x00ffc88b, 0x00ffc979, 0x00ffc989, 0x00ffca7d, 0x00ffca8d, 0x00ffcb7a, 0x00ffcb8a,
0x00ffcc7d, 0x00ffcc8d, 0x00ffcd79, 0x00ffcd89, 0x00ffce7d, 0x00ffce8d, 0x00ffcf80, 0x00ffcf99,
0x00ffc080, 0x00ffc090, 0x00ffc180, 0x00ffc190, 0x00ffc27b, 0x00ffc28b, 0x00ffc37b, 0x00ffc38b,
0x00ffc480, 0x00ffc490, 0x00ffc579, 0x00ffc589, 0x00ffc679, 0x00ffc689, 0x00ffc780, 0x00ffc790,
0x00ffc87d, 0x00ffc88b, 0x00ffc979, 0x00ffc989, 0x00ffca7d, 0x00ffca8d, 0x00ffcb7a, 0x00ffcb8a,
0x00ffcc7d, 0x00ffcc8d, 0x00ffcd79, 0x00ffcd89, 0x00ffce7d, 0x00ffce8d, 0x00ffcf80, 0x00ffcf99,
0x00ffc080, 0x00ffc090, 0x00ffc180, 0x00ffc190, 0x00ffc27b, 0x00ffc28b, 0x00ffc37b, 0x00ffc38b,
0x00ffc480, 0x00ffc490, 0x00ffc579, 0x00ffc589, 0x00ffc679, 0x00ffc689, 0x00ffc780, 0x00ffc790,
#endif
};
static uint32_t txgain_table[32] = {
0xA4B22189, 0x00007825, 0xA4B2214B, 0x00007825, 0xA4B2214F, 0x00007825, 0xA4B221D5, 0x00007825,
0xA4B221DC, 0x00007825, 0xA4B221E5, 0x00007825, 0xAC9221E5, 0x00006825, 0xAC9221EF, 0x00006825,
0xBC9221EE, 0x00006825, 0xBC9221FF, 0x00006825, 0xBC9221FF, 0x00004025, 0xB792203F, 0x00004026,
0xDC92203F, 0x00004025, 0xE692203F, 0x00004025, 0xFF92203F, 0x00004035, 0xFFFE203F, 0x00004832,
};
static uint32_t rxgain_table_24g_20m[64] = {
0x82f282d1, 0x9591a324, 0x80808419, 0x000000f0, 0x42f282d1, 0x95923524, 0x80808419, 0x000000f0,
0x22f282d1, 0x9592c724, 0x80808419, 0x000000f0, 0x02f282d1, 0x9591a324, 0x80808419, 0x000000f0,
0x06f282d1, 0x9591a324, 0x80808419, 0x000000f0, 0x0ef29ad1, 0x9591a324, 0x80808419, 0x000000f0,
0x0ef29ad3, 0x95923524, 0x80808419, 0x000000f0, 0x0ef29ad7, 0x9595a324, 0x80808419, 0x000000f0,
0x06f282d2, 0x95911124, 0x80808419, 0x000000f0, 0x06f282f4, 0x95911124, 0x80808419, 0x000000f0,
0x06f282e6, 0x9591a324, 0x80808419, 0x000000f0, 0x06f282e6, 0x9595a324, 0x80808419, 0x000000f0,
0x06f282e6, 0x9599a324, 0x80808419, 0x000000f0, 0x06f282e6, 0x959b5924, 0x80808419, 0x000000f0,
0x06f282e6, 0x959f5924, 0x80808419, 0x000000f0, 0x0ef29ae6, 0x959f5924, 0x80808419, 0x000000f0,
};
static uint32_t rxgain_table_24g_40m[64] = {
0x83428151, 0x9631a328, 0x80808419, 0x000000f0, 0x43428151, 0x96323528, 0x80808419, 0x000000f0,
0x23428151, 0x9632c728, 0x80808419, 0x000000f0, 0x03428151, 0x9631a328, 0x80808419, 0x000000f0,
0x07429951, 0x9631a328, 0x80808419, 0x000000f0, 0x0f42d151, 0x9631a328, 0x80808419, 0x000000f0,
0x0f42d153, 0x96323528, 0x80808419, 0x000000f0, 0x0f42d157, 0x9635a328, 0x80808419, 0x000000f0,
0x07429952, 0x96311128, 0x80808419, 0x000000f0, 0x07429974, 0x96311128, 0x80808419, 0x000000f0,
0x07429966, 0x9631a328, 0x80808419, 0x000000f0, 0x07429966, 0x9635a328, 0x80808419, 0x000000f0,
0x07429966, 0x9639a328, 0x80808419, 0x000000f0, 0x07429966, 0x963b5928, 0x80808419, 0x000000f0,
0x07429966, 0x963f5928, 0x80808419, 0x000000f0, 0x0f42d166, 0x963f5928, 0x80808419, 0x000000f0,
};
static u32 patch_tbl_func[][2] = {
#ifndef CONFIG_FOR_IPCOM
{0x00110054, 0x0018186D}, // same as jump_tbl idx 168
{0x0011005C, 0x0018186D}, // same as jump_tbl idx 168
#else
{0x00110054, 0x00182A79}, // same as jump_tbl idx 168
{0x0011005C, 0x00182A79}, // same as jump_tbl idx 168
{0x001118D4, 0x00000011},
#endif
};
static u32 patch_tbl_rf_func[][2] = {
{0x00110bf0, 0x00180001},
};
static const struct aicbsp_firmware fw_u01[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u01)",
.bt_adid = "aic8800dc/fw_adid.bin",
.bt_patch = "aic8800dc/fw_patch.bin",
.bt_table = "aic8800dc/fw_patch_table.bin",
.wl_fw = "aic8800dc/fmacfw_patch.bin",
.wl_table = "aic8800dc/fmacfw_patch_tbl.bin",
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u01)",
.bt_adid = "aic8800dc/fw_adid.bin",
.bt_patch = "aic8800dc/fw_patch.bin",
.bt_table = "aic8800dc/fw_patch_table.bin",
.wl_fw = "aic8800dc/lmacfw_rf.bin",
.wl_table = NULL,
},
};
static const struct aicbsp_firmware fw_u02[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u02)",
.bt_adid = "aic8800dc/fw_adid_u02.bin",
.bt_patch = "aic8800dc/fw_patch_u02.bin",
.bt_table = "aic8800dc/fw_patch_table_u02.bin",
.wl_fw = "aic8800dc/fmacfw_patch_u02.bin",
.wl_table = "aic8800dc/fmacfw_patch_tbl_u02.bin",
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u02)",
.bt_adid = "aic8800dc/fw_adid_u02.bin",
.bt_patch = "aic8800dc/fw_patch_u02.bin",
.bt_table = "aic8800dc/fw_patch_table_u02.bin",
.wl_fw = "aic8800dc/lmacfw_rf.bin",
.wl_table = NULL,
},
};
static int aic8800dc_wifi_patch_table_load(struct aic_sdio_dev *sdiodev, const char *filename)
{
unsigned int i = 0;
int size;
u32 *dst = NULL;
int err = 0;
const struct firmware *fw = NULL;
int ret = request_firmware(&fw, filename, NULL);
u32 FMACFW_PATCH_TBL_8800DC_U02_DESCRIBE_BASE = 0X183E00;
u32 FMACFW_PATCH_TBL_8800DC_U02_DESCRIBE_SIZE = 128;
printk("rwnx_request_firmware, name: %s\n", filename);
if (ret < 0) {
printk("Load %s fail\n", filename);
return ret;
}
size = fw->size;
dst = (u32 *)fw->data;
if (size <= 0) {
printk("wrong size of firmware file\n");
release_firmware(fw);
return -1;
}
if (!err && (i < size)) {
err = rwnx_send_dbg_mem_block_write_req(sdiodev, FMACFW_PATCH_TBL_8800DC_U02_DESCRIBE_BASE, FMACFW_PATCH_TBL_8800DC_U02_DESCRIBE_SIZE, &dst[0]);
if (err)
printk("write describe information fail\n");
printk("wifi patch version: %s", (char *)dst);
}
if (!err && (i < size)) {// <1KB data
for (i = 128 / 4; i < size / 4; i += 2)
err = rwnx_send_dbg_mem_write_req(sdiodev, dst[i], dst[i+1]);
if (err)
printk("bin upload fail: %x, err:%d\n", dst[i], err);
}
release_firmware(fw);
return err;
}
static int aic8800dc_wifi_patch_config(struct aic_sdio_dev *sdiodev)
{
int ret = 0;
int cnt = 0;
if (aicbsp_info.cpmode == AICBSP_CPMODE_WORK) {
const u32 cfg_base = 0x10164;
u32 wifisetting_cfg_addr;
u32 ldpc_cfg_addr;
u32 agc_cfg_addr;
u32 txgain_cfg_addr;
u32 jump_tbl_addr;
u32 patch_tbl_wifisetting_num;
u32 ldpc_cfg_size = sizeof(ldpc_cfg_ram);
u32 agc_cfg_size = sizeof(agc_cfg_ram);
u32 txgain_cfg_size = sizeof(txgain_map);
u32 jump_tbl_size = sizeof(jump_tbl)/2;
u32 patch_tbl_func_num = sizeof(patch_tbl_func)/sizeof(u32)/2;
struct dbg_mem_read_cfm cfm;
int i;
array2_tbl_t jump_tbl_base = NULL;
array2_tbl_t patch_tbl_func_base = NULL;
array2_tbl_t patch_tbl_wifisetting_8800dc_base = NULL;
if (aicbsp_info.chipinfo->subrev == 0) {
jump_tbl_base = jump_tbl;
jump_tbl_size = sizeof(jump_tbl)/2;
patch_tbl_func_base = patch_tbl_func;
patch_tbl_func_num = sizeof(patch_tbl_func)/sizeof(u32)/2;
patch_tbl_wifisetting_num = sizeof(patch_tbl_wifisetting_8800dc_u01)/sizeof(u32)/2;
patch_tbl_wifisetting_8800dc_base = patch_tbl_wifisetting_8800dc_u01;
} else if (aicbsp_info.chipinfo->subrev == 1) {
patch_tbl_wifisetting_num = sizeof(patch_tbl_wifisetting_8800dc_u02)/sizeof(u32)/2;
patch_tbl_wifisetting_8800dc_base = patch_tbl_wifisetting_8800dc_u02;
} else {
printk("unsupported id: %d", aicbsp_info.chipinfo->subrev);
ret = -1;
goto out;
}
ret = rwnx_send_dbg_mem_read_req(sdiodev, cfg_base, &cfm);
if (ret) {
pr_err("setting base[0x%x] rd fail: %d\n", cfg_base, ret);
goto out;
}
wifisetting_cfg_addr = cfm.memdata;
if (aicbsp_info.chipinfo->subrev == 0) {
ret = rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 4, &cfm);
if (ret) {
pr_err("setting base[0x%x] rd fail: %d\n", cfg_base + 4, ret);
goto out;
}
jump_tbl_addr = cfm.memdata;
}
ret = rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 8, &cfm);
if (ret) {
pr_err("setting base[0x%x] rd fail: %d\n", cfg_base + 8, ret);
goto out;
}
ldpc_cfg_addr = cfm.memdata;
ret = rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 0xc, &cfm);
if (ret) {
pr_err("setting base[0x%x] rd fail: %d\n", cfg_base + 0xc, ret);
goto out;
}
agc_cfg_addr = cfm.memdata;
if (rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 0x10, &cfm)) {
pr_err("setting base[0x%x] rd fail: %d\n", cfg_base + 0x10, ret);
goto out;
}
txgain_cfg_addr = cfm.memdata;
printk("wifisetting_cfg_addr=%x, ldpc_cfg_addr=%x, agc_cfg_addr=%x, txgain_cfg_addr=%x\n", wifisetting_cfg_addr, ldpc_cfg_addr, agc_cfg_addr, txgain_cfg_addr);
for (cnt = 0; cnt < patch_tbl_wifisetting_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, wifisetting_cfg_addr + patch_tbl_wifisetting_8800dc_base[cnt][0], patch_tbl_wifisetting_8800dc_base[cnt][1]);
if (ret) {
pr_err("wifisetting %x write fail\n", patch_tbl_wifisetting_8800dc_base[cnt][0]);
goto out;
}
}
if (ldpc_cfg_size > 512) {// > 0.5KB data
for (i = 0; i < (ldpc_cfg_size - 512); i += 512) {//each time write 0.5KB
ret = rwnx_send_dbg_mem_block_write_req(sdiodev, ldpc_cfg_addr + i, 512, ldpc_cfg_ram + i / 4);
if (ret) {
pr_err("ldpc upload fail: %x, err:%d\r\n", ldpc_cfg_addr + i, ret);
goto out;
}
}
}
if (!ret && (i < ldpc_cfg_size)) {// < 0.5KB data
ret = rwnx_send_dbg_mem_block_write_req(sdiodev, ldpc_cfg_addr + i, ldpc_cfg_size - i, ldpc_cfg_ram + i / 4);
if (ret) {
pr_err("ldpc upload fail: %x, err:%d\r\n", ldpc_cfg_addr + i, ret);
goto out;
}
}
if (agc_cfg_size > 512) {// > 0.5KB data
for (i = 0; i < (agc_cfg_size - 512); i += 512) {//each time write 0.5KB
ret = rwnx_send_dbg_mem_block_write_req(sdiodev, agc_cfg_addr + i, 512, agc_cfg_ram + i / 4);
if (ret) {
pr_err("agc upload fail: %x, err:%d\r\n", agc_cfg_addr + i, ret);
goto out;
}
}
}
if (!ret && (i < agc_cfg_size)) {// < 0.5KB data
ret = rwnx_send_dbg_mem_block_write_req(sdiodev, agc_cfg_addr + i, agc_cfg_size - i, agc_cfg_ram + i / 4);
if (ret) {
pr_err("agc upload fail: %x, err:%d\r\n", agc_cfg_addr + i, ret);
goto out;
}
}
#if !defined(CONFIG_FPGA_VERIFICATION)
ret = rwnx_send_dbg_mem_block_write_req(sdiodev, txgain_cfg_addr, txgain_cfg_size, txgain_map);
if (ret) {
pr_err("txgain upload fail: %x, err:%d\r\n", txgain_cfg_addr, ret);
goto out;
}
if (aicbsp_info.chipinfo->subrev == 0) {
for (cnt = 0; cnt < jump_tbl_size/4; cnt += 1) {
//printk("%x = %x\n", jump_tbl[cnt][0]*4+jump_tbl_addr, jump_tbl[cnt][1]);
ret = rwnx_send_dbg_mem_write_req(sdiodev, jump_tbl_base[cnt][0]*4+jump_tbl_addr, jump_tbl_base[cnt][1]);
if (ret) {
pr_err("%x write fail\n", jump_tbl_addr+8*cnt);
goto out;
}
}
for (cnt = 0; cnt < patch_tbl_func_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_tbl_func_base[cnt][0], patch_tbl_func_base[cnt][1]);
if (ret) {
pr_err("patch_tbl_func %x write fail\n", patch_tbl_func_base[cnt][0]);
goto out;
}
}
} else {
ret = aic8800dc_wifi_patch_table_load(sdiodev, aicbsp_firmware_list[aicbsp_info.cpmode].wl_table);
if (ret) {
printk("patch_tbl upload fail: err:%d\r\n", ret);
goto out;
}
}
#endif
ret = rwnx_send_rf_config_req(sdiodev, 0, 1, (u8 *)txgain_table, 128);
if (ret)
goto out;
ret = rwnx_send_rf_config_req(sdiodev, 0, 0, (u8 *)rxgain_table_24g_20m, 256);
if (ret)
goto out;
ret = rwnx_send_rf_config_req(sdiodev, 32, 0, (u8 *)rxgain_table_24g_40m, 256);
} else {
if (aicbsp_info.chipinfo->subrev == 0) {
u32 patch_tbl_rf_func_num = sizeof(patch_tbl_rf_func)/sizeof(u32)/2;
for (cnt = 0; cnt < patch_tbl_rf_func_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_tbl_rf_func[cnt][0], patch_tbl_rf_func[cnt][1]);
if (ret) {
pr_err("patch_tbl_rf_func %x write fail\n", patch_tbl_rf_func[cnt][0]);
goto out;
}
}
}
}
out:
return ret;
}
static int aic8800dc_bt_patch_config(struct aic_sdio_dev *sdiodev)
{
struct aicbt_info_t btcfg = {
.btmode = AICBT_BTMODE_BT_WIFI_COMBO,
.btport = AICBT_BTPORT_DEFAULT,
.uart_baud = AICBT_UART_BAUD_DEFAULT,
.uart_flowctrl = AICBT_UART_FC_DEFAULT,
.lpm_enable = AICBT_LPM_ENABLE_DEFAULT,
.txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT,
};
struct aicbt_patch_table *head = aicbt_patch_table_alloc(aicbsp_firmware_list[aicbsp_info.cpmode].bt_table);
int ret = aicbt_patch_info_unpack(head, &btcfg);
if (head == NULL)
return -1;
if (ret) {
btcfg.addr_adid = RAM_8800DC_ADID_ADDR;
btcfg.addr_patch = RAM_8800DC_FW_PATCH_ADDR;
}
ret = rwnx_plat_bin_fw_upload_android(sdiodev, btcfg.addr_adid, aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid);
if (ret)
goto err;
ret = rwnx_plat_bin_fw_upload_android(sdiodev, btcfg.addr_patch, aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch);
if (ret)
goto err;
ret = aicbt_patch_table_load(sdiodev, &btcfg, head);
if (ret)
printk("aicbt_patch_table_load fail\n");
err:
aicbt_patch_table_free(&head);
return ret;
}
int aicbsp_8800dc_fw_init(struct aic_sdio_dev *sdiodev)
{
u32 mem_addr = 0x40500000;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
int syscfg_num, cnt, ret;
u32 boot_type = HOST_START_APP_DUMMY;
u32 rd_addr, fw_addr, ld_addr;
if (aicbsp_info.cpmode == AICBSP_CPMODE_TEST) {
rd_addr = RAM_LMAC_FW_ADDR;
fw_addr = RAM_LMAC_FW_ADDR;
ld_addr = RAM_LMAC_FW_ADDR;
} else {
rd_addr = RAM_FMAC_FW_ADDR;
fw_addr = RAM_FMAC_FW_ADDR;
ld_addr = ROM_FMAC_PATCH_ADDR;
}
aicbsp_firmware_list = fw_u01;
if (rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm))
return -1;
aicbsp_info.chipinfo->rev = (u8)(rd_mem_addr_cfm.memdata >> 16);
aicbsp_info.chipinfo->mcuid = 0;
if (((rd_mem_addr_cfm.memdata >> 25) & 0x01UL) == 0x00UL)
aicbsp_info.chipinfo->mcuid = 1;
mem_addr = 0x00000020;
if (rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm))
return -1;
aicbsp_info.chipinfo->subrev = (u8)rd_mem_addr_cfm.memdata;
printk("%s(%d), rev: %d, subrev: %d, mucid: %d\n", __func__, __LINE__,
aicbsp_info.chipinfo->rev, aicbsp_info.chipinfo->subrev, aicbsp_info.chipinfo->mcuid);
if (aicbsp_info.chipinfo->subrev != 0 && aicbsp_info.chipinfo->subrev != 1) {
printk("%s(%d), unsupported subrev: %d\n", __func__, __LINE__, aicbsp_info.chipinfo->subrev);
return -1;
}
if (aicbsp_info.chipinfo->rev == CHIP_REV_U02)
aicbsp_firmware_list = fw_u02;
mem_addr = 0x40500010;
if (rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm))
return -1;
aic8800dc_bt_patch_config(sdiodev);
syscfg_num = sizeof(syscfg_tbl_8800dc) / sizeof(u32) / 2;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, syscfg_tbl_8800dc[cnt][0], syscfg_tbl_8800dc[cnt][1]);
if (ret) {
sdio_err("%x write fail: %d\n", syscfg_tbl_8800dc[cnt][0], ret);
return ret;
}
}
if (aicbsp_info.chipinfo->mcuid == 0) {
if (aicbsp_info.chipinfo->subrev == 0) {
syscfg_num = sizeof(syscfg_tbl_8800dc_sdio_u01) / sizeof(u32) / 2;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, syscfg_tbl_8800dc_sdio_u01[cnt][0], syscfg_tbl_8800dc_sdio_u01[cnt][1]);
if (ret) {
printk("%x write fail: %d\n", syscfg_tbl_8800dc_sdio_u01[cnt][0], ret);
return ret;
}
}
} else if (aicbsp_info.chipinfo->subrev == 1) {
syscfg_num = sizeof(syscfg_tbl_8800dc_sdio_u02) / sizeof(u32) / 2;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, syscfg_tbl_8800dc_sdio_u02[cnt][0], syscfg_tbl_8800dc_sdio_u02[cnt][1]);
if (ret) {
printk("%x write fail: %d\n", syscfg_tbl_8800dc_sdio_u02[cnt][0], ret);
return ret;
}
}
}
}
syscfg_num = sizeof(syscfg_tbl_masked_8800dc) / sizeof(u32) / 3;
for (cnt = 0; cnt < syscfg_num; cnt++) {
if (syscfg_tbl_masked_8800dc[cnt][0] == 0x00000000)
break;
if (syscfg_tbl_masked_8800dc[cnt][0] == 0x70001000) {
if (aicbsp_info.chipinfo->mcuid == 0) {
syscfg_tbl_masked_8800dc[cnt][1] |= ((0x1 << 8) | (0x1 << 15)); // mask
syscfg_tbl_masked_8800dc[cnt][2] |= ((0x1 << 8) | (0x1 << 15));
}
}
ret = rwnx_send_dbg_mem_mask_write_req(sdiodev,
syscfg_tbl_masked_8800dc[cnt][0], syscfg_tbl_masked_8800dc[cnt][1], syscfg_tbl_masked_8800dc[cnt][2]);
if (ret) {
printk("%x mask write fail: %d\n", syscfg_tbl_masked_8800dc[cnt][0], ret);
return ret;
}
}
if (aicbsp_info.chipinfo->subrev == 0) {
syscfg_num = sizeof(syscfg_tbl_masked_8800dc_u01) / sizeof(u32) / 3;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_mask_write_req(sdiodev,
syscfg_tbl_masked_8800dc_u01[cnt][0], syscfg_tbl_masked_8800dc_u01[cnt][1], syscfg_tbl_masked_8800dc_u01[cnt][2]);
if (ret) {
printk("%x mask write fail: %d\n", syscfg_tbl_masked_8800dc_u01[cnt][0], ret);
return ret;
}
}
}
if (aicbsp_info.chipinfo->subrev == 0 && aicbsp_info.cpmode == AICBSP_CPMODE_TEST) {
ret = rwnx_plat_bin_fw_upload_android(sdiodev, ROM_FMAC_PATCH_ADDR, RF_PATCH_NAME_8800DC);
if (ret)
return ret;
}
ret = rwnx_plat_bin_fw_upload_android(sdiodev, ld_addr, aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw);
if (ret)
return ret;
aic8800dc_wifi_patch_config(sdiodev);
printk("Read FW mem: %08x\n", rd_addr);
if (rwnx_send_dbg_mem_read_req(sdiodev, rd_addr, &rd_mem_addr_cfm))
return -1;
printk("cfm: [%08x] = %08x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
boot_type = HOST_START_APP_DUMMY;
if (aicbsp_info.cpmode == AICBSP_CPMODE_TEST)
boot_type = HOST_START_APP_AUTO;
/* fw start */
printk("Start app: %08x, %d\n", fw_addr, boot_type);
if (rwnx_send_dbg_start_app_req(sdiodev, fw_addr, boot_type, NULL))
return -1;
return 0;
}

View File

@ -1,10 +1,7 @@
/**
******************************************************************************
*
* rwnx_cmds.c
*
* Handles queueing (push to IPC, ack/cfm from IPC) of commands issued to
* LMAC FW
* aic_bsp_driver.c
*
* Copyright (C) RivieraWaves 2014-2019
*
@ -18,10 +15,9 @@
#include "aicsdio.h"
#include "aic_bsp_driver.h"
static u8 binding_enc_data[16];
static bool need_binding_verify;
u8 binding_enc_data[16];
bool need_binding_verify;
int wcn_bind_verify_calculate_verify_data(uint8_t *din, uint8_t *dout);
#ifndef CONFIG_PLATFORM_ALLWINNER
int wcn_bind_verify_calculate_verify_data(uint8_t *din, uint8_t *dout)
{
@ -460,6 +456,32 @@ int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32
return rwnx_send_msg(sdiodev, start_app_req, 1, DBG_START_APP_CFM, start_app_cfm);
}
int rwnx_send_rf_config_req(struct aic_sdio_dev *sdiodev, u8 ofst, u8 sel, u8 *tbl, u16 len)
{
struct mm_set_rf_config_req *rf_config_req;
int error;
/* Build the MM_SET_RF_CONFIG_REQ message */
rf_config_req = rwnx_msg_zalloc(MM_SET_RF_CONFIG_REQ, TASK_MM, DRV_TASK_ID,
sizeof(struct mm_set_rf_config_req));
if (!rf_config_req) {
return -ENOMEM;
}
rf_config_req->table_sel = sel;
rf_config_req->table_ofst = ofst;
rf_config_req->table_num = 16;
rf_config_req->deft_page = 0;
memcpy(rf_config_req->data, tbl, len);
/* Send the MM_SET_RF_CONFIG_REQ message to UMAC FW */
error = rwnx_send_msg(sdiodev, rf_config_req, 1, MM_SET_RF_CONFIG_CFM, NULL);
return error;
};
static inline int dbg_binding_ind(struct rwnx_cmd *cmd, struct ipc_e2a_msg *msg)
{
struct dbg_binding_ind *ind = (struct dbg_binding_ind *)msg->param;
@ -473,7 +495,11 @@ static msg_cb_fct dbg_hdlrs[MSG_I(DBG_MAX)] = {
[MSG_I(DBG_BINDING_IND)] = (msg_cb_fct)dbg_binding_ind,
};
static msg_cb_fct mm_hdlrs[MSG_I(MM_MAX)] = {
};
static msg_cb_fct *msg_hdlrs[] = {
[TASK_MM] = mm_hdlrs,
[TASK_DBG] = dbg_hdlrs,
};
@ -609,32 +635,36 @@ err:
return NULL;
}
int aicbt_patch_trap_data_load(struct aic_sdio_dev *sdiodev)
int aicbt_patch_info_unpack(struct aicbt_patch_table *head, struct aicbt_info_t *aicbt_info)
{
uint32_t fw_ram_adid_base_addr = FW_RAM_ADID_BASE_ADDR;
if (aicbsp_info.chip_rev != CHIP_REV_U02)
fw_ram_adid_base_addr = FW_RAM_ADID_BASE_ADDR_U03;
struct aicbt_patch_table *p;
int ret = -1;
if (rwnx_plat_bin_fw_upload_android(sdiodev, fw_ram_adid_base_addr, aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid))
return -1;
if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_RAM_PATCH_BASE_ADDR, aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch))
return -1;
return 0;
for (p = head; p != NULL; p = p->next) {
if (AICBT_PT_INF == p->type) {
aicbt_info->addr_adid = *(p->data + 1);
aicbt_info->addr_patch = *(p->data + 3);
printk("%s bt adid addr: 0x%08x, patch addr: 0x%08x\n", __func__, aicbt_info->addr_adid, aicbt_info->addr_patch);
ret = 0;
}
if (AICBT_PT_VER == p->type) {
printk("%s bt patch version: %s\n", __func__, (char *)p->data);
}
}
return ret;
}
static struct aicbt_info_t aicbt_info = {
.btmode = AICBT_BTMODE_DEFAULT,
.btport = AICBT_BTPORT_DEFAULT,
.uart_baud = AICBT_UART_BAUD_DEFAULT,
.uart_flowctrl = AICBT_UART_FC_DEFAULT,
};
int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev)
int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev, struct aicbt_info_t *aicbt_info, struct aicbt_patch_table *head)
{
struct aicbt_patch_table *head, *p;
struct aicbt_patch_table *p;
int ret = 0, i;
uint32_t *data = NULL;
head = aicbt_patch_table_alloc(aicbsp_firmware_list[aicbsp_info.cpmode].bt_table);
printk("%s bt uart baud: %d, flowctrl: %d, lpm_enable: %d, tx_pwr: %d\n", __func__,
aicbt_info->uart_baud, aicbt_info->uart_flowctrl, aicbt_info->lpm_enable, aicbt_info->txpwr_lvl);
for (p = head; p != NULL; p = p->next) {
data = p->data;
if (AICBT_PT_BTMODE == p->type) {
@ -642,14 +672,16 @@ int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev)
*(data + 3) = aicbsp_info.hwinfo;
*(data + 5) = aicbsp_info.cpmode;
*(data + 7) = aicbt_info.btmode;
*(data + 9) = aicbt_info.btport;
*(data + 11) = aicbt_info.uart_baud;
*(data + 13) = aicbt_info.uart_flowctrl;
*(data + 7) = aicbt_info->btmode;
*(data + 9) = aicbt_info->btport;
*(data + 11) = aicbt_info->uart_baud;
*(data + 13) = aicbt_info->uart_flowctrl;
*(data + 15) = aicbt_info->lpm_enable;
*(data + 17) = aicbt_info->txpwr_lvl;
}
if (AICBT_PT_VER == p->type) {
printk("aicbsp: bt patch version: %s\n", (char *)p->data);
continue;
}
@ -662,185 +694,6 @@ int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev)
if (p->type == AICBT_PT_PWRON)
udelay(500);
}
aicbt_patch_table_free(&head);
return 0;
}
int aicbt_init(struct aic_sdio_dev *sdiodev)
{
if (aicbt_patch_trap_data_load(sdiodev)) {
printk("aicbt_patch_trap_data_load fail\n");
return -1;
}
if (aicbt_patch_table_load(sdiodev)) {
printk("aicbt_patch_table_load fail\n");
return -1;
}
return 0;
}
static int aicwifi_start_from_bootrom(struct aic_sdio_dev *sdiodev)
{
int ret = 0;
/* memory access */
const u32 fw_addr = RAM_FMAC_FW_ADDR;
struct dbg_start_app_cfm start_app_cfm;
/* fw start */
ret = rwnx_send_dbg_start_app_req(sdiodev, fw_addr, HOST_START_APP_AUTO, &start_app_cfm);
if (ret) {
return -1;
}
aicbsp_info.hwinfo_r = start_app_cfm.bootstatus & 0xFF;
return 0;
}
u32 patch_tbl[][2] = {
};
u32 syscfg_tbl_masked[][3] = {
{0x40506024, 0x000000FF, 0x000000DF}, // for clk gate lp_level
};
u32 rf_tbl_masked[][3] = {
{0x40344058, 0x00800000, 0x00000000},// pll trx
};
static int aicwifi_sys_config(struct aic_sdio_dev *sdiodev)
{
int ret, cnt;
int syscfg_num = sizeof(syscfg_tbl_masked) / sizeof(u32) / 3;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_mask_write_req(sdiodev,
syscfg_tbl_masked[cnt][0], syscfg_tbl_masked[cnt][1], syscfg_tbl_masked[cnt][2]);
if (ret) {
printk("%x mask write fail: %d\n", syscfg_tbl_masked[cnt][0], ret);
return ret;
}
}
ret = rwnx_send_dbg_mem_mask_write_req(sdiodev,
rf_tbl_masked[0][0], rf_tbl_masked[0][1], rf_tbl_masked[0][2]);
if (ret) {
printk("rf config %x write fail: %d\n", rf_tbl_masked[0][0], ret);
return ret;
}
return 0;
}
static int aicwifi_patch_config(struct aic_sdio_dev *sdiodev)
{
const u32 rd_patch_addr = RAM_FMAC_FW_ADDR + 0x0180;
u32 config_base;
uint32_t start_addr = 0x1e6000;
u32 patch_addr = start_addr;
u32 patch_num = sizeof(patch_tbl)/4;
struct dbg_mem_read_cfm rd_patch_addr_cfm;
int ret = 0;
u16 cnt = 0;
u32 patch_addr_reg = 0x1e4d80;
u32 patch_num_reg = 0x1e4d84;
if (aicbsp_info.cpmode == AICBSP_CPMODE_TEST) {
patch_addr_reg = 0x1e4d74;
patch_num_reg = 0x1e4d78;
}
ret = rwnx_send_dbg_mem_read_req(sdiodev, rd_patch_addr, &rd_patch_addr_cfm);
if (ret) {
printk("patch rd fail\n");
return ret;
}
config_base = rd_patch_addr_cfm.memdata;
ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_addr_reg, patch_addr);
if (ret) {
printk("0x%x write fail\n", patch_addr_reg);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_num_reg, patch_num);
if (ret) {
printk("0x%x write fail\n", patch_num_reg);
return ret;
}
for (cnt = 0; cnt < patch_num/2; cnt += 1) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt, patch_tbl[cnt][0]+config_base);
if (ret) {
printk("%x write fail\n", start_addr+8*cnt);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt+4, patch_tbl[cnt][1]);
if (ret) {
printk("%x write fail\n", start_addr+8*cnt+4);
return ret;
}
}
return 0;
}
int aicwifi_init(struct aic_sdio_dev *sdiodev)
{
if (rwnx_plat_bin_fw_upload_android(sdiodev, RAM_FMAC_FW_ADDR, aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw)) {
printk("download wifi fw fail\n");
return -1;
}
if (aicwifi_patch_config(sdiodev)) {
printk("aicwifi_patch_config fail\n");
return -1;
}
if (aicwifi_sys_config(sdiodev)) {
printk("aicwifi_sys_config fail\n");
return -1;
}
if (aicwifi_start_from_bootrom(sdiodev)) {
printk("wifi start fail\n");
return -1;
}
return 0;
}
u32 aicbsp_syscfg_tbl[][2] = {
{0x40500014, 0x00000101}, // 1)
{0x40500018, 0x00000109}, // 2)
{0x40500004, 0x00000010}, // 3) the order should not be changed
// def CONFIG_PMIC_SETTING
// U02 bootrom only
{0x40040000, 0x00001AC8}, // 1) fix panic
{0x40040084, 0x00011580},
{0x40040080, 0x00000001},
{0x40100058, 0x00000000},
{0x50000000, 0x03220204}, // 2) pmic interface init
{0x50019150, 0x00000002}, // 3) for 26m xtal, set div1
{0x50017008, 0x00000000}, // 4) stop wdg
};
static int aicbsp_system_config(struct aic_sdio_dev *sdiodev)
{
int syscfg_num = sizeof(aicbsp_syscfg_tbl) / sizeof(u32) / 2;
int ret, cnt;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, aicbsp_syscfg_tbl[cnt][0], aicbsp_syscfg_tbl[cnt][1]);
if (ret) {
sdio_err("%x write fail: %d\n", aicbsp_syscfg_tbl[cnt][0], ret);
return ret;
}
}
return 0;
}
@ -858,79 +711,24 @@ void aicbsp_platform_deinit(struct aic_sdio_dev *sdiodev)
int aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev)
{
const u32 mem_addr = 0x40500000;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
if (aicbsp_info.chipinfo == NULL)
goto err;
uint8_t binding_status;
uint8_t dout[16];
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800D)
return aicbsp_8800d_fw_init(sdiodev);
need_binding_verify = false;
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800DC || aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800DW)
return aicbsp_8800dc_fw_init(sdiodev);
if (rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm))
return -1;
aicbsp_info.chip_rev = (u8)(rd_mem_addr_cfm.memdata >> 16);
if (aicbsp_info.chip_rev != CHIP_REV_U02 &&
aicbsp_info.chip_rev != CHIP_REV_U03 &&
aicbsp_info.chip_rev != CHIP_REV_U04) {
pr_err("aicbsp: %s, unsupport chip rev: %d\n", __func__, aicbsp_info.chip_rev);
return -1;
}
printk("aicbsp: %s, chip rev: %d\n", __func__, aicbsp_info.chip_rev);
if (aicbsp_info.chip_rev != CHIP_REV_U02)
aicbsp_firmware_list = fw_u03;
if (aicbsp_system_config(sdiodev))
return -1;
if (aicbt_init(sdiodev))
return -1;
if (aicwifi_init(sdiodev))
return -1;
if (need_binding_verify) {
printk("aicbsp: crypto data %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
binding_enc_data[0], binding_enc_data[1], binding_enc_data[2], binding_enc_data[3],
binding_enc_data[4], binding_enc_data[5], binding_enc_data[6], binding_enc_data[7],
binding_enc_data[8], binding_enc_data[9], binding_enc_data[10], binding_enc_data[11],
binding_enc_data[12], binding_enc_data[13], binding_enc_data[14], binding_enc_data[15]);
/* calculate verify data from crypto data */
if (wcn_bind_verify_calculate_verify_data(binding_enc_data, dout)) {
pr_err("aicbsp: %s, binding encrypt data incorrect\n", __func__);
return -1;
}
printk("aicbsp: verify data %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
dout[0], dout[1], dout[2], dout[3],
dout[4], dout[5], dout[6], dout[7],
dout[8], dout[9], dout[10], dout[11],
dout[12], dout[13], dout[14], dout[15]);
if (rwnx_send_dbg_binding_req(sdiodev, dout, &binding_status)) {
pr_err("aicbsp: %s, send binding request failn", __func__);
return -1;
}
if (binding_status) {
pr_err("aicbsp: %s, binding verify fail\n", __func__);
return -1;
}
}
if (aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 4)) {
sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
return -1;
}
return 0;
err:
pr_err("%s no matched chip found\n", __func__);
return -1;
}
int aicbsp_get_feature(struct aicbsp_feature_t *feature)
{
feature->cpmode = aicbsp_info.cpmode;
feature->chipinfo = aicbsp_info.chipinfo;
feature->sdio_clock = FEATURE_SDIO_CLOCK;
feature->sdio_phase = FEATURE_SDIO_PHASE;
feature->hwinfo = aicbsp_info.hwinfo;
@ -938,3 +736,81 @@ int aicbsp_get_feature(struct aicbsp_feature_t *feature)
return 0;
}
EXPORT_SYMBOL_GPL(aicbsp_get_feature);
#ifdef AICBSP_RESV_MEM_SUPPORT
static struct skb_buff_pool resv_skb[] = {
{AIC_RESV_MEM_TXDATA, 1536*64, "resv_mem_txdata", 0, NULL},
};
int aicbsp_resv_mem_init(void)
{
int i = 0;
for (i = 0; i < sizeof(resv_skb) / sizeof(resv_skb[0]); i++) {
resv_skb[i].skb = dev_alloc_skb(resv_skb[i].size);
}
return 0;
}
int aicbsp_resv_mem_deinit(void)
{
int i = 0;
for (i = 0; i < sizeof(resv_skb) / sizeof(resv_skb[0]); i++) {
if (resv_skb[i].used == 0 && resv_skb[i].skb)
dev_kfree_skb(resv_skb[i].skb);
}
return 0;
}
struct sk_buff *aicbsp_resv_mem_alloc_skb(unsigned int length, uint32_t id)
{
if (resv_skb[id].size < length) {
pr_err("aicbsp: %s, no enough mem\n", __func__);
goto fail;
}
if (resv_skb[id].used) {
pr_err("aicbsp: %s, mem in use\n", __func__);
goto fail;
}
if (resv_skb[id].skb == NULL) {
pr_err("aicbsp: %s, mem not initialazed\n", __func__);
resv_skb[id].skb = dev_alloc_skb(resv_skb[id].size);
if (resv_skb[id].skb == NULL) {
pr_err("aicbsp: %s, mem reinitial still fail\n", __func__);
goto fail;
}
}
printk("aicbsp: %s, alloc %s succuss, id: %d, size: %d\n", __func__,
resv_skb[id].name, resv_skb[id].id, resv_skb[id].size);
resv_skb[id].used = 1;
return resv_skb[id].skb;
fail:
return NULL;
}
EXPORT_SYMBOL_GPL(aicbsp_resv_mem_alloc_skb);
void aicbsp_resv_mem_kfree_skb(struct sk_buff *skb, uint32_t id)
{
resv_skb[id].used = 0;
printk("aicbsp: %s, free %s succuss, id: %d, size: %d\n", __func__,
resv_skb[id].name, resv_skb[id].id, resv_skb[id].size);
}
EXPORT_SYMBOL_GPL(aicbsp_resv_mem_kfree_skb);
#else
int aicbsp_resv_mem_init(void)
{
return 0;
}
int aicbsp_resv_mem_deinit(void)
{
return 0;
}
#endif

View File

@ -201,9 +201,17 @@ enum dbg_msg_tag {
DBG_MAX,
};
enum mm_msg_tag {
MM_SET_RF_CONFIG_REQ = 103,
MM_SET_RF_CONFIG_CFM,
MM_MAX
};
enum {
HOST_START_APP_AUTO = 1,
HOST_START_APP_CUSTOM
HOST_START_APP_CUSTOM,
HOST_START_APP_FNCALL = 4,
HOST_START_APP_DUMMY = 5,
};
struct dbg_mem_block_write_req {
@ -272,6 +280,14 @@ struct dbg_binding_req {
u8 driver_data[16];
};
struct mm_set_rf_config_req {
u8 table_sel;
u8 table_ofst;
u8 table_num;
u8 deft_page;
u32 data[64];
};
int rwnx_send_dbg_mem_read_req(struct aic_sdio_dev *sdiodev, u32 mem_addr,
struct dbg_mem_read_cfm *cfm);
int rwnx_send_dbg_mem_block_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr,
@ -283,19 +299,18 @@ int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32
int rwnx_send_dbg_binding_req(struct aic_sdio_dev *sdiodev, u8 *dout, u8 *binding_status);
void rwnx_rx_handle_msg(struct aic_sdio_dev *sdiodev, struct ipc_e2a_msg *msg);
int rwnx_send_rf_config_req(struct aic_sdio_dev *sdiodev, u8 ofst, u8 sel, u8 *tbl, u16 len);
int aicbsp_platform_init(struct aic_sdio_dev *sdiodev);
void aicbsp_platform_deinit(struct aic_sdio_dev *sdiodev);
int aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev);
#define RAM_FMAC_FW_ADDR 0x00120000
#define FW_RAM_ADID_BASE_ADDR 0x00161928
#define FW_RAM_ADID_BASE_ADDR_U03 0x00161928
#define FW_RAM_PATCH_BASE_ADDR 0x00100000
int aicbsp_resv_mem_init(void);
int aicbsp_resv_mem_deinit(void);
#define AICBT_PT_TAG "AICBT_PT_TAG"
enum aicbt_patch_table_type {
AICBT_PT_INF = 0x0,
AICBT_PT_TRAP = 0x1,
AICBT_PT_B4,
AICBT_PT_BTMODE,
@ -339,18 +354,16 @@ enum aicbt_uart_flowctrl_type {
AICBT_UART_FLOWCTRL_ENABLE, // uart with flow ctrl
};
enum aicbsp_cpmode_type {
AICBSP_CPMODE_WORK,
AICBSP_CPMODE_TEST,
AICBSP_CPMODE_MAX,
};
enum chip_rev {
CHIP_REV_U02 = 3,
CHIP_REV_U03 = 7,
CHIP_REV_U04 = 7,
};
///aic bt tx pwr lvl :lsb->msb: first byte, min pwr lvl; second byte, max pwr lvl;
///pwr lvl:20(min), 30 , 40 , 50 , 60(max)
#define AICBT_TXPWR_LVL 0x00006020
#define AICBSP_HWINFO_DEFAULT (-1)
#define AICBSP_CPMODE_DEFAULT AICBSP_CPMODE_WORK
@ -358,6 +371,8 @@ enum chip_rev {
#define AICBT_BTPORT_DEFAULT AICBT_BTPORT_UART
#define AICBT_UART_BAUD_DEFAULT AICBT_UART_BAUD_1_5M
#define AICBT_UART_FC_DEFAULT AICBT_UART_FLOWCTRL_ENABLE
#define AICBT_LPM_ENABLE_DEFAULT 0
#define AICBT_TXPWR_LVL_DEFAULT AICBT_TXPWR_LVL
#define FEATURE_SDIO_CLOCK 70000000 // 0: default, other: target clock rate
#define FEATURE_SDIO_PHASE 2 // 0: default, 2: 180°
@ -375,6 +390,10 @@ struct aicbt_info_t {
uint32_t btport;
uint32_t uart_baud;
uint32_t uart_flowctrl;
uint32_t lpm_enable;
uint32_t txpwr_lvl;
uint32_t addr_adid;
uint32_t addr_patch;
};
struct aicbsp_firmware {
@ -383,20 +402,32 @@ struct aicbsp_firmware {
const char *bt_patch;
const char *bt_table;
const char *wl_fw;
const char *wl_table;
};
struct aicbsp_info_t {
int hwinfo;
int hwinfo_r;
uint32_t cpmode;
uint32_t chip_rev;
bool fwlog_en;
struct device_match_entry *chipinfo;
};
int aicbsp_8800d_fw_init(struct aic_sdio_dev *sdiodev);
int aicbsp_8800dc_fw_init(struct aic_sdio_dev *sdiodev);
int wcn_bind_verify_calculate_verify_data(uint8_t *din, uint8_t *dout);
int rwnx_plat_bin_fw_upload_android(struct aic_sdio_dev *sdiodev, u32 fw_addr, const char *filename);
int aicbt_patch_table_free(struct aicbt_patch_table **head);
struct aicbt_patch_table *aicbt_patch_table_alloc(const char *filename);
int aicbt_patch_info_unpack(struct aicbt_patch_table *head, struct aicbt_info_t *aicbt_info);
int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev, struct aicbt_info_t *btcfg, struct aicbt_patch_table *head);
extern u8 binding_enc_data[16];
extern bool need_binding_verify;
extern struct aicbsp_info_t aicbsp_info;
extern struct mutex aicbsp_power_lock;
extern const struct aicbsp_firmware *aicbsp_firmware_list;
extern const struct aicbsp_firmware fw_u02[];
extern const struct aicbsp_firmware fw_u03[];
#endif

View File

@ -1,6 +1,8 @@
#ifndef __AIC_BSP_EXPORT_H
#define __AIC_BSP_EXPORT_H
#define AICBSP_RESV_MEM_SUPPORT
enum aicbsp_subsys {
AIC_BLUETOOTH,
AIC_WIFI,
@ -11,14 +13,53 @@ enum aicbsp_pwr_state {
AIC_PWR_ON,
};
enum skb_buff_id {
AIC_RESV_MEM_TXDATA,
};
enum AIC_PRODUCT_ID {
PRODUCT_ID_AIC8800D = 0,
PRODUCT_ID_AIC8800DC,
PRODUCT_ID_AIC8800DW,
PRODUCT_ID_AIC8800D80
};
enum aicbsp_cpmode_type {
AICBSP_CPMODE_WORK,
AICBSP_CPMODE_TEST,
AICBSP_CPMODE_MAX,
};
struct device_match_entry {
u16 vid;
u16 pid;
u16 chipid;
char *name;
u16 rev;
u16 subrev;
u16 mcuid;
};
struct skb_buff_pool {
uint32_t id;
uint32_t size;
const char *name;
uint8_t used;
struct sk_buff *skb;
};
struct aicbsp_feature_t {
int hwinfo;
uint32_t sdio_clock;
uint8_t sdio_phase;
bool fwlog_en;
struct device_match_entry *chipinfo;
uint8_t cpmode;
};
int aicbsp_set_subsys(int, int);
int aicbsp_get_feature(struct aicbsp_feature_t *feature);
struct sk_buff *aicbsp_resv_mem_alloc_skb(unsigned int length, uint32_t id);
void aicbsp_resv_mem_kfree_skb(struct sk_buff *skb, uint32_t id);
#endif

View File

@ -13,45 +13,21 @@
#define DRV_AUTHOR "AICSemi"
#define DRV_VERS_MOD "1.0"
#if defined(AICWF_SDIO_SUPPORT)
#define DRV_TYPE_NAME "sdio"
#elif defined(AICWF_USB_SUPPORT)
#define DRV_TYPE_NAME "usb"
#else
#define DRV_TYPE_NAME "unknow"
#endif
#define DRV_RELEASE_DATE "20221108"
#define DRV_PATCH_LEVEL "001"
#define DRV_RELEASE_TAG "aic-bsp-" DRV_TYPE_NAME "-" DRV_RELEASE_DATE "-" DRV_PATCH_LEVEL
static struct platform_device *aicbsp_pdev;
const struct aicbsp_firmware *aicbsp_firmware_list = fw_u02;
const struct aicbsp_firmware fw_u02[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u02)",
.bt_adid = "fw_adid.bin",
.bt_patch = "fw_patch.bin",
.bt_table = "fw_patch_table.bin",
.wl_fw = "fmacfw.bin"
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u02)",
.bt_adid = "fw_adid.bin",
.bt_patch = "fw_patch.bin",
.bt_table = "fw_patch_table.bin",
.wl_fw = "fmacfw_rf.bin"
},
};
const struct aicbsp_firmware fw_u03[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u03/u04)",
.bt_adid = "fw_adid_u03.bin",
.bt_patch = "fw_patch_u03.bin",
.bt_table = "fw_patch_table_u03.bin",
.wl_fw = "fmacfw.bin"
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u03/u04)",
.bt_adid = "fw_adid_u03.bin",
.bt_patch = "fw_patch_u03.bin",
.bt_table = "fw_patch_table_u03.bin",
.wl_fw = "fmacfw_rf.bin"
},
};
const struct aicbsp_firmware *aicbsp_firmware_list;
struct aicbsp_info_t aicbsp_info = {
.hwinfo_r = AICBSP_HWINFO_DEFAULT,
@ -80,6 +56,11 @@ static ssize_t cpmode_show(struct device *dev,
ssize_t count = 0;
uint8_t i = 0;
if (aicbsp_firmware_list == NULL) {
count += sprintf(&buf[count], "Wi-Fi not opened since system power on\n");
return count;
}
count += sprintf(&buf[count], "Support mode value:\n");
for (i = 0; i < AICBSP_CPMODE_MAX; i++) {
@ -109,7 +90,7 @@ static ssize_t cpmode_store(struct device *dev,
}
aicbsp_info.cpmode = val;
printk("%s, set mode to: %lu[%s] done\n", __func__, val, aicbsp_firmware_list[val].desc);
printk("%s, set mode to: %lu[%s] done\n", __func__, val, aicbsp_firmware_list ? aicbsp_firmware_list[val].desc : "unknow");
return count;
}
@ -119,11 +100,12 @@ static ssize_t hwinfo_show(struct device *dev,
{
ssize_t count = 0;
count += sprintf(&buf[count], "chip hw rev: ");
if (aicbsp_info.hwinfo_r < 0)
count += sprintf(&buf[count], "-1(not avalible)\n");
if (aicbsp_info.chipinfo == NULL)
count += sprintf(&buf[count], "chip info not avalible)\n");
else
count += sprintf(&buf[count], "0x%02X\n", aicbsp_info.chip_rev);
count += sprintf(&buf[count], "chip name: %s, id: 0x%02X, rev: 0x%02X, subrev: 0x%02X\n",
aicbsp_info.chipinfo->name, aicbsp_info.chipinfo->chipid,
aicbsp_info.chipinfo->rev, aicbsp_info.chipinfo->subrev);
count += sprintf(&buf[count], "hwinfo read: ");
if (aicbsp_info.hwinfo_r < 0)
@ -270,7 +252,9 @@ static int __init aicbsp_init(void)
{
int ret;
printk("%s\n", __func__);
printk("%s, Driver Release Tag: %s\n", __func__, DRV_RELEASE_TAG);
aicbsp_resv_mem_init();
mutex_init(&aicbsp_power_lock);
ret = platform_driver_register(&aicbsp_driver);
if (ret) {
@ -312,6 +296,7 @@ err1:
platform_driver_unregister(&aicbsp_driver);
err0:
mutex_destroy(&aicbsp_power_lock);
aicbsp_resv_mem_deinit();
return ret;
}
@ -322,6 +307,7 @@ static void __exit aicbsp_exit(void)
platform_device_del(aicbsp_pdev);
platform_driver_unregister(&aicbsp_driver);
mutex_destroy(&aicbsp_power_lock);
aicbsp_resv_mem_deinit();
printk("%s\n", __func__);
}

View File

@ -33,6 +33,15 @@ static struct aic_sdio_dev *aicbsp_sdiodev;
static struct semaphore *aicbsp_notify_semaphore;
static const struct sdio_device_id aicbsp_sdmmc_ids[];
static struct device_match_entry aicdev_match_table[] = {
{0x544a, 0x0146, PRODUCT_ID_AIC8800D, "aic8800d", 0, 0}, // 8800d in bootloader mode
{0xc8a1, 0xc18d, PRODUCT_ID_AIC8800DC, "aic8800dc", 0, 0}, // 8800dc in bootloader mode
// {0x5449, 0x0145, PRODUCT_ID_AIC8800DW, "aic8800dw", 0, 0},
// {0x5449, 0x0145, PRODUCT_ID_AIC8800D80, "aic8800d80", 0, 0},
};
static struct device_match_entry *aic_matched_ic;
static int aicbsp_dummy_probe(struct sdio_func *func, const struct sdio_device_id *id)
{
if (func && (func->num != 2))
@ -142,7 +151,7 @@ void *aicbsp_get_drvdata(void *args)
(void)args;
if (aicbsp_sdiodev)
return aicbsp_sdiodev->bus_if;
return NULL;
return dev_get_drvdata((const struct device *)args);
}
static int aicbsp_sdio_probe(struct sdio_func *func,
@ -152,12 +161,22 @@ static int aicbsp_sdio_probe(struct sdio_func *func,
struct aic_sdio_dev *sdiodev;
struct aicwf_bus *bus_if;
int err = -ENODEV;
int i = 0;
sdio_dbg("%s:%d\n", __func__, func->num);
if (func->num != 2) {
return err;
for (i = 0; i < sizeof(aicdev_match_table) / sizeof(aicdev_match_table[0]); i++) {
if (func->vendor == aicdev_match_table[i].vid && func->device == aicdev_match_table[i].pid) {
aic_matched_ic = &aicdev_match_table[i];
}
}
if (aic_matched_ic == NULL)
return err;
sdio_dbg("%s:%d, matched chip: %s\n", __func__, func->num, aic_matched_ic ? aic_matched_ic->name : "none");
if (func->num != 2)
return err;
func = func->card->sdio_func[1 - 1]; //replace 2 with 1
host = func->card->host;
sdio_dbg("%s after replace:%d\n", __func__, func->num);
@ -175,9 +194,16 @@ static int aicbsp_sdio_probe(struct sdio_func *func,
return -ENOMEM;
}
sdiodev->func = func;
aicbsp_info.chipinfo = aic_matched_ic;
sdiodev->func[0] = func;
sdiodev->bus_if = bus_if;
bus_if->bus_priv.sdio = sdiodev;
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800DC) {
sdiodev->func[1] = func->card->sdio_func[1];
dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
}
dev_set_drvdata(&func->dev, bus_if);
sdiodev->dev = &func->dev;
err = aicwf_sdio_func_init(sdiodev);
@ -201,6 +227,7 @@ fail:
dev_set_drvdata(&func->dev, NULL);
kfree(sdiodev);
kfree(bus_if);
aic_matched_ic = NULL;
return err;
}
@ -222,19 +249,20 @@ static void aicbsp_sdio_remove(struct sdio_func *func)
goto done;
}
func = sdiodev->func;
func = sdiodev->func[0];
host = func->card->host;
host->caps &= ~MMC_CAP_NONREMOVABLE;
aicwf_sdio_release(sdiodev);
aicwf_sdio_func_deinit(sdiodev);
dev_set_drvdata(&sdiodev->func->dev, NULL);
dev_set_drvdata(&sdiodev->func[0]->dev, NULL);
kfree(sdiodev);
kfree(bus_if);
done:
aicbsp_sdiodev = NULL;
aic_matched_ic = NULL;
sdio_dbg("%s done\n", __func__);
}
@ -270,7 +298,8 @@ static int aicbsp_sdio_resume(struct device *dev)
}
static const struct sdio_device_id aicbsp_sdmmc_ids[] = {
{SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN)},
{SDIO_DEVICE(0x544a, 0x0146)}, // aic8800d in bootloader mode
{SDIO_DEVICE(0xc8a1, 0xc18d)}, // aic8800dc in bootloader mode
{ },
};
@ -352,27 +381,34 @@ void aicbsp_sdio_exit(void)
void aicbsp_sdio_release(struct aic_sdio_dev *sdiodev)
{
int funcnum = 1, i = 0;
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800DC)
funcnum = 2;
sdiodev->bus_if->state = BUS_DOWN_ST;
sdio_claim_host(sdiodev->func);
sdio_release_irq(sdiodev->func);
sdio_release_host(sdiodev->func);
for (i = 0; i < funcnum; i++) {
sdio_claim_host(sdiodev->func[i]);
sdio_release_irq(sdiodev->func[i]);
sdio_release_host(sdiodev->func[i]);
}
}
int aicwf_sdio_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val)
int aicwf_sdio_readb(struct sdio_func *func, uint regaddr, u8 *val)
{
int ret;
sdio_claim_host(sdiodev->func);
*val = sdio_readb(sdiodev->func, regaddr, &ret);
sdio_release_host(sdiodev->func);
sdio_claim_host(func);
*val = sdio_readb(func, regaddr, &ret);
sdio_release_host(func);
return ret;
}
int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val)
int aicwf_sdio_writeb(struct sdio_func *func, uint regaddr, u8 val)
{
int ret;
sdio_claim_host(sdiodev->func);
sdio_writeb(sdiodev->func, val, regaddr, &ret);
sdio_release_host(sdiodev->func);
sdio_claim_host(func);
sdio_writeb(func, val, regaddr, &ret);
sdio_release_host(func);
return ret;
}
@ -383,7 +419,7 @@ int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev)
u32 count = 0;
while (true) {
ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_FLOW_CTRL_REG, &fc_reg);
ret = aicwf_sdio_readb(sdiodev->func[0], SDIOWIFI_FLOW_CTRL_REG, &fc_reg);
if (ret) {
return -1;
}
@ -413,9 +449,20 @@ int aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count)
{
int ret = 0;
sdio_claim_host(sdiodev->func);
ret = sdio_writesb(sdiodev->func, 7, buf, count);
sdio_release_host(sdiodev->func);
sdio_claim_host(sdiodev->func[0]);
ret = sdio_writesb(sdiodev->func[0], 7, buf, count);
sdio_release_host(sdiodev->func[0]);
return ret;
}
int aicwf_sdio_send_msg(struct aic_sdio_dev *sdiodev, u8 *buf, uint count)
{
int ret = 0;
sdio_claim_host(sdiodev->func[0]);
ret = sdio_writesb(sdiodev->func[1], 7, buf, count);
sdio_release_host(sdiodev->func[1]);
return ret;
}
@ -429,9 +476,30 @@ int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf,
return -EINVAL;;
}
sdio_claim_host(sdiodev->func);
ret = sdio_readsb(sdiodev->func, skbbuf->data, 8, size);
sdio_release_host(sdiodev->func);
sdio_claim_host(sdiodev->func[0]);
ret = sdio_readsb(sdiodev->func[0], skbbuf->data, 8, size);
sdio_release_host(sdiodev->func[0]);
if (ret < 0) {
return ret;
}
skbbuf->len = size;
return ret;
}
int aicwf_sdio_recv_msg(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf,
u32 size)
{
int ret;
if ((!skbbuf) || (!size)) {
return -EINVAL;;
}
sdio_claim_host(sdiodev->func[1]);
ret = sdio_readsb(sdiodev->func[1], skbbuf->data, 8, size);
sdio_release_host(sdiodev->func[1]);
if (ret < 0) {
return ret;
@ -451,7 +519,7 @@ int aicwf_sdio_wakeup(struct aic_sdio_dev *sdiodev)
//if (sdiodev->rwnx_hw->vif_started) {
down(&sdiodev->pwrctl_wakeup_sema);
while (write_retry) {
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 1);
ret = aicwf_sdio_writeb(sdiodev->func[0], SDIOWIFI_WAKEUP_REG, 1);
if (ret) {
txrx_err("sdio wakeup fail\n");
ret = -1;
@ -459,7 +527,7 @@ int aicwf_sdio_wakeup(struct aic_sdio_dev *sdiodev)
read_retry = 10;
while (read_retry) {
u8 val;
ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
ret = aicwf_sdio_readb(sdiodev->func[0], SDIOWIFI_SLEEP_REG, &val);
if ((ret == 0) && (val & 0x10)) {
break;
}
@ -490,7 +558,7 @@ int aicwf_sdio_sleep_allow(struct aic_sdio_dev *sdiodev)
struct aicwf_bus *bus_if = sdiodev->bus_if;
if (bus_if->state == BUS_DOWN_ST) {
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
ret = aicwf_sdio_writeb(sdiodev->func[0], SDIOWIFI_SLEEP_REG, 0x10);
if (ret) {
sdio_err("Write sleep fail!\n");
}
@ -501,7 +569,7 @@ int aicwf_sdio_sleep_allow(struct aic_sdio_dev *sdiodev)
if (sdiodev->state == SDIO_ACTIVE_ST) {
{
sdio_dbg("s\n");
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
ret = aicwf_sdio_writeb(sdiodev->func[0], SDIOWIFI_SLEEP_REG, 0x10);
if (ret)
sdio_err("Write sleep fail!\n");
}
@ -573,7 +641,7 @@ static int aicwf_sdio_intr_get_len_bytemode(struct aic_sdio_dev *sdiodev, u8 *by
if (sdiodev->bus_if->state == BUS_DOWN_ST) {
*byte_len = 0;
} else {
ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_BYTEMODE_LEN_REG, byte_len);
ret = aicwf_sdio_readb(sdiodev->func[0], SDIOWIFI_BYTEMODE_LEN_REG, byte_len);
sdiodev->rx_priv->data_len = (*byte_len)*4;
}
@ -636,6 +704,33 @@ struct sk_buff *aicwf_sdio_readframes(struct aic_sdio_dev *sdiodev)
return skb;
}
struct sk_buff *aicwf_sdio_readmessages(struct aic_sdio_dev *sdiodev)
{
int ret = 0;
u32 size = 0;
struct sk_buff *skb = NULL;
struct aicwf_bus *bus_if = dev_get_drvdata(sdiodev->dev);
if (bus_if->state == BUS_DOWN_ST) {
sdio_dbg("bus down\n");
return NULL;
}
size = sdiodev->rx_priv->data_len;
skb = __dev_alloc_skb(size, GFP_KERNEL);
if (!skb) {
return NULL;
}
ret = aicwf_sdio_recv_msg(sdiodev, skb, size);
if (ret) {
dev_kfree_skb(skb);
skb = NULL;
}
return skb;
}
static int aicwf_sdio_tx_msg(struct aic_sdio_dev *sdiodev)
{
int err = 0;
@ -663,22 +758,31 @@ static int aicwf_sdio_tx_msg(struct aic_sdio_dev *sdiodev)
} else
len = payload_len;
buffer_cnt = aicwf_sdio_flow_ctrl(sdiodev);
while ((buffer_cnt <= 0 || len > (buffer_cnt * BUFFER_SIZE)) && retry < 5) {
retry++;
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800D) {
buffer_cnt = aicwf_sdio_flow_ctrl(sdiodev);
while ((buffer_cnt <= 0 || len > (buffer_cnt * BUFFER_SIZE)) && retry < 5) {
retry++;
buffer_cnt = aicwf_sdio_flow_ctrl(sdiodev);
}
}
down(&sdiodev->tx_priv->cmd_txsema);
if (buffer_cnt > 0 && len < (buffer_cnt * BUFFER_SIZE)) {
err = aicwf_sdio_send_pkt(sdiodev, payload, len);
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800D) {
if (buffer_cnt > 0 && len < (buffer_cnt * BUFFER_SIZE)) {
err = aicwf_sdio_send_pkt(sdiodev, payload, len);
if (err) {
sdio_err("aicwf_sdio_send_pkt fail%d\n", err);
}
} else {
up(&sdiodev->tx_priv->cmd_txsema);
sdio_err("tx msg fc retry fail\n");
return -1;
}
} else if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800DC) {
err = aicwf_sdio_send_msg(sdiodev, payload, len);
if (err) {
sdio_err("aicwf_sdio_send_pkt fail%d\n", err);
}
} else {
up(&sdiodev->tx_priv->cmd_txsema);
sdio_err("tx msg fc retry fail\n");
return -1;
}
sdiodev->tx_priv->cmd_txstate = false;
@ -736,7 +840,9 @@ static void aicwf_sdio_tx_process(struct aic_sdio_dev *sdiodev)
return;
}
sdiodev->tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
if (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq))
sdiodev->tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
while (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) {
aicwf_sdio_send(sdiodev->tx_priv);
if (sdiodev->tx_priv->cmd_txstate)
@ -797,7 +903,7 @@ static int aicwf_sdio_bus_txmsg(struct device *dev, u8 *msg, uint msglen)
if (sdiodev->tx_priv->cmd_txstate) {
int timeout = msecs_to_jiffies(CMD_TX_TIMEOUT);
ret = wait_event_interruptible_timeout(sdiodev->tx_priv->cmd_txdone_wait, \
ret = wait_event_timeout(sdiodev->tx_priv->cmd_txdone_wait, \
!(sdiodev->tx_priv->cmd_txstate), timeout);
}
@ -959,20 +1065,37 @@ static int aicwf_sdio_bus_start(struct device *dev)
struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0;
#if 1
sdio_claim_host(sdiodev->func);
sdio_claim_irq(sdiodev->func, aicwf_sdio_hal_irqhandler);
#else
//since we have func2 we don't register irq handler
sdio_claim_irq(sdiodev->func, NULL);
sdiodev->func->irq_handler = (sdio_irq_handler_t *)aicwf_sdio_hal_irqhandler;
#endif
//enable sdio interrupt
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x07);
sdio_release_host(sdiodev->func);
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800D) {
sdio_claim_host(sdiodev->func[0]);
sdio_claim_irq(sdiodev->func[0], aicwf_sdio_hal_irqhandler);
//enable sdio interrupt
ret = aicwf_sdio_writeb(sdiodev->func[0], SDIOWIFI_INTR_CONFIG_REG, 0x07);
if (ret != 0)
sdio_err("intr register failed:%d\n", ret);
sdio_release_host(sdiodev->func[0]);
} else if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800DC) {
sdio_claim_host(sdiodev->func[0]);
if (ret != 0)
sdio_err("intr register failed:%d\n", ret);
//since we have func2 we don't register irq handler
sdio_claim_irq(sdiodev->func[0], NULL);
sdio_claim_irq(sdiodev->func[1], NULL);
sdiodev->func[0]->irq_handler = (sdio_irq_handler_t *)aicwf_sdio_hal_irqhandler;
sdiodev->func[1]->irq_handler = (sdio_irq_handler_t *)aicwf_sdio_hal_irqhandler_func2;
sdio_release_host(sdiodev->func[0]);
//enable sdio interrupt
ret = aicwf_sdio_writeb(sdiodev->func[0], SDIOWIFI_INTR_CONFIG_REG, 0x07);
if (ret != 0)
sdio_err("intr register failed:%d\n", ret);
//enable sdio interrupt
ret = aicwf_sdio_writeb(sdiodev->func[1], SDIOWIFI_INTR_CONFIG_REG, 0x07);
if (ret != 0)
sdio_err("func2 intr register failed:%d\n", ret);
}
bus_if->state = BUS_UP_ST;
@ -1068,10 +1191,10 @@ void aicwf_sdio_hal_irqhandler(struct sdio_func *func)
return;
}
ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_BLOCK_CNT_REG, &intstatus);
ret = aicwf_sdio_readb(sdiodev->func[0], SDIOWIFI_BLOCK_CNT_REG, &intstatus);
while (ret || (intstatus & SDIO_OTHER_INTERRUPT)) {
sdio_err("ret=%d, intstatus=%x\r\n", ret, intstatus);
ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_BLOCK_CNT_REG, &intstatus);
ret = aicwf_sdio_readb(sdiodev->func[0], SDIOWIFI_BLOCK_CNT_REG, &intstatus);
}
sdiodev->rx_priv->data_len = intstatus * SDIOWIFI_FUNC_BLOCKSIZE;
@ -1093,6 +1216,52 @@ void aicwf_sdio_hal_irqhandler(struct sdio_func *func)
complete(&bus_if->busrx_trgg);
}
void aicwf_sdio_hal_irqhandler_func2(struct sdio_func *func)
{
struct aicwf_bus *bus_if = aicbsp_sdiodev->bus_if;
struct aic_sdio_dev *sdiodev = aicbsp_sdiodev;
u8 intstatus = 0;
u8 byte_len = 0;
struct sk_buff *pkt = NULL;
int ret;
if (!bus_if || bus_if->state == BUS_DOWN_ST) {
if (!bus_if)
sdio_err("bus if none\n");
else
sdio_err("bus state down\n");
sdio_err("bus err\n");
return;
}
ret = aicwf_sdio_readb(sdiodev->func[1], SDIOWIFI_BLOCK_CNT_REG, &intstatus);
while (ret || (intstatus & SDIO_OTHER_INTERRUPT)) {
sdio_err("ret=%d, intstatus=%x\r\n", ret, intstatus);
ret = aicwf_sdio_readb(sdiodev->func[0], SDIOWIFI_BLOCK_CNT_REG, &intstatus);
}
sdiodev->rx_priv->data_len = intstatus * SDIOWIFI_FUNC_BLOCKSIZE;
if (intstatus > 0) {
if (intstatus < 64) {
pkt = aicwf_sdio_readmessages(sdiodev);
} else {
sdio_info("byte mode len=%d\r\n", byte_len);
aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len);//byte_len must<= 128
pkt = aicwf_sdio_readmessages(sdiodev);
}
} else {
#ifndef CONFIG_PLATFORM_ALLWINNER
sdio_err("Interrupt but no data\n");
#endif
}
if (pkt)
aicwf_sdio_enq_rxpkt(sdiodev, pkt);
complete(&bus_if->busrx_trgg);
}
void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration)
{
uint timeout;
@ -1123,20 +1292,26 @@ void aicwf_sdio_release(struct aic_sdio_dev *sdiodev)
{
struct aicwf_bus *bus_if;
int ret = 0;
int funcnum = 1, i = 0;
sdio_dbg("%s\n", __func__);
bus_if = sdiodev->bus_if;
bus_if->state = BUS_DOWN_ST;
sdio_claim_host(sdiodev->func);
//disable sdio interrupt
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x0);
if (ret < 0) {
sdio_err("reg:%d write failed!\n", SDIOWIFI_INTR_CONFIG_REG);
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800DC)
funcnum = 2;
for (i = 0; i < funcnum; i++) {
sdio_claim_host(sdiodev->func[i]);
//disable sdio interrupt
ret = aicwf_sdio_writeb(sdiodev->func[i], SDIOWIFI_INTR_CONFIG_REG, 0x0);
if (ret < 0) {
sdio_err("reg:%d write failed!\n", SDIOWIFI_INTR_CONFIG_REG);
}
sdio_release_irq(sdiodev->func[i]);
sdio_release_host(sdiodev->func[i]);
}
sdio_release_irq(sdiodev->func);
sdio_release_host(sdiodev->func);
if (sdiodev->dev)
aicwf_bus_deinit(sdiodev->dev);
@ -1160,25 +1335,25 @@ int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev)
struct aicbsp_feature_t feature;
aicbsp_get_feature(&feature);
host = sdiodev->func->card->host;
host = sdiodev->func[0]->card->host;
sdio_claim_host(sdiodev->func);
sdiodev->func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
sdio_f0_writeb(sdiodev->func, feature.sdio_phase, 0x13, &ret);
sdio_claim_host(sdiodev->func[0]);
sdiodev->func[0]->card->quirks |= MMC_QUIRK_LENIENT_FN0;
sdio_f0_writeb(sdiodev->func[0], feature.sdio_phase, 0x13, &ret);
if (ret < 0) {
sdio_err("write func0 fail %d\n", ret);
return ret;
}
ret = sdio_set_block_size(sdiodev->func, SDIOWIFI_FUNC_BLOCKSIZE);
ret = sdio_set_block_size(sdiodev->func[0], SDIOWIFI_FUNC_BLOCKSIZE);
if (ret < 0) {
sdio_err("set blocksize fail %d\n", ret);
sdio_release_host(sdiodev->func);
sdio_release_host(sdiodev->func[0]);
return ret;
}
ret = sdio_enable_func(sdiodev->func);
ret = sdio_enable_func(sdiodev->func[0]);
if (ret < 0) {
sdio_release_host(sdiodev->func);
sdio_release_host(sdiodev->func[0]);
sdio_err("enable func fail %d.\n", ret);
}
@ -1187,16 +1362,49 @@ int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev)
host->ops->set_ios(host, &host->ios);
sdio_dbg("Set SDIO Clock %d MHz\n", host->ios.clock/1000000);
}
sdio_release_host(sdiodev->func);
sdio_release_host(sdiodev->func[0]);
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_REGISTER_BLOCK, block_bit0);
if (aicbsp_info.chipinfo->chipid == PRODUCT_ID_AIC8800DC) {
sdio_claim_host(sdiodev->func[1]);
//set sdio blocksize
ret = sdio_set_block_size(sdiodev->func[1], SDIOWIFI_FUNC_BLOCKSIZE);
if (ret < 0) {
printk("set func2 blocksize fail %d\n", ret);
sdio_release_host(sdiodev->func[1]);
return ret;
}
//set sdio enable func
ret = sdio_enable_func(sdiodev->func[1]);
if (ret < 0) {
printk("enable func2 fail %d.\n", ret);
}
sdio_release_host(sdiodev->func[1]);
ret = aicwf_sdio_writeb(sdiodev->func[1], SDIOWIFI_REGISTER_BLOCK, block_bit0);
if (ret < 0) {
printk("reg:%d write failed!\n", SDIOWIFI_REGISTER_BLOCK);
return ret;
}
//1: no byte mode
ret = aicwf_sdio_writeb(sdiodev->func[1], SDIOWIFI_BYTEMODE_ENABLE_REG, byte_mode_disable);
if (ret < 0) {
printk("reg:%d write failed!\n", SDIOWIFI_BYTEMODE_ENABLE_REG);
return ret;
}
}
ret = aicwf_sdio_writeb(sdiodev->func[0], SDIOWIFI_REGISTER_BLOCK, block_bit0);
if (ret < 0) {
sdio_err("reg:%d write failed!\n", SDIOWIFI_REGISTER_BLOCK);
return ret;
}
//1: no byte mode
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_BYTEMODE_ENABLE_REG, byte_mode_disable);
ret = aicwf_sdio_writeb(sdiodev->func[0], SDIOWIFI_BYTEMODE_ENABLE_REG, byte_mode_disable);
if (ret < 0) {
sdio_err("reg:%d write failed!\n", SDIOWIFI_BYTEMODE_ENABLE_REG);
return ret;
@ -1208,9 +1416,9 @@ int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev)
void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev)
{
sdio_claim_host(sdiodev->func);
sdio_disable_func(sdiodev->func);
sdio_release_host(sdiodev->func);
sdio_claim_host(sdiodev->func[0]);
sdio_disable_func(sdiodev->func[0]);
sdio_release_host(sdiodev->func[0]);
}
void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev)

View File

@ -49,7 +49,7 @@ typedef enum {
struct aic_sdio_dev {
struct rwnx_cmd_mgr cmd_mgr;
struct sdio_func *func;
struct sdio_func *func[2];
struct device *dev;
struct aicwf_bus *bus_if;
@ -67,8 +67,9 @@ struct aic_sdio_dev {
};
void *aicbsp_get_drvdata(void *args);
int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
int aicwf_sdio_writeb(struct sdio_func *func, uint regaddr, u8 val);
void aicwf_sdio_hal_irqhandler(struct sdio_func *func);
void aicwf_sdio_hal_irqhandler_func2(struct sdio_func *func);
void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration);
int aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target);
int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev);

View File

@ -21,7 +21,8 @@
int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
{
int ret = 0;
int ret = -ENOMEM;
int errnum = 0;
struct aicwf_bus *bus_if;
if (!dev) {
@ -31,7 +32,6 @@ int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
bus_if = dev_get_drvdata(dev);
bus_if->cmd_buf = kzalloc(CMD_BUF_MAX, GFP_KERNEL);
if (!bus_if->cmd_buf) {
ret = -ENOMEM;
txrx_err("proto_attach failed\n");
goto fail;
}
@ -45,18 +45,20 @@ int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
#endif
if (IS_ERR(bus_if->bustx_thread)) {
errnum = PTR_ERR(bus_if->bustx_thread);
bus_if->bustx_thread = NULL;
txrx_err("aicwf_bustx_thread run fail\n");
txrx_err("aicwf_bustx_thread run fail, errnum is %d\n", errnum);
goto fail;
}
if (IS_ERR(bus_if->busrx_thread)) {
errnum = PTR_ERR(bus_if->busrx_thread);
bus_if->busrx_thread = NULL;
txrx_err("aicwf_bustx_thread run fail\n");
txrx_err("aicwf_busrx_thread run fail, errnum is %d\n", errnum);
goto fail;
}
return ret;
return 0;
fail:
aicwf_bus_deinit(dev);
@ -83,7 +85,7 @@ void aicwf_bus_deinit(struct device *dev)
bus_if->cmd_buf = NULL;
}
if (bus_if->bustx_thread) {
if (!IS_ERR_OR_NULL(bus_if->bustx_thread)) {
complete_all(&bus_if->bustx_trgg);
kthread_stop(bus_if->bustx_thread);
bus_if->bustx_thread = NULL;
@ -284,7 +286,7 @@ static void aicwf_recvframe_queue_deinit(struct list_head *q)
void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv)
{
if (rx_priv->sdiodev->bus_if->busrx_thread) {
if (!IS_ERR_OR_NULL(rx_priv->sdiodev->bus_if->busrx_thread)) {
complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg);
kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread);
rx_priv->sdiodev->bus_if->busrx_thread = NULL;

View File

@ -62,9 +62,11 @@
/*
* Defines
*/
#define VERSION "1.3.3"
#define PROC_DIR "bluetooth/sleep"
#define DRV_RELEASE_DATE "20220429"
#define DRV_PATCH_LEVEL "003"
#define DRV_RELEASE_TAG "aic-btlpm-" DRV_RELEASE_DATE "-" DRV_PATCH_LEVEL
#define VERSION "1.3.3"
#define PROC_DIR "bluetooth/sleep"
#define DEFAULT_UART_INDEX 1
#define BT_BLUEDROID_SUPPORT 1
@ -107,8 +109,9 @@ DECLARE_DELAYED_WORK(sleep_workqueue, bluesleep_sleep_work);
#define BT_PROTO 0x01
#define BT_TXDATA 0x02
#define BT_ASLEEP 0x04
#define BT_RXTIMER 0x20
#define BT_TXIDLE 0x08
#define BT_PAUSE 0x09
#define BT_RXTIMER 0x0a
#if BT_BLUEDROID_SUPPORT
static bool has_lpm_enabled;
@ -211,7 +214,8 @@ static void bluesleep_sleep_work(struct work_struct *work)
BT_DBG("already asleep");
return;
}
if (bsi->uport->ops->tx_empty(bsi->uport)) {
if (bsi->uport->ops->tx_empty(bsi->uport) ||
(test_bit(BT_PAUSE, &flags) && test_bit(BT_TXIDLE, &flags))) {
BT_DBG("going to sleep...");
set_bit(BT_ASLEEP, &flags);
/*Deactivating UART */
@ -242,9 +246,22 @@ static void bluesleep_sleep_work(struct work_struct *work)
set_bit(BT_RXTIMER, &flags);
hsuart_power(1);
} else {
static int tx_idle_cnt;
if (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert && test_bit(BT_TXIDLE, &flags))
tx_idle_cnt++;
else
tx_idle_cnt = 0;
mod_timer(&rx_timer, jiffies + (RX_TIMER_INTERVAL * HZ));
if (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert
&& !test_bit(BT_TXIDLE, &flags)) {
set_bit(BT_RXTIMER, &flags);
if (test_bit(BT_PAUSE, &flags)) {
BT_DBG("rx wake du BT_PAUSE:%lx", flags);
///enable bt sleep immediately
gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
} else if ((gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert
&& !test_bit(BT_TXIDLE, &flags)) || tx_idle_cnt > 5) {
tx_idle_cnt = 0;
BT_DBG("force retrigger bt wake:%lx", flags);
gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert);
msleep(20);
@ -340,11 +357,20 @@ static ssize_t bluesleep_write_proc_lpm(struct file *file,
return -EFAULT;
if (b == '0') {
#if 1
set_bit(BT_PAUSE, &flags);
set_bit(BT_TXIDLE, &flags);
clear_bit(BT_TXDATA, &flags);
/* deassert BT_WAKE */
gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
#else
/* HCI_DEV_UNREG */
bluesleep_stop();
has_lpm_enabled = false;
bsi->uport = NULL;
#endif
} else {
clear_bit(BT_PAUSE, &flags);
/* HCI_DEV_REG */
if (!has_lpm_enabled) {
has_lpm_enabled = true;
@ -478,6 +504,7 @@ static void bluesleep_tx_allow_sleep(void)
spin_lock_irqsave(&rw_lock, irq_flags);
gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
set_bit(BT_TXIDLE, &flags);
clear_bit(BT_TXDATA, &flags);
bluesleep_tx_idle();
spin_unlock_irqrestore(&rw_lock, irq_flags);
}
@ -569,7 +596,7 @@ fail:
/**
* Stops the Sleep-Mode Protocol on the Host.
*/
static void bluesleep_stop(void)
static __attribute__((unused)) void bluesleep_stop(void)
{
unsigned long irq_flags;
@ -917,8 +944,6 @@ static int bluesleep_remove(struct platform_device *pdev)
/* assert bt wake */
gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert);
if (test_bit(BT_PROTO, &flags)) {
if (disable_irq_wake(bsi->host_wake_irq))
BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
free_irq(bsi->host_wake_irq, &bsi->pdev->dev);
del_timer(&rx_timer);
if (test_bit(BT_ASLEEP, &flags))
@ -966,6 +991,7 @@ static int __init bluesleep_init(void)
struct proc_dir_entry *ent;
BT_DBG("BlueSleep Mode Driver Ver %s", VERSION);
BT_DBG("Driver Release Tag: %s", DRV_RELEASE_TAG);
retval = platform_driver_probe(&bluesleep_driver, bluesleep_probe);
if (retval)

View File

@ -48,6 +48,7 @@ CONFIG_RWNX_BFMER ?= n
CONFIG_SDIO_SUPPORT =y
CONFIG_USB_SUPPORT =n
CONFIG_PCIE_SUPPORT =n
CONFIG_RX_REORDER ?=y
CONFIG_ARP_OFFLOAD =y
CONFIG_RADAR_OR_IR_DETECT =n
@ -55,6 +56,7 @@ CONFIG_DOWNLOAD_FW =y
CONFIG_RFTEST=y
CONFIG_USB_BT =n
CONFIG_GKI_OPT_FEATURES ?= y
CONFIG_WPA3_FOR_OLD_KERNEL ?= n
# Support of MU-MIMO transmission (need FW support)
@ -79,6 +81,7 @@ CONFIG_RWNX_DBG ?= y
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) := aic8800_fdrv.o
aic8800_fdrv-y := \
rwnx_wakelock.o \
rwnx_gki.o \
rwnx_msg_tx.o \
rwnx_msg_rx.o \
@ -94,7 +97,6 @@ aic8800_fdrv-y := \
rwnx_mod_params.o \
rwnx_mesh.o \
rwnx_platform.o \
rwnx_pci.o \
rwnx_dini.o \
rwnx_v7.o \
ipc_host.o \
@ -115,6 +117,8 @@ aic8800_fdrv-$(CONFIG_USB_SUPPORT) += usb_host.o
aic8800_fdrv-$(CONFIG_USB_SUPPORT) += aicwf_txrxif.o
aic8800_fdrv-$(CONFIG_USB_SUPPORT) += aicwf_usb.o
aic8800_fdrv-$(CONFIG_PCIE_SUPPORT) += rwnx_pci.o
ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_DEBUGFS
ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_UM_HELPER_DFLT=\"$(CONFIG_RWNX_UM_HELPER_DFLT)\"
ccflags-$(CONFIG_RWNX_P2P_DEBUGFS) += -DCONFIG_RWNX_P2P_DEBUGFS
@ -139,11 +143,6 @@ ccflags-$(CONFIG_START_FROM_BOOTROM) += -DCONFIG_START_FROM_BOOTROM
ccflags-$(CONFIG_PMIC_SETTING) += -DCONFIG_PMIC_SETTING
ccflags-$(CONFIG_ROM_PATCH_EN) += -DCONFIG_ROM_PATCH_EN
CURRENT_CODE_VERSION := $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)
MINI_VERSION_REQUEST := 4.14.0
ifeq ($(shell expr $(CURRENT_CODE_VERSION) \< $(MINI_VERSION_REQUEST)),1)
ccflags-y += -DCONFIG_HE_FOR_OLD_KERNEL
endif
ccflags-$(CONFIG_PLATFORM_ALLWINNER) += -DCONFIG_COEX
ccflags-$(CONFIG_PLATFORM_NANOPI_M4) += -DCONFIG_COEX
@ -162,6 +161,7 @@ ccflags-$(CONFIG_RWNX_DBG) += -DCONFIG_RWNX_DBG
ccflags-$(CONFIG_RWNX_SW_PROFILING) += -DCONFIG_RWNX_SW_PROFILING
ccflags-$(CONFIG_RWNX_MUMIMO_TX) += -DCONFIG_RWNX_MUMIMO_TX
ccflags-$(CONFIG_RFTEST) += -DCONFIG_RFTEST
ccflags-$(CONFIG_WPA3_FOR_OLD_KERNEL) += -DCONFIG_WPA3_FOR_OLD_KERNEL
ifeq ($(CONFIG_SDIO_SUPPORT), y)
ccflags-y += -DAICWF_SDIO_SUPPORT
@ -171,6 +171,10 @@ ifeq ($(CONFIG_USB_SUPPORT), y)
ccflags-y += -DAICWF_USB_SUPPORT
endif
ifeq ($(CONFIG_PCIE_SUPPORT), y)
ccflags-y += -DAICWF_PCIE_SUPPORT
endif
ifeq ($(CONFIG_RWNX_MUMIMO_TX), y)
ccflags-y += -DCONFIG_USER_MAX=2
else

View File

@ -10,6 +10,7 @@
#include <net/netlink.h>
#include "rwnx_version_gen.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
static struct wifi_ring_buffer_status ring_buffer[] = {
{
.name = "aicwf_ring_buffer0",
@ -843,12 +844,15 @@ const struct wiphy_vendor_command aicwf_vendor_cmd[] = {
static const struct nl80211_vendor_cmd_info aicwf_vendor_events[] = {
};
#endif
int aicwf_vendor_init(struct wiphy *wiphy)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
wiphy->vendor_commands = aicwf_vendor_cmd;
wiphy->n_vendor_commands = ARRAY_SIZE(aicwf_vendor_cmd);
wiphy->vendor_events = aicwf_vendor_events;
wiphy->n_vendor_events = ARRAY_SIZE(aicwf_vendor_events);
#endif
return 0;
}

View File

@ -25,6 +25,7 @@
#include "mach/jzmmc.h"
#endif /* CONFIG_INGENIC_T20 */
#include "aic_bsp_export.h"
#include "rwnx_wakelock.h"
extern uint8_t scanning;
int aicwf_sdio_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val)
@ -45,7 +46,7 @@ int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val)
return ret;
}
int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev)
int aicwf_sdio_flow_ctrl_msg(struct aic_sdio_dev *sdiodev)
{
int ret = -1;
u8 fc_reg = 0;
@ -69,9 +70,42 @@ int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev)
if (count < 30)
udelay(200);
else if (count < 40)
mdelay(1);
msleep(2);
else
mdelay(10);
msleep(10);
}
}
return ret;
}
int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev)
{
int ret = -1;
u8 fc_reg = 0;
u32 count = 0;
while (true) {
ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_FLOW_CTRL_REG, &fc_reg);
if (ret) {
return -1;
}
if ((fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG) > DATA_FLOW_CTRL_THRESH) {
ret = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG;
return ret;
} else {
if (count >= FLOW_CTRL_RETRY_COUNT) {
ret = -fc_reg;
break;
}
count++;
if (count < 30)
udelay(200);
else if (count < 40)
msleep(2);
else
msleep(10);
}
}
@ -110,8 +144,6 @@ int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf,
return ret;
}
static int wakeup_enable;
static u32 hostwake_irq_num;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
extern int sunxi_wlan_get_oob_irq(int *, int *);
#else
@ -119,23 +151,11 @@ extern int sunxi_wlan_get_oob_irq(void);
extern int sunxi_wlan_get_oob_irq_flags(void);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
static struct wakeup_source *ws;
#else
#include <linux/wakelock.h>
static struct wake_lock irq_wakelock;
#endif
static irqreturn_t rwnx_hostwake_irq_handler(int irq, void *para)
{
static int wake_cnt;
wake_cnt++;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
__pm_wakeup_event(ws, HZ / 20);
#else
wake_lock_timeout(&irq_wakelock, HZ / 20);
#endif
printk("%s(%d): wake_irq_cnt = %d\n", __func__, __LINE__, wake_cnt);
rwnx_wakeup_lock_timeout(g_rwnx_plat->sdiodev->rwnx_hw->ws_rx, jiffies_to_msecs(5));
return IRQ_HANDLED;
}
@ -143,6 +163,8 @@ static int rwnx_register_hostwake_irq(struct device *dev)
{
int ret = -1;
int irq_flags;
int wakeup_enable;
u32 hostwake_irq_num;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
hostwake_irq_num = sunxi_wlan_get_oob_irq(&irq_flags, &wakeup_enable);
#else
@ -152,11 +174,6 @@ static int rwnx_register_hostwake_irq(struct device *dev)
#endif
if (wakeup_enable) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
ws = wakeup_source_register(dev, "wifisleep");
#else
wake_lock_init(&irq_wakelock, WAKE_LOCK_SUSPEND, "wifisleep");
#endif
ret = device_init_wakeup(dev, true);
if (ret < 0) {
pr_err("%s(%d): device init wakeup failed!\n", __func__, __LINE__);
@ -178,7 +195,9 @@ static int rwnx_register_hostwake_irq(struct device *dev)
goto fail2;
}
}
disable_irq(hostwake_irq_num);
g_rwnx_plat->sdiodev->rwnx_hw->wakeup_enable = wakeup_enable;
g_rwnx_plat->sdiodev->rwnx_hw->hostwake_irq_num = hostwake_irq_num;
printk("%s(%d)\n", __func__, __LINE__);
return ret;
@ -186,44 +205,22 @@ fail2:
dev_pm_clear_wake_irq(dev);
fail1:
device_init_wakeup(dev, false);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
wakeup_source_unregister(ws);
#else
wake_lock_destroy(&irq_wakelock);
#endif
return ret;
}
static int rwnx_unregister_hostwake_irq(struct device *dev)
{
int wakeup_enable = g_rwnx_plat->sdiodev->rwnx_hw->wakeup_enable;
u32 hostwake_irq_num = g_rwnx_plat->sdiodev->rwnx_hw->hostwake_irq_num;
if (wakeup_enable) {
free_irq(hostwake_irq_num, NULL);
device_init_wakeup(dev, false);
dev_pm_clear_wake_irq(dev);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
wakeup_source_unregister(ws);
#else
wake_lock_destroy(&irq_wakelock);
#endif
}
free_irq(hostwake_irq_num, NULL);
printk("%s(%d)\n", __func__, __LINE__);
return 0;
}
static int rwnx_enable_hostwake_irq(void)
{
enable_irq(hostwake_irq_num);
printk("%s(%d)\n", __func__, __LINE__);
return 0;
}
static int rwnx_disable_hostwake_irq(void)
{
printk("%s(%d)\n", __func__, __LINE__);
disable_irq(hostwake_irq_num);
return 0;
}
static int aicwf_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@ -270,10 +267,11 @@ static int aicwf_sdio_probe(struct sdio_func *func,
host->caps |= MMC_CAP_NONREMOVABLE;
aicwf_rwnx_sdio_platform_init(sdiodev);
aicwf_hostif_ready();
err = rwnx_register_hostwake_irq(sdiodev->dev);
if (err != 0)
return err;
aicwf_hostif_fail();
else
aicwf_hostif_ready();
return 0;
fail:
aicwf_sdio_func_deinit(sdiodev);
@ -302,7 +300,6 @@ static void aicwf_sdio_remove(struct sdio_func *func)
if (!sdiodev) {
return;
}
rwnx_unregister_hostwake_irq(sdiodev->dev);
sdiodev->bus_if->state = BUS_DOWN_ST;
aicwf_sdio_release(sdiodev);
aicwf_sdio_func_deinit(sdiodev);
@ -342,7 +339,6 @@ static int aicwf_sdio_suspend(struct device *dev)
up(&sdiodev->tx_priv->txctl_sema);
break;
}
rwnx_enable_hostwake_irq();
return 0;
}
@ -354,23 +350,18 @@ static int aicwf_sdio_resume(struct device *dev)
struct rwnx_vif *rwnx_vif, *tmp;
sdio_dbg("%s\n", __func__);
rwnx_disable_hostwake_irq();
list_for_each_entry_safe(rwnx_vif, tmp, &sdiodev->rwnx_hw->vifs, list) {
if (rwnx_vif->ndev)
netif_device_attach(rwnx_vif->ndev);
}
aicwf_sdio_pwr_stctl(sdiodev, SDIO_ACTIVE_ST);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
__pm_relax(ws);
#else
wake_unlock(&irq_wakelock);
#endif
return 0;
}
static const struct sdio_device_id aicwf_sdmmc_ids[] = {
{SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN)},
{SDIO_DEVICE(0x5449, 0x0145)}, // 8800d in nomal mode
{SDIO_DEVICE(0xc8a1, 0xc08d)}, // 8800dc in nomal mode
{ },
};
@ -429,8 +420,10 @@ void aicwf_sdio_register(void)
void aicwf_sdio_exit(void)
{
if (g_rwnx_plat && g_rwnx_plat->enabled)
if (g_rwnx_plat && g_rwnx_plat->enabled) {
rwnx_unregister_hostwake_irq(g_rwnx_plat->sdiodev->dev);
rwnx_platform_deinit(g_rwnx_plat->sdiodev->rwnx_hw);
}
udelay(500);
sdio_unregister_driver(&aicwf_sdio_driver);
@ -662,10 +655,10 @@ static int aicwf_sdio_tx_msg(struct aic_sdio_dev *sdiodev)
} else
len = payload_len;
buffer_cnt = aicwf_sdio_flow_ctrl(sdiodev);
buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
while ((buffer_cnt <= 0 || (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && retry < 10) {
retry++;
buffer_cnt = aicwf_sdio_flow_ctrl(sdiodev);
buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
printk("buffer_cnt = %d\n", buffer_cnt);
}
@ -765,7 +758,11 @@ static int aicwf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
prio = (pkt->priority & 0x7);
spin_lock_bh(&sdiodev->tx_priv->txqlock);
if (!aicwf_frame_enq(sdiodev->dev, &sdiodev->tx_priv->txq, pkt, prio)) {
aicwf_dev_skb_free(pkt);
struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data;
int headroom = txhdr->sw_hdr->headroom;
kmem_cache_free(txhdr->sw_hdr->rwnx_vif->rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
skb_pull(pkt, headroom);
consume_skb(pkt);
spin_unlock_bh(&sdiodev->tx_priv->txqlock);
return -ENOSR;
} else {
@ -780,7 +777,8 @@ static int aicwf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
atomic_inc(&sdiodev->tx_priv->tx_pktcnt);
spin_unlock_bh(&sdiodev->tx_priv->txqlock);
complete(&bus_if->bustx_trgg);
if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) == 1)
complete(&bus_if->bustx_trgg);
return ret;
}
@ -1023,8 +1021,13 @@ int sdio_bustx_thread(void *data)
if (sdiodev->bus_if->state == BUS_DOWN_ST)
continue;
if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > 0) || (sdiodev->tx_priv->cmd_txstate == true))
rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_tx);
while ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > 0) || (sdiodev->tx_priv->cmd_txstate == true)) {
aicwf_sdio_tx_process(sdiodev);
if (sdiodev->bus_if->state == BUS_DOWN_ST)
break;
}
rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_tx);
}
}
@ -1035,6 +1038,7 @@ int sdio_busrx_thread(void *data)
{
struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data;
struct aicwf_bus *bus_if = rx_priv->sdiodev->bus_if;
struct aic_sdio_dev *sdiodev = rx_priv->sdiodev;
while (1) {
if (kthread_should_stop()) {
@ -1044,7 +1048,9 @@ int sdio_busrx_thread(void *data)
if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) {
if (bus_if->state == BUS_DOWN_ST)
continue;
rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_rx);
aicwf_process_rxframes(rx_priv);
rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_rx);
}
}
@ -1063,11 +1069,14 @@ static int aicwf_sdio_pwrctl_thread(void *data)
if (!wait_for_completion_interruptible(&sdiodev->pwrctrl_trgg)) {
if (sdiodev->bus_if->state == BUS_DOWN_ST)
continue;
rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_pwrctrl);
if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) <= 0) && (sdiodev->tx_priv->cmd_txstate == false) && \
atomic_read(&sdiodev->rx_priv->rx_cnt) == 0)
aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST);
else
aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_pwrctrl);
}
}
@ -1123,6 +1132,7 @@ void aicwf_sdio_hal_irqhandler(struct sdio_func *func)
u8 byte_len = 0;
struct sk_buff *pkt = NULL;
int ret;
int retry = 10;
if (!bus_if || bus_if->state == BUS_DOWN_ST) {
sdio_err("bus err\n");
@ -1133,6 +1143,8 @@ void aicwf_sdio_hal_irqhandler(struct sdio_func *func)
while (ret || (intstatus & SDIO_OTHER_INTERRUPT)) {
sdio_err("ret=%d, intstatus=%x\r\n", ret, intstatus);
ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_BLOCK_CNT_REG, &intstatus);
if (retry-- <= 0)
break;
}
sdiodev->rx_priv->data_len = intstatus * SDIOWIFI_FUNC_BLOCKSIZE;
@ -1281,7 +1293,7 @@ int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev)
return ret;
}
mdelay(2);
mdelay(5);
ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
if (ret < 0) {
sdio_err("reg:%d read failed!\n", SDIOWIFI_SLEEP_REG);

View File

@ -78,6 +78,7 @@ int aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target);
int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev);
void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_flow_ctrl_msg(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, u32 size);
int aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count);
void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev);

View File

@ -25,10 +25,12 @@
#ifdef AICWF_SDIO_SUPPORT
#include "sdio_host.h"
#endif
#include "aic_bsp_export.h"
int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
{
int ret = 0;
int errnum = 0;
struct aicwf_bus *bus_if;
if (!dev) {
@ -56,14 +58,16 @@ int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
#endif
if (IS_ERR(bus_if->bustx_thread)) {
errnum = PTR_ERR(bus_if->bustx_thread);
bus_if->bustx_thread = NULL;
txrx_err("aicwf_bustx_thread run fail\n");
txrx_err("aicwf_bustx_thread run fail, errnum is %d\n", errnum);
goto fail;
}
if (IS_ERR(bus_if->busrx_thread)) {
errnum = PTR_ERR(bus_if->busrx_thread);
bus_if->busrx_thread = NULL;
txrx_err("aicwf_bustx_thread run fail\n");
txrx_err("aicwf_busrx_thread run fail, errnum is %d\n", errnum);
goto fail;
}
@ -109,7 +113,7 @@ void aicwf_bus_deinit(struct device *dev)
bus_if->cmd_buf = NULL;
}
if (bus_if->bustx_thread) {
if (!IS_ERR_OR_NULL(bus_if->bustx_thread)) {
complete_all(&bus_if->bustx_trgg);
kthread_stop(bus_if->bustx_thread);
bus_if->bustx_thread = NULL;
@ -150,7 +154,11 @@ struct aicwf_tx_priv *aicwf_tx_init(void *arg)
#endif
atomic_set(&tx_priv->aggr_count, 0);
#ifdef AICBSP_RESV_MEM_SUPPORT
tx_priv->aggr_buf = aicbsp_resv_mem_alloc_skb(MAX_AGGR_TXPKT_LEN, AIC_RESV_MEM_TXDATA);
#else
tx_priv->aggr_buf = dev_alloc_skb(MAX_AGGR_TXPKT_LEN);
#endif
if (!tx_priv->aggr_buf) {
txrx_err("Alloc bus->txdata_buf failed!\n");
kfree(tx_priv);
@ -165,7 +173,11 @@ struct aicwf_tx_priv *aicwf_tx_init(void *arg)
void aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv)
{
if (tx_priv && tx_priv->aggr_buf) {
#ifdef AICBSP_RESV_MEM_SUPPORT
aicbsp_resv_mem_kfree_skb(tx_priv->aggr_buf, AIC_RESV_MEM_TXDATA);
#else
dev_kfree_skb(tx_priv->aggr_buf);
#endif
kfree(tx_priv);
}
}
@ -358,6 +370,7 @@ int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv)
skb_put(skb_inblock, aggr_len);
memcpy(skb_inblock->data, data, aggr_len);
aicwf_count_rx_tp(rx_priv, aggr_len);
rwnx_rxdataind_aicwf(rx_priv->usbdev->rwnx_hw, skb_inblock, (void *)rx_priv);
///TODO: here need to add rx data process
@ -462,23 +475,25 @@ void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv)
struct reord_ctrl_info *reord_info, *tmp;
txrx_dbg("%s\n", __func__);
spin_lock_bh(&rx_priv->stas_reord_lock);
list_for_each_entry_safe(reord_info, tmp,
&rx_priv->stas_reord_list, list) {
reord_deinit_sta(rx_priv, reord_info);
}
spin_unlock_bh(&rx_priv->stas_reord_lock);
#endif
#ifdef AICWF_SDIO_SUPPORT
txrx_dbg("sdio rx thread\n");
if (rx_priv->sdiodev->bus_if->busrx_thread) {
if (!IS_ERR_OR_NULL(rx_priv->sdiodev->bus_if->busrx_thread)) {
complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg);
kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread);
rx_priv->sdiodev->bus_if->busrx_thread = NULL;
}
#endif
#ifdef AICWF_USB_SUPPORT
if (rx_priv->usbdev->bus_if->busrx_thread) {
txrx_dbg("usb rx thread\n");
if (!IS_ERR_OR_NULL(rx_priv->usbdev->bus_if->busrx_thread)) {
complete_all(&rx_priv->usbdev->bus_if->busrx_trgg);
kthread_stop(rx_priv->usbdev->bus_if->busrx_thread);
rx_priv->usbdev->bus_if->busrx_thread = NULL;
@ -608,48 +623,13 @@ struct sk_buff *aicwf_frame_dequeue(struct frame_queue *pq)
return p;
}
static struct sk_buff *aicwf_skb_dequeue_tail(struct frame_queue *pq, int prio)
{
struct sk_buff_head *q = &pq->queuelist[prio];
struct sk_buff *p = skb_dequeue_tail(q);
if (!p)
return NULL;
pq->qcnt--;
return p;
}
bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio)
{
struct sk_buff *p = NULL;
int prio_modified = -1;
if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) {
aicwf_frame_queue_penq(q, prio, pkt);
return true;
}
if (q->queuelist[prio].qlen >= q->qmax) {
prio_modified = prio;
} else if (q->qcnt >= q->qmax) {
p = aicwf_frame_queue_peek_tail(q, &prio_modified);
if (prio_modified > prio)
return false;
}
if (prio_modified >= 0) {
if (prio_modified == prio)
return false;
p = aicwf_skb_dequeue_tail(q, prio_modified);
aicwf_dev_skb_free(p);
p = aicwf_frame_queue_penq(q, prio_modified, pkt);
if (p == NULL)
txrx_err("failed\n");
}
return p != NULL;
} else
return false;
}

View File

@ -14,6 +14,7 @@
#include "rwnx_defs.h"
#include "usb_host.h"
#include "rwnx_platform.h"
#include "rwnx_wakelock.h"
void aicwf_usb_tx_flowctrl(struct rwnx_hw *rwnx_hw, bool state)
{
@ -153,6 +154,7 @@ static void aicwf_usb_rx_complete(struct urb *urb)
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
usb_err("rx_priv->rxq is over flow!!!\n");
aicwf_dev_skb_free(skb);
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
return;
}
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
@ -297,8 +299,10 @@ int usb_bustx_thread(void *data)
if (!wait_for_completion_interruptible(&bus->bustx_trgg)) {
if (usbdev->bus_if->state == BUS_DOWN_ST)
continue;
rwnx_wakeup_lock(usbdev->rwnx_hw->ws_tx);
if (usbdev->tx_post_count > 0)
aicwf_usb_tx_process(usbdev);
rwnx_wakeup_unlock(usbdev->rwnx_hw->ws_tx);
}
}
@ -309,6 +313,7 @@ int usb_busrx_thread(void *data)
{
struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data;
struct aicwf_bus *bus_if = rx_priv->usbdev->bus_if;
struct aic_usb_dev *usbdev = rx_priv->usbdev;
while (1) {
if (kthread_should_stop()) {
@ -318,7 +323,9 @@ int usb_busrx_thread(void *data)
if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) {
if (bus_if->state == BUS_DOWN_ST)
continue;
rwnx_wakeup_lock(usbdev->rwnx_hw->ws_rx);
aicwf_process_rxframes(rx_priv);
rwnx_wakeup_unlock(usbdev->rwnx_hw->ws_rx);
}
}
@ -556,7 +563,7 @@ static int aicwf_usb_bus_txdata(struct device *dev, struct sk_buff *skb)
complete(&bus_if->bustx_trgg);
ret = 0;
flow_ctrl:
flow_ctrl:
spin_lock_irqsave(&usb_dev->tx_flow_lock, flags);
if (usb_dev->tx_free_count < AICWF_USB_TX_LOW_WATER) {
usb_dev->tbusy = true;
@ -781,8 +788,6 @@ static int aicwf_parse_usb(struct aic_usb_dev *usb_dev, struct usb_interface *in
return ret;
}
static struct aicwf_bus_ops aicwf_usb_bus_ops = {
.start = aicwf_usb_bus_start,
.stop = aicwf_usb_bus_stop,

View File

@ -129,19 +129,10 @@
// c.f LMAC/src/tx/tx_swdesc.h
/// Descriptor filled by the Host
struct hostdesc {
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
/// Pointers to packet payloads
u32_l packet_addr[NX_TX_PAYLOAD_MAX];
/// Sizes of the MPDU/MSDU payloads
u16_l packet_len[NX_TX_PAYLOAD_MAX];
/// Number of payloads forming the MPDU
u8_l packet_cnt;
#else
/// Pointer to packet payload
u32_l packet_addr;
/// Size of the payload
u16_l packet_len;
#endif //(NX_AMSDU_TX)
u16_l flags_ext;
#ifdef CONFIG_RWNX_FULLMAC
/// Address of the status descriptor in host memory (used for confirmation upload)
@ -152,12 +143,6 @@ struct hostdesc {
struct mac_addr eth_src_addr;
/// Ethernet Type
u16_l ethertype;
/// Buffer containing the PN to be used for this packet
u16_l pn[4];
/// Sequence Number used for transmission of this MPDU
u16_l sn;
/// Timestamp of first transmission of this MPDU
u16_l timestamp;
#else /* ! CONFIG_RWNX_FULLMAC */
#ifdef CONFIG_RWNX_AGG_TX
///Sequence Number for AMPDU MPDUs - for quick check if it's allowed within window
@ -166,6 +151,7 @@ struct hostdesc {
/// Padding between the buffer control structure and the MPDU in host memory
u8_l padding;
#endif /* CONFIG_RWNX_FULLMAC */
u8_l ac;
/// Packet TID (0xFF if not a QoS frame)
u8_l tid;
/// Interface Id

View File

@ -434,6 +434,12 @@ enum mac_connection_flags {
REASSOCIATION = BIT(5),
};
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
#include <linux/ieee80211.h>
#else
#define CONFIG_HE_FOR_OLD_KERNEL 1
#endif
#ifdef CONFIG_HE_FOR_OLD_KERNEL
#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02
@ -465,9 +471,6 @@ enum mac_connection_flags {
#define IEEE80211_HE_PPE_THRES_MAX_LEN 25
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
#include <linux/ieee80211.h>
#else
struct ieee80211_he_cap_elem {
u8 mac_cap_info[6];
u8 phy_cap_info[11];
@ -495,5 +498,4 @@ struct ieee80211_sband_iftype_data {
};
#endif
#endif
#endif // LMAC_MAC_H_

View File

@ -364,8 +364,8 @@ enum mm_msg_tag {
MM_GET_STA_INFO_REQ,
MM_GET_STA_INFO_CFM,
MM_SET_TXPWR_IDX_REQ,
MM_SET_TXPWR_IDX_CFM,
MM_SET_TXPWR_IDX_LVL_REQ,
MM_SET_TXPWR_IDX_LVL_CFM,
MM_SET_TXPWR_OFST_REQ,
MM_SET_TXPWR_OFST_CFM,
@ -1209,6 +1209,20 @@ struct mm_set_txpwr_idx_req {
txpwr_idx_conf_t txpwr_idx;
};
typedef struct {
u8_l enable;
s8_l pwrlvl_11b_11ag_2g4[12];
s8_l pwrlvl_11n_11ac_2g4[10];
s8_l pwrlvl_11ax_2g4[12];
} txpwr_lvl_conf_v2_t;
struct mm_set_txpwr_lvl_req {
union {
txpwr_idx_conf_t txpwr_lvl;
txpwr_lvl_conf_v2_t txpwr_lvl_v2;
};
};
typedef struct {
u8_l enable;
s8_l chan_1_4;
@ -1220,6 +1234,12 @@ typedef struct {
s8_l chan_142_165;
} txpwr_ofst_conf_t;
typedef struct {
u8_l enable;
u8_l xtal_cap;
u8_l xtal_cap_fine;
} xtal_cap_conf_t;
struct mm_set_txpwr_ofst_req {
txpwr_ofst_conf_t txpwr_ofst;
};

View File

@ -16,7 +16,7 @@
#include "rwnx_cmds.h"
#include "rwnx_defs.h"
#include "rwnx_strs.h"
#define CREATE_TRACE_POINTS
//#define CREATE_TRACE_POINTS
#include "rwnx_events.h"
#include "aicwf_txrxif.h"
#ifdef AICWF_SDIO_SUPPORT
@ -29,6 +29,37 @@
*/
extern int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
static int rwnx_exception_event(struct rwnx_cmd_mgr *cmd_mgr)
{
#if defined(AICWF_SDIO_SUPPORT)
struct aic_sdio_dev *pdev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
#elif defined(AICWF_USB_SUPPORT)
struct aic_usb_dev *pdev = container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr);
#else
struct aic_usb_dev *pdev = NULL;
#endif
static bool need_send = true;
char *envp[] = {
"SYSTEM=WIFI",
"EVENT=EXCEPTION",
"SUBEVENT=FW_CRASH",
NULL};
if (!need_send)
return 0;
if (pdev) {
kobject_uevent_env(&pdev->dev->kobj, KOBJ_CHANGE, envp);
need_send = true;
printk(KERN_CRIT "%s send exception uevent to userspace", __func__);
return 0;
}
return -1;
}
static void cmd_dump(const struct rwnx_cmd *cmd)
{
printk(KERN_CRIT "tkn[%d] flags:%04x result:%3d cmd:%4d-%-24s - reqcfm(%4d-%-s)\n",
@ -63,8 +94,9 @@ int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd
bool defer_push = false;
RWNX_DBG(RWNX_FN_ENTRY_STR);
#ifdef CREATE_TRACE_POINTS
trace_msg_send(cmd->id);
#endif
spin_lock_bh(&cmd_mgr->lock);
if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
@ -118,8 +150,9 @@ static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
bool defer_push = false;
//RWNX_DBG(RWNX_FN_ENTRY_STR);
#ifdef CREATE_TRACE_POINTS
trace_msg_send(cmd->id);
#endif
spin_lock_bh(&cmd_mgr->lock);
if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
@ -225,6 +258,7 @@ static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
cmd_complete(cmd_mgr, cmd);
}
spin_unlock_bh(&cmd_mgr->lock);
rwnx_exception_event(cmd_mgr);
} else {
kfree(cmd);
if (!list_empty(&cmd_mgr->cmds))
@ -341,6 +375,7 @@ void cmd_mgr_task_process(struct work_struct *work)
cmd_complete(cmd_mgr, next);
}
spin_unlock_bh(&cmd_mgr->lock);
rwnx_exception_event(cmd_mgr);
} else
kfree(next);
}
@ -358,9 +393,9 @@ static int cmd_mgr_run_callback(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd,
return 0;
}
//RWNX_DBG(RWNX_FN_ENTRY_STR);
spin_lock_bh(&rwnx_hw->cb_lock);
//spin_lock_bh(&rwnx_hw->cb_lock);
res = cb(rwnx_hw, cmd, msg);
spin_unlock_bh(&rwnx_hw->cb_lock);
//spin_unlock_bh(&rwnx_hw->cb_lock);
return res;
}
@ -384,8 +419,9 @@ static int cmd_mgr_msgind(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd_e2amsg *
bool found = false;
// RWNX_DBG(RWNX_FN_ENTRY_STR);
#ifdef CREATE_TRACE_POINTS
trace_msg_recv(msg->id);
#endif
//printk("cmd->id=%x\n", msg->id);
spin_lock_bh(&cmd_mgr->lock);
list_for_each_entry(cmd, &cmd_mgr->cmds, list) {

View File

@ -1225,6 +1225,34 @@ static ssize_t rwnx_dbgfs_set_write(struct file *file,
DEBUGFS_READ_WRITE_FILE_OPS(set);
#endif /* CONFIG_RWNX_RADAR */
static ssize_t rwnx_dbgfs_regdbg_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
char buf[32];
u32 addr, val, oper;
size_t len = min_t(size_t, count, sizeof(buf) - 1);
struct dbg_mem_read_cfm mem_read_cfm;
int ret;
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (sscanf(buf, "%x %x %x", &oper, &addr, &val) > 0)
printk("addr=%x, val=%x,oper=%d\n", addr, val, oper);
if (oper == 0) {
ret = rwnx_send_dbg_mem_read_req(priv, addr, &mem_read_cfm);
printk("[0x%x] = [0x%x]\n", mem_read_cfm.memaddr, mem_read_cfm.memdata);
}
return count;
}
DEBUGFS_WRITE_FILE_OPS(regdbg);
#ifdef CONFIG_RWNX_FULLMAC
#define LINE_MAX_SZ 150

View File

@ -126,6 +126,13 @@ struct rwnx_csa {
struct work_struct work;
};
struct apm_probe_sta {
u8 sta_mac_addr[6];
u8 vif_idx;
u64 probe_id;
struct work_struct apmprobestaWork;
struct workqueue_struct *apmprobesta_wq;
};
/// Possible States of the TDLS link.
enum tdls_status_tag {
/// TDLS link is not active (no TDLS peer connected)
@ -229,6 +236,7 @@ struct rwnx_vif {
u8_l key_has_add;
u8_l is_p2p_vif;
struct apm_probe_sta sta_probe;
};
#define RWNX_VIF_TYPE(rwnx_vif) (rwnx_vif->wdev.iftype)
@ -508,6 +516,8 @@ struct rwnx_hw {
bool band_5g_support;
u8_l vendor_info;
bool fwlog_en;
u16 chipid;
u8 cpmode;
struct list_head defrag_list;
spinlock_t defrag_lock;
@ -516,6 +526,13 @@ struct rwnx_hw {
struct workqueue_struct *apmStaloss_wq;
u8 apm_vif_idx;
u8 sta_mac_addr[6];
struct wakeup_source *ws_rx;
struct wakeup_source *ws_tx;
struct wakeup_source *ws_pwrctrl;
u8 wakeup_enable;
u32 hostwake_irq_num;
};
u8 *rwnx_build_bcn(struct rwnx_bcn *bcn, struct cfg80211_beacon_data *new);

View File

@ -48,6 +48,7 @@
#include "aicwf_usb.h"
#endif
#include "aic_bsp_export.h"
#include "rwnx_wakelock.h"
#define RW_DRV_DESCRIPTION "RivieraWaves 11nac driver for Linux cfg80211"
#define RW_DRV_COPYRIGHT "Copyright(c) 2015-2017 RivieraWaves"
@ -687,18 +688,48 @@ static void rwnx_del_csa(struct rwnx_vif *vif)
kfree(csa);
vif->ap.csa = NULL;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
static void rwnx_csa_finish(struct work_struct *ws)
{
struct rwnx_csa *csa = container_of(ws, struct rwnx_csa, work);
struct rwnx_vif *vif = csa->vif;
struct rwnx_hw *rwnx_hw = vif->rwnx_hw;
int error = csa->status;
u8 *buf, *pos;
if (!error)
RWNX_DBG(RWNX_FN_ENTRY_STR);
buf = kmalloc(csa->bcn.len, GFP_KERNEL);
if (!buf) {
printk ("%s buf fail\n", __func__);
return;
}
pos = buf;
memcpy(pos, csa->bcn.head, csa->bcn.head_len);
pos += csa->bcn.head_len;
*pos++ = WLAN_EID_TIM;
*pos++ = 4;
*pos++ = 0;
*pos++ = csa->bcn.dtim;
*pos++ = 0;
*pos++ = 0;
if (csa->bcn.tail) {
memcpy(pos, csa->bcn.tail, csa->bcn.tail_len);
pos += csa->bcn.tail_len;
}
if (csa->bcn.ies) {
memcpy(pos, csa->bcn.ies, csa->bcn.ies_len);
}
if (!error) {
error = rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, csa->bcn.len);
if (error)
return;
error = rwnx_send_bcn_change(rwnx_hw, vif->vif_index, 0,
csa->bcn.len, csa->bcn.head_len,
csa->bcn.tim_len, NULL);
}
if (error) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
@ -724,6 +755,7 @@ static void rwnx_csa_finish(struct work_struct *ws)
}
rwnx_del_csa(vif);
}
#endif
/**
* rwnx_external_auth_enable - Enable external authentication on a vif
@ -1601,7 +1633,7 @@ int handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
} else {
printk("wrong args\n");
}
} else if (strcasecmp(argv[0], "SETSUSPENDMODE") == 0) {
} else if (strcasecmp(argv[0], "SETSUSPENDMODE") == 0 && g_rwnx_plat->sdiodev->rwnx_hw->cpmode != AICBSP_CPMODE_TEST) {
#ifdef AICWF_SDIO_SUPPORT
setsusp_mode = command_strtoul(argv[1], NULL, 10);
rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, setsusp_mode);
@ -2345,7 +2377,6 @@ static int rwnx_cfg80211_change_iface(struct wiphy *wiphy,
if (type == NL80211_IFTYPE_P2P_CLIENT || type == NL80211_IFTYPE_P2P_GO)
p2p = true;
if (type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_P2P_GO) {
if (vif->up) {
/* Abort scan request on the vif */
if (vif->rwnx_hw->scan_request &&
@ -2388,7 +2419,6 @@ static int rwnx_cfg80211_change_iface(struct wiphy *wiphy,
vif->vif_index = add_if_cfm.inst_nbr;
vif->rwnx_hw->vif_table[add_if_cfm.inst_nbr] = vif;
spin_unlock_bh(&vif->rwnx_hw->cb_lock);
}
}
return 0;
}
@ -2465,6 +2495,9 @@ static int rwnx_cfg80211_scan(struct wiphy *wiphy,
RWNX_DBG(RWNX_FN_ENTRY_STR);
if (rwnx_hw->cpmode == AICBSP_CPMODE_TEST)
return -EBUSY;
if (scanning) {
printk("is scanning, abort\n");
error = rwnx_send_scanu_cancel_req(rwnx_hw, NULL);
@ -2473,12 +2506,11 @@ static int rwnx_cfg80211_scan(struct wiphy *wiphy,
msleep(150);
}
rwnx_hw->scan_request = request;
error = rwnx_send_scanu_req(rwnx_hw, rwnx_vif, request);
if (error)
return error;
rwnx_hw->scan_request = request;
return 0;
}
@ -2703,7 +2735,7 @@ static int rwnx_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
key_params.cipher = sme->crypto.cipher_group;
rwnx_cfg80211_add_key(wiphy, dev, sme->key_idx, false, NULL, &key_params);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
else if ((sme->auth_type == NL80211_AUTHTYPE_SAE) &&
!(sme->flags & CONNECT_REQ_EXTERNAL_AUTH_SUPPORT)) {
netdev_err(dev, "Doesn't support SAE without external authentication\n");
@ -2759,7 +2791,7 @@ static int rwnx_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
return rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, reason_code);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
/**
* @external_auth: indicates result of offloaded authentication processing from
* user space
@ -2965,6 +2997,7 @@ static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy,
macaddr = cur->mac_addr;
printk("deinit:macaddr:%x,%x,%x,%x,%x,%x\r\n", macaddr[0], macaddr[1], macaddr[2], \
macaddr[3], macaddr[4], macaddr[5]);
spin_lock_bh(&rx_priv->stas_reord_lock);
list_for_each_entry_safe(reord_info, reord_tmp,
&rx_priv->stas_reord_list, list) {
printk("reord_mac:%x,%x,%x,%x,%x,%x\r\n", reord_info->mac_addr[0], reord_info->mac_addr[1], reord_info->mac_addr[2], \
@ -2974,6 +3007,7 @@ static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy,
break;
}
}
spin_unlock_bh(&rx_priv->stas_reord_lock);
}
#endif
@ -2992,7 +3026,7 @@ static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy,
#ifdef CONFIG_DEBUG_FS
rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur);
#endif
found++;
found = true;
break;
}
}
@ -3056,9 +3090,9 @@ void apm_staloss_work_process(struct work_struct *work)
}
}
}
if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP || rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
/*if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP || rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
cfg80211_del_sta(rwnx_vif->ndev, cur->mac_addr, GFP_KERNEL);
}
}*/
#ifdef AICWF_RX_REORDER
#ifdef AICWF_SDIO_SUPPORT
@ -3072,6 +3106,7 @@ void apm_staloss_work_process(struct work_struct *work)
macaddr = cur->mac_addr;
printk("deinit:macaddr:%x,%x,%x,%x,%x,%x\r\n", macaddr[0], macaddr[1], macaddr[2], \
macaddr[3], macaddr[4], macaddr[5]);
spin_lock_bh(&rx_priv->stas_reord_lock);
list_for_each_entry_safe(reord_info, reord_tmp,
&rx_priv->stas_reord_list, list) {
printk("reord_mac:%x,%x,%x,%x,%x,%x\r\n", reord_info->mac_addr[0], reord_info->mac_addr[1], reord_info->mac_addr[2], \
@ -3081,6 +3116,7 @@ void apm_staloss_work_process(struct work_struct *work)
break;
}
}
spin_unlock_bh(&rx_priv->stas_reord_lock);
}
#endif
@ -3110,7 +3146,39 @@ void apm_staloss_work_process(struct work_struct *work)
rwnx_update_mesh_power_mode(rwnx_vif);
}
void apm_probe_sta_work_process(struct work_struct *work)
{
struct apm_probe_sta *probe_sta = container_of(work, struct apm_probe_sta, apmprobestaWork);
struct rwnx_vif *rwnx_vif = container_of(probe_sta, struct rwnx_vif, sta_probe);
bool found = false;
struct rwnx_sta *cur, *tmp;
u8 *mac = rwnx_vif->sta_probe.sta_mac_addr;
RWNX_DBG(RWNX_FN_ENTRY_STR);
list_for_each_entry_safe(cur, tmp, &rwnx_vif->ap.sta_list, list) {
if (!memcmp(cur->mac_addr, mac, ETH_ALEN)) {
found = true;
break;
}
}
printk("sta %pM found = %d\n", mac, found);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
if (found)
cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 1, 0, false, GFP_ATOMIC);
else
cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 0, 0, false, GFP_ATOMIC);
#else
if (found)
cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 1, GFP_ATOMIC);
else
cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 0, GFP_ATOMIC);
#endif
rwnx_vif->sta_probe.probe_id++;
}
/**
* @change_station: Modify a given station. Note that flags changes are not much
* validated in cfg80211, in particular the auth/assoc/authorized flags
@ -3281,6 +3349,12 @@ static int rwnx_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
RWNX_DBG(RWNX_FN_ENTRY_STR);
INIT_WORK(&rwnx_vif->sta_probe.apmprobestaWork, apm_probe_sta_work_process);
rwnx_vif->sta_probe.apmprobesta_wq = create_singlethread_workqueue("apmprobe_wq");
if (!rwnx_vif->sta_probe.apmprobesta_wq) {
txrx_err("insufficient memory to create apmprobe_wq.\n");
return -ENOBUFS;
}
if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)
rwnx_hw->is_p2p_connected = 1;
/* Forward the information to the LMAC */
@ -3412,6 +3486,9 @@ static int rwnx_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
rwnx_del_bcn(&rwnx_vif->ap.bcn);
rwnx_del_csa(rwnx_vif);
flush_workqueue(rwnx_vif->sta_probe.apmprobesta_wq);
destroy_workqueue(rwnx_vif->sta_probe.apmprobesta_wq);
netif_tx_stop_all_queues(dev);
netif_carrier_off(dev);
@ -3489,6 +3566,29 @@ static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy,
int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u64 *cookie)
{
//struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
struct rwnx_vif *vif = netdev_priv(dev);
struct rwnx_sta *sta = NULL;
RWNX_DBG(RWNX_FN_ENTRY_STR);
if ((RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_AP) && (RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_P2P_GO) &&
(RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_AP_VLAN))
return -EINVAL;
list_for_each_entry(sta, &vif->ap.sta_list, list) {
if (sta->valid && ether_addr_equal(sta->mac_addr, peer))
break;
}
if (!sta)
return -ENOENT;
memcpy(vif->sta_probe.sta_mac_addr, peer, 6);
queue_work(vif->sta_probe.apmprobesta_wq, &vif->sta_probe.apmprobestaWork);
*cookie = vif->sta_probe.probe_id;
return 0;
}
@ -3639,8 +3739,9 @@ rwnx_cfg80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* For debug purpose (use ftrace kernel option) */
#ifdef CREATE_TRACE_POINTS
trace_roc(rwnx_vif->vif_index, chan->center_freq, duration);
#endif
/* Check that no other RoC procedure has been launched */
if (rwnx_hw->roc_elem) {
msleep(2);
@ -3731,13 +3832,15 @@ static int rwnx_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
u64 cookie)
{
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
#ifdef CREATE_TRACE_POINTS
struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev);//netdev_priv(wdev->netdev);
#endif
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* For debug purpose (use ftrace kernel option) */
#ifdef CREATE_TRACE_POINTS
trace_cancel_roc(rwnx_vif->vif_index);
#endif
/* Check if a RoC procedure is pending */
if (!rwnx_hw->roc_elem) {
return 0;
@ -3885,11 +3988,11 @@ static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
/* Get STA on which management frame has to be sent */
rwnx_sta = rwnx_retrieve_sta(rwnx_hw, rwnx_vif, mgmt->da,
mgmt->frame_control, ap);
#ifdef CREATE_TRACE_POINTS
trace_mgmt_tx((channel) ? channel->center_freq : 0,
rwnx_vif->vif_index, (rwnx_sta) ? rwnx_sta->sta_idx : 0xFF,
mgmt);
#endif
if (ap || rwnx_sta)
goto send_frame;
@ -4098,7 +4201,11 @@ int rwnx_cfg80211_channel_switch (struct wiphy *wiphy,
goto end;
} else {
INIT_WORK(&csa->work, rwnx_csa_finish);
rwnx_cfg80211_ch_switch_started_notify(dev, &csa->chandef, params->count);
rwnx_cfg80211_ch_switch_started_notify(dev, &csa->chandef, params->count
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
, params->block_tx
#endif
);
}
end:
@ -4471,7 +4578,8 @@ static int rwnx_fill_station_info(struct rwnx_sta *sta, struct rwnx_vif *vif,
case FORMATMOD_HE_SU:
case FORMATMOD_HE_ER:
sinfo->rxrate.flags = RATE_INFO_FLAGS_VHT_MCS;
sinfo->rxrate.mcs = rx_vect1->he.mcs;
sinfo->rxrate.mcs = rx_vect1->he.mcs;
break;
#endif
default:
return -EINVAL;
@ -4527,7 +4635,7 @@ static int rwnx_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev
if (sta)
return rwnx_fill_station_info(sta, vif, sinfo);
return -EINVAL;
return -ENOENT;
}
@ -5031,7 +5139,7 @@ static struct cfg80211_ops rwnx_cfg80211_ops = {
.tdls_mgmt = rwnx_cfg80211_tdls_mgmt,
.tdls_oper = rwnx_cfg80211_tdls_oper,
.change_bss = rwnx_cfg80211_change_bss,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
.external_auth = rwnx_cfg80211_external_auth,
#endif
};
@ -5122,7 +5230,6 @@ static const struct wiphy_wowlan_support aic_wowlan_support = {
*
*/
extern int aicwf_vendor_init(struct wiphy *wiphy);
extern txpwr_idx_conf_t nvram_txpwr_idx;
int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data)
{
@ -5158,6 +5265,7 @@ int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data)
rwnx_hw->wiphy = wiphy;
rwnx_hw->plat = rwnx_plat;
rwnx_hw->dev = rwnx_platform_get_dev(rwnx_plat);
rwnx_hw->chipid = feature.chipinfo->chipid;
#ifdef AICWF_SDIO_SUPPORT
rwnx_hw->sdiodev = rwnx_plat->sdiodev;
rwnx_plat->sdiodev->rwnx_hw = rwnx_hw;
@ -5170,6 +5278,7 @@ int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data)
rwnx_hw->mod_params = &rwnx_mod_params;
rwnx_hw->tcp_pacing_shift = 7;
aicwf_wakeup_lock_init(rwnx_hw);
rwnx_init_aic(rwnx_hw);
/* set device pointer for wiphy */
set_wiphy_dev(wiphy, rwnx_hw->dev);
@ -5232,6 +5341,7 @@ int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data)
wiphy->mgmt_stypes = rwnx_default_mgmt_stypes;
rwnx_hw->fwlog_en = feature.fwlog_en;
rwnx_hw->cpmode = feature.cpmode;
ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, feature.hwinfo < 0, feature.hwinfo, feature.fwlog_en, &set_start_cfm);
if (ret)
goto err_lmac_reqs;
@ -5285,7 +5395,7 @@ int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data)
#endif
0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
wiphy->features |= NL80211_FEATURE_SAE;
#endif
@ -5450,6 +5560,7 @@ err_platon:
//err_config:
kmem_cache_destroy(rwnx_hw->sw_txhdr_cache);
err_cache:
aicwf_wakeup_lock_deinit(rwnx_hw);
wiphy_free(wiphy);
err_out:
return ret;
@ -5495,6 +5606,7 @@ void rwnx_cfg80211_deinit(struct rwnx_hw *rwnx_hw)
rwnx_radar_detection_deinit(&rwnx_hw->radar);
rwnx_platform_off(rwnx_hw, NULL);
kmem_cache_destroy(rwnx_hw->sw_txhdr_cache);
aicwf_wakeup_lock_deinit(rwnx_hw);
wiphy_free(rwnx_hw->wiphy);
}
@ -5551,6 +5663,7 @@ static int __init rwnx_mod_init(void)
#ifdef AICWF_USB_SUPPORT
aicwf_usb_exit();
#endif /*AICWF_USB_SUPPORT */
aicbsp_set_subsys(AIC_WIFI, AIC_PWR_OFF);
return -ENODEV;
}

View File

@ -33,7 +33,7 @@ struct rwnx_mod_params rwnx_mod_params = {
COMMON_PARAM(vht_on, true, true)
COMMON_PARAM(he_on, true, true)
COMMON_PARAM(mcs_map, IEEE80211_VHT_MCS_SUPPORT_0_9, IEEE80211_VHT_MCS_SUPPORT_0_9)
COMMON_PARAM(he_mcs_map, IEEE80211_HE_MCS_SUPPORT_0_9, IEEE80211_HE_MCS_SUPPORT_0_9)
COMMON_PARAM(he_mcs_map, IEEE80211_HE_MCS_SUPPORT_0_11, IEEE80211_HE_MCS_SUPPORT_0_11)
COMMON_PARAM(he_ul_on, false, false)
COMMON_PARAM(ldpc_on, true, true)
COMMON_PARAM(stbc_on, true, true)
@ -973,9 +973,15 @@ static void rwnx_set_he_capa(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
#endif
if (rwnx_hw->mod_params->stbc_on)
he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 |
IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
#else
he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 |
IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA;
#endif
if (rwnx_hw->mod_params->bfmee) {
he_cap->he_cap_elem.phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
he_cap->he_cap_elem.phy_cap_info[4] |=
@ -983,12 +989,21 @@ static void rwnx_set_he_capa(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
}
he_cap->he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
#else
he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
#endif
he_cap->he_cap_elem.phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
@ -1062,9 +1077,15 @@ static void rwnx_set_he_capa(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
#endif
if (rwnx_hw->mod_params->stbc_on)
he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 |
IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
#else
he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 |
IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA;
#endif
if (rwnx_hw->mod_params->bfmee) {
he_cap->he_cap_elem.phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
he_cap->he_cap_elem.phy_cap_info[4] |=
@ -1072,12 +1093,21 @@ static void rwnx_set_he_capa(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
}
he_cap->he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
#else
he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
#endif
he_cap->he_cap_elem.phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)

View File

@ -45,7 +45,7 @@ static int rwnx_freq_to_idx(struct rwnx_hw *rwnx_hw, int freq)
}
}
BUG_ON(1);
WARN_ON(1);
exit:
// Channel has been found, return the index
@ -218,8 +218,9 @@ static inline int rwnx_rx_remain_on_channel_exp_ind(struct rwnx_hw *rwnx_hw,
rwnx_vif = container_of(roc_elem->wdev, struct rwnx_vif, wdev);
/* For debug purpose (use ftrace kernel option) */
#ifdef CREATE_TRACE_POINTS
trace_roc_exp(rwnx_vif->vif_index);
#endif
/* If mgmt_roc is true, remain on channel has been started by ourself */
/* If RoC has been cancelled before we switched on channel, do not call cfg80211 */
if (!roc_elem->mgmt_roc && roc_elem->on_chan) {
@ -506,7 +507,7 @@ static inline int rwnx_rx_ps_change_ind(struct rwnx_hw *rwnx_hw,
} else if (rwnx_hw->adding_sta) {
sta->ps.active = ind->ps_state ? true : false;
} else {
if (rwnx_hw->vif_table[sta->vif_idx]->ndev)
if (rwnx_hw->vif_table[sta->vif_idx] && rwnx_hw->vif_table[sta->vif_idx]->ndev)
netdev_err(rwnx_hw->vif_table[sta->vif_idx]->ndev,
"Ignore PS mode change on invalid sta\n");
}
@ -572,7 +573,6 @@ static inline int rwnx_rx_scanu_start_cfm(struct rwnx_hw *rwnx_hw,
{
RWNX_DBG(RWNX_FN_ENTRY_STR);
scanning = 0;
if (rwnx_hw->scan_request) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
struct cfg80211_scan_info info = {
@ -586,6 +586,7 @@ static inline int rwnx_rx_scanu_start_cfm(struct rwnx_hw *rwnx_hw,
}
rwnx_hw->scan_request = NULL;
scanning = 0;
return 0;
}
@ -633,7 +634,7 @@ static inline int rwnx_rx_scanu_result_ind(struct rwnx_hw *rwnx_hw,
CFG80211_BSS_FTYPE_UNKNOWN,
#endif
mgmt->bssid, tsf, capability, beacon_interval,
ie, ielen, ind->rssi * 100, GFP_KERNEL);
ie, ielen, ind->rssi * 100, GFP_ATOMIC);
}
if (bss != NULL)
@ -842,7 +843,7 @@ static inline int rwnx_rx_sm_disconnect_ind(struct rwnx_hw *rwnx_hw,
{
struct sm_disconnect_ind *ind = (struct sm_disconnect_ind *)msg->param;
struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
struct net_device *dev = rwnx_vif->ndev;
struct net_device *dev;
#ifdef AICWF_RX_REORDER
struct reord_ctrl_info *reord_info, *tmp;
u8 *macaddr;
@ -852,6 +853,10 @@ static inline int rwnx_rx_sm_disconnect_ind(struct rwnx_hw *rwnx_hw,
RWNX_DBG(RWNX_FN_ENTRY_STR);
dhcped = 0;
if (!rwnx_vif)
return 0;
dev = rwnx_vif->ndev;
if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
rwnx_hw->is_p2p_connected = 0;
/* if vif is not up, rwnx_close has already been called */
@ -879,7 +884,7 @@ static inline int rwnx_rx_sm_disconnect_ind(struct rwnx_hw *rwnx_hw,
macaddr = rwnx_vif->ndev->dev_addr;
printk("deinit:macaddr:%x,%x,%x,%x,%x,%x\r\n", macaddr[0], macaddr[1], macaddr[2], \
macaddr[3], macaddr[4], macaddr[5]);
spin_lock_bh(&rx_priv->stas_reord_lock);
list_for_each_entry_safe(reord_info, tmp, &rx_priv->stas_reord_list, list) {
macaddr = rwnx_vif->ndev->dev_addr;
printk("reord_mac:%x,%x,%x,%x,%x,%x\r\n", reord_info->mac_addr[0], reord_info->mac_addr[1], reord_info->mac_addr[2], \
@ -889,6 +894,7 @@ static inline int rwnx_rx_sm_disconnect_ind(struct rwnx_hw *rwnx_hw,
break;
}
}
spin_unlock_bh(&rx_priv->stas_reord_lock);
} else if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
BUG();//should be not here: del_sta function
}
@ -914,7 +920,7 @@ static inline int rwnx_rx_sm_external_auth_required_ind(struct rwnx_hw *rwnx_hw,
struct sm_external_auth_required_ind *ind =
(struct sm_external_auth_required_ind *)msg->param;
struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
struct net_device *dev = rwnx_vif->ndev;
struct cfg80211_external_auth_params params;
@ -1090,7 +1096,9 @@ static inline int rwnx_rx_mesh_path_update_ind(struct rwnx_hw *rwnx_hw,
/* Check if element has been deleted */
if (ind->delete) {
if (found) {
#ifdef CREATE_TRACE_POINTS
trace_mesh_delete_path(mesh_path);
#endif
/* Remove element from list */
list_del_init(&mesh_path->list);
/* Free the element */
@ -1100,7 +1108,9 @@ static inline int rwnx_rx_mesh_path_update_ind(struct rwnx_hw *rwnx_hw,
if (found) {
// Update the Next Hop STA
mesh_path->p_nhop_sta = &rwnx_hw->sta_table[ind->nhop_sta_idx];
#ifdef CREATE_TRACE_POINTS
trace_mesh_update_path(mesh_path);
#endif
} else {
// Allocate a Mesh Path structure
mesh_path = (struct rwnx_mesh_path *)kmalloc(sizeof(struct rwnx_mesh_path), GFP_ATOMIC);
@ -1114,8 +1124,9 @@ static inline int rwnx_rx_mesh_path_update_ind(struct rwnx_hw *rwnx_hw,
// Insert the path in the list of path
list_add_tail(&mesh_path->list, &rwnx_vif->ap.mpath_list);
#ifdef CREATE_TRACE_POINTS
trace_mesh_create_path(mesh_path);
#endif
}
}
}

View File

@ -19,6 +19,8 @@
#include "rwnx_compat.h"
#include "rwnx_cmds.h"
#include "aicwf_txrxif.h"
#include "rwnx_wakelock.h"
#include "aic_bsp_export.h"
const struct mac_addr mac_addr_bcst = {{0xFFFF, 0xFFFF, 0xFFFF}};
@ -227,6 +229,7 @@ static int rwnx_send_msg(struct rwnx_hw *rwnx_hw, const void *msg_params,
//RWNX_DBG(RWNX_FN_ENTRY_STR);
rwnx_wakeup_lock_timeout(rwnx_hw->ws_tx, jiffies_to_msecs(5));
#ifdef AICWF_USB_SUPPORT
if (rwnx_hw->usbdev->state == USB_DOWN_ST) {
rwnx_msg_free(rwnx_hw, msg_params);
@ -325,6 +328,7 @@ static int rwnx_send_msg1(struct rwnx_hw *rwnx_hw, const void *msg_params,
RWNX_DBG(RWNX_FN_ENTRY_STR);
rwnx_wakeup_lock_timeout(rwnx_hw->ws_tx, jiffies_to_msecs(5));
msg = container_of((void *)msg_params, struct lmac_msg, param);
//nonblock = is_non_blocking_msg(msg->id);
@ -853,6 +857,9 @@ int rwnx_send_coex_req(struct rwnx_hw *rwnx_hw, u8_l disable_coexnull, u8_l enab
struct mm_set_coex_req *coex_req;
int error;
if (rwnx_hw->chipid == PRODUCT_ID_AIC8800DC && rwnx_hw->cpmode == AICBSP_CPMODE_TEST)
return 0;
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Build the MM_SET_COEX_REQ message */
@ -908,8 +915,12 @@ int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw)
int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm)
{
struct mm_set_rf_calib_req *rf_calib_req;
xtal_cap_conf_t xtal_cap = {0,};
int error;
if (rwnx_hw->chipid == PRODUCT_ID_AIC8800DC && rwnx_hw->cpmode == AICBSP_CPMODE_TEST)
return 0;
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Build the MM_SET_P2P_NOA_REQ message */
@ -928,6 +939,13 @@ int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *
rf_calib_req->xtal_cap = 0;
rf_calib_req->xtal_cap_fine = 0;
get_userconfig_xtal_cap(&xtal_cap);
if (xtal_cap.enable) {
rf_calib_req->xtal_cap = xtal_cap.xtal_cap;
rf_calib_req->xtal_cap_fine = xtal_cap.xtal_cap_fine;
}
/* Send the MM_SET_RF_CALIB_REQ message to UMAC FW */
error = rwnx_send_msg(rwnx_hw, rf_calib_req, 1, MM_SET_RF_CALIB_CFM, cfm);
@ -1044,6 +1062,52 @@ int rwnx_send_get_fw_version_req(struct rwnx_hw *rwnx_hw, struct mm_get_fw_versi
return error;
}
int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw)
{
struct mm_set_txpwr_lvl_req *txpwr_lvl_req;
txpwr_lvl_conf_v2_t txpwr_lvl_v2_tmp;
txpwr_lvl_conf_v2_t *txpwr_lvl_v2;
int error = 0;
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Build the MM_SET_TXPWR_LVL_REQ message */
txpwr_lvl_req = rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_REQ, TASK_MM, DRV_TASK_ID,
sizeof(struct mm_set_txpwr_lvl_req));
if (!txpwr_lvl_req) {
return -ENOMEM;
}
txpwr_lvl_v2 = &txpwr_lvl_v2_tmp;
get_userconfig_txpwr_lvl_v2(txpwr_lvl_v2);
if (txpwr_lvl_v2->enable == 0) {
rwnx_msg_free(rwnx_hw, txpwr_lvl_req);
} else {
struct aicbsp_feature_t feature;
aicbsp_get_feature(&feature);
if ((feature.cpmode != AICBSP_CPMODE_TEST) && (feature.chipinfo->subrev == 0)) {
txpwr_lvl_req->txpwr_lvl.enable = txpwr_lvl_v2->enable;
txpwr_lvl_req->txpwr_lvl.dsss = txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]; // 11M
txpwr_lvl_req->txpwr_lvl.ofdmlowrate_2g4 = txpwr_lvl_v2->pwrlvl_11ax_2g4[4]; // MCS4
txpwr_lvl_req->txpwr_lvl.ofdm64qam_2g4 = txpwr_lvl_v2->pwrlvl_11ax_2g4[7]; // MCS7
txpwr_lvl_req->txpwr_lvl.ofdm256qam_2g4 = txpwr_lvl_v2->pwrlvl_11ax_2g4[9]; // MCS9
txpwr_lvl_req->txpwr_lvl.ofdm1024qam_2g4 = txpwr_lvl_v2->pwrlvl_11ax_2g4[11]; // MCS11
txpwr_lvl_req->txpwr_lvl.ofdmlowrate_5g = 13; // unused
txpwr_lvl_req->txpwr_lvl.ofdm64qam_5g = 13; // unused
txpwr_lvl_req->txpwr_lvl.ofdm256qam_5g = 13; // unused
txpwr_lvl_req->txpwr_lvl.ofdm1024qam_5g = 13; // unused
} else {
txpwr_lvl_req->txpwr_lvl_v2 = *txpwr_lvl_v2;
}
/* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */
error = rwnx_send_msg(rwnx_hw, txpwr_lvl_req, 1, MM_SET_TXPWR_IDX_LVL_CFM, NULL);
}
return error;
}
int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw)
{
@ -1051,10 +1115,14 @@ int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw)
txpwr_idx_conf_t *txpwr_idx;
int error;
if (rwnx_hw->chipid == PRODUCT_ID_AIC8800DC) {
return rwnx_send_txpwr_lvl_req(rwnx_hw);
}
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Build the MM_SET_TXPWR_IDX_REQ message */
txpwr_idx_req = rwnx_msg_zalloc(MM_SET_TXPWR_IDX_REQ, TASK_MM, DRV_TASK_ID,
txpwr_idx_req = rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_REQ, TASK_MM, DRV_TASK_ID,
sizeof(struct mm_set_txpwr_idx_req));
if (!txpwr_idx_req) {
@ -1080,7 +1148,7 @@ int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw)
return 0;
} else {
/* Send the MM_SET_TXPWR_IDX_REQ message to UMAC FW */
error = rwnx_send_msg(rwnx_hw, txpwr_idx_req, 1, MM_SET_TXPWR_IDX_CFM, NULL);
error = rwnx_send_msg(rwnx_hw, txpwr_idx_req, 1, MM_SET_TXPWR_IDX_LVL_CFM, NULL);
return error;
}
@ -1149,6 +1217,8 @@ int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw)
#endif
uint8_t *ht_mcs;
int i;
if (rwnx_hw->chipid == PRODUCT_ID_AIC8800DC && rwnx_hw->cpmode == AICBSP_CPMODE_TEST)
return 0;
if (rwnx_hw->band_5g_support) {
ht_cap = &wiphy->bands[NL80211_BAND_5GHZ]->ht_cap;
@ -1197,8 +1267,6 @@ int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw)
#if defined(CONFIG_HE_FOR_OLD_KERNEL)
if (1) {
he_cap = &rwnx_he_capa.he_cap;
#else
{
#endif
req->he_supp = he_cap->has_he;
for (i = 0; i < ARRAY_SIZE(he_cap->he_cap_elem.mac_cap_info); i++) {
@ -1218,7 +1286,6 @@ int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw)
}
req->he_ul_on = rwnx_hw->mod_params->he_ul_on;
}
}
#else
req->he_supp = false;
req->he_ul_on = false;
@ -1247,6 +1314,9 @@ int rwnx_send_me_chan_config_req(struct rwnx_hw *rwnx_hw)
struct wiphy *wiphy = rwnx_hw->wiphy;
int i;
if (rwnx_hw->chipid == PRODUCT_ID_AIC8800DC && rwnx_hw->cpmode == AICBSP_CPMODE_TEST)
return 0;
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Build the ME_CHAN_CONFIG_REQ message */

View File

@ -16,7 +16,6 @@
#include "reg_access.h"
#include "hal_desc.h"
#include "rwnx_main.h"
#include "rwnx_pci.h"
#ifndef CONFIG_RWNX_FHOST
#include "ipc_host.h"
#endif /* !CONFIG_RWNX_FHOST */
@ -30,6 +29,12 @@
#include "aicwf_usb.h"
#endif
#ifdef AICWF_PCIE_SUPPORT
#include "rwnx_pci.h"
#endif
#include "aic_bsp_export.h"
struct rwnx_plat *g_rwnx_plat;
#ifdef CONFIG_RWNX_TL4
@ -224,7 +229,9 @@ static int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr,
typedef struct {
txpwr_idx_conf_t txpwr_idx;
txpwr_lvl_conf_v2_t txpwr_lvl_v2;
txpwr_ofst_conf_t txpwr_ofst;
xtal_cap_conf_t xtal_cap;
} nvram_info_t;
nvram_info_t nvram_info = {
@ -240,6 +247,18 @@ nvram_info_t nvram_info = {
.ofdm256qam_5g = 9,
.ofdm1024qam_5g = 9
},
.txpwr_lvl_v2 = {
.enable = 1,
.pwrlvl_11b_11ag_2g4 = {
// 1M, 2M, 5M5, 11M, 6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M
20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16},
.pwrlvl_11n_11ac_2g4 = {
// MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
20, 20, 20, 20, 18, 18, 16, 16, 16, 16},
.pwrlvl_11ax_2g4 = {
// MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10, MCS11
20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15},
},
.txpwr_ofst = {
.enable = 1,
.chan_1_4 = 0,
@ -250,8 +269,18 @@ nvram_info_t nvram_info = {
.chan_122_140 = 0,
.chan_142_165 = 0,
},
.xtal_cap = {
.enable = 0,
.xtal_cap = 24,
.xtal_cap_fine = 31,
},
};
void get_userconfig_txpwr_lvl_v2(txpwr_lvl_conf_v2_t *txpwr_lvl_v2)
{
memcpy(txpwr_lvl_v2, &(nvram_info.txpwr_lvl_v2), sizeof(txpwr_lvl_conf_v2_t));
}
void get_userconfig_txpwr_idx(txpwr_idx_conf_t *txpwr_idx)
{
memcpy(txpwr_idx, &(nvram_info.txpwr_idx), sizeof(txpwr_idx_conf_t));
@ -262,6 +291,11 @@ void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst)
memcpy(txpwr_ofst, &(nvram_info.txpwr_ofst), sizeof(txpwr_ofst_conf_t));
}
void get_userconfig_xtal_cap(xtal_cap_conf_t *xtal_cap)
{
memcpy(xtal_cap, &(nvram_info.xtal_cap), sizeof(xtal_cap_conf_t));
}
#define MATCH_NODE(type, node, cfg_key) {cfg_key, offsetof(type, node)}
struct parse_match_t {
@ -272,6 +306,7 @@ struct parse_match_t {
static const char *parse_key_prefix[] = {
[0x01] = "module0_",
[0x21] = "module1_",
[0xFF] = "",
};
static const struct parse_match_t parse_match_tab[] = {
@ -286,6 +321,43 @@ static const struct parse_match_t parse_match_tab[] = {
MATCH_NODE(nvram_info_t, txpwr_idx.ofdm256qam_5g, "ofdm256qam_5g"),
MATCH_NODE(nvram_info_t, txpwr_idx.ofdm1024qam_5g, "ofdm1024qam_5g"),
{"lvl_11b_11ag_1m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 0},
{"lvl_11b_11ag_2m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 1},
{"lvl_11b_11ag_5m5_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 2},
{"lvl_11b_11ag_11m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 3},
{"lvl_11b_11ag_6m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 4},
{"lvl_11b_11ag_9m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 5},
{"lvl_11b_11ag_12m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 6},
{"lvl_11b_11ag_18m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 7},
{"lvl_11b_11ag_24m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 8},
{"lvl_11b_11ag_36m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 9},
{"lvl_11b_11ag_48m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 10},
{"lvl_11b_11ag_54m_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11b_11ag_2g4) + 11},
{"lvl_11n_11ac_mcs0_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 0},
{"lvl_11n_11ac_mcs1_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 1},
{"lvl_11n_11ac_mcs2_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 2},
{"lvl_11n_11ac_mcs3_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 3},
{"lvl_11n_11ac_mcs4_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 4},
{"lvl_11n_11ac_mcs5_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 5},
{"lvl_11n_11ac_mcs6_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 6},
{"lvl_11n_11ac_mcs7_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 7},
{"lvl_11n_11ac_mcs8_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 8},
{"lvl_11n_11ac_mcs9_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11n_11ac_2g4) + 9},
{"lvl_11ax_mcs0_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 0},
{"lvl_11ax_mcs1_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 1},
{"lvl_11ax_mcs2_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 2},
{"lvl_11ax_mcs3_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 3},
{"lvl_11ax_mcs4_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 4},
{"lvl_11ax_mcs5_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 5},
{"lvl_11ax_mcs6_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 6},
{"lvl_11ax_mcs7_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 7},
{"lvl_11ax_mcs8_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 8},
{"lvl_11ax_mcs9_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 9},
{"lvl_11ax_mcs10_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 10},
{"lvl_11ax_mcs11_2g4", offsetof(nvram_info_t, txpwr_lvl_v2.pwrlvl_11ax_2g4) + 11},
MATCH_NODE(nvram_info_t, txpwr_ofst.enable, "ofst_enable"),
MATCH_NODE(nvram_info_t, txpwr_ofst.chan_1_4, "ofst_chan_1_4"),
MATCH_NODE(nvram_info_t, txpwr_ofst.chan_5_9, "ofst_chan_5_9"),
@ -294,6 +366,10 @@ static const struct parse_match_t parse_match_tab[] = {
MATCH_NODE(nvram_info_t, txpwr_ofst.chan_100_120, "ofst_chan_100_120"),
MATCH_NODE(nvram_info_t, txpwr_ofst.chan_122_140, "ofst_chan_122_140"),
MATCH_NODE(nvram_info_t, txpwr_ofst.chan_142_165, "ofst_chan_142_165"),
MATCH_NODE(nvram_info_t, xtal_cap.enable, "xtal_enable"),
MATCH_NODE(nvram_info_t, xtal_cap.xtal_cap, "xtal_cap"),
MATCH_NODE(nvram_info_t, xtal_cap.xtal_cap_fine, "xtal_cap_fine"),
};
static int parse_key_val(const char *str, const char *key, char *val)
@ -366,6 +442,7 @@ void rwnx_plat_userconfig_parsing(struct rwnx_hw *rwnx_hw, char *buffer, int siz
char *data;
int i = 0, err, len = 0;
long val;
u8 efuse_idx = 0;
if (size <= 0) {
pr_err("Config buffer size %d error\n", size);
@ -377,6 +454,15 @@ void rwnx_plat_userconfig_parsing(struct rwnx_hw *rwnx_hw, char *buffer, int siz
return;
}
efuse_idx = rwnx_hw->vendor_info;
if (rwnx_hw->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->chipid == PRODUCT_ID_AIC8800DW) {
printk("AIC8800DC chipset\n");
efuse_idx = 0xFF;
} else if (rwnx_hw->vendor_info == 0x00) {
printk("Empty efuse, using module0 config\n");
efuse_idx = 0x01;
}
data = vmalloc(size + 1);
if (!data) {
pr_err("vmalloc fail\n");
@ -402,10 +488,10 @@ void rwnx_plat_userconfig_parsing(struct rwnx_hw *rwnx_hw, char *buffer, int siz
// store value to data struct
for (i = 0; i < sizeof(parse_match_tab) / sizeof(parse_match_tab[0]); i++) {
sprintf(&keyname[0], "%s%s", parse_key_prefix[rwnx_hw->vendor_info], parse_match_tab[i].keyname);
sprintf(&keyname[0], "%s%s", parse_key_prefix[efuse_idx], parse_match_tab[i].keyname);
if (parse_key_val(line, keyname, conf) == 0) {
err = kstrtol(conf, 0, &val);
*(unsigned long *)((unsigned long)&nvram_info + parse_match_tab[i].offset) = val;
*(unsigned char *)((unsigned long)&nvram_info + parse_match_tab[i].offset) = val;
printk("%s, %s = %ld\n", __func__, parse_match_tab[i].keyname, val);
break;
}
@ -414,7 +500,8 @@ void rwnx_plat_userconfig_parsing(struct rwnx_hw *rwnx_hw, char *buffer, int siz
vfree(data);
}
#define FW_USERCONFIG_NAME "aic_userconfig.txt"
#define FW_USERCONFIG_NAME_8800D "aic_userconfig.txt"
#define FW_USERCONFIG_NAME_8800DC "aic8800dc/aic_userconfig.txt"
int rwnx_plat_userconfig_upload_android(struct rwnx_hw *rwnx_hw, char *filename)
{
@ -457,7 +544,11 @@ static int rwnx_plat_fmac_load(struct rwnx_hw *rwnx_hw)
int ret = 0;
RWNX_DBG(RWNX_FN_ENTRY_STR);
ret = rwnx_plat_userconfig_upload_android(rwnx_hw, FW_USERCONFIG_NAME);
if (rwnx_hw->chipid == PRODUCT_ID_AIC8800D)
ret = rwnx_plat_userconfig_upload_android(rwnx_hw, FW_USERCONFIG_NAME_8800D);
else if (rwnx_hw->chipid == PRODUCT_ID_AIC8800DC)
ret = rwnx_plat_userconfig_upload_android(rwnx_hw, FW_USERCONFIG_NAME_8800DC);
return ret;
}
#endif /* !CONFIG_ROM_PATCH_EN */
@ -788,6 +879,7 @@ void rwnx_platform_deinit(struct rwnx_hw *rwnx_hw)
#endif
}
#ifdef AICWF_PCIE_SUPPORT
/**
* rwnx_platform_register_drv() - Register all possible platform drivers
*/
@ -804,6 +896,23 @@ void rwnx_platform_unregister_drv(void)
{
return rwnx_pci_unregister_drv();
}
#else
/**
* rwnx_platform_register_drv() - Register all possible platform drivers
*/
int rwnx_platform_register_drv(void)
{
return 0;
}
/**
* rwnx_platform_unregister_drv() - Unegister all platform drivers
*/
void rwnx_platform_unregister_drv(void)
{
}
#endif
struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat)
{
@ -813,7 +922,9 @@ struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat)
#ifdef AICWF_USB_SUPPORT
return rwnx_plat->usbdev->dev;
#endif
#ifdef AICWF_PCIE_SUPPORT
return &(rwnx_plat->pci_dev->dev);
#endif
}

View File

@ -111,8 +111,10 @@ void rwnx_platform_off(struct rwnx_hw *rwnx_hw, void **config);
int rwnx_platform_register_drv(void);
void rwnx_platform_unregister_drv(void);
void get_userconfig_txpwr_lvl_v2(txpwr_lvl_conf_v2_t *txpwr_lvl_v2);
void get_userconfig_txpwr_idx(txpwr_idx_conf_t *txpwr_idx);
void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst);
void get_userconfig_xtal_cap(xtal_cap_conf_t *xtal_cap);
extern struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat);

View File

@ -1125,7 +1125,9 @@ static bool dfs_pattern_detector_add_pulse(struct dfs_pattern_detector *dpd,
ps = pde->ops->add_pulse(pde, len, dpd->last_pulse_ts, pri);
if (ps != NULL) {
#ifdef CREATE_TRACE_POINTS
trace_radar_detected(chain, dpd->region, pde->freq, i, ps->pri);
#endif
// reset everything instead of just the channel detector
dfs_pattern_detector_reset(dpd);
return true;
@ -1339,7 +1341,9 @@ static void rwnx_radar_process_pulse(struct work_struct *ws)
for (i = 0; i < pulses_count[chain] ; i++) {
struct radar_pulse *p = (struct radar_pulse *)&pulses[chain][i];
#ifdef CREATE_TRACE_POINTS
trace_radar_pulse(chain, p);
#endif
if (dfs_pattern_detector_add_pulse(radar->dpd[chain], chain,
(s16)freq + (2 * p->freq),
p->rep, (p->len * 2), now)) {
@ -1444,9 +1448,9 @@ bool rwnx_radar_set_domain(struct rwnx_radar *radar,
{
if (radar->dpd[0] == NULL)
return false;
#ifdef CREATE_TRACE_POINTS
trace_radar_set_region(region);
#endif
return (dfs_pattern_detector_set_domain(radar->dpd[RWNX_RADAR_RIU],
region, RWNX_RADAR_RIU) &&
dfs_pattern_detector_set_domain(radar->dpd[RWNX_RADAR_FCU],
@ -1456,7 +1460,9 @@ bool rwnx_radar_set_domain(struct rwnx_radar *radar,
void rwnx_radar_detection_enable(struct rwnx_radar *radar, u8 enable, u8 chain)
{
if (chain < RWNX_RADAR_LAST) {
#ifdef CREATE_TRACE_POINTS
trace_radar_enable_detection(radar->dpd[chain]->region, enable, chain);
#endif
spin_lock_bh(&radar->lock);
radar->dpd[chain]->enabled = enable;
spin_unlock_bh(&radar->lock);

View File

@ -626,10 +626,10 @@ static void rwnx_rx_mgmt_any(struct rwnx_hw *rwnx_hw, struct sk_buff *skb,
{
struct rwnx_vif *rwnx_vif;
int vif_idx = hw_rxhdr->flags_vif_idx;
#ifdef CREATE_TRACE_POINTS
trace_mgmt_rx(hw_rxhdr->phy_info.phy_prim20_freq, vif_idx,
hw_rxhdr->flags_sta_idx, (struct ieee80211_mgmt *)skb->data);
#endif
if (vif_idx == RWNX_INVALID_VIF) {
list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
if (!rwnx_vif->up)
@ -1264,13 +1264,6 @@ void reord_deinit_sta(struct aicwf_rx_priv *rx_priv, struct reord_ctrl_info *reo
for (i = 0; i < 8; i++) {
struct recv_msdu *req, *next;
preorder_ctrl = &reord_info->preorder_ctrl[i];
if (preorder_ctrl->enable) {
preorder_ctrl->enable = false;
if (timer_pending(&preorder_ctrl->reord_timer)) {
ret = del_timer_sync(&preorder_ctrl->reord_timer);
}
cancel_work_sync(&preorder_ctrl->reord_timer_work);
}
spin_lock_irqsave(&preorder_ctrl->reord_list_lock, flags);
list_for_each_entry_safe(req, next, &preorder_ctrl->reord_list, reord_pending_list) {
list_del_init(&req->reord_pending_list);
@ -1280,11 +1273,13 @@ void reord_deinit_sta(struct aicwf_rx_priv *rx_priv, struct reord_ctrl_info *reo
reord_rxframe_free(&rx_priv->freeq_lock, &rx_priv->rxframes_freequeue, &req->rxframe_list);
}
spin_unlock_irqrestore(&preorder_ctrl->reord_list_lock, flags);
if (timer_pending(&preorder_ctrl->reord_timer)) {
ret = del_timer_sync(&preorder_ctrl->reord_timer);
}
cancel_work_sync(&preorder_ctrl->reord_timer_work);
}
spin_lock_bh(&rx_priv->stas_reord_lock);
list_del(&reord_info->list);
spin_unlock_bh(&rx_priv->stas_reord_lock);
kfree(reord_info);
}
@ -1475,7 +1470,7 @@ int reord_process_unit(struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, u16 s
pframe->forward = forward;
preorder_ctrl = pframe->preorder_ctrl;
if ((ntohs(eh->h_proto) == ETH_P_PAE) || (((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) && is_mcast))
if ((ntohs(eh->h_proto) == ETH_P_PAE) || is_mcast)
return reord_single_frame_ind(rx_priv, pframe);
if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))

View File

@ -119,8 +119,8 @@ static const char *const rwnx_mmid2str[MSG_I(MM_MAX)] = {
[MSG_I(MM_GET_MAC_ADDR_CFM)] = "MM_GET_MAC_ADDR_CFM",
[MSG_I(MM_GET_STA_INFO_REQ)] = "MM_GET_STA_INFO_REQ",
[MSG_I(MM_GET_STA_INFO_CFM)] = "MM_GET_STA_INFO_CFM",
[MSG_I(MM_SET_TXPWR_IDX_REQ)] = "MM_SET_TXPWR_IDX_REQ",
[MSG_I(MM_SET_TXPWR_IDX_CFM)] = "MM_SET_TXPWR_IDX_CFM",
[MSG_I(MM_SET_TXPWR_IDX_LVL_REQ)] = "MM_SET_TXPWR_IDX_LVL_REQ",
[MSG_I(MM_SET_TXPWR_IDX_LVL_CFM)] = "MM_SET_TXPWR_IDX_LVL_CFM",
[MSG_I(MM_SET_TXPWR_OFST_REQ)] = "MM_SET_TXPWR_OFST_REQ",
[MSG_I(MM_SET_TXPWR_OFST_CFM)] = "MM_SET_TXPWR_OFST_CFM",
[MSG_I(MM_SET_STACK_START_REQ)] = "MM_SET_STACK_START_REQ",
@ -224,6 +224,8 @@ static const char *const rwnx_apmid2str[MSG_I(APM_MAX)] = {
[MSG_I(APM_START_CAC_CFM)] = "APM_START_CAC_CFM",
[MSG_I(APM_STOP_CAC_REQ)] = "APM_STOP_CAC_REQ",
[MSG_I(APM_STOP_CAC_CFM)] = "APM_STOP_CAC_CFM",
[MSG_I(APM_SET_BEACON_IE_REQ)] = "APM_SET_BEACON_IE_REQ",
[MSG_I(APM_SET_BEACON_IE_CFM)] = "APM_SET_BEACON_IE_CFM",
};
static const char *const rwnx_meshid2str[MSG_I(MESH_MAX)] = {

View File

@ -41,7 +41,9 @@ void rwnx_set_traffic_status(struct rwnx_hw *rwnx_hw,
} else {
bool uapsd = (ps_id != LEGACY_PS_ID);
rwnx_send_me_traffic_ind(rwnx_hw, sta->sta_idx, uapsd, available);
#ifdef CREATE_TRACE_POINTS
trace_ps_traffic_update(sta->sta_idx, available, uapsd);
#endif
}
}
@ -76,8 +78,9 @@ void rwnx_ps_bh_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
struct rwnx_txq *txq;
if (enable) {
#ifdef CREATE_TRACE_POINTS
trace_ps_enable(sta);
#endif
spin_lock_bh(&rwnx_hw->tx_lock);
sta->ps.active = true;
sta->ps.sp_cnt[LEGACY_PS_ID] = 0;
@ -100,14 +103,15 @@ void rwnx_ps_bh_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
spin_unlock_bh(&rwnx_hw->tx_lock);
if (sta->ps.pkt_ready[LEGACY_PS_ID])
/*if (sta->ps.pkt_ready[LEGACY_PS_ID])
rwnx_set_traffic_status(rwnx_hw, sta, true, LEGACY_PS_ID);
if (sta->ps.pkt_ready[UAPSD_ID])
rwnx_set_traffic_status(rwnx_hw, sta, true, UAPSD_ID);
rwnx_set_traffic_status(rwnx_hw, sta, true, UAPSD_ID);*/
} else {
#ifdef CREATE_TRACE_POINTS
trace_ps_disable(sta->sta_idx);
#endif
spin_lock_bh(&rwnx_hw->tx_lock);
sta->ps.active = false;
@ -125,11 +129,11 @@ void rwnx_ps_bh_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
rwnx_txq_sta_start(sta, RWNX_TXQ_STOP_STA_PS, rwnx_hw);
spin_unlock_bh(&rwnx_hw->tx_lock);
if (sta->ps.pkt_ready[LEGACY_PS_ID])
/*if (sta->ps.pkt_ready[LEGACY_PS_ID])
rwnx_set_traffic_status(rwnx_hw, sta, false, LEGACY_PS_ID);
if (sta->ps.pkt_ready[UAPSD_ID])
rwnx_set_traffic_status(rwnx_hw, sta, false, UAPSD_ID);
rwnx_set_traffic_status(rwnx_hw, sta, false, UAPSD_ID);*/
tasklet_schedule(&rwnx_hw->task);
}
@ -168,9 +172,9 @@ void rwnx_ps_bh_traffic_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
printk("sta %pM is not in Power Save mode", sta->mac_addr);
return;
}
#ifdef CREATE_TRACE_POINTS
trace_ps_traffic_req(sta, pkt_req, ps_id);
#endif
spin_lock_bh(&rwnx_hw->tx_lock);
/* Fw may ask to stop a service period with PS_SP_INTERRUPTED. This only
@ -446,9 +450,9 @@ static inline void rwnx_set_more_data_flag(struct rwnx_hw *rwnx_hw,
if (unlikely(sta->ps.active)) {
sta->ps.pkt_ready[txq->ps_id]--;
sta->ps.sp_cnt[txq->ps_id]--;
#ifdef CREATE_TRACE_POINTS
trace_ps_push(sta);
#endif
if (((txq->ps_id == UAPSD_ID) || (vif->wdev.iftype == NL80211_IFTYPE_MESH_POINT) || (sta->tdls.active))
&& !sta->ps.sp_cnt[txq->ps_id]) {
sw_txhdr->desc.host.flags |= TXU_CNTRL_EOSP;
@ -578,7 +582,8 @@ void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags)
between queue and push (because of PS) */
sw_txhdr->hw_queue = hw_queue;
sw_txhdr->desc.host.packet_addr = hw_queue; //use packet_addr field for hw_txq
//sw_txhdr->desc.host.packet_addr = hw_queue; //use packet_addr field for hw_txq
sw_txhdr->desc.host.ac = hw_queue; //use ac field for hw_txq
#ifdef CONFIG_RWNX_MUMIMO_TX
/* MU group is only selected during hwq processing */
sw_txhdr->desc.host.mumimo_info = txq->mumimo_info;
@ -589,8 +594,9 @@ void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags)
/* only for AP mode */
rwnx_set_more_data_flag(rwnx_hw, sw_txhdr);
}
#ifdef CREATE_TRACE_POINTS
trace_push_desc(skb, sw_txhdr, flags);
#endif
#if 0
txq->credits--;
#endif
@ -674,12 +680,6 @@ static void rwnx_tx_retry(struct rwnx_hw *rwnx_hw, struct sk_buff *skb,
if (!sw_retry) {
/* update sw desc */
sw_txhdr->desc.host.sn = cfm->sn;
sw_txhdr->desc.host.pn[0] = cfm->pn[0];
sw_txhdr->desc.host.pn[1] = cfm->pn[1];
sw_txhdr->desc.host.pn[2] = cfm->pn[2];
sw_txhdr->desc.host.pn[3] = cfm->pn[3];
sw_txhdr->desc.host.timestamp = cfm->timestamp;
sw_txhdr->desc.host.flags |= TXU_CNTRL_RETRY;
#ifdef CONFIG_RWNX_AMSDUS_TX
@ -1094,7 +1094,7 @@ netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev)
(memcmp(desc->host.eth_dest_addr.array, rwnx_vif->sta.tdls_sta->mac_addr, ETH_ALEN) == 0)) {
desc->host.flags |= TXU_CNTRL_TDLS;
rwnx_vif->sta.tdls_sta->tdls.last_tid = desc->host.tid;
rwnx_vif->sta.tdls_sta->tdls.last_sn = desc->host.sn;
//rwnx_vif->sta.tdls_sta->tdls.last_sn = desc->host.sn;
}
if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_MESH_POINT) {
@ -1121,12 +1121,6 @@ netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Fill-in TX descriptor */
frame_oft = sizeof(struct rwnx_txhdr) - offsetof(struct rwnx_txhdr, hw_hdr)
+ hdr_pads;// + sizeof(*eth);
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
desc->host.packet_addr[0] = sw_txhdr->dma_addr + frame_oft;
desc->host.packet_cnt = 1;
#else
desc->host.packet_addr = sw_txhdr->dma_addr + frame_oft;
#endif
desc->host.status_desc_addr = sw_txhdr->dma_addr;
spin_lock_bh(&rwnx_hw->tx_lock);
@ -1311,12 +1305,6 @@ int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
}
frame_oft = sizeof(struct rwnx_txhdr) - offsetof(struct rwnx_txhdr, hw_hdr);
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
desc->host.packet_addr[0] = sw_txhdr->dma_addr + frame_oft;
desc->host.packet_cnt = 1;
#else
desc->host.packet_addr = sw_txhdr->dma_addr + frame_oft;
#endif
desc->host.status_desc_addr = sw_txhdr->dma_addr;
//----------------------------------------------------------------------
@ -1359,6 +1347,19 @@ int rwnx_txdatacfm(void *pthis, void *host_id)
return -1;
}
#if defined(AICWF_USB_SUPPORT)
if (rwnx_hw->usbdev->state == USB_DOWN_ST)
#elif defined(AICWF_SDIO_SUPPORT)
if (rwnx_hw->sdiodev->bus_if->state == BUS_DOWN_ST)
#endif
{
headroom = sw_txhdr->headroom;
kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr);
skb_pull(skb, headroom);
consume_skb(skb);
return 0;
}
txq = sw_txhdr->txq;
/* don't use txq->hwq as it may have changed between push and confirm */
hwq = &rwnx_hw->hwq[sw_txhdr->hw_queue];
@ -1369,11 +1370,11 @@ int rwnx_txdatacfm(void *pthis, void *host_id)
printk("done=%d retry_required=%d sw_retry_required=%d acknowledged=%d\n",
rwnx_txst.tx_done, rwnx_txst.retry_required,
rwnx_txst.sw_retry_required, rwnx_txst.acknowledged);
#ifdef CREATE_TRACE_POINTS
trace_mgmt_cfm(sw_txhdr->rwnx_vif->vif_index,
(sw_txhdr->rwnx_sta) ? sw_txhdr->rwnx_sta->sta_idx : 0xFF,
rwnx_txst.acknowledged);
#endif
/* Confirm transmission to CFG80211 */
cfg80211_mgmt_tx_status(&sw_txhdr->rwnx_vif->wdev,
(unsigned long)skb,
@ -1393,9 +1394,9 @@ int rwnx_txdatacfm(void *pthis, void *host_id)
rwnx_tx_retry(rwnx_hw, skb, txhdr, sw_retry);
return 0;
}
#ifdef CREATE_TRACE_POINTS
trace_skb_confirm(skb, txq, hwq, &txhdr->hw_hdr.cfm);
#endif
/* STA may have disconnect (and txq stopped) when buffers were stored
in fw. In this case do nothing when they're returned */
if (txq->idx != TXQ_INACTIVE) {
@ -1469,7 +1470,9 @@ void rwnx_txq_credit_update(struct rwnx_hw *rwnx_hw, int sta_idx, u8 tid,
if (txq->idx != TXQ_INACTIVE) {
//txq->credits += update;
#ifdef CREATE_TRACE_POINTS
trace_credit_update(txq, update);
#endif
if (txq->credits <= 0)
rwnx_txq_stop(txq, RWNX_TXQ_STOP_FULL);
else

View File

@ -137,15 +137,15 @@ void rwnx_txq_flush(struct rwnx_hw *rwnx_hw, struct rwnx_txq *txq)
if (sw_txhdr->desc.host.packet_cnt > 1) {
struct rwnx_amsdu_txhdr *amsdu_txhdr;
list_for_each_entry(amsdu_txhdr, &sw_txhdr->amsdu.hdrs, list) {
dma_unmap_single(rwnx_hw->dev, amsdu_txhdr->dma_addr,
amsdu_txhdr->map_len, DMA_TO_DEVICE);
//dma_unmap_single(rwnx_hw->dev, amsdu_txhdr->dma_addr,
// amsdu_txhdr->map_len, DMA_TO_DEVICE);
dev_kfree_skb_any(amsdu_txhdr->skb);
}
}
#endif
kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr);
dma_unmap_single(rwnx_hw->dev, sw_txhdr->dma_addr, sw_txhdr->map_len,
DMA_TO_DEVICE);
//dma_unmap_single(rwnx_hw->dev, sw_txhdr->dma_addr, sw_txhdr->map_len,
// DMA_TO_DEVICE);
#ifdef CONFIG_RWNX_FULLMAC
dev_kfree_skb_any(skb);
@ -384,7 +384,9 @@ void rwnx_txq_tdls_vif_deinit(struct rwnx_vif *rwnx_vif)
void rwnx_txq_add_to_hw_list(struct rwnx_txq *txq)
{
if (!(txq->status & RWNX_TXQ_IN_HWQ_LIST)) {
#ifdef CREATE_TRACE_POINTS
trace_txq_add_to_hw(txq);
#endif
txq->status |= RWNX_TXQ_IN_HWQ_LIST;
list_add_tail(&txq->sched_list, &txq->hwq->list);
txq->hwq->need_processing = true;
@ -402,7 +404,9 @@ void rwnx_txq_add_to_hw_list(struct rwnx_txq *txq)
void rwnx_txq_del_from_hw_list(struct rwnx_txq *txq)
{
if (txq->status & RWNX_TXQ_IN_HWQ_LIST) {
#ifdef CREATE_TRACE_POINTS
trace_txq_del_from_hw(txq);
#endif
txq->status &= ~RWNX_TXQ_IN_HWQ_LIST;
list_del(&txq->sched_list);
}
@ -440,7 +444,9 @@ void rwnx_txq_start(struct rwnx_txq *txq, u16 reason)
{
BUG_ON(txq == NULL);
if (txq->idx != TXQ_INACTIVE && (txq->status & reason)) {
#ifdef CREATE_TRACE_POINTS
trace_txq_start(txq, reason);
#endif
txq->status &= ~reason;
if (!rwnx_txq_is_stopped(txq) && rwnx_txq_skb_ready(txq))
rwnx_txq_add_to_hw_list(txq);
@ -460,7 +466,9 @@ void rwnx_txq_stop(struct rwnx_txq *txq, u16 reason)
{
BUG_ON(txq == NULL);
if (txq->idx != TXQ_INACTIVE) {
#ifdef CREATE_TRACE_POINTS
trace_txq_stop(txq, reason);
#endif
txq->status |= reason;
rwnx_txq_del_from_hw_list(txq);
}
@ -492,8 +500,9 @@ void rwnx_txq_sta_start(struct rwnx_sta *rwnx_sta, u16 reason
{
struct rwnx_txq *txq;
int tid;
#ifdef CREATE_TRACE_POINTS
trace_txq_sta_start(rwnx_sta->sta_idx);
#endif
foreach_sta_txq(rwnx_sta, txq, tid, rwnx_hw) {
rwnx_txq_start(txq, reason);
@ -528,8 +537,9 @@ void rwnx_txq_sta_stop(struct rwnx_sta *rwnx_sta, u16 reason
if (!rwnx_sta)
return;
#ifdef CREATE_TRACE_POINTS
trace_txq_sta_stop(rwnx_sta->sta_idx);
#endif
foreach_sta_txq(rwnx_sta, txq, tid, rwnx_hw) {
rwnx_txq_stop(txq, reason);
}
@ -539,7 +549,9 @@ void rwnx_txq_sta_stop(struct rwnx_sta *rwnx_sta, u16 reason
void rwnx_txq_tdls_sta_start(struct rwnx_vif *rwnx_vif, u16 reason,
struct rwnx_hw *rwnx_hw)
{
#ifdef CREATE_TRACE_POINTS
trace_txq_vif_start(rwnx_vif->vif_index);
#endif
spin_lock_bh(&rwnx_hw->tx_lock);
if (rwnx_vif->sta.tdls_sta)
@ -553,7 +565,9 @@ void rwnx_txq_tdls_sta_start(struct rwnx_vif *rwnx_vif, u16 reason,
void rwnx_txq_tdls_sta_stop(struct rwnx_vif *rwnx_vif, u16 reason,
struct rwnx_hw *rwnx_hw)
{
#ifdef CREATE_TRACE_POINTS
trace_txq_vif_stop(rwnx_vif->vif_index);
#endif
spin_lock_bh(&rwnx_hw->tx_lock);
@ -613,9 +627,9 @@ void rwnx_txq_vif_start(struct rwnx_vif *rwnx_vif, u16 reason,
struct rwnx_hw *rwnx_hw)
{
struct rwnx_txq *txq;
#ifdef CREATE_TRACE_POINTS
trace_txq_vif_start(rwnx_vif->vif_index);
#endif
spin_lock_bh(&rwnx_hw->tx_lock);
#ifdef CONFIG_RWNX_FULLMAC
@ -657,8 +671,9 @@ void rwnx_txq_vif_stop(struct rwnx_vif *rwnx_vif, u16 reason,
struct rwnx_hw *rwnx_hw)
{
struct rwnx_txq *txq;
#ifdef CREATE_TRACE_POINTS
trace_txq_vif_stop(rwnx_vif->vif_index);
#endif
spin_lock_bh(&rwnx_hw->tx_lock);
#ifdef CONFIG_RWNX_FULLMAC
@ -758,8 +773,9 @@ int rwnx_txq_queue_skb(struct sk_buff *skb, struct rwnx_txq *txq,
#ifdef CONFIG_RWNX_FULLMAC
if (unlikely(txq->sta && txq->sta->ps.active)) {
txq->sta->ps.pkt_ready[txq->ps_id]++;
#ifdef CREATE_TRACE_POINTS
trace_ps_queue(txq->sta);
#endif
if (txq->sta->ps.pkt_ready[txq->ps_id] == 1) {
rwnx_set_traffic_status(rwnx_hw, txq->sta, true, txq->ps_id);
}
@ -778,9 +794,9 @@ int rwnx_txq_queue_skb(struct sk_buff *skb, struct rwnx_txq *txq,
txq->last_retry_skb = skb;
txq->nb_retry++;
}
#ifdef CREATE_TRACE_POINTS
trace_txq_queue_skb(skb, txq, retry);
#endif
/* Flowctrl corresponding netdev queue if needed */
#ifdef CONFIG_RWNX_FULLMAC
/* If too many buffer are queued for this TXQ stop netdev queue */
@ -788,7 +804,9 @@ int rwnx_txq_queue_skb(struct sk_buff *skb, struct rwnx_txq *txq,
(skb_queue_len(&txq->sk_list) > RWNX_NDEV_FLOW_CTRL_STOP)) {
txq->status |= RWNX_TXQ_NDEV_FLOW_CTRL;
netif_stop_subqueue(txq->ndev, txq->ndev_idx);
#ifdef CREATE_TRACE_POINTS
trace_txq_flowctrl_stop(txq);
#endif
}
#else /* ! CONFIG_RWNX_FULLMAC */
@ -1150,9 +1168,9 @@ void rwnx_hwq_process(struct rwnx_hw *rwnx_hw, struct rwnx_hwq *hwq)
struct rwnx_txq *txq, *next;
int user, credit_map = 0;
bool mu_enable;
#ifdef CREATE_TRACE_POINTS
trace_process_hw_queue(hwq);
#endif
hwq->need_processing = false;
mu_enable = rwnx_txq_take_mu_lock(rwnx_hw);
@ -1164,10 +1182,15 @@ void rwnx_hwq_process(struct rwnx_hw *rwnx_hw, struct rwnx_hwq *hwq)
struct sk_buff_head sk_list_push;
struct sk_buff *skb;
bool txq_empty;
#ifdef CREATE_TRACE_POINTS
trace_process_txq(txq);
#endif
/* sanity check for debug */
BUG_ON(!(txq->status & RWNX_TXQ_IN_HWQ_LIST));
if (txq->idx == TXQ_INACTIVE) {
printk("%s txq->idx == TXQ_INACTIVE \r\n", __func__);
continue;
}
BUG_ON(txq->idx == TXQ_INACTIVE);
BUG_ON(txq->credits <= 0);
BUG_ON(!rwnx_txq_skb_ready(txq));
@ -1213,10 +1236,12 @@ void rwnx_hwq_process(struct rwnx_hw *rwnx_hw, struct rwnx_hwq *hwq)
/* restart netdev queue if number of queued buffer is below threshold */
if (unlikely(txq->status & RWNX_TXQ_NDEV_FLOW_CTRL) &&
skb_queue_len(&txq->sk_list) < RWNX_NDEV_FLOW_CTRL_RESTART) {
(skb_queue_len(&txq->sk_list) < RWNX_NDEV_FLOW_CTRL_RESTART)) {
txq->status &= ~RWNX_TXQ_NDEV_FLOW_CTRL;
netif_wake_subqueue(txq->ndev, txq->ndev_idx);
#ifdef CREATE_TRACE_POINTS
trace_txq_flowctrl_restart(txq);
#endif
}
#endif /* CONFIG_RWNX_FULLMAC */
}

View File

@ -6,6 +6,7 @@
static inline void rwnx_print_version(void)
{
printk(RWNX_VERS_BANNER"\n");
printk("Driver Release Tag: %s\n", DRV_RELEASE_TAG);
}
#endif /* _RWNX_VERSION_H_ */

View File

@ -1,3 +1,15 @@
#define RWNX_VERS_REV "241c091M (master)"
#define RWNX_VERS_MOD "20211129-6.4.3.0"
#define RWNX_VERS_REV "241c091M (master)"
#define DRV_RELEASE_DATE "20221108"
#define DRV_PATCH_LEVEL "004"
#define RWNX_VERS_MOD DRV_RELEASE_DATE "-" DRV_PATCH_LEVEL "-6.4.3.0"
#define RWNX_VERS_BANNER "rwnx " RWNX_VERS_MOD " - - " RWNX_VERS_REV
#if defined(AICWF_SDIO_SUPPORT)
#define DRV_TYPE_NAME "sdio"
#elif defined(AICWF_USB_SUPPORT)
#define DRV_TYPE_NAME "usb"
#else
#define DRV_TYPE_NAME "unknow"
#endif
#define DRV_RELEASE_TAG "aic-rwnx-" DRV_TYPE_NAME "-" DRV_RELEASE_DATE "-" DRV_PATCH_LEVEL

View File

@ -0,0 +1,68 @@
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include "rwnx_defs.h"
#include "rwnx_wakelock.h"
struct wakeup_source *rwnx_wakeup_init(const char *name)
{
struct wakeup_source *ws;
ws = wakeup_source_create(name);
wakeup_source_add(ws);
return ws;
}
void rwnx_wakeup_deinit(struct wakeup_source *ws)
{
if (ws && ws->active)
__pm_relax(ws);
wakeup_source_remove(ws);
wakeup_source_destroy(ws);
}
struct wakeup_source *rwnx_wakeup_register(struct device *dev, const char *name)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
return wakeup_source_register(dev, name);
#else
return wakeup_source_register(name);
#endif
}
void rwnx_wakeup_unregister(struct wakeup_source *ws)
{
if (ws && ws->active)
__pm_relax(ws);
wakeup_source_unregister(ws);
}
void rwnx_wakeup_lock(struct wakeup_source *ws)
{
__pm_stay_awake(ws);
}
void rwnx_wakeup_unlock(struct wakeup_source *ws)
{
__pm_relax(ws);
}
void rwnx_wakeup_lock_timeout(struct wakeup_source *ws, unsigned int msec)
{
__pm_wakeup_event(ws, msec);
}
void aicwf_wakeup_lock_init(struct rwnx_hw *rwnx_hw)
{
rwnx_hw->ws_tx = rwnx_wakeup_init("rwnx_tx_wakelock");
rwnx_hw->ws_rx = rwnx_wakeup_init("rwnx_rx_wakelock");
rwnx_hw->ws_pwrctrl = rwnx_wakeup_init("rwnx_pwrcrl_wakelock");
}
void aicwf_wakeup_lock_deinit(struct rwnx_hw *rwnx_hw)
{
rwnx_wakeup_deinit(rwnx_hw->ws_tx);
rwnx_wakeup_deinit(rwnx_hw->ws_rx);
rwnx_wakeup_deinit(rwnx_hw->ws_pwrctrl);
}

View File

@ -0,0 +1,21 @@
#ifndef __RWNX_WAKELOCK_H
#define __RWNX_WAKELOCK_H
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/platform_device.h>
struct wakeup_source *rwnx_wakeup_init(const char *name);
void rwnx_wakeup_deinit(struct wakeup_source *ws);
struct wakeup_source *rwnx_wakeup_register(struct device *dev, const char *name);
void rwnx_wakeup_unregister(struct wakeup_source *ws);
void rwnx_wakeup_lock(struct wakeup_source *ws);
void rwnx_wakeup_unlock(struct wakeup_source *ws);
void rwnx_wakeup_lock_timeout(struct wakeup_source *ws, unsigned int msec);
void aicwf_wakeup_lock_init(struct rwnx_hw *rwnx_hw);
void aicwf_wakeup_lock_deinit(struct rwnx_hw *rwnx_hw);
#endif