Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+145 −0
Original line number Diff line number Diff line
@@ -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)
{
	struct rsi_hw *adapter = common->priv;
@@ -989,6 +996,133 @@ static int rsi_load_9113_firmware(struct rsi_hw *adapter)
	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)
{
	struct rsi_common *common = adapter->priv;
@@ -1006,6 +1140,17 @@ int rsi_hal_device_init(struct rsi_hw *adapter)
			return -EINVAL;
		}
		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:
		return -EINVAL;
	}
+65 −0
Original line number Diff line number Diff line
@@ -923,6 +923,70 @@ static int rsi_sdio_reinit_device(struct rsi_hw *adapter)
	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 = {
	.write_pkt		= rsi_sdio_host_intf_write_pkt,
	.read_pkt		= rsi_sdio_host_intf_read_pkt,
@@ -933,6 +997,7 @@ static struct rsi_host_intf_ops sdio_host_intf_ops = {
	.master_reg_write	= rsi_sdio_master_reg_write,
	.load_data_master_write	= rsi_sdio_load_data_master_write,
	.reinit_device          = rsi_sdio_reinit_device,
	.ta_reset		= rsi_sdio_ta_reset,
};

/**
+27 −0
Original line number Diff line number Diff line
@@ -114,8 +114,17 @@

#define FW_FLASH_OFFSET			0x820
#define LMAC_VER_OFFSET_9113		(FW_FLASH_OFFSET + 0x200)
#define LMAC_VER_OFFSET_9116		0x22C2
#define MAX_DWORD_ALIGN_BYTES		64
#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 {
	__le32 flags;
@@ -130,6 +139,24 @@ struct ta_metadata {
	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 {
	__le16 len_qno;
	u8 frame_type;
+1 −0
Original line number Diff line number Diff line
@@ -385,6 +385,7 @@ struct rsi_host_intf_ops {
				      u32 instructions_size, u16 block_size,
				      u8 *fw);
	int (*reinit_device)(struct rsi_hw *adapter);
	int (*ta_reset)(struct rsi_hw *adapter);
};

enum rsi_host_intf rsi_get_host_intf(void *priv);
+1 −1
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ enum sdio_interrupt_type {
#define TA_SOFT_RST_SET              BIT(0)
#define TA_PC_ZERO                   0
#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 MISC_CFG_BASE_ADDR           0x4105