software/liblitesdcard/spisdcard: simplify/rewrite for consistency with the others...
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 5 Jun 2020 07:07:19 +0000 (09:07 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 5 Jun 2020 10:46:23 +0000 (12:46 +0200)
- 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
litex/soc/software/liblitesdcard/fat16.c
litex/soc/software/liblitesdcard/fat16.h
litex/soc/software/liblitesdcard/sdcard.c
litex/soc/software/liblitesdcard/sdcard.h
litex/soc/software/liblitesdcard/spisdcard.c
litex/soc/software/liblitesdcard/spisdcard.h

index 5b224968e66ee504e832d34518954172b36c6ef4..f344bb1ae7a25a05219b69956b700d31bbef390e 100644 (file)
@@ -538,37 +538,43 @@ void romboot(void)
 
 void sdcardboot(void)
 {
+       unsigned int result;
+
        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");
+
+       /* 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;
        }
-       #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");
+
+       /* Read MBR */
+       result = fat16_read_mbr();
+       if (result == 0) {
+               printf("SDCard MBR read failed.\n");
                return;
        }
 
-       unsigned int result;
-
+       /* 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
index dea422421b8db45e9e463843eb5a037d65664bb8..3625438064d99f833c1f1d62837eb8261ddf5f12 100644 (file)
 
 #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; n<sdCardFatBootSector.fat_size_sectors; n++) {
-        if( readSector(fatSectorStart+n, (uint8_t *)((uint8_t*)sdCardFatTable)+sdCardFatBootSector.sector_size*n)==FAILURE ) {
+        if( read_block(fatSectorStart+n, (uint8_t *)((uint8_t*)sdCardFatTable)+sdCardFatBootSector.sector_size*n)==FAILURE ) {
             printf("Error reading FAT16 table - sector %d\n",n);
             return FAILURE;
         }
@@ -216,7 +211,7 @@ uint8_t sdcard_readMBR(void)
     // Calculate Start of FAT ROOT DIRECTORY (start of partition plues reserved sectors plus size of File Allocation Table(s))
     rootDirSectorStart=sdCardPartition.start_sector+sdCardFatBootSector.reserved_sectors+sdCardFatBootSector.number_of_fats*sdCardFatBootSector.fat_size_sectors;
     for(n=0; n<sdCardFatBootSector.root_dir_entries*sizeof(Fat16Entry)/sdCardFatBootSector.sector_size; n++) {
-        if( readSector(rootDirSectorStart+n, (uint8_t *)(sdCardFatBootSector.sector_size*n+(uint8_t *)(sdCardFat16RootDir)))==FAILURE ) {
+        if( read_block(rootDirSectorStart+n, (uint8_t *)(sdCardFatBootSector.sector_size*n+(uint8_t *)(sdCardFat16RootDir)))==FAILURE ) {
             printf("Error reading Root Dir - sector %d\n",n);
             return FAILURE;
         }
@@ -258,7 +253,7 @@ uint8_t sdcard_readMBR(void)
 //      Return 0 success, 1 failure
 //
 // Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
-uint8_t sdcard_readFile(char *filename, char *ext, unsigned long address)
+uint8_t fat16_read_file(char *filename, char *ext, unsigned long address)
 {
     int i, n, sector;
     uint16_t fileClusterStart;
@@ -311,14 +306,14 @@ uint8_t sdcard_readFile(char *filename, char *ext, unsigned long address)
             // If whole sector to be read, read directly into memory
             // Otherwise, read to sdCardSector buffer and transfer appropriate number of bytes
             if(bytesRemaining>sdCardFatBootSector.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;
                 }
index a207cbf865d91e8ba165695bdd53e6eed238b0ea..4d7d34480338a090d1b86e1e9b53efe40eb86432 100644 (file)
@@ -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 */
index 376c9df300a2f27a4c1319fb6eb9fa3bd7fe1fb7..fac22e893f3eb24228ae477c3fecfab9d1178cce 100644 (file)
@@ -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<SD_BLOCK_SIZE; n++)
-        storage[n] = sdread_buf[n];
+        buf[n] = sdread_buf[n];
     return 1;
 }
 
