From: Raptor Engineering Development Team Date: Sat, 2 Apr 2022 19:11:08 +0000 (-0500) Subject: Add Tercel PHY reset synchronization X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;p=microwatt.git Add Tercel PHY reset synchronization 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. --- diff --git a/tercel/phy.v b/tercel/phy.v index 57cbe2c..b3600a2 100644 --- a/tercel/phy.v +++ b/tercel/phy.v @@ -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 diff --git a/tercel/wishbone_spi_master.v b/tercel/wishbone_spi_master.v index 4cf64fa..018f2a5 100644 --- a/tercel/wishbone_spi_master.v +++ b/tercel/wishbone_spi_master.v @@ -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;