---------- Forwarded message ----------
From: champ yen <[email protected]>
Date: Wed, Aug 19, 2009 at 11:30 PM
Subject: Re: Re : Re: [Prex-devel] FAT32 support for Prex
To: Richard PANDION <[email protected]>


Hello Richard:
    Multi-partitioned Card may be supported. I have tried this in Febuary. I
implemented this by analyzing partition table of a block device first(in
block device driver not fs server). And partition device nodes are built by
block device driver(of course, they are read/write via same driver with
partition's parameters. ex:offset and length). For full multi-partition
support, an official implementation between fs server and primative block
device driver should be implemented.
    For further detail, you can refer to the attached file. I'm sorry for
the messy code and the code is ported from S3C2440 demo program. I just
study to understand the major part and make it work under prex.

best regards
champ yen


On Wed, Aug 19, 2009 at 9:26 PM, Richard PANDION <[email protected]>wrote:

>   Hi Andrew, hi Champ,
>
>
> I have tested the new FAT32 support on my Beagle Board with my WIP SD/MMC
> device driver and it seems to be OK.
>
>
> I say "seems" since, by default, prex FAT implementation only supports
> non-partitionned devices (i.e., floppy devices  or non-floppy devices
> formatted as "big floppies").
>
> As Champ did not remove this limitation in its code, it did not work out of
> the box with my partitionned SD card media.
>
>
> Also, as I hit this problem before (with the original prex code) and
> developped a patch to deal with this issue at that time, I have backported
> my patch against Champ's FAT32 changes and I have been able to access both a
> FAT16 and a FAT32 formatted SD card (single partition).
>
>
> I have attached the 2 files I've changed for reference. The patch is
> against the fat_read_pbp() function. Please note that my patch only allows
> access to a single FAT partition. If the media has more than 1 partition
> on it, the FAT partition MUST be the first one (other partitions are
> ignored).
>
>
> Best regards,
>
>
> RICHARD
>
>
> P.S. : Champ, I have removed the check for validity of FAT Media Descriptor
> in fat_read_bpb() as, per Microsoft documentation: " This dates back to
> the old MS-DOS 1.x media determination and is no longer usually used for
> anything."...
>
>
>
>
>  ----- Message d'origine -----
>
> De : Andrew Dennison
>
> Envoyés : 16.08.09 09:02
>
> À : champ yen
>
> Objet : Re: [Prex-devel] FAT32 support for Prex
>
>
> On Tue, Aug 11, 2009 at 9:46 PM, Andrew Dennison wrote:
> > On Sun, Aug 9, 2009 at 12:30 AM, champ yen wrote:
> >> Hello Andrew:
> >>     The commented part is removed from original 0.8.1 code base. The fat
> >> infomation is getting by lines before the "Build FAT mount data".  I
> >> modified the fatfs implementation just for fun. Therefore, further
> testing
> >> is required. To clean the unnecessary code may be needed. I just
> provides
> >> the code for those who want to add FAT32 support for their
> implementation.
> >> If you want to commit it to SVN, some works must be done first. I'm
> willing
> >> to do it, but it takes some time. Since I do not have much spare time
> now.
> >
> > Hi Champ Yen,
> >
> > I've had a look at this in more detail and most of the changes are
> > safe to commit as they only affect FAT32. I just need to check through
> > the changes in vfsops more carefully.
>
> Hi Champ,
>
> I've just committed fat32 support to git, see:
>
> http://github.com/AndrewD/prex/tree/master
>
> All looks ok but I made some changes to fat_read_bpb() that are only
> compile tested. Is there anyone currently using fat filesystems that
> can test? Note that this filesystem currently doesn't support big
> endian systems.
>
> Andrew
>
>
> ------------------------------------------------------------------------------
> Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
>
> trial. Simplify your report design, integration and deployment - and focus
> on
> what you do best, core application coding. Discover what's new with
> Crystal Reports now. http://p.sf.net/sfu/bobj-july
> _______________________________________________
> Prex-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/prex-devel
>
>
>
>
/*
 * card.c - SD Card disk driver
 */

#include <driver.h>
#include <arm/platform/at2440ii.h>

/* #define DEBUG_SDCARD 1 */
//#define DEBUG_SDCARD
#define _USE_DMA0_	1

#ifdef DEBUG_SDCARD
#define DPRINTF(a) printf a
#else
#define DPRINTF(a)
#endif

//YH 0811#define INICLK	300000
#define INICLK	400000
//#define NORCLK	25000000
#define SDCLK	24000000	//PCLK=49.392MHz
#define MMCCLK	15000000	//PCLK=49.392MHz

#define PCLK		66608640

/* Block size */
#define BSIZE		512

static int card_read(device_t, char *, size_t *, int);
static int card_write(device_t, char *, size_t *, int);
static int card_open(void);
static int card_close(void);
static int card_init(void);

/*
 * Driver structure
 */
struct driver card_drv = {
	/* name */	"SD card",
	/* order */	6,
	/* init */	card_init,
};

/*
 * Device I/O table
 */
static struct devio card_io = {
	/* open */	NULL,
	/* close */	NULL,
	/* read */	card_read,
	/* write */	card_write,
	/* ioctl */	NULL,
	/* event */	NULL,
};

static struct timer card_tmr;

static device_t card_dev;		/* Device object */
static device_t card_part_dev[4];	/* Device object */
static int part_offset[4];


static struct event	card_event;

//static char *img_start;
//static size_t img_size;

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

#if !_USE_DMA0_
#define CARD_READ	0
#define CARD_WRITE	1
static unsigned int *read_buf = NULL;
static unsigned int *write_buf = NULL;
static int card_op = 0;
static int op_length = 0;
static int op_count = 0;
#endif

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

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

		SDICSTA= finish0;// Clear cmd end state

		return 1;
	}else{
		// With response
		finish0 = SDICSTA;
		//	while( !( ((finish0&0x200)==0x200) | ((finish0&0x400)==0x800) ))	// Check cmd/rsp end
		//	while((finish0&0x1800)!=0x1800) //YH 0811 Check cmd end
		while( !( ((finish0 & 0x200)==0x200) | ((finish0 & 0x400)==0x400) ))    // Check cmd/rsp end
			finish0 = SDICSTA;
		//	Uart_Printf("CMD%d:rSDICSTA=0x%x\n", cmd, rSDICSTA);	//YH 0811

		// CRC no check, CMD9 is a long Resp. command.
		//YH 0624	if(cmd==1 | cmd==9 | cmd==41)	// CRC no check
		if(cmd==1 | cmd==41){
			
			// Check error
			if( (finish0 & 0xf00) != 0xa00 ){
				SDICSTA = finish0;   // Clear error state

				if(((finish0&0x400)==0x400))
					return 0;	// Timeout error
			}
			SDICSTA = finish0;	// Clear cmd & rsp end state
		}else{
		// CRC check
			// Check error
			if( (finish0 & 0x1f00) != 0xa00 ){
				DPRINTF(("CMD%d:SDICSTA=0x%x, SDIRSP0=0x%x\n",cmd, SDICSTA, SDIRSP0));
				SDICSTA = finish0;   // Clear error state

				// Timeout error
				if(((finish0&0x400)==0x400))
					return 0;	
			}
			SDICSTA = finish0;
		}
		return 1;
	}
}

