From 4b3c5203edeb53a5b9b29da6ed68c5fe317b1d59 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 3 Jun 2020 20:03:18 +0200 Subject: [PATCH] software/bios/libsdcard: add initial boot from sdcard with litescard, rename spisdcardboot command to sdcardboot. --- litex/soc/software/bios/boot.c | 15 +- litex/soc/software/bios/boot.h | 5 +- litex/soc/software/bios/cmds/cmd_boot.c | 12 +- litex/soc/software/bios/main.c | 5 +- litex/soc/software/liblitesdcard/sdcard.c | 331 +++++++++++++++++++ litex/soc/software/liblitesdcard/sdcard.h | 4 + litex/soc/software/liblitesdcard/spisdcard.c | 2 +- 7 files changed, 357 insertions(+), 17 deletions(-) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index e751a9574..e11b78f57 100644 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -29,6 +29,7 @@ #include #include +#include extern void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); @@ -532,16 +533,22 @@ void romboot(void) } #endif -// SPI HARDWARE BITBANG -#ifdef CSR_SPISDCARD_BASE +#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE) -void spisdcardboot(void) +void sdcardboot(void) { - printf("SD Card via SPI Initialising\n"); + 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(spi_sdcard_readMBR() == 0) { printf("SD Card MBR Timeout\n"); diff --git a/litex/soc/software/bios/boot.h b/litex/soc/software/bios/boot.h index f9517bad9..e481201f3 100644 --- a/litex/soc/software/bios/boot.h +++ b/litex/soc/software/bios/boot.h @@ -5,9 +5,6 @@ int serialboot(void); void netboot(void); void flashboot(void); void romboot(void); - -#ifdef CSR_SPISDCARD_BASE -void spisdcardboot(void); -#endif +void sdcardboot(void); #endif /* __BOOT_H */ diff --git a/litex/soc/software/bios/cmds/cmd_boot.c b/litex/soc/software/bios/cmds/cmd_boot.c index c9cb8a11d..618580171 100644 --- a/litex/soc/software/bios/cmds/cmd_boot.c +++ b/litex/soc/software/bios/cmds/cmd_boot.c @@ -16,7 +16,7 @@ * */ #ifdef FLASH_BOOT_ADDRESS -define_command(flashboot, flashboot, "Boot from flash", BOOT_CMDS); +define_command(flashboot, flashboot, "Boot from Flash", BOOT_CMDS); #endif /** @@ -26,7 +26,7 @@ define_command(flashboot, flashboot, "Boot from flash", BOOT_CMDS); * */ #ifdef ROM_BOOT_ADDRESS -define_command(romboot, romboot, "Boot from embedded rom", BOOT_CMDS); +define_command(romboot, romboot, "Boot from ROM", BOOT_CMDS); #endif /** @@ -35,7 +35,7 @@ define_command(romboot, romboot, "Boot from embedded rom", BOOT_CMDS); * Boot software from serial interface * */ -define_command(serialboot, serialboot, "Boot via SFL", BOOT_CMDS); +define_command(serialboot, serialboot, "Boot from Serial (SFL)", BOOT_CMDS); /** * Command "netboot" @@ -44,7 +44,7 @@ define_command(serialboot, serialboot, "Boot via SFL", BOOT_CMDS); * */ #ifdef CSR_ETHMAC_BASE -define_command(netboot, netboot, "Boot via TFTP", BOOT_CMDS); +define_command(netboot, netboot, "Boot via Ethernet (TFTP)", BOOT_CMDS); #endif /** @@ -53,7 +53,7 @@ define_command(netboot, netboot, "Boot via TFTP", BOOT_CMDS); * Boot software from SDcard * */ -#ifdef CSR_SPISDCARD_BASE -define_command(spisdcardboot, spisdcardboot, "Boot from SDCard via SPI hardware bitbang", BOOT_CMDS); +#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE) +define_command(sdcardboot, sdcardboot, "Boot from SDCard", BOOT_CMDS); #endif diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index f56adff26..5ba73a76b 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -55,8 +55,9 @@ static void boot_sequence(void) #ifdef ROM_BOOT_ADDRESS romboot(); #endif -#ifdef CSR_SPISDCARD_BASE - spisdcardboot(); +//#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE) +#if defined(CSR_SPISDCARD_BASE) // FIXME + sdcardboot(); #endif #ifdef CSR_ETHMAC_BASE #ifdef CSR_ETHPHY_MODE_DETECTION_MODE_ADDR diff --git a/litex/soc/software/liblitesdcard/sdcard.c b/litex/soc/software/liblitesdcard/sdcard.c index 585c7a333..be0ed6ccd 100644 --- a/litex/soc/software/liblitesdcard/sdcard.c +++ b/litex/soc/software/liblitesdcard/sdcard.c @@ -707,4 +707,335 @@ int sdcard_test(unsigned int blocks) #endif return 0; } + +// Return values +#define SUCCESS 0x01 +#define FAILURE 0x00 + +// 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; + + // FIXME: handle errors. + + sdcard_read(sectorNumber, 1); + for(n=0; n<512; n++) + storage[n] = sdread_buf[n]; + + return SUCCESS; +} + +// FAT16 Specific code starts here +// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ + +// Structure to store SD CARD partition table +typedef struct { + uint8_t first_byte; + uint8_t start_chs[3]; + uint8_t partition_type; + uint8_t end_chs[3]; + uint32_t start_sector; + uint32_t length_sectors; +} __attribute((packed)) PartitionTable; + +PartitionTable sdCardPartition; + +// Structure to store SD CARD FAT16 Boot Sector (boot code is ignored, provides layout of the FAT16 partition on the SD CARD) +typedef struct { + uint8_t jmp[3]; + uint8_t oem[8]; + uint16_t sector_size; + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t number_of_fats; + uint16_t root_dir_entries; + uint16_t total_sectors_short; // if zero, later field is used + uint8_t media_descriptor; + uint16_t fat_size_sectors; + uint16_t sectors_per_track; + uint16_t number_of_heads; + uint32_t hidden_sectors; + uint32_t total_sectors_long; + + uint8_t drive_number; + uint8_t current_head; + uint8_t boot_signature; + uint32_t volume_id; + uint8_t volume_label[11]; + uint8_t fs_type[8]; + uint8_t boot_code[448]; + uint16_t boot_sector_signature; +} __attribute((packed)) Fat16BootSector; + +Fat16BootSector sdCardFatBootSector; + +// Structure to store SD CARD FAT16 Root Directory Entries +// Allocated to MAIN RAM - hence pointer +typedef struct { + uint8_t filename[8]; + uint8_t ext[3]; + uint8_t attributes; + uint8_t reserved[10]; + uint16_t modify_time; + uint16_t modify_date; + uint16_t starting_cluster; + uint32_t file_size; +} __attribute((packed)) Fat16Entry; + +Fat16Entry *sdCardFat16RootDir; + +// Structure to store SD CARD FAT16 Entries +// Array of uint16_tS (16bit integers) +uint16_t *sdCardFatTable; + +// Calculated sector numbers on the SD CARD for the FAT16 Entries and ROOT DIRECTORY +uint32_t fatSectorStart, rootDirSectorStart; + +// Storage for SECTOR read from SD CARD +uint8_t sdCardSector[512]; + +// SPI_SDCARD_READMBR +// Function exposed to BIOS to retrieve FAT16 partition details, FAT16 Entry Table, FAT16 Root Directory +// MBR = Master Boot Record - Sector 0x00000000 on SD CARD - Contains Partition 1 details at 0x1be +// +// FIXME only checks partition 1 out of 4 +// +// Return 0 success, 1 failure +// +// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ +uint8_t spi_sdcard_readMBR(void) +{ + int i, n; + + // Read Sector 0x00000000 + printf("Reading MBR\n"); + if( readSector(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)); + + // Check Partition 1 is valid, FIRST_BYTE=0x00 or 0x80 + // Check Partition 1 has type 4, 6 or 14 (FAT16 of various sizes) + printf("Partition 1 Information: Active=0x%02x, Type=0x%02x, LBAStart=0x%08x\n", sdCardPartition.first_byte, sdCardPartition.partition_type, sdCardPartition.start_sector); + if( (sdCardPartition.first_byte!=0x80) && (sdCardPartition.first_byte!=0x00) ) { + printf("Partition 1 Not Valid\n"); + return FAILURE; + } + if( (sdCardPartition.partition_type==4) || (sdCardPartition.partition_type==6) || (sdCardPartition.partition_type==14) ) { + printf("Partition 1 is FAT16\n"); + } + else { + printf("Partition 1 Not FAT16\n"); + return FAILURE; + } + } + else { + printf("Failed to read MBR\n"); + return FAILURE; + } + + // Read Parition 1 Boot Sector - Found from Partion Table + printf("\nRead FAT16 Boot Sector\n"); + sdCardPartition.start_sector = sdCardPartition.start_sector/512; + if( readSector(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) { + memcpy(&sdCardFatBootSector, &sdCardSector, sizeof(Fat16BootSector)); + } + else { + printf("Failed to read FAT16 Boot Sector\n"); + return FAILURE; + } + + // Print details of Parition 1 + printf(" Jump Code: 0x%02x 0x%02x 0x%02x\n",sdCardFatBootSector.jmp[0],sdCardFatBootSector.jmp[1],sdCardFatBootSector.jmp[2]); + printf(" OEM Code: ["); + for(n=0; n<8; n++) + printf("%c",sdCardFatBootSector.oem[n]); + printf("]\n"); + printf(" Sector Size: %d\n",sdCardFatBootSector.sector_size); + printf(" Sectors Per Cluster: %d\n",sdCardFatBootSector.sectors_per_cluster); + printf(" Reserved Sectors: %d\n",sdCardFatBootSector.reserved_sectors); + printf(" Number of Fats: %d\n",sdCardFatBootSector.number_of_fats); + printf(" Root Dir Entries: %d\n",sdCardFatBootSector.root_dir_entries); + printf(" Total Sectors Short: %d\n",sdCardFatBootSector.total_sectors_short); + printf(" Media Descriptor: 0x%02x\n",sdCardFatBootSector.media_descriptor); + printf(" Fat Size Sectors: %d\n",sdCardFatBootSector.fat_size_sectors); + printf(" Sectors Per Track: %d\n",sdCardFatBootSector.sectors_per_track); + printf(" Number of Heads: %d\n",sdCardFatBootSector.number_of_heads); + printf(" Hidden Sectors: %d\n",sdCardFatBootSector.hidden_sectors); + printf(" Total Sectors Long: %d\n",sdCardFatBootSector.total_sectors_long); + printf(" Drive Number: 0x%02x\n",sdCardFatBootSector.drive_number); + printf(" Current Head: 0x%02x\n",sdCardFatBootSector.current_head); + printf(" Boot Signature: 0x%02x\n",sdCardFatBootSector.boot_signature); + printf(" Volume ID: 0x%08x\n",sdCardFatBootSector.volume_id); + printf(" Volume Label: ["); + for(n=0; n<11; n++) + printf("%c",sdCardFatBootSector.volume_label[n]); + printf("]\n"); + printf(" Volume Label: ["); + for(n=0; n<8; n++) + printf("%c",sdCardFatBootSector.fs_type[n]); + printf("]\n"); + printf(" Boot Sector Signature: 0x%04x\n\n",sdCardFatBootSector.boot_sector_signature); + + // Check Partition 1 is valid, not 0 length + if(sdCardFatBootSector.total_sectors_long==0) { + printf("Error reading FAT16 Boot Sector\n"); + return FAILURE; + } + + // 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); + printf("sdCardFatTable = 0x%08x Reading Fat16 Table (%d Sectors Long)\n\n",sdCardFatTable,sdCardFatBootSector.fat_size_sectors); + + // Calculate Start of FAT16 File Allocation Table (start of partition plus reserved sectors) + fatSectorStart=sdCardPartition.start_sector+sdCardFatBootSector.reserved_sectors; + for(n=0; n0)) { + printf(" File %d [",n); + for( i=0; i<8; i++) { + if( (sdCardFat16RootDir[n].filename[i]>31) && (sdCardFat16RootDir[n].filename[i]<127) ) + printf("%c",sdCardFat16RootDir[n].filename[i]); + else + printf(" "); + } + printf("."); + for( i=0; i<3; i++) { + if( (sdCardFat16RootDir[n].ext[i]>31) && (sdCardFat16RootDir[n].ext[i]<127) ) + printf("%c",sdCardFat16RootDir[n].ext[i]); + else + printf(" "); + } + printf("] @ Cluster %d for %d bytes\n",sdCardFat16RootDir[n].starting_cluster,sdCardFat16RootDir[n].file_size); + } + } + + printf("\n"); + return SUCCESS; +} + +// SPI_SDCARD_READFILE +// Function exposed to BIOS to retrieve FILENAME+EXT into ADDRESS +// +// FIXME only checks UPPERCASE 8+3 filenames +// +// Return 0 success, 1 failure +// +// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ +uint8_t spi_sdcard_readFile(char *filename, char *ext, unsigned long address) +{ + int i, n, sector; + uint16_t fileClusterStart; + uint32_t fileLength, bytesRemaining, clusterSectorStart; + uint16_t nameMatch; + printf("Reading File [%s.%s] into 0x%08x : ",filename, ext, address); + + // Find FILENAME+EXT in Root Directory + // Indicate FILE found by setting the starting cluster number + fileClusterStart=0; n=0; + while( (fileClusterStart==0) && (n1) + for(i=0; i<1+((fileLength/sdCardFatBootSector.sectors_per_cluster)/sdCardFatBootSector.sector_size); i++) { + printf("\rCluster: %d",fileClusterStart); + + // Locate start of cluster on SD CARD and read appropraite number of sectors + clusterSectorStart=rootDirSectorStart+(fileClusterStart-1)*sdCardFatBootSector.sectors_per_cluster; + for(sector=0; sectorsdCardFatBootSector.sector_size) { + if( readSector(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 ) { + printf("\nRead Error\n"); + return FAILURE; + } + memcpy((uint8_t *)address, sdCardSector, bytesRemaining); + bytesRemaining=0; + } + } + + // Move to next cluster + fileClusterStart=sdCardFatTable[fileClusterStart]; + } + printf("\n\n"); + return SUCCESS; +} + #endif /* CSR_SDCORE_BASE */ diff --git a/litex/soc/software/liblitesdcard/sdcard.h b/litex/soc/software/liblitesdcard/sdcard.h index 57dbc6cbb..c4373ee7a 100644 --- a/litex/soc/software/liblitesdcard/sdcard.h +++ b/litex/soc/software/liblitesdcard/sdcard.h @@ -108,6 +108,10 @@ int sdcard_sddatawriter_wait(void); int sdcard_sddatareader_wait(void); int sdcard_test(unsigned int blocks); +/* FAT16 (FIXME: avoid duplication with spisdcard) */ +uint8_t spi_sdcard_readMBR(void); +uint8_t spi_sdcard_readFile(char *, char *, unsigned long); + #endif /* CSR_SDCORE_BASE */ #endif /* __SDCARD_H */ diff --git a/litex/soc/software/liblitesdcard/spisdcard.c b/litex/soc/software/liblitesdcard/spisdcard.c index b335da401..f9cdaef7b 100644 --- a/litex/soc/software/liblitesdcard/spisdcard.c +++ b/litex/soc/software/liblitesdcard/spisdcard.c @@ -459,6 +459,7 @@ uint8_t spi_sdcard_readMBR(void) 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 @@ -473,7 +474,6 @@ uint8_t spi_sdcard_readMBR(void) return FAILURE; } } -#endif // Read in FAT16 Root Directory // Calculate Storage from TOP of MAIN RAM