diff --git a/CHANGES b/CHANGES index 397e31fd9..6b1dc9f7e 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,7 @@ - Add CV32E40P CPU support (ex RI5CY). - JTAG UART with uart_name=jtag_uart (validated on Spartan6, 7-Series, Ultrascale(+)). - Add Symbiflow experimental support on Arty. + - Add SDCard boot from FAT/exFAT filesystems with FatFs. [> API changes/Deprecation -------------------------- diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index f344bb1ae..8e40a7941 100644 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -30,7 +30,7 @@ #include #include -#include +#include extern void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); @@ -536,8 +536,33 @@ void romboot(void) #if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE) +static int copy_image_from_sdcard_to_ram(const char * filename, unsigned int ram_address) +{ + FRESULT fr; + FIL file; + UINT br; + UINT offset; + + fr = f_open(&file, filename, FA_READ); + if (fr == FR_OK){ + printf("Copying %d bytes from %s to 0x%08x...\n", f_size(&file), filename, ram_address); + offset = 0; + for (;;) { + fr = f_read(&file, (void *) ram_address + offset, 512, &br); + if (br == 0) break; + offset += br; + } + } else { + printf("%s file not found.\n", filename); + return 0; + } + f_close(&file); + return 1; +} + void sdcardboot(void) { + FATFS FatFs; unsigned int result; printf("Booting from SDCard...\n"); @@ -556,36 +581,26 @@ void sdcardboot(void) 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 = fat16_read_file("IMAGE", "", MAIN_RAM_BASE + KERNEL_IMAGE_RAM_OFFSET); - - if(result) - result &= fat16_read_file("ROOTFS~1", "CPI", MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET); - - if(result) - result &= fat16_read_file("RV32", "DTB", MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET); - - if(result) - result &= fat16_read_file("EMULATOR", "BIN", MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); - - if(result) { + f_mount(&FatFs, "", 0); + printf("Loading Linux images from SDCard to RAM...\n"); + result = copy_image_from_sdcard_to_ram("rv32.dtb", MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET); + if (result) + result &= copy_image_from_sdcard_to_ram("emulator.bin", MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); + if (result) + result &= copy_image_from_sdcard_to_ram("Image", MAIN_RAM_BASE + KERNEL_IMAGE_RAM_OFFSET); + if (result) + result &= copy_image_from_sdcard_to_ram("ROOTFS", MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET); /* FIXME should be rootfs.cpio */ + f_mount(0, "", 0); + if (result) boot(0, 0, 0, MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); - return; - } + printf("Unable to load all Linux images, falling back to boot.bin...\n"); #endif - - result = fat16_read_file("BOOT", "BIN", MAIN_RAM_BASE); + result = copy_image_from_sdcard_to_ram("boot.bin", MAIN_RAM_BASE); if(result) boot(0, 0, 0, MAIN_RAM_BASE); else - printf("SDCard boot failed\n"); + printf("SDCard boot failed.\n"); } #endif diff --git a/litex/soc/software/liblitesdcard/Makefile b/litex/soc/software/liblitesdcard/Makefile index d9b302fe9..40ae9db22 100644 --- a/litex/soc/software/liblitesdcard/Makefile +++ b/litex/soc/software/liblitesdcard/Makefile @@ -1,7 +1,7 @@ include ../include/generated/variables.mak include $(SOC_DIRECTORY)/software/common.mak -OBJECTS=fat16.o sdcard.o spisdcard.o +OBJECTS=ff.o sdcard.o spisdcard.o all: liblitesdcard.a diff --git a/litex/soc/software/liblitesdcard/fat16.c b/litex/soc/software/liblitesdcard/fat16.c deleted file mode 100644 index 362543806..000000000 --- a/litex/soc/software/liblitesdcard/fat16.c +++ /dev/null @@ -1,331 +0,0 @@ -// This file is Copyright (c) 2020 Rob Shelton -// License: BSD -// -// SD CARD code for loading files from a FAT16 formatted partition into memory - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "spisdcard.h" -#include "sdcard.h" -#include "fat16.h" - -// Return values -#define SUCCESS 0x01 -#define FAILURE 0x00 - -#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/ - -// 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 fat16_read_mbr(void) -{ - int i, n; - - // Read Sector 0x00000000 - printf("Reading MBR\n"); - 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)); - - // 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"); - if( read_block(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 fat16_read_file(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( 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( read_block(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 diff --git a/litex/soc/software/liblitesdcard/fat16.h b/litex/soc/software/liblitesdcard/fat16.h deleted file mode 100644 index 4d7d34480..000000000 --- a/litex/soc/software/liblitesdcard/fat16.h +++ /dev/null @@ -1,10 +0,0 @@ -// This file is Copyright (c) 2020 Rob Shelton -// License: BSD - -#ifndef __FAT16_H -#define __FAT16_H - -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/ffconf.h b/litex/soc/software/liblitesdcard/ffconf.h index 34d9d2d42..484667ddd 100644 --- a/litex/soc/software/liblitesdcard/ffconf.h +++ b/litex/soc/software/liblitesdcard/ffconf.h @@ -8,7 +8,7 @@ / Function Configurations /---------------------------------------------------------------------------*/ -#define FF_FS_READONLY 0 +#define FF_FS_READONLY 1 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() @@ -68,7 +68,7 @@ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ -#define FF_CODE_PAGE 932 +#define FF_CODE_PAGE 437 /* This option specifies the OEM code page to be used on the target system. / Incorrect code page setting can cause a file open failure. / @@ -221,7 +221,7 @@ / System Configurations /---------------------------------------------------------------------------*/ -#define FF_FS_TINY 1 +#define FF_FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector diff --git a/litex/soc/software/liblitesdcard/spisdcard.c b/litex/soc/software/liblitesdcard/spisdcard.c index 86095177d..a1c4e86d2 100644 --- a/litex/soc/software/liblitesdcard/spisdcard.c +++ b/litex/soc/software/liblitesdcard/spisdcard.c @@ -43,7 +43,6 @@ 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 */ @@ -416,45 +415,6 @@ DRESULT disk_read ( return count ? RES_ERROR : RES_OK; } -/*-----------------------------------------------------------------------*/ -/* Write Sector(s) */ -/*-----------------------------------------------------------------------*/ - -DRESULT disk_write ( - BYTE drv, /* Physical drive nmuber (0) */ - const BYTE *buff, /* Pointer to the data to be written */ - LBA_t sector, /* Start sector number (LBA) */ - UINT count /* Sector count (1..128) */ -) -{ - DWORD sect = (DWORD)sector; - - - //FIXME if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY; - if (!(CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */ - - if (count == 1) { /* Single block write */ - if ((send_cmd(CMD24, sect) == 0) /* WRITE_BLOCK */ - && xmit_datablock(buff, 0xFE)) - count = 0; - } - else { /* Multiple block write */ - if (CardType & CT_SDC) send_cmd(ACMD23, count); - if (send_cmd(CMD25, sect) == 0) { /* WRITE_MULTIPLE_BLOCK */ - do { - if (!xmit_datablock(buff, 0xFC)) break; - buff += 512; - } while (--count); - if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ - count = 1; - } - } - deselect(); - - return count ? RES_ERROR : RES_OK; -} - - /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ diff --git a/litex/soc/software/liblitesdcard/spisdcard.h b/litex/soc/software/liblitesdcard/spisdcard.h index 6eb319af0..cc5dc5b2c 100644 --- a/litex/soc/software/liblitesdcard/spisdcard.h +++ b/litex/soc/software/liblitesdcard/spisdcard.h @@ -1,5 +1,5 @@ -// This file is Copyright (c) 2020 Rob Shelton // This file is Copyright (c) 2020 Florent Kermarrec +// This file is Copyright (c) 2020 Rob Shelton // License: BSD #ifndef __SPISDCARD_H