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.
-// © 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
//
// Released under the terms of the GPL v3
// See the LICENSE file for full details
module spi_master_phy_quad(
input wire platform_clock,
input wire reset,
module spi_master_phy_quad(
input wire platform_clock,
input wire reset,
input wire [31:0] tx_data,
output reg [31:0] rx_data,
input wire [7:0] dummy_cycle_count,
input wire [31:0] tx_data,
output reg [31:0] rx_data,
input wire [7:0] dummy_cycle_count,
output reg spi_quad_mode_pin_enable
);
output reg spi_quad_mode_pin_enable
);
reg [3:0] transfer_state = 0;
reg [31:0] data_shift_out = 0;
reg [3:0] transfer_state = 0;
reg [31:0] data_shift_out = 0;
reg [7:0] sspi_transfer_cycle_stop_value = 0;
reg [3:0] qspi_transfer_cycle_stop_value = 0;
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
always @(posedge platform_clock) begin
if (reset) begin
transfer_state <= 0;
state_iteration <= 0;
transaction_complete <= 1;
transfer_state <= 0;
state_iteration <= 0;
transaction_complete <= 1;
spi_ss_n <= 1'b0;
transfer_state <= 1;
spi_ss_n <= 1'b0;
transfer_state <= 1;
end else begin
if (!hold_ss_active) begin
ss_state_at_idle <= 1'b1;
end
spi_quad_mode_pin_enable <= 0;
transfer_state <= 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;
parameter PHY_IO_TYPE_SINGLE = 0;
parameter PHY_IO_TYPE_QUAD = 2;
parameter PHY_IO_TYPE_SINGLE = 0;
parameter PHY_IO_TYPE_QUAD = 2;
+ // PHY clock generator and reset synchronizer
// Divisor:
// (spi_clock_divisor - 1) * 2
// 0 == undefined (actually divide by two)
// Divisor:
// (spi_clock_divisor - 1) * 2
// 0 == undefined (actually divide by two)
// 6 == divide by 10
// 7 == divide by 12
// etc.
// 6 == divide by 10
// 7 == divide by 12
// etc.
wire spi_phy_clock;
reg spi_phy_clock_gen_reg = 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
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
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
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;
reg [31:0] phy_tx_data = 0;
wire [31:0] phy_rx_data;
reg phy_hold_ss_active = 0;
reg [31:0] phy_tx_data = 0;
wire [31:0] phy_rx_data;
reg phy_hold_ss_active = 0;
spi_master_phy_quad spi_master_phy_quad(
.platform_clock(spi_phy_clock),
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),
.tx_data(phy_tx_data),
.rx_data(phy_rx_data),
.dummy_cycle_count(phy_dummy_cycle_count),
reg [31:0] wishbone_dat_r_reg = 0;
assign wishbone_dat_r = wishbone_dat_r_reg;
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;
parameter SPI_MASTER_TRANSFER_STATE_TR03 = 16;
parameter SPI_MASTER_TRANSFER_STATE_TR04 = 17;
parameter SPI_MASTER_TRANSFER_STATE_TR05 = 18;
multicycle_write_in_progress <= 0;
multicycle_transaction_address <= 0;
spi_cs_active_counter <= 0;
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)
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;
SPI_MASTER_TRANSFER_STATE_IDLE: begin
// Compute effective address
spi_address_reg[31:2] = wishbone_adr;