diff --git a/src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.f b/src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.f new file mode 100644 index 0000000..a39ceb6 --- /dev/null +++ b/src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.f @@ -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 diff --git a/src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.sv b/src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.sv new file mode 100644 index 0000000..3bdf793 --- /dev/null +++ b/src/pyrite/rtl/pyrite_pcie_us_vsec_bpi.sv @@ -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 diff --git a/src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f b/src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f new file mode 100644 index 0000000..2bba095 --- /dev/null +++ b/src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f @@ -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 diff --git a/src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.sv b/src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.sv new file mode 100644 index 0000000..4ae937c --- /dev/null +++ b/src/pyrite/rtl/pyrite_pcie_us_vsec_qspi.sv @@ -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 diff --git a/src/pyrite/utils/pyrite.c b/src/pyrite/utils/pyrite.c index 88a1f74..cd6e94e 100644 --- a/src/pyrite/utils/pyrite.c +++ b/src/pyrite/utils/pyrite.c @@ -506,6 +506,7 @@ struct reg_if *reg_if_open_vpd(int fd) { char buf[32]; int offset; + bool found = false; 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) { pread(fd, buf, 2, offset); - if (buf[0] == PCI_CAP_ID_VPD) + if (buf[0] == PCI_CAP_ID_VPD) { + found = true; break; + } offset = buf[1] & 0xfc; } - if (!offset || buf[0] != PCI_CAP_ID_VPD) { - perror("Failed to locate VPD capability"); + if (!found) { + 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); return NULL; } @@ -554,7 +639,7 @@ int main(int argc, char *argv[]) int opt; int ret = 0; - struct reg_if *vpd_regs; + struct reg_if *ctrl_regs; char dev_name[32] = ""; char *read_file_name = NULL; @@ -683,9 +768,12 @@ int main(int argc, char *argv[]) return -1; } - vpd_regs = reg_if_open_vpd(config_fd); - if (!vpd_regs) { - perror("Failed to initialize VPD capability"); + if ((ctrl_regs = reg_if_open_vsec(config_fd))) { + // found VSEC + } else if ((ctrl_regs = reg_if_open_vpd(config_fd))) { + // found VPD + } else { + fprintf(stderr, "Failed to locate capability structure\n"); ret = -1; 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 (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"); 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); // disconnect - reg_if_close(vpd_regs); - vpd_regs = NULL; + reg_if_close(ctrl_regs); + ctrl_regs = NULL; close(config_fd); } @@ -1484,7 +1572,7 @@ err: flash_release(pri_flash); flash_release(sec_flash); - reg_if_close(vpd_regs); + reg_if_close(ctrl_regs); close(config_fd); return ret;