bios: add litesdcard test routines to boot menu

This is a straightforward import of the sdcard initialization and
testing routines from the LiteSDCard demo example, made available
as mainline LiteX bios boot-prompt commands.

Signed-off-by: Gabriel Somlo <gsomlo@gmail.com>
This commit is contained in:
Gabriel Somlo 2020-01-08 12:49:52 -05:00
parent 7a2e33b817
commit d4d2b7f7c6
4 changed files with 778 additions and 1 deletions

View File

@ -10,7 +10,7 @@ ifdef TFTP_SERVER_PORT
CFLAGS += -DTFTP_SERVER_PORT=$(TFTP_SERVER_PORT) CFLAGS += -DTFTP_SERVER_PORT=$(TFTP_SERVER_PORT)
endif endif
OBJECTS=isr.o sdram.o main.o boot-helper-$(CPU).o boot.o OBJECTS=isr.o sdram.o sdcard.o main.o boot-helper-$(CPU).o boot.o
all: bios.bin all: bios.bin

View File

@ -40,6 +40,7 @@
#endif #endif
#include "sdram.h" #include "sdram.h"
#include "sdcard.h"
#include "boot.h" #include "boot.h"
/* General address space functions */ /* General address space functions */
@ -375,6 +376,12 @@ static void help(void)
puts(""); puts("");
#ifdef CSR_SDRAM_BASE #ifdef CSR_SDRAM_BASE
puts("memtest - run a memory test"); puts("memtest - run a memory test");
#endif
puts("");
#ifdef CSR_SDCORE_BASE
puts("sdclk <freq> - SDCard set clk frequency (Mhz)");
puts("sdinit - SDCard initialization");
puts("sdtest <loops> - SDCard test");
#endif #endif
} }
@ -459,6 +466,13 @@ static void do_command(char *c)
#endif #endif
else if(strcmp(token, "memtest") == 0) memtest(); else if(strcmp(token, "memtest") == 0) memtest();
#endif #endif
#ifdef CSR_SDCORE_BASE
else if(strcmp(token, "sdclk") == 0) sdclk_set_clk(atoi(get_token(&c)));
else if(strcmp(token, "sdinit") == 0) sdcard_init();
else if(strcmp(token, "sdtest") == 0) sdcard_test(atoi(get_token(&c)));
#endif
else if(strcmp(token, "") != 0) else if(strcmp(token, "") != 0)
printf("Command not found\n"); printf("Command not found\n");
} }

View File

