Add Tercel PHY reset synchronization master
authorRaptor Engineering Development Team <support@raptorengineering.com>
Sat, 2 Apr 2022 19:11:08 +0000 (14:11 -0500)
committerRaptor Engineering Development Team <support@raptorengineering.com>
Sat, 2 Apr 2022 19:26:09 +0000 (14:26 -0500)
When the external peripheral reset pulse length is short
compared to the PHY clock period, the power on reset
may be missed leaving the PHY in an undefined state.

Synchronize the external peripheral reset signal into
the PHY clock domain to avoid this potential issue.

tercel/phy.v
tercel/wishbone_spi_master.v

index 57cbe2c07c4122d19872bba60dddc4a2f4d12a7d..b3600a279a58dbc75102ed14c384aa90d090f6e2 100644 (file)
@@ -1,4 +1,4 @@
-// © 2017 - 2021 Raptor Engineering, LLC
+// © 2017 - 2022 Raptor Engineering, LLC
 //
 // Released under the terms of the GPL v3
 // See the LICENSE file for full details
@@ -9,6 +9,7 @@
 module spi_master_phy_quad(
                input wire platform_clock,
                input wire reset,
+               output wire ready,
                input wire [31:0] tx_data,
                output reg [31:0] rx_data,
                input wire [7:0] dummy_cycle_count,
@@ -33,6 +34,8 @@ module spi_master_phy_quad(
                output reg spi_quad_mode_pin_enable
        );
 
+       reg phy_ready = 0;
+
        reg [3:0] transfer_state = 0;
        reg [31:0] data_shift_out = 0;
 
@@ -46,8 +49,11 @@ module spi_master_phy_quad(
        reg [7:0] sspi_transfer_cycle_stop_value = 0;
        reg [3:0] qspi_transfer_cycle_stop_value = 0;
 
+       assign ready = phy_ready;
+
        always @(posedge platform_clock) begin
                if (reset) begin
+                       phy_ready <= 0;
                        transfer_state <= 0;
                        state_iteration <= 0;
                        transaction_complete <= 1;
@@ -93,12 +99,14 @@ module spi_master_phy_quad(
                                                spi_ss_n <= 1'b0;
 
                                                transfer_state <= 1;
+                                               phy_ready <= 0;
                                        end else begin
                                                if (!hold_ss_active) begin
                                                        ss_state_at_idle <= 1'b1;
                                                end
                                                spi_quad_mode_pin_enable <= 0;
                                                transfer_state <= 0;
+                                               phy_ready <= 1;
                                        end
                                end
                                1: begin
index 4cf64fa93de9ced02c2ca4a755fb63eee4358da2..018f2a576a1dc04405dfaf76b86221e6a7697ebe 100644 (file)
@@ -274,7 +274,7 @@ module tercel_core(
        parameter PHY_IO_TYPE_SINGLE = 0;
        parameter PHY_IO_TYPE_QUAD = 2;
 
-       // PHY clock generator
+       // PHY clock generator and reset synchronizer
        // Divisor:
        // (spi_clock_divisor - 1) * 2
        // 0 == undefined (actually divide by two)
@@ -286,19 +286,34 @@ module tercel_core(
        // 6 == divide by 10
        // 7 == divide by 12
        // etc.
+       reg phy_reset = 0;
        wire spi_phy_clock;
        reg spi_phy_clock_gen_reg = 0;
+       reg spi_phy_clock_gen_reg_prev = 0;
        reg [7:0] spi_phy_clock_counter = 0;
        assign spi_phy_clock = (spi_clock_divisor == 1)?peripheral_clock:spi_phy_clock_gen_reg;
        always @(posedge peripheral_clock) begin
+               // Clock generator
                if (spi_phy_clock_counter >= (spi_clock_divisor - 2)) begin
                        spi_phy_clock_gen_reg <= ~spi_phy_clock_gen_reg;
                        spi_phy_clock_counter <= 0;
                end else begin
                        spi_phy_clock_counter <= spi_phy_clock_counter + 1;
                end
+
+               // Reset synchronizer
+               if ((spi_phy_clock_gen_reg_prev == 0) && (spi_phy_clock_gen_reg == 1)) begin
+                       phy_reset <= 0;
+               end else begin
+                       if (peripheral_reset) begin
+                               phy_reset <= 1;
+                       end
+               end
+
+               spi_phy_clock_gen_reg_prev <= spi_phy_clock_gen_reg;
        end
 
+       wire phy_ready;
        reg [31:0] phy_tx_data = 0;
        wire [31:0] phy_rx_data;
        reg phy_hold_ss_active = 0;
@@ -313,7 +328,8 @@ module tercel_core(
 
        spi_master_phy_quad spi_master_phy_quad(
                .platform_clock(spi_phy_clock),
-               .reset(peripheral_reset),
+               .reset(phy_reset),
+               .ready(phy_ready),
                .tx_data(phy_tx_data),
                .rx_data(phy_rx_data),
                .dummy_cycle_count(phy_dummy_cycle_count),
@@ -344,9 +360,10 @@ module tercel_core(
        reg [31:0] wishbone_dat_r_reg = 0;
        assign wishbone_dat_r = wishbone_dat_r_reg;
 
-       parameter SPI_MASTER_TRANSFER_STATE_IDLE = 0;
-       parameter SPI_MASTER_TRANSFER_STATE_TR01 = 1;
-       parameter SPI_MASTER_TRANSFER_STATE_TR02 = 2;
+       parameter SPI_MASTER_TRANSFER_STATE_PHYI = 0;
+       parameter SPI_MASTER_TRANSFER_STATE_IDLE = 1;
+       parameter SPI_MASTER_TRANSFER_STATE_TR01 = 2;
+       parameter SPI_MASTER_TRANSFER_STATE_TR02 = 3;
        parameter SPI_MASTER_TRANSFER_STATE_TR03 = 16;
        parameter SPI_MASTER_TRANSFER_STATE_TR04 = 17;
        parameter SPI_MASTER_TRANSFER_STATE_TR05 = 18;
@@ -405,9 +422,14 @@ module tercel_core(
                        multicycle_write_in_progress <= 0;
                        multicycle_transaction_address <= 0;
                        spi_cs_active_counter <= 0;
-                       spi_transfer_state <= SPI_MASTER_TRANSFER_STATE_IDLE;
+                       spi_transfer_state <= SPI_MASTER_TRANSFER_STATE_PHYI;
                end else begin
                        case (spi_transfer_state)
+                               SPI_MASTER_TRANSFER_STATE_PHYI: begin
+                                       if (phy_ready && (!phy_reset)) begin
+                                               spi_transfer_state <= SPI_MASTER_TRANSFER_STATE_IDLE;
+                                       end
+                               end
                                SPI_MASTER_TRANSFER_STATE_IDLE: begin
                                        // Compute effective address
                                        spi_address_reg[31:2] = wishbone_adr;