mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
[SC64][SW] Made I2C in primer stable
This commit is contained in:
parent
bc921d762d
commit
6081391bca
@ -70,7 +70,7 @@ $(BUILD_DIR)/bootloader.elf: $(OBJS) N64.ld
|
|||||||
$(BUILD_DIR)/bootloader.bin: $(BUILD_DIR)/bootloader.elf
|
$(BUILD_DIR)/bootloader.bin: $(BUILD_DIR)/bootloader.elf
|
||||||
@$(OBJCOPY) -O binary $< $@
|
@$(OBJCOPY) -O binary $< $@
|
||||||
@chksum64 $@ > /dev/null
|
@chksum64 $@ > /dev/null
|
||||||
@truncate --size=1028k $@
|
@$(PYTHON) tools/strip.py $@
|
||||||
|
|
||||||
$(BUILD_DIR)/bootloader.hex: $(BUILD_DIR)/bootloader.bin
|
$(BUILD_DIR)/bootloader.hex: $(BUILD_DIR)/bootloader.bin
|
||||||
@$(OBJCOPY) -I binary -O ihex $< $@
|
@$(OBJCOPY) -I binary -O ihex $< $@
|
||||||
|
@ -55,6 +55,13 @@ SECTIONS {
|
|||||||
. += __stack_size;
|
. += __stack_size;
|
||||||
_sp = .;
|
_sp = .;
|
||||||
|
|
||||||
|
.fill : {
|
||||||
|
. = ALIGN(1024);
|
||||||
|
FILL(0xFFFFFFFF);
|
||||||
|
BYTE(0xFFFFFFFF);
|
||||||
|
. = ORIGIN(rom) + LENGTH(rom);
|
||||||
|
} > rom
|
||||||
|
|
||||||
/DISCARD/ : {
|
/DISCARD/ : {
|
||||||
*(.MIPS.*)
|
*(.MIPS.*)
|
||||||
}
|
}
|
||||||
|
25
sw/bootloader/tools/strip.py
Normal file
25
sw/bootloader/tools/strip.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if (len(sys.argv) != 2):
|
||||||
|
print(f"Usage: python {sys.argv[0]} file_path")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
file = sys.argv[1]
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = b''
|
||||||
|
with open(file, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
with open(file, 'wb') as f:
|
||||||
|
f.write(data.strip(b'\xFF'))
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Couldn't open file \"{file}\"")
|
||||||
|
sys.exit(2)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
sys.exit(3)
|
@ -126,6 +126,10 @@ void hw_uart_write (uint8_t *data, int length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hw_uart_wait_busy (void) {
|
||||||
|
while (!(USART1->ISR & USART_ISR_TC));
|
||||||
|
}
|
||||||
|
|
||||||
void hw_spi_start (void) {
|
void hw_spi_start (void) {
|
||||||
hw_gpio_reset(GPIO_ID_SPI_CS);
|
hw_gpio_reset(GPIO_ID_SPI_CS);
|
||||||
}
|
}
|
||||||
@ -195,26 +199,42 @@ 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) {
|
void hw_i2c_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
|
||||||
if (type & I2C_START) {
|
while (I2C1->ISR & I2C_ISR_BUSY);
|
||||||
|
|
||||||
|
if (tx_length > 0) {
|
||||||
I2C1->ICR = I2C_ICR_NACKCF;
|
I2C1->ICR = I2C_ICR_NACKCF;
|
||||||
}
|
I2C1->CR2 = (
|
||||||
I2C1->CR2 = (
|
((rx_length == 0) ? I2C_CR2_AUTOEND : 0) |
|
||||||
((type & I2C_AUTOEND) ? I2C_CR2_AUTOEND : 0) |
|
(tx_length << I2C_CR2_NBYTES_Pos) |
|
||||||
(length << I2C_CR2_NBYTES_Pos) |
|
I2C_CR2_START |
|
||||||
((type & I2C_STOP) ? I2C_CR2_STOP : 0) |
|
(i2c_address << I2C_CR2_SADD_Pos)
|
||||||
((type & I2C_START) ? I2C_CR2_START : 0) |
|
);
|
||||||
((type & I2C_READ) ? I2C_CR2_RD_WRN : 0) |
|
for (int i = 0; i < tx_length; i++) {
|
||||||
(i2c_address << I2C_CR2_SADD_Pos)
|
while (!(I2C1->ISR & I2C_ISR_TXIS));
|
||||||
);
|
I2C1->TXDR = *tx_data++;
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
if (!(I2C1->CR2 & I2C_CR2_AUTOEND)) {
|
||||||
|
while (!(I2C1->ISR & (I2C_ISR_NACKF | I2C_ISR_TC)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_length > 0) {
|
||||||
|
I2C1->CR2 = (
|
||||||
|
I2C_CR2_AUTOEND |
|
||||||
|
(rx_length << I2C_CR2_NBYTES_Pos) |
|
||||||
|
I2C_CR2_START |
|
||||||
|
I2C_CR2_RD_WRN |
|
||||||
|
(i2c_address << I2C_CR2_SADD_Pos)
|
||||||
|
);
|
||||||
|
for (int i = 0; i < rx_length; i++) {
|
||||||
|
while (!(I2C1->ISR & I2C_ISR_RXNE));
|
||||||
|
*rx_data++ = I2C1->RXDR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tx_length > 0) || (rx_length > 0)) {
|
||||||
|
while (!(I2C1->ISR & I2C_ISR_STOPF));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +458,7 @@ static void hw_init_spi (void) {
|
|||||||
static void hw_init_i2c (void) {
|
static void hw_init_i2c (void) {
|
||||||
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
|
RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
|
||||||
|
|
||||||
I2C1->TIMINGR = 0x10B17DB5UL;
|
I2C1->TIMINGR = 0x00C12166UL;
|
||||||
I2C1->CR1 |= (I2C_CR1_TCIE | I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE | I2C_CR1_PE);
|
I2C1->CR1 |= (I2C_CR1_TCIE | I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE | I2C_CR1_PE);
|
||||||
|
|
||||||
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_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
||||||
@ -450,12 +470,12 @@ static void hw_init_uart (void) {
|
|||||||
|
|
||||||
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
|
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
|
||||||
|
|
||||||
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_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, 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);
|
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->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;
|
USART1->RQR = USART_RQR_TXFRQ | USART_RQR_RXFRQ;
|
||||||
|
USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_init_tim (void) {
|
static void hw_init_tim (void) {
|
||||||
|
@ -73,13 +73,14 @@ void hw_gpio_set (gpio_id_t id);
|
|||||||
void hw_gpio_reset (gpio_id_t id);
|
void hw_gpio_reset (gpio_id_t id);
|
||||||
void hw_uart_read (uint8_t *data, int length);
|
void hw_uart_read (uint8_t *data, int length);
|
||||||
void hw_uart_write (uint8_t *data, int length);
|
void hw_uart_write (uint8_t *data, int length);
|
||||||
|
void hw_uart_wait_busy (void);
|
||||||
void hw_spi_start (void);
|
void hw_spi_start (void);
|
||||||
void hw_spi_stop (void);
|
void hw_spi_stop (void);
|
||||||
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction);
|
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_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));
|
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);
|
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_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
|
||||||
void hw_i2c_disable_irq (void);
|
void hw_i2c_disable_irq (void);
|
||||||
void hw_i2c_enable_irq (void);
|
void hw_i2c_enable_irq (void);
|
||||||
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void));
|
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void));
|
||||||
|
@ -36,12 +36,14 @@
|
|||||||
#define LSC_READ_FEABITS (0xFB)
|
#define LSC_READ_FEABITS (0xFB)
|
||||||
#define ISC_NOOP (0xFF)
|
#define ISC_NOOP (0xFF)
|
||||||
|
|
||||||
|
#define ISC_ERASE_SRAM (1 << 16)
|
||||||
#define ISC_ERASE_FEATURE (1 << 17)
|
#define ISC_ERASE_FEATURE (1 << 17)
|
||||||
#define ISC_ERASE_CFG (1 << 18)
|
#define ISC_ERASE_CFG (1 << 18)
|
||||||
#define ISC_ERASE_UFM (1 << 19)
|
#define ISC_ERASE_UFM (1 << 19)
|
||||||
|
|
||||||
#define LSC_STATUS_1_BUSY (1 << 4)
|
#define LSC_STATUS_CFG_ENABLE (1 << 9)
|
||||||
#define LSC_STATUS_1_FAIL (1 << 5)
|
#define LSC_STATUS_BUSY (1 << 12)
|
||||||
|
#define LSC_STATUS_FAIL (1 << 13)
|
||||||
|
|
||||||
#define DEVICE_ID_SIZE (4)
|
#define DEVICE_ID_SIZE (4)
|
||||||
|
|
||||||
@ -69,50 +71,8 @@ static void lcmxo2_reg_set (uint8_t reg, uint8_t value) {
|
|||||||
);
|
);
|
||||||
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
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) {
|
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) {
|
while (length > 0) {
|
||||||
uint32_t block_size = (length > 4) ? 4 : length;
|
uint32_t block_size = (length > 4) ? 4 : length;
|
||||||
fpga_reg_set(REG_VENDOR_SCR,
|
fpga_reg_set(REG_VENDOR_SCR,
|
||||||
@ -129,13 +89,9 @@ static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) {
|
|||||||
length -= 1;
|
length -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
|
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) {
|
while (length > 0) {
|
||||||
uint32_t block_size = (length > 4) ? 4 : length;
|
uint32_t block_size = (length > 4) ? 4 : length;
|
||||||
uint32_t data = 0;
|
uint32_t data = 0;
|
||||||
@ -153,94 +109,128 @@ static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
|
|||||||
);
|
);
|
||||||
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
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), NULL, 0);
|
||||||
|
#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, uint8_t *buffer, uint8_t length, bool write) {
|
||||||
|
#ifdef LCMXO2_I2C
|
||||||
|
uint8_t packet[20] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) };
|
||||||
|
int packet_length = ((type == CMD_TWO_OP) ? 3 : 4);
|
||||||
|
if (write) {
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
packet[packet_length + i] = buffer[i];
|
||||||
|
}
|
||||||
|
packet_length += length;
|
||||||
|
}
|
||||||
|
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
|
||||||
|
#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);
|
||||||
|
if (length > 0) {
|
||||||
|
if (write) {
|
||||||
|
lcmxo2_write_data(buffer, length);
|
||||||
|
} else {
|
||||||
|
lcmxo2_read_data(buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_read_device_id (uint8_t *id) {
|
static void lcmxo2_read_device_id (uint8_t *id) {
|
||||||
lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL);
|
lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false);
|
||||||
lcmxo2_read_data(id, DEVICE_ID_SIZE);
|
}
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
|
static uint32_t lcmxo2_read_status (void) {
|
||||||
|
uint32_t status = 0;
|
||||||
|
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&status), 4, false);
|
||||||
|
return SWAP32(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_wait_busy (void) {
|
static bool lcmxo2_wait_busy (void) {
|
||||||
uint8_t status[4];
|
uint32_t status;
|
||||||
do {
|
do {
|
||||||
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL);
|
status = lcmxo2_read_status();
|
||||||
lcmxo2_read_data(status, 4);
|
} while(status & LSC_STATUS_BUSY);
|
||||||
lcmxo2_finish_cmd();
|
return (status & LSC_STATUS_FAIL);
|
||||||
} while(status[2] & LSC_STATUS_1_BUSY);
|
|
||||||
return status[2] & LSC_STATUS_1_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_enable_flash (void) {
|
static bool lcmxo2_enable_flash (void) {
|
||||||
#ifdef LCMXO2_I2C
|
#ifdef LCMXO2_I2C
|
||||||
lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_NORMAL);
|
lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false);
|
||||||
#else
|
#else
|
||||||
lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL);
|
lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false);
|
||||||
#endif
|
#endif
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_disable_flash (void) {
|
static void lcmxo2_disable_flash (void) {
|
||||||
lcmxo2_wait_busy();
|
lcmxo2_wait_busy();
|
||||||
lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP);
|
lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false);
|
||||||
lcmxo2_finish_cmd();
|
lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false);
|
||||||
lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL);
|
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_erase_flash (void) {
|
static bool lcmxo2_erase_sram (void) {
|
||||||
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG, CMD_NORMAL);
|
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_SRAM, CMD_NORMAL, NULL, 0, false);
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_erase_all (void) {
|
static bool lcmxo2_erase_featbits (void) {
|
||||||
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG | ISC_ERASE_FEATURE, CMD_NORMAL);
|
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false);
|
||||||
lcmxo2_finish_cmd();
|
return lcmxo2_wait_busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool lcmxo2_erase_flash (void) {
|
||||||
|
lcmxo2_execute_cmd(ISC_ERASE, (ISC_ERASE_UFM | ISC_ERASE_CFG), CMD_NORMAL, NULL, 0, false);
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_reset_flash_address (void) {
|
static void lcmxo2_reset_flash_address (void) {
|
||||||
lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL);
|
lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false);
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lcmxo2_write_flash_page (uint8_t *buffer) {
|
static bool lcmxo2_write_flash_page (uint8_t *buffer) {
|
||||||
lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL);
|
lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true);
|
||||||
lcmxo2_write_data(buffer, FLASH_PAGE_SIZE);
|
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
return lcmxo2_wait_busy();
|
return lcmxo2_wait_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_read_flash_page (uint8_t *buffer) {
|
static void lcmxo2_read_flash_page (uint8_t *buffer) {
|
||||||
lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED);
|
lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false);
|
||||||
lcmxo2_read_data(buffer, FLASH_PAGE_SIZE);
|
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_program_done (void) {
|
static void lcmxo2_program_done (void) {
|
||||||
lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL);
|
lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false);
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
lcmxo2_wait_busy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_write_featbits (uint8_t *buffer) {
|
static void lcmxo2_write_featbits (uint8_t *buffer) {
|
||||||
lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL);
|
lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true);
|
||||||
lcmxo2_write_data(buffer, FEATBITS_SIZE);
|
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_read_featbits (uint8_t *buffer) {
|
static void lcmxo2_read_featbits (uint8_t *buffer) {
|
||||||
lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL);
|
lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false);
|
||||||
lcmxo2_read_data(buffer, FEATBITS_SIZE);
|
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lcmxo2_refresh (void) {
|
static void lcmxo2_refresh (void) {
|
||||||
lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP);
|
lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false);
|
||||||
lcmxo2_finish_cmd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static vendor_error_t lcmxo2_fail (vendor_error_t error) {
|
static vendor_error_t lcmxo2_fail (vendor_error_t error) {
|
||||||
@ -248,6 +238,7 @@ static vendor_error_t lcmxo2_fail (vendor_error_t error) {
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t vendor_flash_size (void) {
|
uint32_t vendor_flash_size (void) {
|
||||||
return (FLASH_PAGE_SIZE * FLASH_NUM_PAGES);
|
return (FLASH_PAGE_SIZE * FLASH_NUM_PAGES);
|
||||||
}
|
}
|
||||||
@ -324,6 +315,10 @@ vendor_error_t vendor_reconfigure (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define FEATBITS_0_SPI_OFF (1 << 1)
|
||||||
|
#define FEATBITS_1_PROGRAMN_OFF (1 << 5)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CMD_GET_PRIMER_ID = '?',
|
CMD_GET_PRIMER_ID = '?',
|
||||||
CMD_PROBE_FPGA = '#',
|
CMD_PROBE_FPGA = '#',
|
||||||
@ -331,13 +326,12 @@ typedef enum {
|
|||||||
CMD_GET_DEVICE_ID = 'I',
|
CMD_GET_DEVICE_ID = 'I',
|
||||||
CMD_ENABLE_FLASH = 'E',
|
CMD_ENABLE_FLASH = 'E',
|
||||||
CMD_DISABLE_FLASH = 'D',
|
CMD_DISABLE_FLASH = 'D',
|
||||||
CMD_ERASE_ALL = 'X',
|
CMD_ERASE_FLASH = 'X',
|
||||||
CMD_RESET_ADDRESS = 'A',
|
CMD_RESET_ADDRESS = 'A',
|
||||||
CMD_WRITE_PAGE = 'W',
|
CMD_WRITE_PAGE = 'W',
|
||||||
CMD_READ_PAGE = 'R',
|
CMD_READ_PAGE = 'R',
|
||||||
CMD_PROGRAM_DONE = 'F',
|
CMD_PROGRAM_DONE = 'F',
|
||||||
CMD_WRITE_FEATBITS = 'Q',
|
CMD_INIT_FEATBITS = 'Q',
|
||||||
CMD_READ_FEATBITS = 'Y',
|
|
||||||
CMD_REFRESH = 'B',
|
CMD_REFRESH = 'B',
|
||||||
} primer_cmd_e;
|
} primer_cmd_e;
|
||||||
|
|
||||||
@ -346,14 +340,13 @@ static bool primer_check_rx_length (primer_cmd_e cmd, size_t rx_length) {
|
|||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case CMD_WRITE_PAGE:
|
case CMD_WRITE_PAGE:
|
||||||
return (rx_length != FLASH_PAGE_SIZE);
|
return (rx_length != FLASH_PAGE_SIZE);
|
||||||
case CMD_WRITE_FEATBITS:
|
|
||||||
return (rx_length != FEATBITS_SIZE);
|
|
||||||
default:
|
default:
|
||||||
return (rx_length != 0);
|
return (rx_length != 0);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_response_t send_response) {
|
void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_response_t send_response) {
|
||||||
bool runninng = true;
|
bool runninng = true;
|
||||||
primer_cmd_e cmd;
|
primer_cmd_e cmd;
|
||||||
@ -386,7 +379,6 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
|
|||||||
case CMD_PROBE_FPGA:
|
case CMD_PROBE_FPGA:
|
||||||
buffer[0] = fpga_id_get();
|
buffer[0] = fpga_id_get();
|
||||||
tx_length = 1;
|
tx_length = 1;
|
||||||
error = (buffer[0] != FPGA_ID);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_RESTART:
|
case CMD_RESTART:
|
||||||
@ -403,11 +395,14 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_DISABLE_FLASH:
|
case CMD_DISABLE_FLASH:
|
||||||
lcmxo2_disable_flash();
|
if (lcmxo2_read_status() & LSC_STATUS_CFG_ENABLE) {
|
||||||
|
error = lcmxo2_erase_sram();
|
||||||
|
lcmxo2_disable_flash();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_ERASE_ALL:
|
case CMD_ERASE_FLASH:
|
||||||
error = lcmxo2_erase_all();
|
error = lcmxo2_erase_flash();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_RESET_ADDRESS:
|
case CMD_RESET_ADDRESS:
|
||||||
@ -427,18 +422,19 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
|
|||||||
lcmxo2_program_done();
|
lcmxo2_program_done();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_WRITE_FEATBITS:
|
case CMD_INIT_FEATBITS:
|
||||||
lcmxo2_write_featbits(buffer);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMD_READ_FEATBITS:
|
|
||||||
lcmxo2_read_featbits(buffer);
|
lcmxo2_read_featbits(buffer);
|
||||||
tx_length = FEATBITS_SIZE;
|
if ((buffer[0] != FEATBITS_0_SPI_OFF) && (buffer[1] != FEATBITS_1_PROGRAMN_OFF)) {
|
||||||
|
buffer[0] = FEATBITS_0_SPI_OFF;
|
||||||
|
buffer[1] = FEATBITS_1_PROGRAMN_OFF;
|
||||||
|
lcmxo2_erase_featbits();
|
||||||
|
lcmxo2_write_featbits(buffer);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_REFRESH:
|
case CMD_REFRESH:
|
||||||
lcmxo2_refresh();
|
lcmxo2_refresh();
|
||||||
hw_delay_ms(1000);
|
hw_delay_ms(100);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -4,16 +4,11 @@
|
|||||||
#include "vendor.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 cmd_token[3] = { 'C', 'M', 'D' };
|
||||||
static const uint8_t rsp_token[3] = { 'R', 'S', 'P' };
|
static const uint8_t rsp_token[3] = { 'R', 'S', 'P' };
|
||||||
static const uint8_t err_token[3] = { 'E', 'R', 'R' };
|
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) {
|
static void primer_get_and_calculate_crc32 (uint8_t *buffer, uint8_t rx_length, uint32_t *crc32) {
|
||||||
hw_uart_read(buffer, rx_length);
|
hw_uart_read(buffer, rx_length);
|
||||||
*crc32 = hw_crc32_calculate(buffer, rx_length);
|
*crc32 = hw_crc32_calculate(buffer, rx_length);
|
||||||
@ -74,10 +69,7 @@ static void primer_send_response (uint8_t cmd, uint8_t *buffer, uint8_t tx_lengt
|
|||||||
|
|
||||||
void primer (void) {
|
void primer (void) {
|
||||||
hw_primer_init();
|
hw_primer_init();
|
||||||
|
|
||||||
primer_send_hello();
|
|
||||||
|
|
||||||
vendor_initial_configuration(primer_get_command, primer_send_response);
|
vendor_initial_configuration(primer_get_command, primer_send_response);
|
||||||
|
hw_uart_wait_busy();
|
||||||
hw_reset(NULL);
|
hw_reset(NULL);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ class JedecFile:
|
|||||||
__fuse_length: int = 0
|
__fuse_length: int = 0
|
||||||
__fuse_offset: int = 0
|
__fuse_offset: int = 0
|
||||||
__fuse_data: bytes = b''
|
__fuse_data: bytes = b''
|
||||||
|
__fuse_ignore: bool = False
|
||||||
__byte_buffer: int = 0
|
__byte_buffer: int = 0
|
||||||
|
|
||||||
def __handle_q_field(self, f: BufferedRandom) -> None:
|
def __handle_q_field(self, f: BufferedRandom) -> None:
|
||||||
@ -77,6 +78,19 @@ class JedecFile:
|
|||||||
else:
|
else:
|
||||||
raise JedecError('Unexpected byte inside L field fuse data')
|
raise JedecError('Unexpected byte inside L field fuse data')
|
||||||
|
|
||||||
|
def __handle_n_field(self, f: BufferedRandom) -> None:
|
||||||
|
data = b''
|
||||||
|
buffer = b''
|
||||||
|
while (buffer != b'*'):
|
||||||
|
buffer = f.read(1)
|
||||||
|
if (buffer == b''):
|
||||||
|
raise JedecError('Unexpected end of file')
|
||||||
|
if (buffer != b'*'):
|
||||||
|
data += buffer
|
||||||
|
if (data == b'OTE END CONFIG DATA'):
|
||||||
|
self.__fuse_length = self.__fuse_offset
|
||||||
|
self.__fuse_ignore = True
|
||||||
|
|
||||||
def __ignore_field(self, f: BufferedRandom) -> None:
|
def __ignore_field(self, f: BufferedRandom) -> None:
|
||||||
data = None
|
data = None
|
||||||
while (data != b'*'):
|
while (data != b'*'):
|
||||||
@ -88,6 +102,7 @@ class JedecFile:
|
|||||||
self.__fuse_length = 0
|
self.__fuse_length = 0
|
||||||
self.__fuse_offset = 0
|
self.__fuse_offset = 0
|
||||||
self.__fuse_data = b''
|
self.__fuse_data = b''
|
||||||
|
self.__fuse_ignore = False
|
||||||
self.__byte_buffer = 0
|
self.__byte_buffer = 0
|
||||||
|
|
||||||
field = None
|
field = None
|
||||||
@ -104,8 +119,10 @@ class JedecFile:
|
|||||||
field = f.read(1)
|
field = f.read(1)
|
||||||
if (field == b'Q'):
|
if (field == b'Q'):
|
||||||
self.__handle_q_field(f)
|
self.__handle_q_field(f)
|
||||||
elif (field == b'L'):
|
elif (field == b'L' and not self.__fuse_ignore):
|
||||||
self.__handle_l_field(f)
|
self.__handle_l_field(f)
|
||||||
|
elif (field == b'N'):
|
||||||
|
self.__handle_n_field(f)
|
||||||
elif (field == b'\r' or field == b'\n'):
|
elif (field == b'\r' or field == b'\n'):
|
||||||
pass
|
pass
|
||||||
elif (field == b'\x03'):
|
elif (field == b'\x03'):
|
||||||
|
Loading…
Reference in New Issue
Block a user