diff mbox series

[RFC,v5,1/2] hw/riscv: sifive_u: Add write operation and write-once protection

Message ID 20200901154711.18457-2-green.wan@sifive.com
State Accepted
Commit a54d259157e2575b69e2cf7cf03592c74559cb7e
Headers show
Series Add file-backed and write-once features to OTP | expand

Commit Message

Green Wan Sept. 1, 2020, 3:47 p.m. UTC
- Add write operation to update fuse data bit when PWE bit is on.
 - Add array, fuse_wo, to store the 'written' status for all bits
   of OTP to block the write operation.

Signed-off-by: Green Wan <green.wan@sifive.com>
---
 hw/riscv/sifive_u_otp.c         | 30 +++++++++++++++++++++++++++++-
 include/hw/riscv/sifive_u_otp.h |  3 +++
 2 files changed, 32 insertions(+), 1 deletion(-)

Comments

Alistair Francis Sept. 25, 2020, 9:34 p.m. UTC | #1
On Tue, Sep 1, 2020 at 9:09 AM Green Wan <green.wan@sifive.com> wrote:
>

>  - Add write operation to update fuse data bit when PWE bit is on.

>  - Add array, fuse_wo, to store the 'written' status for all bits

>    of OTP to block the write operation.

>

> Signed-off-by: Green Wan <green.wan@sifive.com>


Reviewed-by: Alistair Francis <alistair.francis@wdc.com>


Alistair

> ---

>  hw/riscv/sifive_u_otp.c         | 30 +++++++++++++++++++++++++++++-

>  include/hw/riscv/sifive_u_otp.h |  3 +++

>  2 files changed, 32 insertions(+), 1 deletion(-)

>

> diff --git a/hw/riscv/sifive_u_otp.c b/hw/riscv/sifive_u_otp.c

> index f6ecbaa2ca..b8369e9035 100644

> --- a/hw/riscv/sifive_u_otp.c

> +++ b/hw/riscv/sifive_u_otp.c

> @@ -25,6 +25,14 @@

>  #include "qemu/module.h"

>  #include "hw/riscv/sifive_u_otp.h"

>

> +#define WRITTEN_BIT_ON 0x1

> +

> +#define SET_FUSEARRAY_BIT(map, i, off, bit)    \

> +    map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(bit << off))

> +

> +#define GET_FUSEARRAY_BIT(map, i, off)    \

> +    ((map[i] >> off) & 0x1)

> +

>  static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)

>  {

>      SiFiveUOTPState *s = opaque;

> @@ -123,7 +131,24 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr,

>          s->ptrim = val32;

>          break;

>      case SIFIVE_U_OTP_PWE:

> -        s->pwe = val32;

> +        s->pwe = val32 & SIFIVE_U_OTP_PWE_EN;

> +

> +        /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */

> +        if (s->pwe && !s->pas) {

> +            if (GET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio)) {

> +                qemu_log_mask(LOG_GUEST_ERROR,

> +                              "Error: write idx<%u>, bit<%u>\n",

> +                              s->pa, s->paio);

> +                break;

> +            }

> +

> +            /* write bit data */

> +            SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin);

> +

> +            /* update written bit */

> +            SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON);

> +        }

> +

>          break;

>      default:

>          qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx

> @@ -165,6 +190,9 @@ static void sifive_u_otp_reset(DeviceState *dev)

>      /* Make a valid content of serial number */

>      s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;

>      s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial);

> +

> +    /* Initialize write-once map */

> +    memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo));

>  }

>

>  static void sifive_u_otp_class_init(ObjectClass *klass, void *data)

> diff --git a/include/hw/riscv/sifive_u_otp.h b/include/hw/riscv/sifive_u_otp.h

> index 639297564a..4a5a0acf48 100644

> --- a/include/hw/riscv/sifive_u_otp.h

> +++ b/include/hw/riscv/sifive_u_otp.h

> @@ -35,6 +35,8 @@

>  #define SIFIVE_U_OTP_PTRIM      0x34

>  #define SIFIVE_U_OTP_PWE        0x38

>

> +#define SIFIVE_U_OTP_PWE_EN     (1 << 0)

> +

>  #define SIFIVE_U_OTP_PCE_EN     (1 << 0)

>

>  #define SIFIVE_U_OTP_PDSTB_EN   (1 << 0)

> @@ -73,6 +75,7 @@ typedef struct SiFiveUOTPState {

>      uint32_t ptrim;

>      uint32_t pwe;

>      uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES];

> +    uint32_t fuse_wo[SIFIVE_U_OTP_NUM_FUSES];

>      /* config */

>      uint32_t serial;

>  } SiFiveUOTPState;

> --

> 2.17.1

>

>
diff mbox series

Patch

diff --git a/hw/riscv/sifive_u_otp.c b/hw/riscv/sifive_u_otp.c
index f6ecbaa2ca..b8369e9035 100644
--- a/hw/riscv/sifive_u_otp.c
+++ b/hw/riscv/sifive_u_otp.c
@@ -25,6 +25,14 @@ 
 #include "qemu/module.h"
 #include "hw/riscv/sifive_u_otp.h"
 
+#define WRITTEN_BIT_ON 0x1
+
+#define SET_FUSEARRAY_BIT(map, i, off, bit)    \
+    map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(bit << off))
+
+#define GET_FUSEARRAY_BIT(map, i, off)    \
+    ((map[i] >> off) & 0x1)
+
 static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
 {
     SiFiveUOTPState *s = opaque;
@@ -123,7 +131,24 @@  static void sifive_u_otp_write(void *opaque, hwaddr addr,
         s->ptrim = val32;
         break;
     case SIFIVE_U_OTP_PWE:
-        s->pwe = val32;
+        s->pwe = val32 & SIFIVE_U_OTP_PWE_EN;
+
+        /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */
+        if (s->pwe && !s->pas) {
+            if (GET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio)) {
+                qemu_log_mask(LOG_GUEST_ERROR,
+                              "Error: write idx<%u>, bit<%u>\n",
+                              s->pa, s->paio);
+                break;
+            }
+
+            /* write bit data */
+            SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin);
+
+            /* update written bit */
+            SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON);
+        }
+
         break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
@@ -165,6 +190,9 @@  static void sifive_u_otp_reset(DeviceState *dev)
     /* Make a valid content of serial number */
     s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
     s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial);
+
+    /* Initialize write-once map */
+    memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo));
 }
 
 static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
diff --git a/include/hw/riscv/sifive_u_otp.h b/include/hw/riscv/sifive_u_otp.h
index 639297564a..4a5a0acf48 100644
--- a/include/hw/riscv/sifive_u_otp.h
+++ b/include/hw/riscv/sifive_u_otp.h
@@ -35,6 +35,8 @@ 
 #define SIFIVE_U_OTP_PTRIM      0x34
 #define SIFIVE_U_OTP_PWE        0x38
 
+#define SIFIVE_U_OTP_PWE_EN     (1 << 0)
+
 #define SIFIVE_U_OTP_PCE_EN     (1 << 0)
 
 #define SIFIVE_U_OTP_PDSTB_EN   (1 << 0)
@@ -73,6 +75,7 @@  typedef struct SiFiveUOTPState {
     uint32_t ptrim;
     uint32_t pwe;
     uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES];
+    uint32_t fuse_wo[SIFIVE_U_OTP_NUM_FUSES];
     /* config */
     uint32_t serial;
 } SiFiveUOTPState;