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