[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC PATCH v5 1/2] hw/riscv: sifive_u: Add write operation and write
From: |
Alistair Francis |
Subject: |
Re: [RFC PATCH v5 1/2] hw/riscv: sifive_u: Add write operation and write-once protection |
Date: |
Fri, 25 Sep 2020 14:34:56 -0700 |
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
>
>