diff options
author | Prameela Rani Garnepudi <prameela.j04cs@gmail.com> | 2017-05-16 13:01:15 +0300 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2017-05-24 16:37:52 +0300 |
commit | b97e9b94ad75caf8d9fcb6a20cd1e3d7f1e67ae8 (patch) | |
tree | 80e619940b0476a071e7986fea2c7c8f90b02d8b /drivers/net/wireless/rsi/rsi_91x_sdio.c | |
parent | a2ce952c8e09eb36e3f1da0c2dbe8b41c7b8297c (diff) | |
download | linux-b97e9b94ad75caf8d9fcb6a20cd1e3d7f1e67ae8.tar.xz |
rsi: Add new host interface operations
Host interface opearation master_reg_read, master_reg_write and
load_data_master_write are added. These functions are needed for the
new firmware loading method. As part of this, the function
master_access_msword is moved from rsi_91x_sdio_ops.c to rsi_91x_sdio.c.
Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/rsi/rsi_91x_sdio.c')
-rw-r--r-- | drivers/net/wireless/rsi/rsi_91x_sdio.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index bdbec8b27071..b397e2c2059d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -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, }; /** |