|  | /******************************************************************************* | 
|  | * °æÈ¨ËùÓÐ (C)2010, ÉîÛÚÊÐÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£ | 
|  | * | 
|  | * ÎļþÃû³Æ£º sdio.c | 
|  | * ÄÚÈÝÕªÒª£º | 
|  | * ÆäËü˵Ã÷£º | 
|  | * µ±Ç°°æ±¾£º 1.0 | 
|  | * ×÷¡¡¡¡Õߣºcaidaofang | 
|  | * Íê³ÉÈÕÆÚ£º | 
|  | * | 
|  | * | 
|  | *******************************************************************************/ | 
|  | #include <common.h> | 
|  | #include <linux/byteorder/generic.h> | 
|  | #include <asm/io.h> | 
|  | #include <sdio.h> | 
|  | #include <image.h> | 
|  |  | 
|  |  | 
|  | #define SYS_STD_CRM_BASE                   0x1307000 | 
|  | #define DMA_BUFFER_SIZE_16K               (0x2<<1) | 
|  |  | 
|  | #define DMA_BUFFER_SIZE_32K               (0x3<<1) | 
|  | #define DMA_BUFFER_SIZE_64K               (0x4<<1) | 
|  |  | 
|  | #define DMA_BUFFER_SIZE_256K              (0x6<<1) | 
|  | #define DMA_BUFFER_SIZE_512K              (0x7<<1) | 
|  | #define SDIO_ERR                           -1 | 
|  | #define SDIO_INPROGRESS                    -2 | 
|  |  | 
|  | uint32_t uboot_entry_point = 0; | 
|  |  | 
|  | static void sdio_clk_reset(void) | 
|  | { | 
|  | // enable sdio clk  16,17 hclk | 
|  | REG32(SYS_STD_CRM_BASE+0x44) |= (0x3<<16); | 
|  | usdelay(80); | 
|  | // release reset sdio clk 16 ahb clk | 
|  | REG32(SYS_STD_CRM_BASE+0x48) |= (0x1<<16); | 
|  | usdelay(80); | 
|  | } | 
|  |  | 
|  | /*²ÉÓÃCPU¶ÁÈ¡FIFO£¬½ûÖ¹ÖжÏ*/ | 
|  | static void sdio_initial_setup(void) | 
|  | { | 
|  | u32 val = 0; | 
|  | REG32(SDIO_SLAVE_IOREADY)          |= 0x3e;//ÅäÖÃ1-5bit | 
|  |  | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN)      = 0;  //mask sdio int | 
|  | REG32(SDIO_SLAVE_INTSTATUS)         = 0xffffffff;//clear int | 
|  |  | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN)      = 0xffffffff; //enable status int | 
|  |  | 
|  | //REG32(SDIO_SLAVE_INTSTATUS_EN)      = 0x33C0181B; //enable status int | 
|  | REG32(SDIO_SLAVE_INTSIGNAL_EN)      = 0; //maskedÖжÏÐźÅ1£¬²»Éϱ¨¸øÖжϿØÖÆÆ÷ | 
|  | REG32(SDIO_SLAVE_INT_SIGNAL_EN2)    = 0; //maskedÖжÏÐźÅ2£¬²»Éϱ¨¸øÖжϿØÖÆÆ÷ | 
|  | val = REG32(SDIO_SLAVE_SDIO_CCCR_CTRL); | 
|  | REG32(SDIO_SLAVE_SDIO_CCCR_CTRL)    = val;//0x3FF3E343; | 
|  |  | 
|  | REG32(0x1307080)= 0x7ffe0; | 
|  |  | 
|  | memset((u8*)0x20000000,0,1024*180); | 
|  |  | 
|  | val = REG32(SDIO_SLAVE_CARD_OCR); | 
|  |  | 
|  | REG32(SDIO_SLAVE_CARD_OCR) = val|0x01000000; | 
|  |  | 
|  | /*dma*/ | 
|  | /*dma1 address register config*/ | 
|  | //  REG32(SDIO_SLAVE_DMA1ADDR)          = CFG_SDIO_LOAD_BASE; //set dma address | 
|  | /*adma/dma1 address register and buffer size is 0:not valid 1:valid,buffer size is 4K(default)*/ | 
|  | // REG32(SDIO_SLAVE_DMA1CTRL)         |=0x1|DMA_BUFFER_SIZE_256K;  //enable dma address | 
|  | /*disable adma£¬enable dma ,sel one*/ | 
|  | REG32(SDIO_SLAVE_CTRL2)            &=(~0x4); | 
|  |  | 
|  | /*sdio slave config ready operate*/ | 
|  | REG32(SDIO_SLAVE_CTRL)             |=0x4; //ÅäÖõÚ2bit£¬±íʾ׼±¸²Ù×÷ | 
|  |  | 
|  |  | 
|  |  | 
|  | } | 
|  |  | 
|  | int Sdio_Slave_Read_4K(const u32 load_addr,u32 len) | 
|  | { | 
|  | u32 status =0 ; | 
|  | int ret = 0; | 
|  |  | 
|  | u32 dma_addr = (u32)CFG_SDIO_LOAD_BASE; | 
|  |  | 
|  | REG32(SDIO_SLAVE_DMA1ADDR)  = CFG_SDIO_LOAD_BASE;  //CFG_SDIO_LOAD_BASE; | 
|  | REG32(SDIO_SLAVE_DMA1CTRL) |= 0x1;    //|DMA_BUFFER_SIZE_512K;    //256K | 
|  |  | 
|  | while(1) | 
|  | { | 
|  | status = REG32(SDIO_SLAVE_INTSTATUS); | 
|  |  | 
|  | if((status &SDIO_STS_DMA1)!=0) | 
|  | { | 
|  |  | 
|  | dma_addr += 0x1000; | 
|  | /*1,mask*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN)&=(~SDIO_STS_DMA1); | 
|  | /*2,clear*/ | 
|  |  | 
|  | REG32(SDIO_SLAVE_INTSTATUS) |= SDIO_STS_DMA1; | 
|  | /*3,enalbe*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) |= SDIO_STS_DMA1; | 
|  |  | 
|  | REG32(SDIO_SLAVE_DMA1ADDR)  = dma_addr ;//CFG_SDIO_LOAD_BASE; | 
|  | REG32(SDIO_SLAVE_DMA1CTRL) |= 0x1; | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | if((status &SDIO_STS_TC)!=0) | 
|  | { | 
|  | // printf("SDIO xfer OK!\n"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if((status &SDIO_STS_F_CRC_E)!=0) | 
|  | { | 
|  | printf("SDIO CRC Error!\n"); | 
|  |  | 
|  | /*1,mask*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN)&=(~SDIO_STS_F_CRC_E); | 
|  | /*2,clear*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS) |= SDIO_STS_F_CRC_E; | 
|  | /*3,enalbe*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) |= SDIO_STS_F_CRC_E; | 
|  |  | 
|  | ret = SDIO_ERR; | 
|  | } | 
|  |  | 
|  | if((status &SDIO_STS_F_A)!=0) | 
|  | { | 
|  |  | 
|  | /*1,mask*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN)&=(~SDIO_STS_F_A); | 
|  | /*2,clear*/ | 
|  | //status = REG32(SDIO_SLAVE_INTSTATUS); | 
|  | REG32(SDIO_SLAVE_INTSTATUS) |= SDIO_STS_F_A; | 
|  | /*3,enalbe*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) |= SDIO_STS_F_A; | 
|  |  | 
|  |  | 
|  | printf("SDIO ABORT Xfer!\n"); | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | } | 
|  | /*thansfer complete,write program done*/ | 
|  | REG32(SDIO_SLAVE_CTRL)     |= 0x1; | 
|  | /*clear int status*/ | 
|  | /*1,mask*/ | 
|  | // REG32(SDIO_SLAVE_INTSTATUS_EN)&=(~(SDIO_STS_TC|SDIO_STS_WS|SDIO_STS_DMA1|SDIO_STS_F_A|SDIO_STS_F_CRC_E)); | 
|  |  | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) = 0; | 
|  | /*2,clear*/ | 
|  | status = REG32(SDIO_SLAVE_INTSTATUS); | 
|  | REG32(SDIO_SLAVE_INTSTATUS) = status; | 
|  | /*3,enalbe*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) = 0xffffffff; | 
|  |  | 
|  | /*thansfer complete,write program done*/ | 
|  | // REG32(SDIO_SLAVE_CTRL)     |= 0x1; | 
|  |  | 
|  | // REG32(SDIO_SLAVE_INTSTATUS_EN)      = 0x33C0181B; //enable status int; | 
|  | memcpy(load_addr,(u32)CFG_SDIO_LOAD_BASE,len); | 
|  |  | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | int Sdio_Slave_Write_Ack(void) | 
|  | { | 
|  |  | 
|  |  | 
|  | u32 status = 0; | 
|  | int ret = 0; | 
|  |  | 
|  | //u32 ack[2] = {0x11223344,0xAABBCCDD}; | 
|  | char *ack = "rxok"; | 
|  |  | 
|  | memcpy((u32)CFG_SDIO_LOAD_BASE,ack,4); | 
|  |  | 
|  | printf("SDIO write ack\n"); | 
|  |  | 
|  | REG32(SDIO_SLAVE_DMA1ADDR)  = CFG_SDIO_LOAD_BASE; | 
|  | REG32(SDIO_SLAVE_DMA1CTRL) |= 0x1; | 
|  |  | 
|  | while(1) | 
|  | { | 
|  | status = REG32(SDIO_SLAVE_INTSTATUS); | 
|  |  | 
|  |  | 
|  | if((status &SDIO_STS_TC)!=0) | 
|  | { | 
|  | // printf("SDIO xfer OK!\n"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if((status &SDIO_STS_F_CRC_E)!=0) | 
|  | { | 
|  | printf("SDIO CRC Error!\n"); | 
|  |  | 
|  | /*1,mask*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN)&=(~SDIO_STS_F_CRC_E); | 
|  | /*2,clear*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS) |= SDIO_STS_F_CRC_E; | 
|  | /*3,enalbe*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) |= SDIO_STS_F_CRC_E; | 
|  |  | 
|  | ret = SDIO_ERR; | 
|  | } | 
|  |  | 
|  | if((status &SDIO_STS_F_A)!=0) | 
|  | { | 
|  |  | 
|  | /*1,mask*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN)&=(~SDIO_STS_F_A); | 
|  | /*2,clear*/ | 
|  | //status = REG32(SDIO_SLAVE_INTSTATUS); | 
|  | REG32(SDIO_SLAVE_INTSTATUS) |= SDIO_STS_F_A; | 
|  | /*3,enalbe*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) |= SDIO_STS_F_A; | 
|  |  | 
|  |  | 
|  | printf("SDIO ABORT Xfer!\n"); | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | } | 
|  | /*thansfer complete,write program done*/ | 
|  | // REG32(SDIO_SLAVE_CTRL)     |= 0x1; | 
|  | /*clear int status*/ | 
|  | /*1,mask*/ | 
|  |  | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) = 0; | 
|  | /*2,clear*/ | 
|  | status = REG32(SDIO_SLAVE_INTSTATUS); | 
|  | REG32(SDIO_SLAVE_INTSTATUS) = status; | 
|  | /*3,enalbe*/ | 
|  | REG32(SDIO_SLAVE_INTSTATUS_EN) = 0xffffffff; | 
|  |  | 
|  | return ret; | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | static int sdio_slave_init(void) | 
|  | { | 
|  |  | 
|  | // SDIOÉèÖÃCPRMÄ£¿éµÄ´úÂë | 
|  | //sdio_clk_reset(); | 
|  |  | 
|  | // Initialize controller | 
|  | sdio_initial_setup(); | 
|  |  | 
|  |  | 
|  |  | 
|  | } | 
|  |  | 
|  | static int slave_size = 0; | 
|  |  | 
|  | /**************   success :return boot size  ***********/ | 
|  | int sdio_slave_read(const u32 load_addr) | 
|  | { | 
|  | u32 dwInt_status = 0; | 
|  | u32 dwCurrent_Cmd = 0; | 
|  | u32 cmdreg =0; | 
|  | u32 argreg = 0; | 
|  | u32 cmd = 0; | 
|  | u32 blksize = 0; | 
|  | u32 blkcnt = 0; | 
|  | u32 boot_size = 0; | 
|  |  | 
|  | int ret = SDIO_INPROGRESS; | 
|  |  | 
|  | while(1) | 
|  | { | 
|  | // dwCurrent_CmdΪ53ʱ£¬½øÐÐÊý¾Ýдor¶Á²Ù×÷ | 
|  |  | 
|  | dwCurrent_Cmd = ((REG32(SDIO_SLAVE_CMD)>>13) & 0x3F); | 
|  |  | 
|  | switch(dwCurrent_Cmd) | 
|  | { | 
|  | case SDIO_CMD53: | 
|  | { | 
|  |  | 
|  | dwInt_status = REG32(SDIO_SLAVE_INTSTATUS); | 
|  |  | 
|  |  | 
|  | if((dwInt_status & SDIO_STS_WS) == SDIO_STS_WS) | 
|  | { | 
|  | cmdreg = REG32(SDIO_SLAVE_CMD); | 
|  | argreg = REG32(SDIO_SLAVE_ARGU); | 
|  |  | 
|  | blksize = (cmdreg >>1) &0xFFF; | 
|  |  | 
|  | blkcnt = argreg & 0x1FF; | 
|  |  | 
|  | if(!(argreg & 0x08000000)) | 
|  | { | 
|  |  | 
|  | boot_size =blksize; | 
|  | } | 
|  | else | 
|  | { | 
|  | boot_size =blkcnt * blksize; | 
|  | } | 
|  |  | 
|  | slave_size = boot_size; | 
|  |  | 
|  |  | 
|  | ret = Sdio_Slave_Read_4K(load_addr,boot_size); | 
|  |  | 
|  | if(!ret) | 
|  | return boot_size; | 
|  | else if(ret == SDIO_ERR) | 
|  | return SDIO_ERR; | 
|  |  | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | return boot_size; | 
|  | } | 
|  |  | 
|  | int sdio_slave_write(void) | 
|  | { | 
|  |  | 
|  |  | 
|  | u32 dwInt_status = 0; | 
|  | u32 dwCurrent_Cmd = 0; | 
|  | u32 cmdreg =0; | 
|  | u32 argreg = 0; | 
|  | u32 cmd = 0; | 
|  | u32 blksize = 0; | 
|  | u32 blkcnt = 0; | 
|  | u32 boot_size = 0; | 
|  |  | 
|  | int ret = SDIO_INPROGRESS; | 
|  |  | 
|  | printf("SDIO slave write \n"); | 
|  |  | 
|  | REG32(SDIO_SLAVE_FUN1CTRL) |= (0x4 & 0xFFFF); | 
|  |  | 
|  | while(1) | 
|  | { | 
|  | dwCurrent_Cmd = ((REG32(SDIO_SLAVE_CMD)>>13) & 0x3F); | 
|  |  | 
|  | switch(dwCurrent_Cmd) | 
|  | { | 
|  | case SDIO_CMD53: | 
|  | { | 
|  |  | 
|  | dwInt_status = REG32(SDIO_SLAVE_INTSTATUS); | 
|  |  | 
|  |  | 
|  | if((dwInt_status & SDIO_STS_RS) == SDIO_STS_RS) | 
|  | { | 
|  | cmdreg = REG32(SDIO_SLAVE_CMD); | 
|  | argreg = REG32(SDIO_SLAVE_ARGU); | 
|  |  | 
|  | blksize = (cmdreg >>1) &0xFFF; | 
|  |  | 
|  | blkcnt = argreg & 0x1FF; | 
|  |  | 
|  | if(!(argreg & 0x08000000)) | 
|  | { | 
|  |  | 
|  | boot_size =blksize; | 
|  | } | 
|  | else | 
|  | { | 
|  | boot_size =blkcnt * blksize; | 
|  | } | 
|  |  | 
|  |  | 
|  | ret = Sdio_Slave_Write_Ack(); | 
|  |  | 
|  | if(!ret) | 
|  | return boot_size; | 
|  | else if(ret == SDIO_ERR) | 
|  | return SDIO_ERR; | 
|  |  | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  |  | 
|  | } | 
|  |  | 
|  | return boot_size; | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | /******************************************************************************* | 
|  | * Function: | 
|  | * Description: | 
|  | * Parameters: | 
|  | *	 Input: | 
|  | * | 
|  | *	 Output: | 
|  | * | 
|  | * Returns: | 
|  | * | 
|  | * | 
|  | * Others: | 
|  | ********************************************************************************/ | 
|  | int sdio_slave_read_bin() | 
|  | { | 
|  | int32_t len = 0; | 
|  | uint32_t i =0; | 
|  |  | 
|  | /*1.µÚÒ»´Î½ÓÊÕ */ | 
|  | len = sdio_slave_read((u32)CFG_TEMP_ADDR); | 
|  | if( len < 0 ) | 
|  | { | 
|  | printf("sdio_slave: read first error\n"); | 
|  | goto sdio_error1; | 
|  | } | 
|  |  | 
|  | /*2.»ñÈ¡°æ±¾ÐÅÏ¢ */ | 
|  | image_header_t *header = NULL; | 
|  | header = (image_header_t *)CFG_TEMP_ADDR; | 
|  | uint32_t header_size = sizeof(image_header_t); | 
|  | uint32_t size = ___htonl(header->ih_size); | 
|  | uint32_t load_addr = ___htonl(header->ih_load); | 
|  | uboot_entry_point = ___htonl(header->ih_ep); | 
|  |  | 
|  | /*3.¿½±´µÚÒ»´ÎÊý¾Ý */ | 
|  | memcpy(load_addr, CFG_TEMP_ADDR+sizeof(image_header_t), len); | 
|  | load_addr = load_addr + len - header_size; | 
|  |  | 
|  | /*4.¼ÆËã´«Êä´ÎÊý */ | 
|  | /* Èç¹ûµÚÒ»´Î´«ÊäµÄ×Ö½Ú´óÓÚ»òµÈÓÚ°æ±¾µÄ´óС£¬Ôò´«ÊäÍê³ÉÖ±½Ó·µ»Ø */ | 
|  | if( (len > size) || (len == size) ) | 
|  | { | 
|  | printf("sdio_slave: first finsh and return\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | uint32_t left_times = size/CFG_SDIO_SLAVE_PACKAGE_LEN; | 
|  | uint32_t mod = size%CFG_SDIO_SLAVE_PACKAGE_LEN; | 
|  | if( mod == 0 ) | 
|  | { | 
|  | left_times--; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* debug */ | 
|  | printf("sdio_slave: display the transfer times\n"); | 
|  | for( i=0; i<left_times+1; i++ ) | 
|  | printf(" + "); | 
|  | printf("\n"); | 
|  |  | 
|  | /*5.½ÓÊÕÆäÓàµÄÊý¾Ý */ | 
|  | for( i=0; i<left_times; i++ ) | 
|  | { | 
|  | len = sdio_slave_read(load_addr); | 
|  | if( len < 0 ) | 
|  | { | 
|  | printf("sdio_slave: read others error\n"); | 
|  | goto sdio_error1; | 
|  | } | 
|  | load_addr += len; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | sdio_error1: | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /******************************************************************************* | 
|  | * Function: | 
|  | * Description: | 
|  | * Parameters: | 
|  | *	 Input: | 
|  | * | 
|  | *	 Output: | 
|  | * | 
|  | * Returns: | 
|  | * | 
|  | * | 
|  | * Others: | 
|  | ********************************************************************************/ | 
|  | void sdio_slave_process(void) | 
|  | { | 
|  | int ret = 0; | 
|  |  | 
|  | //sdio_slave_init(); | 
|  | printf("run into sdio_slave_process\n"); | 
|  | /* 1. ½ÓÊÕuboot  */ | 
|  | ret = sdio_slave_read_bin(); | 
|  | if( ret != 0 ) | 
|  | { | 
|  | printf("sdio_slave: read uboot error\n"); | 
|  | goto wait_error; | 
|  | } | 
|  | printf("sdio_slave: read uboot OK\n"); | 
|  |  | 
|  |  | 
|  |  | 
|  | ret = sdio_slave_write(); | 
|  | if(ret > 0) | 
|  | { | 
|  |  | 
|  | printf("sdio_slave: write ack success\n"); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /*  r7 Ìø×ªÆô¶¯´úÂë */ | 
|  | writel(0xE59ff000, 0x100000); | 
|  | writel(uboot_entry_point, 0x100000 + 8); | 
|  |  | 
|  | printf("Start the uboot....\n"); | 
|  |  | 
|  |  | 
|  | writel(0xf, 0x130702c); | 
|  |  | 
|  | while(1); | 
|  |  | 
|  | wait_error: | 
|  | printf("sdio_slave: error wait\n"); | 
|  | while(1); | 
|  | } | 
|  |  |