diff options
Diffstat (limited to 'drivers/net/wireless/rsi/rsi_91x_sdio.c')
| -rw-r--r-- | drivers/net/wireless/rsi/rsi_91x_sdio.c | 228 | 
1 files changed, 212 insertions, 16 deletions
| diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 8428858204a6..e5ea99bb2dd8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -18,6 +18,7 @@  #include <linux/module.h>  #include "rsi_sdio.h"  #include "rsi_common.h" +#include "rsi_hal.h"  /**   * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg. @@ -138,6 +139,8 @@ static void rsi_handle_interrupt(struct sdio_func *function)  {  	struct rsi_hw *adapter = sdio_get_drvdata(function); +	if (adapter->priv->fsm_state == FSM_FW_NOT_LOADED) +		return;  	sdio_release_host(function);  	rsi_interrupt_handler(adapter);  	sdio_claim_host(function); @@ -365,6 +368,7 @@ static int rsi_setblocklength(struct rsi_hw *adapter, u32 length)  	status = sdio_set_block_size(dev->pfunction, length);  	dev->pfunction->max_blksize = 256; +	adapter->block_size = dev->pfunction->max_blksize;  	rsi_dbg(INFO_ZONE,  		"%s: Operational blk length is %d\n", __func__, length); @@ -487,8 +491,8 @@ void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit)   */  static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter,  					   u32 addr, -					   u32 count, -					   u8 *data) +					   u8 *data, +					   u16 count)  {  	struct rsi_91x_sdiodev *dev =  		(struct rsi_91x_sdiodev *)adapter->rsi_dev; @@ -518,7 +522,7 @@ static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter,  int rsi_sdio_write_register_multiple(struct rsi_hw *adapter,  				     u32 addr,  				     u8 *data, -				     u32 count) +				     u16 count)  {  	struct rsi_91x_sdiodev *dev =  		(struct rsi_91x_sdiodev *)adapter->rsi_dev; @@ -552,6 +556,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. @@ -614,8 +794,8 @@ int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter,  	status = rsi_sdio_read_register_multiple(adapter,  						 length, -						 length, /*num of bytes*/ -						 (u8 *)pkt); +						 (u8 *)pkt, +						 length); /*num of bytes*/  	if (status)  		rsi_dbg(ERR_ZONE, "%s: Failed to read frame: %d\n", __func__, @@ -676,8 +856,6 @@ static int rsi_init_sdio_interface(struct rsi_hw *adapter,  	}  	sdio_release_host(pfunction); -	adapter->host_intf_write_pkt = rsi_sdio_host_intf_write_pkt; -	adapter->host_intf_read_pkt = rsi_sdio_host_intf_read_pkt;  	adapter->determine_event_timeout = rsi_sdio_determine_event_timeout;  	adapter->check_hw_queue_status = rsi_sdio_read_buffer_status_register; @@ -691,6 +869,17 @@ fail:  	return status;  } +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, +	.master_access_msword	= rsi_sdio_master_access_msword, +	.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, +}; +  /**   * rsi_probe() - This function is called by kernel when the driver provided   *		 Vendor and device IDs are matched. All the initialization @@ -713,31 +902,38 @@ static int rsi_probe(struct sdio_func *pfunction,  			__func__);  		return 1;  	} +	adapter->rsi_host_intf = RSI_HOST_INTF_SDIO; +	adapter->host_intf_ops = &sdio_host_intf_ops;  	if (rsi_init_sdio_interface(adapter, pfunction)) {  		rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n",  			__func__);  		goto fail;  	} +	sdio_claim_host(pfunction); +	if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { +		rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); +		sdio_release_host(pfunction); +		goto fail; +	} +	sdio_release_host(pfunction); +	rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); -	if (rsi_sdio_device_init(adapter->priv)) { +	if (rsi_hal_device_init(adapter)) {  		rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__);  		sdio_claim_host(pfunction); +		sdio_release_irq(pfunction);  		sdio_disable_func(pfunction);  		sdio_release_host(pfunction);  		goto fail;  	} +	rsi_dbg(INFO_ZONE, "===> RSI Device Init Done <===\n"); -	sdio_claim_host(pfunction); -	if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { -		rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); -		sdio_release_host(pfunction); -		goto fail; +	if (rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR)) { +		rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); +		return -EIO;  	} -	sdio_release_host(pfunction); -	rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); -  	return 0;  fail:  	rsi_91x_deinit(adapter); |