Message ID | 20200928101146.12786-2-green.wan@sifive.com |
---|---|
State | New |
Headers | show |
Series | Add file-backed and write-once features to OTP | expand |
Hi Green, On Mon, Sep 28, 2020 at 6:12 PM 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> > --- > hw/misc/sifive_u_otp.c | 30 +++++++++++++++++++++++++++++- > include/hw/misc/sifive_u_otp.h | 3 +++ > 2 files changed, 32 insertions(+), 1 deletion(-) > I am not sure how you tested this. I wrote a simple U-Boot command to call U-Boot sifive-otp driver to test the write functionality, but it failed. => misc write otp@10070000 0 80200000 10 => misc read otp@10070000 0 80400000 10 => md 80400000 80400000: ffffffff ffffffff ffffffff ffffffff ................ 80400010: 00000000 00000000 00000000 00000000 ................ 80400020: 00000000 00000000 00000000 00000000 ................ 80400030: 00000000 00000000 00000000 00000000 ................ 80400040: 00000000 00000000 00000000 00000000 ................ 80400050: 00000000 00000000 00000000 00000000 ................ 80400060: 00000000 00000000 00000000 00000000 ................ 80400070: 00000000 00000000 00000000 00000000 ................ 80400080: 00000000 00000000 00000000 00000000 ................ 80400090: 00000000 00000000 00000000 00000000 ................ 804000a0: 00000000 00000000 00000000 00000000 ................ 804000b0: 00000000 00000000 00000000 00000000 ................ 804000c0: 00000000 00000000 00000000 00000000 ................ 804000d0: 00000000 00000000 00000000 00000000 ................ 804000e0: 00000000 00000000 00000000 00000000 ................ 804000f0: 00000000 00000000 00000000 00000000 ................ => misc write otp@10070000 0 80200010 10 => misc read otp@10070000 0 80400010 10 => md 80400000 80400000: ffffffff ffffffff ffffffff ffffffff ................ 80400010: ffffffff ffffffff ffffffff ffffffff ................ 80400020: 00000000 00000000 00000000 00000000 ................ 80400030: 00000000 00000000 00000000 00000000 ................ 80400040: 00000000 00000000 00000000 00000000 ................ 80400050: 00000000 00000000 00000000 00000000 ................ 80400060: 00000000 00000000 00000000 00000000 ................ 80400070: 00000000 00000000 00000000 00000000 ................ 80400080: 00000000 00000000 00000000 00000000 ................ 80400090: 00000000 00000000 00000000 00000000 ................ 804000a0: 00000000 00000000 00000000 00000000 ................ 804000b0: 00000000 00000000 00000000 00000000 ................ 804000c0: 00000000 00000000 00000000 00000000 ................ 804000d0: 00000000 00000000 00000000 00000000 ................ 804000e0: 00000000 00000000 00000000 00000000 ................ 804000f0: 00000000 00000000 00000000 00000000 ................ But it can read the serial number at offset 0x3f0 => misc read otp@10070000 3f0 80400010 10 => md 80400000 80400000: ffffffff ffffffff ffffffff ffffffff ................ 80400010: 00000001 fffffffe ffffffff ffffffff ................ 80400020: 00000000 00000000 00000000 00000000 ................ 80400030: 00000000 00000000 00000000 00000000 ................ 80400040: 00000000 00000000 00000000 00000000 ................ 80400050: 00000000 00000000 00000000 00000000 ................ 80400060: 00000000 00000000 00000000 00000000 ................ 80400070: 00000000 00000000 00000000 00000000 ................ 80400080: 00000000 00000000 00000000 00000000 ................ 80400090: 00000000 00000000 00000000 00000000 ................ 804000a0: 00000000 00000000 00000000 00000000 ................ 804000b0: 00000000 00000000 00000000 00000000 ................ 804000c0: 00000000 00000000 00000000 00000000 ................ 804000d0: 00000000 00000000 00000000 00000000 ................ 804000e0: 00000000 00000000 00000000 00000000 ................ 804000f0: 00000000 00000000 00000000 00000000 ................ Regards, Bin
diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index c2f3c8e129..685c1f8e07 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -25,6 +25,14 @@ #include "qemu/module.h" #include "hw/misc/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/misc/sifive_u_otp.h b/include/hw/misc/sifive_u_otp.h index 82c9176c8f..ebffbc1fa5 100644 --- a/include/hw/misc/sifive_u_otp.h +++ b/include/hw/misc/sifive_u_otp.h @@ -36,6 +36,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) @@ -75,6 +77,7 @@ 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; };