From 7d141258bea55e08aa5d156e5c9beb8ebcd0643c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 5 Jun 2020 09:07:19 +0200 Subject: [PATCH] software/liblitesdcard/spisdcard: simplify/rewrite for consistency with the others parts of the project. - Improve code readability, remove un-needed or duplicate comments. - Only use a spi_xfer function for both write/read. - Set the SDCard to low clk freq before init and increase it when initialized. --- litex/soc/software/bios/boot.c | 54 ++- litex/soc/software/liblitesdcard/fat16.c | 37 +- litex/soc/software/liblitesdcard/fat16.h | 4 +- litex/soc/software/liblitesdcard/sdcard.c | 9 +- litex/soc/software/liblitesdcard/sdcard.h | 2 +- litex/soc/software/liblitesdcard/spisdcard.c | 471 +++++++++---------- litex/soc/software/liblitesdcard/spisdcard.h | 11 +- 7 files changed, 267 insertions(+), 321 deletions(-) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index 5b224968e..f344bb1ae 100644 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -538,37 +538,43 @@ void romboot(void) void sdcardboot(void) { - printf("Booting from SDCard...\n"); - #ifdef CSR_SPISDCARD_BASE - printf("Initializing SDCard in SPI-Mode...\n"); - if(spi_sdcard_goidle() == 0) { - printf("SD Card Timeout\n"); - return; - } - #endif - #ifdef CSR_SDCORE_BASE - printf("Initializing SDCard in SD-Mode...\n"); - sdcard_init(); // FIXME : check returned value - #endif - - if(sdcard_readMBR() == 0) { - printf("SD Card MBR Timeout\n"); - return; - } - unsigned int result; + printf("Booting from SDCard...\n"); + + /* Initialize SDCard */ +#ifdef CSR_SPISDCARD_BASE + printf("Initializing SDCard in SPI-Mode...\n"); + result = spisdcard_init(); +#endif +#ifdef CSR_SDCORE_BASE + printf("Initializing SDCard in SD-Mode...\n"); + result = sdcard_init(); +#endif + if (result == 0) { + printf("SDCard initialization failed.\n"); + return; + } + + /* Read MBR */ + result = fat16_read_mbr(); + if (result == 0) { + printf("SDCard MBR read failed.\n"); + return; + } + + /* Copy files to RAM */ #if defined(CONFIG_CPU_TYPE_VEXRISCV) && defined(CONFIG_CPU_VARIANT_LINUX) - result = sdcard_readFile("IMAGE", "", MAIN_RAM_BASE + KERNEL_IMAGE_RAM_OFFSET); + result = fat16_read_file("IMAGE", "", MAIN_RAM_BASE + KERNEL_IMAGE_RAM_OFFSET); if(result) - result &= sdcard_readFile("ROOTFS~1", "CPI", MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET); + result &= fat16_read_file("ROOTFS~1", "CPI", MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET); if(result) - result &= sdcard_readFile("RV32", "DTB", MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET); + result &= fat16_read_file("RV32", "DTB", MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET); if(result) - result &= sdcard_readFile("EMULATOR", "BIN", MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); + result &= fat16_read_file("EMULATOR", "BIN", MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); if(result) { boot(0, 0, 0, MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); @@ -576,10 +582,10 @@ void sdcardboot(void) } #endif - result = sdcard_readFile("BOOT", "BIN", MAIN_RAM_BASE); + result = fat16_read_file("BOOT", "BIN", MAIN_RAM_BASE); if(result) boot(0, 0, 0, MAIN_RAM_BASE); else - printf("SD Card SPI boot failed\n"); + printf("SDCard boot failed\n"); } #endif diff --git a/litex/soc/software/liblitesdcard/fat16.c b/litex/soc/software/liblitesdcard/fat16.c index dea422421..362543806 100644 --- a/litex/soc/software/liblitesdcard/fat16.c +++ b/litex/soc/software/liblitesdcard/fat16.c @@ -24,6 +24,14 @@ #if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE) +#if defined(CSR_SPISDCARD_BASE) +#define read_block spisdcard_read_block +#endif + +#if defined(CSR_SDCORE_BASE) +#define read_block sdcard_read_block +#endif + // FAT16 Specific code starts here // Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ @@ -102,13 +110,13 @@ uint8_t sdCardSector[512]; // Return 0 success, 1 failure // // Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ -uint8_t sdcard_readMBR(void) +uint8_t fat16_read_mbr(void) { int i, n; // Read Sector 0x00000000 printf("Reading MBR\n"); - if( readSector(0x00000000, sdCardSector)==SUCCESS ) { + if( read_block(0x00000000, sdCardSector)==SUCCESS ) { // Copy Partition 1 Entry from byte 0x1be // FIXME should check 0x55 0xaa at end of sector memcpy(&sdCardPartition, &sdCardSector[0x1be], sizeof(PartitionTable)); @@ -135,7 +143,7 @@ uint8_t sdcard_readMBR(void) // Read Parition 1 Boot Sector - Found from Partion Table printf("\nRead FAT16 Boot Sector\n"); - if( readSector(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) { + if( read_block(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) { memcpy(&sdCardFatBootSector, &sdCardSector, sizeof(Fat16BootSector)); } else { @@ -181,19 +189,6 @@ uint8_t sdcard_readMBR(void) return FAILURE; } -#ifdef USE_SPISCARD_RECLOCKING - // Reclock the card - // Calculate 16MHz as an integer divider from the CONFIG_CLOCK_FREQUENCY - // Add 1 as will be rounded down - // Always ensure divider is at least 2 - half the processor speed - int divider; - divider = (int)(CONFIG_CLOCK_FREQUENCY/(16e6)) + 1; - if( divider<2 ) - divider=2; - printf("Reclocking from %dKHz to %dKHz\n\n", CONFIG_CLOCK_FREQUENCY/(int)spisdcard_clk_divider_read()/1000, CONFIG_CLOCK_FREQUENCY/divider/1000); - spisdcard_clk_divider_write(divider); -#endif - // Read in FAT16 File Allocation Table, array of 16bit unsinged integers // Calculate Storage from TOP of MAIN RAM sdCardFatTable = (uint16_t *)(MAIN_RAM_BASE+MAIN_RAM_SIZE-sdCardFatBootSector.sector_size*sdCardFatBootSector.fat_size_sectors); @@ -202,7 +197,7 @@ uint8_t sdcard_readMBR(void) // Calculate Start of FAT16 File Allocation Table (start of partition plus reserved sectors) fatSectorStart=sdCardPartition.start_sector+sdCardFatBootSector.reserved_sectors; for(n=0; nsdCardFatBootSector.sector_size) { - if( readSector(clusterSectorStart+sector,(uint8_t *)address) == FAILURE ) { + if( read_block(clusterSectorStart+sector,(uint8_t *)address) == FAILURE ) { printf("\nRead Error\n"); return FAILURE; } bytesRemaining=bytesRemaining-sdCardFatBootSector.sector_size; address=address+sdCardFatBootSector.sector_size; } else { - if( readSector(clusterSectorStart+sector,sdCardSector) == FAILURE ) { + if( read_block(clusterSectorStart+sector,sdCardSector) == FAILURE ) { printf("\nRead Error\n"); return FAILURE; } diff --git a/litex/soc/software/liblitesdcard/fat16.h b/litex/soc/software/liblitesdcard/fat16.h index a207cbf86..4d7d34480 100644 --- a/litex/soc/software/liblitesdcard/fat16.h +++ b/litex/soc/software/liblitesdcard/fat16.h @@ -4,7 +4,7 @@ #ifndef __FAT16_H #define __FAT16_H -uint8_t sdcard_readMBR(void); -uint8_t sdcard_readFile(char *, char *, unsigned long); +uint8_t fat16_read_mbr(void); +uint8_t fat16_read_file(char *, char *, unsigned long); #endif /* __FAT16_H */ diff --git a/litex/soc/software/liblitesdcard/sdcard.c b/litex/soc/software/liblitesdcard/sdcard.c index 376c9df30..fac22e893 100644 --- a/litex/soc/software/liblitesdcard/sdcard.c +++ b/litex/soc/software/liblitesdcard/sdcard.c @@ -622,7 +622,7 @@ int sdcard_init(void) { /* set block length */ sdcard_app_set_blocklen(SD_BLOCK_SIZE); - return 0; + return 1; } extern void dump_bytes(unsigned int *ptr, int count, unsigned long addr); @@ -713,15 +713,14 @@ int sdcard_test(unsigned int blocks) return 0; } -uint8_t readSector(uint32_t sectorNumber, uint8_t *storage) -{ +uint8_t sdcard_read_block(uint32_t addr, uint8_t *buf) { int n; // FIXME: handle errors, avoid recopy. - sdcard_read(sectorNumber, 1); + sdcard_read(addr, 1); for(n=0; n +// This file is Copyright (c) 2020 Florent Kermarrec // License: BSD // -// SD CARD bitbanging code for loading files from a FAT16 forrmatted partition into memory -// -// Code is known to work on a de10nano with MiSTer SDRAM and IO Boards - IO Board has a secondary SD CARD interface connected to GPIO pins -// SPI signals CLK, CS and MOSI are configured as GPIO output pins, and MISO is configued as GPIO input pins -// -// Protocol details developed from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ -// -// FAT16 details developed from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ and https://codeandlife.com/2012/04/07/simple-fat-and-sd-tutorial-part-2/ +// SDCard SPI-Mode support for LiteX's SPIMaster. -// Import LiteX SoC details that are generated each time the SoC is compiled for the FPGA -// csr defines the SPI Control registers -// soc defines the clock CONFIG_CLOCK_FREQUENCY (50MHz for the VexRiscV processor on the MiSTer FPGA -// mem defines the addresses for the SDRAM MAIN_RAM_BASE and MAIN_RAM_SIZE -#include -#include -#include - -#include #include #include -#include #include + +#include +#include #include -#ifdef CSR_SPISDCARD_BASE -// Import prototypes for the functions #include "spisdcard.h" -// SPI -// cs line - high to indicate DESELECT -// - low to indicate SELECT -#define CS_HIGH 0x00 -#define CS_LOW 0x01 +#ifdef CSR_SPISDCARD_BASE -// control register values -// onebyte to indicate 1 byte being transferred -// spi_start to indicate START of transfer -// spi_done to indicate transfer DONE -#define ONEBYTE 0x0800 -#define SPI_START 0x01 -#define SPI_DONE 0x01 +/* SPI Master flags */ -// Return values -#define SUCCESS 0x01 -#define FAILURE 0x00 +#define SPI_CS_HIGH (0 << 0) +#define SPI_CS_LOW (1 << 0) +#define SPI_START (1 << 0) +#define SPI_DONE (1 << 0) +#define SPI_LENGTH (1 << 8) -// spi_write_byte -// Send a BYTE (8bits) to the SD CARD -// Seqeunce -// Set MOSI -// Set START bit and LENGTH=8 -// Await DONE -// -// No return values -// -// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands" -void spi_write_byte(uint8_t char_to_send); -void spi_write_byte(uint8_t char_to_send) -{ - // Place data into MOSI register - // Pulse the START bit and set LENGTH=8 - spisdcard_mosi_write(char_to_send); - spisdcard_control_write(ONEBYTE | SPI_START); +/* SPI Master low-level functions */ - // Wait for DONE - while( (spisdcard_status_read() != SPI_DONE)) {} - - // Signal end of transfer - spisdcard_control_write( 0x00 ); +static void spi_set_clk_freq(uint32_t clk_freq) { + uint32_t divider; + divider = CONFIG_CLOCK_FREQUENCY/clk_freq + 1; + printf("divider: %d\n", divider); + if (divider >= 65535) /* 16-bit hardware divider */ + divider = 65535; + if (divider <= 2) /* At least half CPU speed */ + divider = 2; + printf("Setting SDCard clk freq to "); + if (clk_freq > 1000000) + printf("%d MHz\n", (CONFIG_CLOCK_FREQUENCY/divider)/1000000); + else + printf("%d KHz\n", (CONFIG_CLOCK_FREQUENCY/divider)/1000); + spisdcard_clk_divider_write(divider); } - -// spi_read_rbyte -// Read a command response from the SD CARD - Equivalent to and R1 response or first byte of an R7 response -// Sequence -// Read MISO -// If MSB != 0 then send dsummy byte and re-read MISO -// -// Return value is the response from the SD CARD -// If the MSB is not 0, this would represent an ERROR -// Calling function to determine if the correct response has been received -// -// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands" -uint8_t spi_read_rbyte(void); -uint8_t spi_read_rbyte(void) -{ - int timeout=32; - uint8_t r=0; - - // Check if MISO is 0x0xxxxxxx as MSB=0 indicates valid response - r = spisdcard_miso_read(); - while( ((r&0x80)!=0) && timeout>0) { - spisdcard_mosi_write( 0xff ); - spisdcard_control_write(ONEBYTE | SPI_START); - while( (spisdcard_status_read() != SPI_DONE)) {} - r = spisdcard_miso_read(); - spisdcard_control_write( 0x00 ); - timeout--; - } - -// printf("Done\n"); - return r; +static uint8_t spi_xfer(uint8_t byte) { + /* Write byte on MOSI */ + spisdcard_mosi_write(byte); + /* Initiate SPI Xfer */ + spisdcard_control_write(8*SPI_LENGTH | SPI_START); + /* Wait SPI Xfer to be done */ + while(spisdcard_status_read() != SPI_DONE); + /* Read MISO and return it */ + return spisdcard_miso_read(); } -// spi_read_byte -// Sequence -// Send dummy byte -// Read MISO -// -// Read subsequenct bytes from the SD CARD - MSB first -// NOTE different from the spi_read_rbyte as no need to await an intial 0 bit as card is already responsing -// Used to read additional response bytes, or data bytes from the SD CARD -// -// Return value is the byte read -// NOTE no error status as assumed bytes are read via CLK pulses -// -// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands" -uint8_t spi_read_byte(void); -uint8_t spi_read_byte(void) -{ - uint8_t r=0; +/* SPI SDCard functions */ - spi_write_byte( 0xff ); - r = spisdcard_miso_read(); +static uint8_t spisdcard_wait_response(void) { + uint8_t timeout; + uint8_t response; - return r; -} - -// SETSPIMODE -// Signal the SD CARD to switch to SPI mode -// Pulse the CLK line HIGH/LOW repeatedly with MOSI and CS_N HIGH -// Drop CS_N LOW and pulse the CLK -// Check MISO for HIGH -// Return 0 success, 1 failure -// -// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Initializing the SD Card" -uint8_t spi_setspimode(void); -uint8_t spi_setspimode(void) -{ - uint32_t r; - int i, timeout=32; - - // Initialise SPI mode - // set CS to HIGH - // Send pulses - do { - // set CS HIGH and send pulses - spisdcard_cs_write(CS_HIGH); - for (i=0; i<10; i++) { - spi_write_byte( 0xff ); - } - - // set CS LOW and send pulses - spisdcard_cs_write(CS_LOW); - r = spi_read_rbyte(); - - timeout--; - } while ( (timeout>0) && (r==0) ); - - if(timeout==0) return FAILURE; - - return SUCCESS; -} - -// SPI_SDCARD_GOIDLE -// Function exposed to BIOS to initialise SPI mode -// -// Sequence -// Set 100KHz timer mode -// Send CLK pulses to set SD CARD to SPI mode -// Send CMD0 - Software RESET - force SD CARD IDLE -// Send CMD8 - Check SD CARD type -// Send CMD55+ACMD41 - Force SD CARD READY -// Send CMD58 - Read SD CARD OCR (status register) -// Send CMD16 - Set SD CARD block size to 512 - Sector Size for the SD CARD -// NOTE - Each command is prefixed with a dummy set of CLK pulses to prepare SD CARD to receive a command -// Return 0 success, 1 failure -// -// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Initializing the SD Card" -uint8_t spi_sdcard_goidle(void) -{ - uint8_t r; // Response from SD CARD - int i, timeout; // TIMEOUT loop to send CMD55+ACMD41 repeatedly - - r = spi_setspimode(); // Set SD CARD to SPI mode - if( r != 0x01 ) return FAILURE; - - // CMD0 - Software reset - SD CARD IDLE - // Command Sequence is DUMMY=0xff CMD0=0x40 0x00 0x00 0x00 0x00 CRC=0x95 - // Expected R1 response is 0x01 indicating SD CARD is IDLE - spi_write_byte( 0xff ); spi_write_byte( 0x40 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x95 ); - r = spi_read_rbyte(); - if(r!=0x01) return FAILURE; - - // CMD8 - Check SD CARD type - // Command sequence is DUMMY=0xff CMD8=0x48 0x00 0x00 0x01 0xaa CRC=0x87 - // Expected R7 response is 0x01 followed by 0x00 0x00 0x01 0xaa (these trailing 4 bytes not currently checked) - spi_write_byte( 0xff ); spi_write_byte( 0x48 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x01 ); spi_write_byte( 0xaa ); spi_write_byte( 0x87 ); - r = spi_read_rbyte(); - if(r!=0x01) return FAILURE; - // Receive the trailing 4 bytes for R7 response - FIXME should check for 0x00 0x00 0x01 0xaa - for(i=0; i<4; i++) - r=spi_read_byte(); - - // CMD55+ACMD41 - Force SD CARD READY - prepare card for reading/writing - // Command sequence is CMD55 followed by ACMD41 - // Send commands repeatedly until SD CARD indicates READY 0x00 - // CMD55 Sequence is DUMMY=0xff CMD55=0x77 0x00 0x00 0x00 0x00 CRC=0x00 - // ACMD41 Sequence is DUMMY=0xff ACMD41=0x69 0x40 0x00 0x00 0x00 CRC=0x00 - // Expected R1 response is 0x00 indicating SD CARD is READY - timeout=32; + timeout = 32; + /* Do SPI Xfers on SDCard until MISO MSB's is 0 (valid response) or timeout is expired */ do { - spi_write_byte( 0xff ); spi_write_byte( 0x77 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); - r = spi_read_rbyte(); - - spi_write_byte( 0xff ); spi_write_byte( 0x69 ); spi_write_byte( 0x40 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); - r = spi_read_rbyte(); + response = spi_xfer(0xff); timeout--; - busy_wait(20); - } while ((r != 0x00) && (timeout>0)); - if(r!=0x00) return FAILURE; - - // CMD58 - Read SD CARD OCR (status register) - // FIXME - Find details on expected response from CMD58 to allow accurate checking of SD CARD R3 response - // Command sequence is DUMMY=0xff CMD58=0x7a 0x00 0x00 0x01 0xaa CRC=0xff - // Expected R3 response is 0x00 OR 0x01 followed by 4 (unchecked) trailing bytes - spi_write_byte( 0xff ); spi_write_byte( 0x7a ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0xff ); - r = spi_read_rbyte(); - if(r>0x01) return FAILURE; - // // Receive the trailing 4 bytes for R3 response - for(i=0; i<4; i++) - r=spi_read_byte(); - - // CMD16 - Set SD CARD block size to 512 - Sector Size for the SD CARD - // Command Sequence is DUMMY=0xff CMD16=0x50 (512 as unsigned 32bit = 0x00000200) 0x00 0x00 0x02 0x00 CRC=0xff - // Expected R1 response is 0x00 indicating SD CARD is READY - spi_write_byte( 0xff ); spi_write_byte( 0x50 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x02 ); spi_write_byte( 0x00 ); spi_write_byte( 0xff ); - r=spi_read_rbyte(); - if(r!=0x00) return FAILURE; - - return SUCCESS; + } while(((response & 0x80) !=0) && timeout > 0); + return response; } -// READSECTOR -// Read a 512 byte sector from the SD CARD -// Given SECTORNUMBER and memory STORAGE -// -// Sequence -// Send CMD17 - Read Block -// Command Sequence is DUMMY=0xff CMD17=0x51 SECTORNUMBER (32bit UNSIGNED as bits 32-25,24-17, 16-9, 8-1) CRC=0xff -// Wait for SD CARD to send 0x00 indicating SD CARD is processing -// Wait for SD CARD to send 0xfe indicating SD CARD BLOCK START -// Read 512 bytes -// Read 8 DUMMY bytes -// Return 0 success, 1 failure -// -// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Read/Write SD Card" -uint8_t readSector(uint32_t sectorNumber, uint8_t *storage); -uint8_t readSector(uint32_t sectorNumber, uint8_t *storage) -{ - int n, timeout; // Number of bytes loop, timeout loop awaiting response bytes - uint8_t r; // Response bytes from SD CARD +static uint8_t spisdcard_set_mode(void) { + uint8_t timeout; + uint8_t response; - // CMD17 - Read Block - // Command Sequence is DUMMY=0xff CMD17=0x51 SECTORNUMBER (32bit UNSIGNED as bits 32-25,24-17, 16-9, 8-1) CRC=0xff - // Expected R1 response is 0x00 indicating SD CARD is processing - spi_write_byte( 0xff ); spi_write_byte( 0x51 ); spi_write_byte( (sectorNumber>>24)&0xff ); spi_write_byte( (sectorNumber>>16)&0xff ); spi_write_byte( (sectorNumber>>8)&0xff ); spi_write_byte( (sectorNumber)&0xff ); spi_write_byte( 0xff ); - r=spi_read_rbyte(); - if( r!=0x00 ) return FAILURE; + timeout = 32; + do { + int i; + /* Set CS and send 80 clock pulses to set the SDCard in SPI Mode */ + spisdcard_cs_write(SPI_CS_HIGH); + for (i=0; i<10; i++) + spi_xfer(0xff); + /* Clear CS and read response, if 0 the SDCard has been initialized to SPI Mode */ + spisdcard_cs_write(SPI_CS_LOW); + response = spisdcard_wait_response(); - // Await 0xfe to indicate BLOCK START - r=spi_read_byte(); - timeout=16384; - while( (r!=0xfe) && (timeout>0) ) { - r=spi_read_byte(); timeout--; - } - if( r!=0xfe ) return FAILURE; + } while ((timeout > 0) && (response == 0)); - // Read 512 bytes into storage - for(n=0; n<512; n++) - storage[n]=spi_read_byte(); + if(timeout == 0) + return 0; - // Read 8 dummy bytes - for(n=0; n<8; n++) - r=spi_read_byte(); + return 1; +} - return SUCCESS; +uint8_t spisdcard_init(void) { + uint8_t i; + uint8_t r; + uint8_t timeout; + + /* Set SPI clk freq to 400KHz */ + spi_set_clk_freq(400000); + + /* Set SDCard in SPI Mode */ + r = spisdcard_set_mode(); + if(r != 0x01) + return 0; + + /* Send SD CARD IDLE */ + /* CMD0 */ + spi_xfer(0xff); + spi_xfer(0x40); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x95); + /* R1 response, expects 0x1 */ + r = spisdcard_wait_response(); + if(r != 0x01) + return 0; + + /* Send Check SD CARD type */ + /* CMD8 */ + spi_xfer(0xff); + spi_xfer(0x48); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x01); + spi_xfer(0xaa); + spi_xfer(0x87); + /* R7, expects 0x1 */ + r = spisdcard_wait_response(); + if(r != 0x01) + return 0; + /* Reveice the 4 trailing bytes */ + for(i=0; i<4; i++) + r = spi_xfer(0xff); /* FIXME: add check? */ + + /* Send Force SD CARD READY (CMD55 + ACMD41), expects 0x00 R1 response */ + timeout = 32; + do { + /* CMD55 */ + spi_xfer(0xff); + spi_xfer(0x77); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + r = spisdcard_wait_response(); + /* ACMD41 */ + spi_xfer(0xff); + spi_xfer(0x69); + spi_xfer(0x40); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + /* R1 */ + r = spisdcard_wait_response(); + timeout--; + /* 20ms delay */ + busy_wait(20); + } while ((r != 0x00) && (timeout > 0)); + if(r != 0x00) + return 0; + + /* Send Read SD CARD OCR (status register) */ + /* CMD58 */ + spi_xfer(0xff); + spi_xfer(0x7a); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0xff); + /* R3, expects 0x1 */ + r = spisdcard_wait_response(); + if(r > 0x01) + return 0; + /* Reveice the 4 trailing bytes */ + for(i=0; i<4; i++) + r = spi_xfer(0xff); /* FIXME: add check? */ + + /* Send Set SD CARD block size */ + /* CMD16 */ + spi_xfer(0xff); + spi_xfer(0x50); + spi_xfer(0x00); + spi_xfer(0x00); + spi_xfer(0x02); + spi_xfer(0x00); + spi_xfer(0xff); + /* RI, expects 0x00 */ + r = spisdcard_wait_response(); + if(r != 0x00) + return 0; + + /* Set SPI clk freq to 16MHz */ + spi_set_clk_freq(16000000); + + return 1; +} + +uint8_t spisdcard_read_block(uint32_t addr, uint8_t *buf) { + int i; + uint32_t timeout; + uint8_t r; + + /* Send Read Block */ + /* CMD17 */ + spi_xfer(0xff); + spi_xfer(0x51); + spi_xfer((addr >> 24) & 0xff); + spi_xfer((addr >> 16) & 0xff); + spi_xfer((addr >> 8) & 0xff); + spi_xfer((addr >> 0) & 0xff); + spi_xfer(0xff); + /* R1, expects 0x00 that indicates the SDCard is processing */ + r = spisdcard_wait_response(); + if(r != 0x00) + return 0; + + /* Do SPI Xfers on SDCard until 0xfe is received (block start) or timeout is expired */ + r = spi_xfer(0xff); + timeout = 16384; + do { + r = spi_xfer(0xff); + timeout--; + } while((r != 0xfe) && (timeout>0)); + if(r != 0xfe) + return 0; + + /* Read the block from the SDCard and copy it to the buffer */ + for(i=0; i<512; i++) + buf[i] = spi_xfer(0xff); + + /* Read the 8 dummy bytes */ + for(i=0; i<8; i++) + r = spi_xfer(0xff); + + return 1; } #endif diff --git a/litex/soc/software/liblitesdcard/spisdcard.h b/litex/soc/software/liblitesdcard/spisdcard.h index 4c02edb53..6eb319af0 100644 --- a/litex/soc/software/liblitesdcard/spisdcard.h +++ b/litex/soc/software/liblitesdcard/spisdcard.h @@ -1,4 +1,5 @@ // This file is Copyright (c) 2020 Rob Shelton +// This file is Copyright (c) 2020 Florent Kermarrec // License: BSD #ifndef __SPISDCARD_H @@ -8,14 +9,8 @@ #ifdef CSR_SPISDCARD_BASE -#define USE_SPISCARD_RECLOCKING - -int spi_sdcard_init(uint32_t device); -int spi_sdcard_read_sector(uint32_t device, uint32_t lba,uint_least8_t *buf); - -uint8_t spi_sdcard_goidle(void); - -uint8_t readSector(uint32_t sectorNumber, uint8_t *storage); +uint8_t spisdcard_init(void); +uint8_t spisdcard_read_block(uint32_t addr, uint8_t *buf); #endif /* CSR_SPISDCARD_BASE */