@ -0,0 +1,664 @@
// This file is Copyright (c) 2017 Florent Kermarrec <florent@enjoy-digital.fr>
// This file is Copyright (c) 2019 Kees Jongenburger <kees.jongenburger@gmail.com>
// This file is Copyright (c) 2018 bunnie <bunnie@kosagi.com>
// License: BSD
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <generated/csr.h>
#include <generated/mem.h>
#include <hw/flags.h>
#include <system.h>
#include "sdcard.h"
#ifdef CSR_SDCORE_BASE
#define SDCARD_DEBUG
/* clocking */
#ifdef CSR_SDCLK_CMD_DATA_ADDR
static void sdclk_dcm_write(int cmd, int data)
{
int word;
word = (data << 2) | cmd;
sdclk_cmd_data_write(word);
sdclk_send_cmd_data_write(1);
while(sdclk_status_read() & CLKGEN_STATUS_BUSY);
}
/* FIXME: add vco frequency check */
static void sdclk_get_config(unsigned int freq, unsigned int *best_m, unsigned int *best_d)
{
unsigned int ideal_m, ideal_d;
unsigned int bm, bd;
unsigned int m, d;
unsigned int diff_current;
unsigned int diff_tested;
ideal_m = freq;
ideal_d = 5000;
bm = 1;
bd = 0;
for(d=1;d<=256;d++)
for(m=2;m<=256;m++) {
/* common denominator is d*bd*ideal_d */
diff_current = abs(d*ideal_d*bm - d*bd*ideal_m);
diff_tested = abs(bd*ideal_d*m - d*bd*ideal_m);
if(diff_tested < diff_current) {
bm = m;
bd = d;
}
}
*best_m = bm;
*best_d = bd;
}
void sdclk_set_clk(unsigned int freq) {
unsigned int clk_m, clk_d;
sdclk_get_config(100*freq, &clk_m, &clk_d);
sdclk_dcm_write(0x1, clk_d-1);
sdclk_dcm_write(0x3, clk_m-1);
sdclk_send_go_write(1);
while(!(sdclk_status_read() & CLKGEN_STATUS_PROGDONE));
while(!(sdclk_status_read() & CLKGEN_STATUS_LOCKED));
}
#else
static void sdclk_mmcm_write(unsigned int adr, unsigned int data) {
sdclk_mmcm_adr_write(adr);
sdclk_mmcm_dat_w_write(data);
sdclk_mmcm_write_write(1);
while(!sdclk_mmcm_drdy_read());
}
static void sdclk_set_config(unsigned int m, unsigned int d) {
/* clkfbout_mult = m */
if(m%2)
sdclk_mmcm_write(0x14, 0x1000 | ((m/2)<<6) | (m/2 + 1));
else
sdclk_mmcm_write(0x14, 0x1000 | ((m/2)<<6) | m/2);
/* divclk_divide = d */
if (d == 1)
sdclk_mmcm_write(0x16, 0x1000);
else if(d%2)
sdclk_mmcm_write(0x16, ((d/2)<<6) | (d/2 + 1));
else
sdclk_mmcm_write(0x16, ((d/2)<<6) | d/2);
/* clkout0_divide = 10 */
sdclk_mmcm_write(0x8, 0x1000 | (5<<6) | 5);
/* clkout1_divide = 2 */
sdclk_mmcm_write(0xa, 0x1000 | (1<<6) | 1);
}
/* FIXME: add vco frequency check */
static void sdclk_get_config(unsigned int freq, unsigned int *best_m, unsigned int *best_d) {
unsigned int ideal_m, ideal_d;
unsigned int bm, bd;
unsigned int m, d;
unsigned int diff_current;
unsigned int diff_tested;
ideal_m = freq;
ideal_d = 10000;
bm = 1;
bd = 0;
for(d=1;d<=128;d++)
for(m=2;m<=128;m++) {
/* common denominator is d*bd*ideal_d */
diff_current = abs(d*ideal_d*bm - d*bd*ideal_m);
diff_tested = abs(bd*ideal_d*m - d*bd*ideal_m);
if(diff_tested < diff_current) {
bm = m;
bd = d;
}
}
*best_m = bm;
*best_d = bd;
}
void sdclk_set_clk(unsigned int freq) {
unsigned int clk_m, clk_d;
sdclk_get_config(1000*freq, &clk_m, &clk_d);
sdclk_set_config(clk_m, clk_d);
}
#endif
/* command utils */
static void busy_wait(unsigned int ms)
{
timer0_en_write(0);
timer0_reload_write(0);
timer0_load_write(CONFIG_CLOCK_FREQUENCY/1000*ms);
timer0_en_write(1);
timer0_update_value_write(1);
while(timer0_value_read()) timer0_update_value_write(1);
}
static void sdtimer_init(void)
{
sdtimer_en_write(0);
sdtimer_load_write(0xffffffff);
sdtimer_reload_write(0xffffffff);
sdtimer_en_write(1);
}
static unsigned int sdtimer_get(void)
{
sdtimer_update_value_write(1);
return sdtimer_value_read();
}
unsigned int sdcard_response[4];
int sdcard_wait_cmd_done(void) {
unsigned int cmdevt;
while (1) {
cmdevt = sdcore_cmdevt_read();
#ifdef SDCARD_DEBUG
printf("cmdevt: %08x\n", cmdevt);
#endif
if (cmdevt & 0x1) {
if (cmdevt & 0x4) {
#ifdef SDCARD_DEBUG
printf("cmdevt: SD_TIMEOUT\n");
#endif
return SD_TIMEOUT;
}
else if (cmdevt & 0x8) {
#ifdef SDCARD_DEBUG
printf("cmdevt: SD_CRCERROR\n");
return SD_CRCERROR;
#endif
}
return SD_OK;
}
}
}
int sdcard_wait_data_done(void) {
unsigned int dataevt;
while (1) {
dataevt = sdcore_dataevt_read();
#ifdef SDCARD_DEBUG
printf("dataevt: %08x\n", dataevt);
#endif
if (dataevt & 0x1) {
if (dataevt & 0x4)
return SD_TIMEOUT;
else if (dataevt & 0x8)
return SD_CRCERROR;
return SD_OK;
}
}
}
int sdcard_wait_response(void) {
int status = sdcard_wait_cmd_done();
csr_rd_buf_uint32(CSR_SDCORE_RESPONSE_ADDR, sdcard_response, 4);
#ifdef SDCARD_DEBUG
printf("sdcard_response = [%08x, %08x, %08x, %08x];\n",
sdcard_response[0], sdcard_response[1],
sdcard_response[2], sdcard_response[3]);
#endif
return status;
}
/* commands */
void sdcard_go_idle(void) {
#ifdef SDCARD_DEBUG
printf("CMD0: GO_IDLE\n");
#endif
sdcore_argument_write(0x00000000);
sdcore_command_write((0 << 8) | SDCARD_CTRL_RESPONSE_NONE);
}
int sdcard_send_ext_csd(void) {
#ifdef SDCARD_DEBUG
printf("CMD8: SEND_EXT_CSD\n");
#endif
sdcore_argument_write(0x000001aa);
sdcore_command_write((8 << 8) | SDCARD_CTRL_RESPONSE_NONE);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_app_cmd(int rca) {
#ifdef SDCARD_DEBUG
printf("CMD55: APP_CMD\n");
#endif
sdcore_argument_write(rca << 16);
sdcore_command_write((55 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_app_send_op_cond(int hcs, int s18r) {
unsigned int arg;
#ifdef SDCARD_DEBUG
printf("ACMD41: APP_SEND_OP_COND\n");
#endif
arg = 0x10ff8000;
if (hcs)
arg |= 0x60000000;
if (s18r)
arg |= 0x01000000;
sdcore_argument_write(arg);
sdcore_command_write((41 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_all_send_cid(void) {
#ifdef SDCARD_DEBUG
printf("CMD2: ALL_SEND_CID\n");
#endif
sdcore_argument_write(0x00000000);
sdcore_command_write((2 << 8) | SDCARD_CTRL_RESPONSE_LONG);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_set_relative_address(void) {
#ifdef SDCARD_DEBUG
printf("CMD3: SET_RELATIVE_ADDRESS\n");
#endif
sdcore_argument_write(0x00000000);
sdcore_command_write((3 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_send_cid(unsigned int rca) {
#ifdef SDCARD_DEBUG
printf("CMD10: SEND_CID\n");
#endif
sdcore_argument_write(rca << 16);
sdcore_command_write((10 << 8) | SDCARD_CTRL_RESPONSE_LONG);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_send_csd(unsigned int rca) {
#ifdef SDCARD_DEBUG
printf("CMD9: SEND_CSD\n");
#endif
sdcore_argument_write(rca << 16);
sdcore_command_write((9 << 8) | SDCARD_CTRL_RESPONSE_LONG);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_select_card(unsigned int rca) {
#ifdef SDCARD_DEBUG
printf("CMD7: SELECT_CARD\n");
#endif
sdcore_argument_write(rca << 16);
sdcore_command_write((7 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_app_set_bus_width(void) {
#ifdef SDCARD_DEBUG
printf("ACMD6: SET_BUS_WIDTH\n");
#endif
sdcore_argument_write(0x00000002);
sdcore_command_write((6 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_switch(unsigned int mode, unsigned int group, unsigned int value, unsigned int dstaddr) {
unsigned int arg;
#ifdef SDCARD_DEBUG
printf("CMD6: SWITCH_FUNC\n");
#endif
arg = (mode << 31) | 0xffffff;
arg &= ~(0xf << (group * 4));
arg |= value << (group * 4);
sdcore_argument_write(arg);
sdcore_blocksize_write(64);
sdcore_blockcount_write(1);
sdcore_command_write((6 << 8) | SDCARD_CTRL_RESPONSE_SHORT |
(SDCARD_CTRL_DATA_TRANSFER_READ << 5));
busy_wait(1);
sdcard_wait_response();
busy_wait(1);
return sdcard_wait_data_done();
}
int sdcard_app_send_scr(void) {
#ifdef SDCARD_DEBUG
printf("CMD51: APP_SEND_SCR\n");
#endif
sdcore_argument_write(0x00000000);
sdcore_blocksize_write(8);
sdcore_blockcount_write(1);
sdcore_command_write((51 << 8) | SDCARD_CTRL_RESPONSE_SHORT |
(SDCARD_CTRL_DATA_TRANSFER_READ << 5));
busy_wait(1);
sdcard_wait_response();
busy_wait(1);
return sdcard_wait_data_done();
}
int sdcard_app_set_blocklen(unsigned int blocklen) {
#ifdef SDCARD_DEBUG
printf("CMD16: SET_BLOCKLEN\n");
#endif
sdcore_argument_write(blocklen);
sdcore_command_write((16 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_write_single_block(unsigned int blockaddr) {
#ifdef SDCARD_DEBUG
printf("CMD24: WRITE_SINGLE_BLOCK\n");
#endif
int cmd_response = -1;
while (cmd_response != SD_OK) {
sdcore_argument_write(blockaddr);
sdcore_blocksize_write(512);
sdcore_blockcount_write(1);
sdcore_command_write((24 << 8) | SDCARD_CTRL_RESPONSE_SHORT |
(SDCARD_CTRL_DATA_TRANSFER_WRITE << 5));
cmd_response = sdcard_wait_response();
}
return cmd_response;
}
int sdcard_write_multiple_block(unsigned int blockaddr, unsigned int blockcnt) {
#ifdef SDCARD_DEBUG
printf("CMD25: WRITE_MULTIPLE_BLOCK\n");
#endif
int cmd_response = -1;
while (cmd_response != SD_OK) {
sdcore_argument_write(blockaddr);
sdcore_blocksize_write(512);
sdcore_blockcount_write(blockcnt);
sdcore_command_write((25 << 8) | SDCARD_CTRL_RESPONSE_SHORT |
(SDCARD_CTRL_DATA_TRANSFER_WRITE << 5));
cmd_response = sdcard_wait_response();
}
return cmd_response;
}
int sdcard_read_single_block(unsigned int blockaddr) {
#ifdef SDCARD_DEBUG
printf("CMD17: READ_SINGLE_BLOCK\n");
#endif
int cmd_response = -1;
while (cmd_response != SD_OK) {
sdcore_argument_write(blockaddr);
sdcore_blocksize_write(512);
sdcore_blockcount_write(1);
sdcore_command_write((17 << 8) | SDCARD_CTRL_RESPONSE_SHORT |
(SDCARD_CTRL_DATA_TRANSFER_READ << 5));
cmd_response = sdcard_wait_response();
}
return sdcard_wait_data_done();
}
int sdcard_read_multiple_block(unsigned int blockaddr, unsigned int blockcnt) {
#ifdef SDCARD_DEBUG
printf("CMD18: READ_MULTIPLE_BLOCK\n");
#endif
int cmd_response = -1;
while (cmd_response != SD_OK) {
sdcore_argument_write(blockaddr);
sdcore_blocksize_write(512);
sdcore_blockcount_write(blockcnt);
sdcore_command_write((18 << 8) | SDCARD_CTRL_RESPONSE_SHORT |
(SDCARD_CTRL_DATA_TRANSFER_READ << 5));
cmd_response = sdcard_wait_response();
}
return cmd_response;
}
int sdcard_stop_transmission(void) {
#ifdef SDCARD_DEBUG
printf("CMD12: STOP_TRANSMISSION\n");
#endif
sdcore_argument_write(0x0000000);
sdcore_command_write((12 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_send_status(unsigned int rca) {
#ifdef SDCARD_DEBUG
printf("CMD13: SEND_STATUS\n");
#endif
sdcore_argument_write(rca << 16);
sdcore_command_write((13 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
int sdcard_set_block_count(unsigned int blockcnt) {
#ifdef SDCARD_DEBUG
printf("CMD23: SET_BLOCK_COUNT\n");
#endif
sdcore_argument_write(blockcnt);
sdcore_command_write((23 << 8) | SDCARD_CTRL_RESPONSE_SHORT);
busy_wait(1);
return sdcard_wait_response();
}
void sdcard_decode_cid(void) {
printf(
"CID Register: 0x%08x%08x%08x%08x\n"
"Manufacturer ID: 0x%x\n"
"Application ID 0x%x\n"
"Product name: %c%c%c%c%c\n",
sdcard_response[0],
sdcard_response[1],
sdcard_response[2],
sdcard_response[3],
(sdcard_response[0] >> 16) & 0xffff,
sdcard_response[0] & 0xffff,
(sdcard_response[1] >> 24) & 0xff,
(sdcard_response[1] >> 16) & 0xff,
(sdcard_response[1] >> 8) & 0xff,
(sdcard_response[1] >> 0) & 0xff,
(sdcard_response[2] >> 24) & 0xff
);
}
void sdcard_decode_csd(void) {
/* FIXME: only support CSR structure version 2.0 */
printf(
"CSD Register: 0x%x%08x%08x%08x\n"
"Max data transfer rate: %d MB/s\n"
"Max read block length: %d bytes\n"
"Device size: %d GB\n",
sdcard_response[0],
sdcard_response[1],
sdcard_response[2],
sdcard_response[3],
(sdcard_response[1] >> 24) & 0xff,
(1 << ((sdcard_response[1] >> 8) & 0xf)),
((sdcard_response[2] >> 8) & 0x3fffff)*512/(1024*1024)
);
}
/* bist */
void sdcard_bist_generator_start(unsigned int blockcnt) {
bist_generator_reset_write(1);
bist_generator_count_write(blockcnt);
bist_generator_start_write(1);
}
void sdcard_bist_generator_wait(void) {
while((bist_generator_done_read() & 0x1) == 0);
}
void sdcard_bist_checker_start(unsigned int blockcnt) {
bist_checker_reset_write(1);
bist_checker_count_write(blockcnt);
bist_checker_start_write(1);
}
void sdcard_bist_checker_wait(void) {
while((bist_checker_done_read() & 0x1) == 0);
}
/* user */
int sdcard_init(void) {
unsigned short rca;
/* initialize SD driver parameters */
sdcore_cmdtimeout_write(1<<19);
sdcore_datatimeout_write(1<<19);
sdtimer_init();
/* reset card */
sdcard_go_idle();
busy_wait(1);
sdcard_send_ext_csd();
/* wait for card to be ready */
/* FIXME: 1.8v support */
for(;;) {
sdcard_app_cmd(0);
sdcard_app_send_op_cond(1, 0);
if (sdcard_response[3] & 0x80000000) {
break;
}
busy_wait(1);
}
/* send identification */
sdcard_all_send_cid();
#ifdef SDCARD_DEBUG
sdcard_decode_cid();
#endif
/* set relative card address */
sdcard_set_relative_address();
rca = (sdcard_response[3] >> 16) & 0xffff;
/* set cid */
sdcard_send_cid(rca);
#ifdef SDCARD_DEBUG
/* FIXME: add cid decoding (optional) */
#endif
/* set csd */
sdcard_send_csd(rca);
#ifdef SDCARD_DEBUG
sdcard_decode_csd();
#endif
/* select card */
sdcard_select_card(rca);
/* set bus width */
sdcard_app_cmd(rca);
sdcard_app_set_bus_width();
/* switch speed */
sdcard_switch(SD_SWITCH_SWITCH, SD_GROUP_ACCESSMODE, SD_SPEED_SDR104, SRAM_BASE);
/* switch driver strength */
sdcard_switch(SD_SWITCH_SWITCH, SD_GROUP_DRIVERSTRENGTH, SD_DRIVER_STRENGTH_D, SRAM_BASE);
/* send scr */
/* FIXME: add scr decoding (optional) */
sdcard_app_cmd(rca);
sdcard_app_send_scr();
/* set block length */
sdcard_app_set_blocklen(512);
return 0;
}
int sdcard_test(unsigned int loops) {
unsigned int i;
unsigned int length;
unsigned int blocks;
unsigned int start;
unsigned int end;
unsigned int errors = 0;
unsigned long write_speed, read_speed;
sdcore_cmdtimeout_write(1<<19);
sdcore_datatimeout_write(1<<19);
sdtimer_init();
length = 4*1024*1024;
blocks = length/512;
for(i=0; i<loops; i++) {
/* write */
start = sdtimer_get();
sdcard_set_block_count(blocks);
sdcard_bist_generator_start(blocks);
sdcard_write_multiple_block(i, blocks);
sdcard_bist_generator_wait();
sdcard_stop_transmission();
end = sdtimer_get();
write_speed = length*(CONFIG_CLOCK_FREQUENCY/100000)/((start - end)/100000);
/* delay FIXME */
busy_wait(200);
/* read */
start = sdtimer_get();
sdcard_set_block_count(blocks);
sdcard_bist_checker_start(blocks);
sdcard_read_multiple_block(i, blocks);
sdcard_bist_checker_wait();
end = sdtimer_get();
read_speed = length*(CONFIG_CLOCK_FREQUENCY/100000)/((start - end)/100000);
/* errors */
errors = bist_checker_errors_read();
/* infos */
if ((i%8) == 0)
printf("LOOP WRITE_SPEED READ_SPEED ERRORS\n");
printf("%4d %6d MB/s %6d MB/s %6d\n",
i,
write_speed/(1024*1024),
read_speed/(1024*1024),
errors
);
}
return errors;
}
#endif /* CSR_SDCORE_BASE */

View File

@ -0,0 +1,99 @@
// This file is Copyright (c) 2017 Florent Kermarrec <florent@enjoy-digital.fr>
// License: BSD
#ifndef __SDCARD_H
#define __SDCARD_H
#include <generated/csr.h>
#ifdef CSR_SDCORE_BASE
#define SD_OK 0
#define SD_CRCERROR 1
#define SD_TIMEOUT 2
#define SD_WRITEERROR 3
#define SD_SWITCH_CHECK 0
#define SD_SWITCH_SWITCH 1
#define SD_SPEED_SDR12 0
#define SD_SPEED_SDR25 1
#define SD_SPEED_SDR50 2
#define SD_SPEED_SDR104 3
#define SD_SPEED_DDR50 4
#define SD_DRIVER_STRENGTH_B 0
#define SD_DRIVER_STRENGTH_A 1
#define SD_DRIVER_STRENGTH_C 2
#define SD_DRIVER_STRENGTH_D 3
#define SD_GROUP_ACCESSMODE 0
#define SD_GROUP_COMMANDSYSTEM 1
#define SD_GROUP_DRIVERSTRENGTH 2
#define SD_GROUP_POWERLIMIT 3
#define SDCARD_STREAM_STATUS_OK 0b000
#define SDCARD_STREAM_STATUS_TIMEOUT 0b001
#define SDCARD_STREAM_STATUS_DATAACCEPTED 0b010
#define SDCARD_STREAM_STATUS_CRCERROR 0b101
#define SDCARD_STREAM_STATUS_WRITEERROR 0b110
#define SDCARD_CTRL_DATA_TRANSFER_NONE 0
#define SDCARD_CTRL_DATA_TRANSFER_READ 1
#define SDCARD_CTRL_DATA_TRANSFER_WRITE 2
#define SDCARD_CTRL_RESPONSE_NONE 0
#define SDCARD_CTRL_RESPONSE_SHORT 1
#define SDCARD_CTRL_RESPONSE_LONG 2
/* clocking */
void sdclk_set_clk(unsigned int freq);
/* command utils */
int sdcard_wait_cmd_done(void);
int sdcard_wait_data_done(void);
int sdcard_wait_response(void);
/* commands */
void sdcard_go_idle(void);
int sdcard_send_ext_csd(void);
int sdcard_app_cmd(int rca);
int sdcard_app_send_op_cond(int hcc, int s18r);
int sdcard_all_send_cid(void);
int sdcard_set_relative_address(void);
int sdcard_send_cid(unsigned int rca);
void sdcard_decode_cid(void);
int sdcard_send_csd(unsigned int rca);
void sdcard_decode_csd(void);
int sdcard_select_card(unsigned int rca);
int sdcard_app_set_bus_width(void);
int sdcard_switch(unsigned int mode, unsigned int group, unsigned int value, unsigned int dstaddr);
int sdcard_app_send_scr(void);
int sdcard_app_set_blocklen(unsigned int blocklen);
int sdcard_write_single_block(unsigned int blockaddr);
int sdcard_write_multiple_block(unsigned int blockaddr, unsigned int blockcnt);
int sdcard_read_single_block(unsigned int blockaddr);
int sdcard_read_multiple_block(unsigned int blockaddr, unsigned int blockcnt);
int sdcard_stop_transmission(void);
int sdcard_send_status(unsigned int rca);
int sdcard_set_block_count(unsigned int blockcnt);
/* bist */
void sdcard_bist_generator_start(unsigned int blockcnt);
void sdcard_bist_generator_wait(void);
void sdcard_bist_checker_start(unsigned int blockcnt);
void sdcard_bist_checker_wait(void);
/* user */
int sdcard_init(void);
int sdcard_test(unsigned int loops);
#endif /* CSR_SDCORE_BASE */
#endif /* __SDCARD_H */