blob: 40244f2022c6cd639e4d6fbd6011566819799287 [file] [log] [blame]
/*******************************************************************************
* °æÈ¨ËùÓÐ (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);
}