| /******************************************************************************* | 
 | * °æÈ¨ËùÓÐ (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); | 
 | } | 
 |  |