|
@@ -552,6 +552,182 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter,
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
+static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter,
|
|
|
+ u32 base_address,
|
|
|
+ u32 instructions_sz,
|
|
|
+ u16 block_size,
|
|
|
+ u8 *ta_firmware)
|
|
|
+{
|
|
|
+ u32 num_blocks, offset, i;
|
|
|
+ u16 msb_address, lsb_address;
|
|
|
+ u8 temp_buf[block_size];
|
|
|
+ int status;
|
|
|
+
|
|
|
+ num_blocks = instructions_sz / block_size;
|
|
|
+ msb_address = base_address >> 16;
|
|
|
+
|
|
|
+ rsi_dbg(INFO_ZONE, "ins_size: %d, num_blocks: %d\n",
|
|
|
+ instructions_sz, num_blocks);
|
|
|
+
|
|
|
+ /* Loading DM ms word in the sdio slave */
|
|
|
+ status = rsi_sdio_master_access_msword(adapter, msb_address);
|
|
|
+ if (status < 0) {
|
|
|
+ rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (offset = 0, i = 0; i < num_blocks; i++, offset += block_size) {
|
|
|
+ memset(temp_buf, 0, block_size);
|
|
|
+ memcpy(temp_buf, ta_firmware + offset, block_size);
|
|
|
+ lsb_address = (u16)base_address;
|
|
|
+ status = rsi_sdio_write_register_multiple
|
|
|
+ (adapter,
|
|
|
+ lsb_address | RSI_SD_REQUEST_MASTER,
|
|
|
+ temp_buf, block_size);
|
|
|
+ if (status < 0) {
|
|
|
+ rsi_dbg(ERR_ZONE, "%s: failed to write\n", __func__);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+ rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i);
|
|
|
+ base_address += block_size;
|
|
|
+
|
|
|
+ if ((base_address >> 16) != msb_address) {
|
|
|
+ msb_address += 1;
|
|
|
+
|
|
|
+ /* Loading DM ms word in the sdio slave */
|
|
|
+ status = rsi_sdio_master_access_msword(adapter,
|
|
|
+ msb_address);
|
|
|
+ if (status < 0) {
|
|
|
+ rsi_dbg(ERR_ZONE,
|
|
|
+ "%s: Unable to set ms word reg\n",
|
|
|
+ __func__);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (instructions_sz % block_size) {
|
|
|
+ memset(temp_buf, 0, block_size);
|
|
|
+ memcpy(temp_buf, ta_firmware + offset,
|
|
|
+ instructions_sz % block_size);
|
|
|
+ lsb_address = (u16)base_address;
|
|
|
+ status = rsi_sdio_write_register_multiple
|
|
|
+ (adapter,
|
|
|
+ lsb_address | RSI_SD_REQUEST_MASTER,
|
|
|
+ temp_buf,
|
|
|
+ instructions_sz % block_size);
|
|
|
+ if (status < 0)
|
|
|
+ return status;
|
|
|
+ rsi_dbg(INFO_ZONE,
|
|
|
+ "Written Last Block in Address 0x%x Successfully\n",
|
|
|
+ offset | RSI_SD_REQUEST_MASTER);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#define FLASH_SIZE_ADDR 0x04000016
|
|
|
+static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
|
|
|
+ u32 *read_buf, u16 size)
|
|
|
+{
|
|
|
+ u32 addr_on_bus, *data;
|
|
|
+ u32 align[2] = {};
|
|
|
+ u16 ms_addr;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ data = PTR_ALIGN(&align[0], 8);
|
|
|
+
|
|
|
+ ms_addr = (addr >> 16);
|
|
|
+ status = rsi_sdio_master_access_msword(adapter, ms_addr);
|
|
|
+ if (status < 0) {
|
|
|
+ rsi_dbg(ERR_ZONE,
|
|
|
+ "%s: Unable to set ms word to common reg\n",
|
|
|
+ __func__);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+ addr &= 0xFFFF;
|
|
|
+
|
|
|
+ addr_on_bus = (addr & 0xFF000000);
|
|
|
+ if ((addr_on_bus == (FLASH_SIZE_ADDR & 0xFF000000)) ||
|
|
|
+ (addr_on_bus == 0x0))
|
|
|
+ addr_on_bus = (addr & ~(0x3));
|
|
|
+ else
|
|
|
+ addr_on_bus = addr;
|
|
|
+
|
|
|
+ /* Bring TA out of reset */
|
|
|
+ status = rsi_sdio_read_register_multiple
|
|
|
+ (adapter,
|
|
|
+ (addr_on_bus | RSI_SD_REQUEST_MASTER),
|
|
|
+ (u8 *)data, 4);
|
|
|
+ if (status < 0) {
|
|
|
+ rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+ if (size == 2) {
|
|
|
+ if ((addr & 0x3) == 0)
|
|
|
+ *read_buf = *data;
|
|
|
+ else
|
|
|
+ *read_buf = (*data >> 16);
|
|
|
+ *read_buf = (*read_buf & 0xFFFF);
|
|
|
+ } else if (size == 1) {
|
|
|
+ if ((addr & 0x3) == 0)
|
|
|
+ *read_buf = *data;
|
|
|
+ else if ((addr & 0x3) == 1)
|
|
|
+ *read_buf = (*data >> 8);
|
|
|
+ else if ((addr & 0x3) == 2)
|
|
|
+ *read_buf = (*data >> 16);
|
|
|
+ else
|
|
|
+ *read_buf = (*data >> 24);
|
|
|
+ *read_buf = (*read_buf & 0xFF);
|
|
|
+ } else {
|
|
|
+ *read_buf = *data;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
|
|
|
+ unsigned long addr,
|
|
|
+ unsigned long data, u16 size)
|
|
|
+{
|
|
|
+ unsigned long data1[2], *data_aligned;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ data_aligned = PTR_ALIGN(&data1[0], 8);
|
|
|
+
|
|
|
+ if (size == 2) {
|
|
|
+ *data_aligned = ((data << 16) | (data & 0xFFFF));
|
|
|
+ } else if (size == 1) {
|
|
|
+ u32 temp_data = data & 0xFF;
|
|
|
+
|
|
|
+ *data_aligned = ((temp_data << 24) | (temp_data << 16) |
|
|
|
+ (temp_data << 8) | temp_data);
|
|
|
+ } else {
|
|
|
+ *data_aligned = data;
|
|
|
+ }
|
|
|
+ size = 4;
|
|
|
+
|
|
|
+ status = rsi_sdio_master_access_msword(adapter, (addr >> 16));
|
|
|
+ if (status < 0) {
|
|
|
+ rsi_dbg(ERR_ZONE,
|
|
|
+ "%s: Unable to set ms word to common reg\n",
|
|
|
+ __func__);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ addr = addr & 0xFFFF;
|
|
|
+
|
|
|
+ /* Bring TA out of reset */
|
|
|
+ status = rsi_sdio_write_register_multiple
|
|
|
+ (adapter,
|
|
|
+ (addr | RSI_SD_REQUEST_MASTER),
|
|
|
+ (u8 *)data_aligned, size);
|
|
|
+ if (status < 0) {
|
|
|
+ rsi_dbg(ERR_ZONE,
|
|
|
+ "%s: Unable to do AHB reg write\n", __func__);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* rsi_sdio_host_intf_write_pkt() - This function writes the packet to device.
|
|
|
* @adapter: Pointer to the adapter structure.
|
|
@@ -694,6 +870,9 @@ static struct rsi_host_intf_ops sdio_host_intf_ops = {
|
|
|
.read_pkt = rsi_sdio_host_intf_read_pkt,
|
|
|
.read_reg_multiple = rsi_sdio_read_register_multiple,
|
|
|
.write_reg_multiple = rsi_sdio_write_register_multiple,
|
|
|
+ .master_reg_read = rsi_sdio_master_reg_read,
|
|
|
+ .master_reg_write = rsi_sdio_master_reg_write,
|
|
|
+ .load_data_master_write = rsi_sdio_load_data_master_write,
|
|
|
};
|
|
|
|
|
|
/**
|