From a33f660026a08bed477bce550a9777a21f6d5159 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 30 Mar 2017 22:33:12 -0400 Subject: [PATCH 01/32] Cherry-pick flash files from arty-soc branch. Add SPI flash bitbang test. --- firmware/Makefile | 1 + firmware/ci.c | 8 ++++++++ firmware/flash.c | 31 +++++++++++++++++++++++++++++-- firmware/flash.h | 1 + 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 1076a6f8..91409c0d 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 \ diff --git a/firmware/ci.c b/firmware/ci.c index a8fdddb2..d02a14ed 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"); +#ifdef CSR_SPIFLASH_BASE + 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"); @@ -1266,6 +1270,10 @@ void ci_service(void) #endif if(found == 0) wprintf("%s port has no EDID capabilities\r\n", token); +#ifdef CSR_SPIFLASH_BASE + } else if(strcmp(token, "spiflash") == 0) { + bitbang_test(); +#endif #ifdef CSR_CAS_BASE } else if(strcmp(token, "cas") == 0) { token = get_token(&str); diff --git a/firmware/flash.c b/firmware/flash.c index ed3e1c8d..d30c58f6 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -1,4 +1,5 @@ #include +#include #ifdef SPIFLASH_PAGE_SIZE #include "flash.h" @@ -7,6 +8,7 @@ #include #include #include +#include #include "ci.h" @@ -53,7 +55,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 +63,29 @@ void flash_test(void) { mr(0x20000000, test_size); } -#endif \ No newline at end of file +void bitbang_test(void) { + unsigned int *flashbase; + unsigned int length; + unsigned int *free_start; + unsigned int free_space; + int i = 0; + + unsigned int buf[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[i] = ~(*(free_start + i)); + } + + write_to_flash((unsigned int) free_start, (unsigned char *) buf, 512); + mr((unsigned int) free_start, 512); +} + +#endif diff --git a/firmware/flash.h b/firmware/flash.h index 8e09be7a..7e1b4b31 100644 --- a/firmware/flash.h +++ b/firmware/flash.h @@ -2,5 +2,6 @@ #define __FLASH_H void flash_test(void); +void bitbang_test(void); #endif /* __FLASH_H */ From afb11eff9351b063673479665fd576a84918f907 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 30 Mar 2017 21:57:33 -0400 Subject: [PATCH 02/32] Add erase free area to bitbang test. --- firmware/flash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/flash.c b/firmware/flash.c index d30c58f6..ce3b1b42 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -86,6 +86,7 @@ void bitbang_test(void) { write_to_flash((unsigned int) free_start, (unsigned char *) buf, 512); mr((unsigned int) free_start, 512); + erase_flash_sector((unsigned int) free_start); } #endif From 0662522489d92822e292a608f09038e53fda2cfc Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 30 Mar 2017 21:58:09 -0400 Subject: [PATCH 03/32] Flush data cache between reads in bitbang test. --- firmware/flash.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/flash.c b/firmware/flash.c index ce3b1b42..a59b1bc1 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "ci.h" @@ -85,6 +86,7 @@ void bitbang_test(void) { } write_to_flash((unsigned int) free_start, (unsigned char *) buf, 512); + flush_cpu_dcache(); mr((unsigned int) free_start, 512); erase_flash_sector((unsigned int) free_start); } From 13e75f1cd5f1d281ab8f8bf4b21cfb98de85ac6c Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 2 Apr 2017 00:07:02 -0400 Subject: [PATCH 04/32] Add non-zero write to spiflash debug. --- firmware/flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/flash.c b/firmware/flash.c index a59b1bc1..3f542fae 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -82,7 +82,7 @@ void bitbang_test(void) { mr((unsigned int) free_start, 512); for(i = 0; i < 512; i++) { - buf[i] = ~(*(free_start + i)); + buf[i] = (unsigned int) i; } write_to_flash((unsigned int) free_start, (unsigned char *) buf, 512); From f435a0dc956e38a2adaf67a4e80a255e46e021eb Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 2 Apr 2017 01:50:38 -0400 Subject: [PATCH 05/32] Fix include guard for flash bitbang interface. --- firmware/flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/flash.c b/firmware/flash.c index 3f542fae..5453ce24 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -1,6 +1,6 @@ #include #include -#ifdef SPIFLASH_PAGE_SIZE +#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) #include "flash.h" #include From 0cfbf8517cf44546e4298cb13901df0faa990b79 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 4 Aug 2017 18:48:36 -0400 Subject: [PATCH 06/32] Add stub xmodem/sfl implementation. --- firmware/ci.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++- firmware/flash.c | 40 +++++++++++++++++++--- firmware/flash.h | 5 +++ 3 files changed, 126 insertions(+), 5 deletions(-) diff --git a/firmware/ci.c b/firmware/ci.c index d02a14ed..17294e51 100644 --- a/firmware/ci.c +++ b/firmware/ci.c @@ -186,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"); @@ -227,6 +236,7 @@ static void ci_help(void) wputs(""); #endif help_debug(); + help_write(); } static char *readstr(void) @@ -974,6 +984,68 @@ 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; + unsigned long addr; + unsigned long len; + unsigned long crc; + + + token = get_token(&str); + + if(strcmp(token, "xmodem") == 0) { + NEXT_TOKEN_OR_RETURN(str, token, "Invalid address."); + addr = atoi(token); + + NEXT_TOKEN_OR_RETURN(str, token, "Invalid length."); + len = atoi(token); + + // Get CRC anyway to consume the entire line just in case, but ignore it. + get_token(&str); + (void) crc; + + wprintf("Will use xmodem with addr %lX, len %ld.\r\n", addr, len); + rc = write_xmodem(addr, len); + } + else if(strcmp(token, "sfl") == 0) { + NEXT_TOKEN_OR_RETURN(str, token, "Invalid address."); + addr = atoi(token); + + NEXT_TOKEN_OR_RETURN(str, token, "Invalid length."); + len = atoi(token); + + NEXT_TOKEN_OR_RETURN(str, token, "Invalid CRC."); + crc = atoi(token); + + wprintf("Will use sfl with addr %lX, len %ld, and crc %lX.\r\n", addr, len, crc); + rc = write_sfl(addr, len, crc); + } + else { + wprintf("Protocol not supported.\r\n"); + return; + } + + 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"); + + return; +} +#endif + void ci_prompt(void) { wprintf("H2U %s>", uptime_str()); @@ -1022,6 +1094,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(""); @@ -1303,7 +1377,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 5453ce24..98fbd007 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -6,15 +6,18 @@ #include #include #include +#include #include #include #include #include #include "ci.h" - #define test_size 1024 +static char bitbang_buffer[128*1024]; +static char bus_buffer[128*1024]; +static char xmodem_buffer[1027]; #define NUMBER_OF_BYTES_ON_A_LINE 16 static void dump_bytes(unsigned int *ptr, int count, unsigned addr) @@ -71,7 +74,8 @@ void bitbang_test(void) { unsigned int free_space; int i = 0; - unsigned int buf[512]; + unsigned int buf_w[512]; + unsigned int buf_r[512]; flashbase = (unsigned int *)FLASH_BOOT_ADDRESS; length = *flashbase++; @@ -82,13 +86,41 @@ void bitbang_test(void) { mr((unsigned int) free_start, 512); for(i = 0; i < 512; i++) { - buf[i] = (unsigned int) i; + buf_w[i] = (unsigned int) ( (i << 8) | i ); } - write_to_flash((unsigned int) free_start, (unsigned char *) buf, 512); + 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); } + +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 21 +#define CAN 24 + +// Abbreviated xmodem. +int write_xmodem(unsigned long addr, unsigned long len) { + return 0; +} + + +int write_sfl(unsigned long addr, unsigned long len, unsigned long crc) { + return 0; +} + #endif diff --git a/firmware/flash.h b/firmware/flash.h index 7e1b4b31..60838e4f 100644 --- a/firmware/flash.h +++ b/firmware/flash.h @@ -4,4 +4,9 @@ void flash_test(void); void bitbang_test(void); +#ifdef CSR_UART_BASE +int write_xmodem(unsigned long addr, unsigned long len); +int write_sfl(unsigned long addr, unsigned long len, unsigned long crc); +#endif + #endif /* __FLASH_H */ From 72a4bce82fd6bba71a7ecf602a2c9f6ac0c80e6b Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 4 Aug 2017 23:51:01 -0400 Subject: [PATCH 07/32] Add XMODEM implementation for SPI (currently nonfunctional). --- firmware/flash.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 302 insertions(+), 1 deletion(-) diff --git a/firmware/flash.c b/firmware/flash.c index 98fbd007..ae8ee68f 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -4,8 +4,10 @@ #include "flash.h" #include +#include #include #include +#include #include #include #include @@ -17,7 +19,7 @@ static char bitbang_buffer[128*1024]; static char bus_buffer[128*1024]; -static char xmodem_buffer[1027]; +static char xmodem_buffer[1029]; #define NUMBER_OF_BYTES_ON_A_LINE 16 static void dump_bytes(unsigned int *ptr, int count, unsigned addr) @@ -106,6 +108,16 @@ void bitbang_test(void) { } +// 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 + + #define SOH 1 #define STX 2 #define EOT 4 @@ -113,12 +125,301 @@ void bitbang_test(void) { #define NAK 21 #define CAN 24 +static inline unsigned short generate_crc(char * data, size_t size) +{ + const unsigned int crc_poly = 0x1021; + unsigned int crc = 0x0000; + + for(unsigned int octet_count = 0; octet_count < size; octet_count++) + { + crc = (crc ^ (unsigned int) (data[octet_count] & (0xFF)) << 8); + for(unsigned int bit_count = 1; bit_count <= 8; bit_count++) + { + if(crc & 0x8000) + { + crc = (crc << 1) ^ crc_poly; + } + else + { + crc <<= 1; + } + } + } + return crc; +} + + +// Return: +// 0- Read was okay. +// 1- We timed out. +static int recv_with_timeout(unsigned int timeout, char * recvd) { + // Software-based timeout for now while QEMU timer is broken. + // 1/100th of clock frequency worked well for me. + for(unsigned int i = 0; i < CONFIG_CLOCK_FREQUENCY/100; i++) { + for(unsigned int j = 0; j < timeout; j++) { + //printf("%d, %d", i, j); + if(uart_read_nonblock()) { + *recvd = uart_read(); + return 0; + } + } + } + + return -1; +} + + +// Clear UART buffer until timeout occurs. +static void purge_uart_buffer(void) { + char dummy; + while(recv_with_timeout(1, &dummy) == 0); +} + + +// Return +// 0- Recv okay +// -1- Transmitter timed out +// -2- Using 1k and checksum- This doesn't make sense. +// Full packet (including already filled start char) should be +// passed into this function. +static int recv_packet_with_timeout(char * packet, int using_crc, int using_1k) { + int bytes_total = 3; // 2 bytes for block number and ones-compl + + if(using_crc) { + bytes_total += 2; + } else { + bytes_total += 1; + } + + if(using_1k) { + if(using_crc) { + return -2; + } else { + bytes_total += 1024; + } + } else { + bytes_total += 128; + } + + for(int i = 1; i < bytes_total; i++) { + char xmit; + + if(recv_with_timeout(1, &xmit) == -1) { + return -1; + } else { + packet[i] = xmit; + } + } + + return 0; +} + +// Return codes: +// 128 or 1024 +// -1- Invalid config +static inline int payload_len(int using_crc, int using_1k) { + if(using_1k) { + if(using_crc) { + return -1; + } else { + return 1024; + } + } else { + return 128; + } +} + + +// Return codes: +// 1- Previous block was resent- everything else okay. +// 0- All is okay +// -1- Invalid configuration +// -2- Block mismatch in header +// -3- Unexpected block +// -4- Bad CRC/Checksum +static inline int verify_packet(char * packet, unsigned char expected_block, int using_crc, int using_1k) { + int rc = 0; + + if(packet[1] == (expected_block - 1)) { + rc = 1; + } else if(packet[1] == expected_block) { + rc = 0; // Do nothing + } else { + return -3; + } + + if(!(packet[1] == !packet[2])) { + return -2; + } + + if(using_crc) { + if(!(generate_crc(&packet[3], payload_len(using_crc, using_1k) == 0))) { + return -4; + } + } else { + return -4; // Not implemented yet + } + + return rc; +} + + // Abbreviated xmodem. int write_xmodem(unsigned long addr, unsigned long len) { + int using_1k = 0; + int using_crc = 1; + int initial_retries = 0; + unsigned int data_offset = 0; + unsigned char expected_block = 1; + + // Initial handshake + for(initial_retries = 0; initial_retries < 10; initial_retries++) { + char first; + char send = using_crc ? 'C' : NAK; + uart_write(send); + int res = recv_with_timeout(10, &first); + + if(res == 0) { + switch(first) { + case SOH: + xmodem_buffer[0] = first; + goto initial_handshake_over; + break; + case STX: + xmodem_buffer[0] = first; + using_1k = 1; + goto initial_handshake_over; + break; + default: + // Unexpected/invalid char. + purge_uart_buffer(); + break; + } + } + + // Switch to checksum mode after three timeouts. + if(initial_retries == 3) { + using_crc = 0; // Only set here. + } + } + +initial_handshake_over: + if(initial_retries >= 10) { + return -1; + } + + int initial_handshake_occurred = 1; + int done = 0; + int num_errors = 0; + char send_code; + while(!done) { + // Skip this the first time around. For control flow purposes + // It makes sense to keep it at top of while loop. + if(!initial_handshake_occurred) { + int res; + char first; + + if(num_errors >= 10) { + send_code = CAN; + } + + // Subsequent handshakes + if(send_code == NAK) + { + purge_uart_buffer(); + } + + uart_write(send_code); + if(send_code == CAN) { + return -1; + } else { + res = recv_with_timeout(10, &first); + } + + if(res == 0) { + switch(first) { + case SOH: + xmodem_buffer[0] = first; + break; + case STX: + xmodem_buffer[0] = first; + using_1k = 1; + break; + case EOT: + done = 1; + continue; + default: + // Unexpected/invalid char. + send_code = NAK; + num_errors++; + continue; + } + } else { + send_code = NAK; + num_errors++; + continue; + } + } + + if(initial_handshake_occurred) { + initial_handshake_occurred = 0; + } + + + // Subsequent receives + int recv_rc = recv_packet_with_timeout(xmodem_buffer, using_crc, using_1k); + switch(recv_rc) { + case 0: + break; + case -2: + send_code = CAN; + num_errors++; + continue; + case -1: + default: + send_code = NAK; + num_errors++; + continue; + } + + int ver_rc = verify_packet(xmodem_buffer, expected_block, using_crc, using_1k); + switch(ver_rc) { + case 0: + // Assuming !using_crc && using_1k is impossible. + { + int len = payload_len(using_crc, using_1k); + memcpy(bus_buffer + data_offset + len, xmodem_buffer + 3, len); + data_offset += len; + } + send_code = ACK; + expected_block++; + break; + case 1: // Last block was resent. Nothing to do. + send_code = ACK; + break; + case -1: + case -3: + send_code = CAN; + num_errors++; + continue; + case -2: + case -4: + default: + send_code = NAK; + num_errors++; + continue; + } + + // Every time we successfully send a packet, reset error count. + num_errors = 0; + } + return 0; } + + int write_sfl(unsigned long addr, unsigned long len, unsigned long crc) { return 0; } From 8ca8ed805a8051e9d7802df8c6d7cf5860f0b77c Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 18 Aug 2017 14:37:23 -0400 Subject: [PATCH 08/32] Integrate libmodem as submodule (library link compiles). --- .gitmodules | 3 +++ Makefile | 8 +++++++- firmware/Makefile | 15 ++++++++++++--- third_party/libmodem | 1 + 4 files changed, 23 insertions(+), 4 deletions(-) create mode 160000 third_party/libmodem diff --git a/.gitmodules b/.gitmodules index f2a04704..856c0dc9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [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 diff --git a/Makefile b/Makefile index 8c937e05..c11664db 100644 --- a/Makefile +++ b/Makefile @@ -163,7 +163,11 @@ gateware-clean: # Firmware - the stuff which runs in the soft CPU inside the FPGA. # -------------------------------------- -firmware-cmd: +FIRMWARE_MODULES=libmodem +firmware-submodules: $(addsuffix /.git,$(addprefix third_party/,$(FIRMWARE_MODULES))) + @true + +firmware-cmd: firmware-submodules mkdir -p $(TARGET_BUILD_DIR) ifneq ($(OS),Windows_NT) $(MAKE_CMD) --no-compile-gateware \ @@ -199,6 +203,7 @@ firmware-clear: firmware-clear-$(PLATFORM) .PHONY: firmware-load-$(PLATFORM) firmware-flash-$(PLATFORM) firmware-connect-$(PLATFORM) firmware-clear-$(PLATFORM) firmware-clean: + cd third_party/libmodem && scons TARGET_OS=hdmi2usb-lm32 HDMI2USB_BUILD=$(PWD)/$(TARGET_BUILD_DIR) -c rm -rf $(TARGET_BUILD_DIR)/software .PHONY: firmware-cmd $(FIRMWARE_FILEBASE).bin firmware firmware-load firmware-flash firmware-connect firmware-clean @@ -353,6 +358,7 @@ reset: reset-$(PLATFORM) clean: rm build/cache.mk + cd third_party/libmodem && scons TARGET_OS=hdmi2usb-lm32 HDMI2USB_BUILD=$(PWD)/$(TARGET_BUILD_DIR) -c rm -rf $(TARGET_BUILD_DIR) py3clean . || rm -rf $$(find -name __pycache__) diff --git a/firmware/Makefile b/firmware/Makefile index 91409c0d..fe46c3c5 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -16,6 +16,9 @@ CFLAGS += -DPLATFORM_$(UPLATFORM) -DTARGET_$(UTARGET) BUILD_DIRECTORY=$(BUILDINC_DIRECTORY)/../../ FIRMBUILD_DIRECTORY=$(BUILD_DIRECTORY)/software/firmware +LIBMODEM_DIR=../../../../third_party/libmodem +LIBMODEM=$(LIBMODEM_DIR)/build/hdmi2usb-lm32/libmodem.a + OBJECTS=\ bist.o \ ci.o \ @@ -53,7 +56,8 @@ OBJECTS=\ CFLAGS += \ -I$(FIRMWARE_DIRECTORY) \ - -I$(BUILD_DIRECTORY)/software/firmware + -I$(BUILD_DIRECTORY)/software/firmware \ + -I$(LIBMODEM_DIR)/src CFLAGS += \ -Wall \ @@ -75,7 +79,7 @@ all: firmware.bin firmware.fbi $(OBJCOPY) -O binary $< $@ chmod -x $@ -firmware.elf: $(FIRMWARE_DIRECTORY)/linker.ld $(OBJECTS) +firmware.elf: $(FIRMWARE_DIRECTORY)/linker.ld $(OBJECTS) $(LIBMODEM) %.elf: ../libbase/crt0-$(CPU).o ../libbase/libbase-nofloat.a ../libcompiler_rt/libcompiler_rt.a ../uip/libuip.a $(LD) $(LDFLAGS) \ @@ -88,7 +92,9 @@ firmware.elf: $(FIRMWARE_DIRECTORY)/linker.ld $(OBJECTS) -L../libcompiler_rt \ -lcompiler_rt \ -L../uip \ - -luip + -luip \ + -L$(LIBMODEM_DIR)/build/hdmi2usb-lm32 \ + -lmodem chmod -x $@ # pull in dependency info for *existing* .o files @@ -133,4 +139,7 @@ $(FIRMBUILD_DIRECTORY)/hdmi_in1.c: $(FIRMWARE_DIRECTORY)/hdmi_in0.c $(FIRMWARE_D # Check the files exist [ -e $(FIRMBUILD_DIRECTORY)/hdmi_in1.c ] +$(LIBMODEM): + cd $(LIBMODEM_DIR) && scons TARGET_OS=hdmi2usb-lm32 BUILD_TYPE=Release HDMI2USB_BUILD=$(BUILD_DIRECTORY) + .PHONY: all clean libs version_data diff --git a/third_party/libmodem b/third_party/libmodem new file mode 160000 index 00000000..e3603ead --- /dev/null +++ b/third_party/libmodem @@ -0,0 +1 @@ +Subproject commit e3603ead3525d70a316c7d6add50542a42a54d6d From 9d90b0fb3b706c1bba8e78f12064c60f7cd829a2 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 18 Aug 2017 23:35:18 -0400 Subject: [PATCH 09/32] Ensure rebuild of libmodem if contents change. --- firmware/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index fe46c3c5..95ff5543 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -139,7 +139,7 @@ $(FIRMBUILD_DIRECTORY)/hdmi_in1.c: $(FIRMWARE_DIRECTORY)/hdmi_in0.c $(FIRMWARE_D # Check the files exist [ -e $(FIRMBUILD_DIRECTORY)/hdmi_in1.c ] -$(LIBMODEM): +$(LIBMODEM): $(LIBMODEM_DIR)/src/*.c cd $(LIBMODEM_DIR) && scons TARGET_OS=hdmi2usb-lm32 BUILD_TYPE=Release HDMI2USB_BUILD=$(BUILD_DIRECTORY) .PHONY: all clean libs version_data From 36baad5404bedbd9dc6f41d7e225d365cd1da017 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 18 Aug 2017 23:35:35 -0400 Subject: [PATCH 10/32] Start integrating libmodem into firmware. --- firmware/flash.c | 325 +++++------------------------------------------ 1 file changed, 35 insertions(+), 290 deletions(-) diff --git a/firmware/flash.c b/firmware/flash.c index ae8ee68f..f73e68ff 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -15,11 +15,23 @@ #include #include "ci.h" +#include +#include + #define test_size 1024 -static char bitbang_buffer[128*1024]; -static char bus_buffer[128*1024]; -static char xmodem_buffer[1029]; +static unsigned char __attribute__ ((section ("main_ram"))) bitbang_buffer[128*1024]; +static unsigned char __attribute__ ((section ("main_ram"))) bus_buffer[128*1024]; +static unsigned char xmodem_buffer[1029]; + +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); #define NUMBER_OF_BYTES_ON_A_LINE 16 static void dump_bytes(unsigned int *ptr, int count, unsigned addr) @@ -118,310 +130,43 @@ void bitbang_test(void) { // XMODEM helpers -#define SOH 1 -#define STX 2 -#define EOT 4 -#define ACK 6 -#define NAK 21 -#define CAN 24 +int write_to_buf(const char * buf, const int buf_size, const int eof, void * const chan_state) { + flash_writer_t * writer = chan_state; -static inline unsigned short generate_crc(char * data, size_t size) -{ - const unsigned int crc_poly = 0x1021; - unsigned int crc = 0x0000; - - for(unsigned int octet_count = 0; octet_count < size; octet_count++) - { - crc = (crc ^ (unsigned int) (data[octet_count] & (0xFF)) << 8); - for(unsigned int bit_count = 1; bit_count <= 8; bit_count++) - { - if(crc & 0x8000) - { - crc = (crc << 1) ^ crc_poly; - } - else - { - crc <<= 1; - } - } - } - return crc; -} + int space_left = writer->buflen - writer->bufpos; + int size_sent = space_left < buf_size ? space_left : buf_size; + memcpy(writer->buf, buf, size_sent); -// Return: -// 0- Read was okay. -// 1- We timed out. -static int recv_with_timeout(unsigned int timeout, char * recvd) { - // Software-based timeout for now while QEMU timer is broken. - // 1/100th of clock frequency worked well for me. - for(unsigned int i = 0; i < CONFIG_CLOCK_FREQUENCY/100; i++) { - for(unsigned int j = 0; j < timeout; j++) { - //printf("%d, %d", i, j); - if(uart_read_nonblock()) { - *recvd = uart_read(); - return 0; - } - } - } - - return -1; + writer->bufpos += size_sent; + return size_sent; } +int write_xmodem(unsigned long addr, unsigned long len) { + flash_writer_t writer = { bitbang_buffer, len, 0, sizeof(bitbang_buffer)/sizeof(bitbang_buffer[0]) }; + serial_handle_t uart; -// Clear UART buffer until timeout occurs. -static void purge_uart_buffer(void) { char dummy; - while(recv_with_timeout(1, &dummy) == 0); -} + serial_init(0, 0, &uart); + serial_flush(uart); + int xrc = xmodem_rx(write_to_buf, xmodem_buffer, &writer, uart, XMODEM_1K); -// Return -// 0- Recv okay -// -1- Transmitter timed out -// -2- Using 1k and checksum- This doesn't make sense. -// Full packet (including already filled start char) should be -// passed into this function. -static int recv_packet_with_timeout(char * packet, int using_crc, int using_1k) { - int bytes_total = 3; // 2 bytes for block number and ones-compl - - if(using_crc) { - bytes_total += 2; - } else { - bytes_total += 1; - } - - if(using_1k) { - if(using_crc) { - return -2; - } else { - bytes_total += 1024; - } - } else { - bytes_total += 128; - } + /* char data[] = "C"; + for(int count = 0; count < 10; count++) + { + serial_rcv(&dummy, 1, 1, NULL, uart); + serial_snd(data, 1, uart); + } */ - for(int i = 1; i < bytes_total; i++) { - char xmit; - - if(recv_with_timeout(1, &xmit) == -1) { - return -1; - } else { - packet[i] = xmit; - } - } - return 0; } -// Return codes: -// 128 or 1024 -// -1- Invalid config -static inline int payload_len(int using_crc, int using_1k) { - if(using_1k) { - if(using_crc) { - return -1; - } else { - return 1024; - } - } else { - return 128; - } -} - - -// Return codes: -// 1- Previous block was resent- everything else okay. -// 0- All is okay -// -1- Invalid configuration -// -2- Block mismatch in header -// -3- Unexpected block -// -4- Bad CRC/Checksum -static inline int verify_packet(char * packet, unsigned char expected_block, int using_crc, int using_1k) { - int rc = 0; - - if(packet[1] == (expected_block - 1)) { - rc = 1; - } else if(packet[1] == expected_block) { - rc = 0; // Do nothing - } else { - return -3; - } - - if(!(packet[1] == !packet[2])) { - return -2; - } - - if(using_crc) { - if(!(generate_crc(&packet[3], payload_len(using_crc, using_1k) == 0))) { - return -4; - } - } else { - return -4; // Not implemented yet - } - - return rc; -} - - -// Abbreviated xmodem. -int write_xmodem(unsigned long addr, unsigned long len) { - int using_1k = 0; - int using_crc = 1; - int initial_retries = 0; - unsigned int data_offset = 0; - unsigned char expected_block = 1; - - // Initial handshake - for(initial_retries = 0; initial_retries < 10; initial_retries++) { - char first; - char send = using_crc ? 'C' : NAK; - uart_write(send); - int res = recv_with_timeout(10, &first); - - if(res == 0) { - switch(first) { - case SOH: - xmodem_buffer[0] = first; - goto initial_handshake_over; - break; - case STX: - xmodem_buffer[0] = first; - using_1k = 1; - goto initial_handshake_over; - break; - default: - // Unexpected/invalid char. - purge_uart_buffer(); - break; - } - } - - // Switch to checksum mode after three timeouts. - if(initial_retries == 3) { - using_crc = 0; // Only set here. - } - } - -initial_handshake_over: - if(initial_retries >= 10) { - return -1; - } - - int initial_handshake_occurred = 1; - int done = 0; - int num_errors = 0; - char send_code; - while(!done) { - // Skip this the first time around. For control flow purposes - // It makes sense to keep it at top of while loop. - if(!initial_handshake_occurred) { - int res; - char first; - - if(num_errors >= 10) { - send_code = CAN; - } - - // Subsequent handshakes - if(send_code == NAK) - { - purge_uart_buffer(); - } - - uart_write(send_code); - if(send_code == CAN) { - return -1; - } else { - res = recv_with_timeout(10, &first); - } - - if(res == 0) { - switch(first) { - case SOH: - xmodem_buffer[0] = first; - break; - case STX: - xmodem_buffer[0] = first; - using_1k = 1; - break; - case EOT: - done = 1; - continue; - default: - // Unexpected/invalid char. - send_code = NAK; - num_errors++; - continue; - } - } else { - send_code = NAK; - num_errors++; - continue; - } - } - - if(initial_handshake_occurred) { - initial_handshake_occurred = 0; - } - - - // Subsequent receives - int recv_rc = recv_packet_with_timeout(xmodem_buffer, using_crc, using_1k); - switch(recv_rc) { - case 0: - break; - case -2: - send_code = CAN; - num_errors++; - continue; - case -1: - default: - send_code = NAK; - num_errors++; - continue; - } - - int ver_rc = verify_packet(xmodem_buffer, expected_block, using_crc, using_1k); - switch(ver_rc) { - case 0: - // Assuming !using_crc && using_1k is impossible. - { - int len = payload_len(using_crc, using_1k); - memcpy(bus_buffer + data_offset + len, xmodem_buffer + 3, len); - data_offset += len; - } - send_code = ACK; - expected_block++; - break; - case 1: // Last block was resent. Nothing to do. - send_code = ACK; - break; - case -1: - case -3: - send_code = CAN; - num_errors++; - continue; - case -2: - case -4: - default: - send_code = NAK; - num_errors++; - continue; - } - - // Every time we successfully send a packet, reset error count. - num_errors = 0; - } - +int write_sfl(unsigned long addr, unsigned long len, unsigned long crc) { return 0; } -int write_sfl(unsigned long addr, unsigned long len, unsigned long crc) { - return 0; -} - #endif From beb0f356a50c58813076ebcf1b9820e6d7fdaaff Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 19 Aug 2017 20:19:57 -0400 Subject: [PATCH 11/32] XMODEM xfers now succeed with libmodem. Update libmodem submodule. --- firmware/ci.c | 2 ++ firmware/flash.c | 21 +++++++++++---------- third_party/libmodem | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/firmware/ci.c b/firmware/ci.c index 17294e51..acffcaff 100644 --- a/firmware/ci.c +++ b/firmware/ci.c @@ -1041,6 +1041,8 @@ static void write_spi(char* str) 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; } diff --git a/firmware/flash.c b/firmware/flash.c index f73e68ff..eb19fa88 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -146,18 +146,19 @@ int write_xmodem(unsigned long addr, unsigned long len) { flash_writer_t writer = { bitbang_buffer, len, 0, sizeof(bitbang_buffer)/sizeof(bitbang_buffer[0]) }; serial_handle_t uart; - char dummy; + //if(addr < FLASH_BOOT_ADDRESS || addr > ) serial_init(0, 0, &uart); - serial_flush(uart); - int xrc = xmodem_rx(write_to_buf, xmodem_buffer, &writer, uart, XMODEM_1K); - - /* char data[] = "C"; - for(int count = 0; count < 10; count++) - { - serial_rcv(&dummy, 1, 1, NULL, uart); - serial_snd(data, 1, uart); - } */ + int rc = xmodem_rx(write_to_buf, xmodem_buffer, &writer, uart, XMODEM_1K); + serial_close(&uart); + + if(rc != MODEM_NO_ERRORS) { + return -1; + } + + memcpy(bus_buffer, (void *) FLASH_BOOT_ADDRESS, len); + mr((unsigned int) &bus_buffer[0], 512); + mr((unsigned int) &bitbang_buffer[0], 512); return 0; } diff --git a/third_party/libmodem b/third_party/libmodem index e3603ead..316bb2e2 160000 --- a/third_party/libmodem +++ b/third_party/libmodem @@ -1 +1 @@ -Subproject commit e3603ead3525d70a316c7d6add50542a42a54d6d +Subproject commit 316bb2e270b3e0b9f1bec6478a6c3a2d63d0d804 From 61c0b008f113cfb93d001f913cec049b0c400a68 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 19 Aug 2017 20:36:19 -0400 Subject: [PATCH 12/32] CRC token required for all xfer modes; BIOS uses it. --- firmware/ci.c | 7 +++---- firmware/flash.c | 6 ++++-- firmware/flash.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/firmware/ci.c b/firmware/ci.c index acffcaff..491def17 100644 --- a/firmware/ci.c +++ b/firmware/ci.c @@ -1010,12 +1010,11 @@ static void write_spi(char* str) NEXT_TOKEN_OR_RETURN(str, token, "Invalid length."); len = atoi(token); - // Get CRC anyway to consume the entire line just in case, but ignore it. - get_token(&str); - (void) crc; + NEXT_TOKEN_OR_RETURN(str, token, "Invalid CRC."); + crc = atoi(token); wprintf("Will use xmodem with addr %lX, len %ld.\r\n", addr, len); - rc = write_xmodem(addr, len); + rc = write_xmodem(addr, len, crc); } else if(strcmp(token, "sfl") == 0) { NEXT_TOKEN_OR_RETURN(str, token, "Invalid address."); diff --git a/firmware/flash.c b/firmware/flash.c index eb19fa88..fab1d4eb 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -142,10 +142,12 @@ int write_to_buf(const char * buf, const int buf_size, const int eof, void * con return size_sent; } -int write_xmodem(unsigned long addr, unsigned long len) { - flash_writer_t writer = { bitbang_buffer, len, 0, sizeof(bitbang_buffer)/sizeof(bitbang_buffer[0]) }; +int write_xmodem(unsigned long addr, unsigned long len, unsigned long crc) { + flash_writer_t writer = { bitbang_buffer + 8, len, 0, sizeof(bitbang_buffer)/sizeof(bitbang_buffer[0]) }; serial_handle_t uart; + memcpy((void *) bitbang_buffer + 0, &len, sizeof(unsigned int)); + memcpy((void *) bitbang_buffer + 4, &crc, sizeof(unsigned int)); //if(addr < FLASH_BOOT_ADDRESS || addr > ) serial_init(0, 0, &uart); diff --git a/firmware/flash.h b/firmware/flash.h index 60838e4f..eb40131f 100644 --- a/firmware/flash.h +++ b/firmware/flash.h @@ -5,7 +5,7 @@ void flash_test(void); void bitbang_test(void); #ifdef CSR_UART_BASE -int write_xmodem(unsigned long addr, unsigned long len); +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 From f6d4830a28d2a3206258263b7b39782d3648f22c Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 19 Aug 2017 22:20:02 -0400 Subject: [PATCH 13/32] Move .bss to main_ram so file buffers fit. --- firmware/flash.c | 4 ++-- firmware/linker.ld | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/flash.c b/firmware/flash.c index fab1d4eb..b9b73a30 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -20,8 +20,8 @@ #define test_size 1024 -static unsigned char __attribute__ ((section ("main_ram"))) bitbang_buffer[128*1024]; -static unsigned char __attribute__ ((section ("main_ram"))) bus_buffer[128*1024]; +static unsigned char bitbang_buffer[128*1024]; +static unsigned char bus_buffer[128*1024]; static unsigned char xmodem_buffer[1029]; typedef struct flash_writer { 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); From 3ccd4862504b50430e8f6be4357b50d69a4e0252 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 19 Aug 2017 22:38:58 -0400 Subject: [PATCH 14/32] Allow hex values for write commands. --- firmware/ci.c | 33 ++++++++++++++++++++++++++------- firmware/flash.c | 8 ++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/firmware/ci.c b/firmware/ci.c index 491def17..f1400f38 100644 --- a/firmware/ci.c +++ b/firmware/ci.c @@ -996,6 +996,7 @@ static void write_spi(char* str) { char *token; int rc; + char * endptr; unsigned long addr; unsigned long len; unsigned long crc; @@ -1005,26 +1006,44 @@ static void write_spi(char* str) if(strcmp(token, "xmodem") == 0) { NEXT_TOKEN_OR_RETURN(str, token, "Invalid address."); - addr = atoi(token); + addr = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in address."); + } NEXT_TOKEN_OR_RETURN(str, token, "Invalid length."); - len = atoi(token); + len = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in length."); + } NEXT_TOKEN_OR_RETURN(str, token, "Invalid CRC."); - crc = atoi(token); + crc = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in CRC."); + } - wprintf("Will use xmodem with addr %lX, len %ld.\r\n", addr, len); + wprintf("Will use xmodem with addr %lX, len %ld and crc %lX.\r\n", addr, len, crc); rc = write_xmodem(addr, len, crc); } else if(strcmp(token, "sfl") == 0) { NEXT_TOKEN_OR_RETURN(str, token, "Invalid address."); - addr = atoi(token); + addr = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in address."); + } NEXT_TOKEN_OR_RETURN(str, token, "Invalid length."); - len = atoi(token); + len = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in length."); + } NEXT_TOKEN_OR_RETURN(str, token, "Invalid CRC."); - crc = atoi(token); + crc = strtoul(token, &endptr, 0); + if(*endptr != '\0') { + wprintf("Invalid chars in CRC."); + } wprintf("Will use sfl with addr %lX, len %ld, and crc %lX.\r\n", addr, len, crc); rc = write_sfl(addr, len, crc); diff --git a/firmware/flash.c b/firmware/flash.c index b9b73a30..60909d59 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -159,6 +159,14 @@ int write_xmodem(unsigned long addr, unsigned long len, unsigned long crc) { } memcpy(bus_buffer, (void *) FLASH_BOOT_ADDRESS, len); + + for(unsigned int count = 0; count < len; count++) { + if(bus_buffer[count] != bitbang_buffer[count]) { + wprintf("Comparison failed at offset %X\r\n", count) + return -2; + } + } + mr((unsigned int) &bus_buffer[0], 512); mr((unsigned int) &bitbang_buffer[0], 512); From 41d62786681e77d8a8db9ecacf67148a782b4a0a Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 20 Aug 2017 02:03:16 -0400 Subject: [PATCH 15/32] write_to_buf needs to move offset into buffer to avoid overwriting data. --- firmware/flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/flash.c b/firmware/flash.c index 60909d59..66c1b250 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -136,7 +136,7 @@ int write_to_buf(const char * buf, const int buf_size, const int eof, void * con int space_left = writer->buflen - writer->bufpos; int size_sent = space_left < buf_size ? space_left : buf_size; - memcpy(writer->buf, buf, size_sent); + memcpy(writer->buf + writer->bufpos, buf, size_sent); writer->bufpos += size_sent; return size_sent; From d99096eae2363cded6decfe5015a966701b345fc Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 20 Aug 2017 02:03:57 -0400 Subject: [PATCH 16/32] Do not write len/CRC; assume arbitrary data input. --- firmware/flash.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/firmware/flash.c b/firmware/flash.c index 66c1b250..c6fd9b51 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -143,13 +143,9 @@ int write_to_buf(const char * buf, const int buf_size, const int eof, void * con } int write_xmodem(unsigned long addr, unsigned long len, unsigned long crc) { - flash_writer_t writer = { bitbang_buffer + 8, len, 0, sizeof(bitbang_buffer)/sizeof(bitbang_buffer[0]) }; + flash_writer_t writer = { bitbang_buffer, len, 0, sizeof(bitbang_buffer)/sizeof(bitbang_buffer[0]) }; serial_handle_t uart; - memcpy((void *) bitbang_buffer + 0, &len, sizeof(unsigned int)); - memcpy((void *) bitbang_buffer + 4, &crc, sizeof(unsigned int)); - //if(addr < FLASH_BOOT_ADDRESS || addr > ) - serial_init(0, 0, &uart); int rc = xmodem_rx(write_to_buf, xmodem_buffer, &writer, uart, XMODEM_1K); serial_close(&uart); From ed8d2031f29631f21dc0787d8754dfe3dfd90b31 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 20 Aug 2017 02:05:33 -0400 Subject: [PATCH 17/32] write_xmodem() at arbitrary flash addresses is functional. --- firmware/flash.c | 59 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/firmware/flash.c b/firmware/flash.c index c6fd9b51..8a0e6a32 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -23,6 +23,8 @@ 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; @@ -154,17 +156,66 @@ int write_xmodem(unsigned long addr, unsigned long len, unsigned long crc) { return -1; } - memcpy(bus_buffer, (void *) FLASH_BOOT_ADDRESS, len); + // Do CRC check. Return if no match. + + 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(sector_buf_pre, (void *) sector_start, prepend_len); + memcpy(sector_buf_post, (void *) erase_end, append_len); + erase_flash_sector(sector_start); + printf("Write leading data.\r\n"); + write_to_flash(sector_start, sector_buf_pre, 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, sector_buf_post, 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(); + 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]) { - wprintf("Comparison failed at offset %X\r\n", 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; } } - mr((unsigned int) &bus_buffer[0], 512); - mr((unsigned int) &bitbang_buffer[0], 512); + /* 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; } From 86a116a2d814773d6d99ae636d778fe1bfdccaa8 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 20 Aug 2017 02:44:13 -0400 Subject: [PATCH 18/32] Mild refactor of SPI flash write code paths. --- firmware/ci.c | 78 ++++++++++++++++++++++-------------------------- firmware/flash.c | 67 ++++++++++++++++++++++------------------- 2 files changed, 72 insertions(+), 73 deletions(-) diff --git a/firmware/ci.c b/firmware/ci.c index f1400f38..dce67aa9 100644 --- a/firmware/ci.c +++ b/firmware/ci.c @@ -995,64 +995,58 @@ static void debug_ddr(void) static void write_spi(char* str) { char *token; - int rc; + 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) { - NEXT_TOKEN_OR_RETURN(str, token, "Invalid address."); - addr = strtoul(token, &endptr, 0); - if(*endptr != '\0') { - wprintf("Invalid chars in address."); - } - - NEXT_TOKEN_OR_RETURN(str, token, "Invalid length."); - len = strtoul(token, &endptr, 0); - if(*endptr != '\0') { - wprintf("Invalid chars in length."); - } - - NEXT_TOKEN_OR_RETURN(str, token, "Invalid CRC."); - crc = strtoul(token, &endptr, 0); - if(*endptr != '\0') { - wprintf("Invalid chars in CRC."); - } - - wprintf("Will use xmodem with addr %lX, len %ld and crc %lX.\r\n", addr, len, crc); - rc = write_xmodem(addr, len, crc); + use_xmodem = 1; + proto_str = "xmodem"; } else if(strcmp(token, "sfl") == 0) { - NEXT_TOKEN_OR_RETURN(str, token, "Invalid address."); - addr = strtoul(token, &endptr, 0); - if(*endptr != '\0') { - wprintf("Invalid chars in address."); - } - - NEXT_TOKEN_OR_RETURN(str, token, "Invalid length."); - len = strtoul(token, &endptr, 0); - if(*endptr != '\0') { - wprintf("Invalid chars in length."); - } - - NEXT_TOKEN_OR_RETURN(str, token, "Invalid CRC."); - crc = strtoul(token, &endptr, 0); - if(*endptr != '\0') { - wprintf("Invalid chars in CRC."); - } - - wprintf("Will use sfl with addr %lX, len %ld, and crc %lX.\r\n", addr, len, crc); - rc = write_sfl(addr, len, crc); + 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) diff --git a/firmware/flash.c b/firmware/flash.c index 8a0e6a32..09feac19 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -34,6 +34,7 @@ typedef struct flash_writer { } 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) @@ -158,37 +159,7 @@ int write_xmodem(unsigned long addr, unsigned long len, unsigned long crc) { // Do CRC check. Return if no match. - 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(sector_buf_pre, (void *) sector_start, prepend_len); - memcpy(sector_buf_post, (void *) erase_end, append_len); - erase_flash_sector(sector_start); - printf("Write leading data.\r\n"); - write_to_flash(sector_start, sector_buf_pre, 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, sector_buf_post, 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(); + 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"); @@ -224,6 +195,40 @@ 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(); +} + From 220a547c31608e23c5ee57922bbc52f6984f6958 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 20 Aug 2017 03:32:37 -0400 Subject: [PATCH 19/32] Add CRC32 support to upload (and helper script). --- firmware/flash.c | 9 +++++++++ getcrc32.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 getcrc32.py diff --git a/firmware/flash.c b/firmware/flash.c index 09feac19..50f44f19 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "ci.h" @@ -148,7 +149,9 @@ int write_to_buf(const char * buf, const int buf_size, const int eof, void * con 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); @@ -158,6 +161,12 @@ int write_xmodem(unsigned long addr, unsigned long len, unsigned long crc) { } // 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); 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() From ab9443ce13d3d472af299a64e4cf52d9b79c4ae4 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 24 Aug 2017 04:09:16 -0400 Subject: [PATCH 20/32] Bump third_party/libmodem up to documentation commits. --- third_party/libmodem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/libmodem b/third_party/libmodem index 316bb2e2..224b25b0 160000 --- a/third_party/libmodem +++ b/third_party/libmodem @@ -1 +1 @@ -Subproject commit 316bb2e270b3e0b9f1bec6478a6c3a2d63d0d804 +Subproject commit 224b25b0d4bd21a2490ddd60a26b12545993fa45 From 7dae4bc6fa200e16bc63006a0435d56e77b95bd9 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 6 Sep 2017 02:21:09 -0400 Subject: [PATCH 21/32] libmodem uses Meson build system now. Integrate libmodem build like libuip. --- firmware/Makefile | 12 +++--------- firmware/modem/Makefile | 17 +++++++++++++++++ firmware/modem/Makefile.mk | 5 +++++ firmware/modem/README.md | 12 ++++++++++++ make.py | 1 + third_party/libmodem | 2 +- 6 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 firmware/modem/Makefile create mode 100644 firmware/modem/Makefile.mk create mode 100644 firmware/modem/README.md diff --git a/firmware/Makefile b/firmware/Makefile index 95ff5543..d2e50af7 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -16,9 +16,6 @@ CFLAGS += -DPLATFORM_$(UPLATFORM) -DTARGET_$(UTARGET) BUILD_DIRECTORY=$(BUILDINC_DIRECTORY)/../../ FIRMBUILD_DIRECTORY=$(BUILD_DIRECTORY)/software/firmware -LIBMODEM_DIR=../../../../third_party/libmodem -LIBMODEM=$(LIBMODEM_DIR)/build/hdmi2usb-lm32/libmodem.a - OBJECTS=\ bist.o \ ci.o \ @@ -57,7 +54,6 @@ OBJECTS=\ CFLAGS += \ -I$(FIRMWARE_DIRECTORY) \ -I$(BUILD_DIRECTORY)/software/firmware \ - -I$(LIBMODEM_DIR)/src CFLAGS += \ -Wall \ @@ -67,6 +63,7 @@ CFLAGS += \ include $(UIP_DIRECTORY)/Makefile.mk +include $(MODEM_DIRECTORY)/Makefile.mk LDFLAGS += \ @@ -79,7 +76,7 @@ all: firmware.bin firmware.fbi $(OBJCOPY) -O binary $< $@ chmod -x $@ -firmware.elf: $(FIRMWARE_DIRECTORY)/linker.ld $(OBJECTS) $(LIBMODEM) +firmware.elf: $(FIRMWARE_DIRECTORY)/linker.ld $(OBJECTS) %.elf: ../libbase/crt0-$(CPU).o ../libbase/libbase-nofloat.a ../libcompiler_rt/libcompiler_rt.a ../uip/libuip.a $(LD) $(LDFLAGS) \ @@ -93,7 +90,7 @@ firmware.elf: $(FIRMWARE_DIRECTORY)/linker.ld $(OBJECTS) $(LIBMODEM) -lcompiler_rt \ -L../uip \ -luip \ - -L$(LIBMODEM_DIR)/build/hdmi2usb-lm32 \ + -L../modem \ -lmodem chmod -x $@ @@ -139,7 +136,4 @@ $(FIRMBUILD_DIRECTORY)/hdmi_in1.c: $(FIRMWARE_DIRECTORY)/hdmi_in0.c $(FIRMWARE_D # Check the files exist [ -e $(FIRMBUILD_DIRECTORY)/hdmi_in1.c ] -$(LIBMODEM): $(LIBMODEM_DIR)/src/*.c - cd $(LIBMODEM_DIR) && scons TARGET_OS=hdmi2usb-lm32 BUILD_TYPE=Release HDMI2USB_BUILD=$(BUILD_DIRECTORY) - .PHONY: all clean libs version_data diff --git a/firmware/modem/Makefile b/firmware/modem/Makefile new file mode 100644 index 00000000..888ba7f7 --- /dev/null +++ b/firmware/modem/Makefile @@ -0,0 +1,17 @@ +include ../include/generated/variables.mak +include $(SOC_DIRECTORY)/software/common.mak + +VPATH=$(MODEM_DIRECTORY) + +include $(MODEM_DIRECTORY)/Makefile.mk + +libmodem.a: $(LIBMODEMDIR)/build.ninja ninja-hack + ninja -f $< + +# meson doesn't understand vpath +REALSRCDIR=$(MODEM_DIRECTORY)/$(LIBMODEMDIR) + +$(LIBMODEMDIR)/build.ninja: $(LIBMODEMDIR)/meson.build $(LIBMODEMDIR)/targets/hdmi2usb-$(CPU).txt + meson.py $(LIBMODEMDIR) $(REALSRCDIR) --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..e2502b42 --- /dev/null +++ b/firmware/modem/Makefile.mk @@ -0,0 +1,5 @@ +LIBMODEMDIR=../../third_party/libmodem +MODEMDIR=. + +CFLAGS += \ + -I$(MODEMDIR)/$(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/make.py b/make.py index d6b781be..ec4fda58 100755 --- a/make.py +++ b/make.py @@ -117,6 +117,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)) diff --git a/third_party/libmodem b/third_party/libmodem index 224b25b0..a3d26a03 160000 --- a/third_party/libmodem +++ b/third_party/libmodem @@ -1 +1 @@ -Subproject commit 224b25b0d4bd21a2490ddd60a26b12545993fa45 +Subproject commit a3d26a03fff4c03d9c7d5b6662ca7c22f489c434 From 01b6d8f116a8d1b61600b971480df960f6c1cd3f Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 7 Sep 2017 22:11:51 -0400 Subject: [PATCH 22/32] Fix libmodem compilation so that hdmi2usb_dir is set properly, uses only single build directory. --- firmware/modem/Makefile | 6 +++--- third_party/libmodem | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/modem/Makefile b/firmware/modem/Makefile index 888ba7f7..28698ff3 100644 --- a/firmware/modem/Makefile +++ b/firmware/modem/Makefile @@ -5,13 +5,13 @@ VPATH=$(MODEM_DIRECTORY) include $(MODEM_DIRECTORY)/Makefile.mk -libmodem.a: $(LIBMODEMDIR)/build.ninja ninja-hack +libmodem.a: build.ninja ninja-hack ninja -f $< # meson doesn't understand vpath REALSRCDIR=$(MODEM_DIRECTORY)/$(LIBMODEMDIR) -$(LIBMODEMDIR)/build.ninja: $(LIBMODEMDIR)/meson.build $(LIBMODEMDIR)/targets/hdmi2usb-$(CPU).txt - meson.py $(LIBMODEMDIR) $(REALSRCDIR) --cross-file=$(REALSRCDIR)/targets/hdmi2usb-$(CPU).txt +build.ninja: $(LIBMODEMDIR)/meson.build $(LIBMODEMDIR)/targets/hdmi2usb-$(CPU).txt + meson.py . $(REALSRCDIR) -Dhdmi2usb_dir=$(BUILDINC_DIRECTORY)/../.. --cross-file=$(REALSRCDIR)/targets/hdmi2usb-$(CPU).txt .PHONY: ninja-hack diff --git a/third_party/libmodem b/third_party/libmodem index a3d26a03..2906c00c 160000 --- a/third_party/libmodem +++ b/third_party/libmodem @@ -1 +1 @@ -Subproject commit a3d26a03fff4c03d9c7d5b6662ca7c22f489c434 +Subproject commit 2906c00ccb404bd49aec053c5047d0554673aeef From 0e3b1380ee1677939751ebd6667a680b5701cddb Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 11 Sep 2017 18:09:58 -0400 Subject: [PATCH 23/32] Fix libmodem include path, remove scons remnants. --- Makefile | 2 -- firmware/modem/Makefile.mk | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c11664db..83394750 100644 --- a/Makefile +++ b/Makefile @@ -203,7 +203,6 @@ firmware-clear: firmware-clear-$(PLATFORM) .PHONY: firmware-load-$(PLATFORM) firmware-flash-$(PLATFORM) firmware-connect-$(PLATFORM) firmware-clear-$(PLATFORM) firmware-clean: - cd third_party/libmodem && scons TARGET_OS=hdmi2usb-lm32 HDMI2USB_BUILD=$(PWD)/$(TARGET_BUILD_DIR) -c rm -rf $(TARGET_BUILD_DIR)/software .PHONY: firmware-cmd $(FIRMWARE_FILEBASE).bin firmware firmware-load firmware-flash firmware-connect firmware-clean @@ -358,7 +357,6 @@ reset: reset-$(PLATFORM) clean: rm build/cache.mk - cd third_party/libmodem && scons TARGET_OS=hdmi2usb-lm32 HDMI2USB_BUILD=$(PWD)/$(TARGET_BUILD_DIR) -c rm -rf $(TARGET_BUILD_DIR) py3clean . || rm -rf $$(find -name __pycache__) diff --git a/firmware/modem/Makefile.mk b/firmware/modem/Makefile.mk index e2502b42..6c07f3ad 100644 --- a/firmware/modem/Makefile.mk +++ b/firmware/modem/Makefile.mk @@ -2,4 +2,4 @@ LIBMODEMDIR=../../third_party/libmodem MODEMDIR=. CFLAGS += \ - -I$(MODEMDIR)/$(LIBMODEMDIR)/src + -I$(MODEM_DIRECTORY)/$(LIBMODEMDIR)/src From 308b27e49292271c34034a2f108a5dc27fbc3a21 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 27 Sep 2017 02:36:15 -0400 Subject: [PATCH 24/32] Disable PIC option added by meson when compiling libmodem- crashes firmware. --- firmware/modem/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/modem/Makefile b/firmware/modem/Makefile index 28698ff3..93dd3428 100644 --- a/firmware/modem/Makefile +++ b/firmware/modem/Makefile @@ -12,6 +12,6 @@ libmodem.a: build.ninja ninja-hack REALSRCDIR=$(MODEM_DIRECTORY)/$(LIBMODEMDIR) build.ninja: $(LIBMODEMDIR)/meson.build $(LIBMODEMDIR)/targets/hdmi2usb-$(CPU).txt - meson.py . $(REALSRCDIR) -Dhdmi2usb_dir=$(BUILDINC_DIRECTORY)/../.. --cross-file=$(REALSRCDIR)/targets/hdmi2usb-$(CPU).txt + meson.py . $(REALSRCDIR) -Db_staticpic=false -Dhdmi2usb_dir=$(BUILDINC_DIRECTORY)/../.. --cross-file=$(REALSRCDIR)/targets/hdmi2usb-$(CPU).txt .PHONY: ninja-hack From 955cf6d09263e7aea2a45a84d0bf769e9a6ee747 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 7 Oct 2017 10:33:59 -0400 Subject: [PATCH 25/32] Ensure firmware compiles successfully after merge. --- firmware/Makefile | 1 + firmware/flash.c | 2 +- firmware/spiflash.c | 183 ++++++++++++++++++++++++++++++++++++++++++ firmware/spiflash.h | 9 +++ gateware/spi_flash.py | 1 - 5 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 firmware/spiflash.c create mode 100644 firmware/spiflash.h diff --git a/firmware/Makefile b/firmware/Makefile index d2e50af7..2936bc77 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -41,6 +41,7 @@ OBJECTS=\ pll.o \ processor.o \ reboot.o \ + spiflash.o \ stdio_wrap.o \ telnet.o \ tofe_eeprom.o \ diff --git a/firmware/flash.c b/firmware/flash.c index 50f44f19..f571f5d7 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -1,6 +1,7 @@ #include #include #if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) +#include "spiflash.h" #include "flash.h" #include @@ -11,7 +12,6 @@ #include #include #include -#include #include #include #include "ci.h" 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 02f3dcfb..d85e5bdc 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) - From bc8dd4784d44ca9506f60d7efadf4cf52bdfff6e Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 13 Dec 2017 10:44:11 -0500 Subject: [PATCH 26/32] Parameterize meson executable name, which may be available as 'meson' or 'meson.py'. --- Makefile | 3 +++ firmware/modem/Makefile | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 83394750..50d4bc1f 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ endif PYTHON ?= python export PYTHON +MESON ?= meson +export MESON + PLATFORM ?= opsis export PLATFORM # Default board diff --git a/firmware/modem/Makefile b/firmware/modem/Makefile index 93dd3428..8398fb96 100644 --- a/firmware/modem/Makefile +++ b/firmware/modem/Makefile @@ -12,6 +12,6 @@ libmodem.a: build.ninja ninja-hack REALSRCDIR=$(MODEM_DIRECTORY)/$(LIBMODEMDIR) build.ninja: $(LIBMODEMDIR)/meson.build $(LIBMODEMDIR)/targets/hdmi2usb-$(CPU).txt - meson.py . $(REALSRCDIR) -Db_staticpic=false -Dhdmi2usb_dir=$(BUILDINC_DIRECTORY)/../.. --cross-file=$(REALSRCDIR)/targets/hdmi2usb-$(CPU).txt + $(MESON) . $(REALSRCDIR) -Db_staticpic=false -Dhdmi2usb_dir=$(BUILDINC_DIRECTORY)/../.. --cross-file=$(REALSRCDIR)/targets/hdmi2usb-$(CPU).txt .PHONY: ninja-hack From 02fbd6628b948abcf82b94a1db3a073db7a1999e Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 13 Dec 2017 10:45:15 -0500 Subject: [PATCH 27/32] Add meson as travis CI dependency to build libmodem. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 00bec819..81b1c73e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ addons: - libftdi-dev - libreadline-dev - libusb-1.0-0-dev + - meson - python-yaml - realpath - util-linux From 02296eb015156d6ca1707a23eae3c9b24d5a1010 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 13 Dec 2017 11:12:19 -0500 Subject: [PATCH 28/32] Fix travis CI dependencies. --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 81b1c73e..cac740f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ addons: - libftdi-dev - libreadline-dev - libusb-1.0-0-dev - - meson + - python3-pip - python-yaml - realpath - util-linux @@ -27,6 +27,12 @@ env: - HDMI2USB_UDEV_IGNORE=1 - CLEAN_CHECK=1 +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 CPU="$C" - export PLATFORMS="$P" From 96428a293b73be483c4455186b9c0d958d582f6a Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 14 Dec 2017 12:19:06 -0500 Subject: [PATCH 29/32] CC needs to be set to a dummy value for meson. Add comment explaining. --- firmware/modem/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/modem/Makefile b/firmware/modem/Makefile index 8398fb96..0e5f19fb 100644 --- a/firmware/modem/Makefile +++ b/firmware/modem/Makefile @@ -12,6 +12,10 @@ libmodem.a: build.ninja ninja-hack REALSRCDIR=$(MODEM_DIRECTORY)/$(LIBMODEMDIR) build.ninja: $(LIBMODEMDIR)/meson.build $(LIBMODEMDIR)/targets/hdmi2usb-$(CPU).txt - $(MESON) . $(REALSRCDIR) -Db_staticpic=false -Dhdmi2usb_dir=$(BUILDINC_DIRECTORY)/../.. --cross-file=$(REALSRCDIR)/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 From 2f87f9d507a4353402ca32ab36d6dd59dc8f52fe Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 14 Dec 2017 12:45:46 -0500 Subject: [PATCH 30/32] Update libmodem to include hdmi2usb-or1k backend. --- third_party/libmodem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/libmodem b/third_party/libmodem index 2906c00c..a3a2f804 160000 --- a/third_party/libmodem +++ b/third_party/libmodem @@ -1 +1 @@ -Subproject commit 2906c00ccb404bd49aec053c5047d0554673aeef +Subproject commit a3a2f804cd3b88cf3eb9ec921569780ab6f65b87 From 3f0c3299155c18d4cd464b12749c4eb31b4d11aa Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 14 Dec 2017 12:55:40 -0500 Subject: [PATCH 31/32] Improve conditional compilation for bitbang_test. --- firmware/ci.c | 4 ++-- firmware/flash.c | 2 ++ firmware/flash.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/ci.c b/firmware/ci.c index dce67aa9..319b2ac3 100644 --- a/firmware/ci.c +++ b/firmware/ci.c @@ -175,7 +175,7 @@ static void help_debug(void) #endif wputs(" debug dna - show Board's DNA"); wputs(" debug edid - dump monitor EDID"); -#ifdef CSR_SPIFLASH_BASE +#if defined(CSR_SPIFLASH_BASE) && defined(FLASH_BOOT_ADDRESS) wputs(" debug spiflash - test bitbang write"); #endif #ifdef CSR_CAS_BASE @@ -1358,7 +1358,7 @@ void ci_service(void) #endif if(found == 0) wprintf("%s port has no EDID capabilities\r\n", token); -#ifdef CSR_SPIFLASH_BASE +#if defined(CSR_SPIFLASH_BASE) && defined(FLASH_BOOT_ADDRESS) } else if(strcmp(token, "spiflash") == 0) { bitbang_test(); #endif diff --git a/firmware/flash.c b/firmware/flash.c index f571f5d7..f74db568 100644 --- a/firmware/flash.c +++ b/firmware/flash.c @@ -85,6 +85,7 @@ void flash_test(void) { mr(0x20000000, test_size); } +#ifdef FLASH_BOOT_ADDRESS void bitbang_test(void) { unsigned int *flashbase; unsigned int length; @@ -122,6 +123,7 @@ void bitbang_test(void) { erase_flash_sector((unsigned int) free_start); } +#endif // XMODEM: diff --git a/firmware/flash.h b/firmware/flash.h index eb40131f..5df3b3c6 100644 --- a/firmware/flash.h +++ b/firmware/flash.h @@ -2,7 +2,9 @@ #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); From 6a4935aa34a5104e04db3185c22ba4571160428b Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 14 Dec 2017 13:14:05 -0500 Subject: [PATCH 32/32] Fix bad libmodem update. --- third_party/libmodem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/libmodem b/third_party/libmodem index a3a2f804..1499a0bc 160000 --- a/third_party/libmodem +++ b/third_party/libmodem @@ -1 +1 @@ -Subproject commit a3a2f804cd3b88cf3eb9ec921569780ab6f65b87 +Subproject commit 1499a0bcc545668413a21ed3ec43e102b46621fa