123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- /*
- * 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://www.rt-thread.org/license/LICENSE
- *
- * Change Logs:
- * Date Author Notes
- * 2007-12-02 Yi.Qiu the first version
- * 2010-01-01 Bernard Modify for mini2440
- * 2012-12-15 amr168 support SDHC
- */
- #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;
- volatile rt_int32_t sd_type;
- static void sd_delay(rt_uint32_t ms)
- {
- ms *= 7326;
- while(--ms);
- }
- static int sd_cmd_end(int cmd, int be_resp)
- {
- int finish0;
- if (!be_resp)
- {
- finish0 = SDICSTA;
- while ((finish0&0x800) != 0x800)
- finish0 = SDICSTA;
- SDICSTA = finish0;
- 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;
- }
- }
- 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;
- }
- static void sd_cmd0(void)
- {
- SDICARG = 0x0;
- SDICCON = (1<<8) | 0x40;
- sd_cmd_end(0, 0);
- SDICSTA = 0x800; /* Clear cmd_end(no rsp) */
- }
- static int sd_cmd55(void)
- {
- SDICARG = RCA << 16;
- SDICCON = (0x1 << 9) | (0x1 << 8) | 0x77;
- if (sd_cmd_end(55, 1) == RT_ERROR)
- {
- /* rt_kprintf("CMD55 error\n"); */
- return RT_ERROR;
- }
- SDICSTA = 0xa00;
- return RT_EOK;
- }
- static void sd_sel_desel(char sel_desel)
- {
- if (sel_desel)
- {
- RECMDS7:
- SDICARG = RCA << 16;
- SDICCON = (0x1 << 9) | (0x1 << 8) | 0x47;
- if (sd_cmd_end(7, 1) == RT_ERROR)
- goto RECMDS7;
- SDICSTA = 0xa00;
- if (SDIRSP0 & 0x1e00 != 0x800)
- goto RECMDS7;
- }
- else
- {
- RECMDD7:
- SDICARG = 0 << 16;
- SDICCON = (0x1 << 8) | 0x47;
- if (sd_cmd_end(7, 0) == RT_ERROR)
- goto RECMDD7;
- SDICSTA = 0x800;
- }
- }
- static void sd_setbus(void)
- {
- do
- {
- sd_cmd55();
- SDICARG = 1 << 1; /* 4bit bus */
- SDICCON = (0x1<<9) | (0x1<<8) | 0x46; /* sht_resp, wait_resp, start, CMD55 */
- }while (sd_cmd_end(6, 1) == RT_ERROR);
- SDICSTA=0xa00; /* Clear cmd_end(with rsp) */
- }
- static int sd_ocr(void)
- {
- int i, ver=0;
- /* Negotiate operating condition for SD, it makes card ready state */
- for (i = 0; i < 50; i ++)
- {
- sd_cmd55();
- SDICARG = 0x40ff8000; /* HCS=1, compatible v1.x and v2.0 */
- 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 (sd_cmd_end(41, 1) == RT_EOK)
- {
- if (SDIRSP0 == 0x80ff8000)
- {
- ver = 1; /* SD V1.x, CCS=0 */
- break;
- }
- else if (SDIRSP0 == 0xc0ff8000)
- {
- ver = 2; /* SD V2.0, CCS=1 */
- break;
- }
- }
- sd_delay(200);
- }
- SDICSTA = 0xa00;
- return ver;
- }
- rt_err_t sd_cmd8(void)
- {
- SDICARG = 0x000001AA;
- SDICCON = (0x1<<9) | (0x1<<8) | 0x48; //sht_resp, wait_resp, start
- if (sd_cmd_end(8, 1) == RT_ERROR)
- return RT_ERROR;
- SDICSTA = 0xa00;
-
- if ((SDIRSP0&0x1aa) == 0x1aa)
- return RT_EOK;
- else
- return RT_ERROR;
- }
- static rt_uint8_t sd_init(void)
- {
- //-- SD controller & card initialize
- int i;
- /* Important notice for MMC test condition */
- /* Cmd & Data lines must be enabled by pull up resister */
- SDIPRE = PCLK / (INICLK) - 1;
- SDICON = (0<<4) | 1; // Type A, clk enable
- SDIFSTA = SDIFSTA | (1<<16);
- SDIBSIZE = 0x200; /* 512byte per one block */
- SDIDTIMER = 0x7fffff; /* timeout count */
- /* Wait 74SDCLK for MMC card */
- for (i = 0; i < 0x1000; i ++);
- sd_cmd0();
- sd_cmd8(); /* Must be use it, Host shall supports high capacity */
- /* Check SD card OCR */
- sd_type = sd_ocr();
- if (sd_type > 0)
- {
- 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; /* lng_resp, wait_resp, start, CMD2 */
- if (sd_cmd_end(2, 1) == RT_ERROR)
- goto RECMD2;
- SDICSTA = 0xa00; /* Clear cmd_end(with rsp) */
- RECMD3:
- SDICARG = 0<<16; /* CMD3(MMC:Set RCA, SD:Ask RCA-->SBZ) */
- SDICCON = (0x1<<9)|(0x1<<8)|0x43; /* sht_resp, wait_resp, start, CMD3 */
- if (sd_cmd_end(3, 1) == RT_ERROR)
- goto RECMD3;
- SDICSTA=0xa00; /* Clear cmd_end(with rsp) */
- RCA = (SDIRSP0 & 0xffff0000) >> 16;
- SDIPRE = PCLK / (SDCLK) - 1; /* Normal clock=25MHz */
- if (SDIRSP0 & 0x1e00 != 0x600)
- goto RECMD3;
- sd_sel_desel(1);
- sd_delay(200);
- sd_setbus();
- return RT_EOK;
- }
- static rt_uint8_t sd_readblock(rt_uint32_t address, rt_uint8_t *buf)
- {
- rt_uint32_t status, tmp;
- rd_cnt = 0;
- SDIFSTA = SDIFSTA | (1<<16);
- 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)
- {
- rt_kprintf("Read CMD Error\n");
- goto RERDCMD;
- }
- SDICSTA = 0xa00;
- while (rd_cnt < 128)
- {
- if ((SDIDSTA & 0x20) == 0x20)
- {
- SDIDSTA = (0x1 << 0x5);
- break;
- }
- status = SDIFSTA;
- if ((status & 0x1000) == 0x1000)
- {
- tmp = SDIDAT;
- rt_memcpy(buf, &tmp, sizeof(rt_uint32_t));
- rd_cnt ++;
- buf += 4;
- }
- }
- if (sd_data_end() == RT_ERROR)
- {
- rt_kprintf("Dat error\n");
- return RT_ERROR;
- }
- SDIDCON = SDIDCON &~ (7<<12);
- SDIFSTA = SDIFSTA & 0x200;
- SDIDSTA = 0x10;
- return RT_EOK;
- }
- static rt_uint8_t sd_writeblock(rt_uint32_t address, rt_uint8_t *buf)
- {
- rt_uint32_t status, tmp;
- wt_cnt = 0;
- 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;
- SDICSTA = 0xa00;
- while (wt_cnt < 128)
- {
- status = SDIFSTA;
- if ((status & 0x2000) == 0x2000)
- {
- rt_memcpy(&tmp, buf, sizeof(rt_uint32_t));
- SDIDAT = tmp;
- wt_cnt ++;
- buf += 4;
- }
- }
- if (sd_data_end() == RT_ERROR)
- {
- rt_kprintf("Data Error\n");
- return RT_ERROR;
- }
- 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];
- static rt_err_t rt_sdcard_init(rt_device_t dev)
- {
- return RT_EOK;
- }
- static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
- {
- return RT_EOK;
- }
- static rt_err_t rt_sdcard_close(rt_device_t dev)
- {
- return RT_EOK;
- }
- static rt_err_t rt_sdcard_control(rt_device_t dev, rt_uint8_t cmd, void *args)
- {
- return RT_EOK;
- }
- static rt_size_t rt_sdcard_read(rt_device_t dev,
- rt_off_t pos,
- void *buffer,
- rt_size_t size)
- {
- int i, addr;
- struct dfs_partition *part = (struct dfs_partition *)dev->user_data;
- if (dev == RT_NULL)
- {
- rt_set_errno(-DFS_STATUS_EINVAL);
- return 0;
- }
- /* read all sectors */
- for (i = 0; i < size; i ++)
- {
- rt_sem_take(part->lock, RT_WAITING_FOREVER);
- if (sd_type == 1)
- addr = (part->offset + i + pos)*SECTOR_SIZE;
- else
- addr = (part->offset + i + pos);
- sd_readblock(addr, (rt_uint8_t *)((rt_uint8_t *)buffer + i * SECTOR_SIZE));
- rt_sem_release(part->lock);
- }
- /* the length of reading must align to SECTOR SIZE */
- return size;
- }
- static rt_size_t rt_sdcard_write(rt_device_t dev,
- rt_off_t pos,
- const void *buffer,
- rt_size_t size)
- {
- int i, addr;
- struct dfs_partition *part = (struct dfs_partition *)dev->user_data;
- if (dev == RT_NULL)
- {
- rt_set_errno(-DFS_STATUS_EINVAL);
- return 0;
- }
- /* read all sectors */
- for (i = 0; i < size; i++)
- {
- rt_sem_take(part->lock, RT_WAITING_FOREVER);
- if (sd_type == 1)
- addr = (part->offset + i + pos)*SECTOR_SIZE;
- else
- addr = (part->offset + i + pos);
- sd_writeblock(addr, (rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE));
- rt_sem_release(part->lock);
- }
- /* the length of reading must align to SECTOR SIZE */
- return size;
- }
- void rt_hw_sdcard_init(void)
- {
- rt_uint8_t i, status;
- rt_uint8_t *sector;
- char dname[4];
- char sname[8];
- /* Enable PCLK into SDI Block */
- CLKCON |= 1 << 9;
- /* Setup GPIO as SD and SDCMD, SDDAT[3:0] Pull up En */
- GPEUP = GPEUP & (~(0x3f << 5)) | (0x01 << 5);
- GPECON = GPECON & (~(0xfff << 10)) | (0xaaa << 10);
- RCA = 0;
- if (sd_init() == RT_EOK)
- {
- /* get the first sector to read partition table */
- sector = (rt_uint8_t*) rt_malloc (512);
- if (sector == RT_NULL)
- {
- 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);
- part[i].lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
- /* register sdcard device */
- sdcard_device[i].type = RT_Device_Class_Block;
- 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].user_data = &part[i];
- rt_device_register(&sdcard_device[i], dname,
- RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
- }
- else
- {
- if (i == 0)
- {
- /* there is no partition table */
- part[0].offset = 0;
- part[0].size = 0;
- part[0].lock = rt_sem_create("sem_sd0", 1, RT_IPC_FLAG_FIFO);
- /* register sdcard device */
- sdcard_device[0].type = RT_Device_Class_Block;
- 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].user_data = &part[0];
- rt_device_register(&sdcard_device[0], "sd0",
- RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
- break;
- }
- }
- }
- }
- else
- {
- rt_kprintf("read sdcard first sector failed\n");
- }
- /* release sector buffer */
- rt_free(sector);
- return;
- }
- else
- {
- rt_kprintf("sdcard init failed\n");
- }
- }
- #endif
|