⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sd.c

📁 基于s3c2410、2440的从SD卡引导Linux内核程序
💻 C
字号:
#include <stdio.h>
#include <string.h>
#include "2440addr.h"
#include "SD.h"
#include "UART.h"

//#define	S3C2440		1	//It's S3C2440
#define	S3C2440		0	//It's S3C2410

#define debug		0

extern unsigned int PCLK;

#define INICLK	200000		//200KHz
#define SDCLK	24000000	//24MHz
#define MMCCLK	10000000	//10MHz

volatile unsigned int rd_cnt=0;
volatile unsigned int wt_cnt=0;

int Wide=0; // 0:1bit, 1:4bit
int MMC=0;  // 0:SD  , 1:MMC

volatile int RCA;

int SD_card_init(void)
{
	//-- SD controller & card initialize 
	int i;

	RCA=0;

	Uart_Printf(0,"Now,Start to Init MMC/SD Card.\n");

	/* Important notice for MMC test condition */
	/* Cmd & Data lines must be enabled by pull up resister */
#if	S3C2440
	rSDIPRE=PCLK/INICLK-1;			// 200KHz
	Uart_Printf(0,"Init. Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));
	rSDICON=(0<<4)|1;				// Type A, clk enable
	rSDIFSTA=rSDIFSTA|(1<<16);		// FIFO reset
	rSDIBSIZE=0x200;				// 512byte(128word)
	rSDIDTIMER=0x7fffff;			// Set timeout count
#else	//S3C2410
	rSDIPRE=PCLK/2/INICLK-1;		// 200KHz
	Uart_Printf(0,"Init. Frequency is %dHz\n",(PCLK/2/(rSDIPRE+1)));
	rSDICON=(0<<4)|(1<<1)|(1<<0);	// Type A, FIFO reset, clk enable
	rSDIBSIZE=0x200;				// 512byte(128word)
	rSDIDTIMER=0xffff;
#endif

	for(i=0;i<0x1000;i++);		// Wait 74SDCLK for MMC card
	
#if	S3C2440
	rSDICON=(0<<4)|1;			// Type A, clk enable
	rSDIFSTA=rSDIFSTA|(1<<16);	// FIFO reset
#else
	rSDICON=(0<<4)|(1<<1)|(1<<0);	// Type A, FIFO reset, clk enable
#endif

	CMD0();

	Uart_Printf(0,"Check MMC Card.\n");

	//-- Check MMC card OCR
	if(Chk_MMC_OCR()) 
	{
		MMC=1;
		Uart_Printf(0,"In MMC ready!\n");
		goto RECMD2;
	}

	Uart_Printf(0,"It isn't MMC.\nCheck SD Card.\n");

	//-- Check SD card OCR
	if(Chk_SD_OCR())
	{
		MMC=0;
		Uart_Printf(0,"In SD ready!\n");
	}
	else
	{
		Uart_Printf(0,"Initialize fail\nNo Card assertion\n");
		return 0;
	}
	
RECMD2:
	do
	{
		//-- Check attaced cards, it makes card identification state
		rSDICARG=0x0;	// CMD2(stuff bit)
		rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42;	//lng_resp, wait_resp, start, CMD2
		//-- Check end of CMD2
	}while(!Chk_CMDend(2,1));

	Uart_Printf(0,"CMD2 ---- Successfull !\n");
	//rSDICSTA=0xa00;	// Clear cmd_end(with rsp)
	
RECMD3:
	do{
		//--Send RCA
		rSDICARG=MMC<<16;	    			// CMD3(MMC:Set RCA, SD:Ask RCA-->SBZ)
		rSDICCON=(0x1<<9)|(0x1<<8)|0x43;	// sht_resp, wait_resp, start, CMD3
		//-- Check end of CMD3
	}while(!Chk_CMDend(3,1));

	Uart_Printf(0,"CMD3 ---- Successfull !\n");
	//rSDICSTA=0xa00;	// Clear cmd_end(with rsp)
	
	//--Publish RCA
	if(MMC)
	{
		RCA=1;
#if	S3C2440
		rSDIPRE=(PCLK/MMCCLK)-1;	
		Uart_Printf(0,"MMC Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));
#else
		rSDIPRE=(PCLK/2/MMCCLK)-1;	
		Uart_Printf(0,"MMC Frequency is %dHz\n",(PCLK/2/(rSDIPRE+1)));
#endif
	}
	else 
	{
		RCA=(rSDIRSP0 & 0xffff0000)>>16;
#if	S3C2440
		rSDIPRE=PCLK/SDCLK-1;	// Normal clock=24MHz
		Uart_Printf(0,"SD Frequency is %dHz\n",(PCLK/(rSDIPRE+1)));
#else
		rSDIPRE=PCLK/2/SDCLK-1;	// Normal clock=24MHz
		Uart_Printf(0,"SD Frequency is %dHz\n",(PCLK/2/(rSDIPRE+1)));
#endif
	}
	//--State(stand-by) check
	if(rSDIRSP0 & 0x1e00!=0x600)  // CURRENT_STATE check
		goto RECMD3;
 
	Card_sel_desel(1);	// Select

	if(!MMC)
		Set_4bit_bus();	//SD
	else
		Set_1bit_bus();	//MMC

	return 1;
}

void Card_sel_desel(char sel_desel)
{
	//-- Card select or deselect
	if(sel_desel)
	{
		do
		{
			rSDICARG=RCA<<16;					// CMD7(RCA,stuff bit)
			rSDICCON= (0x1<<9)|(0x1<<8)|0x47;	// sht_resp, wait_resp, start, CMD7
		}while((!Chk_CMDend(7,1))&&(rSDIRSP0 & 0x1e00!=0x800));
		//rSDICSTA=0xa00;	// Clear cmd_end(with rsp)
	}
	else
	{
		do
		{	
			rSDICARG=0<<16;		//CMD7(RCA,stuff bit)
			rSDICCON=(0x1<<8)|0x47;	//no_resp, start, CMD7
		}while(!Chk_CMDend(7,0));
		//rSDICSTA=0x800;	// Clear cmd_end(no rsp)
	}
}

int ReadS(unsigned int address,unsigned int *data,unsigned int size)
{
	int status,block;

	address=address<<9;	//address*512
	
	block=(size/512) + ((size%512 == 0)?0:1);

	rd_cnt=0;    

#if	S3C2440
	rSDIFSTA=rSDIFSTA|(1<<16);	// FIFO reset
	rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<14)|(2<<12)|(block<<0);
#else	//S3C2410
	rSDICON = rSDICON|(1<<1);    //FIFO reset
	rSDIDCON=(1<<19)|(1<<17)|(Wide<<16)|(2<<12)|(block<<0);
#endif

	rSDICARG=address;	// CMD17/18(addr)
	
RERDCMD:
	if(block<2)  //SINGLE_READ   
	{   
		rSDICCON=(0x1<<9)|(0x1<<8)|0x51;    //sht_resp, wait_resp, dat, start, CMD24   
		if(!Chk_CMDend(17,1))  				//Check end of CMD17   
			goto RERDCMD;   
	}   
	else    //MULTI_READ   
	{   
		rSDICCON=(0x1<<9)|(0x1<<8)|0x52;	//sht_resp, wait_resp, dat, start, CMD25   
		if(!Chk_CMDend(18,1))				//Check end of CMD18   
			goto RERDCMD;
	}

	rSDICSTA=0xa00;	// Clear cmd_end(with rsp)

	while(rd_cnt<128*block)	// 512*block bytes
	{
		if((rSDIDSTA&0x20)==0x20) // Check timeout 
		{
			rSDIDSTA=(0x1<<0x5);  // Clear timeout flag
			break;
		}
		status=rSDIFSTA;
		if((status&0x1000)==0x1000)	// Is Rx data?
		{
			*data++ = rSDIDAT;
			rd_cnt++;
		}
	}
	//-- Check end of DATA
	if(!Chk_DATend())
	{
		Uart_Printf(0,"Dat error\n");
		rSDIDSTA=0x10;	// Clear data Tx/Rx end detect
		return 0;
	}
	
	rSDIDSTA=0x10;
	
	if(block>1)   
	{   
		do   
		{   
			rSDICARG=0x0;                       //CMD12(stuff bit)   
			rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;    //sht_resp, wait_resp, start, CMD12   
		}while(!Chk_CMDend(12, 1));   
    } 
	
#if	S3C2440
	rSDIDCON=rSDIDCON&~(7<<12);		
	rSDIFSTA=rSDIFSTA&0x200;	//Clear Rx FIFO Last data Ready
#endif

	rSDIDSTA=0x10;	// Clear data Tx/Rx end detect
	
	return 1;
}


int WriteS(unsigned int address,unsigned int *data,unsigned int size)
{
	int status,block;

	address=address<<9;	//address*512
	
	block=(size/512) + ((size%512 == 0)?0:1);
	
	wt_cnt=0;    

#if	S3C2440
	rSDIFSTA=rSDIFSTA|(1<<16);	// FIFO reset
	rSDIDCON=(2<<22)|(1<<20)|(1<<17)|(Wide<<16)|(1<<14)|(3<<12)|(block<<0);
#else	//S3C2410
	rSDICON = rSDICON|(1<<1);    //FIFO reset
	rSDIDCON=(1<<20)|(1<<17)|(Wide<<16)|(3<<12)|(block<<0);
#endif

	
    rSDICARG=address;	    // CMD24/25(addr)
    
REWTCMD:
	if(block<2)  //SINGLE_WRITE   
	{   
		rSDICCON=(0x1<<9)|(0x1<<8)|0x58;    //sht_resp, wait_resp, dat, start, CMD24   
		if(!Chk_CMDend(24, 1))  //Check end of CMD24   
			goto REWTCMD;   
	}   
	else    //MULTI_WRITE   
	{   
		rSDICCON=(0x1<<9)|(0x1<<8)|0x59;    //sht_resp, wait_resp, dat, start, CMD25   
		if(!Chk_CMDend(25, 1))  //Check end of CMD25   
			goto REWTCMD;
	}
		
	rSDICSTA=0xa00;	// Clear cmd_end(with rsp)  
	while(wt_cnt<128*block)
	{
		status=rSDIFSTA;
		if((status&0x2000)==0x2000) 
		{
			rSDIDAT = *data++;
			wt_cnt++;
			//Uart_Printf("Block No.=%d, wt_cnt=%d\n",block,wt_cnt);
		}
	}
	//-- Check end of DATA
	if(!Chk_DATend())
	{
		Uart_Printf(0,"Dat error\n");
		rSDIDSTA=0x10;	// Clear data Tx/Rx end
		return 1;
	}
	
	if(block>1)   
	{   
		do
		{   
			rSDIDCON=(1<<18)|(1<<17)|(0<<16)|(1<<12)|(block<<0);   
             
			rSDICARG=0x0;						//CMD12(stuff bit)   
			rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;	//sht_resp, wait_resp, start, CMD12   
   
		}while(!Chk_CMDend(12,1));	//Stop cmd(CMD12)  
   
		if(!Chk_BUSYend())      //Check end of DATA(with busy state)   
			Uart_Printf(0,"Error\n");   
               
		rSDIDSTA=0x08;   
	} 
	
#if	S3C2440
	rSDIDCON=rSDIDCON&~(7<<12);		//Clear Data Transfer mode => no operation, Cleata Data Transfer start
#endif

	rSDIDSTA=0x10;	// Clear data Tx/Rx end
	
	return 0;
}


int Chk_CMDend(int cmd, int be_resp)
//0: Timeout
{
	int finish0;

	if(!be_resp)    // No response
	{
		finish0=rSDICSTA;
		while((finish0&0x800)!=0x800)	// Check cmd end
			finish0=rSDICSTA;

		rSDICSTA=finish0;// Clear cmd end state
		
#if debug		
		Uart_Printf(0,"CMD%d ---- Successfull !\n",cmd);
#endif

		return 1;
	}
	else	// With response
	{
		finish0=rSDICSTA;
		while( !( ((finish0&0x200)==0x200) | ((finish0&0x400)==0x400) ))    // Check cmd/rsp end
			finish0=rSDICSTA;
		if(cmd==1 | cmd==41)	// CRC no check, CMD9 is a long Resp. command.
		{
			if( (finish0&0xf00) != 0xa00 )  // Check error
			{
				rSDICSTA=finish0;   // Clear error state
				if(((finish0&0x400)==0x400))
					return 0;	// Timeout error
			}
			rSDICSTA=finish0;	// Clear cmd & rsp end state
		}
		else	// CRC check
		{
			if( (finish0&0x1f00) != 0xa00 )	// Check error
			{
				Uart_Printf(0,"ERRER!\n");
				Uart_Printf(0,"CMD%d:rSDICSTA=0x%x, rSDIRSP0=0x%x\n",cmd, rSDICSTA, rSDIRSP0);
				rSDICSTA=finish0;   // Clear error state
				if(((finish0&0x400)==0x400))
					return 0;	// Timeout error
			}
			rSDICSTA=finish0;
		}
		
#if debug
		Uart_Printf(0,"CMD%d ---- Successfull !\n",cmd);
#endif

		return 1;
	}
}

int Chk_DATend(void)
{
	int finish;

	finish=rSDIDSTA;
	while( !( ((finish&0x10)==0x10) | ((finish&0x20)==0x20) ))	// Chek timeout or data end
		finish=rSDIDSTA;
	if( (finish&0xfc) != 0x10 )
	{
		Uart_Printf(0,"DATA:finish=0x%x\n", finish);
		rSDIDSTA=0xec;  // Clear error state
		return 0;
	}
	return 1;
}

int Chk_BUSYend(void)
{
	int finish;

	finish=rSDIDSTA;
	while( !( ((finish&0x08)==0x08) | ((finish&0x20)==0x20) ))
		finish=rSDIDSTA;
	if( (finish&0xfc) != 0x08 )
	{
		Uart_Printf(0,"DATA:finish=0x%x\n", finish);
		rSDIDSTA=0xf4;  //clear error state
		return 0;
	}
	return 1;
}

int Chk_MMC_OCR(void)
{
	int i,j;
	//-- Negotiate operating condition for MMC, it makes card ready state
	for(i=0;i<50;i++)	//Negotiation time is dependent on CARD Vendors.
	{
		CMD55();
		//rSDICARG=0xff8000;			//CMD1(SD OCR:2.7V~3.6V)
		rSDICARG=0xffc000;			//CMD1(MMC OCR:2.6V~3.6V)
    	rSDICCON=(0x1<<9)|(0x1<<8)|0x41;    //sht_resp, wait_resp, start, CMD1
		if(Chk_CMDend(1,1) & rSDIRSP0==0x80ffc000) //[31]:Card Power up status bit (busy)
		{
			//rSDICSTA=0xa00;	// Clear cmd_end(with rsp)
			return 1;	// Success
		}
		for(j=0;j<0x1000;j++);	// Wait Card power up status
	}
	//rSDICSTA=0xa00;	// Clear cmd_end(with rsp)
	return 0;		// Fail
}

int Chk_SD_OCR(void)
{
	int i,j;
	//-- Negotiate operating condition for SD, it makes card ready state
	for(i=0;i<50;i++)	//If this time is short, init. can be fail.
	{
		CMD55();    // Make ACMD
    	rSDICARG=0xff8000;		//ACMD41(SD OCR:2.7V~3.6V)
    	//rSDICARG=0xffc000;		//ACMD41(MMC OCR:2.6V~3.6V)
    	rSDICCON=(0x1<<9)|(0x1<<8)|0x69;//sht_resp, wait_resp, start, ACMD41
		//-- Check end of ACMD41
    	if( Chk_CMDend(41,1) & rSDIRSP0==0x80ff8000 ) 
		{
			//rSDICSTA=0xa00;	// Clear cmd_end(with rsp)
			return 1;	// Success	    
		}
		for(j=0;j<0x1000;j++);	// Wait Card power up status
    }
	//rSDICSTA=0xa00;	// Clear cmd_end(with rsp)
	return 0;		// Fail
}

void CMD0(void)
{
	//--CMD0
	//-- Make card idle state 
	rSDICARG=0x0;				// CMD0(stuff bit)
	rSDICCON=(1<<8)|0x40;		// No_resp, start, CMD0
	//-- Check end of CMD0
	Chk_CMDend(0,0);
	//rSDICSTA=0x800;				// Clear cmd_end(no rsp)
}

int CMD55(void)
{
	//--Make ACMD
	rSDICARG=RCA<<16;					//CMD7(RCA,stuff bit)
	rSDICCON=(0x1<<9)|(0x1<<8)|0x77;	//sht_resp, wait_resp, start, CMD55
	//-- Check end of CMD55
	if(!Chk_CMDend(55,1)) 
		return 0;
	//rSDICSTA=0xa00;	// Clear cmd_end(with rsp)
	return 1;
}

void Set_1bit_bus(void)
{
	Wide=0;
	if(!MMC)
		SetBus();
}

void Set_4bit_bus(void)
{
    Wide=1;
	SetBus();
}

void SetBus(void)
{
	do
	{
		CMD55();	// Make ACMD
		//-- ACMD6 implement
		rSDICARG=Wide<<1;	//Wide 0: 1bit, 1: 4bit
		rSDICCON=(0x1<<9)|(0x1<<8)|0x46;	//sht_resp, wait_resp, start, CMD55->ACMD6
	}while(!Chk_CMDend(6,1));
	
	//rSDICSTA=0xa00;			// Clear cmd_end(with rsp)
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -