From: Florent Kermarrec Date: Mon, 18 May 2020 20:49:12 +0000 (+0200) Subject: software: create liblitescard and move sdcard init/test code to it. X-Git-Tag: 24jan2021_ls180~328^2~4 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=403355a8edf41745b7ac301337d53e978b489f42;p=litex.git software: create liblitescard and move sdcard init/test code to it. --- diff --git a/litex/soc/integration/builder.py b/litex/soc/integration/builder.py index 64dca9d6..496903eb 100644 --- a/litex/soc/integration/builder.py +++ b/litex/soc/integration/builder.py @@ -27,6 +27,7 @@ soc_software_packages = [ "libbase", "liblitedram", "libliteeth", + "liblitesdcard", "bios" ] diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index 73d9ed0a..a4c39660 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -11,18 +11,17 @@ CFLAGS += -DTFTP_SERVER_PORT=$(TFTP_SERVER_PORT) endif OBJECTS = isr.o \ - sdcard.o \ - main.o \ boot-helper.o \ boot.o \ helpers.o \ cmd_bios.o \ + cmd_mem.o \ cmd_boot.o \ + cmd_spiflash.o \ cmd_litedram.o \ cmd_liteeth.o \ - cmd_mem.o \ - cmd_litesdcard.o \ - cmd_spiflash.o \ + cmd_litesdcard.o \ + main.o ifneq "$(or $(TERM_NO_COMPLETE),$(TERM_MINI))" "" CFLAGS += -DTERM_NO_COMPLETE @@ -62,7 +61,8 @@ bios.elf: $(BIOS_DIRECTORY)/linker.ld $(OBJECTS) ../libcompiler_rt/libcompiler_rt.a \ ../libbase/libbase-nofloat.a \ ../liblitedram/liblitedram.a \ - ../libliteeth/libliteeth.a + ../libliteeth/libliteeth.a \ + ../liblitesdcard/liblitesdcard.a $(LD) $(LDFLAGS) -T $(BIOS_DIRECTORY)/linker.ld -N -o $@ \ ../libbase/crt0-ctr.o \ $(OBJECTS) \ @@ -70,8 +70,9 @@ bios.elf: $(BIOS_DIRECTORY)/linker.ld $(OBJECTS) -L../libbase \ -L../liblitedram \ -L../libliteeth \ + -L../liblitesdcard \ $(BP_LIBS) \ - -lcompiler_rt -lbase-nofloat -llitedram -lliteeth \ + -lcompiler_rt -lbase-nofloat -llitedram -lliteeth -llitesdcard \ $(BP_FLAGS) ifneq ($(OS),Windows_NT) diff --git a/litex/soc/software/bios/commands/cmd_litedram.c b/litex/soc/software/bios/commands/cmd_litedram.c index dbca4129..0d05b253 100644 --- a/litex/soc/software/bios/commands/cmd_litedram.c +++ b/litex/soc/software/bios/commands/cmd_litedram.c @@ -5,9 +5,10 @@ #include +#include "sdram.h" + #include "../command.h" #include "../helpers.h" -#include "../sdram.h" /** * Command "sdrrow" diff --git a/litex/soc/software/bios/commands/cmd_litesdcard.c b/litex/soc/software/bios/commands/cmd_litesdcard.c index d9545e07..63347667 100644 --- a/litex/soc/software/bios/commands/cmd_litesdcard.c +++ b/litex/soc/software/bios/commands/cmd_litesdcard.c @@ -5,9 +5,10 @@ #include +#include "sdcard.h" + #include "../command.h" #include "../helpers.h" -#include "../sdcard.h" /** * Command "sdclk" diff --git a/litex/soc/software/bios/sdcard.c b/litex/soc/software/bios/sdcard.c deleted file mode 100644 index 274f3cfa..00000000 --- a/litex/soc/software/bios/sdcard.c +++ /dev/null @@ -1,913 +0,0 @@ -// This file is Copyright (c) 2017 Florent Kermarrec -// This file is Copyright (c) 2019 Kees Jongenburger -// This file is Copyright (c) 2018 bunnie -// This file is Copyright (c) 2020 Antmicro -// License: BSD - -#include -#include -#include - -#include -#include -#include -#include - -#include "sdcard.h" - -#ifdef CSR_SDCORE_BASE - -#define SDCARD_DEBUG - -#define CHECK_LOOPS_PRINT_THRESHOLD 1000000 - -#define REPEATED_MSG(cnt, thr, fmt, ...) do { \ - const int _cnt = (cnt); \ - if((_cnt) >= (thr)) { \ - if((_cnt) > (thr)) { \ - printf("\033[1A\033[1G"); \ - } \ - printf(fmt "\033[0m\033[K\n", ## __VA_ARGS__); \ - } \ - } while(0); - -#define BLOCK_SIZE 512 -#define NO_RESPONSE 0xFF - -#define SDCARD_RESPONSE_SIZE 5 -unsigned int sdcard_response[SDCARD_RESPONSE_SIZE]; - -volatile char *SDREAD = (char*)(SDREAD_BASE); -volatile char *SDWRITE = (char*)(SDWRITE_BASE); - -#ifdef CSR_SDCLK_CMD_DATA_ADDR - -/* clocking */ -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)); -} - -#elif CSR_MMCM_DRP_WRITE_ADDR - -static void sdclk_mmcm_write(unsigned int adr, unsigned int data) { - mmcm_drp_adr_write(adr); - mmcm_drp_dat_w_write(data); - mmcm_drp_write_write(1); - while(!mmcm_drp_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); -} - -#else - -void sdclk_set_clk(unsigned int freq) { - printf("Unimplemented!\n"); -} - -#endif - -/* command utils */ - -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(); -} - - -int sdcard_wait_cmd_done(void) { - unsigned check_counter = 0; - unsigned int cmdevt; - while (1) { - cmdevt = sdcore_cmdevt_read(); - REPEATED_MSG(++check_counter, CHECK_LOOPS_PRINT_THRESHOLD, - "\033[36m cmdevt: %08x (check #%d)", - cmdevt, check_counter); - if(check_counter > CHECK_LOOPS_PRINT_THRESHOLD) { - putchar('\n'); - return NO_RESPONSE; //If we reach threshold, and cmdevt didn't return valid status, return NO_RESPONSE - } - if (cmdevt & 0x1) { - if (cmdevt & 0x4) - return SD_TIMEOUT; - else if (cmdevt & 0x8) - return SD_CRCERROR; - return SD_OK; - } - } -} - -int sdcard_wait_data_done(void) { - unsigned check_counter = 0; - unsigned int dataevt; - while (1) { - dataevt = sdcore_dataevt_read(); - REPEATED_MSG(++check_counter, CHECK_LOOPS_PRINT_THRESHOLD, - "\033[36m dataevt: %08x (check #%d)", - dataevt, check_counter); - if(check_counter > CHECK_LOOPS_PRINT_THRESHOLD) { - putchar('\n'); - return NO_RESPONSE; //If we reach threshold, and cmdevt didn't return valid status, return NO_RESPONSE - } - 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 i, j; - int status; - - status = sdcard_wait_cmd_done(); - -#if CONFIG_CSR_DATA_WIDTH == 8 - unsigned int r; - - // LSB is located at RESPONSE_ADDR + (RESPONSE_SIZE - 1) * 4 - int offset; - for(i = 0; i < SDCARD_RESPONSE_SIZE; i++) { - r = 0; - for(j = 0; j < 4; j++) { - // SD card response consists of 17 bytes - // scattered accross 5 32-bit CSRs. - // In a configuration with CONFIG_CSR_DATA_WIDTH == 8 - // this means we need to do 17 32-bit reads - // and group bytes as described below: - // sdcard_response | CSR_SDCORE_RESPONSE_ADDR - // offset | offsets - // ------------------------------------------ - // 0 | [ 0 ] - // 1 | [ 4 8 12 16 ] - // 2 | [ 20 23 28 32 ] - // 3 | [ 36 40 44 48 ] - // 4 | [ 52 56 60 64 ] - // ------------------------------------------ - // | ^ | - // +--- u32 --|--+ - // LS byte - offset = 4 * ((CSR_SDCORE_RESPONSE_SIZE - 1) - j - i * 4); - if(offset >= 0) { - // Read response and move it by 'j' bytes - r |= ((csr_read_simple(CSR_SDCORE_RESPONSE_ADDR + offset) & 0xFF) << (j * 8)); - } - } - sdcard_response[(SDCARD_RESPONSE_SIZE - 1) - i] = r; // NOTE: this is "backwards" but sticking with this because it's compatible with CSR32 - } -#else - volatile unsigned int *buffer = (unsigned int *)CSR_SDCORE_RESPONSE_ADDR; - - for(i = 0; i < SDCARD_RESPONSE_SIZE; i++) { - sdcard_response[i] = buffer[i]; - } -#endif - -#ifdef SDCARD_DEBUG - for(i = 0; i < SDCARD_RESPONSE_SIZE; i++) { - printf("%08x ", sdcard_response[i]); - } - printf("\n"); -#endif - - return status; -} - -/* commands */ -#if CONFIG_CSR_DATA_WIDTH == 8 -#define CSR8_CMD_FIX sdcore_issue_cmd_write(1) -#else -#define CSR8_CMD_FIX -#endif - -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); - CSR8_CMD_FIX; -} - -int sdcard_send_ext_csd(void) { - unsigned int arg; - arg = 0x000001aa; -#ifdef SDCARD_DEBUG - printf("CMD8: SEND_EXT_CSD, arg: 0x%08x\n", arg); -#endif - sdcore_argument_write(arg); - sdcore_command_write((8 << 8) | SDCARD_CTRL_RESPONSE_SHORT); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - return sdcard_wait_response(); -} - -int sdcard_app_send_op_cond(int hcs, int s18r) { - unsigned int arg; - arg = 0x10ff8000; - if (hcs) - arg |= 0x60000000; - if (s18r) - arg |= 0x01000000; -#ifdef SDCARD_DEBUG - printf("ACMD41: APP_SEND_OP_COND, arg: %08x\n", arg); -#endif - sdcore_argument_write(arg); - sdcore_command_write((41 << 8) | SDCARD_CTRL_RESPONSE_SHORT); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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)); - CSR8_CMD_FIX; - sdcard_wait_response(); - 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)); - CSR8_CMD_FIX; - sdcard_wait_response(); - 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); - CSR8_CMD_FIX; - 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(BLOCK_SIZE); - sdcore_blockcount_write(1); - sdcore_command_write((24 << 8) | SDCARD_CTRL_RESPONSE_SHORT | - (SDCARD_CTRL_DATA_TRANSFER_WRITE << 5)); - CSR8_CMD_FIX; - 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(BLOCK_SIZE); - sdcore_blockcount_write(blockcnt); - sdcore_command_write((25 << 8) | SDCARD_CTRL_RESPONSE_SHORT | - (SDCARD_CTRL_DATA_TRANSFER_WRITE << 5)); - CSR8_CMD_FIX; - 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(BLOCK_SIZE); - sdcore_blockcount_write(1); - sdcore_command_write((17 << 8) | SDCARD_CTRL_RESPONSE_SHORT | - (SDCARD_CTRL_DATA_TRANSFER_READ << 5)); - CSR8_CMD_FIX; - 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(BLOCK_SIZE); - sdcore_blockcount_write(blockcnt); - sdcore_command_write((18 << 8) | SDCARD_CTRL_RESPONSE_SHORT | - (SDCARD_CTRL_DATA_TRANSFER_READ << 5)); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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); - CSR8_CMD_FIX; - 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[1], - sdcard_response[2], - sdcard_response[3], - sdcard_response[4], - - (sdcard_response[1] >> 16) & 0xffff, - - sdcard_response[1] & 0xffff, - - (sdcard_response[2] >> 24) & 0xff, - (sdcard_response[2] >> 16) & 0xff, - (sdcard_response[2] >> 8) & 0xff, - (sdcard_response[2] >> 0) & 0xff, - (sdcard_response[3] >> 24) & 0xff - ); - int crc = sdcard_response[4] & 0x000000FF; - int month = (sdcard_response[4] & 0x00000F00) >> 8; - int year = (sdcard_response[4] & 0x000FF000) >> 12; - int psn = ((sdcard_response[4] & 0xFF000000) >> 24) | ((sdcard_response[3] & 0x00FFFFFF) << 8); - printf( "CRC: %02x\n", crc); - printf( "Production date(m/yy): %d/%d\n", month, year); - printf( "PSN: %08x\n", psn); - printf( "OID: %c%c\n", (sdcard_response[1] & 0x00FF0000) >> 16, (sdcard_response[1] & 0x0000FF00) >> 8); -} - -void sdcard_decode_csd(void) { - /* FIXME: only support CSR structure version 2.0 */ - - int size = ((sdcard_response[3] & 0xFFFF0000) >> 16) + ((sdcard_response[2] & 0x000000FF) << 16) + 1; - 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[1], - sdcard_response[2], - sdcard_response[3], - sdcard_response[4], - - (sdcard_response[1] >> 24) & 0xff, - - (1 << ((sdcard_response[2] >> 16) & 0xf)), - - size * BLOCK_SIZE / (1024 * 1024) - ); -} - -/* bist */ - -#ifdef CSR_SDDATAWRITER_BASE -void sdcard_sddatawriter_start(void) { - sddatawriter_reset_write(1); - sddatawriter_start_write(1); -} - -int sdcard_sddatawriter_wait(void) { - unsigned check_counter = 0; - unsigned done = 0; - while(!done) { - done = sddatawriter_done_read(); - REPEATED_MSG(++check_counter, CHECK_LOOPS_PRINT_THRESHOLD, - "\033[36m sddatawriter_done_read: %08x (check #%d)", - done, ++check_counter); - if(check_counter > CHECK_LOOPS_PRINT_THRESHOLD) { - putchar('\n'); - return NO_RESPONSE; //If we reach threshold, and cmdevt didn't return valid status, return NO_RESPONSE - } - } - return 0; -} -#endif - -#ifdef CSR_SDDATAREADER_BASE -void sdcard_sddatareader_start(void) { - sddatareader_reset_write(1); - sddatareader_start_write(1); -} - -int sdcard_sddatareader_wait(void) { - unsigned check_counter = 0; - unsigned done = 0; - while((done & 1) == 0) { - done = sddatareader_done_read(); - REPEATED_MSG(++check_counter, CHECK_LOOPS_PRINT_THRESHOLD, - "\033[36m sddatareader_done_read: %08x (check #%d)", - done, check_counter); - if(check_counter > CHECK_LOOPS_PRINT_THRESHOLD) { - putchar('\n'); - return NO_RESPONSE; //If we reach threshold, and cmdevt didn't return valid status, return NO_RESPONSE - } - } - return 0; -} -#endif - -/* 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(); -#ifdef SDCARD_DEBUG - printf("Accepted voltage: "); - if(sdcard_response[4] & 0x0) - printf("Not defined\n"); - else if(sdcard_response[4] >> 8 & 0x1) - printf("2.7-3.6V\n"); - else if(sdcard_response[4] >> 12 & 0x1) - printf("Reserved\n"); - else if(sdcard_response[4] >> 16 & 0x1) - printf("Reserved\n"); - else - printf("Invalid response\n"); -#endif - - /* 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[4] & 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[4] >> 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(BLOCK_SIZE); - - return 0; -} - -void hexdump(volatile const char *buf, size_t len) -{ - enum { - BYTES_PER_ROW = 16, - BYTES_PER_GROUP = 4, - ADDR_COL_1 = 1, - HEX_COL_1 = ADDR_COL_1 + 7, - CHAR_COL_1 = HEX_COL_1 + 3 * BYTES_PER_ROW - + (BYTES_PER_ROW/BYTES_PER_GROUP) + 1, - }; - - int i; - unsigned char c; - int printable = 0; - unsigned column, hex_column, char_column; - char cstr[] = "."; - - // Erase line - printf("\033[2K"); - - for(i = 0; i < len; ++i) { - c = cstr[0] = buf[i]; - printable = (c >= ' ' && c < 127); - column = i % BYTES_PER_ROW; - hex_column = HEX_COL_1 + 3 * column + (column/BYTES_PER_GROUP); - char_column = CHAR_COL_1 + column + (column/BYTES_PER_GROUP); - - if(column == 0) { - printf("\033[33m%04x\033[0m", i); - } - - printf("\033[%uG""%02x" - "\033[%uG""%s""%s" - "\033[0m%s", - hex_column, c, - char_column, printable ? "\033[40m" : "\033[90m", - printable ? cstr : ".", - (column == BYTES_PER_ROW - 1 || i == len - 1) ? "\n" : ""); - } - printf("\n"); -} - -void sdcard_test_write(unsigned block, const char *data) -{ -#ifdef CSR_SDDATAWRITER_BASE - const char *c = data; - int i; - for(i = 0; i < BLOCK_SIZE; i++) { - SDWRITE[i] = *c; - if(*(++c) == 0) { - c = data; - } - } - - printf("SDWRITE:\n"); - hexdump(SDWRITE, BLOCK_SIZE); - - sdcard_set_block_count(1); - sdcard_sddatawriter_start(); - sdcard_write_single_block(block * BLOCK_SIZE); - sdcard_sddatawriter_wait(); - sdcard_stop_transmission(); -#else - printf("Writer core not present\n"); -#endif -} - -void sdcard_test_read(unsigned block) -{ -#ifdef CSR_SDDATAREADER_BASE - int i; - for(i = 0; i < sizeof(SDREAD); ++i) { - SDREAD[i] = 0; - } - printf("SDREAD (0x%08x) before read:\n", SDREAD); - hexdump(SDREAD, BLOCK_SIZE); - - sdcard_set_block_count(1); - sdcard_sddatareader_start(); - sdcard_read_single_block(block * BLOCK_SIZE); - sdcard_sddatareader_wait(); - - printf("SDREAD (0x%08x) after read:\n", SDREAD); - hexdump(SDREAD, BLOCK_SIZE); -#else - printf("Reader core not present\n"); -#endif -} - -int sdcard_test(unsigned int count) -{ -#if defined(CSR_SDDATAREADER_BASE) && defined(CSR_SDDATAWRITER_BASE) - srand(0); - int i, j, status; - int crcerrors = 0; - int timeouterrors = 0; - int repeat = 0; - - sdcore_datawcrcclear_write(1); - - for(i = 0; i < count; i = repeat ? i : i + 1) { - REPEATED_MSG(i, 0, "\033[96mWriting block %d (%d/%d); crc errors: %d; timeouts: %d; datawcrc: %u", - i, i + 1, count, crcerrors, timeouterrors, sdcore_datawcrcerrors_read()); - if(!repeat) { - for(j = 0; j < BLOCK_SIZE; ++j) { - unsigned number = rand(); - SDWRITE[j] = number & 0xFF; - } - } else { - busy_wait(1); - } - repeat = 0; - - sdcard_set_block_count(1); - sdcard_sddatawriter_start(); - status = sdcard_write_single_block(i * BLOCK_SIZE); - if (status == SD_CRCERROR) { - ++crcerrors; - } else if (status == SD_TIMEOUT) { - ++timeouterrors; - } - if (status != SD_OK) { - REPEATED_MSG(1, 0, "\033[31m Repeating\n"); - repeat = 1; - } - status = sdcard_sddatawriter_wait(); - if (status != 0) { - REPEATED_MSG(1, 0, "\033[31m Repeating\n"); - repeat = 1; - } - sdcard_stop_transmission(); - } - REPEATED_MSG(i, 0, "\033[39;1mWriting crc errors: %d; timeouts: %d; datawcrc: %u", - crcerrors, timeouterrors, sdcore_datawcrcerrors_read()); - - srand(0); - int errors = 0; - int errorsblk = 0; - crcerrors = 0; - timeouterrors = 0; - for(i = 0; i < count; i = repeat ? i : i + 1) { - REPEATED_MSG(i, 0, "\033[96mReading and checking block %d (%d/%d); errors: %d in %d blocks; crc errors: %d; timeouts: %d", - i, i + 1, count, errors, errorsblk, crcerrors, timeouterrors); - - repeat = 0; - sdcard_set_block_count(1); - sdcard_sddatareader_start(); - status = sdcard_read_single_block(i * BLOCK_SIZE); - if (status == SD_CRCERROR) { - ++crcerrors; - } else if (status == SD_TIMEOUT) { - ++timeouterrors; - } - if (status != SD_OK) { - REPEATED_MSG(1, 0, "\033[31m Repeating\n"); - repeat = 1; - continue; - } - status = sdcard_sddatareader_wait(); - if (status != 0) { - REPEATED_MSG(1, 0, "\033[31m Repeating\n"); - repeat = 1; - continue; - } - - int ok = 1; - for(j = 0; j < BLOCK_SIZE; ++j) { - unsigned number = rand(); - - if(SDREAD[j] != (number & 0xFF)) { - ++errors; - ok = 0; - } - } - if(!ok) { - REPEATED_MSG(0, 0, "\033[31m Block check failed\n"); - ++errorsblk; - } - } - REPEATED_MSG(i, 0, "\033[39;1mReading errors: %d in %d blocks; crc errors: %d; timeouts: %d", - errors, errorsblk, crcerrors, timeouterrors); -#else - printf("Reader and/or writer core not present\n"); -#endif - return 0; -} -#endif /* CSR_SDCORE_BASE */ diff --git a/litex/soc/software/bios/sdcard.h b/litex/soc/software/bios/sdcard.h deleted file mode 100644 index 690d85bc..00000000 --- a/litex/soc/software/bios/sdcard.h +++ /dev/null @@ -1,106 +0,0 @@ -// This file is Copyright (c) 2017 Florent Kermarrec -// License: BSD - -#ifndef __SDCARD_H -#define __SDCARD_H - -#include - -#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 */ -void hexdump(volatile const char *buf, size_t len); - -int sdcard_init(void); -void sdcard_test_write(unsigned block, const char *data); -void sdcard_test_read(unsigned block); -void sdcard_sddatawriter_start(void); -void sdcard_sddatareader_start(void); -int sdcard_sddatawriter_wait(void); -int sdcard_sddatareader_wait(void); -int sdcard_test(unsigned int loops); - -#endif /* CSR_SDCORE_BASE */ - -#endif /* __SDCARD_H */ diff --git a/litex/soc/software/common.mak b/litex/soc/software/common.mak index 80891531..1431ad55 100644 --- a/litex/soc/software/common.mak +++ b/litex/soc/software/common.mak @@ -51,7 +51,8 @@ INCLUDES = -I$(SOC_DIRECTORY)/software/include/base \ -I$(BUILDINC_DIRECTORY) \ -I$(CPU_DIRECTORY) \ -I$(SOC_DIRECTORY)/software/liblitedram \ - -I$(SOC_DIRECTORY)/software/libliteeth + -I$(SOC_DIRECTORY)/software/libliteeth \ + -I$(SOC_DIRECTORY)/software/liblitesdcard COMMONFLAGS = $(DEPFLAGS) -Os $(CPUFLAGS) -g3 -fomit-frame-pointer -Wall -fno-builtin -nostdinc $(INCLUDES) CFLAGS = $(COMMONFLAGS) -fexceptions -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes CXXFLAGS = $(COMMONFLAGS) -std=c++11 -I$(SOC_DIRECTORY)/software/include/basec++ -fexceptions -fno-rtti -ffreestanding diff --git a/litex/soc/software/liblitesdcard/Makefile b/litex/soc/software/liblitesdcard/Makefile new file mode 100644 index 00000000..7b0c749a --- /dev/null +++ b/litex/soc/software/liblitesdcard/Makefile @@ -0,0 +1,23 @@ +include ../include/generated/variables.mak +include $(SOC_DIRECTORY)/software/common.mak + +OBJECTS=sdcard.o + +all: liblitesdcard.a + +liblitesdcard.a: $(OBJECTS) + $(AR) crs liblitesdcard.a $(OBJECTS) + +# pull in dependency info for *existing* .o files +-include $(OBJECTS:.o=.d) + +%.o: $(LIBLITESDCARD_DIRECTORY)/%.c + $(compile) + +%.o: %.S + $(assemble) + +.PHONY: all clean + +clean: + $(RM) $(OBJECTS) liblitesdcard.a .*~ *~ diff --git a/litex/soc/software/liblitesdcard/sdcard.c b/litex/soc/software/liblitesdcard/sdcard.c new file mode 100644 index 00000000..274f3cfa --- /dev/null +++ b/litex/soc/software/liblitesdcard/sdcard.c @@ -0,0 +1,913 @@ +// This file is Copyright (c) 2017 Florent Kermarrec +// This file is Copyright (c) 2019 Kees Jongenburger +// This file is Copyright (c) 2018 bunnie +// This file is Copyright (c) 2020 Antmicro +// License: BSD + +#include +#include +#include + +#include +#include +#include +#include + +#include "sdcard.h" + +#ifdef CSR_SDCORE_BASE + +#define SDCARD_DEBUG + +#define CHECK_LOOPS_PRINT_THRESHOLD 1000000 + +#define REPEATED_MSG(cnt, thr, fmt, ...) do { \ + const int _cnt = (cnt); \ + if((_cnt) >= (thr)) { \ + if((_cnt) > (thr)) { \ + printf("\033[1A\033[1G"); \ + } \ + printf(fmt "\033[0m\033[K\n", ## __VA_ARGS__); \ + } \ + } while(0); + +#define BLOCK_SIZE 512 +#define NO_RESPONSE 0xFF + +#define SDCARD_RESPONSE_SIZE 5 +unsigned int sdcard_response[SDCARD_RESPONSE_SIZE]; + +volatile char *SDREAD = (char*)(SDREAD_BASE); +volatile char *SDWRITE = (char*)(SDWRITE_BASE); + +#ifdef CSR_SDCLK_CMD_DATA_ADDR + +/* clocking */ +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)); +} + +#elif CSR_MMCM_DRP_WRITE_ADDR + +static void sdclk_mmcm_write(unsigned int adr, unsigned int data) { + mmcm_drp_adr_write(adr); + mmcm_drp_dat_w_write(data); + mmcm_drp_write_write(1); + while(!mmcm_drp_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); +} + +#else + +void sdclk_set_clk(unsigned int freq) { + printf("Unimplemented!\n"); +} + +#endif + +/* command utils */ + +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(); +} + + +int sdcard_wait_cmd_done(void) { + unsigned check_counter = 0; + unsigned int cmdevt; + while (1) { + cmdevt = sdcore_cmdevt_read(); + REPEATED_MSG(++check_counter, CHECK_LOOPS_PRINT_THRESHOLD, + "\033[36m cmdevt: %08x (check #%d)", + cmdevt, check_counter); + if(check_counter > CHECK_LOOPS_PRINT_THRESHOLD) { + putchar('\n'); + return NO_RESPONSE; //If we reach threshold, and cmdevt didn't return valid status, return NO_RESPONSE + } + if (cmdevt & 0x1) { + if (cmdevt & 0x4) + return SD_TIMEOUT; + else if (cmdevt & 0x8) + return SD_CRCERROR; + return SD_OK; + } + } +} + +int sdcard_wait_data_done(void) { + unsigned check_counter = 0; + unsigned int dataevt; + while (1) { + dataevt = sdcore_dataevt_read(); + REPEATED_MSG(++check_counter, CHECK_LOOPS_PRINT_THRESHOLD, + "\033[36m dataevt: %08x (check #%d)", + dataevt, check_counter); + if(check_counter > CHECK_LOOPS_PRINT_THRESHOLD) { + putchar('\n'); + return NO_RESPONSE; //If we reach threshold, and cmdevt didn't return valid status, return NO_RESPONSE + } + 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 i, j; + int status; + + status = sdcard_wait_cmd_done(); + +#if CONFIG_CSR_DATA_WIDTH == 8 + unsigned int r; + + // LSB is located at RESPONSE_ADDR + (RESPONSE_SIZE - 1) * 4 + int offset; + for(i = 0; i < SDCARD_RESPONSE_SIZE; i++) { + r = 0; + for(j = 0; j < 4; j++) { + // SD card response consists of 17 bytes + // scattered accross 5 32-bit CSRs. + // In a configuration with CONFIG_CSR_DATA_WIDTH == 8 + // this means we need to do 17 32-bit reads + // and group bytes as described below: + // sdcard_response | CSR_SDCORE_RESPONSE_ADDR + // offset | offsets + // ------------------------------------------ + // 0 | [ 0 ] + // 1 | [ 4 8 12 16 ] + // 2 | [ 20 23 28 32 ] + // 3 | [ 36 40 44 48 ] + // 4 | [ 52 56 60 64 ] + // ------------------------------------------ + // | ^ | + // +--- u32 --|--+ + // LS byte + offset = 4 * ((CSR_SDCORE_RESPONSE_SIZE - 1) - j - i * 4); + if(offset >= 0) { + // Read response and move it by 'j' bytes + r |= ((csr_read_simple(CSR_SDCORE_RESPONSE_ADDR + offset) & 0xFF) << (j * 8)); + } + } + sdcard_response[(SDCARD_RESPONSE_SIZE - 1) - i] = r; // NOTE: this is "backwards" but sticking with this because it's compatible with CSR32 + } +#else + volatile unsigned int *buffer = (unsigned int *)CSR_SDCORE_RESPONSE_ADDR; + + for(i = 0; i < SDCARD_RESPONSE_SIZE; i++) { + sdcard_response[i] = buffer[i]; + } +#endif + +#ifdef SDCARD_DEBUG + for(i = 0; i < SDCARD_RESPONSE_SIZE; i++) { + printf("%08x ", sdcard_response[i]); + } + printf("\n"); +#endif + + return status; +} + +/* commands */ +#if CONFIG_CSR_DATA_WIDTH == 8 +#define CSR8_CMD_FIX sdcore_issue_cmd_write(1) +#else +#define CSR8_CMD_FIX +#endif + +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); + CSR8_CMD_FIX; +} + +int sdcard_send_ext_csd(void) { + unsigned int arg; + arg = 0x000001aa; +#ifdef SDCARD_DEBUG + printf("CMD8: SEND_EXT_CSD, arg: 0x%08x\n", arg); +#endif + sdcore_argument_write(arg); + sdcore_command_write((8 << 8) | SDCARD_CTRL_RESPONSE_SHORT); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + return sdcard_wait_response(); +} + +int sdcard_app_send_op_cond(int hcs, int s18r) { + unsigned int arg; + arg = 0x10ff8000; + if (hcs) + arg |= 0x60000000; + if (s18r) + arg |= 0x01000000; +#ifdef SDCARD_DEBUG + printf("ACMD41: APP_SEND_OP_COND, arg: %08x\n", arg); +#endif + sdcore_argument_write(arg); + sdcore_command_write((41 << 8) | SDCARD_CTRL_RESPONSE_SHORT); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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)); + CSR8_CMD_FIX; + sdcard_wait_response(); + 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)); + CSR8_CMD_FIX; + sdcard_wait_response(); + 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); + CSR8_CMD_FIX; + 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(BLOCK_SIZE); + sdcore_blockcount_write(1); + sdcore_command_write((24 << 8) | SDCARD_CTRL_RESPONSE_SHORT | + (SDCARD_CTRL_DATA_TRANSFER_WRITE << 5)); + CSR8_CMD_FIX; + 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(BLOCK_SIZE); + sdcore_blockcount_write(blockcnt); + sdcore_command_write((25 << 8) | SDCARD_CTRL_RESPONSE_SHORT | + (SDCARD_CTRL_DATA_TRANSFER_WRITE << 5)); + CSR8_CMD_FIX; + 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(BLOCK_SIZE); + sdcore_blockcount_write(1); + sdcore_command_write((17 << 8) | SDCARD_CTRL_RESPONSE_SHORT | + (SDCARD_CTRL_DATA_TRANSFER_READ << 5)); + CSR8_CMD_FIX; + 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(BLOCK_SIZE); + sdcore_blockcount_write(blockcnt); + sdcore_command_write((18 << 8) | SDCARD_CTRL_RESPONSE_SHORT | + (SDCARD_CTRL_DATA_TRANSFER_READ << 5)); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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); + CSR8_CMD_FIX; + 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[1], + sdcard_response[2], + sdcard_response[3], + sdcard_response[4], + + (sdcard_response[1] >> 16) & 0xffff, + + sdcard_response[1] & 0xffff, + + (sdcard_response[2] >> 24) & 0xff, + (sdcard_response[2] >> 16) & 0xff, + (sdcard_response[2] >> 8) & 0xff, + (sdcard_response[2] >> 0) & 0xff, + (sdcard_response[3] >> 24) & 0xff + ); + int crc = sdcard_response[4] & 0x000000FF; + int month = (sdcard_response[4] & 0x00000F00) >> 8; + int year = (sdcard_response[4] & 0x000FF000) >> 12; + int psn = ((sdcard_response[4] & 0xFF000000) >> 24) | ((sdcard_response[3] & 0x00FFFFFF) << 8); + printf( "CRC: %02x\n", crc); + printf( "Production date(m/yy): %d/%d\n", month, year); + printf( "PSN: %08x\n", psn); + printf( "OID: %c%c\n", (sdcard_response[1] & 0x00FF0000) >> 16, (sdcard_response[1] & 0x0000FF00) >> 8); +} + +void sdcard_decode_csd(void) { + /* FIXME: only support CSR structure version 2.0 */ + + int size = ((sdcard_response[3] & 0xFFFF0000) >> 16) + ((sdcard_response[2] & 0x000000FF) << 16) + 1; + 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[1], + sdcard_response[2], + sdcard_response[3], + sdcard_response[4], + + (sdcard_response[1] >> 24) & 0xff, + + (1 << ((sdcard_response[2] >> 16) & 0xf)), + + size * BLOCK_SIZE / (1024 * 1024) + ); +} + +/* bist */ + +#ifdef CSR_SDDATAWRITER_BASE +void sdcard_sddatawriter_start(void) { + sddatawriter_reset_write(1); + sddatawriter_start_write(1); +} + +int sdcard_sddatawriter_wait(void) { + unsigned check_counter = 0; + unsigned done = 0; + while(!done) { + done = sddatawriter_done_read(); + REPEATED_MSG(++check_counter, CHECK_LOOPS_PRINT_THRESHOLD, + "\033[36m sddatawriter_done_read: %08x (check #%d)", + done, ++check_counter); + if(check_counter > CHECK_LOOPS_PRINT_THRESHOLD) { + putchar('\n'); + return NO_RESPONSE; //If we reach threshold, and cmdevt didn't return valid status, return NO_RESPONSE + } + } + return 0; +} +#endif + +#ifdef CSR_SDDATAREADER_BASE +void sdcard_sddatareader_start(void) { + sddatareader_reset_write(1); + sddatareader_start_write(1); +} + +int sdcard_sddatareader_wait(void) { + unsigned check_counter = 0; + unsigned done = 0; + while((done & 1) == 0) { + done = sddatareader_done_read(); + REPEATED_MSG(++check_counter, CHECK_LOOPS_PRINT_THRESHOLD, + "\033[36m sddatareader_done_read: %08x (check #%d)", + done, check_counter); + if(check_counter > CHECK_LOOPS_PRINT_THRESHOLD) { + putchar('\n'); + return NO_RESPONSE; //If we reach threshold, and cmdevt didn't return valid status, return NO_RESPONSE + } + } + return 0; +} +#endif + +/* 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(); +#ifdef SDCARD_DEBUG + printf("Accepted voltage: "); + if(sdcard_response[4] & 0x0) + printf("Not defined\n"); + else if(sdcard_response[4] >> 8 & 0x1) + printf("2.7-3.6V\n"); + else if(sdcard_response[4] >> 12 & 0x1) + printf("Reserved\n"); + else if(sdcard_response[4] >> 16 & 0x1) + printf("Reserved\n"); + else + printf("Invalid response\n"); +#endif + + /* 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[4] & 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[4] >> 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(BLOCK_SIZE); + + return 0; +} + +void hexdump(volatile const char *buf, size_t len) +{ + enum { + BYTES_PER_ROW = 16, + BYTES_PER_GROUP = 4, + ADDR_COL_1 = 1, + HEX_COL_1 = ADDR_COL_1 + 7, + CHAR_COL_1 = HEX_COL_1 + 3 * BYTES_PER_ROW + + (BYTES_PER_ROW/BYTES_PER_GROUP) + 1, + }; + + int i; + unsigned char c; + int printable = 0; + unsigned column, hex_column, char_column; + char cstr[] = "."; + + // Erase line + printf("\033[2K"); + + for(i = 0; i < len; ++i) { + c = cstr[0] = buf[i]; + printable = (c >= ' ' && c < 127); + column = i % BYTES_PER_ROW; + hex_column = HEX_COL_1 + 3 * column + (column/BYTES_PER_GROUP); + char_column = CHAR_COL_1 + column + (column/BYTES_PER_GROUP); + + if(column == 0) { + printf("\033[33m%04x\033[0m", i); + } + + printf("\033[%uG""%02x" + "\033[%uG""%s""%s" + "\033[0m%s", + hex_column, c, + char_column, printable ? "\033[40m" : "\033[90m", + printable ? cstr : ".", + (column == BYTES_PER_ROW - 1 || i == len - 1) ? "\n" : ""); + } + printf("\n"); +} + +void sdcard_test_write(unsigned block, const char *data) +{ +#ifdef CSR_SDDATAWRITER_BASE + const char *c = data; + int i; + for(i = 0; i < BLOCK_SIZE; i++) { + SDWRITE[i] = *c; + if(*(++c) == 0) { + c = data; + } + } + + printf("SDWRITE:\n"); + hexdump(SDWRITE, BLOCK_SIZE); + + sdcard_set_block_count(1); + sdcard_sddatawriter_start(); + sdcard_write_single_block(block * BLOCK_SIZE); + sdcard_sddatawriter_wait(); + sdcard_stop_transmission(); +#else + printf("Writer core not present\n"); +#endif +} + +void sdcard_test_read(unsigned block) +{ +#ifdef CSR_SDDATAREADER_BASE + int i; + for(i = 0; i < sizeof(SDREAD); ++i) { + SDREAD[i] = 0; + } + printf("SDREAD (0x%08x) before read:\n", SDREAD); + hexdump(SDREAD, BLOCK_SIZE); + + sdcard_set_block_count(1); + sdcard_sddatareader_start(); + sdcard_read_single_block(block * BLOCK_SIZE); + sdcard_sddatareader_wait(); + + printf("SDREAD (0x%08x) after read:\n", SDREAD); + hexdump(SDREAD, BLOCK_SIZE); +#else + printf("Reader core not present\n"); +#endif +} + +int sdcard_test(unsigned int count) +{ +#if defined(CSR_SDDATAREADER_BASE) && defined(CSR_SDDATAWRITER_BASE) + srand(0); + int i, j, status; + int crcerrors = 0; + int timeouterrors = 0; + int repeat = 0; + + sdcore_datawcrcclear_write(1); + + for(i = 0; i < count; i = repeat ? i : i + 1) { + REPEATED_MSG(i, 0, "\033[96mWriting block %d (%d/%d); crc errors: %d; timeouts: %d; datawcrc: %u", + i, i + 1, count, crcerrors, timeouterrors, sdcore_datawcrcerrors_read()); + if(!repeat) { + for(j = 0; j < BLOCK_SIZE; ++j) { + unsigned number = rand(); + SDWRITE[j] = number & 0xFF; + } + } else { + busy_wait(1); + } + repeat = 0; + + sdcard_set_block_count(1); + sdcard_sddatawriter_start(); + status = sdcard_write_single_block(i * BLOCK_SIZE); + if (status == SD_CRCERROR) { + ++crcerrors; + } else if (status == SD_TIMEOUT) { + ++timeouterrors; + } + if (status != SD_OK) { + REPEATED_MSG(1, 0, "\033[31m Repeating\n"); + repeat = 1; + } + status = sdcard_sddatawriter_wait(); + if (status != 0) { + REPEATED_MSG(1, 0, "\033[31m Repeating\n"); + repeat = 1; + } + sdcard_stop_transmission(); + } + REPEATED_MSG(i, 0, "\033[39;1mWriting crc errors: %d; timeouts: %d; datawcrc: %u", + crcerrors, timeouterrors, sdcore_datawcrcerrors_read()); + + srand(0); + int errors = 0; + int errorsblk = 0; + crcerrors = 0; + timeouterrors = 0; + for(i = 0; i < count; i = repeat ? i : i + 1) { + REPEATED_MSG(i, 0, "\033[96mReading and checking block %d (%d/%d); errors: %d in %d blocks; crc errors: %d; timeouts: %d", + i, i + 1, count, errors, errorsblk, crcerrors, timeouterrors); + + repeat = 0; + sdcard_set_block_count(1); + sdcard_sddatareader_start(); + status = sdcard_read_single_block(i * BLOCK_SIZE); + if (status == SD_CRCERROR) { + ++crcerrors; + } else if (status == SD_TIMEOUT) { + ++timeouterrors; + } + if (status != SD_OK) { + REPEATED_MSG(1, 0, "\033[31m Repeating\n"); + repeat = 1; + continue; + } + status = sdcard_sddatareader_wait(); + if (status != 0) { + REPEATED_MSG(1, 0, "\033[31m Repeating\n"); + repeat = 1; + continue; + } + + int ok = 1; + for(j = 0; j < BLOCK_SIZE; ++j) { + unsigned number = rand(); + + if(SDREAD[j] != (number & 0xFF)) { + ++errors; + ok = 0; + } + } + if(!ok) { + REPEATED_MSG(0, 0, "\033[31m Block check failed\n"); + ++errorsblk; + } + } + REPEATED_MSG(i, 0, "\033[39;1mReading errors: %d in %d blocks; crc errors: %d; timeouts: %d", + errors, errorsblk, crcerrors, timeouterrors); +#else + printf("Reader and/or writer core not present\n"); +#endif + return 0; +} +#endif /* CSR_SDCORE_BASE */ diff --git a/litex/soc/software/liblitesdcard/sdcard.h b/litex/soc/software/liblitesdcard/sdcard.h new file mode 100644 index 00000000..690d85bc --- /dev/null +++ b/litex/soc/software/liblitesdcard/sdcard.h @@ -0,0 +1,106 @@ +// This file is Copyright (c) 2017 Florent Kermarrec +// License: BSD + +#ifndef __SDCARD_H +#define __SDCARD_H + +#include + +#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 */ +void hexdump(volatile const char *buf, size_t len); + +int sdcard_init(void); +void sdcard_test_write(unsigned block, const char *data); +void sdcard_test_read(unsigned block); +void sdcard_sddatawriter_start(void); +void sdcard_sddatareader_start(void); +int sdcard_sddatawriter_wait(void); +int sdcard_sddatareader_wait(void); +int sdcard_test(unsigned int loops); + +#endif /* CSR_SDCORE_BASE */ + +#endif /* __SDCARD_H */