mirror of https://github.com/xemu-project/xemu.git
hw/misc/sifive_u_otp: Add write function and write-once protection
- 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> Reviewed-by: Bin Meng <bin.meng@windriver.com> Tested-by: Bin Meng <bin.meng@windriver.com> Message-id: 20201020033732.12921-2-green.wan@sifive.com Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
33a9a57d2c
commit
a54d259157
|
@ -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] & ~(0x1 << 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,
|
||||
"write once error: 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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue