📄 sdd_mem.c
字号:
SD_card_status_ptr = (SD_CARD_STATUS *)dram_cached(SD_CSTATUS_START);
SD_status_ptr = (SD_STATUS *)dram_cached(SD_STATUS_START);
SD_ocr_reg_ptr = (SD_OCR *)dram_cached(SD_OCR_START);
SD_cid_reg_ptr = (SD_CID *)dram_cached(SD_CID_START);
SD_csd_reg_ptr = (SD_CSD *)dram_cached(SD_CSD_START);
SD_scr_reg_ptr = (SD_SCR *)dram_cached(SD_SCR_START);
/* generate the crc table */
SD_calc_crc16_table(sd_crc16_look_up_table);
SD_calc_crc7_table(sd_crc7_look_up_table);
SD_rca_reg = 0; /* initially '0' */
SD_card_info.type = SD_UNKNOWN;
sd_is_mmc = 0;
SD_card_info.capacity = 0; /* used to check if CSD received */
SD_xmit_info.com_state = SD_IDLE;
#if SD_CHECK_RECV_CRC
SD_xmit_info.crc7_err_cnt = 0;
SD_xmit_info.crc16_err_cnt = 0;
#endif
SD_acmdq.cmd = SD_CMD_EMPTY;
SET_SD_CMD; /* initially high */
SD_DETECT_INPUT;
}
/*
Function: Enable/disable SD eaux ports shared with ATAPI. This is
used to prevent ATAPI initialization problems.
input:
enable: 1 - enable SD IO ports.
0 - disable SD IO ports.
output:
side-effects:
(refer to sd_mem.h for specific eaux ports affected)
*/
void SD_enable_io(int enable)
{
#if defined(SD_MEMORY)
/* shared with ATAPI..
* there is known conflict with ATAPI-D7 (Busy pin) that cause
* ATAPI initialization problem..tread lightly here.
*/
if (enable){
sd_io_status = 1;
ENABLE_SD_GENERAL;
ENABLE_SD_IO;
} else if(sd_io_status){
DISABLE_SD_GENERAL;
DISABLE_SD_IO;
sd_io_status = 0;
}
#endif
}
/*
Function: SD-memory/MMC card detection. Gets relative card
address(RCA) from card if detected.
input: (none)
output:
-2: failed to get CSD register
-1: not voltage compatible
0: no valid SD-mem or MMC card found
5: if successful
*/
int SD_identify_device(void)
{
int status, status1, cnt=0;
SD_enable_io(1);
SD_init();
SD_card_info.inserted = 1;
/* Force SD card to idle-state to start initialization */
SD_clk_restricted_cmd(SD_CMD_GO_IDLE_STATE, 0);
/* send ACMD41 w/acceptable OCR..
* and wait until SD card is ready.
*/
SD_ocr_reg_ptr->card_ready = 0;
do {
status = SD_clk_restricted_cmd(SD_CMD_APP_CMD, 0);
status1 = SD_clk_restricted_cmd(SD_ACMD_SD_SEND_OP_COND,
SD_ACCEPTABLE_OCR);
if ((status == -1) && (status1 == -1)) {
SD_clk_restricted_cmd(SD_CMD_GO_IDLE_STATE, 0);
cnt++;
if (cnt > SD_MAX_RETRIES) {
/* timed out..no response */
status = -3;
break;
}
}
} while (!SD_ocr_reg_ptr->card_ready);
sd_is_mmc = 0;
/*
* if no response: 1) SD card not voltage compatible
* 2) could be Multimedia card..verify
* by sending CMD1 (MMC's ACMD41)
*/
if (status == -3){
/* check if MMC? */
SD_clk_restricted_cmd(SD_CMD_GO_IDLE_STATE, 0);
cnt=0;
SD_ocr_reg_ptr->card_ready = 0;
do {
status = SD_clk_restricted_cmd(SD_CMD_MMC_SEND_OP_COND,
SD_ACCEPTABLE_OCR);
if (status == -1) {
/* no response */
cnt++;
if (cnt > SD_MAX_RETRIES){
/* card not voltage compatible */
return (-1);
}
}
} while (!SD_ocr_reg_ptr->card_ready);
SD_card_info.type = SD_MMC; /* MultiMedia Card */
sd_is_mmc = 1;
} else {
SD_card_info.type = SD_MEM; /* SD Memory Card */
}
if(SD_card_info.type == SD_MMC){
SD_rca_reg = 0x1;
}
else{
SD_rca_reg = 0xffff;
}
/* send CMD2 to get CID number */
status = SD_clk_restricted_cmd(SD_CMD_ALL_SEND_CID, 0);
/* send CMD3 to get RCA */
if(SD_card_info.type == SD_MMC){
status = SD_clk_restricted_cmd(SD_CMD_SEND_REL_ADDR,
SD_rca_reg<<16);
}
else{
status = SD_clk_restricted_cmd(SD_CMD_SEND_REL_ADDR, 0);
}
if (status == 1) {
/* send CMD9 to get Card Specific Data (CSD) */
status = SD_send_cmd(SD_CMD_SEND_CSD, SD_rca_reg<<16, 1);
if (status == 1) {
SD_update_card_info();
/* send card to tranfer state */
SD_send_cmd(SD_CMD_SELECT_CARD, SD_rca_reg<<16, 1);
if (SD_card_info.type > SD_MMC) {
/* send ACMD51 to get SD configuration register */
SD_scr_reg_ptr->sd_bus_widths = 0x1; /* default 1bit */
SD_send_acmd(SD_ACMD_SEND_SCR, 0, 1);
/* set to 4bit data bus if possible */
SD_set_bus_width(2);
/* send ACMD13 to get SD Status register */
SD_send_acmd(SD_ACMD_SD_STATUS, 0, 1);
}
/* we have valid SD/MMC card */
status = 5;
} else {
status = -2; /* failed to get CSD */
}
} else {
SD_card_info.type = SD_UNKNOWN;
status = 0;
}
SD_enable_io(0);
return (status);
}
/*
Function: SD-memory/MMC card reset.
input:
output:
side-effects:
*/
void SD_reset(void)
{
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
SD_send_cmd(SD_CMD_GO_IDLE_STATE, 0, 1);
SD_xmit_info.data_width = 0; /* initially only D0 used */
SD_card_info.type = SD_UNKNOWN;
sd_is_mmc = 0;
SD_card_info.inserted = 0;
SD_card_info.capacity = 0; /* used to check if CSD received */
SD_xmit_info.com_state = SD_IDLE;
#if SD_CHECK_RECV_CRC
SD_xmit_info.crc7_err_cnt = 0;
SD_xmit_info.crc16_err_cnt = 0;
#endif
SD_acmdq.cmd = SD_CMD_EMPTY;
SET_SD_CMD; /* initially high */
}
/*
Function: Set data bus width, 4bit or 1bit.
input:
0 - 1bit data bus (narrow bus)
2 - 4bit data bus (wide bus)
output:
1: success
otherwise: failed
*/
int SD_set_bus_width(int width)
{
uint status = 0;
dawei(("SD_set_bus_width( %d )\n", width));
if ((SD_scr_reg_ptr->sd_bus_widths & 0x4)) {
/* 4bit supported by card */
if ((width>>1) != SD_xmit_info.data_width) {
status = SD_send_acmd(SD_ACMD_SET_BUS_WIDTH, width, 1);
if (status==1) SD_xmit_info.data_width = (width>>1);
}
}
return (status);
}
/*
Function: Read single block from SD. The max block size is card
specific, in the range of 512 to 2048 bytes. The minimum
block size is 1 byte if card support "partial block read".
SD memory card always support PBR.
(NOTE: currently our code is hardwired to 512B block)
input:
addr: location of SD data (lba).
blk_sz: block size to read. (2^val bytes)
data_ptr: SD data destination.
immed: 1 - complete data read in function.
0 - initiate data read..let SD_service() finish
in background.
output:
-4: unsupported block size.
-3: timed out (reached retry limit)
-2: communication busy
-1: invalid or unsupported command or no card.
0: read initiated.."passed" to SD_service().
1: successful
side-effects:
*/
int SD_read_blk(int addr, int blk_sz, uint *data_ptr, int immed)
{
int status;
if (blk_sz != SD_xmit_info.cur_blk_size) {
/* check if card allows block size */
if ((blk_sz == SD_csd_reg_ptr->rd_blk_len) ||
(SD_csd_reg_ptr->rd_blk_len_partial &&
blk_sz < SD_csd_reg_ptr->rd_blk_len)) {
SD_send_cmd(SD_CMD_SET_BLOCKLEN, (1<<blk_sz), immed);
} else {
return (-4); /* invalid block size */
}
}
SD_xmit_info.cur_blk_size = blk_sz;
SD_xmit_info.rd_dest_ptr = data_ptr;
status=SD_send_cmd(SD_CMD_READ_SINGLE_BLOCK, addr, immed);
return (status);
}
static int SD_write_blk(int addr,int blk_sz,int nblk,int*data_ptr, int immed)
{
int status = 1;
int erase_blk_en, sec_size, wr_bl_len, wr_blk_len_partial;
if (blk_sz != SD_xmit_info.cur_blk_size) {
/* check if card allows block size */
if ((blk_sz == SD_csd_reg_ptr->wr_blk_len) ||
(SD_csd_reg_ptr->wr_blk_partial &&
blk_sz < SD_csd_reg_ptr->wr_blk_len)) {
status = SD_send_cmd(SD_CMD_SET_BLOCKLEN, (1<<blk_sz), immed);
} else {
return (-4); /* invalid block size */
}
}
if(status != 1){
JPRINTF(("SD Set Block_len error. status %d\n", status));
return -1;
}
SD_xmit_info.cur_blk_size = blk_sz;
SD_xmit_info.wr_src_ptr = data_ptr;
SD_xmit_info.data_len = nblk*(1<<blk_sz);
if(nblk>1)
status=SD_send_cmd(SD_CMD_WRITE_MULTI_BLOCK, addr, immed);
else
status=SD_send_cmd(SD_CMD_WRITE_BLOCK, addr, immed);
if(status != 1){
JPRINTF(("SD Set Write Cmd error.\n"));
return -1;
}
else if(SD_xmit_info.result != 0){
JPRINTF(("SD Writing error.\n"));
return -1;
}
return 0;
}
/*
Function: Read multiple blocks from SD. The max block size is card
specific, in the range of 512 to 2048 bytes.
(NOTE: currently our code is hardwired to 512B block)
input:
addr: location of SD data (lba).
nblk: number of blocks to read.
data_ptr: SD data destination.
immed: 1 - complete data read in function.
0 - initiate data read..let SD_service() finish
in background.
output:
-3: timed out (reached retry limit)
-2: communication busy
-1: invalid or unsupported command or no card.
0: read initiated.."passed" to SD_service().
1: successful
side-effects:
*/
int SD_read_nblk(int addr, int nblk, uint *data_ptr, int immed)
{
int status, limit;
/* make sure block size is 512B..FAT hardwired */
if (SD_xmit_info.cur_blk_size != 9) {
SD_send_cmd(SD_CMD_SET_BLOCKLEN, 512, immed);
}
SD_xmit_info.cur_blk_size = 9; /* 512..(2^9) */
SD_xmit_info.rd_dest_ptr = data_ptr;
limit = nblk*512;
#if 0
status = SD_send_cmd(MMC_CMD_READ_UNTIL_STOP, addr, 0);
#endif
status = SD_send_cmd(SD_CMD_READ_MULTI_BLOCK, addr, 0);
SD_xmit_info.data_len = nblk*512;
SD_xmit_info.data_cnt = 0;
/* NOTE: for "non-immediate" case, make sure similar process
* below is present in background task to complete the read.
*/
if ((status >= 0) && immed) {
PRINTF(("com_state %d\n",SD_xmit_info.com_state));
while (SD_xmit_info.com_state) {
SD_service();
if (SD_xmit_info.data_cnt >= limit
&& !sd_is_mmc) break;
}
status = SD_send_cmd(SD_CMD_STOP_TRANSMIT, 0, immed);
PRINTF(("xmit bytes %d, required bytes %d, status\n",
SD_xmit_info.data_cnt, SD_xmit_info.data_len, status));
}else{
JPRINTF(("SD_read_nblk... error \n"));
}
return (status);
}
/*
Function: used in SD_service() for post-processing of commands...
1) command retry for errors (up to SD_MAX_RETRIES).
2) send app-command if CMD55 was previously sent.
3) send pending command in queue if any.
input: no arguments..but app-commands and pending commands are
stored in "SD_acmdq" structure for processing.
output:
side-effects:
*/
int SD_get_next_cmd(void)
{
int send=0;
if (SD_xmit_info.response_expected &&
!SD_xmit_info.response_recv) {
if (SD_xmit_info.retry_cnt < SD_MAX_RETRIES) {
/* failed/aborted commands..retry */
SD_xmit_info.wait_nclk = SD_NCR_MAX;
send = 1;
} else {
/* reach retry limit */
SD_xmit_info.retry_cnt = 0xff;
}
} else {
/* command specific post-processing */
switch (SD_xmit_info.cmd) {
case SD_CMD_APP_CMD:
/* send app-command */
SD_set_cmd(SD_acmdq.cmd, SD_acmdq.arg);
SD_acmdq.cmd = SD_CMD_EMPTY; /* clear cmd-Q */
send = 1;
break;
default:
if (SD_acmdq.cmd != SD_CMD_EMPTY) {
/* cmd pending */
send = SD_set_cmd(SD_acmdq.cmd, SD_acmdq.arg);
SD_acmdq.cmd = SD_CMD_EMPTY; /* clear cmd-Q */
}
break;
}
}
return (send);
}
/*
Function: send command to SD card.
input:
command: command index (0-63).
arg: command argument.
immed: 1-complete command immediately
0-initiate command..let SD_service() finish
output:
-3: timed out (reached retry limit)
-2: communication busy
-1: invalid or unsupported command or no card.
0: pending..command "passed" to SD_service().
1: successful
*/
int SD_send_cmd(int command, uint arg, int immed)
{
int status=0;
if (!SD_card_info.inserted || command > 63)
return (-1); /* sanity check */
/* send command w/ CRC7*/
if ( (SD_xmit_info.com_state == SD_IDLE) ||
(command == SD_CMD_STOP_TRANSMIT) ) {
if (!SD_set_cmd(command, arg)) return (-1);
SD_xmit_info.com_state = HOST2SD_START;
if (immed) {
while (SD_xmit_info.com_state) SD_service();
status = (SD_xmit_info.retry_cnt == 0xff) ? -3 : 1;
}
} else {
/* put in cmd-Q..if not app-command */
if (!(command & ACMD_MARKER) &&
(command != SD_CMD_APP_CMD)) {
SD_acmdq.cmd = command;
SD_acmdq.arg = arg;
} else {
status = -2; /* Bus is busy..lost app-command */
}
}
return (status);
}
/*
Function: send application specific command to SD card.
App-commands needs to send pre-command(0x55).
input:
command: app-command index.
arg: app-command argument.
immed: 1-complete command immediately
0-initiate command..let SD_service() finish
output:
-2: communication busy
-1: invalid command.
0: pending..command "passed" to SD_service().
1: successful
*/
int SD_send_acmd(int acmd, uint arg, int immed)
{
int status;
/* set app-command */
SD_acmdq.cmd = acmd;
SD_acmdq.arg = arg;
status = SD_send_cmd(SD_CMD_APP_CMD, SD_rca_reg<<16, immed);
return (status);
}
/*
Function: Initializes xmit data structure for new command.
Checks card(CSD reg) for command class support.
input:
command: command index.
arg: command argument.
output:
0: command not supported by card.
1: successful
*/
static int SD_set_cmd(int command, uint arg)
{
uint is_acmd, cmd, tmp;
uchar *sd_resp_ptr;
cmd = command & 0x3f;
is_acmd = command & ACMD_MARKER;
if (SD_card_info.capacity) {
/* card has been initialized..check class support */
tmp = (is_acmd) ? SD_CL8 : SD_cmd2class[cmd]; /* class */
if (!(SD_csd_reg_ptr->ccc & (1<<tmp))) {
return(0); /* card does not support command class */
}
}
sd_resp_ptr = (is_acmd) ? SD_acmd2resp : SD_cmd2resp;
SD_xmit_info.cmd = command;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -