www.pudn.com > sd(sd_4_data_mode).rar > sd_mem.c
/* Copyright 2002, ESS Technology, Inc. */
/* SCCSID @(#)sd_mem.c 1.40 08/10/04 */
#ifdef SD_MEMORY
#include "common.h"
#include "ioport.h"
#include "mvd.h"
#include "buffer.h"
#include "custmem.h"
#include "memmap.h"
#include "smfont.h"
#include "util.h"
#include "constvar.h"
#include "sd_mem.h"
#include "sysinfo.h"
#include "mem_dev.h"
#include "debug.h"
/*------------------------------------------------------------------------
* Debugging macros
*------------------------------------------------------------------------*/
#define CPRINTF(a)
#define PRINTF(a)
#define JPRINTF(a)
#define SD_ENABLE_WRITE
#if 0
int bpt;
#define BREAKPOINT(x) {bpt=x;while(bpt) VCX_service();}
#else
#define BREAKPOINT(x)
#endif
/*------------------------------------------------------------------------
* macros
*------------------------------------------------------------------------*/
#define USEC(x) (cpuclk*x/10)
#define get_bigend32(pcbuf, off) ((uchar)pcbuf[off]|((uchar)pcbuf[off+1] << 8)| \
( (uchar)pcbuf[off+2] << 16)|((uchar)pcbuf[off+3] <<24))
/*------------------------------------------------------------------------
* Public variables
*------------------------------------------------------------------------*/
SD_CINFO SD_card_info;
SD_XMIT_STATUS SD_xmit_info;
/*------------------------------------------------------------------------
* Private variables
*------------------------------------------------------------------------*/
static SD_CARD_STATUS *SD_card_status_ptr; /* R1 reply */
static SD_STATUS *SD_status_ptr;
static SD_OCR *SD_ocr_reg_ptr;
static SD_CID *SD_cid_reg_ptr;
static SD_CSD *SD_csd_reg_ptr;
static ushort SD_rca_reg; /* rel card address..ID for multi cards */
static SD_SCR *SD_scr_reg_ptr;
static uint SD_rdata32;
static int sd_is_mmc;
static int sd_io_status = 0;
static SD_CMD_Q SD_acmdq; /* SD command queue or appcmd */
static unsigned short sd_crc16_look_up_table[256];
static uchar sd_crc7_look_up_table[256];
static int sdTotalBlockNo, sdPagePerBlock, sdEraseSecSize;
/* NOTE: move LUT's to rom later */
/* LUT for commands with responses: R1, R1b, R2, R3, R6 */
uchar SD_cmd2resp[64] = {
/* CMD0 - CMD7 */
SD_NR, SD_R3, SD_R2, SD_R6, SD_NR, SD_NR, SD_NR, SD_R1b,
/* CMD8 - CMD15 */
SD_NR, SD_R2, SD_R2, SD_R1_RD, SD_R1b,SD_R1, SD_NR, SD_NR,
/* CMD16 - CMD23 */
SD_R1, SD_R1_RD, SD_R1_RD, SD_NR, SD_NR, SD_NR, SD_NR, SD_R1,
/* CMD24 - CMD31 */
SD_R1_WR, SD_R1_WR, SD_NR, SD_R1, SD_R1b,SD_R1b,SD_R1, SD_NR,
/* CMD32 - CMD39 */
SD_R1, SD_R1, SD_NR, SD_NR, SD_NR, SD_NR, SD_R1b,SD_NR,
/* CMD40 - CMD47 */
SD_NR, SD_NR, SD_R1, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR,
/* CMD48 - CMD55 */
SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_R1,
/* CMD56 - CMD63 */
SD_R1, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR
};
/* LUT for app. commands with responses: R1, R1b, R2, R3, R6 */
uchar SD_acmd2resp[52] = {
/* ACMD0 - ACMD7 */
SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_R1, SD_NR,
/* ACMD8 - ACMD15 */
SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_R1_RD, SD_NR, SD_NR,
/* ACMD16 - ACMD23 */
SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_R1, SD_R1,
/* ACMD24 - ACMD31 */
SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR,
/* ACMD32 - ACMD8 */
SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR,
/* ACMD40 - ACMD47 */
SD_NR, SD_R3, SD_R1, SD_NR, SD_NR, SD_NR, SD_NR, SD_NR,
/* ACMD48 - ACMD51 */
SD_NR, SD_NR, SD_NR, SD_R1_RD
};
/* LUT for SD command classes */
uchar SD_cmd2class[64] = {
/* CMD0 - CMD7 */
SD_CL0,SD_CL0,SD_CL0,SD_CL0,SD_CL0,SD_CL0,SD_CL0,SD_CL0,
/* CMD8 - CMD15 */
SD_CL0,SD_CL0,SD_CL0,SD_CL1,SD_CL0,SD_CL0,SD_CL0,SD_CL0,
/* CMD16 - CMD23 */
SD_CL2,SD_CL2,SD_CL2,SD_CL2,SD_CL2,SD_CL2,SD_CL2,SD_CL2,
/* CMD24 - CMD31 */
SD_CL4,SD_CL4,SD_CL4,SD_CL4,SD_CL6,SD_CL6,SD_CL6,SD_CL6,
/* CMD32 - CMD39 */
SD_CL5,SD_CL5,SD_CL5,SD_CL5,SD_CL5,SD_CL5,SD_CL5,SD_CL5,
/* CMD40 - CMD47 */
SD_CL5,SD_CL5,SD_CL7,SD_CL7,SD_CL7,SD_CL7,SD_CL7,SD_CL7,
/* CMD48 - CMD55 */
SD_CL7,SD_CL7,SD_CL7,SD_CL7,SD_CL7,SD_CL7,SD_CL7,SD_CL8,
/* CMD56 - CMD63 */
SD_CL8,SD_CL8,SD_CL8,SD_CL8,SD_CL8,SD_CL8,SD_CL8,SD_CL8,
};
/* LUT for CSD's TAAC time value */
uchar SD_taac_valx10[16] = {
00, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80
};
#ifdef BANK2SPEEDUP
static unsigned old_wait_state;
#endif
/*------------------------------------------------------------------------
* Private functions
*------------------------------------------------------------------------*/
static int SD_set_cmd(int, uint);
static void SD_update_card_info(void);
static ushort SD_calc_crc16(uchar *, ushort);
static void SD_calc_crc16_table(ushort *);
static uchar SD_calc_crc7(uchar *, ushort);
static void SD_calc_crc7_table(uchar *);
static int SD_write_blk(int, int, int, int *, int);
/*------------------------------------------------------------------------
* Begin SD function listing
*------------------------------------------------------------------------*/
/*
Function: Get partition boot record (PBR) address from master
boot record area.
input:
output: PBR start address as physical lba (physical sector number).
side-effects:
*/
unsigned int SD_boot_setup(void)
{
uchar *buff;
uint PBR_start_psn;
SD_enable_io(1); /* enable SD eaux pins */
buff = (uchar *)dram_cached(SD_DATA_START);
SD_read_sector_lba((short *)buff, 0, 1, 1); /* 512B per block */
if (((buff[0x0] == 0xEB) && (buff[0x2] == 0x90))
|| (buff[0x0] == 0xE9)) {
PBR_start_psn = 0;
}else
PBR_start_psn = get_bigend32(buff, 454);
return(PBR_start_psn);
}
/*********************************************************************
return:
1: MMC
0: SD or else
**********************************************************************/
int SD_is_mmc(void){
if(SD_card_info.type == SD_MMC)
return 1;
else
return 0;
}
/*
Function: Reads from specified lba to designated buffer.
input:
buff: pointer for SD data destination.
lba: physical logical block address.
nblk: number of blocks to read.
output: number of bytes read.
side-effects:
*/
int SD_read_sector_lba(short *buff, int lba, int nblk, int immed)
{
int i, start_lba = lba;
short *pDest = buff;
set_bank2_wait ();
if (nblk == 1) {
SD_read_blk(lba<<9, 9, (unsigned int *)buff, immed);
} else {
PRINTF(("SD_multi_block read: %d-->%x : nblk %d \n",
lba, buff, nblk));
if(SD_card_info.type == SD_MMC){
for(i= 0; i1 && immed)
status = SD_send_cmd(SD_CMD_STOP_TRANSMIT, 0, 1);
}
JPRINTF(("SD_write_sector_lba: data_cnt%d nblk %d, status %x\n",
SD_xmit_info.data_cnt, nblk, status));
return (512*nblk);
}
/*
Function: The faster CRC16 calculation procedure
uses 256 x 16-bit Look Up Table (8bit at a time)..
more efficient than generating CRC 1bit at a time.
(adapted from memstick.c version)
input:
data: pointer to data to be protected by CRC.
count: total bytes of data.
output: CRC16
side-effects:
*/
static ushort SD_calc_crc16(uchar *data, ushort count)
{
ushort fcs = 0x0; /* initial FCS value */
ushort i, t, tl, th;
for (i=0; i>8) ^ *data++];
fcs = fcs ^ (t<<8);
}
return(fcs);
}
/* in case of 4-bit mode */
static ushort SD_calc_crc16_4_bit(int *data, ushort count, ushort *crc)
{
ushort fcs0 = 0x0, fcs1=0, fcs2=0, fcs3=0; /* initial FCS value */
ushort i, j ;
int tmp, *pInt;
uint filter;
ushort d0,d1,d2,d3;
ushort tt0,tt1,tt2,tt3;
pInt = data;
for (i=0; i> 24); /* 0 */
d3 |= ((tmp & 0x08000000) >> 21); /* 1 */
d3 |= ((tmp & 0x00800000) >> 18); /* 2 */
d3 |= ((tmp & 0x00080000) >> 15); /* 3 */
d3 |= ((tmp & 0x00008000) >> 12); /* 4 */
d3 |= ((tmp & 0x00000800) >> 9); /* 5 */
d3 |= ((tmp & 0x00000080) >> 6); /* 6 */
d3 |= ((tmp & 0x00000008) >> 3); /* 7 */
d2 = ((tmp & 0x40000000) >> 23); /* 0 */
d2 |= ((tmp & 0x04000000) >> 20); /* 1 */
d2 |= ((tmp & 0x00400000) >> 17); /* 2 */
d2 |= ((tmp & 0x00040000) >> 14); /* 3 */
d2 |= ((tmp & 0x00004000) >> 11); /* 4 */
d2 |= ((tmp & 0x00000400) >> 8); /* 5 */
d2 |= ((tmp & 0x00000040) >> 5); /* 6 */
d2 |= ((tmp & 0x00000004) >> 2); /* 7 */
d1 = ((tmp & 0x20000000) >> 22); /* 0 */
d1 |= ((tmp & 0x02000000) >> 19); /* 1 */
d1 |= ((tmp & 0x00200000) >> 16); /* 2 */
d1 |= ((tmp & 0x00020000) >> 13); /* 3 */
d1 |= ((tmp & 0x00002000) >> 10); /* 4 */
d1 |= ((tmp & 0x00000200) >> 7); /* 5 */
d1 |= ((tmp & 0x00000020) >> 4); /* 6 */
d1 |= ((tmp & 0x00000002) >> 1); /* 7 */
d0 = ((tmp & 0x10000000) >> 21); /* 0 */
d0 |= ((tmp & 0x01000000) >> 18); /* 1 */
d0 |= ((tmp & 0x00100000) >> 15); /* 2 */
d0 |= ((tmp & 0x00010000) >> 12); /* 3 */
d0 |= ((tmp & 0x00001000) >> 9); /* 4 */
d0 |= ((tmp & 0x00000100) >> 6); /* 5 */
d0 |= ((tmp & 0x00000010) >> 3); /* 6 */
d0 |= ((tmp & 0x00000001) ); /* 7 */
// PRINTF(("wanted : %x tmp %x, filter %x\n",
// data_wanted, tmp, filter));
tt0 = fcs0;
tt1 = fcs1;
tt2 = fcs2;
tt3 = fcs3;
fcs0 = sd_crc16_look_up_table[(tt0>>8) ^ d0];
fcs1 = sd_crc16_look_up_table[(tt1>>8) ^ d1];
fcs2 = sd_crc16_look_up_table[(tt2>>8) ^ d2];
fcs3 = sd_crc16_look_up_table[(tt3>>8) ^ d3];
fcs0 = fcs0 ^ (tt0<<8);
fcs1 = fcs1 ^ (tt1<<8);
fcs2 = fcs2 ^ (tt2<<8);
fcs3 = fcs3 ^ (tt3<<8);
}
crc[0] = fcs0;
crc[1] = fcs1;
crc[2] = fcs2;
crc[3] = fcs3;
return(0);
}
static uchar SD_calc_crc7(uchar *data, ushort count)
{
uchar fcs = 0x0; /* initial FCS value */
ushort i;
uchar g = 0x9;
uchar t;
for (i=0; itaac_value];
data >>= 2; /* WS = 4 */
cnt = SD_csd_reg_ptr->taac_unit - 5; /* n power of 10 */
if (cnt < 0) {
do {
data /= 10;
cnt++;
} while (cnt);
} else {
while (cnt) {
data *= 10;
cnt--;
};
}
/* read access time */
SD_card_info.n_ac_max = SD_NAC_MIN + data +
(100 * SD_csd_reg_ptr->nsac);
mmc_ac = 10*(data+100*SD_csd_reg_ptr->nsac);
if(sd_is_mmc)
SD_card_info.n_ac_max = mmc_ac;
JPRINTF(("n_ac_max: sd: %d, mmc %d \n",
SD_card_info.n_ac_max, mmc_ac));
/* write access time */
nwrmax = (SD_card_info.n_ac_max)<<(SD_csd_reg_ptr->r2w_factor);
/*prevent short var n_wr_max overflow*/
if (nwrmax > 0xffff) nwrmax = 0xffff;
SD_card_info.n_wr_max = nwrmax;
/* calculate card capacity = BLOCKNR * BLOCK_LEN */
data = ((SD_csd_reg_ptr->c_size_11_2<<2) |
SD_csd_reg_ptr->c_size_1_0) + 1;
cnt = 1 << (SD_csd_reg_ptr->c_size_mult + 2);
data = data * cnt; /* BLOCKNR */
sdTotalBlockNo = data;
cnt = 1 << (SD_csd_reg_ptr->rd_blk_len); /* BLOCK_LEN */
sdPagePerBlock = cnt/512;
sdEraseSecSize = SD_csd_reg_ptr->sector_size+1;
SD_card_info.capacity = data * cnt; /* in Bytes */
}
/*
Function: Initialize SD related buffers, structure members and
and IO pins.
input:
output:
side-effects:
*/
void SD_init(void)
{
unsigned sclk_high, sclk_low;
dawei(("SD_init()\n"));
SD_GET_SCLK_VAL(sclk_high, sclk_low);
/* initialization */
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<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<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<>4);
SD_xmit_info.wait_nclk = SD_NCR_MAX;
SD_xmit_info.cmd_sent = 0;
SD_xmit_info.retry_cnt = 0;
if (SD_xmit_info.use_data == 2) { /* data read */
/* data destination */
if (SD_xmit_info.cmd == SD_ACMD_SD_STATUS) {
SD_xmit_info.cur_blk_size = 6; /* 64Bytes */
SD_xmit_info.rd_dest_ptr = (uint *)SD_status_ptr;
} else if (SD_xmit_info.cmd == SD_ACMD_SEND_SCR) {
SD_xmit_info.cur_blk_size = 3; /* 8Bytes */
SD_xmit_info.rd_dest_ptr = (uint *)SD_scr_reg_ptr;
}
} else if (!SD_xmit_info.use_data
|| SD_xmit_info.response_expected) {
/* response data destination */
if (SD_xmit_info.response_expected == SD_R2) {
SD_xmit_info.rd_dest_ptr =
(SD_xmit_info.cmd == SD_CMD_SEND_CSD) ?
(uint *)SD_csd_reg_ptr : (uint *)SD_cid_reg_ptr;
} else {
if (SD_xmit_info.response_expected == SD_R3){
SD_xmit_info.rd_dest_ptr = (uint *)SD_ocr_reg_ptr;
} else if (SD_xmit_info.response_expected == SD_R6){
/* R6 is special..*/
SD_xmit_info.rd_dest_ptr = &SD_rdata32;
} else { /* R1 or R1b */
SD_xmit_info.rd_dest_ptr = (uint *)SD_card_status_ptr;
}
}
}
return(1);
}
static int SD_slow_clk_data_out(uchar out_data)
{
int i;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for(i=0; i<8; i++){
if (out_data & 0x80) {
SET_SD_CMD;
} else {
CLEAR_SD_CMD;
}
out_data <<= 1;
CLEAR_SD_CLK;
risc_sleep_a_bit(USEC(2));
SET_SD_CLK;
risc_sleep_a_bit(USEC(2));
}
}
/***********************************************
up to 1 DWORD
************************************************/
static int SD_slow_clk_data_in(int bit_cnt)
{
int data_in = 0, i;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for (i=0; i>24) & 0xff;
*pChar++ = (arg>>16)& 0xff;
*pChar++ = (arg>>8) &0xff;
*pChar++ = arg & 0xff;
sd_crc = SD_calc_crc7(cmd_buf, 5);
for (i=0; i<5; i++)
SD_slow_clk_data_out(cmd_buf[i]);
tmp = (sd_crc<<1) | 1;
/* crc7 + end bit */
SD_slow_clk_data_out(tmp);
SD_CMD_INPUT; /* get ready for response */
if(SD_card_info.type == SD_MMC
&& command == SD_CMD_SEND_REL_ADDR)
sd_timeout = SD_NCR_MAX;
else
sd_timeout = SD_NID_MAX;
for (i = 0; (i < sd_timeout); i++) {
SD_slow_clk_pulse_l2h();
if (SD_CMD_LOW) { /* response start bit */
/* xmit bit */
SD_slow_clk_pulse_l2h();
/* get SD response */
sd_crc = 0;
break;
}
}
if (i >= sd_timeout){
/* timed out..*/
JPRINTF(("clk_res: timed out\n"));
return (-1);
} else {
cnt = 0;
crc_check = 0;
if (command == SD_CMD_ALL_SEND_CID
||command == SD_CMD_SEND_CID ) {
cnt = 3; /* extra data for R2 response */
sd_rdata_ptr = (uint *)SD_cid_reg_ptr;
} else if ((command == SD_ACMD_SD_SEND_OP_COND) ||
(command == SD_CMD_MMC_SEND_OP_COND)) {
sd_rdata_ptr = (uint *)SD_ocr_reg_ptr;
/* R3 */
} else if (command == SD_CMD_SEND_REL_ADDR
&& SD_card_info.type == SD_MEM) {
sd_rdata_ptr = &SD_rdata32;
/* R6 */
crc_check = 1;
} else { /* R1 (SD_CMD_APP_CMD)*/
sd_rdata_ptr = (uint *)SD_card_status_ptr;
crc_check = 1;
}
}
/* clock in cmd and arg (38bits)..save only arg (last 32bits) */
pChar = rcv_buf;
data_in = SD_slow_clk_data_in(6);
*pChar++ = data_in;
rcv_cnt = 1;
rdata_pchar = (char*)sd_rdata_ptr;
for(j=0; j<4; j++){
data_in = SD_slow_clk_data_in(8);
*pChar++ = data_in;
rcv_cnt++;
*rdata_pchar++ = data_in;
}
cnt <<= 2;
while (cnt){
*rdata_pchar++ = SD_slow_clk_data_in(8) ;
cnt--;
if (!cnt) goto sd_exit;
}
/* crc7 + end bit */
data_in = SD_slow_clk_data_in(8) ;
#if CHECK_RECV_CRC
if (!crc_check) {
sd_crc = 0x7f; /* no CRC for R3 response */
}else
sd_crc = SD_calc_crc7(rcv_buf, rcv_cnt);
data_in >>= 1; /* remove end bit */
PRINTF(("Received crc: %x, Computed crc: %x\n", data_in, sd_crc));
if (data_in != sd_crc) {
/* crc error */
CPRINTF(("CRC error in SD_clk_restricted_cmd()\n"));
CPRINTF(("cmd: %d, arg: %\n", command, arg));
CPRINTF(("xmit crc: 0x%x, gen crc: 0x%x\n", data_in, sd_crc));
BREAKPOINT(0);
return (0);
}
#endif
if (command == SD_CMD_SEND_REL_ADDR
&& SD_card_info.type == SD_MEM) {
sd_rdata_ptr = (uint *)SD_card_status_ptr;
*sd_rdata_ptr &= (~0x1fff); /* bit 0-12 */
*sd_rdata_ptr |= (SD_rdata32 & 0x1fff);
SD_card_status_ptr->error =
(SD_rdata32>>13) & 1;
SD_card_status_ptr->illegal_cmd =
(SD_rdata32>>14) & 1;
SD_card_status_ptr->com_crc_error =
(SD_rdata32>>15) & 1;
SD_rca_reg = SD_rdata32>>16; /* new RCA */
}
sd_exit:
/* extra 8 Clocks for SD card post-processing */
for (i = 0; i < 8; i++) {
SD_slow_clk_pulse_l2h();
}
return (1);
}
static void SD_cmd_output(uchar out_cmd)
{
int i;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for (i=0; i<8; i++) {
if (out_cmd &0x80) {
SET_SD_CMD;
} else {
CLEAR_SD_CMD;
}
PULSE_SD_CLK_HL;
out_cmd <<= 1;
}
}
static void SD_1_bit_data_out(uchar out_data)
{
int i;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for (i=0; i<8; i++) {
CLEAR_SD_CLK;
if (out_data & 0x80) {
SET_SD_DAT0;
} else {
CLEAR_SD_DAT0;
}
SET_SD_CLK;
out_data <<= 1;
}
}
static void SD_4_bit_data_out(char *pOutData, int cnt)
{
int i;
char out_data;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for(i= 0; i>4) & 0xf));
SET_SD_CLK;
CLEAR_SD_CLK;
SET_SD_DAT3_0( (out_data&0xf));
SET_SD_CLK;
}
}
/*****************************************************************
up to 1 DWORD
******************************************************************/
static int SD_1_bit_data_in(int bit_cnt)
{
int i, data_in;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
data_in = 0;
for (i=0; i>24)&0xff;
*pChar++ =(arg>>16)&0xff;
*pChar++ =(arg>>8)&0xff;
*pChar = arg & 0xff;
sd_crc[0] = SD_calc_crc7(cmd_buf, 5);
SD_xmit_info.com_state = HOST2SD_CMD;
SD_xmit_info.result = -1; /* need to set to be 0 when succeed,
currently only used in case of Erase */
/*break; save time..let it drop*/
case HOST2SD_CMD:
sd_cnt++; /* for timeout/mode check */
/* command index/argument..8bits at a time */
for(i=0; i<5; i++)
SD_cmd_output(cmd_buf[i]);
SD_xmit_info.com_state = HOST2SD_CRC7;
break;
case HOST2SD_CRC7:
/* send crc7 */
tmp = (sd_crc[0]<<1) | 1; /* crc7 + end bit */
SD_cmd_output(tmp);
CLEAR_SD_CLK;
if (SD_xmit_info.response_expected) {
SD_CMD_INPUT; /* tristate cmd */
if (SD_xmit_info.use_data == 2) {
/* data read */
if (SD_xmit_info.data_width) {
/* all four data lines used */
SD_DAT3_0_INPUT;
} else {
SD_DAT0_INPUT;
}
sd_cmd_info = 0; /* bytes received */
SD_xmit_info.wait_nclk = SD_card_info.n_ac_max;
}
else if(SD_xmit_info.response_expected == SD_R1b){
SD_DAT0_INPUT; /* busy check */
}
sd_rdata_ptr = SD_xmit_info.rd_dest_ptr;
SD_xmit_info.com_state = HOST2SD_WAIT;
} else {
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}
break;
case HOST2SD_WAIT:
/* check 8 cycles at a time */
for (i = 0; SD_xmit_info.wait_nclk; i++) {
SD_LOCK15;
SET_SD_CLK;
if(sd_is_mmc){
CLEAR_SD_CLK;
sd_cmd_high = SD_CMD_HIGH? 1:0;
sd_dat0_high = SD_DAT0_HIGH? 1:0;
}else{
sd_cmd_high = SD_CMD_HIGH? 1:0;
sd_dat0_high = SD_DAT0_HIGH? 1:0;
CLEAR_SD_CLK;
}
if (SD_xmit_info.use_data != 2
&& !SD_xmit_info.response_recv
&& !sd_cmd_high){ /* response start bit */
SD_LOCK15;
SET_SD_CLK;
if(sd_is_mmc){
CLEAR_SD_CLK;
sd_cmd_high = SD_CMD_HIGH? 1:0;
}else{
sd_cmd_high = SD_CMD_HIGH? 1:0;
CLEAR_SD_CLK;
}
/* get SD response */
sd_crc[0] = 0;
sd_mask = 6; /* bit count */
sd_cmd_info = 0; /* clear received bits */
sd_cnt = 0; /* for timeout/mode check */
SD_xmit_info.com_state = SD2HOST_NODATA;
break;
} else if ((SD_xmit_info.use_data==2)
&& !sd_dat0_high) { /* data start bit? */
sd_crc[0] = 0; /* clear crc */
/* current block size (bytes) */
if(SD_xmit_info.cmd == MMC_CMD_READ_UNTIL_STOP)
sd_mask = SD_xmit_info.data_len;
else
sd_mask = 1 << (SD_xmit_info.cur_blk_size);
if(SD_xmit_info.data_width){
SD_xmit_info.com_state = SD2HOST_DATA4;
}
else{
SD_xmit_info.com_state = SD2HOST_DATA1;
}
break;
}
/* btan: After received response, we actually don't need wait n_wr_max clk. *
* 4 clk is ok for my SD. I did not test other SD. If you meet problem in *
* SD writing function, please increase it or let me know. */
else if (SD_xmit_info.use_data != 2 && SD_xmit_info.response_recv
&& sd_cmd_high && SD_xmit_info.wait_nclk > 4) {
SD_xmit_info.wait_nclk = 4;
}
SD_xmit_info.wait_nclk--;
}
if (!SD_xmit_info.wait_nclk) {
#ifdef SD_ENABLE_WRITE
if (SD_xmit_info.use_data == 1
&& SD_xmit_info.response_recv) {
/* prepare to write.. */
/* current block size (bytes) */
sd_cmd_info = 1 << (SD_xmit_info.cur_blk_size);
if (SD_xmit_info.data_width) {
/* write wide bus */
CLEAR_SD_DAT3_0;
SD_xmit_info.com_state = HOST2SD_DATA4;
} else {
CLEAR_SD_DAT0;
SD_xmit_info.com_state = HOST2SD_DATA1;
}
break;
} else
#endif /* SD_ENABLE_WRITE */
{
/* timed out..send again?? */
JPRINTF(("SD res:time out. xmit_len %d, xmit_cnt %d cmd %d\n",
SD_xmit_info.data_len, SD_xmit_info.data_cnt,
SD_xmit_info.cmd));
SD_xmit_info.retry_cnt++;
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}
}
break;
#ifdef SD_ENABLE_WRITE
case HOST2SD_DATA1:
/* write data, one byte at a time */
sd_cmd_info = 1 << (SD_xmit_info.cur_blk_size);
pChar = (char*)SD_xmit_info.wr_src_ptr + SD_xmit_info.data_cnt;
/* crc16 calculation for narrow bus */
sd_crc[0] = SD_calc_crc16((uchar *)pChar,sd_cmd_info);
JPRINTF(("Xmit src %x, len %d\n", pChar, sd_cmd_info));
/* send start bit */
CLEAR_SD_DAT0;
CLEAR_SD_CLK;
SET_SD_CLK;
for(i=0; i>2, sd_crc);
/* send start bit */
CLEAR_SD_DAT3_0;
CLEAR_SD_CLK;
SET_SD_CLK;
SD_4_bit_data_out(pChar, sd_cmd_info);
SD_xmit_info.data_cnt += sd_cmd_info; /* monitor total bytes */
/* set wait timeout cycles..in case multi-block */
SD_xmit_info.wait_nclk = SD_card_info.n_wr_max;
/* finished data "block"..get CRC */
SD_xmit_info.com_state = HOST2SD_CRC16_DATA;
break;
case HOST2SD_CRC16_DATA:
/* send crc16 */
if (SD_xmit_info.data_width){
/* wide bus */
uint filter = 0x8000;
for (i=0; i<16; i++){
CLEAR_SD_CLK;
tmp = 0;
for(j=0; j<4; j++){
tmp |= ( (sd_crc[j]&filter?1:0)<>= 1;
}
/* send end bit */
CLEAR_SD_CLK;
SET_SD_DAT3_0(0xf); /* set dat[3:0] high */
SET_SD_CLK;
SD_DAT0_INPUT;
} else {
/* narrow bus */
SD_1_bit_data_out(sd_crc[0]>>8);
SD_1_bit_data_out(sd_crc[0]&0xff);
/* send end bit */
CLEAR_SD_CLK;
SET_SD_DAT0;
SET_SD_CLK;
SD_DAT0_INPUT;
}
PRINTF(("wait to get crc back \n"));
/* 2 clks..then there should be CRC check start bit */
PULSE_SD_CLK;
PULSE_SD_CLK;
/* crc status: 010: Ok
101: Transimission error
111: Error */
wr_feedback_crc = SD_1_bit_data_in(5);
sd_cnt = 0;
if(wr_feedback_crc != 0x5){
JPRINTF(("crc after xmit CRC16: %x\n",wr_feedback_crc));
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}
else{
SD_xmit_info.wait_nclk = 100*SD_card_info.n_wr_max;
SD_xmit_info.com_state = HOST2SD_CHECK_BUSY;
}
break;
#endif /* SD_ENABLE_WRITE */
case HOST2SD_CHECK_BUSY:
#if 0
/* Reading performance will be impacted */
RISC_sleep_nsec(3000000);
#endif
sd_cnt++; /* for timeout/mode check */
for (i=0; i<8; i++) {
PULSE_SD_CLKZ;
if (SD_DAT0_HIGH) { /* Busy bit */
/* SD not Busy..continue */
/* set next_state..
* - for single-block write, prepare to go idle
* - for multi-block write, write another block
*/
PRINTF((" Not busy ... xmit_cnt %d\n",
SD_xmit_info.data_cnt));
if(SD_xmit_info.cmd == SD_CMD_WRITE_MULTI_BLOCK
&& SD_xmit_info.data_cnt < SD_xmit_info.data_len){
SD_xmit_info.wait_nclk = SD_card_info.n_wr_max;
SD_xmit_info.com_state = HOST2SD_WAIT;
}
else{
SD_xmit_info.com_state = HOST2SD_8CYCLES;
SD_xmit_info.result = 0;
}
/* single block write or erase*/
break;
}
}
/*consider a timeout mechanism for this state */
if (sd_cnt > SD_xmit_info.wait_nclk){
JPRINTF(("Check Bus Busy: Time out\n"));
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}
break;
case SD2HOST_NODATA:
sd_cnt++; /* for timeout/mode check */
/* response: command index/arg..8bits at a time */
data_in = 0;
for (i=0; (i<8) && sd_mask; i++) {
SD_LOCK15;
SET_SD_CLK;
if(sd_is_mmc){
CLEAR_SD_CLK;
sd_cmd_high = SD_CMD_HIGH? 1:0;
}else{
sd_cmd_high = SD_CMD_HIGH? 1:0;
CLEAR_SD_CLK;
}
data_in <<= 1;
data_in |= sd_cmd_high;
sd_mask--; /* bit count remain */
}
if (i==8) { /* one arg byte in..cmd index only has 6 bits */
SD_rdata32 <<= 8;
SD_rdata32 |= data_in;
sd_cmd_info += 8; /* received bits */
if (sd_cmd_info == 32) { /* received 32 bits */
*sd_rdata_ptr++ = SD_rdata32;
/* for 32 bit data we won't get anymore */
sd_cmd_info = 0; /* reset */
}
}
if (!sd_mask) {
if (sd_cnt == 1) {
/* finished cmd..get arg */
if (SD_xmit_info.response_expected == SD_R2) {
sd_mask = 120; /* CID/CSD bit count */
sd_crc[0] = 0; /* CRC7 on arg data only */
} else {
sd_mask = 32; /* bit count */
}
sd_cmd_info = 0; /* clear received bits */
/* no state change..SD_xmit_info.com_state */
} else if ((sd_cnt == 16) &&
(SD_xmit_info.response_expected == SD_R2)) {
/* finished CID/CSD register..next CRC7 */
sd_crc[1] = sd_crc[0]; /* save current crc */
sd_mask = 8; /* internal CRC7 + end bit */
/* no state change..SD_xmit_info.com_state */
} else {
/* finished arg.. */
if (SD_xmit_info.response_expected == SD_R2) {
/* internal crc */
#if SD_CHECK_RECV_CRC
data_in =
(SD_xmit_info.cmd == SD_CMD_SEND_CSD) ?
(uint)SD_csd_reg_ptr->crc :
(uint)SD_cid_reg_ptr->crc;
data_in &= 0x7f; /* 7bit crc */
sd_crc[1] &= 0x7f; /* 7bit crc */
if (data_in != sd_crc[1]) {
/* crc error */
SD_xmit_info.crc7_err_cnt++;
CPRINTF(("R2 CRC7 error in SD_service()\n"));
CPRINTF(("xmit crc: 0x%x, gen crc: 0x%x\n",
data_in, sd_crc[1]));
BREAKPOINT(0);
}
#endif /* SD_CHECK_RECV_CRC */
SD_xmit_info.response_recv = 1;
SD_xmit_info.com_state = HOST2SD_8CYCLES;
} else {
/* R6 response data */
if (SD_xmit_info.response_expected == SD_R6) {
sd_rdata_ptr = (uint *)SD_card_status_ptr;
*sd_rdata_ptr &= (~0x1fff);
*sd_rdata_ptr |= (SD_rdata32 & 0x1fff);
SD_card_status_ptr->error =
(SD_rdata32>>12) & 1;
SD_card_status_ptr->illegal_cmd =
(SD_rdata32>>13) & 1;
SD_card_status_ptr->com_crc_error =
(SD_rdata32>>14) & 1;
SD_rca_reg = SD_rdata32>>16;
}
if (SD_xmit_info.response_expected == SD_R3) {
/* R3 response has no CRC7 */
sd_crc[0] = 0x7f;
}
/* finished arg..get CRC */
SD_xmit_info.com_state = SD2HOST_CRC7_NODATA;
}
}
}
break;
case SD2HOST_DATA1:
/* just get data, 32*sd_maskbits at a time..ignore response */
PRINTF(("SD2HOST_DATA1: xmit_len %d, xmit_data %d sd_mask %d\n",
SD_xmit_info.data_len, SD_xmit_info.data_cnt, sd_mask));
sd_cmd_info = sd_mask;
j = (sd_mask+3)/4;
if(sd_is_mmc){
do{
data_in = 0;
for (i=0; (i<32); i++){
data_in <<= 1;
SD_LOCK15;
SET_SD_CLK;
CLEAR_SD_CLK;
asm("nop"); asm("nop");asm("nop");
data_in |= SD_DAT0;
}
*sd_rdata_ptr++ = data_in;
}while(--j>0);
}else{
do{
data_in = 0;
for (i=0; (i<32); i++){
data_in <<= 1;
SD_LOCK15;
SET_SD_CLK;
data_in |= SD_DAT0;
CLEAR_SD_CLK;
}
*sd_rdata_ptr++ = data_in;
}while(--j>0);
}
PRINTF(("SD_xmit_cmd %d\n", SD_xmit_info.cmd));
if(SD_xmit_info.cmd == SD_CMD_READ_MULTI_BLOCK){
SD_xmit_info.data_cnt += sd_cmd_info;
PRINTF(("SD_xmit_cmd %d\n", SD_xmit_info.cmd));
}
else{
SD_xmit_info.data_cnt = sd_cmd_info;
}
/* set wait timeout cycles..in case multi-block */
SD_xmit_info.wait_nclk = SD_card_info.n_ac_max;
/* finished arg..get CRC */
if(SD_xmit_info.cmd == MMC_CMD_READ_UNTIL_STOP){
SD_xmit_info.com_state = SD_IDLE;
}else{
SD_xmit_info.com_state = SD2HOST_CRC16_DATA;
PRINTF(("go to get CRC16\n"));
}
break;
case SD2HOST_DATA4:
/* just get data, 32bits at a time..ignore response */
sd_cmd_info += sd_mask;
sd_mask >>= 2;
do{
data_in = 0;
for (i=0; (i<8); i++){
SD_LOCK15;
SET_SD_CLK;
data_in <<= 4;
data_in |= SD_DAT3_0;
CLEAR_SD_CLK;
}
*sd_rdata_ptr++ = data_in;
sd_mask--; /* bytes remain */
}while(sd_mask>0);
SD_xmit_info.data_cnt = sd_cmd_info; /* monitor total bytes */
/* set wait timeout cycles..in case multi-block */
SD_xmit_info.wait_nclk = SD_card_info.n_ac_max;
/* finished data block..get CRC */
SD_xmit_info.com_state = SD2HOST_CRC16_DATA;
break;
case SD2HOST_CRC7_NODATA:
/* get crc7 */
data_in = 0;
/* clock in crc7 + end bit */
for (i=0; (i < 8); i++) {
SD_LOCK15;
SET_SD_CLK;
if(sd_is_mmc){
CLEAR_SD_CLK;
sd_cmd_high = SD_CMD_HIGH ?1:0;
}else{
sd_cmd_high = SD_CMD_HIGH ?1:0;
CLEAR_SD_CLK;
}
#if SD_CHECK_RECV_CRC
data_in <<= 1;
data_in |= sd_cmd_high;
#endif
}
SD_xmit_info.response_recv = 1;
if(SD_xmit_info.response_expected == SD_R1b){
if(SD_xmit_info.cmd == SD_CMD_ERASE
&& (SD_card_status_ptr->erase_seq_error
|| SD_card_status_ptr->erase_param)
){
JPRINTF(("Erase error...\n"));
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}else{
SD_xmit_info.wait_nclk = 100*SD_card_info.n_wr_max;
SD_xmit_info.com_state = HOST2SD_CHECK_BUSY;
JPRINTF(("R1b: to check busy state: card_status %x, cmd %d \n",
*(int*)SD_card_status_ptr, SD_xmit_info.cmd));
}
}else{
#ifdef SD_ENABLE_WRITE
if (SD_xmit_info.cmd == SD_CMD_WRITE_BLOCK
||SD_xmit_info.cmd == SD_CMD_WRITE_MULTI_BLOCK ) {
/* data write */
if (SD_xmit_info.data_width) {
SET_SD_DAT3_0(0xf); /* set dat[3:0] high */
} else {
SET_SD_DAT0;
}
SD_xmit_info.wait_nclk = SD_card_info.n_wr_max;
SD_xmit_info.com_state = HOST2SD_WAIT;
SD_xmit_info.data_cnt = 0;
JPRINTF(("Wait to write data, status %x\n",
*(int*)SD_card_status_ptr));
}else
#endif /* SD_ENABLE_WRITE */
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}
break;
case SD2HOST_CRC16_DATA:
/* get crc16 */
data_in = 0;
/* clock in crc16 + end bit */
PRINTF(("SD2HOST_CRC16_DATA:\n"));
for (i=0; (i < 17); i++) {
data_in <<= 1;
SD_LOCK15;
SET_SD_CLK;
if(sd_is_mmc){
CLEAR_SD_CLK;
data_in |= SD_DAT0;
}else{
data_in |= SD_DAT0;
CLEAR_SD_CLK;
}
}
if(data_in &1 == 0)
JPRINTF(("End bit not found.\n"));
/*
* - for single-block read, prepare to go idle
* - for multi-block read, get another block
*/
if (SD_xmit_info.cmd == SD_CMD_READ_MULTI_BLOCK) {
PRINTF(("end of sector, xmit_cnt %d xmit_len %d\n",
SD_xmit_info.data_cnt,SD_xmit_info.data_len));
if(sd_is_mmc
&& SD_xmit_info.data_cnt>= SD_xmit_info.data_len){
SD_xmit_info.com_state = HOST2SD_8CYCLES;
SD_xmit_info.response_recv = 1;
PRINTF(("command->HOST2SD_8CYCLES \n"));
}
else{
SD_xmit_info.com_state = HOST2SD_WAIT;
}
} else {
SD_xmit_info.response_recv = 1; /* prevent resend */
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}
break;
case HOST2SD_8CYCLES:
/* extra 8 Clocks for SD card's post-processing */
for (i = 0; i < 8; i++){
SD_LOCK15;
SET_SD_CLK;
CLEAR_SD_CLK;
}
/* check for next command..or resend */
if (SD_get_next_cmd()){
JPRINTF(("next cmd not empty\n"));
SD_xmit_info.com_state = HOST2SD_START;
} else {
SD_xmit_info.cmd_sent = 1; /* cmd completed */
SD_xmit_info.com_state = SD_IDLE;
}
break;
case SD_IDLE:
default:
break;
}
VCX_service();
}
int SD_get_status(void)
{
int status = 0;
status = SD_send_cmd(SD_CMD_SEND_STATUS, SD_rca_reg<<16, 1);
if(status != 1)
return -1;
else
return (*(int*)SD_card_status_ptr);
}
#ifdef MD_ASYNC_RW
void SD_clear_state()
{
SD_xmit_info.com_state = SD_IDLE;
SD_xmit_info.cmd = SD_CMD_EMPTY;
SD_acmdq.cmd = SD_CMD_EMPTY; /* clear cmd-Q */
return;
}
/* return: 0: not finish; 1: finish; 2:read single finish; *
* 3:write single finish; 4: read multi finish; 5: write multi finish*/
int SD_cmd_service()
{
int ret = 0, status = 1;
if (!SD_card_info.inserted) {
SD_clear_state();
return 1;
}
if (SD_xmit_info.com_state != SD_IDLE) SD_service();
if (SD_xmit_info.com_state == SD_IDLE) {
if (SD_xmit_info.cmd == SD_CMD_READ_SINGLE_BLOCK) {
ret = 2;
}
else if (SD_xmit_info.cmd == SD_CMD_WRITE_BLOCK) {
ret = 3;
}
else if (SD_xmit_info.cmd == SD_CMD_READ_MULTI_BLOCK) {
ret = 4;
}
else if (SD_xmit_info.cmd == SD_CMD_WRITE_MULTI_BLOCK) {
ret = 5;
}
if (SD_xmit_info.cmd == SD_CMD_WRITE_MULTI_BLOCK ||
SD_xmit_info.cmd == SD_CMD_READ_MULTI_BLOCK) {
SD_xmit_info.cmd = SD_CMD_EMPTY;
status = SD_send_cmd(SD_CMD_STOP_TRANSMIT, 0, 0);
}
else {
SD_xmit_info.cmd = SD_CMD_EMPTY;
if (!SD_get_next_cmd() && !ret) ret = 1;
}
}
else if (SD_xmit_info.cmd == SD_CMD_READ_MULTI_BLOCK &&
SD_xmit_info.data_cnt >= SD_xmit_info.data_len && !sd_is_mmc) {
status = SD_send_cmd(SD_CMD_STOP_TRANSMIT, 0, 0);
ret = 4;
}
return ret;
}
#endif /*MD_ASYNC_RW*/
#if NOT_USED
/*
Function:
input:
output:
side-effects:
*/
int SD_get_status(void)
{
uint status = 0;
if (SD_card_info.type > SD_MMC) {
SD_send_acmd(SD_ACMD_SD_STATUS, 0, 1);
}
return (status);
}
/*
Function: SD lock card (password protect)
input:
output:
side-effects:
*/
int SD_lock_card(int action, char *passwd)
{
int status;
/* lock/unlock card */
return (status);
}
/*
Function: SD set password
input:
output:
side-effects:
*/
int SD_set_password(char *passwd)
{
int status;
/* set password */
return (status);
}
/*
Function: SD reset password
input:
output:
side-effects:
*/
int SD_reset_password(char *passwd)
{
int status;
/* reset password w/ and w/o password */
return (status);
}
/*
Function:
input:
output:
side-effects:
*/
int SD_write_data(uint data)
{
int status;
/* send data w/ CRC16 */
return (status);
}
#endif
#endif /* SD_MEMORY */