mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-25 23:24:15 +01:00
added fpga flash update access
This commit is contained in:
parent
0b18c55d1c
commit
9c710a2019
@ -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>
|
||||
|
@ -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"/>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
113
fw/rtl/vendor/lcmxo2/generated/efb_lattice_generated.v
vendored
Normal file
113
fw/rtl/vendor/lcmxo2/generated/efb_lattice_generated.v
vendored
Normal 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
127
fw/rtl/vendor/lcmxo2/vendor.sv
vendored
Normal 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
25
fw/rtl/vendor/vendor_scb.sv
vendored
Normal 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
|
@ -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);
|
||||
|
@ -24,6 +24,7 @@ SRC_FILES = \
|
||||
gvr.c \
|
||||
hw.c \
|
||||
isv.c \
|
||||
lcmxo2.c \
|
||||
main.c \
|
||||
rtc.c \
|
||||
task.c \
|
||||
|
@ -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
232
sw/controller/src/lcmxo2.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
23
sw/controller/src/vendor.h
Normal file
23
sw/controller/src/vendor.h
Normal 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
|
Loading…
Reference in New Issue
Block a user