mirror of
https://github.com/fpganinja/taxi.git
synced 2026-02-28 05:55:09 -08:00
pyrite: Add support for flashing via PCIe VSEC
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
3
src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.f
Normal file
3
src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.f
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pyrite_pcie_us_vsec_bpi.sv
|
||||||
|
../lib/taxi/src/pcie/rtl/taxi_pcie_us_vsec_apb.sv
|
||||||
|
../lib/taxi/src/apb/rtl/taxi_apb_if.sv
|
||||||
250
src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.sv
Normal file
250
src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.sv
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2026 FPGA Ninja, LLC
|
||||||
|
|
||||||
|
Authors:
|
||||||
|
- Alex Forencich
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
`resetall
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
`default_nettype none
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pyrite flashing support for UltraScale+ PCIe VSEC and BPI flash
|
||||||
|
*/
|
||||||
|
module pyrite_pcie_us_vsec_bpi #
|
||||||
|
(
|
||||||
|
parameter logic [15:0] EXT_CAP_ID = 16'h000B,
|
||||||
|
parameter logic [3:0] EXT_CAP_VERSION = 4'h1,
|
||||||
|
parameter logic [11:0] EXT_CAP_OFFSET = 12'h480,
|
||||||
|
parameter logic [11:0] EXT_CAP_NEXT = 12'h000,
|
||||||
|
parameter logic [15:0] EXT_CAP_VSEC_ID = 16'h00DB,
|
||||||
|
parameter logic [3:0] EXT_CAP_VSEC_REV = 4'h1,
|
||||||
|
|
||||||
|
// FW ID
|
||||||
|
parameter FPGA_ID = 32'hDEADBEEF,
|
||||||
|
parameter FW_ID = 32'h00000000,
|
||||||
|
parameter FW_VER = 32'h000_01_000,
|
||||||
|
parameter BOARD_ID = 32'h1234_0000,
|
||||||
|
parameter BOARD_VER = 32'h001_00_000,
|
||||||
|
parameter BUILD_DATE = 32'd602976000,
|
||||||
|
parameter GIT_HASH = 32'h5f87c2e8,
|
||||||
|
parameter RELEASE_INFO = 32'h00000000,
|
||||||
|
|
||||||
|
// Flash
|
||||||
|
parameter logic [3:0] FLASH_SEG_COUNT = 2,
|
||||||
|
parameter logic [3:0] FLASH_SEG_DEFAULT = 1,
|
||||||
|
parameter logic [3:0] FLASH_SEG_FALLBACK = 0,
|
||||||
|
parameter logic [31:0] FLASH_SEG0_SIZE = 32'h00000000,
|
||||||
|
parameter FLASH_DATA_W = 16,
|
||||||
|
parameter FLASH_ADDR_W = 23,
|
||||||
|
parameter FLASH_RGN_W = 1
|
||||||
|
)
|
||||||
|
(
|
||||||
|
input wire logic clk,
|
||||||
|
input wire logic rst,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCIe
|
||||||
|
*/
|
||||||
|
input wire logic cfg_ext_read_received,
|
||||||
|
input wire logic cfg_ext_write_received,
|
||||||
|
input wire logic [9:0] cfg_ext_register_number,
|
||||||
|
input wire logic [7:0] cfg_ext_function_number,
|
||||||
|
input wire logic [31:0] cfg_ext_write_data,
|
||||||
|
input wire logic [3:0] cfg_ext_write_byte_enable,
|
||||||
|
output wire logic [31:0] cfg_ext_read_data,
|
||||||
|
output wire logic cfg_ext_read_data_valid,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BPI flash
|
||||||
|
*/
|
||||||
|
output wire logic fpga_boot,
|
||||||
|
input wire logic [FLASH_DATA_W-1:0] flash_dq_i,
|
||||||
|
output wire logic [FLASH_DATA_W-1:0] flash_dq_o,
|
||||||
|
output wire logic flash_dq_oe,
|
||||||
|
output wire logic [FLASH_ADDR_W-1:0] flash_addr,
|
||||||
|
output wire logic [FLASH_RGN_W-1:0] flash_region,
|
||||||
|
output wire logic flash_region_oe,
|
||||||
|
output wire logic flash_ce_n,
|
||||||
|
output wire logic flash_oe_n,
|
||||||
|
output wire logic flash_we_n,
|
||||||
|
output wire logic flash_adv_n
|
||||||
|
);
|
||||||
|
|
||||||
|
taxi_apb_if #(
|
||||||
|
.DATA_W(32),
|
||||||
|
.ADDR_W(16)
|
||||||
|
) vsec_apb();
|
||||||
|
|
||||||
|
taxi_pcie_us_vsec_apb #(
|
||||||
|
.EXT_CAP_ID(EXT_CAP_ID),
|
||||||
|
.EXT_CAP_VERSION(EXT_CAP_VERSION),
|
||||||
|
.EXT_CAP_OFFSET(EXT_CAP_OFFSET),
|
||||||
|
.EXT_CAP_NEXT(EXT_CAP_NEXT),
|
||||||
|
.EXT_CAP_VSEC_ID(EXT_CAP_VSEC_ID),
|
||||||
|
.EXT_CAP_VSEC_REV(EXT_CAP_VSEC_REV)
|
||||||
|
)
|
||||||
|
vsec_cap_inst (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* APB interface for register space
|
||||||
|
*/
|
||||||
|
.m_apb(vsec_apb),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface to Ultrascale PCIe IP core
|
||||||
|
*/
|
||||||
|
.cfg_ext_read_received(cfg_ext_read_received),
|
||||||
|
.cfg_ext_write_received(cfg_ext_write_received),
|
||||||
|
.cfg_ext_register_number(cfg_ext_register_number),
|
||||||
|
.cfg_ext_function_number(cfg_ext_function_number),
|
||||||
|
.cfg_ext_write_data(cfg_ext_write_data),
|
||||||
|
.cfg_ext_write_byte_enable(cfg_ext_write_byte_enable),
|
||||||
|
.cfg_ext_read_data(cfg_ext_read_data),
|
||||||
|
.cfg_ext_read_data_valid(cfg_ext_read_data_valid)
|
||||||
|
);
|
||||||
|
|
||||||
|
logic vsec_apb_pready_reg = 1'b0;
|
||||||
|
logic [31:0] vsec_apb_prdata_reg = '0;
|
||||||
|
|
||||||
|
logic fpga_boot_reg = 1'b0;
|
||||||
|
|
||||||
|
logic [FLASH_DATA_W-1:0] flash_dq_o_reg = '0;
|
||||||
|
logic flash_dq_oe_reg = 1'b0;
|
||||||
|
logic [FLASH_ADDR_W-1:0] flash_addr_reg = '0;
|
||||||
|
logic [FLASH_RGN_W-1:0] flash_region_reg = '0;
|
||||||
|
logic flash_region_oe_reg = 1'b0;
|
||||||
|
logic flash_ce_n_reg = 1'b1;
|
||||||
|
logic flash_oe_n_reg = 1'b1;
|
||||||
|
logic flash_we_n_reg = 1'b1;
|
||||||
|
logic flash_adv_n_reg = 1'b1;
|
||||||
|
|
||||||
|
assign vsec_apb.pready = vsec_apb_pready_reg;
|
||||||
|
assign vsec_apb.prdata = vsec_apb_prdata_reg;
|
||||||
|
assign vsec_apb.pslverr = 1'b0;
|
||||||
|
assign vsec_apb.pruser = '0;
|
||||||
|
assign vsec_apb.pbuser = '0;
|
||||||
|
|
||||||
|
assign fpga_boot = fpga_boot_reg;
|
||||||
|
|
||||||
|
assign flash_dq_o = flash_dq_o_reg;
|
||||||
|
assign flash_dq_oe = flash_dq_oe_reg;
|
||||||
|
assign flash_addr = flash_addr_reg;
|
||||||
|
assign flash_region = flash_region_reg;
|
||||||
|
assign flash_region_oe = flash_region_oe_reg;
|
||||||
|
assign flash_ce_n = flash_ce_n_reg;
|
||||||
|
assign flash_oe_n = flash_oe_n_reg;
|
||||||
|
assign flash_we_n = flash_we_n_reg;
|
||||||
|
assign flash_adv_n = flash_adv_n_reg;
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
vsec_apb_pready_reg <= 1'b0;
|
||||||
|
|
||||||
|
if (vsec_apb.penable && vsec_apb.psel && !vsec_apb_pready_reg) begin
|
||||||
|
vsec_apb_pready_reg <= 1'b1;
|
||||||
|
vsec_apb_prdata_reg <= '0;
|
||||||
|
|
||||||
|
if (vsec_apb.pwrite) begin
|
||||||
|
case (8'({vsec_apb.paddr >> 2, 2'b00}))
|
||||||
|
// FW ID
|
||||||
|
8'h0C: begin
|
||||||
|
// FW ID: FPGA JTAG ID
|
||||||
|
fpga_boot_reg <= vsec_apb.pwdata == 32'hFEE1DEAD;
|
||||||
|
end
|
||||||
|
// BPI flash
|
||||||
|
8'h4C: begin
|
||||||
|
// BPI flash ctrl: format
|
||||||
|
fpga_boot_reg <= vsec_apb.pwdata == 32'hFEE1DEAD;
|
||||||
|
end
|
||||||
|
8'h50: begin
|
||||||
|
// BPI flash ctrl: control
|
||||||
|
if (vsec_apb.pstrb[0]) begin
|
||||||
|
flash_ce_n_reg <= vsec_apb.pwdata[0];
|
||||||
|
flash_oe_n_reg <= vsec_apb.pwdata[1];
|
||||||
|
flash_we_n_reg <= vsec_apb.pwdata[2];
|
||||||
|
flash_adv_n_reg <= vsec_apb.pwdata[3];
|
||||||
|
end
|
||||||
|
if (vsec_apb.pstrb[1]) begin
|
||||||
|
flash_dq_oe_reg <= vsec_apb.pwdata[8];
|
||||||
|
end
|
||||||
|
if (vsec_apb.pstrb[2]) begin
|
||||||
|
flash_region_oe_reg <= vsec_apb.pwdata[16];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
8'h54: begin
|
||||||
|
// BPI flash ctrl: address
|
||||||
|
{flash_region_reg, flash_addr_reg} <= (FLASH_ADDR_W+FLASH_RGN_W)'(vsec_apb.pwdata);
|
||||||
|
end
|
||||||
|
8'h58: flash_dq_o_reg <= FLASH_DATA_W'(vsec_apb.pwdata); // BPI flash ctrl: data
|
||||||
|
default: begin end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
case (8'({vsec_apb.paddr >> 2, 2'b00}))
|
||||||
|
// FW ID
|
||||||
|
8'h00: vsec_apb_prdata_reg <= 32'hffffffff; // FW ID: Type
|
||||||
|
8'h04: vsec_apb_prdata_reg <= 32'h000_01_000; // FW ID: Version
|
||||||
|
8'h08: vsec_apb_prdata_reg <= 32'h40; // FW ID: Next header
|
||||||
|
8'h0C: vsec_apb_prdata_reg <= FPGA_ID; // FW ID: FPGA JTAG ID
|
||||||
|
8'h10: vsec_apb_prdata_reg <= FW_ID; // FW ID: Firmware ID
|
||||||
|
8'h14: vsec_apb_prdata_reg <= FW_VER; // FW ID: Firmware version
|
||||||
|
8'h18: vsec_apb_prdata_reg <= BOARD_ID; // FW ID: Board ID
|
||||||
|
8'h1C: vsec_apb_prdata_reg <= BOARD_VER; // FW ID: Board version
|
||||||
|
8'h20: vsec_apb_prdata_reg <= BUILD_DATE; // FW ID: Build date
|
||||||
|
8'h24: vsec_apb_prdata_reg <= GIT_HASH; // FW ID: Git commit hash
|
||||||
|
8'h28: vsec_apb_prdata_reg <= RELEASE_INFO; // FW ID: Release info
|
||||||
|
// BPI flash
|
||||||
|
8'h40: vsec_apb_prdata_reg <= 32'h0000C121; // BPI flash ctrl: Type
|
||||||
|
8'h44: vsec_apb_prdata_reg <= 32'h000_01_000; // BPI flash ctrl: Version
|
||||||
|
8'h48: vsec_apb_prdata_reg <= 0; // BPI flash ctrl: Next header
|
||||||
|
8'h4C: begin
|
||||||
|
// BPI flash ctrl: format
|
||||||
|
vsec_apb_prdata_reg[3:0] <= FLASH_SEG_COUNT; // configuration
|
||||||
|
vsec_apb_prdata_reg[7:4] <= FLASH_SEG_DEFAULT; // default segment
|
||||||
|
vsec_apb_prdata_reg[11:8] <= FLASH_SEG_FALLBACK; // fallback segment
|
||||||
|
vsec_apb_prdata_reg[31:12] <= 20'(FLASH_SEG0_SIZE >> 12); // first segment size
|
||||||
|
end
|
||||||
|
8'h50: begin
|
||||||
|
// BPI flash ctrl: control
|
||||||
|
vsec_apb_prdata_reg[0] <= flash_ce_n_reg; // chip enable (inverted)
|
||||||
|
vsec_apb_prdata_reg[1] <= flash_oe_n_reg; // output enable (inverted)
|
||||||
|
vsec_apb_prdata_reg[2] <= flash_we_n_reg; // write enable (inverted)
|
||||||
|
vsec_apb_prdata_reg[3] <= flash_adv_n_reg; // address valid (inverted)
|
||||||
|
vsec_apb_prdata_reg[8] <= flash_dq_oe_reg; // data output enable
|
||||||
|
vsec_apb_prdata_reg[16] <= flash_region_oe_reg; // region output enable (addr bit 25)
|
||||||
|
end
|
||||||
|
8'h54: begin
|
||||||
|
// BPI flash ctrl: address
|
||||||
|
vsec_apb_prdata_reg <= 32'({flash_region_reg, flash_addr_reg});
|
||||||
|
end
|
||||||
|
8'h58: vsec_apb_prdata_reg <= 32'(flash_dq_i); // BPI flash ctrl: data
|
||||||
|
default: begin end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
if (rst) begin
|
||||||
|
vsec_apb_pready_reg <= 1'b0;
|
||||||
|
|
||||||
|
fpga_boot_reg <= 1'b0;
|
||||||
|
|
||||||
|
flash_dq_o_reg <= '0;
|
||||||
|
flash_dq_oe_reg <= 1'b0;
|
||||||
|
flash_addr_reg <= '0;
|
||||||
|
flash_region_reg <= '0;
|
||||||
|
flash_region_oe_reg <= 1'b0;
|
||||||
|
flash_ce_n_reg <= 1'b1;
|
||||||
|
flash_oe_n_reg <= 1'b1;
|
||||||
|
flash_we_n_reg <= 1'b1;
|
||||||
|
flash_adv_n_reg <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
`resetall
|
||||||
3
src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f
Normal file
3
src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pyrite_pcie_us_vsec_qspi.sv
|
||||||
|
../lib/taxi/src/pcie/rtl/taxi_pcie_us_vsec_apb.sv
|
||||||
|
../lib/taxi/src/apb/rtl/taxi_apb_if.sv
|
||||||
252
src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.sv
Normal file
252
src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.sv
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2026 FPGA Ninja, LLC
|
||||||
|
|
||||||
|
Authors:
|
||||||
|
- Alex Forencich
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
`resetall
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
`default_nettype none
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pyrite flashing support for UltraScale+ PCIe VSEC and QSPI flash
|
||||||
|
*/
|
||||||
|
module pyrite_pcie_us_vsec_qspi #
|
||||||
|
(
|
||||||
|
parameter logic [15:0] EXT_CAP_ID = 16'h000B,
|
||||||
|
parameter logic [3:0] EXT_CAP_VERSION = 4'h1,
|
||||||
|
parameter logic [11:0] EXT_CAP_OFFSET = 12'h480,
|
||||||
|
parameter logic [11:0] EXT_CAP_NEXT = 12'h000,
|
||||||
|
parameter logic [15:0] EXT_CAP_VSEC_ID = 16'h00DB,
|
||||||
|
parameter logic [3:0] EXT_CAP_VSEC_REV = 4'h1,
|
||||||
|
|
||||||
|
// FW ID
|
||||||
|
parameter FPGA_ID = 32'hDEADBEEF,
|
||||||
|
parameter FW_ID = 32'h00000000,
|
||||||
|
parameter FW_VER = 32'h000_01_000,
|
||||||
|
parameter BOARD_ID = 32'h1234_0000,
|
||||||
|
parameter BOARD_VER = 32'h001_00_000,
|
||||||
|
parameter BUILD_DATE = 32'd602976000,
|
||||||
|
parameter GIT_HASH = 32'h5f87c2e8,
|
||||||
|
parameter RELEASE_INFO = 32'h00000000,
|
||||||
|
|
||||||
|
// Flash
|
||||||
|
parameter logic [3:0] FLASH_SEG_COUNT = 2,
|
||||||
|
parameter logic [3:0] FLASH_SEG_DEFAULT = 1,
|
||||||
|
parameter logic [3:0] FLASH_SEG_FALLBACK = 0,
|
||||||
|
parameter logic [31:0] FLASH_SEG0_SIZE = 32'h00000000,
|
||||||
|
parameter FLASH_DATA_W = 4,
|
||||||
|
parameter logic FLASH_DUAL_QSPI = 1'b1
|
||||||
|
)
|
||||||
|
(
|
||||||
|
input wire logic clk,
|
||||||
|
input wire logic rst,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCIe
|
||||||
|
*/
|
||||||
|
input wire logic cfg_ext_read_received,
|
||||||
|
input wire logic cfg_ext_write_received,
|
||||||
|
input wire logic [9:0] cfg_ext_register_number,
|
||||||
|
input wire logic [7:0] cfg_ext_function_number,
|
||||||
|
input wire logic [31:0] cfg_ext_write_data,
|
||||||
|
input wire logic [3:0] cfg_ext_write_byte_enable,
|
||||||
|
output wire logic [31:0] cfg_ext_read_data,
|
||||||
|
output wire logic cfg_ext_read_data_valid,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* QSPI flash
|
||||||
|
*/
|
||||||
|
output wire logic fpga_boot,
|
||||||
|
output wire logic qspi_clk,
|
||||||
|
input wire logic [FLASH_DATA_W-1:0] qspi_0_dq_i,
|
||||||
|
output wire logic [FLASH_DATA_W-1:0] qspi_0_dq_o,
|
||||||
|
output wire logic [FLASH_DATA_W-1:0] qspi_0_dq_oe,
|
||||||
|
output wire logic qspi_0_cs,
|
||||||
|
input wire logic [FLASH_DATA_W-1:0] qspi_1_dq_i,
|
||||||
|
output wire logic [FLASH_DATA_W-1:0] qspi_1_dq_o,
|
||||||
|
output wire logic [FLASH_DATA_W-1:0] qspi_1_dq_oe,
|
||||||
|
output wire logic qspi_1_cs
|
||||||
|
);
|
||||||
|
|
||||||
|
taxi_apb_if #(
|
||||||
|
.DATA_W(32),
|
||||||
|
.ADDR_W(16)
|
||||||
|
) vsec_apb();
|
||||||
|
|
||||||
|
taxi_pcie_us_vsec_apb #(
|
||||||
|
.EXT_CAP_ID(EXT_CAP_ID),
|
||||||
|
.EXT_CAP_VERSION(EXT_CAP_VERSION),
|
||||||
|
.EXT_CAP_OFFSET(EXT_CAP_OFFSET),
|
||||||
|
.EXT_CAP_NEXT(EXT_CAP_NEXT),
|
||||||
|
.EXT_CAP_VSEC_ID(EXT_CAP_VSEC_ID),
|
||||||
|
.EXT_CAP_VSEC_REV(EXT_CAP_VSEC_REV)
|
||||||
|
)
|
||||||
|
vsec_cap_inst (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* APB interface for register space
|
||||||
|
*/
|
||||||
|
.m_apb(vsec_apb),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface to Ultrascale PCIe IP core
|
||||||
|
*/
|
||||||
|
.cfg_ext_read_received(cfg_ext_read_received),
|
||||||
|
.cfg_ext_write_received(cfg_ext_write_received),
|
||||||
|
.cfg_ext_register_number(cfg_ext_register_number),
|
||||||
|
.cfg_ext_function_number(cfg_ext_function_number),
|
||||||
|
.cfg_ext_write_data(cfg_ext_write_data),
|
||||||
|
.cfg_ext_write_byte_enable(cfg_ext_write_byte_enable),
|
||||||
|
.cfg_ext_read_data(cfg_ext_read_data),
|
||||||
|
.cfg_ext_read_data_valid(cfg_ext_read_data_valid)
|
||||||
|
);
|
||||||
|
|
||||||
|
logic vsec_apb_pready_reg = 1'b0;
|
||||||
|
logic [31:0] vsec_apb_prdata_reg = '0;
|
||||||
|
|
||||||
|
logic fpga_boot_reg = 1'b0;
|
||||||
|
|
||||||
|
logic qspi_clk_reg = 1'b0;
|
||||||
|
logic qspi_0_cs_reg = 1'b1;
|
||||||
|
logic [FLASH_DATA_W-1:0] qspi_0_dq_o_reg = '0;
|
||||||
|
logic [FLASH_DATA_W-1:0] qspi_0_dq_oe_reg = '0;
|
||||||
|
logic qspi_1_cs_reg = 1'b1;
|
||||||
|
logic [FLASH_DATA_W-1:0] qspi_1_dq_o_reg = '0;
|
||||||
|
logic [FLASH_DATA_W-1:0] qspi_1_dq_oe_reg = '0;
|
||||||
|
|
||||||
|
assign vsec_apb.pready = vsec_apb_pready_reg;
|
||||||
|
assign vsec_apb.prdata = vsec_apb_prdata_reg;
|
||||||
|
assign vsec_apb.pslverr = 1'b0;
|
||||||
|
assign vsec_apb.pruser = '0;
|
||||||
|
assign vsec_apb.pbuser = '0;
|
||||||
|
|
||||||
|
assign fpga_boot = fpga_boot_reg;
|
||||||
|
|
||||||
|
assign qspi_clk = qspi_clk_reg;
|
||||||
|
assign qspi_0_cs = qspi_0_cs_reg;
|
||||||
|
assign qspi_0_dq_o = qspi_0_dq_o_reg;
|
||||||
|
assign qspi_0_dq_oe = qspi_0_dq_oe_reg;
|
||||||
|
assign qspi_1_cs = FLASH_DUAL_QSPI ? qspi_1_cs_reg : 1'b1;
|
||||||
|
assign qspi_1_dq_o = FLASH_DUAL_QSPI ? qspi_1_dq_o_reg : '0;
|
||||||
|
assign qspi_1_dq_oe = FLASH_DUAL_QSPI ? qspi_1_dq_oe_reg : '0;
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
vsec_apb_pready_reg <= 1'b0;
|
||||||
|
|
||||||
|
if (vsec_apb.penable && vsec_apb.psel && !vsec_apb_pready_reg) begin
|
||||||
|
vsec_apb_pready_reg <= 1'b1;
|
||||||
|
vsec_apb_prdata_reg <= '0;
|
||||||
|
|
||||||
|
if (vsec_apb.pwrite) begin
|
||||||
|
case (8'({vsec_apb.paddr >> 2, 2'b00}))
|
||||||
|
// FW ID
|
||||||
|
8'h0C: begin
|
||||||
|
// FW ID: FPGA JTAG ID
|
||||||
|
fpga_boot_reg <= vsec_apb.pwdata == 32'hFEE1DEAD;
|
||||||
|
end
|
||||||
|
// QSPI flash
|
||||||
|
8'h4C: begin
|
||||||
|
// SPI flash ctrl: format
|
||||||
|
fpga_boot_reg <= vsec_apb.pwdata == 32'hFEE1DEAD;
|
||||||
|
end
|
||||||
|
8'h50: begin
|
||||||
|
// SPI flash ctrl: control 0
|
||||||
|
if (vsec_apb.pstrb[0]) begin
|
||||||
|
qspi_0_dq_o_reg <= vsec_apb.pwdata[3:0];
|
||||||
|
end
|
||||||
|
if (vsec_apb.pstrb[1]) begin
|
||||||
|
qspi_0_dq_oe_reg <= vsec_apb.pwdata[11:8];
|
||||||
|
end
|
||||||
|
if (vsec_apb.pstrb[2]) begin
|
||||||
|
qspi_clk_reg <= vsec_apb.pwdata[16];
|
||||||
|
qspi_0_cs_reg <= vsec_apb.pwdata[17];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
8'h54: begin
|
||||||
|
// SPI flash ctrl: control 1
|
||||||
|
if (FLASH_DUAL_QSPI) begin
|
||||||
|
if (vsec_apb.pstrb[0]) begin
|
||||||
|
qspi_1_dq_o_reg <= vsec_apb.pwdata[3:0];
|
||||||
|
end
|
||||||
|
if (vsec_apb.pstrb[1]) begin
|
||||||
|
qspi_1_dq_oe_reg <= vsec_apb.pwdata[11:8];
|
||||||
|
end
|
||||||
|
if (vsec_apb.pstrb[2]) begin
|
||||||
|
qspi_clk_reg <= vsec_apb.pwdata[16];
|
||||||
|
qspi_1_cs_reg <= vsec_apb.pwdata[17];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
default: begin end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
case (8'({vsec_apb.paddr >> 2, 2'b00}))
|
||||||
|
// FW ID
|
||||||
|
8'h00: vsec_apb_prdata_reg <= 32'hffffffff; // FW ID: Type
|
||||||
|
8'h04: vsec_apb_prdata_reg <= 32'h000_01_000; // FW ID: Version
|
||||||
|
8'h08: vsec_apb_prdata_reg <= 32'h40; // FW ID: Next header
|
||||||
|
8'h0C: vsec_apb_prdata_reg <= FPGA_ID; // FW ID: FPGA JTAG ID
|
||||||
|
8'h10: vsec_apb_prdata_reg <= FW_ID; // FW ID: Firmware ID
|
||||||
|
8'h14: vsec_apb_prdata_reg <= FW_VER; // FW ID: Firmware version
|
||||||
|
8'h18: vsec_apb_prdata_reg <= BOARD_ID; // FW ID: Board ID
|
||||||
|
8'h1C: vsec_apb_prdata_reg <= BOARD_VER; // FW ID: Board version
|
||||||
|
8'h20: vsec_apb_prdata_reg <= BUILD_DATE; // FW ID: Build date
|
||||||
|
8'h24: vsec_apb_prdata_reg <= GIT_HASH; // FW ID: Git commit hash
|
||||||
|
8'h28: vsec_apb_prdata_reg <= RELEASE_INFO; // FW ID: Release info
|
||||||
|
// QSPI flash
|
||||||
|
8'h40: vsec_apb_prdata_reg <= 32'h0000C120; // SPI flash ctrl: Type
|
||||||
|
8'h44: vsec_apb_prdata_reg <= 32'h000_01_000; // SPI flash ctrl: Version
|
||||||
|
8'h48: vsec_apb_prdata_reg <= 0; // SPI flash ctrl: Next header
|
||||||
|
8'h4C: begin
|
||||||
|
// SPI flash ctrl: format
|
||||||
|
vsec_apb_prdata_reg[3:0] <= FLASH_SEG_COUNT; // configuration
|
||||||
|
vsec_apb_prdata_reg[7:4] <= FLASH_SEG_DEFAULT; // default segment
|
||||||
|
vsec_apb_prdata_reg[11:8] <= FLASH_SEG_FALLBACK; // fallback segment
|
||||||
|
vsec_apb_prdata_reg[31:12] <= 20'(FLASH_SEG0_SIZE >> 12); // first segment size
|
||||||
|
end
|
||||||
|
8'h50: begin
|
||||||
|
// SPI flash ctrl: control 0
|
||||||
|
vsec_apb_prdata_reg[3:0] <= qspi_0_dq_i;
|
||||||
|
vsec_apb_prdata_reg[11:8] <= qspi_0_dq_oe;
|
||||||
|
vsec_apb_prdata_reg[16] <= qspi_clk;
|
||||||
|
vsec_apb_prdata_reg[17] <= qspi_0_cs;
|
||||||
|
end
|
||||||
|
8'h54: begin
|
||||||
|
// SPI flash ctrl: control 1
|
||||||
|
if (FLASH_DUAL_QSPI) begin
|
||||||
|
vsec_apb_prdata_reg[3:0] <= qspi_1_dq_i;
|
||||||
|
vsec_apb_prdata_reg[11:8] <= qspi_1_dq_oe;
|
||||||
|
vsec_apb_prdata_reg[16] <= qspi_clk;
|
||||||
|
vsec_apb_prdata_reg[17] <= qspi_1_cs;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
default: begin end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
if (rst) begin
|
||||||
|
vsec_apb_pready_reg <= 1'b0;
|
||||||
|
|
||||||
|
fpga_boot_reg <= 1'b0;
|
||||||
|
|
||||||
|
qspi_clk_reg <= 1'b0;
|
||||||
|
qspi_0_cs_reg <= 1'b1;
|
||||||
|
qspi_0_dq_o_reg <= '0;
|
||||||
|
qspi_0_dq_oe_reg <= '0;
|
||||||
|
qspi_1_cs_reg <= 1'b1;
|
||||||
|
qspi_1_dq_o_reg <= '0;
|
||||||
|
qspi_1_dq_oe_reg <= '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
`resetall
|
||||||
@@ -506,6 +506,7 @@ struct reg_if *reg_if_open_vpd(int fd)
|
|||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int offset;
|
int offset;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
struct reg_if *reg = calloc(sizeof(struct reg_if), 1);
|
struct reg_if *reg = calloc(sizeof(struct reg_if), 1);
|
||||||
|
|
||||||
@@ -530,14 +531,98 @@ struct reg_if *reg_if_open_vpd(int fd)
|
|||||||
while (offset > 0) {
|
while (offset > 0) {
|
||||||
pread(fd, buf, 2, offset);
|
pread(fd, buf, 2, offset);
|
||||||
|
|
||||||
if (buf[0] == PCI_CAP_ID_VPD)
|
if (buf[0] == PCI_CAP_ID_VPD) {
|
||||||
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
offset = buf[1] & 0xfc;
|
offset = buf[1] & 0xfc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!offset || buf[0] != PCI_CAP_ID_VPD) {
|
if (!found) {
|
||||||
perror("Failed to locate VPD capability");
|
reg_if_close(reg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->fd = fd;
|
||||||
|
priv->offset = offset;
|
||||||
|
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vsec_reg_priv {
|
||||||
|
int fd;
|
||||||
|
int offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int reg_if_vsec_read32(const struct reg_if *reg, size_t offset, uint32_t *value)
|
||||||
|
{
|
||||||
|
const struct vsec_reg_priv *priv = reg->priv;
|
||||||
|
uint32_t offs = offset & 0x7fffffff; // clear F
|
||||||
|
pwrite(priv->fd, &offs, 4, priv->offset+0x08);
|
||||||
|
pread(priv->fd, value, 4, priv->offset+0x0c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int reg_if_vsec_write32(const struct reg_if *reg, size_t offset, uint32_t value)
|
||||||
|
{
|
||||||
|
const struct vsec_reg_priv *priv = reg->priv;
|
||||||
|
uint32_t offs = offset | 0x80000000; // set F
|
||||||
|
pwrite(priv->fd, &value, 4, priv->offset+0x0c);
|
||||||
|
pwrite(priv->fd, &offs, 4, priv->offset+0x08);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reg_if_vsec_close(const struct reg_if *reg)
|
||||||
|
{
|
||||||
|
free(reg->priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct reg_if_ops reg_if_vsec_ops = {
|
||||||
|
.read32 = reg_if_vsec_read32,
|
||||||
|
.write32 = reg_if_vsec_write32,
|
||||||
|
.close = reg_if_vsec_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reg_if *reg_if_open_vsec(int fd)
|
||||||
|
{
|
||||||
|
uint32_t cap_hdr, vsec_hdr;
|
||||||
|
int offset;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
struct reg_if *reg = calloc(sizeof(struct reg_if), 1);
|
||||||
|
|
||||||
|
if (!reg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct vsec_reg_priv *priv = calloc(sizeof(struct vsec_reg_priv), 1);
|
||||||
|
|
||||||
|
if (!priv) {
|
||||||
|
free(reg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg->priv = priv;
|
||||||
|
reg->ops = ®_if_vsec_ops;
|
||||||
|
|
||||||
|
// find VSEC extended capability (ID 0x000b, VSEC ID 0x00db)
|
||||||
|
offset = 0x100;
|
||||||
|
|
||||||
|
while (offset > 0) {
|
||||||
|
pread(fd, &cap_hdr, 4, offset);
|
||||||
|
|
||||||
|
if ((cap_hdr & 0xfffff) == 0x1000b) {
|
||||||
|
pread(fd, &vsec_hdr, 4, offset+4);
|
||||||
|
if ((vsec_hdr & 0xfffff) == 0x100db) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = cap_hdr >> 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
reg_if_close(reg);
|
reg_if_close(reg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -554,7 +639,7 @@ int main(int argc, char *argv[])
|
|||||||
int opt;
|
int opt;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
struct reg_if *vpd_regs;
|
struct reg_if *ctrl_regs;
|
||||||
|
|
||||||
char dev_name[32] = "";
|
char dev_name[32] = "";
|
||||||
char *read_file_name = NULL;
|
char *read_file_name = NULL;
|
||||||
@@ -683,9 +768,12 @@ int main(int argc, char *argv[])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vpd_regs = reg_if_open_vpd(config_fd);
|
if ((ctrl_regs = reg_if_open_vsec(config_fd))) {
|
||||||
if (!vpd_regs) {
|
// found VSEC
|
||||||
perror("Failed to initialize VPD capability");
|
} else if ((ctrl_regs = reg_if_open_vpd(config_fd))) {
|
||||||
|
// found VPD
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to locate capability structure\n");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -699,7 +787,7 @@ int main(int argc, char *argv[])
|
|||||||
printf("PCIe ID (device): %s\n", strrchr(pci_device_path, '/')+1);
|
printf("PCIe ID (device): %s\n", strrchr(pci_device_path, '/')+1);
|
||||||
printf("PCIe ID (upstream port): %s\n", strrchr(pci_port_path, '/')+1);
|
printf("PCIe ID (upstream port): %s\n", strrchr(pci_port_path, '/')+1);
|
||||||
|
|
||||||
rb_list = enumerate_reg_block_list(vpd_regs, 0x4000, 0, 0x4000);
|
rb_list = enumerate_reg_block_list(ctrl_regs, 0x4000, 0, 0x4000);
|
||||||
|
|
||||||
printf("Register blocks:\n");
|
printf("Register blocks:\n");
|
||||||
for (struct reg_block *rb = rb_list; rb->regs; rb++)
|
for (struct reg_block *rb = rb_list; rb->regs; rb++)
|
||||||
@@ -1422,8 +1510,8 @@ skip_flash:
|
|||||||
reg_if_write32(fw_id_rb->regs, 0x0C, 0xFEE1DEAD);
|
reg_if_write32(fw_id_rb->regs, 0x0C, 0xFEE1DEAD);
|
||||||
|
|
||||||
// disconnect
|
// disconnect
|
||||||
reg_if_close(vpd_regs);
|
reg_if_close(ctrl_regs);
|
||||||
vpd_regs = NULL;
|
ctrl_regs = NULL;
|
||||||
close(config_fd);
|
close(config_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1484,7 +1572,7 @@ err:
|
|||||||
flash_release(pri_flash);
|
flash_release(pri_flash);
|
||||||
flash_release(sec_flash);
|
flash_release(sec_flash);
|
||||||
|
|
||||||
reg_if_close(vpd_regs);
|
reg_if_close(ctrl_regs);
|
||||||
close(config_fd);
|
close(config_fd);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
Reference in New Issue
Block a user