Commit e5a1ecc9 authored by Siva Rebbagondla's avatar Siva Rebbagondla Committed by Kalle Valo

rsi: add firmware loading for 9116 device

New firmware files and firmware loading method are added for 9116.
Signed-off-by: default avatarSiva Rebbagondla <siva8118@gmail.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 3ac61578
...@@ -31,6 +31,13 @@ static struct ta_metadata metadata_flash_content[] = { ...@@ -31,6 +31,13 @@ static struct ta_metadata metadata_flash_content[] = {
}; };
static struct ta_metadata metadata[] = {{"pmemdata_dummy", 0x00000000},
{"rsi/rs9116_wlan.rps", 0x00000000},
{"rsi/rs9116_wlan_bt_classic.rps", 0x00000000},
{"rsi/pmemdata_dummy", 0x00000000},
{"rsi/rs9116_wlan_bt_classic.rps", 0x00000000}
};
int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb) int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
{ {
struct rsi_hw *adapter = common->priv; struct rsi_hw *adapter = common->priv;
...@@ -989,6 +996,133 @@ static int rsi_load_9113_firmware(struct rsi_hw *adapter) ...@@ -989,6 +996,133 @@ static int rsi_load_9113_firmware(struct rsi_hw *adapter)
return status; return status;
} }
static int rsi_load_9116_firmware(struct rsi_hw *adapter)
{
struct rsi_common *common = adapter->priv;
struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
const struct firmware *fw_entry;
struct ta_metadata *metadata_p;
u8 *ta_firmware, *fw_p;
struct bootload_ds bootload_ds;
u32 instructions_sz, base_address;
u16 block_size = adapter->block_size;
u32 dest, len;
int status, cnt;
rsi_dbg(INIT_ZONE, "***** Load 9116 TA Instructions *****\n");
if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
status = bl_cmd(adapter, POLLING_MODE, CMD_PASS,
"POLLING_MODE");
if (status < 0)
return status;
}
status = hif_ops->master_reg_write(adapter, MEM_ACCESS_CTRL_FROM_HOST,
RAM_384K_ACCESS_FROM_TA,
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "%s: Unable to access full RAM memory\n",
__func__);
return status;
}
metadata_p = &metadata[adapter->priv->coex_mode];
rsi_dbg(INIT_ZONE, "%s: loading file %s\n", __func__, metadata_p->name);
status = request_firmware(&fw_entry, metadata_p->name, adapter->device);
if (status < 0) {
rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n",
__func__, metadata_p->name);
return status;
}
ta_firmware = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
if (!ta_firmware)
goto fail_release_fw;
fw_p = ta_firmware;
instructions_sz = fw_entry->size;
rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", instructions_sz);
common->lmac_ver.major = ta_firmware[LMAC_VER_OFFSET_9116];
common->lmac_ver.minor = ta_firmware[LMAC_VER_OFFSET_9116 + 1];
common->lmac_ver.release_num = ta_firmware[LMAC_VER_OFFSET_9116 + 2];
common->lmac_ver.patch_num = ta_firmware[LMAC_VER_OFFSET_9116 + 3];
common->lmac_ver.ver.info.fw_ver[0] =
ta_firmware[LMAC_VER_OFFSET_9116 + 4];
if (instructions_sz % FW_ALIGN_SIZE)
instructions_sz +=
(FW_ALIGN_SIZE - (instructions_sz % FW_ALIGN_SIZE));
rsi_dbg(INFO_ZONE, "instructions_sz : %d\n", instructions_sz);
if (*(u16 *)fw_p == RSI_9116_FW_MAGIC_WORD) {
memcpy(&bootload_ds, fw_p, sizeof(struct bootload_ds));
fw_p += le16_to_cpu(bootload_ds.offset);
rsi_dbg(INFO_ZONE, "FW start = %x\n", *(u32 *)fw_p);
cnt = 0;
do {
rsi_dbg(ERR_ZONE, "%s: Loading chunk %d\n",
__func__, cnt);
dest = le32_to_cpu(bootload_ds.bl_entry[cnt].dst_addr);
len = le32_to_cpu(bootload_ds.bl_entry[cnt].control) &
RSI_BL_CTRL_LEN_MASK;
rsi_dbg(INFO_ZONE, "length %d destination %x\n",
len, dest);
status = hif_ops->load_data_master_write(adapter, dest,
len,
block_size,
fw_p);
if (status < 0) {
rsi_dbg(ERR_ZONE,
"Failed to load chunk %d\n", cnt);
break;
}
fw_p += len;
if (le32_to_cpu(bootload_ds.bl_entry[cnt].control) &
RSI_BL_CTRL_LAST_ENTRY)
break;
cnt++;
} while (1);
} else {
base_address = metadata_p->address;
status = hif_ops->load_data_master_write(adapter,
base_address,
instructions_sz,
block_size,
ta_firmware);
}
if (status) {
rsi_dbg(ERR_ZONE,
"%s: Unable to load %s blk\n",
__func__, metadata_p->name);
goto fail_free_fw;
}
rsi_dbg(INIT_ZONE, "%s: Successfully loaded %s instructions\n",
__func__, metadata_p->name);
if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO) {
if (hif_ops->ta_reset(adapter))
rsi_dbg(ERR_ZONE, "Unable to put ta in reset\n");
} else {
if (bl_cmd(adapter, JUMP_TO_ZERO_PC,
CMD_PASS, "JUMP_TO_ZERO") < 0)
rsi_dbg(INFO_ZONE, "Jump to zero command failed\n");
else
rsi_dbg(INFO_ZONE, "Jump to zero command successful\n");
}
fail_free_fw:
kfree(ta_firmware);
fail_release_fw:
release_firmware(fw_entry);
return status;
}
int rsi_hal_device_init(struct rsi_hw *adapter) int rsi_hal_device_init(struct rsi_hw *adapter)
{ {
struct rsi_common *common = adapter->priv; struct rsi_common *common = adapter->priv;
...@@ -1006,6 +1140,17 @@ int rsi_hal_device_init(struct rsi_hw *adapter) ...@@ -1006,6 +1140,17 @@ int rsi_hal_device_init(struct rsi_hw *adapter)
return -EINVAL; return -EINVAL;
} }
break; break;
case RSI_DEV_9116:
status = rsi_hal_prepare_fwload(adapter);
if (status < 0)
return status;
if (rsi_load_9116_firmware(adapter)) {
rsi_dbg(ERR_ZONE,
"%s: Failed to load firmware to 9116 device\n",
__func__);
return -EINVAL;
}
break;
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -923,6 +923,70 @@ static int rsi_sdio_reinit_device(struct rsi_hw *adapter) ...@@ -923,6 +923,70 @@ static int rsi_sdio_reinit_device(struct rsi_hw *adapter)
return 0; return 0;
} }
static int rsi_sdio_ta_reset(struct rsi_hw *adapter)
{
int status;
u32 addr;
u8 *data;
status = rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR);
if (status < 0) {
rsi_dbg(ERR_ZONE,
"Unable to set ms word to common reg\n");
return status;
}
rsi_dbg(INIT_ZONE, "%s: Bring TA out of reset\n", __func__);
put_unaligned_le32(TA_HOLD_THREAD_VALUE, data);
addr = TA_HOLD_THREAD_REG | RSI_SD_REQUEST_MASTER;
status = rsi_sdio_write_register_multiple(adapter, addr,
(u8 *)&data,
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to hold TA threads\n");
return status;
}
put_unaligned_le32(TA_SOFT_RST_CLR, data);
addr = TA_SOFT_RESET_REG | RSI_SD_REQUEST_MASTER;
status = rsi_sdio_write_register_multiple(adapter, addr,
(u8 *)&data,
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to get TA out of reset\n");
return status;
}
put_unaligned_le32(TA_PC_ZERO, data);
addr = TA_TH0_PC_REG | RSI_SD_REQUEST_MASTER;
status = rsi_sdio_write_register_multiple(adapter, addr,
(u8 *)&data,
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to Reset TA PC value\n");
return -EINVAL;
}
put_unaligned_le32(TA_RELEASE_THREAD_VALUE, data);
addr = TA_RELEASE_THREAD_REG | RSI_SD_REQUEST_MASTER;
status = rsi_sdio_write_register_multiple(adapter, addr,
(u8 *)&data,
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to release TA threads\n");
return status;
}
status = rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to set ms word to common reg\n");
return status;
}
rsi_dbg(INIT_ZONE, "***** TA Reset done *****\n");
return 0;
}
static struct rsi_host_intf_ops sdio_host_intf_ops = { static struct rsi_host_intf_ops sdio_host_intf_ops = {
.write_pkt = rsi_sdio_host_intf_write_pkt, .write_pkt = rsi_sdio_host_intf_write_pkt,
.read_pkt = rsi_sdio_host_intf_read_pkt, .read_pkt = rsi_sdio_host_intf_read_pkt,
...@@ -933,6 +997,7 @@ static struct rsi_host_intf_ops sdio_host_intf_ops = { ...@@ -933,6 +997,7 @@ static struct rsi_host_intf_ops sdio_host_intf_ops = {
.master_reg_write = rsi_sdio_master_reg_write, .master_reg_write = rsi_sdio_master_reg_write,
.load_data_master_write = rsi_sdio_load_data_master_write, .load_data_master_write = rsi_sdio_load_data_master_write,
.reinit_device = rsi_sdio_reinit_device, .reinit_device = rsi_sdio_reinit_device,
.ta_reset = rsi_sdio_ta_reset,
}; };
/** /**
......
...@@ -114,8 +114,17 @@ ...@@ -114,8 +114,17 @@
#define FW_FLASH_OFFSET 0x820 #define FW_FLASH_OFFSET 0x820
#define LMAC_VER_OFFSET_9113 (FW_FLASH_OFFSET + 0x200) #define LMAC_VER_OFFSET_9113 (FW_FLASH_OFFSET + 0x200)
#define LMAC_VER_OFFSET_9116 0x22C2
#define MAX_DWORD_ALIGN_BYTES 64 #define MAX_DWORD_ALIGN_BYTES 64
#define RSI_COMMON_REG_SIZE 2 #define RSI_COMMON_REG_SIZE 2
#define RSI_9116_REG_SIZE 4
#define FW_ALIGN_SIZE 4
#define RSI_9116_FW_MAGIC_WORD 0x5aa5
#define MEM_ACCESS_CTRL_FROM_HOST 0x41300000
#define RAM_384K_ACCESS_FROM_TA (BIT(2) | BIT(3) | BIT(4) | BIT(5) | \
BIT(20) | BIT(21) | BIT(22) | \
BIT(23) | BIT(24) | BIT(25))
struct bl_header { struct bl_header {
__le32 flags; __le32 flags;
...@@ -130,6 +139,24 @@ struct ta_metadata { ...@@ -130,6 +139,24 @@ struct ta_metadata {
unsigned int address; unsigned int address;
}; };
#define RSI_BL_CTRL_LEN_MASK 0xFFFFFF
#define RSI_BL_CTRL_SPI_32BIT_MODE BIT(27)
#define RSI_BL_CTRL_REL_TA_SOFTRESET BIT(28)
#define RSI_BL_CTRL_START_FROM_ROM_PC BIT(29)
#define RSI_BL_CTRL_SPI_8BIT_MODE BIT(30)
#define RSI_BL_CTRL_LAST_ENTRY BIT(31)
struct bootload_entry {
__le32 control;
__le32 dst_addr;
} __packed;
struct bootload_ds {
__le16 fixed_pattern;
__le16 offset;
__le32 reserved;
struct bootload_entry bl_entry[7];
} __packed;
struct rsi_mgmt_desc { struct rsi_mgmt_desc {
__le16 len_qno; __le16 len_qno;
u8 frame_type; u8 frame_type;
......
...@@ -385,6 +385,7 @@ struct rsi_host_intf_ops { ...@@ -385,6 +385,7 @@ struct rsi_host_intf_ops {
u32 instructions_size, u16 block_size, u32 instructions_size, u16 block_size,
u8 *fw); u8 *fw);
int (*reinit_device)(struct rsi_hw *adapter); int (*reinit_device)(struct rsi_hw *adapter);
int (*ta_reset)(struct rsi_hw *adapter);
}; };
enum rsi_host_intf rsi_get_host_intf(void *priv); enum rsi_host_intf rsi_get_host_intf(void *priv);
......
...@@ -92,7 +92,7 @@ enum sdio_interrupt_type { ...@@ -92,7 +92,7 @@ enum sdio_interrupt_type {
#define TA_SOFT_RST_SET BIT(0) #define TA_SOFT_RST_SET BIT(0)
#define TA_PC_ZERO 0 #define TA_PC_ZERO 0
#define TA_HOLD_THREAD_VALUE 0xF #define TA_HOLD_THREAD_VALUE 0xF
#define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF) #define TA_RELEASE_THREAD_VALUE 0xF
#define TA_BASE_ADDR 0x2200 #define TA_BASE_ADDR 0x2200
#define MISC_CFG_BASE_ADDR 0x4105 #define MISC_CFG_BASE_ADDR 0x4105
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment