diff --git a/build.sh b/build.sh index 10e5af8..62f09e4 100755 --- a/build.sh +++ b/build.sh @@ -89,6 +89,7 @@ build_update () { --mcu ../controller/build/app/app.bin \ --fpga ../../fw/project/lcmxo2/impl1/sc64_impl1.jed \ --boot ../bootloader/build/bootloader.bin \ + --primer ../controller/build/primer/primer.bin \ sc64.upd popd > /dev/null @@ -113,7 +114,7 @@ print_usage () { echo "usage: ./build.sh [bootloader] [controller] [fpga] [update] [release] [-c] [--help]" echo "parameters:" echo " bootloader - compile N64 bootloader software" - echo " controller - compile ARM controller software" + echo " controller - compile MCU controller software" echo " fpga - compile FPGA design" echo " update - compile all software and designs" echo " release - collect and zip files for release (triggers 'update' build)" diff --git a/fw/project/lcmxo2/sc64.lpf b/fw/project/lcmxo2/sc64.lpf index dfc6bdd..ac7502d 100644 --- a/fw/project/lcmxo2/sc64.lpf +++ b/fw/project/lcmxo2/sc64.lpf @@ -200,7 +200,7 @@ LOCATE COMP "usb_miosi[6]" SITE "14" ; LOCATE COMP "usb_miosi[7]" SITE "13" ; LOCATE COMP "usb_miso" SITE "10" ; LOCATE COMP "usb_pwrsav" SITE "2" ; -SYSCONFIG SDM_PORT=DISABLE ; +SYSCONFIG SDM_PORT=DISABLE I2C_PORT=ENABLE ; VOLTAGE 3.300 V; FREQUENCY NET "clk" 100.000000 MHz PAR_ADJ 10.000000 ; BLOCK PATH TO PORT "mcu_int" ; diff --git a/sw/bootloader/src/ipl2.S b/sw/bootloader/src/ipl2.S index abf4f4b..ed074f0 100644 --- a/sw/bootloader/src/ipl2.S +++ b/sw/bootloader/src/ipl2.S @@ -1,6 +1,7 @@ .set noat .set noreorder + .section .data.ipl2 ipl2: .global ipl2 diff --git a/sw/controller/app.ld b/sw/controller/app.ld index f90c3fd..bea3e0c 100644 --- a/sw/controller/app.ld +++ b/sw/controller/app.ld @@ -1,6 +1,6 @@ MEMORY { loader (rx) : org = 0x08000000, len = 4k - rom (rx) : org = 0x08001000, len = 28k + code (rx) : org = 0x08001000, len = 28k ram (rwx) : org = 0x20000000, len = 8k } @@ -17,7 +17,7 @@ SECTIONS { . = ALIGN(4); KEEP(*(.isr_vector)) . = ALIGN(4); - } > rom + } > code .text : { . = ALIGN(4); @@ -27,18 +27,16 @@ SECTIONS { *(.glue_7t) . = ALIGN(4); _etext = .; - } > rom + } > code .bss : { . = ALIGN(4); _sbss = .; - __bss_start__ = _sbss; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _ebss = .; - __bss_end__ = _ebss; } > ram .data : { @@ -49,14 +47,14 @@ SECTIONS { *(.data*) . = ALIGN(4); _edata = .; - } > ram AT > rom + } > ram AT > code .rodata : { . = ALIGN(4); *(.rodata) *(.rodata*) . = ALIGN(4); - } > rom + } > code _estack = ORIGIN(ram) + LENGTH(ram); } diff --git a/sw/controller/app.mk b/sw/controller/app.mk index bf5870b..6e67cdc 100644 --- a/sw/controller/app.mk +++ b/sw/controller/app.mk @@ -1,6 +1,9 @@ EXE_NAME = app -LD_SCRIPT = app.ld BUILD_DIR = build/app + +LD_SCRIPT = app.ld +PAD_TO = 0x08008000 + SRC_FILES = \ app.S \ app.c \ @@ -24,7 +27,6 @@ SRC_FILES = \ update.c \ usb.c \ writeback.c -PAD_TO = 0x08008000 include common.mk diff --git a/sw/controller/build.sh b/sw/controller/build.sh index a969cec..a95a007 100755 --- a/sw/controller/build.sh +++ b/sw/controller/build.sh @@ -4,10 +4,12 @@ set -e case "$1" in all) + make all -j -f primer.mk USER_FLAGS="$USER_FLAGS" make all -j -f loader.mk USER_FLAGS="$USER_FLAGS" make all -j -f app.mk USER_FLAGS="$USER_FLAGS" ;; clean) + make clean -f primer.mk make clean -f loader.mk make clean -f app.mk ;; diff --git a/sw/controller/common.mk b/sw/controller/common.mk index 8f714e9..5e6fdc3 100644 --- a/sw/controller/common.mk +++ b/sw/controller/common.mk @@ -14,7 +14,6 @@ SRC_DIR = src SRCS = $(addprefix $(SRC_DIR)/, $(SRC_FILES)) OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(patsubst %,%.o,$(SRCS)))) DEPS = $(OBJS:.o=.d) - VPATH = $(SRC_DIR) $(@info $(shell mkdir -p ./$(BUILD_DIR) &> /dev/null)) diff --git a/sw/controller/loader.ld b/sw/controller/loader.ld index 096e772..97f2f37 100644 --- a/sw/controller/loader.ld +++ b/sw/controller/loader.ld @@ -1,5 +1,5 @@ MEMORY { - rom (rx) : org = 0x08000000, len = 4k + code (rx) : org = 0x08000000, len = 4k ram (rwx) : org = 0x20000000, len = 8k } @@ -10,13 +10,13 @@ SECTIONS { . = ALIGN(4); KEEP(*(.isr_vector)) . = ALIGN(4); - } > rom + } > code .startup : { . = ALIGN(4); *(.text.Reset_Handler) . = ALIGN(4); - } > rom + } > code .text : { _sitext = LOADADDR(.text); @@ -28,18 +28,16 @@ SECTIONS { *(.glue_7t) . = ALIGN(4); _etext = .; - } > ram AT > rom + } > ram AT > code .bss : { . = ALIGN(4); _sbss = .; - __bss_start__ = _sbss; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _ebss = .; - __bss_end__ = _ebss; } > ram .data : { @@ -50,7 +48,7 @@ SECTIONS { *(.data*) . = ALIGN(4); _edata = .; - } > ram AT > rom + } > ram AT > code .rodata : { _sirodata = LOADADDR(.rodata); @@ -60,9 +58,9 @@ SECTIONS { *(.rodata*) . = ALIGN(4); _erodata = .; - } > ram AT > rom + } > ram AT > code - _app_header = ORIGIN(rom) + LENGTH(rom); + _app_header = ORIGIN(code) + LENGTH(code); _app_magic = _app_header + 16; _estack = ORIGIN(ram) + LENGTH(ram); } diff --git a/sw/controller/loader.mk b/sw/controller/loader.mk index 32917db..0637f73 100644 --- a/sw/controller/loader.mk +++ b/sw/controller/loader.mk @@ -1,6 +1,9 @@ EXE_NAME = loader -LD_SCRIPT = loader.ld BUILD_DIR = build/loader + +LD_SCRIPT = loader.ld +PAD_TO = 0x08001000 + SRC_FILES = \ loader.S \ flash.c \ @@ -9,6 +12,5 @@ SRC_FILES = \ lcmxo2.c \ loader.c \ update.c -PAD_TO = 0x08001000 include common.mk diff --git a/sw/controller/primer.ld b/sw/controller/primer.ld new file mode 100644 index 0000000..7225e46 --- /dev/null +++ b/sw/controller/primer.ld @@ -0,0 +1,50 @@ +MEMORY { + ram (rwx) : org = 0x20000000, len = 4k + code (rwx) : org = 0x20001000, len = 4k +} + +ENTRY(Reset_Handler) + +SECTIONS { + .isr_vector : { + . = ALIGN(4); + _header = .; + KEEP(*(.isr_vector)) + . = ALIGN(4); + } > code + + .text : { + . = ALIGN(4); + *(.text) + *(.text*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); + } > code + + .bss : { + . = ALIGN(4); + _sbss = .; + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } > ram + + .data : { + . = ALIGN(4); + *(.data) + *(.data*) + . = ALIGN(4); + } > code + + .rodata : { + . = ALIGN(4); + *(.rodata) + *(.rodata*) + . = ALIGN(4); + } > code + + _estack = ORIGIN(ram) + LENGTH(ram); +} diff --git a/sw/controller/primer.mk b/sw/controller/primer.mk new file mode 100644 index 0000000..1abc92f --- /dev/null +++ b/sw/controller/primer.mk @@ -0,0 +1,16 @@ +EXE_NAME = primer +BUILD_DIR = build/primer + +LD_SCRIPT = primer.ld +PAD_TO = 0x20002000 + +SRC_FILES = \ + primer.S \ + fpga.c \ + hw.c \ + lcmxo2.c \ + primer.c + +include common.mk + +FLAGS += -DLCMXO2_I2C diff --git a/sw/controller/src/app.S b/sw/controller/src/app.S index 0f2b160..5150fde 100644 --- a/sw/controller/src/app.S +++ b/sw/controller/src/app.S @@ -3,6 +3,7 @@ .fpu softvfp .thumb + .section .loader, "a", %progbits .type loader, %object loader: @@ -13,7 +14,6 @@ loader: .type Reset_Handler, %function Reset_Handler: .global Reset_Handler - cpsid i init_data: ldr r0, =_sdata diff --git a/sw/controller/src/hw.c b/sw/controller/src/hw.c index cff7c0e..7b0d054 100644 --- a/sw/controller/src/hw.c +++ b/sw/controller/src/hw.c @@ -1,7 +1,11 @@ +#include #include #include "hw.h" +#define UART_BAUD (115200) + + typedef enum { GPIO_INPUT = 0b00, GPIO_OUTPUT = 0b01, @@ -108,6 +112,13 @@ void hw_gpio_reset (gpio_id_t id) { gpio->BSRR = (GPIO_BSRR_BR0 << pin); } +void hw_uart_read (uint8_t *data, int length) { + for (int i = 0; i < length; i++) { + while (!(USART1->ISR & USART_ISR_RXNE_RXFNE)); + *data++ = (uint8_t) (USART1->RDR); + } +} + void hw_uart_write (uint8_t *data, int length) { for (int i = 0; i < length; i++) { while (!(USART1->ISR & USART_ISR_TXE_TXFNF)); @@ -181,7 +192,30 @@ void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t } uint32_t hw_i2c_get_error (void) { - return I2C1->ISR & I2C_ISR_NACKF; + return (I2C1->ISR & I2C_ISR_NACKF); +} + +void hw_i2c_raw (uint8_t i2c_address, uint8_t *data, int length, i2c_type_t type) { + if (type & I2C_START) { + I2C1->ICR = I2C_ICR_NACKCF; + } + I2C1->CR2 = ( + ((type & I2C_AUTOEND) ? I2C_CR2_AUTOEND : 0) | + (length << I2C_CR2_NBYTES_Pos) | + ((type & I2C_STOP) ? I2C_CR2_STOP : 0) | + ((type & I2C_START) ? I2C_CR2_START : 0) | + ((type & I2C_READ) ? I2C_CR2_RD_WRN : 0) | + (i2c_address << I2C_CR2_SADD_Pos) + ); + for (int i = 0; i < length; i++) { + if (type & I2C_READ) { + while (!(I2C1->ISR & I2C_ISR_RXNE)); + *data++ = I2C1->RXDR; + } else if (type & I2C_WRITE) { + while (!(I2C1->ISR & I2C_ISR_TXE)); + I2C1->TXDR = *data++; + } + } } void hw_i2c_disable_irq (void) { @@ -311,16 +345,18 @@ hw_flash_t hw_flash_read (uint32_t offset) { return *(uint64_t *) (FLASH_BASE + offset); } -void hw_loader_reset (loader_parameters_t *parameters) { - RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN; - PWR->CR1 |= PWR_CR1_DBP; - TAMP->BKP0R = parameters->magic; - TAMP->BKP1R = parameters->flags; - TAMP->BKP2R = parameters->mcu_address; - TAMP->BKP3R = parameters->fpga_address; - TAMP->BKP4R = parameters->bootloader_address; - PWR->CR1 &= ~(PWR_CR1_DBP); - RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN); +void hw_reset (loader_parameters_t *parameters) { + if (parameters != NULL) { + RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN; + PWR->CR1 |= PWR_CR1_DBP; + TAMP->BKP0R = parameters->magic; + TAMP->BKP1R = parameters->flags; + TAMP->BKP2R = parameters->mcu_address; + TAMP->BKP3R = parameters->fpga_address; + TAMP->BKP4R = parameters->bootloader_address; + PWR->CR1 &= ~(PWR_CR1_DBP); + RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN); + } NVIC_SystemReset(); } @@ -397,7 +433,6 @@ static void hw_init_spi (void) { hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0); hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0); hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0); - hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0); } static void hw_init_i2c (void) { @@ -408,7 +443,6 @@ static void hw_init_i2c (void) { hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0); hw_gpio_init(GPIO_ID_I2C_SDA, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0); - hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0); } static void hw_init_uart (void) { @@ -416,11 +450,12 @@ static void hw_init_uart (void) { SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP); - USART1->BRR = (64000000UL) / 1000000; - USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_TE | USART_CR1_UE; - hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, GPIO_AF_1, 0); - hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, GPIO_AF_1, 0); + hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0); + + USART1->BRR = (64000000UL) / UART_BAUD; + USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; + USART1->RQR = USART_RQR_TXFRQ | USART_RQR_RXFRQ; } static void hw_init_tim (void) { @@ -445,14 +480,22 @@ static void hw_init_tim (void) { ); } -static void hw_init_misc (void) { +static void hw_init_crc (void) { RCC->AHBENR |= RCC_AHBENR_CRCEN; CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0); +} +static void hw_init_misc (void) { hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0); hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0); hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_OUTPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1); + hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0); + hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0); +} + +void hw_set_vector_table (uint32_t offset) { + SCB->VTOR = (__IOM uint32_t) (offset); } void hw_init (void) { @@ -461,6 +504,7 @@ void hw_init (void) { hw_init_i2c(); hw_init_uart(); hw_init_tim(); + hw_init_crc(); hw_init_misc(); NVIC_SetPriority(EXTI0_1_IRQn, 0); @@ -489,6 +533,14 @@ void hw_loader_init (void) { hw_init_spi(); } +void hw_primer_init (void) { + hw_init_mcu(); + hw_init_spi(); + hw_init_i2c(); + hw_init_uart(); + hw_init_crc(); +} + void EXTI0_1_IRQHandler (void) { for (int i = 0; i <= 1; i++) { diff --git a/sw/controller/src/hw.h b/sw/controller/src/hw.h index 07658f1..850be40 100644 --- a/sw/controller/src/hw.h +++ b/sw/controller/src/hw.h @@ -29,6 +29,14 @@ typedef enum { GPIO_IRQ_RISING = 0b10, } gpio_irq_t; +typedef enum { + I2C_START = (1 << 0), + I2C_AUTOEND = (1 << 1), + I2C_STOP = (1 << 2), + I2C_READ = (1 << 3), + I2C_WRITE = (1 << 4), +} i2c_type_t; + typedef enum { TIM_ID_CIC = 0, TIM_ID_RTC = 1, @@ -63,6 +71,7 @@ void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void)); uint32_t hw_gpio_get (gpio_id_t id); void hw_gpio_set (gpio_id_t id); void hw_gpio_reset (gpio_id_t id); +void hw_uart_read (uint8_t *data, int length); void hw_uart_write (uint8_t *data, int length); void hw_spi_start (void); void hw_spi_stop (void); @@ -70,6 +79,7 @@ void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction); void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)); void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)); uint32_t hw_i2c_get_error (void); +void hw_i2c_raw (uint8_t i2c_address, uint8_t *data, int length, i2c_type_t type); void hw_i2c_disable_irq (void); void hw_i2c_enable_irq (void); void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void)); @@ -83,10 +93,12 @@ uint32_t hw_flash_size (void); void hw_flash_erase (void); void hw_flash_program (uint32_t offset, hw_flash_t value); hw_flash_t hw_flash_read (uint32_t offset); -void hw_loader_reset (loader_parameters_t *parameters); +void hw_reset (loader_parameters_t *parameters); void hw_loader_get_parameters (loader_parameters_t *parameters); +void hw_set_vector_table (uint32_t offset); void hw_init (void); void hw_loader_init (void); +void hw_primer_init (void); #endif diff --git a/sw/controller/src/lcmxo2.c b/sw/controller/src/lcmxo2.c index 4990444..c00251c 100644 --- a/sw/controller/src/lcmxo2.c +++ b/sw/controller/src/lcmxo2.c @@ -1,253 +1,451 @@ -#include -#include "fpga.h" -#include "vendor.h" - - -#define VENDOR_SCR_START (1 << 0) -#define VENDOR_SCR_BUSY (1 << 0) -#define VENDOR_SCR_WRITE (1 << 1) -#define VENDOR_SCR_LENGTH_BIT (2) -#define VENDOR_SCR_DELAY (1 << 4) -#define VENDOR_SCR_ADDRESS_BIT (8) - -#define LCMXO2_CFGCR (0x70) -#define LCMXO2_CFGTXDR (0x71) -#define LCMXO2_CFGRXDR (0x73) - -#define CFGCR_RSTE (1 << 6) -#define CFGCR_WBCE (1 << 7) - -#define ISC_ERASE (0x0E) -#define ISC_DISABLE (0x26) -#define LSC_READ_STATUS (0x3C) -#define LSC_INIT_ADDRESS (0x46) -#define ISC_PROGRAM_DONE (0x5E) -#define LSC_PROG_INCR_NV (0x70) -#define LSC_READ_INCR_NV (0x73) -#define ISC_ENABLE_X (0x74) -#define LSC_REFRESH (0x79) -#define ISC_NOOP (0xFF) - -#define ISC_ERASE_CFG (1 << 18) -#define ISC_ERASE_UFM (1 << 19) - -#define LSC_STATUS_1_BUSY (1 << 4) -#define LSC_STATUS_1_FAIL (1 << 5) - -#define FLASH_PAGE_SIZE (16) -#define FLASH_NUM_PAGES (11260) - - -typedef enum { - CMD_NORMAL, - CMD_DELAYED, - CMD_TWO_OP, -} cmd_type_t; - - -static void lcmxo2_reg_set (uint8_t reg, uint8_t value) { - fpga_reg_set(REG_VENDOR_DATA, value << 24); - fpga_reg_set(REG_VENDOR_SCR, - (reg << VENDOR_SCR_ADDRESS_BIT) | - (0 << VENDOR_SCR_LENGTH_BIT) | - VENDOR_SCR_WRITE | - VENDOR_SCR_START - ); - while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); -} - -static void lcmxo2_reset_bus (void) { - lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE); - lcmxo2_reg_set(LCMXO2_CFGCR, 0); -} - -static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type) { - lcmxo2_reg_set(LCMXO2_CFGCR, 0); - uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF); - lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE); - fpga_reg_set(REG_VENDOR_DATA, data); - fpga_reg_set(REG_VENDOR_SCR, - (LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) | - (type == CMD_DELAYED ? VENDOR_SCR_DELAY : 0) | - ((type == CMD_TWO_OP ? 2 : 3) << VENDOR_SCR_LENGTH_BIT) | - VENDOR_SCR_WRITE | - VENDOR_SCR_START - ); - while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); -} - -static void lcmxo2_cleanup (void) { - lcmxo2_reg_set(LCMXO2_CFGCR, 0); -} - -static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) { - while (length > 0) { - uint32_t block_size = (length > 4) ? 4 : length; - fpga_reg_set(REG_VENDOR_SCR, - (LCMXO2_CFGRXDR << VENDOR_SCR_ADDRESS_BIT) | - ((block_size - 1) << VENDOR_SCR_LENGTH_BIT) | - VENDOR_SCR_START - ); - while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); - uint32_t data = fpga_reg_get(REG_VENDOR_DATA); - data <<= ((4 - block_size) * 8); - for (int i = 0; i < block_size; i++) { - *buffer++ = ((data >> 24) & 0xFF); - data <<= 8; - length -= 1; - } - } -} - -static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) { - while (length > 0) { - uint32_t block_size = (length > 4) ? 4 : length; - uint32_t data = 0; - for (int i = 0; i < block_size; i++) { - data = ((data << 8) | *buffer++); - length -= 1; - } - data <<= ((4 - block_size) * 8); - fpga_reg_set(REG_VENDOR_DATA, data); - fpga_reg_set(REG_VENDOR_SCR, - (LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) | - ((block_size - 1) << VENDOR_SCR_LENGTH_BIT) | - VENDOR_SCR_WRITE | - VENDOR_SCR_START - ); - while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); - } -} - -static bool lcmxo2_wait_busy (void) { - uint8_t status[4]; - do { - lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL); - lcmxo2_read_data(status, 4); - } while(status[2] & LSC_STATUS_1_BUSY); - return status[2] & LSC_STATUS_1_FAIL; -} - -static bool lcmxo2_enable_flash (void) { - lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL); - return lcmxo2_wait_busy(); -} - -static void lcmxo2_disable_flash (void) { - lcmxo2_wait_busy(); - lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP); - lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL); -} - -static bool lcmxo2_erase_flash (void) { - lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG, CMD_NORMAL); - return lcmxo2_wait_busy(); -} - -static void lcmxo2_reset_flash_address (void) { - lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL); -} - -static bool lcmxo2_write_flash_page (uint8_t *buffer) { - lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL); - lcmxo2_write_data(buffer, FLASH_PAGE_SIZE); - return lcmxo2_wait_busy(); -} - -static void lcmxo2_read_flash_page (uint8_t *buffer) { - lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED); - lcmxo2_read_data(buffer, FLASH_PAGE_SIZE); -} - -static void lcmxo2_program_done (void) { - lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL); - lcmxo2_wait_busy(); -} - -static void lcmxo2_refresh (void) { - lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP); -} - -static vendor_error_t lcmxo2_fail (vendor_error_t error) { - lcmxo2_disable_flash(); - lcmxo2_cleanup(); - return error; -} - -uint32_t vendor_flash_size (void) { - return (FLASH_PAGE_SIZE * FLASH_NUM_PAGES); -} - -vendor_error_t vendor_backup (uint32_t address, uint32_t *length) { - uint8_t buffer[FLASH_PAGE_SIZE]; - - *length = 0; - - lcmxo2_reset_bus(); - if (lcmxo2_enable_flash()) { - return lcmxo2_fail(VENDOR_ERROR_INIT); - } - lcmxo2_reset_flash_address(); - for (int i = 0; i < (FLASH_PAGE_SIZE * FLASH_NUM_PAGES); i += FLASH_PAGE_SIZE) { - lcmxo2_read_flash_page(buffer); - fpga_mem_write(address + i, FLASH_PAGE_SIZE, buffer); - *length += FLASH_PAGE_SIZE; - } - lcmxo2_disable_flash(); - lcmxo2_cleanup(); - - return VENDOR_OK; -} - -vendor_error_t vendor_update (uint32_t address, uint32_t length) { - uint8_t buffer[FLASH_PAGE_SIZE]; - uint8_t verify_buffer[FLASH_PAGE_SIZE]; - - if (length == 0) { - return VENDOR_ERROR_ARGS; - } - if ((length % FLASH_PAGE_SIZE) != 0) { - return VENDOR_ERROR_ARGS; - } - if (length > (FLASH_PAGE_SIZE * FLASH_NUM_PAGES)) { - return VENDOR_ERROR_ARGS; - } - - lcmxo2_reset_bus(); - if (lcmxo2_enable_flash()) { - return lcmxo2_fail(VENDOR_ERROR_INIT); - } - if (lcmxo2_erase_flash()) { - return lcmxo2_fail(VENDOR_ERROR_ERASE); - } - lcmxo2_reset_flash_address(); - for (int i = 0; i < length; i += FLASH_PAGE_SIZE) { - fpga_mem_read(address + i, FLASH_PAGE_SIZE, buffer); - if (lcmxo2_write_flash_page(buffer)) { - return lcmxo2_fail(VENDOR_ERROR_PROGRAM); - } - } - lcmxo2_program_done(); - lcmxo2_reset_flash_address(); - for (int i = 0; i < length; i += FLASH_PAGE_SIZE) { - lcmxo2_read_flash_page(buffer); - fpga_mem_read(address + i, FLASH_PAGE_SIZE, verify_buffer); - for (int x = 0; x < FLASH_PAGE_SIZE; x++) { - if (buffer[x] != verify_buffer[x]) { - return lcmxo2_fail(VENDOR_ERROR_VERIFY); - } - } - } - lcmxo2_disable_flash(); - lcmxo2_cleanup(); - - return VENDOR_OK; -} - -vendor_error_t vendor_reconfigure (void) { - lcmxo2_reset_bus(); - lcmxo2_refresh(); - lcmxo2_cleanup(); - - return VENDOR_OK; -} +#include +#include "fpga.h" +#include "hw.h" +#include "vendor.h" + + +#define VENDOR_SCR_START (1 << 0) +#define VENDOR_SCR_BUSY (1 << 0) +#define VENDOR_SCR_WRITE (1 << 1) +#define VENDOR_SCR_LENGTH_BIT (2) +#define VENDOR_SCR_DELAY (1 << 4) +#define VENDOR_SCR_ADDRESS_BIT (8) + +#define LCMXO2_I2C_ADDR_CFG (0x80) +#define LCMXO2_I2C_ADDR_RESET (0x86) + +#define LCMXO2_CFGCR (0x70) +#define LCMXO2_CFGTXDR (0x71) +#define LCMXO2_CFGRXDR (0x73) + +#define CFGCR_RSTE (1 << 6) +#define CFGCR_WBCE (1 << 7) + +#define ISC_ERASE (0x0E) +#define ISC_DISABLE (0x26) +#define LSC_READ_STATUS (0x3C) +#define LSC_INIT_ADDRESS (0x46) +#define ISC_PROGRAM_DONE (0x5E) +#define LSC_PROG_INCR_NV (0x70) +#define LSC_READ_INCR_NV (0x73) +#define ISC_ENABLE_X (0x74) +#define LSC_REFRESH (0x79) +#define ISC_ENABLE (0xC6) +#define IDCODE_PUB (0xE0) +#define LSC_PROG_FEABITS (0xF8) +#define LSC_READ_FEABITS (0xFB) +#define ISC_NOOP (0xFF) + +#define ISC_ERASE_FEATURE (1 << 17) +#define ISC_ERASE_CFG (1 << 18) +#define ISC_ERASE_UFM (1 << 19) + +#define LSC_STATUS_1_BUSY (1 << 4) +#define LSC_STATUS_1_FAIL (1 << 5) + +#define DEVICE_ID_SIZE (4) + +#define FLASH_PAGE_SIZE (16) +#define FLASH_NUM_PAGES (11260) + +#define FEATBITS_SIZE (2) + + +typedef enum { + CMD_NORMAL, + CMD_DELAYED, + CMD_TWO_OP, +} cmd_type_t; + + +#ifndef LCMXO2_I2C +static void lcmxo2_reg_set (uint8_t reg, uint8_t value) { + fpga_reg_set(REG_VENDOR_DATA, value << 24); + fpga_reg_set(REG_VENDOR_SCR, + (reg << VENDOR_SCR_ADDRESS_BIT) | + (0 << VENDOR_SCR_LENGTH_BIT) | + VENDOR_SCR_WRITE | + VENDOR_SCR_START + ); + while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); +} +#endif + +static void lcmxo2_reset_bus (void) { +#ifdef LCMXO2_I2C + uint8_t reset_data = 0; + hw_i2c_raw(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), I2C_START | I2C_AUTOEND | I2C_WRITE); +#else + lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE); + lcmxo2_reg_set(LCMXO2_CFGCR, 0); +#endif +} + +static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type) { +#ifdef LCMXO2_I2C + uint8_t data[4] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) }; + int length = CMD_TWO_OP ? 3 : 4; + hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, data, length, I2C_START | I2C_WRITE); +#else + uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF); + lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE); + fpga_reg_set(REG_VENDOR_DATA, data); + fpga_reg_set(REG_VENDOR_SCR, + (LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) | + (type == CMD_DELAYED ? VENDOR_SCR_DELAY : 0) | + ((type == CMD_TWO_OP ? 2 : 3) << VENDOR_SCR_LENGTH_BIT) | + VENDOR_SCR_WRITE | + VENDOR_SCR_START + ); + while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); +#endif +} + +static void lcmxo2_finish_cmd (void) { +#ifdef LCMXO2_I2C + hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, NULL, 0, I2C_STOP); +#else + lcmxo2_reg_set(LCMXO2_CFGCR, 0); +#endif +} + +static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) { +#ifdef LCMXO2_I2C + hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, buffer, length, I2C_START | I2C_READ); +#else + while (length > 0) { + uint32_t block_size = (length > 4) ? 4 : length; + fpga_reg_set(REG_VENDOR_SCR, + (LCMXO2_CFGRXDR << VENDOR_SCR_ADDRESS_BIT) | + ((block_size - 1) << VENDOR_SCR_LENGTH_BIT) | + VENDOR_SCR_START + ); + while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); + uint32_t data = fpga_reg_get(REG_VENDOR_DATA); + data <<= ((4 - block_size) * 8); + for (int i = 0; i < block_size; i++) { + *buffer++ = ((data >> 24) & 0xFF); + data <<= 8; + length -= 1; + } + } +#endif +} + +static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) { +#ifdef LCMXO2_I2C + hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, buffer, length, I2C_WRITE); +#else + while (length > 0) { + uint32_t block_size = (length > 4) ? 4 : length; + uint32_t data = 0; + for (int i = 0; i < block_size; i++) { + data = ((data << 8) | *buffer++); + length -= 1; + } + data <<= ((4 - block_size) * 8); + fpga_reg_set(REG_VENDOR_DATA, data); + fpga_reg_set(REG_VENDOR_SCR, + (LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) | + ((block_size - 1) << VENDOR_SCR_LENGTH_BIT) | + VENDOR_SCR_WRITE | + VENDOR_SCR_START + ); + while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); + } +#endif +} + +static void lcmxo2_read_device_id (uint8_t *id) { + lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL); + lcmxo2_read_data(id, DEVICE_ID_SIZE); + lcmxo2_finish_cmd(); +} + +static bool lcmxo2_wait_busy (void) { + uint8_t status[4]; + do { + lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL); + lcmxo2_read_data(status, 4); + lcmxo2_finish_cmd(); + } while(status[2] & LSC_STATUS_1_BUSY); + return status[2] & LSC_STATUS_1_FAIL; +} + +static bool lcmxo2_enable_flash (void) { +#ifdef LCMXO2_I2C + lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_NORMAL); +#else + lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL); +#endif + lcmxo2_finish_cmd(); + return lcmxo2_wait_busy(); +} + +static void lcmxo2_disable_flash (void) { + lcmxo2_wait_busy(); + lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP); + lcmxo2_finish_cmd(); + lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL); + lcmxo2_finish_cmd(); +} + +static bool lcmxo2_erase_flash (void) { + lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG, CMD_NORMAL); + lcmxo2_finish_cmd(); + return lcmxo2_wait_busy(); +} + +static bool lcmxo2_erase_all (void) { + lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG | ISC_ERASE_FEATURE, CMD_NORMAL); + lcmxo2_finish_cmd(); + return lcmxo2_wait_busy(); +} + +static void lcmxo2_reset_flash_address (void) { + lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL); + lcmxo2_finish_cmd(); +} + +static bool lcmxo2_write_flash_page (uint8_t *buffer) { + lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL); + lcmxo2_write_data(buffer, FLASH_PAGE_SIZE); + lcmxo2_finish_cmd(); + return lcmxo2_wait_busy(); +} + +static void lcmxo2_read_flash_page (uint8_t *buffer) { + lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED); + lcmxo2_read_data(buffer, FLASH_PAGE_SIZE); + lcmxo2_finish_cmd(); +} + +static void lcmxo2_program_done (void) { + lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL); + lcmxo2_finish_cmd(); + lcmxo2_wait_busy(); +} + +static void lcmxo2_write_featbits (uint8_t *buffer) { + lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL); + lcmxo2_write_data(buffer, FEATBITS_SIZE); + lcmxo2_finish_cmd(); +} + +static void lcmxo2_read_featbits (uint8_t *buffer) { + lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL); + lcmxo2_read_data(buffer, FEATBITS_SIZE); + lcmxo2_finish_cmd(); +} + +static void lcmxo2_refresh (void) { + lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP); + lcmxo2_finish_cmd(); +} + +static vendor_error_t lcmxo2_fail (vendor_error_t error) { + lcmxo2_disable_flash(); + return error; +} + +uint32_t vendor_flash_size (void) { + return (FLASH_PAGE_SIZE * FLASH_NUM_PAGES); +} + +vendor_error_t vendor_backup (uint32_t address, uint32_t *length) { + uint8_t buffer[FLASH_PAGE_SIZE]; + + *length = 0; + + lcmxo2_reset_bus(); + if (lcmxo2_enable_flash()) { + return lcmxo2_fail(VENDOR_ERROR_INIT); + } + lcmxo2_reset_flash_address(); + for (int i = 0; i < (FLASH_PAGE_SIZE * FLASH_NUM_PAGES); i += FLASH_PAGE_SIZE) { + lcmxo2_read_flash_page(buffer); + fpga_mem_write(address + i, FLASH_PAGE_SIZE, buffer); + *length += FLASH_PAGE_SIZE; + } + lcmxo2_disable_flash(); + + return VENDOR_OK; +} + +vendor_error_t vendor_update (uint32_t address, uint32_t length) { + uint8_t buffer[FLASH_PAGE_SIZE]; + uint8_t verify_buffer[FLASH_PAGE_SIZE]; + + if (length == 0) { + return VENDOR_ERROR_ARGS; + } + if ((length % FLASH_PAGE_SIZE) != 0) { + return VENDOR_ERROR_ARGS; + } + if (length > (FLASH_PAGE_SIZE * FLASH_NUM_PAGES)) { + return VENDOR_ERROR_ARGS; + } + + lcmxo2_reset_bus(); + if (lcmxo2_enable_flash()) { + return lcmxo2_fail(VENDOR_ERROR_INIT); + } + if (lcmxo2_erase_flash()) { + return lcmxo2_fail(VENDOR_ERROR_ERASE); + } + lcmxo2_reset_flash_address(); + for (int i = 0; i < length; i += FLASH_PAGE_SIZE) { + fpga_mem_read(address + i, FLASH_PAGE_SIZE, buffer); + if (lcmxo2_write_flash_page(buffer)) { + return lcmxo2_fail(VENDOR_ERROR_PROGRAM); + } + } + lcmxo2_program_done(); + lcmxo2_reset_flash_address(); + for (int i = 0; i < length; i += FLASH_PAGE_SIZE) { + lcmxo2_read_flash_page(buffer); + fpga_mem_read(address + i, FLASH_PAGE_SIZE, verify_buffer); + for (int x = 0; x < FLASH_PAGE_SIZE; x++) { + if (buffer[x] != verify_buffer[x]) { + return lcmxo2_fail(VENDOR_ERROR_VERIFY); + } + } + } + lcmxo2_disable_flash(); + + return VENDOR_OK; +} + +vendor_error_t vendor_reconfigure (void) { + lcmxo2_reset_bus(); + lcmxo2_refresh(); + + return VENDOR_OK; +} + + +typedef enum { + CMD_GET_PRIMER_ID = '?', + CMD_PROBE_FPGA = '#', + CMD_RESTART = '$', + CMD_GET_DEVICE_ID = 'I', + CMD_ENABLE_FLASH = 'E', + CMD_DISABLE_FLASH = 'D', + CMD_ERASE_ALL = 'X', + CMD_RESET_ADDRESS = 'A', + CMD_WRITE_PAGE = 'W', + CMD_READ_PAGE = 'R', + CMD_PROGRAM_DONE = 'F', + CMD_WRITE_FEATBITS = 'Q', + CMD_READ_FEATBITS = 'Y', + CMD_REFRESH = 'B', +} primer_cmd_e; + + +static bool primer_check_rx_length (primer_cmd_e cmd, size_t rx_length) { + switch (cmd) { + case CMD_WRITE_PAGE: + return (rx_length != FLASH_PAGE_SIZE); + case CMD_WRITE_FEATBITS: + return (rx_length != FEATBITS_SIZE); + default: + return (rx_length != 0); + } + return true; +} + +void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_response_t send_response) { + bool runninng = true; + primer_cmd_e cmd; + uint8_t buffer[256]; + uint8_t rx_length; + uint8_t tx_length; + bool error; + + lcmxo2_reset_bus(); + + while (runninng) { + cmd = get_cmd(buffer, &rx_length); + tx_length = 0; + error = false; + + if (primer_check_rx_length(cmd, rx_length)) { + send_response(cmd, NULL, 0, true); + continue; + } + + switch (cmd) { + case CMD_GET_PRIMER_ID: + buffer[0] = 'M'; + buffer[1] = 'X'; + buffer[2] = 'O'; + buffer[3] = '2'; + tx_length = 4; + break; + + case CMD_PROBE_FPGA: + buffer[0] = fpga_id_get(); + tx_length = 1; + error = (buffer[0] != FPGA_ID); + break; + + case CMD_RESTART: + runninng = false; + break; + + case CMD_GET_DEVICE_ID: + lcmxo2_read_device_id(buffer); + tx_length = 4; + break; + + case CMD_ENABLE_FLASH: + error = lcmxo2_enable_flash(); + break; + + case CMD_DISABLE_FLASH: + lcmxo2_disable_flash(); + break; + + case CMD_ERASE_ALL: + error = lcmxo2_erase_all(); + break; + + case CMD_RESET_ADDRESS: + lcmxo2_reset_flash_address(); + break; + + case CMD_WRITE_PAGE: + error = lcmxo2_write_flash_page(buffer); + break; + + case CMD_READ_PAGE: + lcmxo2_read_flash_page(buffer); + tx_length = FLASH_PAGE_SIZE; + break; + + case CMD_PROGRAM_DONE: + lcmxo2_program_done(); + break; + + case CMD_WRITE_FEATBITS: + lcmxo2_write_featbits(buffer); + break; + + case CMD_READ_FEATBITS: + lcmxo2_read_featbits(buffer); + tx_length = FEATBITS_SIZE; + break; + + case CMD_REFRESH: + lcmxo2_refresh(); + hw_delay_ms(1000); + break; + + default: + error = true; + break; + } + + send_response(cmd, buffer, tx_length, error); + } +} diff --git a/sw/controller/src/loader.S b/sw/controller/src/loader.S index da493c8..059e702 100644 --- a/sw/controller/src/loader.S +++ b/sw/controller/src/loader.S @@ -3,11 +3,11 @@ .fpu softvfp .thumb + .section .text.Reset_Handler .type Reset_Handler, %function Reset_Handler: .global Reset_Handler - cpsid i init_text: ldr r0, =_stext @@ -51,8 +51,9 @@ boot: ldr r0, =_app_header push {r0} - bl set_vector_table_offset + bl hw_set_vector_table pop {r0} + ldr r1, [r0, #0] msr MSP, r1 ldr r1, [r0, #4] diff --git a/sw/controller/src/loader.c b/sw/controller/src/loader.c index 9a10708..be5e67f 100644 --- a/sw/controller/src/loader.c +++ b/sw/controller/src/loader.c @@ -4,17 +4,14 @@ #include "update.h" +void no_valid_image (void) { + hw_loader_init(); + hw_gpio_set(GPIO_ID_LED); +} + void loader (void) { if (update_check()) { hw_loader_init(); update_perform(); } } - -void no_valid_image (void) { - hw_gpio_set(GPIO_ID_LED); -} - -void set_vector_table_offset (uint32_t offset) { - SCB->VTOR = (__IOM uint32_t) (offset); -} diff --git a/sw/controller/src/primer.S b/sw/controller/src/primer.S new file mode 100644 index 0000000..ab6c0ba --- /dev/null +++ b/sw/controller/src/primer.S @@ -0,0 +1,53 @@ +.syntax unified +.cpu cortex-m0plus +.fpu softvfp +.thumb + + +.section .text.Reset_Handler +.type Reset_Handler, %function +Reset_Handler: + .global Reset_Handler + ldr r0, =_estack + msr msp, r0 + +init_bss: + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b 2f +1: + str r3, [r2] + adds r2, r2, #4 +2: + cmp r2, r4 + bcc 1b + +run: + ldr r0, =_header + bl hw_set_vector_table + bl primer + +loop: + b loop + + +.section .text.Default_Handler, "ax", %progbits +Default_Handler: + .global Default_Handler + b Default_Handler + + +.section .isr_vector, "a", %progbits +.type g_pfnVectors, %object +g_pfnVectors: + .global g_pfnVectors + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + + .weak NMI_Handler + .thumb_set NMI_Handler, Default_Handler + .weak HardFault_Handler + .thumb_set HardFault_Handler, Default_Handler diff --git a/sw/controller/src/primer.c b/sw/controller/src/primer.c new file mode 100644 index 0000000..207f282 --- /dev/null +++ b/sw/controller/src/primer.c @@ -0,0 +1,83 @@ +#include +#include +#include "hw.h" +#include "vendor.h" + + +static const uint8_t primer_hello[] = "SC64 Primer\n"; +static const uint8_t cmd_token[3] = { 'C', 'M', 'D' }; +static const uint8_t rsp_token[3] = { 'R', 'S', 'P' }; +static const uint8_t err_token[3] = { 'E', 'R', 'R' }; + + +static void primer_send_hello (void) { + hw_uart_write((uint8_t *) (primer_hello), sizeof(primer_hello) - 1); +} + +static void primer_get_and_calculate_crc32 (uint8_t *buffer, uint8_t rx_length, uint32_t *crc32) { + hw_uart_read(buffer, rx_length); + *crc32 = hw_crc32_calculate(buffer, rx_length); +} + +static uint8_t primer_get_command (uint8_t *buffer, uint8_t *rx_length) { + uint32_t calculated_crc32; + uint32_t received_crc32; + uint8_t token[4]; + + while (1) { + hw_crc32_reset(); + + primer_get_and_calculate_crc32(token, 4, &calculated_crc32); + if (memcmp(token, cmd_token, 3) != 0) { + continue; + } + + primer_get_and_calculate_crc32(rx_length, 1, &calculated_crc32); + + if (*rx_length > 0) { + primer_get_and_calculate_crc32(buffer, *rx_length, &calculated_crc32); + } + + hw_uart_read((uint8_t *) (&received_crc32), sizeof(received_crc32)); + if (calculated_crc32 == received_crc32) { + break; + } + } + + return token[3]; +} + +static void primer_send_and_calculate_crc32 (uint8_t *buffer, uint8_t tx_length, uint32_t *crc32) { + hw_uart_write(buffer, tx_length); + *crc32 = hw_crc32_calculate(buffer, tx_length); +} + +static void primer_send_response (uint8_t cmd, uint8_t *buffer, uint8_t tx_length, bool error) { + uint32_t calculated_crc32; + uint8_t *token = (uint8_t *) (error ? err_token : rsp_token); + uint8_t length = (error ? 0 : tx_length); + + hw_crc32_reset(); + + primer_send_and_calculate_crc32(token, 3, &calculated_crc32); + primer_send_and_calculate_crc32(&cmd, 1, &calculated_crc32); + + primer_send_and_calculate_crc32(&length, 1, &calculated_crc32); + + if ((!error) && (tx_length > 0)) { + primer_send_and_calculate_crc32(buffer, tx_length, &calculated_crc32); + } + + hw_uart_write((uint8_t *) (&calculated_crc32), sizeof(calculated_crc32)); +} + + +void primer (void) { + hw_primer_init(); + + primer_send_hello(); + + vendor_initial_configuration(primer_get_command, primer_send_response); + + hw_reset(NULL); +} diff --git a/sw/controller/src/update.c b/sw/controller/src/update.c index 90aa404..52549cf 100644 --- a/sw/controller/src/update.c +++ b/sw/controller/src/update.c @@ -24,6 +24,7 @@ typedef enum { CHUNK_ID_MCU_DATA = 2, CHUNK_ID_FPGA_DATA = 3, CHUNK_ID_BOOTLOADER_DATA = 4, + CHUNK_ID_PRIMER_DATA = 5, } chunk_id_t; @@ -264,6 +265,9 @@ update_error_t update_prepare (uint32_t address, uint32_t length) { parameters.bootloader_address = data_address; break; + case CHUNK_ID_PRIMER_DATA: + break; + default: return UPDATE_ERROR_UNKNOWN_CHUNK; } @@ -274,7 +278,7 @@ update_error_t update_prepare (uint32_t address, uint32_t length) { void update_start (void) { parameters.magic = UPDATE_MAGIC_START; - hw_loader_reset(¶meters); + hw_reset(¶meters); } bool update_check (void) { @@ -317,5 +321,5 @@ void update_perform (void) { vendor_reconfigure(); parameters.magic = 0; - hw_loader_reset(¶meters); + hw_reset(¶meters); } diff --git a/sw/controller/src/vendor.h b/sw/controller/src/vendor.h index 016fac6..e9e6672 100644 --- a/sw/controller/src/vendor.h +++ b/sw/controller/src/vendor.h @@ -2,6 +2,7 @@ #define VENDOR_H__ +#include #include @@ -14,11 +15,16 @@ typedef enum { VENDOR_ERROR_VERIFY, } vendor_error_t; +typedef uint8_t vendor_get_cmd_t (uint8_t *buffer, uint8_t *rx_length); +typedef void vendor_send_response_t (uint8_t cmd, uint8_t *buffer, uint8_t tx_length, bool error); + uint32_t vendor_flash_size (void); vendor_error_t vendor_backup (uint32_t address, uint32_t *length); vendor_error_t vendor_update (uint32_t address, uint32_t length); vendor_error_t vendor_reconfigure (void); +void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_response_t send_response); + #endif diff --git a/sw/update/update.py b/sw/update/update.py index 5bd7c5c..af7a1f6 100755 --- a/sw/update/update.py +++ b/sw/update/update.py @@ -134,6 +134,7 @@ class SC64UpdateData: __CHUNK_ID_MCU_DATA = 2 __CHUNK_ID_FPGA_DATA = 3 __CHUNK_ID_BOOTLOADER_DATA = 4 + __CHUNK_ID_PRIMER_DATA = 5 __data = b'' @@ -172,6 +173,9 @@ class SC64UpdateData: def add_bootloader_data(self, data: bytes) -> None: self.__add_chunk(self.__CHUNK_ID_BOOTLOADER_DATA, data) + def add_primer_data(self, data: bytes) -> None: + self.__add_chunk(self.__CHUNK_ID_PRIMER_DATA, data) + def get_update_data(self) -> bytes: return self.__data @@ -183,6 +187,7 @@ if __name__ == "__main__": parser.add_argument('--mcu', metavar='mcu_path', required=False, help='path to MCU update data') parser.add_argument('--fpga', metavar='fpga_path', required=False, help='path to FPGA update data') parser.add_argument('--boot', metavar='bootloader_path', required=False, help='path to N64 bootloader update data') + parser.add_argument('--primer', metavar='primer_path', required=False, help='path to MCU board bring-up data') parser.add_argument('output', metavar='output_path', help='path to final update data') if (len(sys.argv) <= 1): @@ -218,6 +223,10 @@ if __name__ == "__main__": with open(args.boot, 'rb+') as f: update.add_bootloader_data(f.read()) + if (args.primer): + with open(args.primer, 'rb+') as f: + update.add_primer_data(f.read()) + with open(args.output, 'wb+') as f: f.write(update.get_update_data()) except JedecError as e: