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 |
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 --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;
- 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(-)