[otbn] Introduce locked state

Introduce a new locked state, represented as LOCKED in the STATUS
register to indicate if OTBN has detected a fatal error and is now
"dead" until a reset.

With this new state, OTBN guarantees a certain value of the STATUS
register after a fatal error was detected, simplifying the documentation
and the verification.

Furthermore, operation handling from Ibex got easier even if fatal
alerts don't reach Ibex for whatever reason: an operation always returns
with a done interrupt, and reading the STATUS register clearly indicates
what happened to OTBN. (Before, software would have to read
FATAL_ALERT_CAUSE as well if STATUS was non-zero to check if an
operation can be restarted [in case of a recoverable error], or if
OTBN is locked.)

Signed-off-by: Philipp Wagner <phw@lowrisc.org>
diff --git a/hw/ip/otbn/data/otbn.hjson b/hw/ip/otbn/data/otbn.hjson
index 0a02f45..b5997f5 100644
--- a/hw/ip/otbn/data/otbn.hjson
+++ b/hw/ip/otbn/data/otbn.hjson
@@ -243,6 +243,15 @@
                   <td>BUSY_SEC_WIPE_IMEM</td>
                   <td>OTBN is securely wiping the instruction memory.</td>
                 </tr>
+                <tr>
+                  <td>0xFF</td>
+                  <td>LOCKED</td>
+                  <td>
+                    OTBN is locked as reaction to a fatal error, and must be
+                    reset to unlock it again. See also the section on fatal
+                    error handling.
+                  </td>
+                </tr>
               </tbody>
             </table>
           '''
diff --git a/hw/ip/otbn/doc/_index.md b/hw/ip/otbn/doc/_index.md
index f9aa1e2..e20876d 100644
--- a/hw/ip/otbn/doc/_index.md
+++ b/hw/ip/otbn/doc/_index.md
@@ -523,17 +523,21 @@
 
 OTBN can be in different operational states.
 OTBN is *busy* for as long it is performing an operation.
+OTBN is *locked* if a fatal error was observed.
 Otherwise OTBN is *idle*.
 
 The current operational state is reflected in the {{< regref "STATUS" >}} register.
 - If OTBN is idle, the {{< regref "STATUS" >}} register is set to `IDLE`.
 - If OTBN is busy, the {{< regref "STATUS" >}} register is set to one of the values starting with `BUSY_`.
+- If OTBN is locked, the {{< regref "STATUS" >}} register is set to `LOCKED`.
 
 OTBN transitions into the busy state as result of host software [issuing a command](#design-details-commands); OTBN is then said to perform an operation.
 OTBN transitions out of the busy state whenever the operation has completed.
 In the {{< regref "STATUS" >}} register the different `BUSY_*` values represent the operation that is currently being performed.
 
-A transition from busy to idle is signaled by the `done` interrupt ({{< regref "INTR_STATE.done" >}}).
+A transition out of the busy state is signaled by the `done` interrupt ({{< regref "INTR_STATE.done" >}}).
+
+The locked state is a terminal state; transitioning out of it requires an OTBN reset.
 
 ### Operations and Commands {#design-details-commands}
 
@@ -557,7 +561,7 @@
 - From this point on, all subsequent instructions are executed according to their semantics until either an {{< otbnInsnRef "ECALL" >}} instruction is executed, or an error is detected.
 - A [secure wipe of internal state](#design-details-secure-wipe-internal) is performed.
 - The {{< regref "ERR_BITS" >}} register is set to indicate either a successful execution (value `0`), or to indicate the error that was observed (a non-zero value).
-- OTBN transitions into the [idle state](#design-details-operational-states).
+- OTBN transitions into the [idle state](#design-details-operational-states) (in case of a successful execution, or a recoverable error) or the locked state (in case of a fatal error).
   This transition is signaled by raising the `done` interrupt ({{< regref "INTR_STATE.done" >}}), and reflected in the {{< regref "STATUS" >}} register.
 
 ### Error Handling and Reporting {#design-details-error-handling-and-reporting}
@@ -603,6 +607,7 @@
    - A [secure wipe of internal state](#design-details-secure-wipe-internal) is performed.
    - The {{< regref "ERR_BITS" >}} register is set to a non-zero value that describes the error.
    - The current operation is marked as complete by setting {{< regref "INTR_STATE.done" >}}.
+   - The {{< regref "STATUS" >}} register is set to `LOCKED`.
 3. A [fatal alert]({{< relref "#alerts" >}}) is raised.
 
 Note that OTBN can detect some errors even when it isn't running.
diff --git a/hw/ip/otbn/rtl/otbn_pkg.sv b/hw/ip/otbn/rtl/otbn_pkg.sv
index c17fc85..f90ea1f 100644
--- a/hw/ip/otbn/rtl/otbn_pkg.sv
+++ b/hw/ip/otbn/rtl/otbn_pkg.sv
@@ -62,7 +62,8 @@
     StatusIdle            = 8'h00,
     StatusBusyExecute     = 8'h01,
     StatusBusySecWipeDmem = 8'h02,
-    StatusBusySecWipeImem = 8'h03
+    StatusBusySecWipeImem = 8'h03,
+    StatusLocked          = 8'hFF
   } status_e;
 
   // Error bits
diff --git a/sw/device/lib/dif/dif_otbn.h b/sw/device/lib/dif/dif_otbn.h
index 5868e8d..c7323be 100644
--- a/sw/device/lib/dif/dif_otbn.h
+++ b/sw/device/lib/dif/dif_otbn.h
@@ -82,6 +82,7 @@
   kDifOtbnStatusBusyExecute = 0x01,
   kDifOtbnStatusBusySecWipeDmem = 0x02,
   kDifOtbnStatusBusySecWipeImem = 0x03,
+  kDifOtbnStatusLocked = 0xFF,
 } dif_otbn_status_t;
 
 /**
diff --git a/sw/device/silicon_creator/lib/drivers/otbn.h b/sw/device/silicon_creator/lib/drivers/otbn.h
index 0d24d49..fd1ed27 100644
--- a/sw/device/silicon_creator/lib/drivers/otbn.h
+++ b/sw/device/silicon_creator/lib/drivers/otbn.h
@@ -42,6 +42,7 @@
   kOtbnStatusBusyExecute = 0x01,
   kOtbnStatusBusySecWipeDmem = 0x02,
   kOtbnStatusBusySecWipeImem = 0x03,
+  kOtbnStatusLocked = 0xFF,
 } otbn_status_t;
 
 /**