sdcard.c 13.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * File      : sd.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006, 2007, RT-Thread Develop Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://openlab.rt-thread.com/license/LICENSE
 *
 * Change Logs:
 * Date           Author       Notes
 * 2007-12-02     Yi.Qiu      the first version
 */

#include "sdcard.h"

extern rt_uint32_t PCLK;
volatile rt_uint32_t rd_cnt;
volatile rt_uint32_t wt_cnt;
volatile rt_int32_t RCA;

/**
B
bernard.xiong 已提交
23
 * This function will set a hook function, which will be invoked when a memory
24
 * block is allocated from heap memory.
B
bernard.xiong 已提交
25
 *
26 27 28 29 30
 * @param hook the hook function
 */
static void sd_delay(rt_uint32_t ms)
{
	ms *= 7326;
B
bernard.xiong 已提交
31
	while(--ms);
32 33 34
}

/**
B
bernard.xiong 已提交
35
 * This function will set a hook function, which will be invoked when a memory
36
 * block is allocated from heap memory.
B
bernard.xiong 已提交
37
 *
38 39 40 41 42 43 44 45 46
 * @param hook the hook function
 */
static int sd_cmd_end(int cmd, int be_resp)
{
	int finish0;

	if(!be_resp)
	{
		finish0=SDICSTA;
B
bernard.xiong 已提交
47

48 49 50 51
		while((finish0&0x800)!=0x800)
	    		finish0=SDICSTA;

		SDICSTA=finish0;
B
bernard.xiong 已提交
52

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
		return RT_EOK;
	}
	else
	{
		finish0=SDICSTA;

		while( !( ((finish0&0x200)==0x200) | ((finish0&0x400)==0x400) ))
		        finish0=SDICSTA;

		if(cmd==1 || cmd==41)
		{
		    	if( (finish0&0xf00) != 0xa00 )
	    		{
	        		SDICSTA=finish0;
	    			if(((finish0&0x400)==0x400))
	        			return RT_ERROR;
	    		}
	    		SDICSTA=finish0;
		}
		else
		{
		    	if( (finish0&0x1f00) != 0xa00 )
		    	{
				rt_kprintf("CMD%d:SDICSTA=0x%x, SDIRSP0=0x%x\n",
					cmd, SDICSTA, SDIRSP0);
		    		SDICSTA=finish0;
		    		if(((finish0&0x400)==0x400))
		        		return RT_ERROR;
		    	}
	    		SDICSTA=finish0;
		}
		return RT_EOK;
	}
}

/**
B
bernard.xiong 已提交
89
 * This function will set a hook function, which will be invoked when a memory
90
 * block is allocated from heap memory.
B
bernard.xiong 已提交
91
 *
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
 * @param hook the hook function
 */
static int sd_data_end(void)
{
	int finish;

	finish=SDIDSTA;

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

	if( (finish&0xfc) != 0x10 )
	{
		SDIDSTA=0xec;
		return RT_ERROR;
	}
	return RT_EOK;
}

/**
B
bernard.xiong 已提交
112
 * This function will set a hook function, which will be invoked when a memory
113
 * block is allocated from heap memory.
B
bernard.xiong 已提交
114
 *
115 116 117 118 119 120 121 122 123 124 125
 * @param hook the hook function
 */
static void sd_cmd0(void)
{
	SDICARG=0x0;
	SDICCON=(1<<8)|0x40;

	sd_cmd_end(0, 0);
}

/**
B
bernard.xiong 已提交
126
 * This function will set a hook function, which will be invoked when a memory
127
 * block is allocated from heap memory.
B
bernard.xiong 已提交
128
 *
129 130 131 132 133 134 135 136 137 138 139 140 141 142
 * @param hook the hook function
 */
static int sd_cmd55(void)
{
	SDICARG = RCA << 16;
	SDICCON = (0x1 << 9) | (0x1 << 8) | 0x77;

	if(sd_cmd_end(55, 1) == RT_ERROR)
		return RT_ERROR;

	return RT_EOK;
}

/**
B
bernard.xiong 已提交
143
 * This function will set a hook function, which will be invoked when a memory
144
 * block is allocated from heap memory.
B
bernard.xiong 已提交
145
 *
146 147 148 149 150 151
 * @param hook the hook function
 */
