From 9af73f3bd3d0be7a3683c5d5903f4bb17dc24ad0 Mon Sep 17 00:00:00 2001 From: Nathanael Huffman Date: Fri, 6 Feb 2026 14:35:29 -0500 Subject: [PATCH 1/2] Remove an un-used I2CCore.rdl which was not used and had typos etc --- hdl/ip/bsv/I2C/BUCK | 25 ----------- hdl/ip/bsv/I2C/I2CCore.rdl | 72 ------------------------------ hdl/projects/sidecar/qsfp_x32/BUCK | 1 - 3 files changed, 98 deletions(-) delete mode 100644 hdl/ip/bsv/I2C/I2CCore.rdl diff --git a/hdl/ip/bsv/I2C/BUCK b/hdl/ip/bsv/I2C/BUCK index e5761718..ee1f317c 100644 --- a/hdl/ip/bsv/I2C/BUCK +++ b/hdl/ip/bsv/I2C/BUCK @@ -1,30 +1,5 @@ load("//tools:bsv.bzl", "bsv_bluesim_tests") load("//tools:bsv.bzl", "bsv_library") -load("//tools:rdl.bzl", "rdl_file") - -# rdl_file -# Note: Buck2 RDL rule enforces strict naming convention -# BSV outputs use "Regs" suffix, VHDL uses "_pkg" suffix -rdl_file( - visibility = ["PUBLIC"], - name = "I2CCore_rdl", - outputs = [ - "I2CCoreRegs.bsv", - "I2CCore.html", - "I2CCore.json", - ], - src = "I2CCore.rdl", -) - -# bsv_library -bsv_library( - visibility = ["PUBLIC"], - name = "I2CCoreRegs", - srcs = [":I2CCore_rdl"], - deps = [ - "//hdl/ip/bsv:RegCommon", - ], -) # bsv_library bsv_library( diff --git a/hdl/ip/bsv/I2C/I2CCore.rdl b/hdl/ip/bsv/I2C/I2CCore.rdl deleted file mode 100644 index d058fe83..00000000 --- a/hdl/ip/bsv/I2C/I2CCore.rdl +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2022 Oxide Computer Company -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -addrmap I2C_core { - name = "I2C Core Registers"; - desc = "Register description for the I2C Core's control registers"; - - default regwidth = 8; - default sw = rw; - default hw = r; - - reg { - name = "Address Byte"; - - field { - desc = "Address to transmit"; - } ADDR[7:1] = 0; - - field { - desc = "Read/write bit. '1' if reading from peripheral, '0' if writing to it."; - } RW[0:0] = 0; - } ADDRESS; - - reg { - name = "Receive data"; - default sw = r; - default hw = rw; - - field { - desc = "Last byte recieved"; - } DATA[7:0] = 0; - } RECEIVE; - - reg { - name = "Transmit data"; - default sw = r; - default hw = rw; - - field { - desc = "Next byte to send"; - } DATA[7:0] = 0; - } TRANSMIT; - - reg { - name = "Control bits for I2C Core"; - - field { - desc = "Begin a transaction"; - } START[0:0] = 0; - } CONTROL; - - reg { - name = "Status"; - default sw = r; - default hw = rw; - - field { - desc = "I2C bus is busy. '1' after a START, '0' after a STOP."; - } ERR[0:0] = 0; - - field { - desc = "'1' while core is idling, '0' otherwise."; - } DONE[1:1] = 0; - - field { - desc = "'1' while core is in a transaction, '0' otherwise"; - } BUSY[0:0] = 0; - } STATUS; -}; \ No newline at end of file diff --git a/hdl/projects/sidecar/qsfp_x32/BUCK b/hdl/projects/sidecar/qsfp_x32/BUCK index 0b3f6caf..45743601 100644 --- a/hdl/projects/sidecar/qsfp_x32/BUCK +++ b/hdl/projects/sidecar/qsfp_x32/BUCK @@ -19,7 +19,6 @@ rdl_file( src = "qsfp_x32_controller.rdl", deps = [ ":vsc8562_rdl", - "//hdl/ip/bsv/I2C:I2CCore_rdl", ":qsfp_modules_top_rdl", ], outputs = [ From d68e394c48bc8f8d6a32225d429da6393a332dd2 Mon Sep 17 00:00:00 2001 From: Nathanael Huffman Date: Sat, 7 Feb 2026 18:25:52 -0500 Subject: [PATCH 2/2] Increase espi register visibility --- hdl/ip/vhd/espi/BUCK | 1 + hdl/ip/vhd/espi/espi_spec_regs.vhd | 14 +++ hdl/ip/vhd/espi/espi_target_top.vhd | 22 +++- .../peripheral_channel/uart_channel_top.vhd | 18 +++ hdl/ip/vhd/espi/sims/espi_tb.vhd | 30 ++--- hdl/ip/vhd/espi/sys_regs/espi_regs.rdl | 112 +++++++++++++++++- hdl/ip/vhd/espi/sys_regs/espi_regs.vhd | 39 +++++- .../espi/sys_regs/espi_spec_regs_view_pkg.vhd | 39 ++++++ .../vhd/espi/txn_layer/response_processor.vhd | 14 ++- hdl/ip/vhd/espi/txn_layer/txn_layer_top.vhd | 10 +- 10 files changed, 270 insertions(+), 29 deletions(-) create mode 100644 hdl/ip/vhd/espi/sys_regs/espi_spec_regs_view_pkg.vhd diff --git a/hdl/ip/vhd/espi/BUCK b/hdl/ip/vhd/espi/BUCK index 9da68291..a92cd6b6 100644 --- a/hdl/ip/vhd/espi/BUCK +++ b/hdl/ip/vhd/espi/BUCK @@ -18,6 +18,7 @@ rdl_file( rdl_file( name = "espi_regs_rdl", src = "sys_regs/espi_regs.rdl", + deps = [":espi_spec_regs_rdl"], outputs = ["espi_regs_pkg.vhd", "espi_regs.html", "espi_regs.json"], visibility = ['PUBLIC'] ) diff --git a/hdl/ip/vhd/espi/espi_spec_regs.vhd b/hdl/ip/vhd/espi/espi_spec_regs.vhd index 3dc70229..fe64ba78 100644 --- a/hdl/ip/vhd/espi/espi_spec_regs.vhd +++ b/hdl/ip/vhd/espi/espi_spec_regs.vhd @@ -15,6 +15,7 @@ use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.numeric_std_unsigned.all; use work.espi_spec_regs_pkg.all; +use work.espi_spec_regs_view_pkg.all; use work.link_layer_pkg.all; use work.espi_base_types_pkg.all; @@ -26,6 +27,9 @@ entity espi_spec_regs is regs_if : view regs_side; espi_reset : in std_logic; + -- Read-only view of all spec registers for the sys_regs block + spec_regs_view : view spec_regs_source; + qspi_mode : out qspi_mode_t; wait_states : out std_logic_vector(3 downto 0); oob_enabled : out std_logic; @@ -41,6 +45,7 @@ architecture rtl of espi_spec_regs is signal ch1_capabilities : ch1_capabilities_type; signal ch2_capabilities : ch2_capabilities_type; signal ch3_capabilities : ch3_capabilities_type; + constant ch3_capabilities2 : ch3_capabilities2_type := rec_reset; signal readdata_valid : std_logic; signal readdata : std_logic_vector(31 downto 0); signal qspi_freq : qspi_freq_t; @@ -53,6 +58,15 @@ begin flash_channel_enable <= ch3_capabilities.flash_channel_enable = '1'; oob_enabled <= ch2_capabilities.chan_en; + + spec_regs_view.device_id <= device_id; + spec_regs_view.general_capabilities <= gen_capabilities; + spec_regs_view.ch0_capabilities <= ch0_capabilities; + spec_regs_view.ch1_capabilities <= ch1_capabilities; + spec_regs_view.ch2_capabilities <= ch2_capabilities; + spec_regs_view.ch3_capabilities <= ch3_capabilities; + spec_regs_view.ch3_capabilities2 <= ch3_capabilities2; + -- Write-side of the spec-defined registers write_reg: process(clk, reset) begin diff --git a/hdl/ip/vhd/espi/espi_target_top.vhd b/hdl/ip/vhd/espi/espi_target_top.vhd index 8b4e9ed9..b52fdb22 100644 --- a/hdl/ip/vhd/espi/espi_target_top.vhd +++ b/hdl/ip/vhd/espi/espi_target_top.vhd @@ -14,6 +14,7 @@ use ieee.numeric_std.all; use ieee.numeric_std_unsigned.all; use work.qspi_link_layer_pkg.all; use work.espi_base_types_pkg.all; +use work.espi_spec_regs_view_pkg.all; use work.flash_channel_pkg.all; use work.uart_channel_pkg.all; use work.link_layer_pkg.all; @@ -68,6 +69,7 @@ architecture rtl of espi_target_top is signal flash_c_avail : std_logic; signal flash_channel_enable : boolean; signal dbg_chan : dbg_chan_t; + signal spec_regs : spec_regs_t; signal response_done : boolean; signal pc_free : std_logic; signal pc_avail : std_logic; @@ -107,6 +109,10 @@ architecture rtl of espi_target_top is signal oob_enabled : std_logic; signal stuff_fifo : std_logic; signal stuff_wds : std_logic_vector(15 downto 0); + signal last_resp_status : std_logic_vector(15 downto 0); + signal host_to_sp_fifo_usedwds : std_logic_vector(12 downto 0); + signal oob_free_saw_full : std_logic; + signal live_espi_status : std_logic_vector(15 downto 0); begin @@ -254,11 +260,16 @@ begin stuff_fifo => stuff_fifo, stuff_wds => stuff_wds, dbg_chan => dbg_chan, + spec_regs_view => spec_regs, post_code => post_code, post_code_valid => post_code_valid, espi_reset => espi_reset_strobe_syncd, to_host_tx_fifo_usedwds => to_host_tx_fifo_usedwds, - ipcc_to_host_byte_cntr => ipcc_to_host_byte_cntr + ipcc_to_host_byte_cntr => ipcc_to_host_byte_cntr, + live_espi_status => live_espi_status, + last_resp_status => last_resp_status, + host_to_sp_fifo_usedwds => host_to_sp_fifo_usedwds, + oob_free_saw_full => oob_free_saw_full ); -- txn layer blocks @@ -292,7 +303,9 @@ begin np_avail => np_avail, oob_free => oob_free, oob_avail => oob_avail, - vwire_avail => vwire_avail + vwire_avail => vwire_avail, + live_espi_status => live_espi_status, + last_resp_status => last_resp_status ); -- espi-internal register block @@ -302,6 +315,7 @@ begin reset => reset, espi_reset => espi_reset_strobe_syncd, regs_if => regs_if, + spec_regs_view => spec_regs, qspi_mode => qspi_mode, wait_states => wait_states_slow, flash_channel_enable => flash_channel_enable, @@ -350,7 +364,9 @@ begin oob_avail => oob_avail, oob_free => oob_free, to_host_tx_fifo_usedwds => to_host_tx_fifo_usedwds, - ipcc_to_host_byte_cntr => ipcc_to_host_byte_cntr + ipcc_to_host_byte_cntr => ipcc_to_host_byte_cntr, + host_to_sp_fifo_usedwds => host_to_sp_fifo_usedwds, + oob_free_saw_full => oob_free_saw_full ); -- vwire channel logic diff --git a/hdl/ip/vhd/espi/peripheral_channel/uart_channel_top.vhd b/hdl/ip/vhd/espi/peripheral_channel/uart_channel_top.vhd index 90b534a5..faf43e98 100644 --- a/hdl/ip/vhd/espi/peripheral_channel/uart_channel_top.vhd +++ b/hdl/ip/vhd/espi/peripheral_channel/uart_channel_top.vhd @@ -55,6 +55,9 @@ entity uart_channel_top is np_avail: out std_logic; to_host_tx_fifo_usedwds : out std_logic_vector(log2ceil(fifo_depth) downto 0); ipcc_to_host_byte_cntr : out std_logic_vector(31 downto 0); + host_to_sp_fifo_usedwds : out std_logic_vector(log2ceil(fifo_depth) downto 0); + -- Sticky: set when oob_free goes low, cleared only by espi_reset + oob_free_saw_full : out std_logic ); end entity; @@ -84,6 +87,7 @@ architecture rtl of uart_channel_top is begin to_host_tx_fifo_usedwds <= tx_rusedwds; + host_to_sp_fifo_usedwds <= rx_wusedwds; -- Not going to support any Non-posted transactions -- on this interface @@ -209,6 +213,20 @@ begin end if; end process; + -- Sticky detector: captures if oob_free ever went low since last espi_reset + oob_free_sticky: process(clk, reset) + begin + if reset then + oob_free_saw_full <= '0'; + elsif rising_edge(clk) then + if espi_reset then + oob_free_saw_full <= '0'; + elsif oob_free = '0' and enabled = '1' then + oob_free_saw_full <= '1'; + end if; + end if; + end process; + from_host_rx_fifo: entity work.dcfifo_xpm generic map( fifo_write_depth => fifo_depth, diff --git a/hdl/ip/vhd/espi/sims/espi_tb.vhd b/hdl/ip/vhd/espi/sims/espi_tb.vhd index 487fd93e..b619c967 100644 --- a/hdl/ip/vhd/espi/sims/espi_tb.vhd +++ b/hdl/ip/vhd/espi/sims/espi_tb.vhd @@ -18,10 +18,10 @@ use work.qspi_vc_pkg.all; use work.espi_controller_vc_pkg.all; use work.espi_base_types_pkg.all; use work.espi_spec_regs_pkg.all; +use work.espi_regs_pkg; use work.espi_dbg_vc_pkg.all; use work.espi_tb_pkg.all; -use work.espi_regs_pkg.all; entity espi_tb is generic ( @@ -105,7 +105,7 @@ begin check_equal(response.status, expected_status, "Status did not match reset value"); exp_data_32 := (others => '0'); -- Should have an empty response queue - read_bus(net, bus_handle, To_StdLogicVector(STATUS_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.STATUS_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, exp_data_32, "Response queue not empty before bad crc command"); -- Issue a command with a bad CRC @@ -113,7 +113,7 @@ begin dbg_wait_for_done(net); wait for 1 us; -- Expect no responses - read_bus(net, bus_handle, To_StdLogicVector(FIFO_STATUS_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.FIFO_STATUS_OFFSET, bus_handle.p_address_length), data_32); exp_data_32 := (others => '0'); check_equal(data_32, exp_data_32, "Expected no response to bad CRC command"); @@ -250,19 +250,19 @@ begin -- verify counts are correct. wait for 1 us; -- Check *last* post code register - read_bus(net, bus_handle, To_StdLogicVector(LAST_POST_CODE_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.LAST_POST_CODE_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, exp_data_32, "Single post code register readback failed"); -- Check post code buffer entry 0 - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_BUFFER_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_BUFFER_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, exp_data_32, "Post code buffer readback failed"); -- Check post code count register - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, std_logic_vector'(x"00000001"), "Post code count register readback failed"); -- issue an espi reset and verify post code count resets dbg_espi_reset(net); wait for 1 us; - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, std_logic_vector'(x"00000000"), "Post code count register did not reset after espi reset"); @@ -277,13 +277,13 @@ begin dbg_wait_for_done(net); wait for 1 us; -- Check *last* post code register - read_bus(net, bus_handle, To_StdLogicVector(LAST_POST_CODE_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.LAST_POST_CODE_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, exp_data_32, "Single post code register readback failed"); -- Check post code buffer entry 0 - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_BUFFER_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_BUFFER_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, exp_data_32, "Post code buffer readback failed"); -- Check post code count register - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, std_logic_vector'(x"00000001"), "Post code count register readback failed"); exp_data_32 := x"000101de"; @@ -293,21 +293,21 @@ begin wait for 1 us; -- Check *last* post code register - read_bus(net, bus_handle, To_StdLogicVector(LAST_POST_CODE_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.LAST_POST_CODE_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, exp_data_32, "Single post code register readback failed"); -- Check post code buffer entry 0 - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_BUFFER_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_BUFFER_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, std_logic_vector'(x"000001de"), "Post code buffer 0 readback failed"); - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_BUFFER_OFFSET + 4, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_BUFFER_OFFSET + 4, bus_handle.p_address_length), data_32); check_equal(data_32, exp_data_32, "Post code buffer 1 readback failed"); -- Check post code count register - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, std_logic_vector'(x"00000002"), "Post code count register readback failed"); -- issue an espi reset and verify post code count resets dbg_espi_reset(net); wait for 1 us; - read_bus(net, bus_handle, To_StdLogicVector(POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); + read_bus(net, bus_handle, To_StdLogicVector(espi_regs_pkg.POST_CODE_COUNT_OFFSET, bus_handle.p_address_length), data_32); check_equal(data_32, std_logic_vector'(x"00000000"), "Post code count register did not reset after espi reset"); elsif run("put_iowr_short") then diff --git a/hdl/ip/vhd/espi/sys_regs/espi_regs.rdl b/hdl/ip/vhd/espi/sys_regs/espi_regs.rdl index 6fa9f878..9c992255 100644 --- a/hdl/ip/vhd/espi/sys_regs/espi_regs.rdl +++ b/hdl/ip/vhd/espi/sys_regs/espi_regs.rdl @@ -126,13 +126,22 @@ addrmap espi_regs { } post_code_count; reg { - name = "IPCC_TO_HOST_USEDWDS"; + name = "IPCC_SP_TO_HOST_USEDWDS"; desc = "Count of usedwds in the IPCC to host TX FIFO"; field { desc = ""; } count[31:0] = 0; } ipcc_to_host_usedwds; + reg { + name = "IPCC_HOST_TO_SP_USEDWDS"; + desc = "Count of used words in the host-to-SP IPCC RX FIFO"; + field { + default sw = r; + desc = ""; + } count[31:0] = 0; + } ipcc_host_to_sp_usedwds; + reg { name = "IPCC_TO_HOST_BYTE_CNTR"; desc = "Count of total bytes sent to host via IPCC UART channel since reset"; @@ -157,6 +166,107 @@ addrmap espi_regs { } count[31:0] = 0; } ipcc_dummy_fill_count; + reg espi_status { + field { + desc = "When '1', indicates the target has a channel 3 + Flash Access non-posted header and data up to + maximum payload size available to send. + This bit is only applicable when controller + attached flash sharing is supported and in + operation. Otherwise, the bit is a don't care."; + } FLASH_NP_AVAIL[13:13]; + field { + desc = "When '1', indicates the target has a channel 3 + Flash Access completion header and data up to + maximum payload size available to send. + This bit is only applicable when target attached + flash sharing is supported and in operation. + Otherwise, the bit is a don't care."; + } FLASH_C_AVAIL[12:12]; + field { + desc = "When '1', indicates the target is free to accept + at least one channel 3 Flash Access non-posted + header and data up to maximum payload size. + This bit is only applicable when target attached + flash sharing is supported and in operation. + Otherwise, the bit is a don't care."; + } FLASH_NP_FREE[9:9]; + field { + desc = "When '1', indicates the target is free to accept + at least one channel 3 Flash Access completion + header and data up to maximum payload size. + This bit must be always a '1'. The target must + be able to accept the completion for the non- + posted request it sends. + This bit is only applicable when controller + attached flash sharing is supported and in + operation. Otherwise, the bit is a don't care."; + } FLASH_C_FREE[8:8]; + field { + desc = "When '1', indicates the target has a channel 2 + OOB (tunneled SMBus) message with data up + to maximum payload size available to send."; + } OOB_AVAIL[7:7]; + field { + desc = "When '1', indicates the target has a channel 1 + tunneled virtual wire available to send."; + } VWIRE_AVAIL[6:6]; + field { + desc = "When '1', indicates the target has a channel 0 + peripheral non-posted header available to + send."; + } NP_AVAIL[5:5]; + + field { + desc = "When '1', indicates the target has a channel 0 + peripheral posted or completion header and + optional data up to maximum payload size + available to send."; + } PC_AVAIL[4:4]; + + field { + desc = "When '1', indicates the target is free to accept + at least one channel 2 OOB (tunneled SMBus) + message with data up to maximum payload size."; + } OOB_FREE[3:3]; + field { + desc = "This bit must be always a '1'. Tunneling of + channel 1 virtual wires is not flow controlled."; + } VWIRE_FREE[2:2]; + field { + desc = "When '1', indicates the target is free to accept + at least one channel 0 peripheral non-posted + header and 1 DW of Data (if applicable)."; + } NP_FREE[1:1]; + field { + desc = "When '1', indicates the target is free to accept + at least one channel 0 peripheral posted or + completion header and data up to maximum + payload size."; + } PC_FREE[0:0]; + + }; + + espi_status LIVE_ESPI_STATUS; + LIVE_ESPI_STATUS->name = "LIVE_ESPI_STATUS"; + + espi_status LAST_RESP_STATUS; + LAST_RESP_STATUS->name = "LAST_RESP_STATUS"; + + + reg { + name = "OOB_FREE_SAW_FULL"; + desc = "Sticky bit: set to 1 if oob_free ever went low (RX FIFO nearly full) since last eSPI reset. Cleared only by eSPI reset."; + field { + default sw = r; + desc = ""; + } saw_full[0:0] = 0; + } oob_free_saw_full; + + // Read-only view of the eSPI spec registers, so the SP can + // observe what the eSPI host has configured. + eSPI_Spec spec_regs @ 0x0080; + mem post_code_buffer_mem { mementries = 4096; memwidth = 32; diff --git a/hdl/ip/vhd/espi/sys_regs/espi_regs.vhd b/hdl/ip/vhd/espi/sys_regs/espi_regs.vhd index 5463276f..a96166fe 100644 --- a/hdl/ip/vhd/espi/sys_regs/espi_regs.vhd +++ b/hdl/ip/vhd/espi/sys_regs/espi_regs.vhd @@ -11,6 +11,8 @@ use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.numeric_std_unsigned.all; use work.espi_regs_pkg.all; +use work.espi_spec_regs_view_pkg.all; +use work.espi_spec_regs_pkg; use work.qspi_link_layer_pkg.all; use work.axil15x32_pkg.all; use work.calc_pkg.log2ceil; @@ -26,12 +28,16 @@ entity espi_regs is espi_reset : in std_logic; stuff_fifo : out std_logic; stuff_wds : out std_logic_vector(15 downto 0); + -- read-only view of eSPI spec registers + spec_regs_view : view spec_regs_sink; -- debug interface dbg_chan : view dbg_regs_if; to_host_tx_fifo_usedwds : in std_logic_vector(12 downto 0); ipcc_to_host_byte_cntr : in std_logic_vector(31 downto 0); - - + live_espi_status : in std_logic_vector(15 downto 0); + last_resp_status : in std_logic_vector(15 downto 0); + host_to_sp_fifo_usedwds : in std_logic_vector(12 downto 0); + oob_free_saw_full : in std_logic ); end entity; @@ -49,6 +55,9 @@ architecture rtl of espi_regs is signal post_code_count_reg : post_code_count_type; signal stuff_count : ipcc_dummy_fill_count_type; signal stuff_enable : ipcc_dummy_fill_en_type; + signal oob_free_saw_full_reg : oob_free_saw_full_type; + signal last_resp_status_reg : espi_status_type; + signal live_status_reg : espi_status_type; constant BUFFER_ENTRIES : integer := 4096; constant BUFFER_ADDR_WIDTH : integer := log2ceil(BUFFER_ENTRIES); signal pc_buf_waddr : std_logic_vector(BUFFER_ADDR_WIDTH - 1 downto 0); @@ -60,6 +69,9 @@ begin fifo_status_reg.resp_used_wds <= dbg_chan.rdstatus.usedwds; status_reg.busy <= dbg_chan.busy; flags_reg.alert <= dbg_chan.alert_pending; + oob_free_saw_full_reg.saw_full <= oob_free_saw_full; + last_resp_status_reg <= unpack(X"0000" & last_resp_status); + live_status_reg <= unpack(X"0000" & live_espi_status); axi_if.read_data.data <= rdata; @@ -173,6 +185,29 @@ begin rdata <= pack(stuff_count); when IPCC_DUMMY_FILL_EN_OFFSET => rdata <= pack(stuff_enable); + when LIVE_ESPI_STATUS_OFFSET => + rdata <= pack(live_status_reg); + when LAST_RESP_STATUS_OFFSET => + rdata <= pack(last_resp_status_reg); + when IPCC_HOST_TO_SP_USEDWDS_OFFSET => + rdata <= resize(host_to_sp_fifo_usedwds, rdata'length); + when OOB_FREE_SAW_FULL_OFFSET => + rdata <= pack(oob_free_saw_full_reg); + -- Read-only eSPI spec registers (base 0x0080) + when SPEC_REGS_DEVICE_ID_OFFSET => + rdata <= espi_spec_regs_pkg.pack(spec_regs_view.device_id); + when SPEC_REGS_GENERAL_CAPABILITIES_OFFSET => + rdata <= espi_spec_regs_pkg.pack(spec_regs_view.general_capabilities); + when SPEC_REGS_CH0_CAPABILITIES_OFFSET => + rdata <= espi_spec_regs_pkg.pack(spec_regs_view.ch0_capabilities); + when SPEC_REGS_CH1_CAPABILITIES_OFFSET => + rdata <= espi_spec_regs_pkg.pack(spec_regs_view.ch1_capabilities); + when SPEC_REGS_CH2_CAPABILITIES_OFFSET => + rdata <= espi_spec_regs_pkg.pack(spec_regs_view.ch2_capabilities); + when SPEC_REGS_CH3_CAPABILITIES_OFFSET => + rdata <= espi_spec_regs_pkg.pack(spec_regs_view.ch3_capabilities); + when SPEC_REGS_CH3_CAPABILITIES2_OFFSET => + rdata <= espi_spec_regs_pkg.pack(spec_regs_view.ch3_capabilities2); when POST_CODE_BUFFER_MEM_RANGE => rdata <= post_code_buffer_rdata; when others => diff --git a/hdl/ip/vhd/espi/sys_regs/espi_spec_regs_view_pkg.vhd b/hdl/ip/vhd/espi/sys_regs/espi_spec_regs_view_pkg.vhd new file mode 100644 index 00000000..1eb4ed1a --- /dev/null +++ b/hdl/ip/vhd/espi/sys_regs/espi_spec_regs_view_pkg.vhd @@ -0,0 +1,39 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, You can obtain one at https://mozilla.org/MPL/2.0/. +-- +-- Copyright 2025 Oxide Computer Company + +-- Composite record and views for exposing eSPI spec register +-- values as a read-only interface in the sys_regs address space. + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.espi_spec_regs_pkg.all; + +package espi_spec_regs_view_pkg is + + type spec_regs_t is record + device_id : device_id_type; + general_capabilities : general_capabilities_type; + ch0_capabilities : ch0_capabilities_type; + ch1_capabilities : ch1_capabilities_type; + ch2_capabilities : ch2_capabilities_type; + ch3_capabilities : ch3_capabilities_type; + ch3_capabilities2 : ch3_capabilities2_type; + end record; + + view spec_regs_source of spec_regs_t is + device_id : out; + general_capabilities : out; + ch0_capabilities : out; + ch1_capabilities : out; + ch2_capabilities : out; + ch3_capabilities : out; + ch3_capabilities2 : out; + end view; + + alias spec_regs_sink is spec_regs_source'converse; + +end package; diff --git a/hdl/ip/vhd/espi/txn_layer/response_processor.vhd b/hdl/ip/vhd/espi/txn_layer/response_processor.vhd index a042642d..4771a13e 100644 --- a/hdl/ip/vhd/espi/txn_layer/response_processor.vhd +++ b/hdl/ip/vhd/espi/txn_layer/response_processor.vhd @@ -37,7 +37,9 @@ entity response_processor is -- uart channel responses sp_to_host_espi : view uart_resp_sink; - alert_needed : out boolean + alert_needed : out boolean; + -- Packed status_t that was last sent on the wire + last_resp_status : out std_logic_vector(15 downto 0) ); end entity; @@ -62,6 +64,7 @@ architecture rtl of response_processor is state : response_state_t; status_idx : std_logic; status : status_t; + last_sent_status : status_t; resp_idx : integer range 0 to 255; payload_cnt : std_logic_vector(11 downto 0); temp_length : std_logic_vector(11 downto 0); @@ -79,6 +82,7 @@ architecture rtl of response_processor is IDLE, '0', rec_reset, + rec_reset, 0, (others => '0'), (others => '0'), @@ -131,10 +135,11 @@ begin response_done <= r.response_done; + last_resp_status <= pack(r.last_sent_status); -- We need to issue alerts when the live status does not match the last-sent -- status - alert_needed <= true when r.has_responded and live_status /= r.status else false; + alert_needed <= true when r.has_responded and live_status /= r.last_sent_status else false; -- Response classes: -- Get Stats -> response, status, crc -- Set Config -> response, status, crc @@ -320,6 +325,7 @@ begin -- Status words if r.state = STATUS and r.status_idx = '0' then v.status := live_status; + v.last_sent_status := live_status; v.cur_data := pack(live_status)(7 downto 0); elsif r.state = STATUS then v.cur_data := pack(r.status)(15 downto 8); @@ -329,10 +335,6 @@ begin -- Reset the command processor state machine v := reg_reset; end if; - -- -- abort the transaction if we're not selected - -- if not chip_sel_active then - -- v.state := IDLE; - -- end if; rin <= v; end process; diff --git a/hdl/ip/vhd/espi/txn_layer/txn_layer_top.vhd b/hdl/ip/vhd/espi/txn_layer/txn_layer_top.vhd index 9231bd18..4b3a427a 100644 --- a/hdl/ip/vhd/espi/txn_layer/txn_layer_top.vhd +++ b/hdl/ip/vhd/espi/txn_layer/txn_layer_top.vhd @@ -56,7 +56,10 @@ entity txn_layer_top is response_done : out boolean; aborted_due_to_bad_crc : out boolean; -- "Streaming" data to serialize and transmit - data_from_host : view byte_sink + data_from_host : view byte_sink; + live_espi_status : out std_logic_vector(15 downto 0); + -- Packed status_t that was last sent on the wire + last_resp_status : out std_logic_vector(15 downto 0) ); end entity; @@ -73,6 +76,8 @@ architecture rtl of txn_layer_top is begin + live_espi_status <= pack(live_status); + -- Basic counter that counts bytes from the shifters -- The shifters deal with the QSPI mode so we will -- be able to use this as an index into the current @@ -154,7 +159,8 @@ begin response_crc => tx_running_crc, flash_resp => flash_resp, sp_to_host_espi => sp_to_host_espi, - alert_needed => alert_needed + alert_needed => alert_needed, + last_resp_status => last_resp_status ); resp_regs_if.write <= regs_if.write;