added fpga flash update access

This commit is contained in:
Polprzewodnikowy 2022-08-01 23:30:40 +02:00
parent 0b18c55d1c
commit 9c710a2019
13 changed files with 595 additions and 7 deletions

View File

@ -78,12 +78,21 @@
<Source name="../../rtl/usb/usb_ft1248.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/vendor/vendor_scb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/vendor/lcmxo2/fifo_8kb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/vendor/lcmxo2/pll.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/vendor/lcmxo2/vendor.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/vendor/lcmxo2/generated/efb_lattice_generated.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/vendor/lcmxo2/generated/fifo_8kb_lattice_generated.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>

View File

@ -92,7 +92,7 @@
<Property name="PROP_MAP_MAPInferGSR" value="True" time="0"/>
<Property name="PROP_MAP_MapModArgs" value="" time="0"/>
<Property name="PROP_MAP_OvermapDevice" value="False" time="0"/>
<Property name="PROP_MAP_PackLogMapDes" value="" time="0"/>
<Property name="PROP_MAP_PackLogMapDes" value="0" time="0"/>
<Property name="PROP_MAP_RegRetiming" value="False" time="0"/>
<Property name="PROP_MAP_SigCrossRef" value="False" time="0"/>
<Property name="PROP_MAP_SymCrossRef" value="False" time="0"/>
@ -119,7 +119,7 @@
<Property name="PROP_PAR_PARModArgs" value="" time="0"/>
<Property name="PROP_PAR_ParMultiNodeList" value="" time="0"/>
<Property name="PROP_PAR_ParRunPlaceOnly" value="False" time="0"/>
<Property name="PROP_PAR_PlcIterParDes" value="1" time="0"/>
<Property name="PROP_PAR_PlcIterParDes" value="3" time="0"/>
<Property name="PROP_PAR_PlcStCostTblParDes" value="1" time="0"/>
<Property name="PROP_PAR_PrefErrorOut" value="True" time="0"/>
<Property name="PROP_PAR_RemoveDir" value="True" time="0"/>

View File

