- 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(-)
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
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
>
>
© 2016 - 2025 Red Hat, Inc.