1565 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1565 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| #include <FreeRTOS.h>
 | |
| #include <task.h>
 | |
| #include <timers.h>
 | |
| #include <stdio.h>
 | |
| #include "kwrap/semaphore.h"
 | |
| #include "semphr.h"
 | |
| #include "sys.h"
 | |
| #include <kwrap/flag.h>
 | |
| #include <kwrap/task.h>
 | |
| #include <sdio.h>
 | |
| 
 | |
| #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
 | |
| */
 | 
