blob: c13585d6ca89fe5770b0cc096471e8f95cde1b3b [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// SPI Flash Read JEDEC ID handler
`include "prim_assert.sv"
module spid_jedec
import spi_device_pkg::*;
(
input clk_i,
input rst_ni,
input clk_out_i, // Output clock (inverted SCK)
input inclk_csb_asserted_pulse_i,
input logic [23:0] sys_jedec_i, // from CSR
output io_mode_e io_mode_o,
input sel_datapath_e sel_dp_i,
input cmd_info_t cmd_info_i,
input logic [CmdInfoIdxW-1:0] cmd_info_idx_i,
output logic outclk_p2s_valid_o,
output spi_byte_t outclk_p2s_byte_o,
input logic outclk_p2s_sent_i
);
typedef enum logic {
StIdle,
StActive
} st_e;
st_e st_q, st_d;
////////////
// Signal //
////////////
assign io_mode_o = SingleIO;
logic [23:0] jedec;
logic p2s_valid;
spi_byte_t p2s_byte;
logic next_byte;
logic [1:0] byte_sel_q, byte_sel_d;
// Unused
logic unused_cmd_info;
assign unused_cmd_info = ^{cmd_info_i , cmd_info_idx_i};
//////////////
// Datapath //
//////////////
// Jedec latch
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) jedec <= 24'h 0;
else if (inclk_csb_asserted_pulse_i) jedec <= sys_jedec_i;
end
// Output to Parallel-to-Serial
always_ff @(posedge clk_out_i or negedge rst_ni) begin
if (!rst_ni) begin
outclk_p2s_valid_o <= 1'b 0;
outclk_p2s_byte_o <= 8'h 0;
end else begin
outclk_p2s_valid_o <= p2s_valid;
outclk_p2s_byte_o <= p2s_byte;
end
end
always_comb begin : p2s_byte_logic
p2s_byte = 8'h 0;
if (st_q == StIdle) begin
// Manufacturer ID always
p2s_byte = jedec[23:16];
end else if (byte_sel_q == 2'h 3) begin
// End of the transfer but host keep toggles SCK. Sending out 0 always
p2s_byte = 8'h 0;
end else begin
// based on byte_sel_q
p2s_byte = jedec[8*byte_sel_q+:8];
end
end : p2s_byte_logic
// Byte selection
always_ff @(posedge clk_i or negedge rst_ni) begin : byte_sel_latch
if (!rst_ni) byte_sel_q <= 8'h 2; // select manufacturer id
else if (next_byte) byte_sel_q <= byte_sel_d;
end : byte_sel_latch
assign byte_sel_d = (byte_sel_q == 2'b 11) ? 2'b 11 : byte_sel_q - 1'b 1;
///////////
// State //
///////////
always_ff @(posedge clk_i or negedge rst_ni) begin : state_latch
if (!rst_ni) st_q <= StIdle;
else st_q <= st_d;
end : state_latch
always_comb begin : next_state_logic
st_d = st_q;
p2s_valid = 1'b 0;
next_byte = 1'b 0;
unique case (st_q)
StIdle: begin
if (sel_dp_i == DpReadJEDEC) begin
st_d = StActive;
// Send out the dat
p2s_valid = 1'b 1;
end
end
StActive: begin
// TERMINAL_STATE
// Sends data
p2s_valid = 1'b 1;
if (outclk_p2s_sent_i) begin
next_byte = 1'b 1;
end
end
default: begin
st_d = StIdle;
end
endcase
end : next_state_logic
endmodule : spid_jedec