mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
[SC64][SW] Added board bring-up via UART header
This commit is contained in:
parent
4f6c65c770
commit
bc921d762d
3
build.sh
3
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)"
|
||||
|
@ -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" ;
|
||||
|
@ -1,6 +1,7 @@
|
||||
.set noat
|
||||
.set noreorder
|
||||
|
||||
|
||||
.section .data.ipl2
|
||||
ipl2:
|
||||
.global ipl2
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
;;
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
50
sw/controller/primer.ld
Normal 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
16
sw/controller/primer.mk
Normal 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
|
@ -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
|
||||
|
@ -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,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++) {
|
||||
|
@ -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
|
||||
|
@ -1,253 +1,451 @@
|
||||
#include <stdbool.h>
|
||||
#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 <stdbool.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
}
|
||||
|
53
sw/controller/src/primer.S
Normal file
53
sw/controller/src/primer.S
Normal 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
|
83
sw/controller/src/primer.c
Normal file
83
sw/controller/src/primer.c
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user