static void sd_sel_desel(char sel_desel)
{
	if(sel_desel)
	{
B
bernard.xiong 已提交
152
RECMDS7:
153 154 155 156 157
		SDICARG =RCA << 16;
		SDICCON = (0x1 << 9) | (0x1 << 8) | 0x47;

		if(sd_cmd_end(7, 1) == RT_ERROR)
	    		goto RECMDS7;
B
bernard.xiong 已提交
158

159 160 161 162 163
		if( SDIRSP0 & (0x1e00 != 0x800))
	    		goto RECMDS7;
	}
	else
	{
B
bernard.xiong 已提交
164
RECMDD7:
165 166 167 168 169 170 171 172 173
		SDICARG=0<<16;
		SDICCON=(0x1<<8)|0x47;

		if(sd_cmd_end(7, 0) == RT_ERROR)
	    		goto RECMDD7;
	}
}

/**
B
bernard.xiong 已提交
174
 * This function will set a hook function, which will be invoked when a memory
175
 * block is allocated from heap memory.
B
bernard.xiong 已提交
176
 *
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
 * @param hook the hook function
 */
static void sd_setbus(void)
{
SET_BUS:
	sd_cmd55();

	SDICARG=1<<1;
	SDICCON=(0x1<<9)|(0x1<<8)|0x46;

	if(sd_cmd_end(6, 1) == RT_ERROR)
		goto SET_BUS;
}

/**
B
bernard.xiong 已提交
192
 * This function will set a hook function, which will be invoked when a memory
193
 * block is allocated from heap memory.
B
bernard.xiong 已提交
194
 *
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
 * @param hook the hook function
 */
int sd_mmc_ocr(void)
{
	int i;

	/* Negotiate operating condition for MMC, it makes card ready state */
	for(i=0; i<100; i++)
	{
		SDICARG = 0xff8000;
		SDICCON = (0x1<<9)|(0x1<<8)|0x41;

		/* Check end of CMD1 */
		if((sd_cmd_end(1, 1) == RT_EOK) && (SDIRSP0>>16)==0x80ff)
		{
			SDICSTA=0xa00;
			return RT_EOK;
		}
	}
	SDICSTA=0xa00;
B
bernard.xiong 已提交
215

216 217 218 219
	return RT_ERROR;
}

/**
B
bernard.xiong 已提交
220
 * This function will set a hook function, which will be invoked when a memory
221
 * block is allocated from heap memory.
B
bernard.xiong 已提交
222
 *
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
 * @param hook the hook function
 */
int sd_ocr(void)
{
	int i;

	/* Negotiate operating condition for SD, it makes card ready state */
	for(i=0;i<50;i++)
	{
		sd_cmd55();

		SDICARG=0xff8000;
		SDICCON=(0x1<<9)|(0x1<<8)|0x69;

		/* if using real board, should replace code here. need to modify qemu in near future*/
		/* Check end of ACMD41 */
		//if( rt_hw_sd_cmd_end(41, 1) && SDIRSP0==0x80ff8000 )
		if( sd_cmd_end(41, 1) == RT_EOK)
		{
			SDICSTA=0xa00;
	    		return RT_EOK;
		}
B
bernard.xiong 已提交
245

246 247 248
		sd_delay(200);
	}
	SDICSTA=0xa00;
B
bernard.xiong 已提交
249

250 251 252 253
	return RT_ERROR;
}

/**
B
bernard.xiong 已提交
254
 * This function will set a hook function, which will be invoked when a memory
255
 * block is allocated from heap memory.
B
bernard.xiong 已提交
256
 *
257 258 259
 * @param hook the hook function
 */
