diff --git a/.gitmodules b/.gitmodules index c124265d..47e8b3b6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,6 +28,9 @@ [submodule "third_party/flash_proxies"] path = third_party/flash_proxies url = https://github.com/jordens/bscan_spi_bitstreams +[submodule "third_party/libmodem"] + path = third_party/libmodem + url = https://github.com/cr1901/libmodem [submodule "third_party/migen"] path = third_party/migen url = https://github.com/m-labs/migen.git diff --git a/.travis.yml b/.travis.yml index 293b8006..0363f0c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ addons: - libftdi-dev - libreadline-dev - libusb-1.0-0-dev + - python3-pip - python-yaml - realpath - util-linux @@ -31,6 +32,12 @@ env: # cores. - JOBS=2 +before_install: + - wget https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip -O /tmp/ninja.zip + - unzip -d ninja-1.8.2 /tmp/ninja.zip + - export PATH=$PATH:$PWD/ninja-1.8.2/ + - pip3 install --user meson + install: - export CPUS="$C" && echo "CPUS='$CPUS'" - export PLATFORMS="$P" && echo "PLATFORMS='$PLATFORMS'" diff --git a/Makefile b/Makefile index 26145226..e7afc4d1 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,9 @@ endif PYTHON ?= python export PYTHON +MESON ?= meson +export MESON + SPLIT_REGEX := ^\([^.]*\)\.\?\(.*\)$$ # The platform to run on. It is made up of FPGA_MAIN_BOARD.EXPANSION_BOARD @@ -275,7 +278,11 @@ gateware-clean: # Firmware - the stuff which runs in the soft CPU inside the FPGA. # -------------------------------------- -firmware-cmd: litex-submodules +FIRMWARE_MODULES=libmodem +firmware-submodules: $(addsuffix /.git,$(addprefix third_party/,$(FIRMWARE_MODULES))) + @true + +firmware-cmd: litex-submodules firmware-submodules mkdir -p $(TARGET_BUILD_DIR) ifneq ($(OS),Windows_NT) $(MAKE_CMD) --no-compile-gateware \ diff --git a/firmware/Makefile b/firmware/Makefile index 1076a6f8..2936bc77 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -24,6 +24,7 @@ OBJECTS=\ encoder.o \ etherbone.o \ ethernet.o \ + flash.o \ fx2.o \ hdmi_in0.o \ hdmi_out0.o \ @@ -40,6 +41,7 @@ OBJECTS=\ pll.o \ processor.o \ reboot.o \ + spiflash.o \ stdio_wrap.o \ telnet.o \ tofe_eeprom.o \ @@ -52,7 +54,7 @@ OBJECTS=\ CFLAGS += \ -I$(FIRMWARE_DIRECTORY) \ - -I$(BUILD_DIRECTORY)/software/firmware + -I$(BUILD_DIRECTORY)/software/firmware \ CFLAGS += \ -Wall \ @@ -62,6 +64,7 @@ CFLAGS += \ include $(UIP_DIRECTORY)/Makefile.mk +include $(MODEM_DIRECTORY)/Makefile.mk LDFLAGS += \ @@ -87,7 +90,9 @@ firmware.elf: $(FIRMWARE_DIRECTORY)/linker.ld $(OBJECTS) -L../libcompiler_rt \ -lcompiler_rt \ -L../uip \ - -luip + -luip \ + -L../modem \ + -lmodem chmod -x $@ # pull in dependency info for *existing* .o files diff --git a/firmware/ci.c b/firmware/ci.c index 8e89bfe5..2d0d4957 100644 --- a/firmware/ci.c +++ b/firmware/ci.c @@ -31,6 +31,7 @@ #include "config.h" #include "edid.h" #include "encoder.h" +#include "flash.h" #include "fx2.h" #include "hdmi_in0.h" #include "hdmi_in1.h" @@ -174,6 +175,9 @@ static void help_debug(void) #endif wputs(" debug dna - show Board's DNA"); wputs(" debug edid - dump monitor EDID"); +#if defined(CSR_SPIFLASH_BASE) && defined(FLASH_BOOT_ADDRESS) + wputs(" debug spiflash - test bitbang write"); +#endif #ifdef CSR_CAS_BASE wputs(" debug cas leds - change the status LEDs"); wputs(" debug cas switches - read the control switches status"); @@ -182,6 +186,15 @@ static void help_debug(void) #endif } +static void help_write(void) +{ + wputs("write commands"); +#ifdef CSR_SPIFLASH_BASE + wputs(" write spi xmodem addr len - upload new spi flash firmware (xmodem)"); + wputs(" write spi sfl addr len crc - upload new spi flash firmware (flterm)"); +#endif +} + static void ci_help(void) { wputs("help - this command"); @@ -224,6 +237,7 @@ static void ci_help(void) wputs(""); #endif help_debug(); + help_write(); } static char *readstr(void) @@ -1004,6 +1018,82 @@ static void debug_ddr(void) } #endif +#undef NEXT_TOKEN_OR_RETURN +#define NEXT_TOKEN_OR_RETURN(s, t, reason) \ + if(!(t = get_token(&s))) { \ + wprintf("Parse failed - " reason " \r\n"); \ + return; \ + } + +#ifdef CSR_SPIFLASH_BASE +static void write_spi(char* str) +{ + char *token; + int rc = 0; + char * endptr; + unsigned long addr; + unsigned long len; + unsigned long crc; + int use_xmodem = 0, use_sfl = 0; + char * proto_str; + + token = get_token(&str); + + if(strcmp(token, "xmodem") == 0) { + use_xmodem = 1; + proto_str = "xmodem"; + } + else if(strcmp(token, "sfl") == 0) { + use_sfl = 1; + proto_str = "sfl"; + } + else { + wprintf("Protocol not supported.\r\n"); + return; + } + + NEXT_TOKEN_OR_RETURN(str, token, "Invalid address."); + addr = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in address."); + return; + } + + NEXT_TOKEN_OR_RETURN(str, token, "Invalid length."); + len = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in length."); + return; + } + + NEXT_TOKEN_OR_RETURN(str, token, "Invalid CRC."); + crc = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in CRC."); + return; + } + + wprintf("Will use %s with addr %lX, len %ld and crc %lX.\r\n", proto_str, addr, len, crc); + if(use_xmodem) + rc = write_xmodem(addr, len, crc); + else if(use_sfl) + rc = write_sfl(addr, len, crc); + else + rc = -3; + + if(rc == 0) + wprintf("New firmware written successfully.\r\n"); + else if(rc == -1) + wprintf("CRC error transmitting firmware.\r\n"); + else if(rc == -2) + wprintf("Flash comparison with in-memory image failed.\r\n"); + else + wprintf("Unspecified error: %d\r\n", rc); + + return; +} +#endif + void ci_prompt(void) { wprintf("H2U %s>", uptime_str()); @@ -1052,6 +1142,8 @@ void ci_service(void) #endif else if(strcmp(token, "debug") == 0) help_debug(); + else if(strcmp(token, "write") == 0) + help_write(); else ci_help(); wputs(""); @@ -1302,6 +1394,10 @@ void ci_service(void) #endif if(found == 0) wprintf("no such port\n"); +#if defined(CSR_SPIFLASH_BASE) && defined(FLASH_BOOT_ADDRESS) + } else if(strcmp(token, "spiflash") == 0) { + bitbang_test(); +#endif #ifdef CSR_CAS_BASE } else if(strcmp(token, "cas") == 0) { token = get_token(&str); @@ -1331,7 +1427,17 @@ void ci_service(void) #endif } else help_debug(); - + } else if(strcmp(token, "write") == 0) { + token = get_token(&str); + if(false) { } // XXX: Replace with "command not supported?" if + // CSR_SPIFLASH_BASE isn't defined? +#ifdef CSR_SPIFLASH_BASE + else if((strcmp(token, "spi") == 0) ) { + write_spi(str); + } +#endif + else + help_write(); } else if(strcmp(token, "version") == 0) { print_version(); } else { diff --git a/firmware/flash.c b/firmware/flash.c index ed3e1c8d..f74db568 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -1,17 +1,41 @@ #include -#ifdef SPIFLASH_PAGE_SIZE +#include +#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) +#include "spiflash.h" #include "flash.h" #include +#include #include #include +#include +#include #include #include +#include +#include #include "ci.h" +#include +#include #define test_size 1024 +static unsigned char bitbang_buffer[128*1024]; +static unsigned char bus_buffer[128*1024]; +static unsigned char xmodem_buffer[1029]; +static unsigned char sector_buf_pre[SPIFLASH_SECTOR_SIZE]; +static unsigned char sector_buf_post[SPIFLASH_SECTOR_SIZE]; + +typedef struct flash_writer { + unsigned char * buf; + size_t inlen; + size_t bufpos; + size_t buflen; +} flash_writer_t; + +int write_to_buf(const char * buf, const int buf_size, const int eof, void * const chan_state); +static void write_to_flash_arb(unsigned int addr, unsigned int len, unsigned char * prepend_buf, unsigned char * append_buf); #define NUMBER_OF_BYTES_ON_A_LINE 16 static void dump_bytes(unsigned int *ptr, int count, unsigned addr) @@ -53,7 +77,7 @@ static void dump_bytes(unsigned int *ptr, int count, unsigned addr) static void mr(unsigned int addr, unsigned int length) { - dump_bytes(addr, length, (unsigned)addr); + dump_bytes((unsigned int *) addr, length, (unsigned)addr); } void flash_test(void) { @@ -61,4 +85,162 @@ void flash_test(void) { mr(0x20000000, test_size); } -#endif \ No newline at end of file +#ifdef FLASH_BOOT_ADDRESS +void bitbang_test(void) { + unsigned int *flashbase; + unsigned int length; + unsigned int *free_start; + unsigned int free_space; + int i = 0; + + unsigned int buf_w[512]; + unsigned int buf_r[512]; + + flashbase = (unsigned int *)FLASH_BOOT_ADDRESS; + length = *flashbase++; + free_start = flashbase + length; + free_space = (unsigned int *)(SPIFLASH_BASE + SPIFLASH_SIZE) - free_start; + + printf("Free space begins at %X, size %d bytes.\n", free_start, free_space); + mr((unsigned int) free_start, 512); + + for(i = 0; i < 512; i++) { + buf_w[i] = (unsigned int) ( (i << 8) | i ); + } + + printf("Read using memory bus 1.\n"); + write_to_flash((unsigned int) free_start, (unsigned char *) buf_w, 512); + flush_cpu_dcache(); + mr((unsigned int) free_start, 512); + + printf("Read using bitbang test.\n"); + read_from_flash((unsigned int) free_start, (unsigned char *) buf_r, 512); + mr((unsigned int) &buf_r[0], 512); // &buf_r[0]: Collapse to ptr to first element. + + printf("Read using memory bus 2.\n"); + flush_cpu_dcache(); + mr((unsigned int) free_start, 512); + + erase_flash_sector((unsigned int) free_start); +} +#endif + + +// XMODEM: +// 10 tries to receive first char of packet- 10 seconds each +// First char of first packet special- either send NAK or C (for CRC) + + +// 1 second timeout for each recv'd char otherwise. + +// XMODEM helpers + + +int write_to_buf(const char * buf, const int buf_size, const int eof, void * const chan_state) { + flash_writer_t * writer = chan_state; + + int space_left = writer->buflen - writer->bufpos; + + int size_sent = space_left < buf_size ? space_left : buf_size; + memcpy(writer->buf + writer->bufpos, buf, size_sent); + + writer->bufpos += size_sent; + return size_sent; +} + +int write_xmodem(unsigned long addr, unsigned long len, unsigned long crc) { + flash_writer_t writer = { bitbang_buffer, len, 0, sizeof(bitbang_buffer)/sizeof(bitbang_buffer[0]) }; + serial_handle_t uart; + unsigned int calc_crc; + + printf("Phase 1: Receive file (Please start XMODEM transmission).\r\n"); + serial_init(0, 0, &uart); + int rc = xmodem_rx(write_to_buf, xmodem_buffer, &writer, uart, XMODEM_1K); + serial_close(&uart); + + if(rc != MODEM_NO_ERRORS) { + return -1; + } + + // Do CRC check. Return if no match. + printf("Phase 2: CRC check.\r\n"); + calc_crc = crc32((unsigned char *) bitbang_buffer, len); + if(crc != calc_crc) { + printf("CRC failed (expected %08x, got %08x)\n", crc, calc_crc); + return -1; + } + + write_to_flash_arb(addr, len, sector_buf_pre, sector_buf_post); + + memcpy(bus_buffer, (void *) addr, len); + printf("Phase 5: Comparing memory bus to received data.\r\n"); + for(unsigned int count = 0; count < len; count++) { + if(bus_buffer[count] != bitbang_buffer[count]) { + printf("Comparison failed at offset %X\r\n", count); + mr((unsigned int) &bus_buffer[count], 512); + mr((unsigned int) &bitbang_buffer[count], 512); + return -2; + } + } + + /* Phase 6 comparison. */ + memset(bitbang_buffer, '\0', len); + printf("Phase 6: Comparing memory bus to bitbang reads.\r\n"); + read_from_flash(addr, (unsigned char *) bitbang_buffer, len); + for(unsigned int count = 0; count < len; count++) { + if(bus_buffer[count] != bitbang_buffer[count]) { + printf("Comparison failed at offset %X\r\n", count); + mr((unsigned int) &bus_buffer[count], 512); + mr((unsigned int) &bitbang_buffer[count], 512); + return -2; + } + } + + flush_cpu_dcache(); + mr(addr, 512); + + return 0; +} + +int write_sfl(unsigned long addr, unsigned long len, unsigned long crc) { + return 0; +} + +static void write_to_flash_arb(unsigned int addr, unsigned int len, unsigned char * prepend_buf, unsigned char * append_buf) { + printf("Phase 3: Erase flash region.\r\n"); + /* All end ptrs are "one past the last byte used for data of the + previous start ptr". */ + unsigned int erase_addr = addr; + unsigned int erase_end = erase_addr + len; + unsigned int sector_start = erase_addr & ~(SPIFLASH_SECTOR_SIZE - 1); + unsigned int sector_end = (erase_end & ~(SPIFLASH_SECTOR_SIZE - 1)) + SPIFLASH_SECTOR_SIZE; + unsigned int prepend_len = erase_addr - sector_start; + unsigned int append_len = sector_end - erase_end; + + memcpy(prepend_buf, (void *) sector_start, prepend_len); + memcpy(append_buf, (void *) erase_end, append_len); + erase_flash_sector(sector_start); + printf("Write leading data.\r\n"); + write_to_flash(sector_start, prepend_buf, prepend_len); + flush_cpu_dcache(); + + unsigned int middle_sectors = sector_start + SPIFLASH_SECTOR_SIZE; + + while(middle_sectors < sector_end) { + erase_flash_sector(middle_sectors); + middle_sectors += SPIFLASH_SECTOR_SIZE; + } + + printf("Write trailing data.\r\n"); + write_to_flash(erase_end, append_buf, append_len); + flush_cpu_dcache(); + + printf("Phase 4: Writing new data to flash.\r\n"); + write_to_flash(addr, (unsigned char *) bitbang_buffer, len); + flush_cpu_dcache(); +} + + + + +#endif diff --git a/firmware/flash.h b/firmware/flash.h index 8e09be7a..5df3b3c6 100644 --- a/firmware/flash.h +++ b/firmware/flash.h @@ -2,5 +2,13 @@ #define __FLASH_H void flash_test(void); +#ifdef FLASH_BOOT_ADDRESS +void bitbang_test(void); +#endif + +#ifdef CSR_UART_BASE +int write_xmodem(unsigned long addr, unsigned long len, unsigned long crc); +int write_sfl(unsigned long addr, unsigned long len, unsigned long crc); +#endif #endif /* __FLASH_H */ diff --git a/firmware/linker.ld b/firmware/linker.ld index 420a48d1..3cc8aff8 100644 --- a/firmware/linker.ld +++ b/firmware/linker.ld @@ -47,7 +47,7 @@ SECTIONS . = ALIGN(4); _ebss = .; _end = .; - } > sram + } > main_ram } PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4); diff --git a/firmware/modem/Makefile b/firmware/modem/Makefile new file mode 100644 index 00000000..0e5f19fb --- /dev/null +++ b/firmware/modem/Makefile @@ -0,0 +1,21 @@ +include ../include/generated/variables.mak +include $(SOC_DIRECTORY)/software/common.mak + +VPATH=$(MODEM_DIRECTORY) + +include $(MODEM_DIRECTORY)/Makefile.mk + +libmodem.a: build.ninja ninja-hack + ninja -f $< + +# meson doesn't understand vpath +REALSRCDIR=$(MODEM_DIRECTORY)/$(LIBMODEMDIR) + +build.ninja: $(LIBMODEMDIR)/meson.build $(LIBMODEMDIR)/targets/hdmi2usb-$(CPU).txt + # If $CC was exported at all from a parent, make will set it to $(CC_quiet). + # This will confuse meson and cause the build to fail, so set it to a dummy + # value for the time being. Since this is a cross-build, cc won't be used + # after meson runs. + CC=cc $(MESON) . $(REALSRCDIR) -Db_staticpic=false -Dhdmi2usb_dir=$(BUILDINC_DIRECTORY)/../.. --cross-file=$(REALSRCDIR)/targets/hdmi2usb-$(CPU).txt + +.PHONY: ninja-hack diff --git a/firmware/modem/Makefile.mk b/firmware/modem/Makefile.mk new file mode 100644 index 00000000..6c07f3ad --- /dev/null +++ b/firmware/modem/Makefile.mk @@ -0,0 +1,5 @@ +LIBMODEMDIR=../../third_party/libmodem +MODEMDIR=. + +CFLAGS += \ + -I$(MODEM_DIRECTORY)/$(LIBMODEMDIR)/src diff --git a/firmware/modem/README.md b/firmware/modem/README.md new file mode 100644 index 00000000..fad40344 --- /dev/null +++ b/firmware/modem/README.md @@ -0,0 +1,12 @@ +`libmodem` currently uses a separate build system from the rest of HDMI2USB. + +The purpose of this directory is to provide a make wrapper around `libmodem` +that Litex picks up as a dependency. + +When building `libmodem` as a dependency of HDMI2USB, there are four directories +used (relative to `$HDMI2USB_ROOT` and for a given `$TARGET`): + +* `$HDMI2USB_ROOT/firmware/modem`: This directory, where Makefiles live. +* `$HDMI2USB_ROOT/third_party/libmodem`: `libmodem` source code. +* `$HDMI2USB_ROOT/build/$TARGET/third_party/libmodem`: Meson output/`build.ninja` are generated here. +* `$HDMI2USB_ROOT/build/$TARGET/software/modem`: Object files and `libmodem.a` are generated here. diff --git a/firmware/spiflash.c b/firmware/spiflash.c new file mode 100644 index 00000000..c77dcf33 --- /dev/null +++ b/firmware/spiflash.c @@ -0,0 +1,183 @@ +#include + +#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) + +#include "spiflash.h" + +#define PAGE_PROGRAM_CMD 0x02 +#define WRDI_CMD 0x04 +#define RDSR_CMD 0x05 +#define WREN_CMD 0x06 +#define RD_CMD 0x0b +#define SE_CMD 0xd8 + +#define BITBANG_CLK (1 << 1) +#define BITBANG_CS_N (1 << 2) +#define BITBANG_DQ_INPUT (1 << 3) // This bit is only used for Dual/Quad SPI +// flash, where MISO/MOSI pins are bidirectional depending on SPI flash command. +// The bitbang interface does not support Dual/Quad reads. + +#define SR_WIP 1 + +static void flash_write_byte(unsigned char b); +static void flash_write_addr(unsigned int addr); +static void wait_for_device_ready(void); + +#define min(a,b) (a>b?b:a) + +// flash_read/flash_write fcns make no assumptions on bitbang reg on entry. +// They will all leave the bitbang reg as 0x00 on exit. +// We latch on positive edge, so only Modes 0 and 3 supported. +// FIXME: Bitbang commands that use the read/write primitives +// leave ~CLK as 0 on exit, which is Mode 0 compatible only. +// How should we handle Mode 3? Set-once global and mask? +static unsigned char flash_read_byte(void) +{ + int i; + unsigned char b = 0; + spiflash_bitbang_write(BITBANG_DQ_INPUT); // ~CS_N ~CLK DQ_INPUT + + for(i = 0; i < 8; i++) { + b <<= 1; + spiflash_bitbang_write(BITBANG_CLK | BITBANG_DQ_INPUT); + b |= spiflash_miso_read(); + spiflash_bitbang_write(0 | BITBANG_DQ_INPUT); + } + + spiflash_bitbang_write(0); // ~CS_N ~CLK + return b; +} + +static void flash_write_byte(unsigned char b) +{ + int i; + spiflash_bitbang_write(0); // ~CS_N ~CLK + + for(i = 0; i < 8; i++, b <<= 1) { + + spiflash_bitbang_write((b & 0x80) >> 7); + spiflash_bitbang_write(((b & 0x80) >> 7) | BITBANG_CLK); + } + + spiflash_bitbang_write(0); // ~CS_N ~CLK +} + +static void flash_write_addr(unsigned int addr) +{ + int i; + spiflash_bitbang_write(0); + + for(i = 0; i < 24; i++, addr <<= 1) { + spiflash_bitbang_write((addr & 0x800000) >> 23); + spiflash_bitbang_write(((addr & 0x800000) >> 23) | BITBANG_CLK); + } + + spiflash_bitbang_write(0); +} + +// Bitbang commands will have flash_read/write fcns set up the bitbang reg +// on entry. On exit, bitbang command fcns will deassert CS_N bitbang +// regs (required) and then disable bitbang interface. +// XXX: write_to_flash_page leaves CS_N as 0. Why? +static void wait_for_device_ready(void) +{ + unsigned char sr; + unsigned char i; + do { + sr = 0; + flash_write_byte(RDSR_CMD); + sr = flash_read_byte(); + spiflash_bitbang_write(BITBANG_CS_N); + } while(sr & SR_WIP); +} + +void erase_flash_sector(unsigned int addr) +{ + unsigned int sector_addr = addr & ~(SPIFLASH_SECTOR_SIZE - 1); + + spiflash_bitbang_en_write(1); + + wait_for_device_ready(); + + flash_write_byte(WREN_CMD); + spiflash_bitbang_write(BITBANG_CS_N); + + flash_write_byte(SE_CMD); + flash_write_addr(sector_addr); + spiflash_bitbang_write(BITBANG_CS_N); + + wait_for_device_ready(); + + spiflash_bitbang_en_write(0); +} + +void read_from_flash(unsigned int addr, unsigned char *c, unsigned int len) +{ + unsigned int i; + + spiflash_bitbang_en_write(1); + + wait_for_device_ready(); + + flash_write_byte(RD_CMD); + flash_write_addr(addr); + (void) flash_read_byte(); // Higher-speed read has a dummy byte. + for(i = 0; i < len; i++) + *c++ = flash_read_byte(); + spiflash_bitbang_write(BITBANG_CS_N); + + wait_for_device_ready(); + + spiflash_bitbang_en_write(0); +} + +void write_to_flash_page(unsigned int addr, const unsigned char *c, unsigned int len) +{ + unsigned int i; + + if(len > SPIFLASH_PAGE_SIZE) + len = SPIFLASH_PAGE_SIZE; + + spiflash_bitbang_en_write(1); + + wait_for_device_ready(); + + flash_write_byte(WREN_CMD); + spiflash_bitbang_write(BITBANG_CS_N); + flash_write_byte(PAGE_PROGRAM_CMD); + flash_write_addr((unsigned int)addr); + for(i = 0; i < len; i++) + flash_write_byte(*c++); + + spiflash_bitbang_write(BITBANG_CS_N); + spiflash_bitbang_write(0); + + wait_for_device_ready(); + + spiflash_bitbang_en_write(0); +} + +#define SPIFLASH_PAGE_MASK (SPIFLASH_PAGE_SIZE - 1) + +void write_to_flash(unsigned int addr, const unsigned char *c, unsigned int len) +{ + unsigned int written = 0; + + if(addr & SPIFLASH_PAGE_MASK) { + written = min(SPIFLASH_PAGE_SIZE - (addr & SPIFLASH_PAGE_MASK), len); + write_to_flash_page(addr, c, written); + c += written; + addr += written; + len -= written; + } + + while(len > 0) { + written = min(len, SPIFLASH_PAGE_SIZE); + write_to_flash_page(addr, c, written); + c += written; + addr += written; + len -= written; + } +} + +#endif /* CSR_SPIFLASH_BASE && SPIFLASH_PAGE_SIZE */ diff --git a/firmware/spiflash.h b/firmware/spiflash.h new file mode 100644 index 00000000..bfbd7672 --- /dev/null +++ b/firmware/spiflash.h @@ -0,0 +1,9 @@ +#ifndef __SPIFLASH_H +#define __SPIFLASH_H + +void write_to_flash_page(unsigned int addr, const unsigned char *c, unsigned int len); +void erase_flash_sector(unsigned int addr); +void write_to_flash(unsigned int addr, const unsigned char *c, unsigned int len); +void read_from_flash(unsigned int addr, unsigned char *c, unsigned int len); + +#endif /* __SPIFLASH_H */ diff --git a/gateware/spi_flash.py b/gateware/spi_flash.py index b5e860aa..02311082 100644 --- a/gateware/spi_flash.py +++ b/gateware/spi_flash.py @@ -258,4 +258,3 @@ def SpiFlash(pads, *args, **kw): return SpiFlashSingle(pads, *args, **kw) else: return SpiFlashDualQuad(pads, *args, **kw) - diff --git a/getcrc32.py b/getcrc32.py new file mode 100644 index 00000000..a9dd1270 --- /dev/null +++ b/getcrc32.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import os +import argparse +import binascii + +def main(): + parser = argparse.ArgumentParser(description="Print file length and CRC32.") + parser.add_argument("-n", help="List filenames of input files.") + parser.add_argument("-l", help="List length of input files.") + parser.add_argument("files", metavar="f", type=str, nargs="+", + help="Files to calculate CRC32") + + args = parser.parse_args() + + lens = [] + crcs = [] + for f in args.files: + lens.append(os.path.getsize(f)) + with open(f, "rb") as fp: + crcs.append(binascii.crc32(fp.read())) + + for n in range(len(args.files)): + print("{}: {} {:#0X}".format(args.files[n], lens[n], crcs[n])) + + + + +if __name__ == "__main__": + main() diff --git a/make.py b/make.py index d5e5d009..14532df8 100755 --- a/make.py +++ b/make.py @@ -123,6 +123,7 @@ def main(): builder = Builder(soc, **buildargs) if not args.no_compile_firmware or args.override_firmware: builder.add_software_package("uip", "{}/firmware/uip".format(os.getcwd())) + builder.add_software_package("modem", "{}/firmware/modem".format(os.getcwd())) builder.add_software_package("firmware", "{}/firmware".format(os.getcwd())) vns = builder.build(**dict(args.build_option)) else: diff --git a/third_party/libmodem b/third_party/libmodem new file mode 160000 index 00000000..1499a0bc --- /dev/null +++ b/third_party/libmodem @@ -0,0 +1 @@ +Subproject commit 1499a0bcc545668413a21ed3ec43e102b46621fa diff --git a/third_party/litedram b/third_party/litedram index 45da365b..f31f8a03 160000 --- a/third_party/litedram +++ b/third_party/litedram @@ -1 +1 @@ -Subproject commit 45da365b7f3bdfccb759038d0b76b7c62c1233e1 +Subproject commit f31f8a03ff6911befa6d07bf347f8478c30448d8 diff --git a/third_party/liteeth b/third_party/liteeth index 33afda74..937c2407 160000 --- a/third_party/liteeth +++ b/third_party/liteeth @@ -1 +1 @@ -Subproject commit 33afda74f77f7bafa3e4e19641b9043320c47e4e +Subproject commit 937c2407276371d9f8c1bb19c4ae8e97e581da83 diff --git a/third_party/litepcie b/third_party/litepcie index 8bc328f7..c836c467 160000 --- a/third_party/litepcie +++ b/third_party/litepcie @@ -1 +1 @@ -Subproject commit 8bc328f723c5923835c16671ac764a5060f79ba2 +Subproject commit c836c467b8d086c7ade23a45557644e4620a4bdc diff --git a/third_party/litesata b/third_party/litesata index a559afb2..c3d49155 160000 --- a/third_party/litesata +++ b/third_party/litesata @@ -1 +1 @@ -Subproject commit a559afb2c53932f29ecc4cec8aa394d1004377c1 +Subproject commit c3d491552cc77312bbadf6488c08e1e3df9612ef diff --git a/third_party/litescope b/third_party/litescope index 9d5e605d..d5887a3e 160000 --- a/third_party/litescope +++ b/third_party/litescope @@ -1 +1 @@ -Subproject commit 9d5e605df3e5f1d54609acc5a2f10764045127e9 +Subproject commit d5887a3eb0de105cfc55e52fbeb9de9da035e7db diff --git a/third_party/liteusb b/third_party/liteusb index 23d6a684..7a17876b 160000 --- a/third_party/liteusb +++ b/third_party/liteusb @@ -1 +1 @@ -Subproject commit 23d6a6840d4276f8d1a7f31bafb8d0aaaecff6d1 +Subproject commit 7a17876bc7f8943a2a0b500e4c1cb1e454c680b6 diff --git a/third_party/litevideo b/third_party/litevideo index 9b4169d5..cd44e3f1 160000 --- a/third_party/litevideo +++ b/third_party/litevideo @@ -1 +1 @@ -Subproject commit 9b4169d5d1e2c400a86ea0cbdb800730d84dc40b +Subproject commit cd44e3f14cd3042a948170d43c21919b00c3c35d diff --git a/third_party/litex b/third_party/litex index b7f7c8d1..56ef2290 160000 --- a/third_party/litex +++ b/third_party/litex @@ -1 +1 @@ -Subproject commit b7f7c8d159a53be0dbb713b86c658c3b79e023cb +Subproject commit 56ef22902926e5edfdb524a064804823fe449502