| /******************************************************************************* |
| * °æÈ¨ËùÓÐ (C)2010, ÉîÛÚÊÐÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£ |
| * |
| * ÎļþÃû³Æ£º sdio.c |
| * ÄÚÈÝÕªÒª£º |
| * ÆäËü˵Ã÷£º |
| * µ±Ç°°æ±¾£º 1.0 |
| * ×÷¡¡¡¡Õߣºcaidaofang |
| * Íê³ÉÈÕÆÚ£º |
| * |
| * |
| *******************************************************************************/ |
| |
| #include <common.h> |
| #include <errno.h> |
| #include <command.h> |
| #include <malloc.h> |
| #include <jffs2/load_kernel.h> |
| #include <linux/list.h> |
| #include <linux/ctype.h> |
| #include <linux/err.h> |
| #include <linux/mtd/mtd.h> |
| #include <load_image.h> |
| #include <linux/byteorder/generic.h> |
| #include <sdio.h> |
| #include <image.h> |
| #include <config.h> |
| |
| |
| #define CFG_TEMP_ADDR 0x22000000 |
| |
| #define CFG_SDIO_SLAVE_PACKAGE_LEN 0xD800 /* K */ |
| #define CFG_SDIO_SLAVE_ALIGN_LEN 0x200 /* 512byte */ |
| |
| |
| |
| #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 |
| |
| static void usdelay(uint32_t delay) |
| { |
| uint32_t i = 0; |
| for( ; i<delay*200; i++ ); |
| } |
| |
| 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) = 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_32K(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_32K; //|DMA_BUFFER_SIZE_512K; //256K |
| |
| while(1) |
| { |
| status = REG32(SDIO_SLAVE_INTSTATUS); |
| |
| if((status &SDIO_STS_DMA1)!=0) |
| { |
| |
| dma_addr += 0x8000; |
| /*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|DMA_BUFFER_SIZE_32K; |
| |
| } |
| |
| |
| 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(); |
| |
| return 0; |
| } |
| |
| 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_32K(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; |
| |
| |
| 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); |
| uint32_t entry_point = ___htonl(header->ih_ep); |
| |
| printf("size = %d\n", (int)size); |
| printf("load_addr = 0x%0x\n", (unsigned int)load_addr); |
| printf("entry_point = 0x%0x\n", (unsigned int)entry_point); |
| |
| |
| /*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: times = %d\n", (int)(left_times+1)); |
| |
| |
| |
| /*5.½ÓÊÕÆäÓàµÄÊý¾Ý */ |
| for( i=0; i<(left_times); i++ ) |
| { |
| //printf("sdio_slave: load_addr = 0x%0x\n",load_addr); |
| 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(); |
| |
| |
| /* 1. ½ÓÊÕ */ |
| ret = sdio_slave_read_bin(); |
| if( ret != 0 ) |
| { |
| printf("sdio_slave: read big bin error\n"); |
| goto wait_error; |
| } |
| |
| ret = sdio_slave_write(); |
| if(ret > 0) |
| { |
| |
| printf("sdio_slave: write ack success\n"); |
| } |
| |
| |
| printf("sdio_slave: read big bin OK\n"); |
| |
| while(1); |
| |
| wait_error: |
| printf("sdio_slave: error wait\n"); |
| while(1); |
| } |
| |