index 613a4edd7884182062e91a17265447a90dd73d20..bb13392ab04cf70f6e63739125f3dfa02a1b4059 100644 (file)
@@ -108,7 +108,7 @@ int sdcard_sddatawriter_wait(void);
 int sdcard_sddatareader_wait(void);
 int sdcard_test(unsigned int blocks);
 
-uint8_t readSector(uint32_t sectorNumber, uint8_t *storage);
+uint8_t sdcard_read_block(uint32_t addr, uint8_t *buf);
 
 #endif /* CSR_SDCORE_BASE */
 
index 509ea605caa8e45e3a097aaa9e402a31b8942640..3049037c16915d7ebb185fe3d4dd25ad1c93ac66 100644 (file)
 // This file is Copyright (c) 2020 Rob Shelton <rob.s.ng15@googlemail.com>
+// This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
 // 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 <generated/csr.h>
-#include <generated/soc.h>
-#include <generated/mem.h>
-
-#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <time.h>
 #include <string.h>
+
+#include <generated/csr.h>
+#include <generated/mem.h>
 #include <system.h>
 
-#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
-
-//      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
-
-// Return values
-#define SUCCESS         0x01
-#define FAILURE         0x00
-
-// 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);
-
-    // Wait for DONE
-    while( (spisdcard_status_read() != SPI_DONE)) {}
-
-    // Signal end of transfer
-    spisdcard_control_write( 0x00 );
-}
-
+#ifdef CSR_SPISDCARD_BASE
 
-// 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--;
-    }
+/* SPI Master flags */
+
+#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 Master low-level functions */
+
+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);
+}
 
-//    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;
+    timeout  = 32;
+    /* Do SPI Xfers on SDCard until MISO MSB's is 0 (valid response) or timeout is expired */
+    do {
+        response = spi_xfer(0xff);
+        timeout--;
+    } while(((response & 0x80) !=0) && timeout > 0);
+    return response;
 }
 
-//  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();
+static uint8_t spisdcard_set_mode(void) {
+    uint8_t timeout;
+    uint8_t response;
+
+    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();
 
         timeout--;
-    } while ( (timeout>0) && (r==0) );
+    } while ((timeout > 0) && (response == 0));
 
-    if(timeout==0) return FAILURE;
+    if(timeout == 0)
+        return 0;
 
-    return SUCCESS;
+    return 1;
 }
 
-// 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
+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_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;
-    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();
+        r = spi_xfer(0xff); /* FIXME: add check? */
 
-        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();
+    /* 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 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
+    } 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_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;
+        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;
 }
 
-// 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
-
-    // 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;
-
-    // Await 0xfe to indicate BLOCK START
-    r=spi_read_byte();
-    timeout=16384;
-    while( (r!=0xfe) && (timeout>0) ) {
-        r=spi_read_byte();
+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--;
-    }
-    if( r!=0xfe ) return FAILURE;
+    } while((r != 0xfe) && (timeout>0));
+    if(r != 0xfe)
+        return 0;
 
-    // Read 512 bytes into storage
-    for(n=0; n<512; n++)
-        storage[n]=spi_read_byte();
+    /* Read the block from the SDCard and copy it to the buffer */
+    for(i=0; i<512; i++)
+        buf[i] = spi_xfer(0xff);
 
-    // Read 8 dummy bytes
-    for(n=0; n<8; n++)
-        r=spi_read_byte();
+    /* Read the 8 dummy bytes */
+    for(i=0; i<8; i++)
+        r = spi_xfer(0xff);
 
-    return SUCCESS;
+    return 1;
 }
 
 #endif
index 4c02edb5370ec34848cb447466a3a837f1c68f67..6eb319af00c03e0ac17c68778498cbcc949cdb2c 100644 (file)
@@ -1,4 +1,5 @@
 // This file is Copyright (c) 2020 Rob Shelton <rob.s.ng15@googlemail.com>
+// This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
 // 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 */