[flash_ctrl] Support the notion of a 'program-repair'.
This function is specific to the underlying flash, and not all will support it.
As a result, expose a "functional available" output from the flash wrapper and allow the controller to properly control whether a transaction should be allowed.
Note, need to add software read back to that status.
Signed-off-by: Timothy Chen <timothytim@google.com>
[flash_ctrl] minor updates
- Add software read back to check what program types are supported
Signed-off-by: Timothy Chen <timothytim@google.com>
[flash_ctrl] Add otp disable to program repair
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.hjson b/hw/ip/flash_ctrl/data/flash_ctrl.hjson
index b42db7a..f420430 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.hjson
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.hjson
@@ -149,9 +149,31 @@
},
]
},
+
{ bits: "6",
+ name: "PROG_SEL",
+ desc: "Flash program operation type selection",
+ resval: "0"
+ enum: [
+ { value: "0",
+ name: "Normal program",
+ desc: '''
+ Normal program operation to the flash
+ '''
+ },
+ { value: "1",
+ name: "Program repair",
+ desc: '''
+ Repair program operation to the flash. Whether this is actually
+ supported depends on the underlying flash memory.
+ '''
+ },
+ ]
+ },
+
+ { bits: "7",
name: "ERASE_SEL",
- desc: "Flash operation selection",
+ desc: "Flash erase operation type selection",
resval: "0"
enum: [
{ value: "0",
@@ -168,7 +190,7 @@
},
]
},
- { bits: "7",
+ { bits: "8",
name: "PARTITION_SEL",
desc: '''
Selects either info or data partition for operation.
@@ -537,10 +559,33 @@
{ bits: "1", name: "rd_empty", desc: "Flash read FIFO empty", resval: "1"},
{ bits: "2", name: "prog_full", desc: "Flash program FIFO full"},
{ bits: "3", name: "prog_empty", desc: "Flash program FIFO empty, software must provide data", resval: "1"},
- { bits: "4", name: "init_wip", desc: "Flash controller undergoing init"},
+ { bits: "4", name: "init_wip", desc: "Flash controller undergoing init, inclusive of phy init"},
{ bits: "16:8", name: "error_addr", desc: "Flash controller error address."},
]
},
+
+ { name: "PHY_STATUS",
+ desc: "Flash Phy Status",
+ swaccess: "ro",
+ hwaccess: "hwo",
+ fields: [
+ { bits: "0",
+ name: "init_wip",
+ desc: "Flash phy controller initializing"
+ },
+ { bits: "1",
+ name: "prog_normal_avail",
+ resval: "0x1",
+ desc: "Normal program supported"
+ },
+ { bits: "2",
+ name: "prog_repair_avail",
+ resval: "0x1",
+ desc: "Program repair supported"
+ },
+ ]
+ },
+
{ name: "Scratch",
desc: "Flash Controller Scratch",
swaccess: "rw",
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
index 5866710..d5bbda4 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
@@ -91,7 +91,7 @@
// Erase Control Connections
logic erase_flash_req;
logic [BusAddrW-1:0] erase_flash_addr;
- logic [EraseBitWidth-1:0] erase_flash_type;
+ flash_erase_e erase_flash_type;
// Done / Error signaling from ctrl modules
logic prog_done, rd_done, erase_done;
@@ -104,6 +104,7 @@
logic flash_error;
logic [BusWidth-1:0] flash_prog_data;
logic flash_prog_last;
+ flash_prog_e flash_prog_type;
logic [BusWidth-1:0] flash_rd_data;
logic flash_phy_busy;
logic rd_op;
@@ -138,7 +139,8 @@
logic [BusAddrW-1:0] op_addr;
flash_op_e op_type;
flash_part_e op_part;
- logic [EraseBitWidth-1:0] op_erase_type;
+ flash_erase_e op_erase_type;
+ flash_prog_e op_prog_type;
logic ctrl_init_busy;
logic fifo_clr;
@@ -220,7 +222,8 @@
assign op_start = muxed_ctrl.start.q;
assign op_num_words = muxed_ctrl.num.q;
- assign op_erase_type = muxed_ctrl.erase_sel.q;
+ assign op_erase_type = flash_erase_e'(muxed_ctrl.erase_sel.q);
+ assign op_prog_type = flash_prog_e'(muxed_ctrl.prog_sel.q);
assign op_addr = muxed_addr[BusByteWidth +: BusAddrW];
assign op_type = flash_op_e'(muxed_ctrl.op.q);
assign op_part = flash_part_e'(muxed_ctrl.partition_sel.q);
@@ -323,16 +326,24 @@
);
// Program handler is consumer of prog_fifo
+
+ // OTP control bits can be used to explicitly disable repair
+ logic [ProgTypes-1:0] otp_en;
+ assign otp_en[FlashProgNormal] = 1'b1;
+ assign otp_en[FlashProgRepair] = otp_i.prog_repair_en;
+
flash_ctrl_prog u_flash_ctrl_prog (
.clk_i,
.rst_ni,
- // Software Interface
+ // Control interface
.op_start_i (prog_op_valid),
.op_num_words_i (op_num_words),
.op_done_o (prog_done),
.op_err_o (prog_err),
.op_addr_i (op_addr),
+ .op_type_i (op_prog_type),
+ .type_avail_i (flash_i.prog_type_avail & otp_en),
// FIFO Interface
.data_i (prog_fifo_rdata),
@@ -345,6 +356,7 @@
.flash_ovfl_o (prog_flash_ovfl),
.flash_data_o (flash_prog_data),
.flash_last_o (flash_prog_last),
+ .flash_type_o (flash_prog_type),
.flash_done_i (flash_prog_done),
.flash_error_i (flash_error)
);
@@ -579,9 +591,18 @@
// if software operation not selected, software is free to change contents
assign hw2reg.ctrl_regwen.d = sw_sel ? !op_start : 1'b1;
+ // phy status
+ assign hw2reg.phy_status.init_wip.d = flash_phy_busy;
+ assign hw2reg.phy_status.init_wip.de = 1'b1;
+ assign hw2reg.phy_status.prog_normal_avail.d = flash_i.prog_type_avail[FlashProgNormal];
+ assign hw2reg.phy_status.prog_normal_avail.de = 1'b1;
+ assign hw2reg.phy_status.prog_repair_avail.d = flash_i.prog_type_avail[FlashProgRepair];
+ assign hw2reg.phy_status.prog_repair_avail.de = 1'b1;
+
// Flash Interface
assign flash_o.addr = flash_addr;
assign flash_o.part = flash_part_sel;
+ assign flash_o.prog_type = flash_prog_type;
assign flash_o.prog_data = flash_prog_data;
assign flash_o.prog_last = flash_prog_last;
assign flash_o.scramble_en = reg2hw.scramble_en.q;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
index f55f1ca..2c93a70 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_erase.sv
@@ -7,18 +7,18 @@
module flash_ctrl_erase import flash_ctrl_pkg::*; (
// Software Interface
- input op_start_i,
- input [EraseBitWidth-1:0] op_type_i,
- input [BusAddrW-1:0] op_addr_i,
- output logic op_done_o,
- output logic op_err_o,
+ input op_start_i,
+ input flash_erase_e op_type_i,
+ input [BusAddrW-1:0] op_addr_i,
+ output logic op_done_o,
+ output logic op_err_o,
// Flash Macro Interface
- output logic flash_req_o,
+ output logic flash_req_o,
output logic [BusAddrW-1:0] flash_addr_o,
- output logic [EraseBitWidth-1:0] flash_op_o,
- input flash_done_i,
- input flash_error_i
+ output flash_erase_e flash_op_o,
+ input flash_done_i,
+ input flash_error_i
);
import flash_ctrl_pkg::*;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
index 8b1ffe6..fcf14f0 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_lcmgr.sv
@@ -162,12 +162,14 @@
logic start;
flash_op_e op;
+ flash_prog_e prog_type;
flash_erase_e erase_type;
flash_part_e part_sel;
logic [11:0] num_words;
logic [BusAddrW-1:0] addr;
logic [BusWidth-1:0] rsp_mask;
+ assign prog_type = FlashProgNormal;
assign erase_type = FlashErasePage;
// seed phase is always read
// rma phase is erase unless we are validating
@@ -332,6 +334,7 @@
assign rma_token_o = rsp_token[0] ^ rsp_token[1] ^ rsp_mask;
assign ctrl_o.start.q = start;
assign ctrl_o.op.q = op;
+ assign ctrl_o.prog_sel.q = prog_type;
assign ctrl_o.erase_sel.q = erase_type;
assign ctrl_o.partition_sel.q = part_sel;
assign ctrl_o.num = num_words;
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
index f253df7..ffdbc88 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_pkg.sv
@@ -167,14 +167,19 @@
FlashOpInvalid = 2'h3
} flash_op_e;
+ // Flash Program Operations Supported
+ typedef enum logic {
+ FlashProgNormal = 0,
+ FlashProgRepair = 1
+ } flash_prog_e;
+ parameter int ProgTypes = 2;
+
// Flash Erase Operations Supported
typedef enum logic {
FlashErasePage = 0,
FlashEraseBank = 1
} flash_erase_e;
- parameter int EraseBitWidth = $bits(flash_erase_e);
-
// Flash function select
typedef enum logic [1:0] {
NoneSel,
@@ -205,6 +210,7 @@
logic [BusAddrW-1:0] addr;
logic [BusWidth-1:0] prog_data;
logic prog_last;
+ flash_prog_e prog_type;
logic scramble_en;
logic [127:0] addr_key;
logic [127:0] data_key;
@@ -221,6 +227,7 @@
addr: '0,
prog_data: '0,
prog_last: '0,
+ prog_type: FlashProgNormal,
scramble_en: '0,
addr_key: 128'hDEADBEEFBEEFFACEDEADBEEF5A5AA5A5,
data_key: 128'hDEADBEEF5A5AA5A5DEADBEEFBEEFFACE
@@ -228,6 +235,7 @@
// memory to flash controller
typedef struct packed {
+ logic [ProgTypes-1:0] prog_type_avail;
logic rd_done;
logic prog_done;
logic erase_done;
@@ -237,6 +245,7 @@
// default value of flash_rsp_t (for dangling ports)
parameter flash_rsp_t FLASH_RSP_DEFAULT = '{
+ prog_type_avail: '{default: '1},
rd_done: 1'b0,
prog_done: 1'b0,
erase_done: 1'b0,
@@ -254,6 +263,7 @@
logic [127:0] data_key;
// TBD: this signal will become multi-bit in the future
logic seed_valid;
+ logic prog_repair_en;
} otp_flash_t;
// lc to flash_ctrl
@@ -281,7 +291,8 @@
parameter otp_flash_t OTP_FLASH_DEFAULT = '{
addr_key: 128'hDEADBEEFBEEFFACEDEADBEEF5A5AA5A5,
data_key: 128'hDEADBEEF5A5AA5A5DEADBEEFBEEFFACE,
- seed_valid: 1'b1
+ seed_valid: 1'b1,
+ prog_repair_en: 1'b1
};
parameter lc_flash_req_t LC_FLASH_REQ_DEFAULT = '{
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
index 0fcbae5..5e2b197 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_prog.sv
@@ -9,12 +9,14 @@
input clk_i,
input rst_ni,
- // Software Interface
+ // Control Interface
input op_start_i,
input [11:0] op_num_words_i,
output logic op_done_o,
output logic op_err_o,
- input [BusAddrW-1:0] op_addr_i,
+ input [BusAddrW-1:0] op_addr_i,
+ input flash_prog_e op_type_i,
+ input [ProgTypes-1:0] type_avail_i,
// FIFO Interface
input data_rdy_i,
@@ -27,6 +29,7 @@
output logic flash_ovfl_o,
output logic [BusWidth-1:0] flash_data_o,
output logic flash_last_o, // last beat of prog data
+ output flash_prog_e flash_type_o,
input flash_done_i,
input flash_error_i
);
@@ -56,6 +59,10 @@
assign txn_done = flash_req_o && flash_done_i;
assign cnt_hit = (cnt == op_num_words_i);
+ // if the requested prog type is available
+ logic prog_type_avail;
+ assign prog_type_avail = type_avail_i[op_type_i];
+
// when error'd, continue to drain all program fifo contents like normal operation
// if this is not done, software may fill up the fifo without anyone
// draining the contents, leading to a lockup
@@ -69,17 +76,22 @@
unique case (st)
StNorm: begin
- flash_req_o = op_start_i & data_rdy_i;
+ // if the select operation type is not available, error
+ if (op_start_i && prog_type_avail) begin
+ flash_req_o = data_rdy_i;
- if(txn_done && cnt_hit) begin
- cnt_nxt = '0;
- data_rd_o = 1'b1;
- op_done_o = 1'b1;
- op_err_o = flash_error_i;
- end else if(txn_done) begin
- cnt_nxt = cnt + 1'b1;
- data_rd_o = 1'b1;
- st_nxt = flash_error_i ? StErr : StNorm;
+ if(txn_done && cnt_hit) begin
+ cnt_nxt = '0;
+ data_rd_o = 1'b1;
+ op_done_o = 1'b1;
+ op_err_o = flash_error_i;
+ end else if(txn_done) begin
+ cnt_nxt = cnt + 1'b1;
+ data_rd_o = 1'b1;
+ st_nxt = flash_error_i ? StErr : StNorm;
+ end
+ end else if (op_start_i && !prog_type_avail) begin
+ st_nxt = StErr;
end
end
StErr: begin
@@ -103,5 +115,6 @@
assign flash_addr_o = int_addr[0 +: BusAddrW];
assign flash_ovfl_o = int_addr[BusAddrW];
assign flash_last_o = flash_req_o & cnt_hit;
+ assign flash_type_o = op_type_i;
endmodule // flash_ctrl_prog
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy.sv b/hw/ip/flash_ctrl/rtl/flash_phy.sv
index 28ad2a1..8f52256 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy.sv
@@ -57,6 +57,7 @@
logic [NumBanks-1:0] prog_done;
logic [NumBanks-1:0] erase_done;
logic [NumBanks-1:0] init_busy;
+ logic [ProgTypes-1:0] prog_type_avail [NumBanks];
// common interface
logic [BusWidth-1:0] rd_data [NumBanks];
@@ -72,6 +73,8 @@
assign host_req_done_o = seq_fifo_pending & host_rsp_vld[rsp_bank_sel];
assign host_rdata_o = host_rsp_data[rsp_bank_sel];
+ // all banks are assumed to be the same in terms of prog_type support
+ assign flash_ctrl_o.prog_type_avail = prog_type_avail[0];
assign flash_ctrl_o.rd_done = rd_done[ctrl_bank_sel];
assign flash_ctrl_o.prog_done = prog_done[ctrl_bank_sel];
assign flash_ctrl_o.erase_done = erase_done[ctrl_bank_sel];
@@ -148,8 +151,10 @@
.addr_i(flash_ctrl_i.addr[0 +: BusBankAddrW]),
.prog_data_i(flash_ctrl_i.prog_data),
.prog_last_i(flash_ctrl_i.prog_last),
+ .prog_type_i(flash_ctrl_i.prog_type),
.addr_key_i(flash_ctrl_i.addr_key),
.data_key_i(flash_ctrl_i.data_key),
+ .prog_type_avail_o(prog_type_avail[bank]),
.host_req_rdy_o(host_req_rdy[bank]),
.host_req_done_o(host_req_done[bank]),
.rd_done_o(rd_done[bank]),
@@ -160,4 +165,19 @@
);
end
+ //////////////////////////////////////////////
+ // Assertions, Assumptions, and Coverpoints //
+ /////////////////////////////////////////////
+ logic [ProgTypes-1:0] unused_prog_type;
+
+ always_comb begin
+ unused_prog_type = '0;
+ for (int i = 0; i < NumBanks; i++) begin : gen_prog_type_xor
+ unused_prog_type ^= prog_type_avail[i];
+ end
+ end
+
+ // all banks must support the same kinds of programs
+ `ASSERT(homogenousProg_a, unused_prog_type == '0)
+
endmodule // flash_phy
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_core.sv b/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
index eacd507..bf57e16 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_core.sv
@@ -27,8 +27,10 @@
input [BusBankAddrW-1:0] addr_i,
input [BusWidth-1:0] prog_data_i,
input prog_last_i,
+ input flash_ctrl_pkg::flash_prog_e prog_type_i,
input [KeySize-1:0] addr_key_i,
input [KeySize-1:0] data_key_i,
+ output logic [ProgTypes-1:0] prog_type_avail_o,
output logic host_req_rdy_o,
output logic host_req_done_o,
output logic rd_done_o,
@@ -340,11 +342,13 @@
.rst_ni,
.rd_i(flash_rd_req),
.prog_i(flash_prog_req),
+ .prog_type_i(prog_type_i),
.pg_erase_i(reqs[PhyPgErase]),
.bk_erase_i(reqs[PhyBkErase]),
.addr_i(muxed_addr[BusBankAddrW-1:LsbAddrBit]),
.part_i(muxed_part),
.prog_data_i(prog_data),
+ .prog_type_avail_o(prog_type_avail_o),
.ack_o(ack),
.rd_data_o(flash_rdata),
.init_busy_o, // TBD this needs to be looked at later. What init do we need to do,
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_pkg.sv b/hw/ip/flash_ctrl/rtl/flash_phy_pkg.sv
index 6da6b6e..738ff86 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_pkg.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_pkg.sv
@@ -23,9 +23,10 @@
// will switch to this after bus widening
// flash ctrl / bus parameters
- parameter int BusWidth = flash_ctrl_pkg::BusWidth;
- parameter int BusBankAddrW = flash_ctrl_pkg::BusBankAddrW;
- parameter int BusWordW = flash_ctrl_pkg::BusWordW;
+ parameter int BusWidth = flash_ctrl_pkg::BusWidth;
+ parameter int BusBankAddrW = flash_ctrl_pkg::BusBankAddrW;
+ parameter int BusWordW = flash_ctrl_pkg::BusWordW;
+ parameter int ProgTypes = flash_ctrl_pkg::ProgTypes;
// address bits remain must be 0
parameter int AddrBitsRemain = DataWidth % BusWidth;
diff --git a/hw/ip/prim_generic/rtl/prim_generic_flash.sv b/hw/ip/prim_generic/rtl/prim_generic_flash.sv
index 29fbabc..b6962d7 100644
--- a/hw/ip/prim_generic/rtl/prim_generic_flash.sv
+++ b/hw/ip/prim_generic/rtl/prim_generic_flash.sv
@@ -21,14 +21,18 @@
input rst_ni,
input rd_i,
input prog_i,
+ // the generic model does not make use of program types
+ input flash_ctrl_pkg::flash_prog_e prog_type_i,
input pg_erase_i,
input bk_erase_i,
input [AddrW-1:0] addr_i,
input flash_ctrl_pkg::flash_part_e part_i,
input [DataWidth-1:0] prog_data_i,
+ output logic [flash_ctrl_pkg::ProgTypes-1:0] prog_type_avail_o,
output logic ack_o,
output logic [DataWidth-1:0] rd_data_o,
output logic init_busy_o,
+
input tck_i,
input tdi_i,
input tms_i,
@@ -328,4 +332,8 @@
// hard-wire assignment for now
assign tdo_o = 1'b0;
+ // this represents the type of program operations that are supported
+ assign prog_type_avail_o[flash_ctrl_pkg::FlashProgNormal] = 1'b1;
+ assign prog_type_avail_o[flash_ctrl_pkg::FlashProgRepair] = 1'b1;
+
endmodule // prim_generic_flash