Files
luban-lite/bsp/peripheral/wireless/atbm603x/hal/sdio/atbm_sdio_fwio.c
刘可亮 8bca5e8332 v1.0.4
2024-04-03 16:40:57 +08:00

449 lines
12 KiB
C

/**************************************************************************************************************
* altobeam RTOS wifi hmac source code
*
* Copyright (c) 2018, altobeam.inc All rights reserved.
*
* The source code contains proprietary information of AltoBeam, and shall not be distributed,
* copied, reproduced, or disclosed in whole or in part without prior written permission of AltoBeam.
*****************************************************************************************************************/
#include "atbm_hal.h"
#include "atbm_sdio.h"
#include "atbm_sdio_hwio.h"
#include "atbm_sdio_fwio.h"
#include "atbm_sdio_bh.h"
#if (PROJ_TYPE == ATHENA_LITE)
#include "firmware_lite.h"
#elif (PROJ_TYPE == ATHENA_B)
#if ATBM_TX_SKB_NO_TXCONFIRM
#include "firmware_athenaB_sdio_notxconfirm.h"
#else //ATBM_TX_SKB_NO_TXCONFIRM
#include "firmware_athenaB_sdio.h"
#endif //ATBM_TX_SKB_NO_TXCONFIRM
#elif (PROJ_TYPE == ARES_A || PROJ_TYPE == ARES_B)
#if ATBM_TX_SKB_NO_TXCONFIRM
#include "firmware_ares_sdio_notxconfirm.h"
#else
#include "firmware_ares_sdio.h"
#endif
#elif (PROJ_TYPE == HERA)
#if ATBM_TX_SKB_NO_TXCONFIRM
#include "firmware_hera_sdio_notxconfirm.h"
#else
#include "firmware_hera_sdio.h"
#endif
#elif (PROJ_TYPE == ASMLITE)
#if CONFIG_WIFI_BT_COMB
#include "firmware_asmlite_sdio_combo_notxconfirm.h"
#else
#include "firmware_asmlite_sdio_notxconfirm.h"
#endif
#else
#error error, project type is invalid.
#endif //ATHENA_LITE
static struct firmware_altobeam fw_altobeam;
extern int atbm_reg_read_32(struct atbmwifi_common *hw_priv, atbm_uint16 addr, atbm_uint32 *val);
extern int atbm_reg_write_32(struct atbmwifi_common *hw_priv, atbm_uint16 addr, atbm_uint32 val);
extern int atbm_reg_read_16(struct atbmwifi_common *hw_priv, atbm_uint16 addr, atbm_uint16 *val);
extern int atbm_reg_write_16(struct atbmwifi_common *hw_priv, atbm_uint16 addr, atbm_uint16 val);
extern int atbm_ahb_read_32(struct atbmwifi_common *hw_priv, atbm_uint32 addr, atbm_uint32 *val);
extern int atbm_ahb_write_32(struct atbmwifi_common *hw_priv, atbm_uint32 addr, atbm_uint32 val);
atbm_void atbm_release_firmware(atbm_void)
{
wifi_printk(WIFI_ALWAYS,"atbm_release_firmware\n");
}
int atbm_init_firmware(atbm_void)
{
wifi_printk(WIFI_ALWAYS,"atbm_init_firmware\n");
atbm_memset(&fw_altobeam,0,sizeof(struct firmware_altobeam));
return 0;
}
int atbm_before_load_firmware(struct atbmwifi_common *hw_priv)
{
int ret=0;
int i;
atbm_uint32 val32;
atbm_uint16 val16;
//int major_revision;
atbm_uint32 config_reg;
ATBM_BUG_ON(!hw_priv);
/* Read CONFIG Register Value - We will read 32 bits */
ret = atbm_reg_read_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID, &val32);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: can't read config register.\n", __FUNCTION__);
goto out;
}
/* Set wakeup bit in device */
ret = atbm_reg_read_16(hw_priv, ATBM_HIFREG_CONTROL_REG_ID, &val16);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: set_wakeup: can't read " \
"control register.\n", __FUNCTION__);
goto out;
}
ret = atbm_reg_write_16(hw_priv, ATBM_HIFREG_CONTROL_REG_ID,
val16 | ATBM_HIFREG_CONT_WUP_BIT);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: set_wakeup: can't write " \
"control register.\n", __FUNCTION__);
goto out;
}
#if TEST_DCXO_DPLL_CONFIG
/*start config dcxo */
ret=atbm_config_dcxo(hw_priv,dcxo_value,PROJ_TYPE,DCXO_TYPE,DPLL_CLOCK);
if (ret<0){
wifi_printk(WIFI_IF, "atbm_config_dcxo error.\n");
}
/*start config dpll */
ret = atbm_config_dpll(hw_priv,dpll_value,PROJ_TYPE,DPLL_CLOCK);
if (ret<0){
wifi_printk(WIFI_IF, "atbm_config_dpll error.\n");
}
/*The fifth step store dpll value to smu*/
atbm_set_config_to_smu(hw_priv,DPLL_CLOCK);
/*start shut down system*/
ret =atbm_system_done(hw_priv);
if (ret<0){
wifi_printk(WIFI_IF, "atbm_system_done error.\n");
}
wifi_printk(WIFI_IF, "atbm_wait_wlan_rdy Wait for wakeup .\n");
/* Set wakeup bit in device */
ret = atbm_reg_read_16(hw_priv, ATBM_HIFREG_CONTROL_REG_ID, &val16);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: set_wakeup: can't read " \
"control register.\n", __FUNCTION__);
goto out;
}
ret = atbm_reg_write_16(hw_priv, ATBM_HIFREG_CONTROL_REG_ID,
val16 | ATBM_HIFREG_CONT_WUP_BIT);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: set_wakeup: can't write " \
"control register.\n", __FUNCTION__);
goto out;
}
#endif
/* Wait for wakeup */
for (i = 0 ; i < 3000 ; i += 1 + i / 2) {
ret = atbm_reg_read_16(hw_priv,
ATBM_HIFREG_CONTROL_REG_ID, &val16);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: wait_for_wakeup: can't read " \
"control register.\n", __FUNCTION__);
goto out;
}
if (val16 & ATBM_HIFREG_CONT_RDY_BIT) {
wifi_printk(WIFI_IF,
"WLAN device is ready.\n");
break;
}
atbm_mdelay(i);
}
if ((val16 & ATBM_HIFREG_CONT_RDY_BIT) == 0) {
wifi_printk(WIFI_IF,
"%s: wait_for_wakeup: device is not responding.\n",
__FUNCTION__);
ret = -ATBM_ETIMEDOUT;
goto out;
}
atbm_reg_read_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID, &config_reg);
if(config_reg & ATBM_HIFREG_PS_SYNC_SDIO_FLAG)
{
config_reg |= ATBM_HIFREG_PS_SYNC_SDIO_CLEAN;
atbm_reg_write_32(hw_priv,ATBM_HIFREG_CONFIG_REG_ID,config_reg);
}
/* set cpu reset ,cpu will stop */
/* Checking for access mode */
ret = atbm_reg_read_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID, &val32);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: enable_irq: can't read " \
"config register.\n", __FUNCTION__);
goto out;
}
val32 |= ATBM_HIFREG_CONFIG_CPU_RESET_BIT|ATBM_HIFREG_CONFIG_ACCESS_MODE_BIT;
ret = atbm_reg_write_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID,val32);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: enable_irq: can't write " \
"config register.\n", __FUNCTION__);
goto out;
}
ret = atbm_reg_read_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID, &val32);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: enable_irq: can't read " \
"config register.\n", __FUNCTION__);
goto out;
}
ATBM_WARN_ON_FUNC(!(val32 & ATBM_HIFREG_CONFIG_ACCESS_MODE_BIT));
out:
return ret;
}
static int atbm_load_firmware_generic(struct atbmwifi_common *priv, atbm_uint8 *data,atbm_uint32 size,atbm_uint32 addr)
{
int ret=0;
atbm_uint32 put = 0;
atbm_uint8 *buf = ATBM_NULL;
buf = (atbm_uint8 *)atbm_kmalloc(DOWNLOAD_BLOCK_SIZE*2,GFP_KERNEL);
if (!buf) {
wifi_printk(WIFI_DBG_ERROR,
"%s: can't allocate bootloader buffer.\n", __FUNCTION__);
ret = -ATBM_ENOMEM;
goto error;
}
//if(priv->sbus_ops->bootloader_debug_config)
// priv->sbus_ops->bootloader_debug_config(priv->sbus_priv,0);
/* downloading loop */
wifi_printk(WIFI_ALWAYS,"%s: addr %x: len %x\n",__FUNCTION__,addr,size);
for (put = 0; put < size ;put += DOWNLOAD_BLOCK_SIZE) {
atbm_uint32 tx_size;
/* calculate the block size */
tx_size = atbm_min((size - put),(atbm_uint32)DOWNLOAD_BLOCK_SIZE);
atbm_memcpy(buf, &data[put], tx_size);
/* send the block to sram */
ret = atbm_fw_write(priv,put+addr,buf, tx_size);
if (ret < 0) {
wifi_printk(WIFI_DBG_ERROR,
"%s: can't write block at line %d.\n",
__FUNCTION__, __LINE__);
goto error;
}
} /* End of bootloader download loop */
error:
atbm_kfree(buf);
return ret;
}
static int atbm_start_load_firmware(struct atbmwifi_common *priv)
{
int ret;
struct firmware_headr* hdr = (struct firmware_headr*)firmware_headr;
wifi_printk(WIFI_DBG_ERROR,"%s: used firmware.h=\n", __FUNCTION__);
fw_altobeam.hdr.iccm_len = sizeof(fw_code);
fw_altobeam.hdr.dccm_len = sizeof(fw_data);
fw_altobeam.fw_iccm = &fw_code[0];
fw_altobeam.fw_dccm = &fw_data[0];
#if CONFIG_WIFI_BT_COMB
fw_altobeam.hdr.sram_len = sizeof(fw_sram);
if (hdr->flags == ALTOBEAM_WIFI_HDR_FLAG_V2)
fw_altobeam.hdr.sram_addr = hdr->sram_addr;
else
fw_altobeam.hdr.sram_addr = DOWNLOAD_BLE_SRAM_ADDR;
fw_altobeam.fw_sram = &fw_sram[0];
#endif
wifi_printk(WIFI_DBG_ERROR,"%s: START DOWNLOAD ICCM=========\n", __FUNCTION__);
ret = atbm_load_firmware_generic(priv,fw_altobeam.fw_iccm,fw_altobeam.hdr.iccm_len,DOWNLOAD_ITCM_ADDR);
if(ret<0)
goto error;
if(fw_altobeam.hdr.dccm_len > 0x9000)
fw_altobeam.hdr.dccm_len = 0x9000;
wifi_printk(WIFI_DBG_ERROR,"%s: START DOWNLOAD DCCM=========\n", __FUNCTION__);
ret = atbm_load_firmware_generic(priv,fw_altobeam.fw_dccm,fw_altobeam.hdr.dccm_len,DOWNLOAD_DTCM_ADDR);
if(ret<0)
goto error;
#if CONFIG_WIFI_BT_COMB
if(fw_altobeam.hdr.sram_len){
wifi_printk(WIFI_DBG_ERROR,"START DOWNLOAD BLE SRAM=========\n");
ret = atbm_load_firmware_generic(priv, fw_altobeam.fw_sram, fw_altobeam.hdr.sram_len, fw_altobeam.hdr.sram_addr);
if(ret<0)
goto error;
}
#endif
wifi_printk(WIFI_DBG_ERROR, "%s: FIRMWARE DOWNLOAD SUCCESS\n",__FUNCTION__);
error:
return ret;
}
//atbm_initial_irq
int atbm_after_load_firmware(struct atbmwifi_common *hw_priv)
{
int ret;
atbm_uint32 val32;
//enable gpio irq register,may need move to lmac/apb.c SMU_Init
ret=atbm_ahb_read_32(hw_priv,0x161000ac,&val32);
val32&=0xFFFFF7F8;
val32|=BIT(12);
ret=atbm_ahb_write_32(hw_priv,0x161000ac,val32);
if(ret<0){
wifi_printk(WIFI_IF,
"%s: enable_irq: can't read " \
"config register.\n", __FUNCTION__);
}
/* Register Interrupt Handler */
ret = hw_priv->sbus_ops->irq_subscribe(hw_priv->sbus_priv,
(sbus_irq_handler)atbm_irq_handler, hw_priv);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: can't register IRQ handler.\n", __FUNCTION__);
}
#if (PROJ_TYPE>=ARES_A)
ret=atbm_ahb_read_32(hw_priv,0x1610102c,&val32);
if(ret<0){
wifi_printk(WIFI_DBG_ERROR,
"%s: 0x1610102c: can't read register.\n", __func__);
goto out;
}
val32 &= ~(0xffff0000);
val32 |= BIT(0) | BIT(1) | (0x1 << 16);
ret=atbm_ahb_write_32(hw_priv,0x1610102c,val32);
if(ret<0){
wifi_printk(WIFI_DBG_ERROR,
"%s: 0x1610102c: can't write register.\n", __func__);
goto out;
}
while(1)
{
ret=atbm_ahb_read_32(hw_priv,0x1610102c,&val32);
if(ret<0){
wifi_printk(WIFI_DBG_ERROR,
"%s: 0x1610102c: can't read register.\n", __func__);
goto out;
}
if (val32 & BIT(16))
break;
atbm_mdelay(1);
}
#endif
/* If device is CW1200 the IRQ enable/disable bits
* are in CONFIG register, clear cpu reset ,cpu will run */
ret = atbm_reg_read_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID, &val32);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: enable_irq: can't read " \
"config register.\n", __FUNCTION__);
goto unsubscribe;
}
val32 |= ATBM_HIFREG_CONF_IRQ_RDY_ENABLE;
val32 &= ~ATBM_HIFREG_CONFIG_CPU_RESET_BIT;
//enable data1 IRQ
val32 &= ~ATBM_HIFREG_CONFIG_CLEAR_INT_BIT;
ret = atbm_reg_write_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID,val32);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: enable_irq: can't write " \
"config register.\n", __FUNCTION__);
goto unsubscribe;
}
#if (PROJ_TYPE==ARES_B)
ret=atbm_ahb_write_32(hw_priv,0x16100074,0x1);
if(ret<0){
wifi_printk(WIFI_DBG_ERROR,
"%s: 0x1610102c: can't write register.\n", __func__);
goto out;
}
#endif
/* Configure device for MESSSAGE MODE */
ret = atbm_reg_read_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID, &val32);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: set_mode: can't read config register.\n",
__FUNCTION__);
goto unsubscribe;
}
ret = atbm_reg_write_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID,
val32 & ~ATBM_HIFREG_CONFIG_ACCESS_MODE_BIT);
if (ret < 0) {
wifi_printk(WIFI_IF,
"%s: set_mode: can't write config register.\n",
__FUNCTION__);
goto unsubscribe;
}
hw_priv->init_done = 1;
/* Unless we read the CONFIG Register we are
* not able to get an interrupt */
atbm_mdelay(10);
atbm_reg_read_32(hw_priv, ATBM_HIFREG_CONFIG_REG_ID, &val32);
out:
return ret;
unsubscribe:
hw_priv->sbus_ops->irq_unsubscribe(hw_priv->sbus_priv);
return ret;
}
atbm_void atbm_firmware_init_check(struct atbmwifi_common *hw_priv)
{
atbm_uint16 ctrl_reg;
ATBM_WARN_ON(atbm_reg_write_16(hw_priv, ATBM_HIFREG_CONTROL_REG_ID,
ATBM_HIFREG_CONT_WUP_BIT));
if (atbm_reg_read_16(hw_priv,ATBM_HIFREG_CONTROL_REG_ID, &ctrl_reg))
ATBM_WARN_ON(atbm_reg_read_16(hw_priv,ATBM_HIFREG_CONTROL_REG_ID,
&ctrl_reg));
ATBM_WARN_ON_FUNC(!(ctrl_reg & ATBM_HIFREG_CONT_RDY_BIT));
}
int atbm_load_firmware(struct atbmwifi_common *hw_priv)
{
int ret;
wifi_printk(WIFI_ALWAYS,"atbm_before_load_firmware++\n");
ret = atbm_before_load_firmware(hw_priv);
if(ret <0)
goto out;
wifi_printk(WIFI_ALWAYS,"atbm_start_load_firmware++\n");
ret = atbm_start_load_firmware(hw_priv);
if(ret <0)
goto out;
wifi_printk(WIFI_ALWAYS,"atbm_after_load_firmware++\n");
ret = atbm_after_load_firmware(hw_priv);
if(ret <0){
goto out;
}
ret =0;
out:
return ret;
}