|
@@ -25,6 +25,14 @@
|
|
#include "qemu/module.h"
|
|
#include "qemu/module.h"
|
|
#include "hw/misc/sifive_u_otp.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)
|
|
static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
|
|
{
|
|
{
|
|
SiFiveUOTPState *s = opaque;
|
|
SiFiveUOTPState *s = opaque;
|
|
@@ -123,7 +131,24 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr,
|
|
s->ptrim = val32;
|
|
s->ptrim = val32;
|
|
break;
|
|
break;
|
|
case SIFIVE_U_OTP_PWE:
|
|
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;
|
|
break;
|
|
default:
|
|
default:
|
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
|
|
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 */
|
|
/* Make a valid content of serial number */
|
|
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
|
|
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
|
|
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(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)
|
|
static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
|