Merge pull request #390 from gsomlo/gls-add-sdcard

Import LiteSDCard support in to LiteX, using nexys4ddr as the initial test target
This commit is contained in:
enjoy-digital 2020-02-20 08:17:54 +01:00 committed by GitHub
commit 8a715f3b12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 827 additions and 14 deletions

View File

@ -19,6 +19,12 @@ from litedram.phy import s7ddrphy
from liteeth.phy.rmii import LiteEthPHYRMII
from liteeth.mac import LiteEthMAC
from litesdcard.phy import SDPHY
from litesdcard.clocker import SDClockerS7
from litesdcard.core import SDCore
from litesdcard.bist import BISTBlockGenerator, BISTBlockChecker
from litex.soc.cores.timer import Timer
# CRG ----------------------------------------------------------------------------------------------
class _CRG(Module):
@ -28,9 +34,12 @@ class _CRG(Module):
self.clock_domains.cd_sys2x_dqs = ClockDomain(reset_less=True)
self.clock_domains.cd_clk200 = ClockDomain()
self.clock_domains.cd_eth = ClockDomain()
self.clock_domains.cd_sdcard = ClockDomain(reset_less=True)
# # #
self.sd_clk_freq = int(100e6)
self.submodules.pll = pll = S7MMCM(speedgrade=-1)
self.comb += pll.reset.eq(~platform.request("cpu_reset"))
pll.register_clkin(platform.request("clk100"), 100e6)
@ -39,6 +48,7 @@ class _CRG(Module):
pll.create_clkout(self.cd_sys2x_dqs, 2*sys_clk_freq, phase=90)
pll.create_clkout(self.cd_clk200, 200e6)
pll.create_clkout(self.cd_eth, 50e6)
pll.create_clkout(self.cd_sdcard, self.sd_clk_freq)
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_clk200)
@ -66,18 +76,12 @@ class BaseSoC(SoCSDRAM):
geom_settings = sdram_module.geom_settings,
timing_settings = sdram_module.timing_settings)
# EthernetSoC --------------------------------------------------------------------------------------
def add_ethernet(self):
mem_map = {
"ethmac": 0xb0000000,
}
mem_map.update(self.mem_map)
class EthernetSoC(BaseSoC):
mem_map = {
"ethmac": 0xb0000000,
}
mem_map.update(BaseSoC.mem_map)
def __init__(self, **kwargs):
BaseSoC.__init__(self, **kwargs)
# Ethernet ---------------------------------------------------------------------------------
# phy
self.submodules.ethphy = LiteEthPHYRMII(
clock_pads = self.platform.request("eth_clocks"),
@ -101,6 +105,33 @@ class EthernetSoC(BaseSoC):
self.ethphy.crg.cd_eth_rx.clk,
self.ethphy.crg.cd_eth_tx.clk)
def add_sdcard(self):
sdcard_pads = self.platform.request("sdcard")
self.comb += sdcard_pads.rst.eq(0)
self.submodules.sdclk = SDClockerS7(clkin=ClockSignal("sdcard"), clkin_freq=self.crg.sd_clk_freq)
self.submodules.sdphy = SDPHY(sdcard_pads, self.platform.device)
self.submodules.sdcore = SDCore(self.sdphy)
self.submodules.sdtimer = Timer()
self.add_csr("sdclk")
self.add_csr("sdphy")
self.add_csr("sdcore")
self.add_csr("sdtimer")
self.submodules.bist_generator = BISTBlockGenerator(random=True)
self.submodules.bist_checker = BISTBlockChecker(random=True)
self.add_csr("bist_generator")
self.add_csr("bist_checker")
self.comb += [
self.sdcore.source.connect(self.bist_checker.sink),
self.bist_generator.source.connect(self.sdcore.sink)
]
self.platform.add_period_constraint(self.sdclk.cd_sd.clk, period_ns(self.crg.sd_clk_freq))
self.platform.add_period_constraint(self.sdclk.cd_sd_fb.clk, period_ns(self.crg.sd_clk_freq))
self.platform.add_false_path_constraints(
self.crg.cd_sys.clk,
self.sdclk.cd_sd.clk,
self.sdclk.cd_sd_fb.clk)
# Build --------------------------------------------------------------------------------------------
def main():
@ -111,10 +142,15 @@ def main():
help="system clock frequency (default=75MHz)")
parser.add_argument("--with-ethernet", action="store_true",
help="enable Ethernet support")
parser.add_argument("--with-sdcard", action="store_true",
help="enable SDCard support")
args = parser.parse_args()
cls = EthernetSoC if args.with_ethernet else BaseSoC
soc = cls(sys_clk_freq=int(float(args.sys_clk_freq)), **soc_sdram_argdict(args))
soc = BaseSoC(sys_clk_freq=int(float(args.sys_clk_freq)), **soc_sdram_argdict(args))
if args.with_ethernet:
soc.add_ethernet()
if args.with_sdcard:
soc.add_sdcard()
builder = Builder(soc, **builder_argdict(args))
builder.build()

View File

@ -10,7 +10,7 @@ ifdef TFTP_SERVER_PORT
CFLAGS += -DTFTP_SERVER_PORT=$(TFTP_SERVER_PORT)
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

View File

@ -40,6 +40,7 @@
#endif
#include "sdram.h"
#include "sdcard.h"
#include "boot.h"
/* General address space functions */
@ -375,6 +376,12 @@ static void help(void)
puts("");
#ifdef CSR_SDRAM_BASE
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
}
@ -459,6 +466,13 @@ static void do_command(char *c)
#endif
else if(strcmp(token, "memtest") == 0) memtest();
#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)
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 */