/* mmc_tnetw1150_api.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Copyright © Texas Instruments Incorporated (Oct 2005) * THIS CODE/PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDED BUT NOT LIMITED TO , THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * This program has been modified from its original operation by Texas * Instruments Incorporated. These changes are covered under version 2 * of the GNU General Public License, dated June 1991. * * Copyright © Google Inc (Feb 2008) */ /*-------------------------------------------------------------------*/ #ifdef TIWLAN_MSM7000 #include #include #include #include "mmc_tnetw1150_api.h" #include #include #include #define SDIO_INVALID_PERIPHERAL_ADDRESS 0x1FFFF /* CCCR 0x000000 - 0x0000ff */ /* Function Basic Register (Function 1) 0x000100 - 0x0001ff */ /* 0x101 - Function 1 Extended standard I/O device type code */ /* 0x102 - RFU[4-0] EnableHighPower Supports High-Power[1-0] SHP[0] */ /* 0x103 - 0x108 - RFU */ /* 0x109 - 0x10b - Pointer to Function 1 Card Information Structure */ /* 0x10c - 0x10e - Pointer to Function 1 Code Storage Area */ /* 0x10f - Data access window to Function 1 Code Storage Area */ /* 0x110 - 0x111 - I/O block size for Function 1 */ /* 0x112 - 0x1ff - RFU */ /* Function Basic Register (Function 2) 0x000200 - 0x0002ff */ /* Function Basic Register (Function 3) 0x000300 - 0x0003ff */ /* Function Basic Register (Function 4) 0x000400 - 0x0004ff */ /* Function Basic Register (Function 5) 0x000500 - 0x0005ff */ /* Function Basic Register (Function 6) 0x000600 - 0x0006ff */ /* Function Basic Register (Function 7) 0x000700 - 0x0007ff */ /* RFU 0x000800 - 0x000fff */ /* CIS common and per-function area 0x001000 - 0x017fff */ /* RFU 0x018000 - 0x01ffff */ #define SDIO_FUNC1_OFFSET 0x1FFC0 typedef struct { Peripheral_Address mem_start_addr; Peripheral_Address mem_part_size; Peripheral_Address mem_end_addr; Peripheral_Address reg_start_addr; Peripheral_Address reg_part_size; Peripheral_Address reg_end_addr; } SDIO_TNETW_partitions; static SDIO_TNETW_partitions TNETW_table; static SDIO_TNETWConfigParams TNETW_params; #ifdef CONFIG_MMC_TNET_INFO typedef struct { u8 scr_space[SDIO_FUNC1_OFFSET]; /* 0x000000 - 0x01ffbf; 131072B(128kB)-64B=131008B(0x01ffc0) */ u32 amap_size1; /* 0x01ffc0 */ u32 amap_offset1; /* 0x01ffc4 */ u32 amap_size2; /* 0x01ffc8 */ u32 amap_offset2; /* 0x01ffcc */ u32 amap_size3; /* 0x01ffd0 */ u32 amap_offset3; /* 0x01ffd4 */ u32 amap_offset4; /* 0x01ffd8 */ u32 cis_offset; /* 0x01ffdc - Card Information Structure */ u32 csa_offset; /* 0x01ffe0 - Code Storage Area */ u8 filler[16]; /* 0x01ffe4 - 0x01fff3 */ u32 wr_err_len; /* 0x01fff4 */ u32 wr_err_addr; /* 0x01fff8 */ u32 status; /* 0x01fffc */ } SDIO_FUNC1AddressMap; SDIO_FUNC1AddressMap mapping; int sdio_tnetw1150_dump(int count) { unsigned long from; unsigned long br_offset; unsigned long offset=0; unsigned long p1_offset=0; unsigned long p2_offset=0; struct mmc_request request; int lines; int i=0; int second_part=0; printk("%s:\n", __FUNCTION__); #define TNETW1150_OFFSET 1024 from=TNETW1150_OFFSET*count; if((from+TNETW1150_OFFSET)>(SDIO_FUNC1_OFFSET+64)) return -1; br_offset=TNETW1150_OFFSET*count; if(br_offset>=TNETW_params.map_reg[0].reg_size) { second_part=1; p2_offset = SDIO_DRIVER_REG_PARTITION_START; offset = TNETW_params.map_reg[1].scr_offset - TNETW_params.map_reg[0].reg_size; } else { p1_offset += SDIO_DOWNLOAD_PARTITION_START; offset = TNETW_params.map_reg[0].scr_offset; } request.cmd=SD_IO_RW_DIRECT; request.buffer_len=1; request.nob=0; request.block_len=0; request.buffer=&mapping.scr_space[from]; printk(" TNETW1150 try br_offset:0x%08lx offset:0x%08lx):\n", br_offset, offset); do { request.arg = SDIO_CMD52_READ(0,FUNCTION_SELECT_1,0,br_offset); if(__submit_control_request(omap_mmc_dev_get_handle(), &request)!=SDIO_SUCCESS) return SDIO_FAILURE; udelay(1); *request.buffer = (char)omap_readw(OMAP_MMC_RSP6); i++; request.buffer++; br_offset++; } while(i>7), ((buf3[0]&0x40)>>6), (buf3[1]&0x0f), buf3[1], (buf3[2]&0x07), buf_fbr[2], buf_fbr[1], buf_fbr[0], buf_fbr[5], buf_fbr[4], buf_fbr[3], buf_fbr[6], buf_fbr[8], buf_fbr[7]):0; *eof = 1; return len; } #endif /*CONFIG_MMC_TNET_STATISTICS*/ /* Initialization of TNETW memory configuration. */ extern int debug_level; SDIO_Status SDIO_TNETWInit(SDIO_TNETWConfigParams *params) { /* debug_level=3; */ /* printk("%s\n", __FUNCTION__); */ memset(&TNETW_params, 0, sizeof(SDIO_TNETWConfigParams)); if(!params) { /* printk("%s set to default\n", __FUNCTION__); */ /* set to default value in case params is not presented */ TNETW_params.num_of_parts = 2; /* First time initialization */ TNETW_params.map_reg[0].reg_size = SDIO_DOWNLOAD_PARTITION_SIZE; TNETW_params.map_reg[0].scr_offset = SDIO_DOWNLOAD_PARTITION_START; /* After firmware has been downloaded, data memory region has to be re-initialized as following: TNETW_params.map_reg[0].reg_size = SDIO_MEM_PARTITION_START; TNETW_params.map_reg[0].scr_offset = SDIO_MEM_PARTITION_SIZE; */ TNETW_params.map_reg[1].reg_size = SDIO_REG_PARTITION_SIZE; TNETW_params.map_reg[1].scr_offset = SDIO_REG_PARTITION_START; } else { /* printk("%s: params->num_of_parts=%d\n", __FUNCTION__, params->num_of_parts); */ /* validate input parameters */ switch(params->num_of_parts) { case 1: if(params->map_reg[0].reg_size > AMAP_ONE_REGION) return SDIO_FAILURE; break; case 2: if((params->map_reg[0].reg_size + params->map_reg[1].reg_size) > AMAP_ONE_REGION) return SDIO_FAILURE; break; case 3: if((params->map_reg[0].reg_size + params->map_reg[1].reg_size + params->map_reg[2].reg_size) > AMAP_ONE_REGION) return SDIO_FAILURE; break; case 4: if((params->map_reg[0].reg_size + params->map_reg[1].reg_size + params->map_reg[2].reg_size + params->map_reg[3].reg_size) > AMAP_ONE_REGION) return SDIO_FAILURE; break; default: return SDIO_FAILURE; } memcpy(&TNETW_params, params, sizeof(SDIO_TNETWConfigParams)); } #ifdef CONFIG_PROC_FS #ifdef CONFIG_MMC_TNET_INFO create_proc_read_entry("sdio_tnetw1150", 0, NULL, sdio_tnetw1150_read_proc, NULL); #endif #endif /* printk("%s completed\n", __FUNCTION__); */ return SDIO_SUCCESS; } SDIO_Status SDIO_TNETWReset(SDIO_TNETWConfigParams *params) { /* printk("%s\n", __FUNCTION__); */ memset(&TNETW_params, 0, sizeof(SDIO_TNETWConfigParams)); if(!params) { /* printk("%s set to default\n", __FUNCTION__); */ /* set to default value in case params is not presented */ TNETW_params.num_of_parts = 2; /* After firmware has been downloaded, data memory region has to be re-initialized as following */ TNETW_params.map_reg[0].reg_size = SDIO_MEM_PARTITION_START; TNETW_params.map_reg[0].scr_offset = SDIO_MEM_PARTITION_SIZE; TNETW_params.map_reg[1].reg_size = SDIO_REG_PARTITION_SIZE; TNETW_params.map_reg[1].scr_offset = SDIO_REG_PARTITION_START; } else { /* printk("%s: params->num_of_parts=%d\n", __FUNCTION__, params->num_of_parts); */ /* validate input parameters */ switch(params->num_of_parts) { case 1: if(params->map_reg[0].reg_size > AMAP_ONE_REGION) return SDIO_FAILURE; break; case 2: if((params->map_reg[0].reg_size + params->map_reg[1].reg_size) > AMAP_ONE_REGION) return SDIO_FAILURE; break; case 3: if((params->map_reg[0].reg_size + params->map_reg[1].reg_size + params->map_reg[2].reg_size) > AMAP_ONE_REGION) return SDIO_FAILURE; break; case 4: if((params->map_reg[0].reg_size + params->map_reg[1].reg_size + params->map_reg[2].reg_size + params->map_reg[3].reg_size) > AMAP_ONE_REGION) return SDIO_FAILURE; break; default: return SDIO_FAILURE; } memcpy(&TNETW_params, params, sizeof(SDIO_TNETWConfigParams)); } /* printk("%s completed\n", __FUNCTION__); */ return SDIO_SUCCESS; } static SDIO_Status config_partition(SDIO_Handle sdioHandle, int partition_no, Peripheral_Address start_addr, SDIO_BufferLength part_size) { struct sdio_func *func = (struct sdio_func *) sdioHandle; u8 data; int br_offset = SDIO_FUNC1_OFFSET + (partition_no-1)*8; int i, rc; /* printk("%s: partition_no=%d\n", __FUNCTION__, partition_no); */ /* Set size - write out 4 bytes by 4 requests */ if (partition_no < AMAP_MAX_REGIONS) { for(i=0;i<4;i++,br_offset++) { data = (part_size>>(8*i))&0xFF; /* put R/W Flag (1 for write); Function Number(1), RAW Flag(0), Register Address - the address of the byte of data inside of the selected function that will be written (br_offset for func1), Write Data - for a direct write command, this is the byte=data, that will be written to the selected address=br_offset). */ sdio_writeb(func, data, br_offset, &rc); if (rc < 0) { printk(KERN_ERR "%s: Error writing size\n", __FUNCTION__); return SDIO_FAILURE; } /* printk("%s: offset byte=%d data=0x%08x at=0x%08x\n", __FUNCTION__, i, data, br_offset); */ } /* Set offset - write out 4 bytes by 4 requests */ for(i=0;i<4;i++,br_offset++) { data = (start_addr>>(8*i))&0xFF; sdio_writeb(func, data, br_offset, &rc); if (rc < 0) { printk(KERN_ERR "%s: Error writing offset\n", __FUNCTION__); return SDIO_FAILURE; } /* printk("%s: offset byte=%d data=0x%08x at=0x%08x\n", __FUNCTION__, i, data, br_offset); */ } } #if 0 if( partition_no == 2 ) { unsigned long id1; for(i=0,br_offset=0x1ce34;i<4;i++,br_offset++) { data = sdio_readb(func, br_offset, &rc); if (rc < 0) { printk(KERN_ERR "%s: Error reading offset\n", __FUNCTION__); return SDIO_FAILURE; } printk("%s: offset byte=%d data=0x%08x at=0x%08x\n", __FUNCTION__, i, data, br_offset); } rc = sdio_memcpy_fromio(func, &id1, 0x1ce34, 4); /* Dm: Important - DO NOT REMOVE !!! */ if (rc < 0) { printk(KERN_ERR "%s: Error reading offset\n", __FUNCTION__); return SDIO_FAILURE; } printk("%s: data=0x%08x at=0x%08x\n", __FUNCTION__, id1, br_offset); } #endif return SDIO_SUCCESS; } /* This function configures the slave SDIO device for the required operation mode. */ SDIO_Status SDIO_TNETWConfig(SDIO_Handle sdioHandle, Peripheral_ConfigParams **peripheral_info) { SDIO_Status rc; /* printk("%s\n", __FUNCTION__); */ TNETW_table.mem_start_addr = TNETW_params.map_reg[0].scr_offset; TNETW_table.mem_part_size = TNETW_params.map_reg[0].reg_size; TNETW_table.mem_end_addr = TNETW_table.mem_start_addr + TNETW_table.mem_part_size - 1; TNETW_table.reg_start_addr = TNETW_params.map_reg[1].scr_offset; TNETW_table.reg_part_size = TNETW_params.map_reg[1].reg_size; TNETW_table.reg_end_addr = TNETW_table.reg_start_addr + TNETW_table.reg_part_size - 1; #if 0 printk("%s: memory area: start_addr=0x%08lx end_addr=0x%08lx part_size=0x%08lx\n", __FUNCTION__, TNETW_table.mem_start_addr, TNETW_table.mem_end_addr, TNETW_table.mem_part_size); printk("%s: register area: start_addr=0x%08lx end_addr=0x%08lx part_size=0x%08lx\n", __FUNCTION__, TNETW_table.reg_start_addr, TNETW_table.reg_end_addr, TNETW_table.reg_part_size); #endif /* Configure 17-bits address range in peripheral */ rc=config_partition(sdioHandle, 1, TNETW_table.mem_start_addr, TNETW_table.mem_part_size); rc = (rc==SDIO_SUCCESS)?config_partition(sdioHandle, 2, TNETW_table.reg_start_addr, TNETW_table.reg_part_size):rc; if(*peripheral_info) *peripheral_info = (void *)&TNETW_table; /* printk("%s: TNETW1150 partitions:\n", __FUNCTION__); printk("Memory : start:0x%08lx end:0x%08lx size:0x%08lx bytes\n", TNETW_table.mem_start_addr, TNETW_table.mem_end_addr, TNETW_table.mem_part_size); printk("Registers: start:0x%08lx end:0x%08lx size:0x%08lx bytes\n", TNETW_table.reg_start_addr, TNETW_table.reg_end_addr, TNETW_table.reg_part_size); */ return rc; } /* This function performs convertion of peripheral adddress into 17 bits SDIO address. If found that the memory partition configuration must be changed, the memory is re-mapped in accordance to requested address. */ SDIO_Address SDIO_ConvertTNETWToSDIOMaster(Peripheral_Address in_tnetw_address, SDIO_BufferLength packet_size) { SDIO_Address out_sdio_address; #ifdef CONFIG_SDIO_ADDRESS_MAPPING_BY_APPLICATION out_sdio_address = in_tnetw_address; #else Peripheral_Address tnetw_last_address = in_tnetw_address + packet_size - 1; /* printk("%s:\n", __FUNCTION__); */ if ((in_tnetw_address >= TNETW_table.mem_start_addr) && (tnetw_last_address <= TNETW_table.mem_end_addr)) { /* printk("%s part1 from=0x%08lx to 0x%08lx\n", __FUNCTION__, in_tnetw_address, tnetw_last_address); */ /* address in the 1-st partition range (data memory space) */ out_sdio_address = in_tnetw_address - TNETW_table.mem_start_addr; } else if ((in_tnetw_address >= TNETW_table.reg_start_addr) && (tnetw_last_address <= TNETW_table.reg_end_addr)) { /* printk("%s part2 from=0x%08lx to 0x%08lx\n", __FUNCTION__, in_tnetw_address, tnetw_last_address); */ /* address in the 2-nd partition range (register memory space) */ out_sdio_address = in_tnetw_address - TNETW_table.reg_start_addr + TNETW_table.mem_part_size; } else { /* printk("%s peripheral addresses from=0x%08lx to 0x%08lx is out of range\n", __FUNCTION__, in_tnetw_address, tnetw_last_address); */ /* invalid address */ return SDIO_INVALID_PERIPHERAL_ADDRESS; } /* printk("%s: in_tnetw_addr=0x%08lx out_sdio_addr=0x%08lx\n", __FUNCTION__, in_tnetw_address, out_sdio_address); */ #endif /* CONFIG_SDIO_ADDRESS_MAPPING_BY_APPLICATION */ return out_sdio_address; } SDIO_Status SDIO_TNETW_Set_ELP_Reg(SDIO_Handle sdioHandle, Peripheral_Address start_addr, unsigned int data) { struct sdio_func *func = (struct sdio_func *) sdioHandle; u8 data1 = 0; int br_offset = start_addr; int i, rc; /* Set size - write out 4 bytes by 4 requests */ for(i=0;i<1;i++,br_offset++) { data1 = (data>>(8*i))&0xFF; /* put R/W Flag (1 for write); Function Number(1), RAW Flag(0), Register Address - the address of the byte of data inside of the selected function that will be written (br_offset for func1), Write Data - for a direct write command, this is the byte=data, that will be written to the selected address=br_offset). */ sdio_writeb(func, data1, br_offset, &rc); if (rc < 0) { printk(KERN_ERR "%s: Error writing size\n", __FUNCTION__); return SDIO_FAILURE; } } return SDIO_SUCCESS; } SDIO_Status SDIO_TNETW_Get_ELP_Reg(SDIO_Handle sdioHandle, Peripheral_Address start_addr, unsigned int *data) { struct sdio_func *func = (struct sdio_func *) sdioHandle; int br_offset = start_addr; int rc; *(u8*)data = sdio_readb_ext(func, br_offset, &rc, 0x01); if (rc) { printk(KERN_ERR "%s: Error reading sdio register (%d)\n", __FUNCTION__, rc); return SDIO_FAILURE; } return SDIO_SUCCESS; } #endif /* TIWLAN_MSM7000 */