rt_uint8_t sd_init(void)
B
bernard.xiong 已提交
260
{
261 262 263
	//-- SD controller & card initialize
	int i;
	/* Important notice for MMC test condition */
B
bernard.xiong 已提交
264
	/* Cmd & Data lines must be enabled by pull up resister */
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
	SDIPRE=PCLK/(INICLK)-1;
	SDICON=1;
	SDIFSTA=SDIFSTA|(1<<16);
	SDIBSIZE = 0x200;
	SDIDTIMER=0x7fffff;

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

	sd_cmd0();
	/* Check MMC card OCR */
	if(sd_mmc_ocr() == RT_EOK)
	{
		rt_kprintf("In MMC ready\n");
		goto RECMD2;
	}
	rt_kprintf("MMC check end!!\n");
	/* Check SD card OCR */
	if(sd_ocr() == RT_EOK)
	{
		rt_kprintf("In SD ready\n");
	}
	else
	{
		rt_kprintf("Initialize fail\nNo Card assertion\n");
		return RT_ERROR;
	}

RECMD2:
	SDICARG=0x0;
	SDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42;
B
bernard.xiong 已提交
296
	if(sd_cmd_end(2, 1) == RT_ERROR)
297 298
		goto RECMD2;

B
bernard.xiong 已提交
299
RECMD3:
300 301
	SDICARG=0<<16;
	SDICCON=(0x1<<9)|(0x1<<8)|0x43;
B
bernard.xiong 已提交
302
	if(sd_cmd_end(3, 1) == RT_ERROR)
303 304 305 306
		goto RECMD3;

	RCA=(SDIRSP0 & 0xffff0000 )>>16;
	SDIPRE=(PCLK/(SDCLK*2))-1;
B
bernard.xiong 已提交
307
	if( SDIRSP0 & (0x1e00!=0x600) )
308 309 310 311 312 313 314 315 316 317
		goto RECMD3;

	sd_sel_desel(1);
	sd_delay(200);
	sd_setbus();

	return RT_EOK;
}

/**
B
bernard.xiong 已提交
318
 * This function will set a hook function, which will be invoked when a memory
319
 * block is allocated from heap memory.
B
bernard.xiong 已提交
320
 *
321 322 323 324 325 326
 * @param hook the hook function
 */
rt_uint8_t sd_readblock(rt_uint32_t address, rt_uint8_t* buf)
{
	int status;

B
bernard.xiong 已提交
327
	rd_cnt=0;
328 329 330 331 332 333 334
	// SDICON |= (1<<1);
	SDIDCON = (2 << 22) | (1 << 19) | (1 << 17) | (1 << 16) | (1 << 14) | (2 << 12) | (1 << 0);
	SDICARG = address;

RERDCMD:
	SDICCON = (0x1 << 9 ) | (0x1 << 8) | 0x51;
	if(sd_cmd_end(17, 1) == RT_ERROR)
B
bernard.xiong 已提交
335
		goto RERDCMD;
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378

	SDICSTA = 0xa00;

	while(rd_cnt < 128)
	{
		if((SDIDSTA & 0x20) == 0x20)
		{
			SDIDSTA = 0x1 << 0x5;
			break;
		}
		status = SDIFSTA;
		if((status & 0x1000) == 0x1000)
		{
#if 0
			register rt_uint32_t value;

			value = SDIDAT;

			/* swap 4 bytes */
			buf[0] = (value >> 24) & 0xff;
			buf[1] = (value >> 16) & 0xff;
			buf[2] = (value >> 8) & 0xff;
			buf[3] = value & 0xff;
#endif
			*(rt_uint32_t *)buf = SDIDAT;
			rd_cnt++;
			buf += 4;
		}
    	}
	if(sd_data_end() == RT_ERROR)
	{
		rt_kprintf("Dat error\n");
		return RT_ERROR;
	}
	SDIDSTA = 0x10;
	SDIDCON = SDIDCON &~ (7<<12);
	SDIFSTA = SDIFSTA & 0x200;
	SDIDSTA = 0x10;

	return RT_EOK;
}

/**
B
bernard.xiong 已提交
379
 * This function will set a hook function, which will be invoked when a memory
380
 * block is allocated from heap memory.
B
bernard.xiong 已提交
381
 *
382 383 384 385 386 387
 * @param hook the hook function
 */
