[SC64][SW] Added board bring-up via UART header

This commit is contained in:
Mateusz Faderewski 2023-01-15 16:57:05 +01:00
parent 4f6c65c770
commit bc921d762d
22 changed files with 792 additions and 308 deletions

View File

@ -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)"

View File

@ -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" ;

View File

@ -1,6 +1,7 @@
.set noat
.set noreorder
.section .data.ipl2
ipl2:
.global ipl2

View File

@ -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);
}

View File

@ -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

View File

@ -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
;;

View File

@ -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))

View File

@ -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);
}

View File

@ -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

50
sw/controller/primer.ld Normal file
View File

@ -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);
}

16
sw/controller/primer.mk Normal file
View File

@ -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

View File

@ -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

View File

@ -1,7 +1,11 @@
#include <stddef.h>
#include <stm32g0xx.h>
#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,7 +345,8 @@ hw_flash_t hw_flash_read (uint32_t offset) {
return *(uint64_t *) (FLASH_BASE + offset);
}
void hw_loader_reset (loader_parameters_t *parameters) {
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;
@ -321,6 +356,7 @@ void hw_loader_reset (loader_parameters_t *parameters) {
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++) {

View File

@ -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

View File

@ -1,5 +1,6 @@
#include <stdbool.h>
#include "fpga.h"
#include "hw.h"
#include "vendor.h"
@ -10,6 +11,9 @@
#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)
@ -26,17 +30,26 @@
#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,
@ -45,6 +58,7 @@ typedef enum {
} 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,
@ -55,14 +69,24 @@ static void lcmxo2_reg_set (uint8_t reg, uint8_t value) {
);
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) {
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
#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);
@ -74,13 +98,21 @@ static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type) {
VENDOR_SCR_START
);
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
#endif
}
static void lcmxo2_cleanup (void) {
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,
@ -97,9 +129,13 @@ static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) {
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;
@ -117,6 +153,13 @@ static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
);
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) {
@ -124,53 +167,84 @@ static bool lcmxo2_wait_busy (void) {
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();
lcmxo2_cleanup();
return error;
}
@ -194,7 +268,6 @@ vendor_error_t vendor_backup (uint32_t address, uint32_t *length) {
*length += FLASH_PAGE_SIZE;
}
lcmxo2_disable_flash();
lcmxo2_cleanup();
return VENDOR_OK;
}
@ -239,7 +312,6 @@ vendor_error_t vendor_update (uint32_t address, uint32_t length) {
}
}
lcmxo2_disable_flash();
lcmxo2_cleanup();
return VENDOR_OK;
}
@ -247,7 +319,133 @@ vendor_error_t vendor_update (uint32_t address, uint32_t length) {
vendor_error_t vendor_reconfigure (void) {
lcmxo2_reset_bus();
lcmxo2_refresh();
lcmxo2_cleanup();
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);
}
}

View File

@ -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]

View File

@ -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);
}

View File

@ -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

View File

@ -0,0 +1,83 @@
#include <stdbool.h>
#include <string.h>
#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);
}

View File

@ -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(&parameters);
hw_reset(&parameters);
}
bool update_check (void) {
@ -317,5 +321,5 @@ void update_perform (void) {
vendor_reconfigure();
parameters.magic = 0;
hw_loader_reset(&parameters);
hw_reset(&parameters);
}

View File

@ -2,6 +2,7 @@
#define VENDOR_H__
#include <stdbool.h>
#include <stdint.h>
@ -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

View File

@ -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: