[ spi_host, rtl/dv/doc ] New "OUTPUT_EN" register

- All SPI_HOST outputs are now disabled by default until the OUTPUT_EN register is set
- Includes a one line change to the SPI_HOST DV environment to activate this
- A description of the new register field has been added to the documentation

Fixes 8920

Signed-off-by: Martin Lueker-Boden <martin.lueker-boden@wdc.com>
diff --git a/hw/ip/spi_host/data/spi_host.hjson b/hw/ip/spi_host/data/spi_host.hjson
index dfb2fa8..5bb9332 100644
--- a/hw/ip/spi_host/data/spi_host.hjson
+++ b/hw/ip/spi_host/data/spi_host.hjson
@@ -108,6 +108,13 @@
                    the IP from reset.''',
           resval: "0x0"
         },
+        { bits: "29",
+          name: "OUTPUT_EN",
+          desc: '''Enable the SPI host output buffers for the sck, csb, and sd lines.  This allows
+                   the SPI_HOST IP to connect to the same bus as other SPI controllers without
+                   interference.''',
+          resval: "0x0"
+        },
         { bits: "15:8",
           name: "TX_WATERMARK"
           desc: '''If !!EVENT_ENABLE.TXWM is set, the IP will send
diff --git a/hw/ip/spi_host/doc/_index.md b/hw/ip/spi_host/doc/_index.md
index b74f81f..f25d983 100644
--- a/hw/ip/spi_host/doc/_index.md
+++ b/hw/ip/spi_host/doc/_index.md
@@ -657,6 +657,11 @@
 
 An unacknowledged error event suspends the core state machine.
 
+### SPI_HOST Output Enable
+
+In addition to enabling the SPI_HOST FSM, the SPI_HOST outputs must also be enabled for successful operation.
+This can be achieved by also setting the {{< regref "CONTROL.OUTPUT_EN" >}} field when enabling the SPI_HOST FSM.
+
 ### Component reset
 
 In addition to the global hardware reset, there is a software reset option which completely resets the SPI host.
diff --git a/hw/ip/spi_host/dv/env/seq_lib/spi_host_base_vseq.sv b/hw/ip/spi_host/dv/env/seq_lib/spi_host_base_vseq.sv
index 629379b..ef27f01 100644
--- a/hw/ip/spi_host/dv/env/seq_lib/spi_host_base_vseq.sv
+++ b/hw/ip/spi_host/dv/env/seq_lib/spi_host_base_vseq.sv
@@ -174,6 +174,7 @@
     ral.control.rx_watermark.set(spi_host_ctrl_reg.rx_watermark);
     // activate spi_host dut
     ral.control.spien.set(1'b1);
+    ral.control.output_en.set(1'b1);
     csr_update(ral.control);
   endtask : program_control_reg
 
diff --git a/hw/ip/spi_host/dv/env/seq_lib/spi_host_tx_rx_vseq.sv b/hw/ip/spi_host/dv/env/seq_lib/spi_host_tx_rx_vseq.sv
index e006bd0..f969594 100644
--- a/hw/ip/spi_host/dv/env/seq_lib/spi_host_tx_rx_vseq.sv
+++ b/hw/ip/spi_host/dv/env/seq_lib/spi_host_tx_rx_vseq.sv
@@ -55,7 +55,6 @@
 
   endtask
 
-
   // sending tx requests to the agent
   virtual task send_trans(spi_transaction_item trans);
     spi_segment_item segment = new();
diff --git a/hw/ip/spi_host/dv/env/spi_host_scoreboard.sv b/hw/ip/spi_host/dv/env/spi_host_scoreboard.sv
index f0dcc1d..f08fa56 100644
--- a/hw/ip/spi_host/dv/env/spi_host_scoreboard.sv
+++ b/hw/ip/spi_host/dv/env/spi_host_scoreboard.sv
@@ -35,6 +35,7 @@
   spi_host_configopts_t             spi_configopts;
   // control bits
   local bit                         spien              = 1'b0;
+  local bit                         output_en          = 1'b0;
   local bit                         sw_rst             = 1'b0;
 
   int                               in_tx_seg_cnt      = 0;
@@ -228,8 +229,9 @@
       case (csr_name)
         // add individual case item for each csr
         "control": begin
-          spien  = bit'(get_field_val(ral.control.spien,  item.a_data));
-          sw_rst = bit'(get_field_val(ral.control.sw_rst, item.a_data));
+          spien      = bit'(get_field_val(ral.control.spien,      item.a_data));
+          output_en  = bit'(get_field_val(ral.control.output_en,  item.a_data));
+          sw_rst     = bit'(get_field_val(ral.control.sw_rst,     item.a_data));
           if (sw_rst || spien) begin
             write_segment_q.delete();
             rx_data_q.delete();
diff --git a/hw/ip/spi_host/rtl/spi_host.sv b/hw/ip/spi_host/rtl/spi_host.sv
index 1c41165..0ebf476 100644
--- a/hw/ip/spi_host/rtl/spi_host.sv
+++ b/hw/ip/spi_host/rtl/spi_host.sv
@@ -89,8 +89,13 @@
   logic             sck;
   logic [NumCS-1:0] csb;
   logic [3:0]       sd_out;
-  logic [3:0]       sd_en;
+  logic [3:0]       sd_en, sd_en_core;
   logic [3:0]       sd_i;
+  logic             output_en;
+
+  assign output_en = reg2hw.control.output_en;
+
+  assign sd_en     = output_en ? sd_en_core : 4'h0;
 
   if (NumCS == 1) begin : gen_passthrough_implementation
     logic passthrough_en;
@@ -111,9 +116,9 @@
     assign pt_sd_en     = passthrough_i.s_en;
 
     assign cio_sck_o    = passthrough_en ? pt_sck    : sck;
-    assign cio_sck_en_o = passthrough_en ? pt_sck_en : 1'b1;
+    assign cio_sck_en_o = passthrough_en ? pt_sck_en : output_en;
     assign cio_csb_o    = passthrough_en ? pt_csb    : csb;
-    assign cio_csb_en_o = passthrough_en ? pt_csb_en : 1'b1;
+    assign cio_csb_en_o = passthrough_en ? pt_csb_en : output_en;
     assign cio_sd_o     = passthrough_en ? pt_sd_out : sd_out;
     assign cio_sd_en_o  = passthrough_en ? pt_sd_en  : sd_en;
 
@@ -123,9 +128,9 @@
     `ASSERT(PassthroughNumCSCompat_A, !passthrough_i.passthrough_en, clk_i, rst_ni)
 
     assign cio_sck_o    = sck;
-    assign cio_sck_en_o = 1'b1;
+    assign cio_sck_en_o = output_en;
     assign cio_csb_o    = csb;
-    assign cio_csb_en_o = {NumCS{1'b1}};
+    assign cio_csb_en_o = {NumCS{output_en}};
     assign cio_sd_o     = sd_out;
     assign cio_sd_en_o  = sd_en;
 
@@ -449,7 +454,7 @@
     .sck_o           (sck),
     .csb_o           (csb),
     .sd_o            (sd_out),
-    .sd_en_o         (sd_en),
+    .sd_en_o         (sd_en_core),
     .sd_i,
     .rx_stall_o      (rx_stall),
     .tx_stall_o      (tx_stall),
diff --git a/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv b/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv
index 2feb78f..18fd080 100644
--- a/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv
+++ b/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv
@@ -64,6 +64,9 @@
     } tx_watermark;
     struct packed {
       logic        q;
+    } output_en;
+    struct packed {
+      logic        q;
     } sw_rst;
     struct packed {
       logic        q;
@@ -276,11 +279,11 @@
 
   // Register -> HW type
   typedef struct packed {
-    spi_host_reg2hw_intr_state_reg_t intr_state; // [125:124]
-    spi_host_reg2hw_intr_enable_reg_t intr_enable; // [123:122]
-    spi_host_reg2hw_intr_test_reg_t intr_test; // [121:118]
-    spi_host_reg2hw_alert_test_reg_t alert_test; // [117:116]
-    spi_host_reg2hw_control_reg_t control; // [115:98]
+    spi_host_reg2hw_intr_state_reg_t intr_state; // [126:125]
+    spi_host_reg2hw_intr_enable_reg_t intr_enable; // [124:123]
+    spi_host_reg2hw_intr_test_reg_t intr_test; // [122:119]
+    spi_host_reg2hw_alert_test_reg_t alert_test; // [118:117]
+    spi_host_reg2hw_control_reg_t control; // [116:98]
     spi_host_reg2hw_configopts_mreg_t [0:0] configopts; // [97:67]
     spi_host_reg2hw_csid_reg_t csid; // [66:35]
     spi_host_reg2hw_command_reg_t command; // [34:17]
diff --git a/hw/ip/spi_host/rtl/spi_host_reg_top.sv b/hw/ip/spi_host/rtl/spi_host_reg_top.sv
index 36274b0..f577621 100644
--- a/hw/ip/spi_host/rtl/spi_host_reg_top.sv
+++ b/hw/ip/spi_host/rtl/spi_host_reg_top.sv
@@ -187,6 +187,8 @@
   logic [7:0] control_rx_watermark_wd;
   logic [7:0] control_tx_watermark_qs;
   logic [7:0] control_tx_watermark_wd;
+  logic control_output_en_qs;
+  logic control_output_en_wd;
   logic control_sw_rst_qs;
   logic control_sw_rst_wd;
   logic control_spien_qs;
@@ -467,6 +469,31 @@
     .qs     (control_tx_watermark_qs)
   );
 
+  //   F[output_en]: 29:29
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRW),
+    .RESVAL  (1'h0)
+  ) u_control_output_en (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (control_we),
+    .wd     (control_output_en_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.control.output_en.q),
+
+    // to register interface (read)
+    .qs     (control_output_en_qs)
+  );
+
   //   F[sw_rst]: 30:30
   prim_subreg #(
     .DW      (1),
@@ -1623,6 +1650,8 @@
 
   assign control_tx_watermark_wd = reg_wdata[15:8];
 
+  assign control_output_en_wd = reg_wdata[29];
+
   assign control_sw_rst_wd = reg_wdata[30];
 
   assign control_spien_wd = reg_wdata[31];
@@ -1717,6 +1746,7 @@
       addr_hit[4]: begin
         reg_rdata_next[7:0] = control_rx_watermark_qs;
         reg_rdata_next[15:8] = control_tx_watermark_qs;
+        reg_rdata_next[29] = control_output_en_qs;
         reg_rdata_next[30] = control_sw_rst_qs;
         reg_rdata_next[31] = control_spien_qs;
       end