rt_uint8_t sd_writeblock(rt_uint32_t address, rt_uint8_t* buf)
{
	int status;

B
bernard.xiong 已提交
388
	wt_cnt=0;
389 390 391 392 393 394 395 396 397
	SDIFSTA = SDIFSTA | (1 << 16);
	SDIDCON = (2 << 22) | (1 << 20) | (1 << 17) | (1 << 16) | (1 << 14) | (3 << 12) | (1 << 0);
	SDICARG = address;

REWTCMD:
	SDICCON = (0x1 << 9) | (0x1 << 8) |0x58;

	if(sd_cmd_end(24, 1) == RT_ERROR)
		goto REWTCMD;
B
bernard.xiong 已提交
398

399 400 401 402 403
	SDICSTA=0xa00;

    	while(wt_cnt < 128*1)
    	{
    		status = SDIFSTA;
B
bernard.xiong 已提交
404
    		if((status & 0x2000) == 0x2000)
405 406 407 408 409 410 411 412 413 414
    		{
        		SDIDAT=*(rt_uint32_t*)buf;
        		wt_cnt++;
	       	buf += 4;
    		}
    	}
	if(sd_data_end() == RT_ERROR)
	{
		rt_kprintf("Data Error\n");
		return RT_ERROR;
B
bernard.xiong 已提交
415
	}
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
	SDIDCON = SDIDCON &~ (7<<12);
	SDIDSTA = 0x10;

	return RT_EOK;
}

#ifdef RT_USING_DFS
/* RT-Thread Device Driver Interface */
#include <rtthread.h>

#include <dfs_fs.h>

struct rt_device sdcard_device[4];
struct dfs_partition part[4];
/**
B
bernard.xiong 已提交
431
 * This function will set a hook function, which will be invoked when a memory
432
 * block is allocated from heap memory.
B
bernard.xiong 已提交
433
 *
434 435 436
 * @param hook the hook function
 */
static rt_err_t rt_sdcard_init(rt_device_t dev)
B
bernard.xiong 已提交
437
{
438 439 440 441
	return 0;
}

/**
B
bernard.xiong 已提交
442
 * This function will set a hook function, which will be invoked when a memory
443
 * block is allocated from heap memory.
B
bernard.xiong 已提交
444
 *
445 446 447 448 449 450 451 452
 * @param hook the hook function
 */
static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
{
	return 0;
}

/**
B
bernard.xiong 已提交
453
 * This function will set a hook function, which will be invoked when a memory
454
 * block is allocated from heap memory.
B
bernard.xiong 已提交
455
 *
456 457 458 459 460 461 462 463
 * @param hook the hook function
 */
static rt_err_t rt_sdcard_close(rt_device_t dev)
{
	return 0;
}

/**
B
bernard.xiong 已提交
464
 * This function will set a hook function, which will be invoked when a memory
465
 * block is allocated from heap memory.
B
bernard.xiong 已提交
466
 *
467 468 469 470 471 472 473 474
 * @param hook the hook function
 */
static rt_err_t rt_sdcard_control(rt_device_t dev, rt_uint8_t cmd, void *args)
{
	return 0;
}

/**
B
bernard.xiong 已提交
475
 * This function will set a hook function, which will be invoked when a memory
476
 * block is allocated from heap memory.
B
bernard.xiong 已提交
477
 *
478 479 480 481 482 483 484
 * @param hook the hook function
 */
static rt_size_t rt_sdcard_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
{
	int i;
	struct dfs_partition *part = (struct dfs_partition *)dev->private;

B
bernard.xiong 已提交
485 486 487 488 489 490
	if ( dev == RT_NULL )
	{
		rt_set_errno(-DFS_STATUS_EINVAL);
		return 0;
	}

491 492 493 494
	/* read all sectors */
	for (i = 0; i < size / SECTOR_SIZE; i ++)
	{
		rt_sem_take(part->lock, RT_WAITING_FOREVER);
B
bernard.xiong 已提交
495 496
		sd_readblock((part->offset + i)*SECTOR_SIZE + pos,
			(rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE));
497 498
		rt_sem_release(part->lock);
	}
B
bernard.xiong 已提交
499

500 501 502 503 504
	/* the length of reading must align to SECTOR SIZE */
	return size;
}

/**
B
bernard.xiong 已提交
505
 * This function will set a hook function, which will be invoked when a memory
506
 * block is allocated from heap memory.
B
bernard.xiong 已提交
507
 *
508 509
 * @param hook the hook function
 */