static int chk_dat_end(void)
{
	int finish;

	finish = SDIDSTA;
	
	// Chek timeout or data end
	while( !( ((finish&0x10) == 0x10) | ((finish&0x20) == 0x20) )){	
		finish = SDIDSTA;
		//DPRINTF(("SDIDSTA:0x%x\n", finish));
	}

	if( (finish&0xfc) != 0x10 ){
		DPRINTF(("DATA:finish=0x%x\n", finish));
		SDIDSTA = 0xec;  // Clear error state
		return 0;
	}
	return 1;
}

static int chk_busy_end(void)
{
	int finish;

	finish = SDIDSTA;
	while( !( ((finish&0x08)==0x08) | ((finish&0x20)==0x20) ))
		finish = SDIDSTA;

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

static void cmd0(void)
{
	//-- Make card idle state 
	SDICARG = 0x0;	    // CMD0(stuff bit)
	SDICCON = (1<<8)|0x40;   // No_resp, start, CMD0

	//-- Check end of CMD0
	chk_cmd_end(0, 0);
	SDICSTA = 0x800;	    // Clear cmd_end(no rsp)
}
static int cmd55(void)
{
	//--Make ACMD
	SDICARG = (RCA << 16);			//CMD7(RCA,stuff bit)
	SDICCON = (0x1<<9)|(0x1<<8)|0x77;	//sht_resp, wait_resp, start, CMD55

	//-- Check end of CMD55
	if(!chk_cmd_end(55, 1)) 
		return 0;

	SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
	return 1;
}

static int cmd13(void)//SEND_STATUS
{
	int response0;

	SDICARG = (RCA<<16);			// CMD13(RCA,stuff bit)
	SDICCON = (0x1<<9)|(0x1<<8)|0x4d;	// sht_resp, wait_resp, start, CMD13

	//-- Check end of CMD13
	if(!chk_cmd_end(13, 1)) 
		return 0;
	//Uart_Printf("rSDIRSP0=0x%x\n", rSDIRSP0);
	if(SDIRSP0 & 0x100)
	//Uart_Printf("Ready for Data\n");
//    else 
	//Uart_Printf("Not Ready\n");
	response0 = SDIRSP0;
	response0 &= 0x3c00;
	response0 = response0 >> 9;
    //Uart_Printf("Current Status=%d\n", response0);
	/*
	if(response0==6)
		Test_SDI();
	*/

	SDICSTA=0xa00;	// Clear cmd_end(with rsp)
	return 1;
}

static int cmd9(void)//SEND_CSD
{
	SDICARG = (RCA<<16);				// CMD9(RCA,stuff bit)
	SDICCON = (0x1<<10)|(0x1<<9)|(0x1<<8)|0x49;	// long_resp, wait_resp, start, CMD9

	DPRINTF(("\n****CSD register****\n"));
	//-- Check end of CMD9
	if(!chk_cmd_end(9, 1)) 
		return 0;

	DPRINTF((" SDIRSP0=0x%x\n SDIRSP1=0x%x\n SDIRSP2=0x%x\n SDIRSP3=0x%x\n",  SDIRSP0, SDIRSP1, SDIRSP2, SDIRSP3));
	return 1;
}

static void set_bus(void)
{
SET_BUS:
	cmd55();	// Make ACMD
	//-- CMD6 implement
	SDICARG = Wide<<1;	    //Wide 0: 1bit, 1: 4bit
	SDICCON = (0x1<<9)|(0x1<<8)|0x46;	//sht_resp, wait_resp, start, CMD55

	if(!chk_cmd_end(6, 1))   // ACMD6
		goto SET_BUS;
	SDICSTA = 0xa00;	    // Clear cmd_end(with rsp)
}

static void set_1bit_bus(void)
{
	Wide=0;
	if(!MMC)
		set_bus();
	DPRINTF(("\n****1bit bus****\n"));
}

static void set_4bit_bus(void)
{
	Wide=1;
	set_bus();
	DPRINTF(("\n****4bit bus****\n"));
}

static void set_prt(void)
{
	//-- Set protection addr.0 ~ 262144(32*16*512) 
	DPRINTF(("[Set protection(addr.0 ~ 262144) test]\n"));

RECMD28:
	//--Make ACMD
	SDICARG = 0;	    // CMD28(addr) 
	SDICCON=(0x1<<9)|(0x1<<8)|0x5c;	//sht_resp, wait_resp, start, CMD28

	//-- Check end of CMD28
	if(!chk_cmd_end(28, 1)) 
	goto RECMD28;
	SDICSTA=0xa00;	// Clear cmd_end(with rsp)
}

static void clr_prt(void)
{
	//-- Clear protection addr.0 ~ 262144(32*16*512) 
	//Uart_Printf("[Clear protection(addr.0 ~ 262144) test]\n");

RECMD29:
	//--Make ACMD
	SDICARG = 0;	    // CMD29(addr)
	SDICCON = (0x1<<9)|(0x1<<8)|0x5d;	//sht_resp, wait_resp, start, CMD29

	//-- Check end of CMD29
	if(!chk_cmd_end(29, 1)) 
		goto RECMD29;
	SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
}

static int chk_mmc_ocr(void)
{
	int i;

	//-- Negotiate operating condition for MMC, it makes card ready state
	//Negotiation time is dependent on CARD Vendors.
	for(i=0;i<100;i++){
		SDICARG = 0xffc000;	    	    //CMD1(MMC OCR:2.6V~3.6V)
		//SDICARG = 0xff8000;	    	    //CMD1(SD OCR:2.7V~3.6V)
		SDICCON = (0x1<<9)|(0x1<<8)|0x41;    //sht_resp, wait_resp, start, CMD1

		//-- Check end of CMD1
		// 	if(Chk_CMDend(1, 1) & rSDIRSP0==0x80ffc000)	//[31]:Card Power up status bit (busy)
		//0xffc000 is Voltage window
		//	if(Chk_CMDend(1, 1) & rSDIRSP0==0x80ff8000) 
		//YH 0903 [31]:Card Power up status bit (busy)
		if( chk_cmd_end(1, 1) && ((SDIRSP0 >> 16) == 0x80ff) ) {
			SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
			return 1;	// Success
		}
	}
	SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
	return 0;		// Fail
}

static int chk_sd_ocr(void)
{
	int i,j=0;

	//-- Negotiate operating condition for SD, it makes card ready state
	//If this time is short, init. can be fail.
	for(i=0;i<500;i++){
		cmd55();    // Make ACMD

		SDICARG = 0xff8000;	//ACMD41(SD OCR:2.7V~3.6V)
		//    	SDICARG=0xffc000;	//ACMD41(MMC OCR:2.6V~3.6V)
		SDICCON = (0x1<<9)|(0x1<<8)|0x69;//sht_resp, wait_resp, start, ACMD41

		//-- Check end of ACMD41
		if( chk_cmd_end(41, 1) & (SDIRSP0 == 0x80ff8000) ) {
			SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
			return 1;	// Success	    
		}
		
		//Delay(200); // Wait Card power up status
		for(j = 0; j < 10000; j++);
		
	}
	//Uart_Printf("SDIRSP0=0x%x\n",rSDIRSP0);
	SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
	return 0;		// Fail
}

static void card_sel_desel(char sel_desel)
{
	//-- Card select or deselect
	if(sel_desel){
RECMDS7:	
		SDICARG = RCA<<16;	// CMD7(RCA,stuff bit)
		SDICCON = (0x1<<9)|(0x1<<8)|0x47;   // sht_resp, wait_resp, start, CMD7

		//-- Check end of CMD7
		if(!chk_cmd_end(7, 1))
			goto RECMDS7;
		SDICSTA = 0xa00;	// Clear cmd_end(with rsp)

		//--State(transfer) check
		if( SDIRSP0 & 0x1e00!=0x800 )
		goto RECMDS7;
	}else{
RECMDD7:	
		SDICARG = 0<<16;		//CMD7(RCA,stuff bit)
		SDICCON = (0x1<<8)|0x47;	//no_resp, start, CMD7

		//-- Check end of CMD7
		if(!chk_cmd_end(7, 0))
			goto RECMDD7;
		SDICSTA=0x800;	// Clear cmd_end(no rsp)
	}
}


static int
card_isr(int irq)
{
#if _USE_DMA0_
	DPRINTF(("dma finish\n"));
	sched_wakeup(&card_event);
#else
	int status;
	int i;

	switch(card_op){
		case CARD_READ:
			status = SDIFSTA;
			if( (status&0x200) == 0x200 ){
				// Check Last interrupt?
				for(i = (status & 0x7f)/4; i> 0; i--){
					*(read_buf + op_count) = SDIDAT;
					op_count++;
				}
				//	Uart_Printf("status1=0x%x\n", status);
				//	status=rSDIFSTA&0x200;	//If you do like this, rSDIFSTA register will not be updated., YH 040221
				SDIFSTA = SDIFSTA&0x200;	//Clear Rx FIFO Last data Ready, YH 040221
				//	Uart_Printf("rSDIFSTA=0x%x\n", rSDIFSTA);
			}else if( (status&0x80) == 0x80 ){
				// Check Half interrupt?
				for(i = 0; i < 8; i++){
					*(read_buf + op_count)=SDIDAT;
					op_count++;
				}
			}
			//DPRINTF(("card read %d %d\n", op_count, op_length));
			if(op_count == op_length)
				sched_wakeup(&card_event);
			break;
		case CARD_WRITE:
			SDIDAT=*(write_buf + op_count);
			op_count++;
			if(op_count == op_length){
				sched_wakeup(&card_event);
			}
			//DPRINTF(("card write %d %d\n", op_count, op_length));
			break;
	}
#endif
	return 0;
}

static int
card_read(device_t dev, char *buf, size_t *nbyte, int blkno)
{
	int i;
	int block = (*nbyte)/BSIZE;
	int offset = 0;
	void *kbuf;
	size_t nr_read;

	if(dev == card_dev){
		offset = 0;
	}else{
		for(i = 0; i < 4; i++){
			if(dev == card_part_dev[i]){
				offset = part_offset[i];
				break;
			}
		}
	}
	
	nr_read = *nbyte;
	kbuf = kmem_map(buf, nr_read);
	//DPRINTF(("card_read: kbuf=%x block=%d blkno=%x\n", kbuf, block, blkno));
	
	/* Clear command and data status registers */
	SDIFSTA = 0xFFFFFFFF;
	SDICSTA = 0xFFFFFFFF;
	SDIDSTA = 0xFFFFFFFF;

	SDIFSTA = SDIFSTA | (1<<16);	// FIFO reset
	SDICARG = (blkno + offset)*512;	// CMD17/18(addr)

RERDCMD:
#if _USE_DMA0_
	SDIDCON = SDIDCON | (1<<24); 				//YH 040227, Burst4 Enable

	DISRC(_DMA0_) = (unsigned int)(SDIDAT_ADDR);			// SDIDAT
	DISRCC(_DMA0_) = (1<<1)+(1<<0);				// APB, fix
	DIDST(_DMA0_) = (unsigned int)(kbuf + 0x30000000);	// Rx_buffer
	DIDSTC(_DMA0_) = (0<<1)+(0<<0);				// AHB, inc
	DCON(_DMA0_) = (1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(2<<24)+(1<<23)+(1<<22)+(2<<20)+128*block;
	//handshake, sync PCLK, TC int, single tx, single service, SDI, H/W request, 
	//auto-reload off, word, 128blk*num
	SDIDCON = (2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<15)|(1<<14)|(2<<12)|block;
	DMASKTRIG(_DMA0_) = (0<<2)+(1<<1)+0;
	
	
	if(block < 2){
		// SINGLE_READ
		SDICCON = (0x1<<9)|(0x1<<8)|0x51;    // sht_resp, wait_resp, dat, start, CMD17
		if(!chk_cmd_end(17, 1))	//-- Check end of CMD17
			goto RERDCMD;	    
	}else{
		// MULTI_READ
		SDICCON = (0x1<<9)|(0x1<<8)|0x52;    // sht_resp, wait_resp, dat, start, CMD18
		if(!chk_cmd_end(18, 1))	//-- Check end of CMD18 
			goto RERDCMD;
	}

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

	DPRINTF(("read wait 0x%x\n", SDIDCNT));
	sched_sleep(&card_event);
	DMASKTRIG(_DMA0_) = (1<<2);	//DMA0 stop
	DPRINTF(("read finish 0x%x\n", SDIDCNT));
#else
	card_op = CARD_READ;
	op_length = (*nbyte) / 4;	//in word(4 bytes)
	op_count = 0;
	read_buf = (unsigned int*)kbuf;
		
	SDIDCON = (2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<14)|(2<<12)|(block<<0);	//YH 040220

	SDIIMSK=5;	// Last & Rx FIFO half int.
	
	if(block<2){
		// SINGLE_READ
		SDICCON = (0x1<<9)|(0x1<<8)|0x51;    // sht_resp, wait_resp, dat, start, CMD17
		if(!chk_cmd_end(17, 1))	//-- Check end of CMD17
			goto RERDCMD;	    
	}else{
		// MULTI_READ
		SDICCON = (0x1<<9)|(0x1<<8)|0x52;    // sht_resp, wait_resp, dat, start, CMD18
		if(!chk_cmd_end(18, 1))	//-- Check end of CMD18 
			goto RERDCMD;
	}
    
	SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
	
	//DPRINTF(("read wait 0x%x\n", SDIDCNT));
	sched_sleep(&card_event);
	//DPRINTF(("read finish 0x%x\n", SDIDCNT));

	SDIIMSK=0;	// All mask
#endif
	
	//-- Check end of DATA
	if(!chk_dat_end()) 
		DPRINTF(("dat error\n"));

	SDIDCON = SDIDCON&~(7<<12);		//YH 040220, Clear Data Transfer mode => no operation, Cleata Data Transfer start
	SDIFSTA = SDIFSTA&0x200;	//Clear Rx FIFO Last data Ready, YH 040221
	SDIDSTA = 0x10;	// Clear data Tx/Rx end detect

	if(block > 1){
RERCMD12:    
		//--Stop cmd(CMD12)
		SDICARG = 0x0;	    //CMD12(stuff bit)
		SDICCON = (0x1<<9)|(0x1<<8)|0x4c;//sht_resp, wait_resp, start, CMD12

		//-- Check end of CMD12
		if(!chk_cmd_end(12, 1)) 
			goto RERCMD12;
		SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
	}

	/* Cleanup controller */
	SDICARG = 0;
	SDIDCON = 0;
	SDIIMSK = 0;
	SDICCON = 0;
	return 0;
}

#if 0
static int
card_read(device_t dev, char *buf, size_t *nbyte, int blkno)
{
	int i;
	size_t size;
	int block = (*nbyte)/512;
	
	for(i = 0; i < block; i++){
		size = 512;
		_card_read(dev, buf+(i*512), &size, blkno+i);
	}
	return 0;
}
#endif


static int
card_write(device_t dev, char *buf, size_t *nbyte, int blkno)
{
	int block = (*nbyte)/BSIZE;
	int i;
	int offset = 0;
	void *kbuf;
	size_t nr_read;

	if(dev == card_dev){
		offset = 0;
	}else{
		for(i = 0; i < 4; i++){
			if(dev == card_part_dev[i]){
				offset = part_offset[i];
				break;
			}
		}
	}
	
	nr_read = *nbyte;
	kbuf = kmem_map(buf, nr_read);
	//DPRINTF(("card_write: buf=%x nbyte=%d blkno=%x\n", buf, *nbyte, blkno));

	/* Clear command and data status registers */
	SDIFSTA = 0xFFFFFFFF;
	SDICSTA = 0xFFFFFFFF;
	SDIDSTA = 0xFFFFFFFF;

	SDIFSTA = SDIFSTA|(1<<16);	//YH 040223 FIFO reset
	SDICARG = (blkno + offset)*512;	    // CMD24/25(addr)

REWTCMD:
#if _USE_DMA0_
	SDIDCON = SDIDCON|(1<<24); //YH 040227, Burst4 Enable

	DISRC(_DMA0_) = (int)(kbuf + 0x30000000);	// Tx_buffer
	DISRCC(_DMA0_) = (0<<1)+(0<<0);	// AHB, inc
	DIDST(_DMA0_) = (unsigned int)(SDIDAT_ADDR);	// SDIDAT
	DIDSTC(_DMA0_) = (1<<1)+(1<<0);	// APB, fix
	//handshake, sync PCLK, TC int, single tx, single service, SDI, H/W request, 
	//auto-reload off, word, 128blk*num
	DCON(_DMA0_) = (1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(2<<24)+(1<<23)+(1<<22)+(2<<20)+128*block;
	DMASKTRIG(_DMA0_) = (0<<2)+(1<<1)+0;    //no-stop, DMA0 channel on, no-sw trigger

	SDIDCON = (2<<22)|(1<<20)|(1<<17)|(Wide<<16)|(1<<15)|(1<<14)|(3<<12)|block;	//YH 040220
	
	if(block<2){
		// SINGLE_WRITE
		SDICCON = (0x1<<9)|(0x1<<8)|0x58;    //sht_resp, wait_resp, dat, start, CMD24
		if(!chk_cmd_end(24, 1))	//-- Check end of CMD24
			goto REWTCMD;	    
	}else{
		// MULTI_WRITE
		SDICCON = (0x1<<9)|(0x1<<8)|0x59;    //sht_resp, wait_resp, dat, start, CMD25
		if(!chk_cmd_end(25, 1))	//-- Check end of CMD25 
			goto REWTCMD;	    
	}

	SDICSTA = 0xa00;	// Clear cmd_end(with rsp)
	DPRINTF(("write wait 0x%x\n", SDIDCNT));
	sched_sleep(&card_event);
	DMASKTRIG(_DMA0_) = (1<<2);	//DMA0 stop
	DPRINTF(("write finish 0x%x\n", SDIDCNT));
#else
	card_op = CARD_WRITE;
	op_length = (*nbyte) / 4;	//in word(4 bytes)
	op_count = 0;
	write_buf = (unsigned int*)kbuf;
	
	SDIDCON=(2<<22)|(1<<20)|(1<<17)|(Wide<<16)|(1<<14)|(3<<12)|block;	//YH 040220

	SDIIMSK=0x10;  // Tx FIFO half int.

	if(block<2){
		// SINGLE_WRITE
		SDICCON=(0x1<<9)|(0x1<<8)|0x58;    //sht_resp, wait_resp, dat, start, CMD24
		if(!chk_cmd_end(24, 1))	//-- Check end of CMD24
			goto REWTCMD;
	}else{
		// MULTI_WRITE
		SDICCON=(0x1<<9)|(0x1<<8)|0x59;    //sht_resp, wait_resp, dat, start, CMD25
		if(!chk_cmd_end(25, 1))	//-- Check end of CMD25 
			goto REWTCMD;
	}
	SDICSTA=0xa00;	// Clear cmd_end(with rsp)

	//DPRINTF(("write wait 0x%x\n", SDIDCNT));
	sched_sleep(&card_event);
	//DPRINTF(("write finish 0x%x\n", SDIDCNT));

	SDIIMSK=0;	// All mask
#endif

	//-- Check end of DATA
	if(!chk_dat_end()) 
		DPRINTF(("dat error\n"));

	SDIDCON = SDIDCON&~(7<<12);		//YH 040220, Clear Data Transfer mode => no operation, Cleata Data Transfer start
	SDIDSTA = 0x10;	// Clear data Tx/Rx end

	if(block > 1){
		//--Stop cmd(CMD12)
REWCMD12:    
		//rSDIDCON=(1<<18)|(1<<17)|(0<<16)|(1<<12)|(block<<0);
		SDIDCON = (1<<18)|(1<<17)|(0<<16)|(1<<14)|(1<<12)|(block<<0); 	//YH  040220

		SDICARG = 0x0;	    //CMD12(stuff bit)
		SDICCON = (0x1<<9)|(0x1<<8)|0x4c;    //sht_resp, wait_resp, start, CMD12

		//-- Check end of CMD12
		if(!chk_cmd_end(12, 1))
			goto REWCMD12;
		SDICSTA = 0xa00;	// Clear cmd_end(with rsp)

		//-- Check end of DATA(with busy state)
		if(!chk_busy_end()) 
			DPRINTF(("error\n"));
		SDIDSTA = 0x08;	//! Should be cleared by writing '1'.
	}
	
	/* Cleanup controller */
	SDICARG = 0;
	SDIDCON = 0;
	SDIIMSK = 0;
	SDICCON = 0;	
	
	return 0;
}

static int
card_open(void)
{
	return 0;
}

static int
card_close(void)
{
	return 0;
}

static void
card_init_partition(void)
{
	//create multi-partition
	int i;
	char dev_name[5] = "card0";
	unsigned char *mbr, *ptr;
	int part_exist = 0;
	size_t mbr_size;

	/* TODO: check boot sector to create partition */
	#if 1
	for(i = 0; i < 4; i++)
		part_offset[i] = 0;
	mbr = kmem_alloc(BSIZE);
	mbr_size = BSIZE;
	card_read(card_dev, mbr, &mbr_size, 0);
	ptr = mbr + 446;
	for(i = 0; i < 4; i++){
		part_exist = *(ptr+4) + (*(ptr+5) << 8) + (*(ptr+6) << 16) + (*(ptr+7) << 24);
		if(part_exist){
			part_offset[i] = *(ptr+8) + (*(ptr+9) << 8) + (*(ptr+10) << 16) + (*(ptr+11) << 24);
			dev_name[4] = '0' + i;
			card_part_dev[i] = device_create(&card_io, dev_name, DF_BLK);
			DPRINTF(("create %s offset=%x\n", dev_name, part_offset[i]));
		}
		ptr += 16;
	}
	kmem_free(mbr);
	#endif

}

/*
 * Initialize
 */
static int
card_init(void)
{
	//-- SD controller & card initialize 
	int i;
	char key;
	

	/* Important notice for MMC test condition */
	/* Cmd & Data lines must be enabled by pull up resister */
	
	//YH 0816, Org    rSDIPRE=PCLK/(2*INICLK)-1;	// 400KHz
	SDIPRE = PCLK/(INICLK)-1;	// 400KHz
	DPRINTF( ("Init. SD Freq. is %dHz\n",(PCLK/(SDIPRE+1))) );
    
	//    rSDICON=(1<<4)|(1<<1)|1;	// Type B, FIFO reset, clk enable
	SDICON = (0<<4)|1;	// Type A, clk enable
	SDIFSTA = SDIFSTA|(1<<16);	//YH 040223 FIFO reset
	SDIBSIZE = 0x200;		// 512byte(128word)
	SDIDTIMER = 0x7fffff;		// Set timeout count

	for(i=0; i<0x1000; i++);  // Wait 74SDCLK for MMC card

	//Uart_Printf("rSDIRSP0=0x%x\n",rSDIRSP0);
	cmd0();
	DPRINTF(("\nIn idle\n"));

	//-- Check MMC card OCR
	if(chk_mmc_ocr()) {
		DPRINTF(("\nIn MMC ready\n"));
		MMC=1;
		goto RECMD2;
	}

	DPRINTF(("MMC check end!!\n"));
	
	//-- Check SD card OCR
	if(chk_sd_ocr()){
		DPRINTF(("\nIn SD ready\n"));
	}else{
		DPRINTF(("\nInitialize fail\nNo Card assertion\n"));
		return 0;
	}

RECMD2:
	//-- Check attaced cards, it makes card identification state
	SDICARG = 0x0;   // CMD2(stuff bit)
	SDICCON = (0x1<<10)|(0x1<<9)|(0x1<<8)|0x42; //lng_resp, wait_resp, start, CMD2

	//-- Check end of CMD2
	if(!chk_cmd_end(2, 1)) 
		goto RECMD2;
	SDICSTA = 0xa00;	// Clear cmd_end(with rsp)

	DPRINTF(("\nEnd id\n"));

RECMD3:
	//--Send RCA
	SDICARG = MMC<<16;	    // CMD3(MMC:Set RCA, SD:Ask RCA-->SBZ)
	SDICCON = (0x1<<9)|(0x1<<8)|0x43;	// sht_resp, wait_resp, start, CMD3

	//-- Check end of CMD3
	if(!chk_cmd_end(3, 1)) 
		goto RECMD3;
	SDICSTA = 0xa00;	// Clear cmd_end(with rsp)

	//--Publish RCA
	if(MMC) {
		RCA=1;
		//YH 0812        rSDIPRE=(PCLK/(MMCCLK)+1)-1;	// YH 0716, Normal clock=20MHz
		SDIPRE=(PCLK/MMCCLK)-1;	// YH 0812, Normal clock=20MHz

		DPRINTF(("MMC Frequency is %dHz\n",(PCLK/(SDIPRE+1))));
    	}else{
		RCA = ( SDIRSP0 & 0xffff0000 )>>16;
		DPRINTF(("RCA=0x%x\n",RCA));

		SDIPRE = PCLK/(SDCLK)-1;	// Normal clock=25MHz
		DPRINTF(("SD Frequency is %dHz\n",(PCLK/(SDIPRE+1))));
    	}	//YH 0716
	
	//--State(stand-by) check
	if( SDIRSP0 & 0x1e00!=0x600 )  // CURRENT_STATE check
		goto RECMD3;
    
	DPRINTF(("\nIn stand-by\n"));
    
//    rSDIPRE=PCLK/(2*NORCLK)-1;	// Normal clock=25MHz
//YH 0716    rSDIPRE=PCLK/(SDCLK)-1;	// Normal clock=25MHz
//YH 0716    //Uart_Printf("SD Frequency is %dMHz\n",(PCLK/(rSDIPRE+1)));

	card_sel_desel(1);	// Select

	if(!MMC)
		set_4bit_bus();
	else
		set_1bit_bus();


#ifdef DEBUG
	printf("SD disk \n");
#endif
	/* Create device object */
	card_dev = device_create(&card_io, "card", DF_BLK);
	//card_dev = device_create(&card_io, "card0", DF_BLK);
	
	event_init(&card_event, "dma_finish");
	{
#if _USE_DMA0_
		irq_t dma_irq;
		dma_irq = irq_attach(DMA0_IRQ, IPL_BLOCK, 0, &card_isr, NULL);
#else
		irq_t card_irq;
		card_irq = irq_attach(SDI_IRQ, IPL_BLOCK, 0, &card_isr, NULL);
#endif
	}

	timer_callout(&card_tmr, 50, &card_init_partition, NULL);
	
	DPRINTF(("Card Initial ok\n"));

	ASSERT(card_dev);
	return 0;
}
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Prex-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/prex-devel

Reply via email to