2023-01-21 04:08:15 +01:00
|
|
|
#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_CFG_ENABLE (1 << 9)
|
|
|
|
#define LSC_STATUS_BUSY (1 << 12)
|
|
|
|
#define LSC_STATUS_FAIL (1 << 13)
|
|
|
|
|
|
|
|
#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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void lcmxo2_reset_bus (void) {
|
|
|
|
#ifdef LCMXO2_I2C
|
|
|
|
uint8_t reset_data = 0;
|
2024-01-29 14:23:18 +01:00
|
|
|
hw_i2c_trx(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), NULL, 0);
|
2023-01-21 04:08:15 +01:00
|
|
|
#else
|
|
|
|
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
|
|
|
|
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-01-29 14:23:18 +01:00
|
|
|
static bool lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint8_t *buffer, uint8_t length, bool write) {
|
2023-01-21 04:08:15 +01:00
|
|
|
#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);
|
2024-01-29 14:23:18 +01:00
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
if (write) {
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
packet[packet_length + i] = buffer[i];
|
|
|
|
}
|
|
|
|
packet_length += length;
|
|
|
|
}
|
2024-01-29 14:23:18 +01:00
|
|
|
|
2024-05-14 01:36:34 +02:00
|
|
|
i2c_error_t error = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
|
2024-01-29 14:23:18 +01:00
|
|
|
|
2024-05-14 01:36:34 +02:00
|
|
|
return (error != I2C_OK);
|
2023-01-21 04:08:15 +01:00
|
|
|
#else
|
|
|
|
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);
|
2024-01-29 14:23:18 +01:00
|
|
|
|
|
|
|
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
|
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
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
|
|
|
|
);
|
2024-01-29 14:23:18 +01:00
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
2024-01-29 14:23:18 +01:00
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
if (length > 0) {
|
|
|
|
if (write) {
|
|
|
|
lcmxo2_write_data(buffer, length);
|
|
|
|
} else {
|
|
|
|
lcmxo2_read_data(buffer, length);
|
|
|
|
}
|
|
|
|
}
|
2024-01-29 14:23:18 +01:00
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
2024-01-29 14:23:18 +01:00
|
|
|
|
|
|
|
return false;
|
2023-01-21 04:08:15 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-01-29 14:23:18 +01:00
|
|
|
static bool lcmxo2_read_device_id (uint8_t *id) {
|
|
|
|
return lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false);
|
2023-01-21 04:08:15 +01:00
|
|
|
}
|
|
|
|
|
2024-01-29 14:23:18 +01:00
|
|
|
static uint32_t lcmxo2_read_status (uint32_t *status) {
|
|
|
|
uint32_t tmp = 0;
|
|
|
|
bool error = lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&tmp), 4, false);
|
|
|
|
*status = SWAP32(tmp);
|
|
|
|
return error;
|
2023-01-21 04:08:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcmxo2_wait_busy (void) {
|
2024-01-29 14:23:18 +01:00
|
|
|
bool error;
|
2023-01-21 04:08:15 +01:00
|
|
|
uint32_t status;
|
|
|
|
do {
|
2024-01-29 14:23:18 +01:00
|
|
|
error = lcmxo2_read_status(&status);
|
|
|
|
} while ((!error) && (status & LSC_STATUS_BUSY));
|
|
|
|
return (error) || (status & LSC_STATUS_FAIL);
|
2023-01-21 04:08:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcmxo2_enable_flash (void) {
|
|
|
|
#ifdef LCMXO2_I2C
|
2024-01-29 14:23:18 +01:00
|
|
|
if (lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-21 04:08:15 +01:00
|
|
|
#else
|
2024-01-29 14:23:18 +01:00
|
|
|
if (lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-21 04:08:15 +01:00
|
|
|
#endif
|
|
|
|
return lcmxo2_wait_busy();
|
|
|
|
}
|
|
|
|
|
2024-01-29 14:23:18 +01:00
|
|
|
static bool lcmxo2_disable_flash (void) {
|
|
|
|
if (lcmxo2_wait_busy()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false);
|
2023-01-21 04:08:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcmxo2_erase_featbits (void) {
|
2024-01-29 14:23:18 +01:00
|
|
|
if (lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-21 04:08:15 +01:00
|
|
|
return lcmxo2_wait_busy();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcmxo2_erase_flash (void) {
|
2024-01-29 14:23:18 +01:00
|
|
|
if (lcmxo2_execute_cmd(ISC_ERASE, (ISC_ERASE_UFM | ISC_ERASE_CFG), CMD_NORMAL, NULL, 0, false)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-21 04:08:15 +01:00
|
|
|
return lcmxo2_wait_busy();
|
|
|
|
}
|
|
|
|
|
2024-01-29 14:23:18 +01:00
|
|
|
static bool lcmxo2_reset_flash_address (void) {
|
|
|
|
return lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false);
|
2023-01-21 04:08:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcmxo2_write_flash_page (uint8_t *buffer) {
|
2024-01-29 14:23:18 +01:00
|
|
|
if (lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-21 04:08:15 +01:00
|
|
|
return lcmxo2_wait_busy();
|
|
|
|
}
|
|
|
|
|
2024-01-29 14:23:18 +01:00
|
|
|
static bool lcmxo2_read_flash_page (uint8_t *buffer) {
|
|
|
|
return lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false);
|
2023-01-21 04:08:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcmxo2_program_done (void) {
|
2024-01-29 14:23:18 +01:00
|
|
|
if (lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-21 04:08:15 +01:00
|
|
|
return lcmxo2_wait_busy();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcmxo2_write_featbits (uint8_t *buffer) {
|
2024-01-29 14:23:18 +01:00
|
|
|
if (lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-21 04:08:15 +01:00
|
|
|
return lcmxo2_wait_busy();
|
|
|
|
}
|
|
|
|
|
2024-01-29 14:23:18 +01:00
|
|
|
static bool lcmxo2_read_featbits (uint8_t *buffer) {
|
|
|
|
return lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false);
|
2023-01-21 04:08:15 +01:00
|
|
|
}
|
|
|
|
|
2024-01-29 14:23:18 +01:00
|
|
|
static bool lcmxo2_refresh (void) {
|
|
|
|
return lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false);
|
2023-01-21 04:08:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lcmxo2_program_done()) {
|
|
|
|
return lcmxo2_fail(VENDOR_ERROR_PROGRAM);
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define FEATBITS_0_SPI_OFF (1 << 1)
|
|
|
|
#define FEATBITS_1_PROGRAMN_OFF (1 << 5)
|
|
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
CMD_GET_PRIMER_ID = '?',
|
|
|
|
CMD_PROBE_FPGA = '#',
|
|
|
|
CMD_RESTART = '$',
|
|
|
|
CMD_GET_DEVICE_ID = 'I',
|
|
|
|
CMD_ENABLE_FLASH = 'E',
|
|
|
|
CMD_ERASE_FLASH = 'X',
|
|
|
|
CMD_RESET_ADDRESS = 'A',
|
|
|
|
CMD_WRITE_PAGE = 'W',
|
|
|
|
CMD_READ_PAGE = 'R',
|
|
|
|
CMD_PROGRAM_DONE = 'F',
|
|
|
|
CMD_INIT_FEATBITS = 'Q',
|
|
|
|
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);
|
|
|
|
default:
|
|
|
|
return (rx_length != 0);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcmxo2_init_featbits (void) {
|
|
|
|
uint8_t programmed[2] = { 0x00, 0x00 };
|
|
|
|
uint8_t target[2] = { FEATBITS_0_SPI_OFF, FEATBITS_1_PROGRAMN_OFF };
|
2024-01-29 14:23:18 +01:00
|
|
|
|
|
|
|
if (lcmxo2_read_featbits(programmed)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
if ((programmed[0] == target[0]) && (programmed[1] == target[1])) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-01-29 14:23:18 +01:00
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
if (lcmxo2_erase_featbits()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (lcmxo2_write_featbits(target)) {
|
|
|
|
return true;
|
|
|
|
}
|
2024-01-29 14:23:18 +01:00
|
|
|
if (lcmxo2_read_featbits(programmed)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
if ((programmed[0] != target[0]) || (programmed[1] != target[1])) {
|
|
|
|
return true;
|
|
|
|
}
|
2024-01-29 14:23:18 +01:00
|
|
|
|
2023-01-21 04:08:15 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_RESTART:
|
|
|
|
runninng = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_GET_DEVICE_ID:
|
2024-01-29 14:23:18 +01:00
|
|
|
error = lcmxo2_read_device_id(buffer);
|
2023-01-21 04:08:15 +01:00
|
|
|
tx_length = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_ENABLE_FLASH:
|
|
|
|
error = lcmxo2_enable_flash();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_ERASE_FLASH:
|
|
|
|
error = lcmxo2_erase_flash();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_RESET_ADDRESS:
|
2024-01-29 14:23:18 +01:00
|
|
|
error = lcmxo2_reset_flash_address();
|
2023-01-21 04:08:15 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_WRITE_PAGE:
|
|
|
|
error = lcmxo2_write_flash_page(buffer);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_READ_PAGE:
|
2024-01-29 14:23:18 +01:00
|
|
|
error = lcmxo2_read_flash_page(buffer);
|
2023-01-21 04:08:15 +01:00
|
|
|
tx_length = FLASH_PAGE_SIZE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_PROGRAM_DONE:
|
|
|
|
error = lcmxo2_program_done();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_INIT_FEATBITS:
|
|
|
|
error = lcmxo2_init_featbits();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_REFRESH:
|
2024-01-29 14:23:18 +01:00
|
|
|
error = lcmxo2_refresh();
|
2023-01-21 04:08:15 +01:00
|
|
|
hw_delay_ms(200);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
send_response(cmd, buffer, tx_length, error);
|
|
|
|
}
|
|
|
|
}
|