B
bernard.xiong 已提交
510
static rt_size_t rt_sdcard_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
511 512 513 514
{
	int i;
	struct dfs_partition *part = (struct dfs_partition *)dev->private;

B
bernard.xiong 已提交
515 516 517 518 519 520
	if ( dev == RT_NULL )
	{
		rt_set_errno(-DFS_STATUS_EINVAL);
		return 0;
	}

521 522 523 524
	/* read all sectors */
	for (i = 0; i < size / SECTOR_SIZE; i++)
	{
		rt_sem_take(part->lock, RT_WAITING_FOREVER);
B
bernard.xiong 已提交
525 526
		sd_writeblock((part->offset + i)*SECTOR_SIZE + pos,
			(rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE));
527 528
		rt_sem_release(part->lock);
	}
B
bernard.xiong 已提交
529

530 531 532 533 534 535
	/* the length of reading must align to SECTOR SIZE */
	return size;
}

/**
 * This function will register sd card to device system
B
bernard.xiong 已提交
536
 *
537 538 539 540 541 542 543
 * @param hook the hook function
 */
void rt_hw_sdcard_init()
{
	rt_uint8_t i, status;
	rt_uint8_t *sector;
	char dname[4];
B
bernard.xiong 已提交
544 545
	char sname[8];

546 547 548 549
	if (sd_init() == RT_EOK)
	{
		/* get the first sector to read partition table */
		sector = (rt_uint8_t*) rt_malloc (512);
B
bernard.xiong 已提交
550
		if (sector == RT_NULL)
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
		{
			rt_kprintf("allocate partition sector buffer failed\n");
			return;
		}
		status = sd_readblock(0, sector);
		if (status == RT_EOK)
		{
			for(i=0; i<4; i++)
			{
				/* get the first partition */
				status = dfs_filesystem_get_partition(&part[i], sector, i);
				if (status == RT_EOK)
				{
					rt_snprintf(dname, 4, "sd%d",  i);
					rt_snprintf(sname, 8, "sem_sd%d",  i);
B
bernard.xiong 已提交
566
					part[i].lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
567 568 569 570 571 572 573 574 575 576

					/* register sdcard device */
					sdcard_device[i].init = rt_sdcard_init;
					sdcard_device[i].open = rt_sdcard_open;
					sdcard_device[i].close = rt_sdcard_close;
					sdcard_device[i].read = rt_sdcard_read;
					sdcard_device[i].write = rt_sdcard_write;
					sdcard_device[i].control = rt_sdcard_control;
					sdcard_device[i].private= &part[i];

B
bernard.xiong 已提交
577
					rt_device_register(&sdcard_device[i], dname,
578 579
						RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
				}
B
bernard.xiong 已提交
580
				else
581 582 583 584 585 586
				{
					if(i == 0)
					{
						/* there is no partition table */
						part[0].offset = 0;
						part[0].size   = 0;
B
bernard.xiong 已提交
587
						part[0].lock = rt_sem_create("sem_sd0", 1, RT_IPC_FLAG_FIFO);
588 589 590 591 592 593 594 595 596 597

						/* register sdcard device */
						sdcard_device[0].init = rt_sdcard_init;
						sdcard_device[0].open = rt_sdcard_open;
						sdcard_device[0].close = rt_sdcard_close;
						sdcard_device[0].read = rt_sdcard_read;
						sdcard_device[0].write = rt_sdcard_write;
						sdcard_device[0].control = rt_sdcard_control;
						sdcard_device[0].private= &part[0];

B
bernard.xiong 已提交
598
						rt_device_register(&sdcard_device[0], "sd0",
599 600 601 602 603
							RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);

						break;
					}
				}
B
bernard.xiong 已提交
604
			}
605 606 607 608 609 610 611 612
		}
		else
		{
			rt_kprintf("read sdcard first sector failed\n");
		}

		/* release sector buffer */
		rt_free(sector);
B
bernard.xiong 已提交
613

614 615 616 617 618 619 620 621 622
		return;
	}
	else
	{
		rt_kprintf("sdcard init failed\n");
	}
}

#endif