@ -9,6 +9,7 @@ module mcu_top (
sd_scb.controller sd_scb,
dma_scb.controller sd_dma_scb,
flash_scb.controller flash_scb,
vendor_scb.controller vendor_scb,
fifo_bus.controller fifo_bus,
mem_bus.controller mem_bus,
@ -353,7 +354,9 @@ module mcu_top (
REG_DD_CMD_DATA,
REG_DD_HEAD_TRACK,
REG_DD_SECTOR_INFO,
REG_DD_DRIVE_ID
REG_DD_DRIVE_ID,
REG_VENDOR_SCR,
REG_VENDOR_DATA
} reg_address_e;
logic bootloader_skip;
@ -579,6 +582,14 @@ module mcu_top (
dd_scb.sector_num
};
end
REG_VENDOR_SCR: begin
reg_rdata <= vendor_scb.control_rdata;
end
REG_VENDOR_DATA: begin
reg_rdata <= vendor_scb.data_rdata;
end
endcase
end
end
@ -614,6 +625,8 @@ module mcu_top (
dd_scb.bm_clear <= 1'b0;
dd_scb.bm_ready <= 1'b0;
vendor_scb.control_valid <= 1'b0;
if (n64_scb.n64_nmi) begin
n64_scb.bootloader_enabled <= !bootloader_skip;
end
@ -792,6 +805,15 @@ module mcu_top (
REG_DD_DRIVE_ID: begin
dd_scb.drive_id <= reg_wdata[15:0];
end
REG_VENDOR_SCR: begin
vendor_scb.control_valid <= 1'b1;
vendor_scb.control_wdata <= reg_wdata;
end
REG_VENDOR_DATA: begin
vendor_scb.data_wdata <= reg_wdata;
end
endcase
end
end

View File

@ -58,6 +58,7 @@ module top (
sd_scb sd_scb ();
dma_scb sd_dma_scb ();
flash_scb flash_scb ();
vendor_scb vendor_scb ();
fifo_bus usb_cfg_fifo_bus ();
fifo_bus usb_dma_fifo_bus ();
@ -93,6 +94,7 @@ module top (
.sd_scb(sd_scb),
.sd_dma_scb(sd_dma_scb),
.flash_scb(flash_scb),
.vendor_scb(vendor_scb),
.fifo_bus(usb_cfg_fifo_bus),
.mem_bus(cfg_mem_bus),
@ -250,4 +252,14 @@ module top (
.mem_bus(bram_mem_bus)
);
// Vendor specific control
vendor vendor_inst (
.clk(clk),
.reset(reset),
.vendor_scb(vendor_scb)
);
endmodule

View File

@ -0,0 +1,113 @@
/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.12.1.454 */
/* Module Version: 1.2 */
/* C:\lscc\diamond\3.12\ispfpga\bin\nt64\scuba.exe -w -n efb_lattice_generated -lang verilog -synth synplify -bus_exp 7 -bb -type efb -arch xo2c00 -freq 100 -ufm -ufm_ebr 2038 -mem_size 8 -ufm_0 -wb -dev 7000 */
/* Sun Jul 31 17:59:17 2022 */
`timescale 1 ns / 1 ps
module efb_lattice_generated (wb_clk_i, wb_rst_i, wb_cyc_i, wb_stb_i,
wb_we_i, wb_adr_i, wb_dat_i, wb_dat_o, wb_ack_o, wbc_ufm_irq)/* synthesis NGD_DRC_MASK=1 */;
input wire wb_clk_i;
input wire wb_rst_i;
input wire wb_cyc_i;
input wire wb_stb_i;
input wire wb_we_i;
input wire [7:0] wb_adr_i;
input wire [7:0] wb_dat_i;
output wire [7:0] wb_dat_o;
output wire wb_ack_o;
output wire wbc_ufm_irq;
wire scuba_vhi;
wire scuba_vlo;
VHI scuba_vhi_inst (.Z(scuba_vhi));
VLO scuba_vlo_inst (.Z(scuba_vlo));
defparam EFBInst_0.UFM_INIT_FILE_FORMAT = "HEX" ;
defparam EFBInst_0.UFM_INIT_FILE_NAME = "NONE" ;
defparam EFBInst_0.UFM_INIT_ALL_ZEROS = "ENABLED" ;
defparam EFBInst_0.UFM_INIT_START_PAGE = 2038 ;
defparam EFBInst_0.UFM_INIT_PAGES = 8 ;
defparam EFBInst_0.DEV_DENSITY = "7000L" ;
defparam EFBInst_0.EFB_UFM = "ENABLED" ;
defparam EFBInst_0.TC_ICAPTURE = "DISABLED" ;
defparam EFBInst_0.TC_OVERFLOW = "DISABLED" ;
defparam EFBInst_0.TC_ICR_INT = "OFF" ;
defparam EFBInst_0.TC_OCR_INT = "OFF" ;
defparam EFBInst_0.TC_OV_INT = "OFF" ;
defparam EFBInst_0.TC_TOP_SEL = "OFF" ;
defparam EFBInst_0.TC_RESETN = "ENABLED" ;
defparam EFBInst_0.TC_OC_MODE = "TOGGLE" ;
defparam EFBInst_0.TC_OCR_SET = 32767 ;
defparam EFBInst_0.TC_TOP_SET = 65535 ;
defparam EFBInst_0.GSR = "ENABLED" ;
defparam EFBInst_0.TC_CCLK_SEL = 1 ;
defparam EFBInst_0.TC_MODE = "CTCM" ;
defparam EFBInst_0.TC_SCLK_SEL = "PCLOCK" ;
defparam EFBInst_0.EFB_TC_PORTMODE = "WB" ;
defparam EFBInst_0.EFB_TC = "DISABLED" ;
defparam EFBInst_0.SPI_WAKEUP = "DISABLED" ;
defparam EFBInst_0.SPI_INTR_RXOVR = "DISABLED" ;
defparam EFBInst_0.SPI_INTR_TXOVR = "DISABLED" ;
defparam EFBInst_0.SPI_INTR_RXRDY = "DISABLED" ;
defparam EFBInst_0.SPI_INTR_TXRDY = "DISABLED" ;
defparam EFBInst_0.SPI_SLAVE_HANDSHAKE = "DISABLED" ;
defparam EFBInst_0.SPI_PHASE_ADJ = "DISABLED" ;
defparam EFBInst_0.SPI_CLK_INV = "DISABLED" ;
defparam EFBInst_0.SPI_LSB_FIRST = "DISABLED" ;
defparam EFBInst_0.SPI_CLK_DIVIDER = 2 ;
defparam EFBInst_0.SPI_MODE = "MASTER" ;
defparam EFBInst_0.EFB_SPI = "DISABLED" ;
defparam EFBInst_0.I2C2_WAKEUP = "DISABLED" ;
defparam EFBInst_0.I2C2_GEN_CALL = "DISABLED" ;
defparam EFBInst_0.I2C2_CLK_DIVIDER = 1 ;
defparam EFBInst_0.I2C2_BUS_PERF = "100kHz" ;
defparam EFBInst_0.I2C2_SLAVE_ADDR = "0b1000010" ;
defparam EFBInst_0.I2C2_ADDRESSING = "7BIT" ;
defparam EFBInst_0.EFB_I2C2 = "DISABLED" ;
defparam EFBInst_0.I2C1_WAKEUP = "DISABLED" ;
defparam EFBInst_0.I2C1_GEN_CALL = "DISABLED" ;
defparam EFBInst_0.I2C1_CLK_DIVIDER = 1 ;
defparam EFBInst_0.I2C1_BUS_PERF = "100kHz" ;
defparam EFBInst_0.I2C1_SLAVE_ADDR = "0b1000001" ;
defparam EFBInst_0.I2C1_ADDRESSING = "7BIT" ;
defparam EFBInst_0.EFB_I2C1 = "DISABLED" ;
defparam EFBInst_0.EFB_WB_CLK_FREQ = "100.0" ;
EFB EFBInst_0 (.WBCLKI(wb_clk_i), .WBRSTI(wb_rst_i), .WBCYCI(wb_cyc_i),
.WBSTBI(wb_stb_i), .WBWEI(wb_we_i), .WBADRI7(wb_adr_i[7]), .WBADRI6(wb_adr_i[6]),
.WBADRI5(wb_adr_i[5]), .WBADRI4(wb_adr_i[4]), .WBADRI3(wb_adr_i[3]),
.WBADRI2(wb_adr_i[2]), .WBADRI1(wb_adr_i[1]), .WBADRI0(wb_adr_i[0]),
.WBDATI7(wb_dat_i[7]), .WBDATI6(wb_dat_i[6]), .WBDATI5(wb_dat_i[5]),
.WBDATI4(wb_dat_i[4]), .WBDATI3(wb_dat_i[3]), .WBDATI2(wb_dat_i[2]),
.WBDATI1(wb_dat_i[1]), .WBDATI0(wb_dat_i[0]), .PLL0DATI7(scuba_vlo),
.PLL0DATI6(scuba_vlo), .PLL0DATI5(scuba_vlo), .PLL0DATI4(scuba_vlo),
.PLL0DATI3(scuba_vlo), .PLL0DATI2(scuba_vlo), .PLL0DATI1(scuba_vlo),
.PLL0DATI0(scuba_vlo), .PLL0ACKI(scuba_vlo), .PLL1DATI7(scuba_vlo),
.PLL1DATI6(scuba_vlo), .PLL1DATI5(scuba_vlo), .PLL1DATI4(scuba_vlo),
.PLL1DATI3(scuba_vlo), .PLL1DATI2(scuba_vlo), .PLL1DATI1(scuba_vlo),
.PLL1DATI0(scuba_vlo), .PLL1ACKI(scuba_vlo), .I2C1SCLI(scuba_vlo),
.I2C1SDAI(scuba_vlo), .I2C2SCLI(scuba_vlo), .I2C2SDAI(scuba_vlo),
.SPISCKI(scuba_vlo), .SPIMISOI(scuba_vlo), .SPIMOSII(scuba_vlo),
.SPISCSN(scuba_vlo), .TCCLKI(scuba_vlo), .TCRSTN(scuba_vlo), .TCIC(scuba_vlo),
.UFMSN(scuba_vhi), .WBDATO7(wb_dat_o[7]), .WBDATO6(wb_dat_o[6]),
.WBDATO5(wb_dat_o[5]), .WBDATO4(wb_dat_o[4]), .WBDATO3(wb_dat_o[3]),
.WBDATO2(wb_dat_o[2]), .WBDATO1(wb_dat_o[1]), .WBDATO0(wb_dat_o[0]),
.WBACKO(wb_ack_o), .PLLCLKO(), .PLLRSTO(), .PLL0STBO(), .PLL1STBO(),
.PLLWEO(), .PLLADRO4(), .PLLADRO3(), .PLLADRO2(), .PLLADRO1(), .PLLADRO0(),
.PLLDATO7(), .PLLDATO6(), .PLLDATO5(), .PLLDATO4(), .PLLDATO3(),
.PLLDATO2(), .PLLDATO1(), .PLLDATO0(), .I2C1SCLO(), .I2C1SCLOEN(),
.I2C1SDAO(), .I2C1SDAOEN(), .I2C2SCLO(), .I2C2SCLOEN(), .I2C2SDAO(),
.I2C2SDAOEN(), .I2C1IRQO(), .I2C2IRQO(), .SPISCKO(), .SPISCKEN(),
.SPIMISOO(), .SPIMISOEN(), .SPIMOSIO(), .SPIMOSIEN(), .SPIMCSN7(),
.SPIMCSN6(), .SPIMCSN5(), .SPIMCSN4(), .SPIMCSN3(), .SPIMCSN2(),
.SPIMCSN1(), .SPIMCSN0(), .SPICSNEN(), .SPIIRQO(), .TCINT(), .TCOC(),
.WBCUFMIRQ(wbc_ufm_irq), .CFGWAKE(), .CFGSTDBY());
// exemplar begin
// exemplar end
endmodule

127
fw/rtl/vendor/lcmxo2/vendor.sv vendored Normal file
View File

@ -0,0 +1,127 @@
module vendor (
input clk,
input reset,
vendor_scb.vendor vendor_scb
);
logic start;
logic busy;
logic [1:0] length;
logic [5:0] delay;
logic request;
logic write;
logic ack;
logic [7:0] address;
logic [7:0] rdata;
logic [7:0] wdata;
logic [23:0] wdata_buffer;
logic ufm_irq;
always_comb begin
start = vendor_scb.control_valid && vendor_scb.control_wdata[0] && !busy;
vendor_scb.control_rdata = {
16'd0,
address,
4'b0000,
length,
write,
busy
};
end
always_ff @(posedge clk) begin
if (reset) begin
busy <= 1'b0;
end else begin
if (start) begin
busy <= 1'b1;
end
if (length == 2'd0 && ack) begin
busy <= 1'b0;
end
end
end
always_ff @(posedge clk) begin
if (start) begin
length <= vendor_scb.control_wdata[3:2];
end
if (ack && length > 2'd0) begin
length <= length - 1'd1;
end
end
always_ff @(posedge clk) begin
if (reset) begin
delay <= 6'd0;
end else begin
if (start && vendor_scb.control_wdata[4]) begin
delay <= 6'd35;
end
if (delay > 6'd0) begin
delay <= delay - 1'd1;
end
end
end
always_ff @(posedge clk) begin
if (reset) begin
request <= 1'b0;
end else begin
if (start) begin
request <= 1'b1;
end
if (busy && !request && delay == 6'd0) begin
request <= 1'b1;
end
if (ack) begin
request <= 1'b0;
end
end
end
always_ff @(posedge clk) begin
if (start) begin
write <= vendor_scb.control_wdata[1];
end
end
always_ff @(posedge clk) begin
if (start) begin
address <= vendor_scb.control_wdata[15:8];
end
end
always_ff @(posedge clk) begin
if (ack) begin
vendor_scb.data_rdata <= {vendor_scb.data_rdata[23:0], rdata};
end
end
always_ff @(posedge clk) begin
if (start) begin
{wdata, wdata_buffer} <= vendor_scb.data_wdata;
end
if (ack) begin
{wdata, wdata_buffer} <= {wdata_buffer, 8'h00};
end
end
efb_lattice_generated efb_lattice_generated_inst (
.wb_clk_i(clk),
.wb_rst_i(reset),
.wb_cyc_i(request),
.wb_stb_i(request),
.wb_we_i(write),
.wb_adr_i(address),
.wb_dat_i(wdata),
.wb_dat_o(rdata),
.wb_ack_o(ack),
.wbc_ufm_irq(ufm_irq)
);
endmodule

25
fw/rtl/vendor/vendor_scb.sv vendored Normal file
View File

@ -0,0 +1,25 @@
interface vendor_scb ();
logic control_valid;
logic [31:0] control_rdata;
logic [31:0] control_wdata;
logic [31:0] data_rdata;
logic [31:0] data_wdata;
modport controller (
output control_valid,
input control_rdata,
output control_wdata,
input data_rdata,
output data_wdata
);
modport vendor (
input control_valid,
output control_rdata,
input control_wdata,
output data_rdata,
input data_wdata
);
endinterface

View File

@ -93,7 +93,7 @@ bool sc64_usb_write_ready (void) {
return result[0];
}
void sc64_usb_write (uint32_t *address, uint32_t length) {
bool sc64_usb_write (uint32_t *address, uint32_t length) {
while (!sc64_usb_write_ready());
uint32_t args[2] = { (uint32_t) (address), length };
return sc64_execute_cmd(SC64_CMD_USB_WRITE, args, NULL);

View File

@ -24,6 +24,7 @@ SRC_FILES = \
gvr.c \
hw.c \
isv.c \
lcmxo2.c \
main.c \
rtc.c \
task.c \

View File

@ -50,7 +50,9 @@ typedef enum {
REG_DD_CMD_DATA,
REG_DD_HEAD_TRACK,
REG_DD_SECTOR_INFO,
REG_DD_DRIVE_ID
REG_DD_DRIVE_ID,
REG_VENDOR_SCR,
REG_VENDOR_DATA
} fpga_reg_t;

232
sw/controller/src/lcmxo2.c Normal file
View File

@ -0,0 +1,232 @@
#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 uint8_t lcmxo2_reg_get (uint8_t reg) {
fpga_reg_set(REG_VENDOR_SCR,
(reg << VENDOR_SCR_ADDRESS_BIT) |
(0 << VENDOR_SCR_LENGTH_BIT) |
VENDOR_SCR_START
);
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
return fpga_reg_get(REG_VENDOR_DATA) & 0xFF;
}
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) {
for (uint32_t i = 0; i < length; i++) {
*buffer++ = lcmxo2_reg_get(LCMXO2_CFGRXDR);
}
}
static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
for (uint32_t i = 0; i < length; i++) {
lcmxo2_reg_set(LCMXO2_CFGTXDR, *buffer++);
}
}
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;
}
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_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_reconfigure (void) {
lcmxo2_reset_bus();
lcmxo2_refresh();
lcmxo2_cleanup();
return VENDOR_OK;
}

View File

@ -1,12 +1,13 @@
#include <stdbool.h>
#include <stdint.h>
#include "cfg.h"
#include "cic.h"
#include "dd.h"
#include "cfg.h"
#include "flash.h"
#include "fpga.h"
#include "rtc.h"
#include "usb.h"
#include "flash.h"
#include "vendor.h"
enum rx_state {
@ -249,12 +250,33 @@ static void usb_rx_process (void) {
}
break;
case 'f':
p.response_info.data[0] = vendor_backup(p.rx_args[0], &p.response_info.data[1]);
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
p.response_info.data_length = 8;
if (p.response_info.data[0] != VENDOR_OK) {
p.response_error = true;
}
break;
case 'F':
p.response_info.data[0] = vendor_update(p.rx_args[0], p.rx_args[1]);
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
p.response_info.data_length = 4;
if (p.response_info.data[0] != VENDOR_OK) {
p.response_error = true;
}
break;
default:
p.rx_state = RX_STATE_IDLE;
p.response_pending = true;
p.response_error = true;
p.response_info.data_length = 4;
p.response_info.data[0] = 0xFF;
break;
}
}
}

View File

@ -0,0 +1,23 @@
#ifndef VENDOR_H__
#define VENDOR_H__
#include <stdint.h>
typedef enum {
VENDOR_OK,
VENDOR_ERROR_ARGS,
VENDOR_ERROR_INIT,
VENDOR_ERROR_ERASE,
VENDOR_ERROR_PROGRAM,
VENDOR_ERROR_VERIFY,
} vendor_error_t;
vendor_error_t vendor_update (uint32_t address, uint32_t length);
vendor_error_t vendor_backup (uint32_t address, uint32_t *length);
vendor_error_t vendor_reconfigure (void);
#endif