#include #include #include #include #include "kwrap/semaphore.h" #include "semphr.h" #include "sys.h" #include #include #include #define u32 unsigned int #define u16 unsigned short #define u8 unsigned char #define min(a,b) (a > b ? b : a) #define SDIO_HOST_ID_2 (1) //< SDIO2 host #define SDIO_IO_R 0x0 ///< IO Read flag #define SDIO_IO_W 0x1 ///< IO Write flag #define SDIO_IO_BYTEMODE 0x0 ///< IO byte access mode #define SDIO_IO_BLOCKMODE 0x1 ///< IO block access mode #define SDIO_IO_DIS_RAW 0x0 ///< Disable IO RAW function #define SDIO_CCCR_IENx 0x04 /* Function/Master Interrupt Enable */ #define SDIO_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */ #define SDIO_FBR_CIS 0x09 /* CIS pointer (3 bytes) */ #define SDIO_FBR_BLKSIZE 0x10 /* block size (2 bytes) */ #define __must_be_array(x) 0 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) struct mmc_ios { unsigned int clock; /* clock rate */ unsigned short vdd; /* vdd stores the bit number of the selected voltage range from below. */ unsigned char bus_mode; /* command output mode */ #define MMC_BUSMODE_OPENDRAIN 1 #define MMC_BUSMODE_PUSHPULL 2 unsigned char chip_select; /* SPI chip select */ #define MMC_CS_DONTCARE 0 #define MMC_CS_HIGH 1 #define MMC_CS_LOW 2 unsigned char power_mode; /* power supply mode */ #define MMC_POWER_OFF 0 #define MMC_POWER_UP 1 #define MMC_POWER_ON 2 unsigned char bus_width; /* data bus width */ #define MMC_BUS_WIDTH_1 0 #define MMC_BUS_WIDTH_4 2 #define MMC_BUS_WIDTH_8 3 unsigned char timing; /* timing specification used */ #define MMC_TIMING_LEGACY 0 #define MMC_TIMING_MMC_HS 1 #define MMC_TIMING_SD_HS 2 }; struct mmc_host_ops { #if 0 void (*request)(struct mmc_host *host, struct mmc_request *req); /* * Avoid calling these three functions too often or in a "fast path", * since underlaying controller might implement them in an expensive * and/or slow way. * * Also note that these functions might sleep, so don't call them * in the atomic contexts! * * Return values for the get_ro callback should be: * 0 for a read/write card * 1 for a read-only card * -ENOSYS when not supported (equal to NULL callback) * or a negative errno value when something bad happened * * Return values for the get_cd callback should be: * 0 for a absent card * 1 for a present card * -ENOSYS when not supported (equal to NULL callback) * or a negative errno value when something bad happened */ void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); int (*get_ro)(struct mmc_host *host); int (*get_cd)(struct mmc_host *host); void (*enable_sdio_irq)(struct mmc_host *host, int enable); #endif }; struct mmc_host { //struct device *parent; //struct device class_dev; int index; const struct mmc_host_ops *ops; unsigned int f_min; unsigned int f_max; u32 ocr_avail; #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ #define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ #define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ #define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ #define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ #define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ #define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ #define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ #define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ #define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ #define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ #define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ #define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ #define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ #define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ #define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ unsigned long caps; /* Host capabilities */ #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ #define MMC_CAP_MMC_HIGHSPEED (1 << 1) /* Can do MMC high-speed timing */ #define MMC_CAP_SD_HIGHSPEED (1 << 2) /* Can do SD high-speed timing */ #define MMC_CAP_SDIO_IRQ (1 << 3) /* Can signal pending SDIO IRQs */ #define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */ #define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */ #define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */ unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */ unsigned short unused; unsigned int max_req_size; /* maximum number of bytes in one req */ unsigned int max_blk_size; /* maximum size of one mmc block */ unsigned int max_blk_count; /* maximum number of blocks in one req */ /* private data */ //spinlock_t lock; /* lock for claim and bus ops */ struct mmc_ios ios; /* current io bus settings */ u32 ocr; /* the current OCR setting */ /* group bitfields together to minimize padding */ unsigned int use_spi_crc:1; unsigned int claimed:1; /* host exclusively claimed */ unsigned int bus_dead:1; /* bus has been released */ #ifdef CONFIG_MMC_DEBUG unsigned int removed:1; /* host is being removed */ #endif struct mmc_card *card; /* device attached to this host */ //wait_queue_head_t wq; //struct delayed_work detect; //const struct mmc_bus_ops *bus_ops; /* current bus driver */ unsigned int bus_refs; /* reference counter */ //unsigned int sdio_irqs; //struct task_struct *sdio_irq_thread; //atomic_t sdio_irq_thread_abort; #ifdef CONFIG_LEDS_TRIGGERS struct led_trigger *led; /* activity led */ #endif //struct dentry *debugfs_root; //unsigned long private[0] ____cacheline_aligned; }; struct sdio_func_tuple { struct sdio_func_tuple *next; unsigned char code; unsigned char size; unsigned char data[0]; }; struct sdio_func { struct mmc_card *card; void (*irq_handler)(struct sdio_func *); unsigned int max_blksize; unsigned int cur_blksize; unsigned int enable_timeout; unsigned int num; unsigned short vendor; unsigned short device; unsigned num_info; const char **info; unsigned char class; unsigned int tmpbuf_reserved; unsigned char tmpbuf[4]; void *drv_priv; }; struct sdio_cccr { unsigned int sdio_vsn; unsigned int sd_vsn; unsigned int multi_block:1; unsigned int low_speed:1; unsigned int wide_bus:1; unsigned int high_power:1; unsigned int high_speed:1; unsigned int disable_cd:1; }; struct sdio_cis { unsigned short vendor; unsigned short device; unsigned short blksize; unsigned int max_dtr; }; struct mmc_card { struct mmc_host *host; struct sdio_cccr cccr; struct sdio_cis cis; struct sdio_func *sdio_func[7]; unsigned int sdio_funcs; unsigned int rca; unsigned int type; unsigned num_info; const char **info; struct sdio_func_tuple *tuples; }; typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *, const unsigned char *, unsigned); struct cis_tpl { unsigned char code; unsigned char min_size; tpl_parse_t *parse; }; typedef enum { SDIO_HOST_IOINT_DIS = 0, ///< sdio host io interrupt enable SDIO_HOST_IOINT_EN = 1 ///< sdio host io interrupt disable }SDIO_HOST_IOINT_ENDIS; static struct mmc_card sdiocard; static struct mmc_host sdiohost; static struct sdio_func func_sdio = { 0 }; struct sdio_func *wifi_sdio_func = &func_sdio; static struct sdio_func_tuple *func_tuples = NULL; static struct sdio_func_tuple *card_tuples = NULL; static struct sdio_func *save_sdio_func; static void(*vpSdioLinuxIoHdl)(struct sdio_func *) = NULL; static SEM_HANDLE wifi_sdio_mutex; static TaskHandle_t sdio_irq_task_handler; static ID FLG_ID_WIFI_SDIO; #define FLGPTN_WIFI_SDIO 0x4 #define uimempoolsize 512 static unsigned char uimempool[uimempoolsize]; static unsigned int func_max_byte_size = 512u; static unsigned int sdio_max_byte_size(struct sdio_func *func) { //?? todo #if 0 unsigned mval = min(func->card->host->max_seg_size, func->card->host->max_blk_size); mval = min(mval, func->max_blksize); return min(mval, 512u); /* maximum size for byte mode */ #else return func_max_byte_size; #endif //?? todo end } void sdio_set_max_byte_size(struct sdio_func *func, unsigned int size) { func_max_byte_size = size; //?? todo end } static int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out) { SDIO_CMD52_STRUCT cmd52; unsigned char rw; //cyg_io_handle_t handle; //unsigned char data; if (write) rw = SDIO_IO_W; else rw = SDIO_IO_R; cmd52.Function_Num = (unsigned char)fn; cmd52.Reg_Addr = (unsigned long)addr; if (write) cmd52.pData = (unsigned char *)∈ else cmd52.pData = (unsigned char *)out; cmd52.ByteCount = 1; cmd52.RW_flag = rw; cmd52.RAW = SDIO_IO_DIS_RAW; cmd52.Stuff = 0; extern int sdio2_sendIOCMD52(PSDIO_CMD52_STRUCT pSDIO_CMD52); if(sdio2_sendIOCMD52(&cmd52)) { printf("mmc_io_rw_direct error\r\n"); //if (vpSdioCmdErrHdl) // vpSdioCmdErrHdl(SDIO_HOST_ERR_CMD52); //return -EIO; return -1; } return 0; } static int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { SDIO_CMD53_STRUCT cmd53; unsigned char rw; //cyg_io_handle_t handle; unsigned char uiblock; unsigned int uibytecnt; if (write) rw = SDIO_IO_W; else rw = SDIO_IO_R; cmd53.Function_Num = (unsigned char)fn; cmd53.Reg_Addr = (unsigned int)addr; cmd53.pData = (unsigned char *)buf; cmd53.OpCode = incr_addr; cmd53.RW_flag = rw; cmd53.Stuff = 0; if (blocks == 1 && blksz <= 512) { //uibytecnt = (blksz == 512) ? 0 : blksz; /* byte mode */ uibytecnt = blksz; uiblock = SDIO_IO_BYTEMODE; } else { uiblock = SDIO_IO_BLOCKMODE; uibytecnt = blocks; /* block mode */ } cmd53.Block = uiblock; cmd53.ByteCount = uibytecnt; extern int sdio2_sendIOCMD53(PSDIO_CMD53_STRUCT pSDIO_CMD53); if(sdio2_sendIOCMD53((void *)&cmd53)) { printf("mmc_io_rw_extended error\r\n"); //if (vpSdioCmdErrHdl) // vpSdioCmdErrHdl(SDIO_HOST_ERR_CMD53); //return -EIO; return -1; } return 0; } static int mmc_io_rw_ext_helper(struct sdio_func *func, int write, unsigned addr, int incr_addr, u8 *buf, unsigned size) { unsigned remainder = size; unsigned max_blocks; int ret; /* Do the bulk of the transfer using block mode (if supported). */ if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) { /* Blocks per command is limited by host count, host transfer * size (we only use a single sg entry) and the maximum for * IO_RW_EXTENDED of 511 blocks. */ //?? //?? todo /*max_blocks = min(func->card->host->max_blk_count, func->card->host->max_seg_size / func->cur_blksize); max_blocks = min(max_blocks, 511u);*/ max_blocks = 511u; //?? todo end while (remainder > func->cur_blksize) { unsigned blocks; blocks = remainder / func->cur_blksize; if (blocks > max_blocks) blocks = max_blocks; size = blocks * func->cur_blksize; ret = mmc_io_rw_extended(func->card, write, func->num, addr, incr_addr, buf, blocks, func->cur_blksize); if (ret) return ret; remainder -= size; buf += size; if (incr_addr) addr += size; } } /* Write the remainder using byte mode. */ while (remainder > 0) { size = min(remainder, sdio_max_byte_size(func)); ret = mmc_io_rw_extended(func->card, write, func->num, addr, incr_addr, buf, 1, size); if (ret) return ret; remainder -= size; buf += size; if (incr_addr) addr += size; } return 0; } static int sdio_cardDetectCB(void) { return 1; } static int sdio_writeProtCB(void) { return 0; } static int sdio_read_cccr(struct mmc_card *card) { int ret; int cccr_vsn; unsigned char data; memset(&card->cccr, 0, sizeof(struct sdio_cccr)); #define SDIO_CCCR_CCCR 0x00 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); if (ret) goto out; cccr_vsn = data & 0x0f; #define SDIO_CCCR_REV_3_00 3 /* CCCR/FBR Version 3.00 */ if (cccr_vsn > SDIO_CCCR_REV_3_00) { //??printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", //?? mmc_hostname(card->host), cccr_vsn); printf("unrecognised CCCR structure version %d\n", cccr_vsn); return -1; } card->cccr.sdio_vsn = (data & 0xf0) >> 4; #define SDIO_CCCR_CAPS 0x08 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); if (ret) goto out; #define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */ if (data & SDIO_CCCR_CAP_SMB) card->cccr.multi_block = 1; #define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */ if (data & SDIO_CCCR_CAP_LSC) card->cccr.low_speed = 1; #define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */ if (data & SDIO_CCCR_CAP_4BLS) card->cccr.wide_bus = 1; #define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */ if (cccr_vsn >= SDIO_CCCR_REV_1_10) { #define SDIO_CCCR_POWER 0x12 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data); if (ret) goto out; #define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */ if (data & SDIO_POWER_SMPC) card->cccr.high_power = 1; } #define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */ if (cccr_vsn >= SDIO_CCCR_REV_1_20) { #define SDIO_CCCR_SPEED 0x13 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); if (ret) goto out; #define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */ if (data & SDIO_SPEED_SHS) card->cccr.high_speed = 1; } out: return ret; } static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func, const unsigned char *buf, unsigned size) { unsigned i, nr_strings; char **buffer, *string; buf += 2; size -= 2; nr_strings = 0; for (i = 0; i < size; i++) { if (buf[i] == 0xff) break; if (buf[i] == 0) nr_strings++; } if (buf[i-1] != '\0') { printf("SDIO: ignoring broken CISTPL_VERS_1\n"); return 0; } size = i; //buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL); buffer = pvPortMalloc(sizeof(char*) * nr_strings + size); if (!buffer) return -1; string = (char*)(buffer + nr_strings); for (i = 0; i < nr_strings; i++) { buffer[i] = string; strcpy(string, (char*)buf); string += strlen(string) + 1; buf += strlen((char*)buf) + 1; } if (func) { func->num_info = nr_strings; func->info = (const char**)buffer; } else { card->num_info = nr_strings; card->info = (const char**)buffer; } return 0; } static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func, const unsigned char *buf, unsigned size) { unsigned int vendor, device; /* TPLMID_MANF */ vendor = buf[0] | (buf[1] << 8); /* TPLMID_CARD */ device = buf[2] | (buf[3] << 8); if (func) { func->vendor = vendor; func->device = device; } else { card->cis.vendor = vendor; card->cis.device = device; } return 0; } static const unsigned char speed_val[16] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; static const unsigned int speed_unit[8] = { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; static int cistpl_funce_common(struct mmc_card *card, const unsigned char *buf, unsigned size) { if (size < 0x04 || buf[0] != 0) return -1; /* TPLFE_FN0_BLK_SIZE */ card->cis.blksize = buf[1] | (buf[2] << 8); /* TPLFE_MAX_TRAN_SPEED */ card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] * speed_unit[buf[3] & 7]; return 0; } static int cistpl_funce_func(struct sdio_func *func, const unsigned char *buf, unsigned size) { unsigned vsn; unsigned min_size; vsn = func->card->cccr.sdio_vsn; #define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */ min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; if (size < min_size || buf[0] != 1) return -1; /* TPLFE_MAX_BLK_SIZE */ func->max_blksize = buf[12] | (buf[13] << 8); /* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */ if (vsn > SDIO_SDIO_REV_1_00) func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10; else func->enable_timeout = 0;//??jiffies_to_msecs(HZ); return 0; } static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, const unsigned char *buf, unsigned size) { int ret; /* * There should be two versions of the CISTPL_FUNCE tuple, * one for the common CIS (function 0) and a version used by * the individual function's CIS (1-7). Yet, the later has a * different length depending on the SDIO spec version. */ if (func) ret = cistpl_funce_func(func, buf, size); else ret = cistpl_funce_common(card, buf, size); if (ret) { printf("bad CISTPL_FUNCE size %u,type %u\n", size, buf[0]); return ret; } return 0; } static const struct cis_tpl cis_tpl_list[] = { { 0x15, 3, cistpl_vers_1 }, { 0x20, 4, cistpl_manfid }, { 0x21, 2, /* cistpl_funcid */ }, { 0x22, 0, cistpl_funce }, }; static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) { int ret; struct sdio_func_tuple *this, **prev; unsigned i, ptr = 0; /* * Note that this works for the common CIS (function number 0) as * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS * have the same offset. */ for (i = 0; i < 3; i++) { unsigned char x, fn; if (func) fn = func->num; else fn = 0; ret = mmc_io_rw_direct(card, 0, 0, SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x); if (ret) return ret; ptr |= x << (i * 8); printf("tpl_ptr = 0x%x\r\n", ptr); } if (func) //prev = &func->tuples; prev = &func_tuples; else //prev = &card->tuples; prev = &card_tuples; //BUG_ON(*prev); do { unsigned char tpl_code, tpl_link; ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code); printf("tpl_code = 0x%02x\r\n", tpl_code); if (ret) break; /* 0xff means we're done */ if (tpl_code == 0xff) break; /* null entries have no link field or data */ if (tpl_code == 0x00) continue; ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); printf("tpl_link = 0x%02x\r\n", tpl_link); if (ret) break; /* a size of 0xff also means we're done */ if (tpl_link == 0xff) { printf("tpl_link done, because equals to 0xff\r\n"); break; } this = pvPortMalloc(sizeof(*this) + tpl_link); if (!this) return -1; printf("tpl_data =\r\n"); for (i = 0; i < tpl_link; i++) { ret = mmc_io_rw_direct(card, 0, 0, ptr + i, 0, &this->data[i]); printf("0x%02x ", this->data[i]); if ((i % 8) == 7) { printf("\r\n"); } if (ret) break; } if (ret) { vPortFree(this); break; } printf("\r\ni = %d, ARRAY_SIZE = %d\r\n", i, ARRAY_SIZE(cis_tpl_list)); for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) if (cis_tpl_list[i].code == tpl_code) break; if (i >= ARRAY_SIZE(cis_tpl_list)) { /* this tuple is unknown to the core */ this->next = NULL; this->code = tpl_code; this->size = tpl_link; *prev = this; prev = &this->next; printf("queuing CIS tuple 0x%02x length %u\n", tpl_code, tpl_link); } else { const struct cis_tpl *tpl = cis_tpl_list + i; if (tpl_link < tpl->min_size) { printf("bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",tpl_code, tpl_link, tpl->min_size); ret = -1; } else if (tpl->parse) { ret = tpl->parse(card, func, this->data, tpl_link); } vPortFree(this); } ptr += tpl_link; } while (!ret); /* * Link in all unknown tuples found in the common CIS so that * drivers don't have to go digging in two places. */ if (func) //*prev = card->tuples; *prev = card_tuples; return ret; } static int sdio_read_common_cis(struct mmc_card *card) { return sdio_read_cis(card, NULL); } static struct sdio_func *sdio_alloc_func(struct mmc_card *card) { struct sdio_func *func; func = pvPortMalloc(sizeof(struct sdio_func)); if (!func) return NULL; memset(func, 0, sizeof(struct sdio_func)); func->card = card; //device_initialize(&func->dev); //??func->dev.parent = &card->dev; //??func->dev.bus = &sdio_bus_type; //??func->dev.release = sdio_release_func; return func; } static int sdio_read_fbr(struct sdio_func *func) { int ret; unsigned char data; #define SDIO_FBR_STD_IF 0x00 ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data); if (ret) goto out; data &= 0x0f; if (data == 0x0f) { #define SDIO_FBR_STD_IF_EXT 0x01 ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data); if (ret) goto out; } func->class = data; out: return ret; } static int sdio_read_func_cis(struct sdio_func *func) { int ret; ret = sdio_read_cis(func->card, func); if (ret) return ret; /* * Since we've linked to tuples in the card structure, * we must make sure we have a reference to it. */ //get_device(&func->card->dev); /* * Vendor/device id is optional for function CIS, so * copy it from the card structure as needed. */ if (func->vendor == 0) { func->vendor = func->card->cis.vendor; func->device = func->card->cis.device; } return 0; } static void sdio_remove_func(struct sdio_func *func) { //?? /*if (sdio_func_present(func)) device_del(&func->dev); put_device(&func->dev);*/ } static int sdio_init_func(struct mmc_card *card, unsigned int fn) { int ret; struct sdio_func *func; //BUG_ON(fn > SDIO_MAX_FUNCS); func = sdio_alloc_func(card); if (func == NULL) return -1; func->num = fn; ret = sdio_read_fbr(func); if (ret) goto fail; ret = sdio_read_func_cis(func); if (ret) goto fail; card->sdio_func[fn - 1] = func; return 0; fail: /* * It is okay to remove the function here even though we hold * the host lock as we haven't registered the device yet. */ sdio_remove_func(func); return ret; } int sdio_set_block_size(struct sdio_func *func, unsigned blksz) { int ret; if (blksz > func->card->host->max_blk_size){ printf("sdio_set_block_size:blksz(%d) > max(%d)\n", blksz, func->card->host->max_blk_size); return -1; } if (blksz == 0) { blksz = min(func->max_blksize, func->card->host->max_blk_size); blksz = min(blksz, 512u); } ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE, blksz & 0xff, NULL); if (ret){ printf("sdio_set_block_size:set SDIO_FBR_BLKSIZE fail\n"); return ret; } ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1, (blksz >> 8) & 0xff, NULL); if (ret){ printf("sdio_set_block_size:set SDIO_FBR_BLKSIZE+1 fail\n"); return ret; } func->cur_blksize = blksz; // set sdio host block size extern void sdioHost_setBlkSize(UINT32 id, UINT32 size); sdioHost_setBlkSize(SDIO_HOST_ID_2, blksz); return 0; } void sdio_claim_host(struct sdio_func*func) { SEM_WAIT(wifi_sdio_mutex); } void sdio_release_host(struct sdio_func *func) { SEM_SIGNAL(wifi_sdio_mutex); } static void sdio_irq_task(void *pvParameters) { FLGPTN uiFlag; if(!wifi_sdio_func){ printf("sdio_irq_task : wifi_sdio_func is NULL\n"); return; } //coverity[no_escape] while(1) { wai_flg(&uiFlag, FLG_ID_WIFI_SDIO, FLGPTN_WIFI_SDIO, TWF_ORW | TWF_CLR); //extern volatile int sdio_io_int_count; //printf("task in(%d)\n", sdio_io_int_count);sdio_io_int_count++; //if(sdio_card_intr) { //sdio_card_intr = 0; sdio_claim_host(wifi_sdio_func); if (wifi_sdio_func->irq_handler) { wifi_sdio_func->irq_handler(wifi_sdio_func); //wifi_sdio_func->irq_handler(wifi_sdio_func); //wifi_sdio_func->irq_handler(wifi_sdio_func); } sdio_release_host(wifi_sdio_func); } //printf("task out(%d)\n", sdio_io_int_count);sdio_io_int_count++; //extern UINT32 sdioHost_setIoIntEn(unsigned int id, int bEn); //sdioHost_setIoIntEn(SDIO_HOST_ID_2, 1); //vTaskDelay(5); } vTaskDelete(NULL); } int wifi_sdio_init(void) { int funcs; int i; SEM_CREATE(wifi_sdio_mutex, 1); cre_flg(&FLG_ID_WIFI_SDIO, NULL, "wifi_sdio_flag"); extern void sdioPrtcl_setDetectCardExistHdl(UINT32 id, void *pHdl); sdioPrtcl_setDetectCardExistHdl(SDIO_HOST_ID_2, sdio_cardDetectCB); extern void sdioPrtcl_setDetectCardProtectHdl(UINT32 id, void *pHdl); sdioPrtcl_setDetectCardProtectHdl(SDIO_HOST_ID_2, sdio_writeProtCB); //sdioHost_creatInt(SDIO_HOST); extern void sdioPrtcl_setMemPool(unsigned int id, unsigned int uiAddr, unsigned int uiSize); sdioPrtcl_setMemPool(SDIO_HOST_ID_2, (unsigned int)uimempool, uimempoolsize); sdio2_setIOEnable(1); extern ER sdioPrtcl_setConfig(UINT32 id, SDIO_CONFIG_ID configID, UINT32 configContext); if(sdioPrtcl_setConfig(SDIO_HOST_ID_2, SDIO_CONFIG_ID_DS_MAX_CLK, 48000000)){ printf("fail to set sdio2 to 48Mhz\n"); return -1; } extern int sdio2strg_open(int id); if(sdio2strg_open(0)){ printf("sdio2strg_open(0) fail\n"); return -1; } extern ER sdioHost_setPadDriving(UINT32 id, UINT32 driving); if(sdioHost_setPadDriving(SDIO_HOST_ID_2, 150)){ printf("fail to set sdio driving padding\n"); return -1; } memset(&func_sdio, 0, sizeof(struct sdio_func)); memset(&sdiocard, 0, sizeof(struct mmc_card)); memset(&sdiohost, 0, sizeof(struct mmc_host)); //get ocr value funcs = 1; //function number printf("funcs = 0x%x\r\n", funcs); //save sdio functions //??sdiocard.sdio_funcs = funcs; func_sdio.card = (struct mmc_card *)&sdiocard; //read cccr if(sdio_read_cccr((struct mmc_card *)&sdiocard)){ printf("sdio_read_cccr() fail\n"); return -1; } //read cis if(sdio_read_common_cis((struct mmc_card *)&sdiocard)){ printf("sdio_read_common_cis() fail\n"); return -1; } //set to 4 bit //sdio_enable_wide((struct mmc_card *)&sdiocard); /* * Initialize (but don't add) all present functions. */ for (i = 0;i < funcs;i++) { if(sdio_init_func((struct mmc_card *)&sdiocard, i + 1)){ printf("sdio_init_func(%d) fail\n", i+1); return -1; } //??if (err) //?? goto remove; } //func_sdio.max_blksize = param.SEL.SET_BLOCK_SIZE.uiblocksize; //func_sdio.cur_blksize = param.SEL.SET_BLOCK_SIZE.uiblocksize; //func_sdio.num =funcs; //??temp solution sdiocard.host = (struct mmc_host *)&sdiohost; //func_sdio.card->host->max_blk_size = param.SEL.SET_BLOCK_SIZE.uiblocksize; //func_sdio.card->host->max_blk_count = 511u; //?? todo for (i = 0; i < funcs; i++) sdiocard.sdio_func[i]->card->host->max_blk_size = 512u; //func_sdio.num = 0;//funcs;//func.num; func_sdio.num = sdiocard.sdio_func[funcs-1]->num;//funcs;//func.num; func_sdio.irq_handler = NULL; //func_sdio.max_blksize = 512u; func_sdio.max_blksize = sdiocard.sdio_func[funcs-1]->max_blksize; //func_sdio.cur_blksize = sdioHost_getBlksize(SDIO_HOST_ID_2); func_sdio.enable_timeout = sdiocard.sdio_func[funcs-1]->enable_timeout; func_sdio.vendor = sdiocard.sdio_func[funcs-1]->vendor; func_sdio.device = sdiocard.sdio_func[funcs-1]->device; func_sdio.num_info = sdiocard.sdio_func[funcs-1]->num_info; func_sdio.class = sdiocard.sdio_func[funcs-1]->class; wifi_sdio_func = &func_sdio; sdio_set_block_size(sdiocard.sdio_func[funcs-1], 0); func_sdio.cur_blksize = sdiocard.sdio_func[funcs-1]->cur_blksize; //xTaskCreate(sdio_irq_task, "sdio_irq_thread", 8192, NULL, 6, &sdio_irq_task_handler ); //xTaskCreate(sdio_irq_task, "sdio_irq_thread", 8192, NULL, 27, &sdio_irq_task_handler ); if(0) xTaskCreate(sdio_irq_task, "sdio_irq_thread", 8192, NULL, 30, &sdio_irq_task_handler ); else{ THREAD_HANDLE wifi_sdio_irq_task = 0; wifi_sdio_irq_task = vos_task_create(sdio_irq_task, 0, "sdio_irq_thread", 1, 8192*4); if (wifi_sdio_irq_task == 0) { printf("create sdio_irq_thread fail\n"); } else { vos_task_resume(wifi_sdio_irq_task); } } return 0; } int sdio_bus_probe(void) { printf("sdio_bus_probe()\n"); return 0; } int sdio_bus_remove(void) { printf("%s \n",__func__); return 0; } struct sdio_func *sdio_get_func(void) { return &func_sdio; } #define SDIO_CCCR_IOEx 0x02 #define SDIO_CCCR_IORx 0x03 int sdio_enable_func(struct sdio_func *func) { int ret; unsigned char reg; //unsigned long timeout; //BUG_ON(!func); //BUG_ON(!func->card); //sdiolinux_printf("SDIO: Enabling device %s...\n", sdio_func_id(func)); ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, ®); if (ret){ printf("sdio_enable_func:set SDIO_CCCR_IOEx fail\n"); goto err; } reg |= 1 << func->num; ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL); if (ret){ printf("sdio_enable_func:set SDIO_CCCR_IOEx fail\n"); goto err; } //?? todo //??timeout = jiffies + msecs_to_jiffies(func->enable_timeout); while (1) { ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, ®); if (ret) goto err; if (reg & (1 << func->num)) break; //??ret = -ETIME; //??if (time_after(jiffies, timeout)) //?? goto err; } //?? todo end //sdiolinux_printf("SDIO: Enabled device %s\n", sdio_func_id(func)); return 0; err: printf("SDIO: Failed to enable device %p\n", func); return ret; } int sdio_disable_func(struct sdio_func *func) { int ret; unsigned char reg; //BUG_ON(!func); //BUG_ON(!func->card); //sdiolinux_printf("SDIO: Disabling device %s...\n", sdio_func_id(func)); ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, ®); if (ret){ printf("sdio_disable_func:set SDIO_CCCR_IOEx fail\n"); goto err; } reg &= ~(1 << func->num); ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL); if (ret){ printf("sdio_disable_func:set SDIO_CCCR_IOEx fail\n"); goto err; } //sdiolinux_printf("SDIO: Disabled device %s\n", sdio_func_id(func)); return 0; err: printf("SDIO: Failed to disable device %p\n", func); return -1; } static BOOL sdio_default_callback(BOOL b) { iset_flg(FLG_ID_WIFI_SDIO, FLGPTN_WIFI_SDIO); return TRUE; } void sdio_host_ioint_enable(unsigned int enable) { extern UINT32 sdioHost_setIoIntEn(unsigned int id, int bEn); sdioHost_setIoIntEn(SDIO_HOST_ID_2, enable); } int sdio_claim_irq(struct sdio_func *func, void(*handler)(struct sdio_func *)) { int ret; unsigned char reg; func->irq_handler = NULL; ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®); if (ret){ printf("sdio_claim_irq:set SDIO_CCCR_IENx fail\n"); return ret; } reg |= 1 << func->num; reg |= 1; /* Master interrupt enable */ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL); if (ret){ printf("sdio_claim_irq:set SDIO_CCCR_IENx fail\n"); return ret; } //sdio_reg_iocallback((sdio_iocallback_hdl)handler); save_sdio_func = func; vpSdioLinuxIoHdl = handler; //sdio_reg_iocallback((sdio_iocallback_hdl)sdio_default_callback); #define SDIO_CALLBACK_IO_INT 4 sdio2_setCallBack(SDIO_CALLBACK_IO_INT, sdio_default_callback); extern UINT32 sdioHost_setIoIntEn(unsigned int id, int bEn); sdioHost_setIoIntEn(SDIO_HOST_ID_2, 1); func->irq_handler = handler; return 0; } int sdio_release_irq(struct sdio_func *func) { int ret; unsigned char reg; if (func->irq_handler) { func->irq_handler = NULL; } //sdio_reg_iocallback((sdio_iocallback_hdl)func->irq_handler); #define SDIO_CALLBACK_IO_INT 4 sdio2_setCallBack(SDIO_CALLBACK_IO_INT, NULL); sdio2_setIOEnable(SDIO_HOST_IOINT_DIS); ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®); if (ret){ printf("sdio_release_irq:set SDIO_CCCR_IENx fail\n"); return ret; } reg &= ~(1 << func->num); /* Disable master interrupt with the last function interrupt */ if (!(reg & 0xFE)) reg = 0; ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL); if (ret){ printf("sdio_release_irq:set SDIO_CCCR_IENx fail\n"); return ret; } return 0; } int sdio_memcpy_fromio(struct sdio_func *func, void *dst,unsigned int addr, int count) { return mmc_io_rw_ext_helper(func, 0, addr, 1, dst, count); } int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,void *src, int count) { return mmc_io_rw_ext_helper(func, 1, addr, 1, src, count); } u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret) { int ret; u8 val; //u8 in; //BUG_ON(!func); if (err_ret) *err_ret = 0; //in = 0; ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val); if (ret) { if (err_ret) *err_ret = ret; return 0xFF; } return val; } u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret) { int ret; if (err_ret) *err_ret = 0; ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2); if (ret) { if (err_ret) *err_ret = ret; return 0xFFFF; } return *(u16 *)func->tmpbuf; } static u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret) { int ret; if (err_ret) *err_ret = 0; ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4); if (ret) { if (err_ret) *err_ret = ret; return 0xFFFFFFFF; } return *(u32 *)(func->tmpbuf); } void sdio_writeb(struct sdio_func *func, u8 b,unsigned int addr, int *err_ret) { int ret; //BUG_ON(!func); ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL); if (err_ret) *err_ret = ret; } static void sdio_writew(struct sdio_func *func, u16 b,unsigned int addr, int *err_ret) { int ret; *(u16 *)func->tmpbuf = b; ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2); if (err_ret) *err_ret = ret; } static void sdio_writel(struct sdio_func *func, u32 b,unsigned int addr, int *err_ret) { int ret; *(u32 *)func->tmpbuf = b; ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4); if (err_ret) *err_ret = ret; } /* test wifi driver */ #define ADDR_MASK 0x10000 #define LOCAL_ADDR_MASK 0x00000 int wifi_read(struct sdio_func *func, u32 addr, u32 cnt, void *pdata) { int err; sdio_claim_host(func); err = sdio_memcpy_fromio(func, pdata, addr, cnt); if (err) { printf("%s: FAIL(%d)! ADDR=%#x Size=%d\n", __func__, err, addr, cnt); } sdio_release_host(func); return err; } int wifi_write(struct sdio_func *func, u32 addr, u32 cnt, void *pdata) { int err; u32 size; sdio_claim_host(func); size = cnt; err = sdio_memcpy_toio(func, addr, pdata, size); if (err) { printf("%s: FAIL(%d)! ADDR=%#x Size=%d(%d)\n", __func__, err, addr, cnt, size); } sdio_release_host(func); return err; } u8 wifi_readb(struct sdio_func *func, u32 addr) { int err; u8 ret = 0; sdio_claim_host(func); ret = sdio_readb(func, ADDR_MASK | addr, &err); sdio_release_host(func); if (err) printf("%s: FAIL!(%d) addr=0x%05x\n", __func__, err, addr); return ret; } u16 wifi_readw(struct sdio_func *func, u32 addr) { int err; u16 v; sdio_claim_host(func); v = sdio_readw(func, ADDR_MASK | addr, &err); sdio_release_host(func); if (err) printf("%s: FAIL!(%d) addr=0x%05x\n", __func__, err, addr); return v; } u32 wifi_readl(struct sdio_func *func, u32 addr) { int err; u32 v; sdio_claim_host(func); v = sdio_readl(func, ADDR_MASK | addr, &err); sdio_release_host(func); return v; } void wifi_writeb(struct sdio_func *func, u32 addr, u8 val) { int err; sdio_claim_host(func); sdio_writeb(func, val, ADDR_MASK | addr, &err); sdio_release_host(func); if (err) printf("%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, err, addr, val); } void wifi_writew(struct sdio_func *func, u32 addr, u16 v) { int err; sdio_claim_host(func); sdio_writew(func, v, ADDR_MASK | addr, &err); sdio_release_host(func); if (err) printf("%s: FAIL!(%d) addr=0x%05x val=0x%04x\n", __func__, err, addr, v); } void wifi_writel(struct sdio_func *func, u32 addr, u32 v) { int err; sdio_claim_host(func); sdio_writel(func, v, ADDR_MASK | addr, &err); sdio_release_host(func); } u8 wifi_readb_local(struct sdio_func *func, u32 addr) { int err; u8 ret = 0; ret = sdio_readb(func, LOCAL_ADDR_MASK | addr, &err); return ret; } void wifi_writeb_local(struct sdio_func *func, u32 addr, u8 val) { int err; sdio_writeb(func, val, LOCAL_ADDR_MASK | addr, &err); } /*below functions are exported sdio_bus_probe, sdio_bus_remove, sdio_enable_func, sdio_disable_func, sdio_reg_driver, sdio_unreg_driver, sdio_claim_irq, sdio_release_irq, sdio_claim_host, sdio_release_host, sdio_readb, sdio_readw, sdio_readl, sdio_writeb, sdio_writew, sdio_writel, sdio_memcpy_fromio, sdio_memcpy_toio */