Switch SPI master over to new quad SPI capable core

Use quad SPI I/O for all firmware read cycles.
This significantly improves overall IPL speed.
parent 4ee2b863
......@@ -57,6 +57,7 @@ set_io spi_external_master_mosi E14
set_io spi_external_master_miso D15
set_io spi_external_master_ss_n D14
set_io spi_external_master_hold_n G15
set_io spi_external_master_wp_n F14
set_io spi_external_master_reset_n H14
# LPC debug mirror port
......
This diff is collapsed.
// © 2017 Raptor Engineering, LLC
// © 2017 - 2020 Raptor Engineering, LLC
//
// Released under the terms of the AGPL v3
// See the LICENSE file for full details
//
// SPI mode 3 transfer
// Single data rate, standard unidirectional transfer
module spi_master_interface(
input wire platform_clock,
input wire reset,
......@@ -16,10 +17,12 @@ module spi_master_interface(
output reg spi_clock,
output reg spi_mosi,
input wire spi_miso,
output reg spi_ss_n
output reg spi_ss_n,
output reg spi_hold_n,
output reg spi_wp_n
);
reg [3:0] transfer_state;
reg [3:0] transfer_state = 0;
reg [7:0] data_shift_out = 0;
reg [7:0] state_iteration = 0;
......@@ -37,6 +40,8 @@ module spi_master_interface(
spi_clock <= 1'b1;
spi_mosi <= 1'b0;
spi_ss_n <= 1'b1;
spi_hold_n <= 1'b1;
spi_wp_n <= 1'b1;
ss_state_at_idle <= 1'b1;
end else begin
case (transfer_state)
......@@ -112,4 +117,187 @@ module spi_master_interface(
tx_data_reg <= tx_data;
end
endmodule
\ No newline at end of file
endmodule
// SPI mode 3 transfer
// Single data rate, quad transfer
// This module assumes it is on the same clock domain as the external control logic
module spi_master_interface_quad(
input wire platform_clock,
input wire reset,
input wire [7:0] tx_data,
output reg [7:0] rx_data,
input wire [7:0] dummy_cycle_count,
input wire hold_ss_active,
input wire qspi_mode_active,
input wire qspi_transfer_direction, // 0 == read (input), 1 == write (output)
input wire cycle_start,
output reg transaction_complete,
output reg spi_clock,
output reg spi_d0_out,
input wire spi_d0_in,
output reg spi_d1_out,
input wire spi_d1_in,
output reg spi_d2_out,
input wire spi_d2_in,
output reg spi_d3_out,
input wire spi_d3_in,
output reg spi_ss_n,
output reg spi_data_direction, // 0 == tristate (input), 1 == driven (output)
output reg spi_quad_mode_pin_enable
);
reg [3:0] transfer_state = 0;
reg [7:0] data_shift_out = 0;
reg [7:0] state_iteration = 0;
reg ss_state_at_idle = 1'b1;
reg [7:0] dummy_cycle_count_reg = 0;
reg [7:0] dummy_cycle_ctr = 0;
always @(posedge platform_clock) begin
if (reset) begin
transfer_state <= 0;
state_iteration <= 0;
transaction_complete <= 1;
dummy_cycle_count_reg <= 0;
spi_clock <= 1'b1;
spi_d0_out <= 1'b0;
spi_d1_out <= 1'b1;
spi_d2_out <= 1'b1;
spi_d3_out <= 1'b1;
spi_ss_n <= 1'b1;
ss_state_at_idle <= 1'b1;
spi_data_direction <= 1'b0;
spi_quad_mode_pin_enable <= 1'b0;
end else begin
case (transfer_state)
0: begin
// Idle state
spi_clock <= 1'b1;
spi_d0_out <= 1'b0;
spi_ss_n <= ss_state_at_idle;
transaction_complete <= 0;
state_iteration <= 0;
if (cycle_start) begin
// Set up transfer
rx_data <= 0;
dummy_cycle_count_reg <= dummy_cycle_count;
data_shift_out <= tx_data;
spi_quad_mode_pin_enable <= qspi_mode_active;
spi_data_direction <= qspi_transfer_direction;
// Drive frame start
spi_clock <= 1'b1;
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
end
1: begin
// Shift out TX byte / toggle clock
spi_clock <= 1'b0;
spi_ss_n <= 1'b0;
if (spi_quad_mode_pin_enable) begin
spi_d3_out <= data_shift_out[7];
spi_d2_out <= data_shift_out[6];
spi_d1_out <= data_shift_out[5];
spi_d0_out <= data_shift_out[4];
data_shift_out <= data_shift_out << 4;
end else begin
spi_d0_out <= data_shift_out[7];
data_shift_out <= data_shift_out << 1;
end
transfer_state <= 2;
end
2: begin
// Shift in RX byte / toggle clock
spi_clock <= 1'b1;
spi_ss_n <= 1'b0;
state_iteration <= state_iteration + 1;
if (spi_quad_mode_pin_enable) begin
rx_data <= {rx_data[3:0], spi_d3_in, spi_d2_in, spi_d1_in, spi_d0_in};
if (state_iteration >= 1) begin
if (hold_ss_active) begin
ss_state_at_idle <= 1'b0;
end else begin
ss_state_at_idle <= 1'b1;
end
transaction_complete <= 1;
if (dummy_cycle_count_reg == 0) begin
transfer_state <= 3;
end else begin
dummy_cycle_ctr <= 0;
transfer_state <= 4;
end
end else begin
transfer_state <= 1;
end
end else begin
rx_data <= {rx_data[6:0], spi_d1_in};
if (state_iteration >= 7) begin
if (hold_ss_active) begin
ss_state_at_idle <= 1'b0;
end else begin
ss_state_at_idle <= 1'b1;
end
transaction_complete <= 1;
if (dummy_cycle_count_reg == 0) begin
transfer_state <= 3;
end else begin
dummy_cycle_ctr <= 0;
transfer_state <= 4;
end
end else begin
transfer_state <= 1;
end
end
end
3: begin
// Wait for host to deassert transaction request
if (!cycle_start) begin
transaction_complete <= 0;
transfer_state <= 0;
end
spi_clock <= 1'b1;
spi_d0_out <= 1'b0;
spi_d1_out <= 1'b1;
spi_d2_out <= 1'b1;
spi_d3_out <= 1'b1;
spi_ss_n <= ss_state_at_idle;
spi_data_direction <= 0;
spi_quad_mode_pin_enable <= 0;
end
4: begin
// Increment counter / toggle clock
spi_clock <= 1'b0;
dummy_cycle_ctr <= dummy_cycle_ctr + 1;
transfer_state <= 5;
end
5: begin
if (dummy_cycle_ctr < dummy_cycle_count_reg) begin
transfer_state <= 4;
end else begin
transfer_state <= 3;
end
// Toggle clock
spi_clock <= 1'b1;
end
default: begin
transfer_state <= 0;
end
endcase
end
end
endmodule
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment