diff mbox series

[RFC,v6,2/2] hw/misc/sifive_u_otp: Add backend drive support

Message ID 20200928101146.12786-3-green.wan@sifive.com
State New
Headers show
Series Add file-backed and write-once features to OTP | expand

Commit Message

Green Wan Sept. 28, 2020, 10:11 a.m. UTC
Add '-drive' support to OTP device. Allow users to assign a raw file
as OTP image.

test commands for 16k otp.img filled with zero:

dd if=/dev/zero of=./otp.img bs=1k count=16
./qemu-system-riscv64 -M sifive_u -m 256M -nographic -bios none \
-kernel ../opensbi/build/platform/sifive/fu540/firmware/fw_payload.elf \
-d guest_errors -drive if=none,format=raw,file=otp.img

Signed-off-by: Green Wan <green.wan@sifive.com>
---
 hw/misc/sifive_u_otp.c         | 51 ++++++++++++++++++++++++++++++++++
 include/hw/misc/sifive_u_otp.h |  2 ++
 2 files changed, 53 insertions(+)

Comments

Bin Meng Oct. 14, 2020, 5:41 a.m. UTC | #1
On Mon, Sep 28, 2020 at 6:12 PM Green Wan <green.wan@sifive.com> wrote:
>

> Add '-drive' support to OTP device. Allow users to assign a raw file

> as OTP image.

>

> test commands for 16k otp.img filled with zero:

>

> dd if=/dev/zero of=./otp.img bs=1k count=16


nits: please prefix the command with a leading "$ ", like

$ dd if=/dev/zero of=./otp.img bs=1k count=16

> ./qemu-system-riscv64 -M sifive_u -m 256M -nographic -bios none \

> -kernel ../opensbi/build/platform/sifive/fu540/firmware/fw_payload.elf \

> -d guest_errors -drive if=none,format=raw,file=otp.img

>

> Signed-off-by: Green Wan <green.wan@sifive.com>

> ---

>  hw/misc/sifive_u_otp.c         | 51 ++++++++++++++++++++++++++++++++++

>  include/hw/misc/sifive_u_otp.h |  2 ++

>  2 files changed, 53 insertions(+)

>

> diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c

> index 685c1f8e07..f2585c1ed7 100644

> --- a/hw/misc/sifive_u_otp.c

> +++ b/hw/misc/sifive_u_otp.c

> @@ -19,11 +19,14 @@

>   */

>

>  #include "qemu/osdep.h"

> +#include "qapi/error.h"

>  #include "hw/qdev-properties.h"

>  #include "hw/sysbus.h"

>  #include "qemu/log.h"

>  #include "qemu/module.h"

>  #include "hw/misc/sifive_u_otp.h"

> +#include "sysemu/blockdev.h"

> +#include "sysemu/block-backend.h"

>

>  #define WRITTEN_BIT_ON 0x1

>

> @@ -54,6 +57,16 @@ static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)

>          if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&

>              (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&

>              (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) {

> +

> +            /* read from backend */

> +            if (s->blk) {

> +                int32_t buf;

> +

> +                blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf,

> +                          SIFIVE_U_OTP_FUSE_WORD);

> +                return buf;

> +            }

> +

>              return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];

>          } else {

>              return 0xff;

> @@ -145,6 +158,12 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr,

>              /* write bit data */

>              SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin);

>

> +            /* write to backend */

> +            if (s->blk) {

> +                blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &val32,

> +                           SIFIVE_U_OTP_FUSE_WORD, 0);

> +            }

> +

>              /* update written bit */

>              SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON);

>          }

> @@ -168,16 +187,48 @@ static const MemoryRegionOps sifive_u_otp_ops = {

>

>  static Property sifive_u_otp_properties[] = {

>      DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),

> +    DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk),

>      DEFINE_PROP_END_OF_LIST(),

>  };

>

>  static void sifive_u_otp_realize(DeviceState *dev, Error **errp)

>  {

>      SiFiveUOTPState *s = SIFIVE_U_OTP(dev);

> +    DriveInfo *dinfo;

>

>      memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s,

>                            TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);

>      sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);

> +

> +    dinfo = drive_get_next(IF_NONE);

> +    if (dinfo) {

> +        int ret;

> +        uint64_t perm;

> +        int filesize;

> +        BlockBackend *blk;

> +

> +        blk = blk_by_legacy_dinfo(dinfo);

> +        filesize = SIFIVE_U_OTP_NUM_FUSES * SIFIVE_U_OTP_FUSE_WORD;

> +        if (blk_getlength(blk) < filesize) {

> +            error_setg(errp, "OTP drive size < 16K");

> +            return;

> +        }

> +

> +        qdev_prop_set_drive_err(dev, "drive", blk, errp);

> +

> +        if (s->blk) {

> +            perm = BLK_PERM_CONSISTENT_READ |

> +                   (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);

> +            ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);

> +            if (ret < 0) {

> +                return;

> +            }

> +

> +            if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) {

> +                error_setg(errp, "failed to read the initial flash content");

> +            }

> +        }

> +    }

>  }

>

>  static void sifive_u_otp_reset(DeviceState *dev)

> diff --git a/include/hw/misc/sifive_u_otp.h b/include/hw/misc/sifive_u_otp.h

> index ebffbc1fa5..5d0d7df455 100644

> --- a/include/hw/misc/sifive_u_otp.h

> +++ b/include/hw/misc/sifive_u_otp.h

> @@ -46,6 +46,7 @@

>

>  #define SIFIVE_U_OTP_PA_MASK        0xfff

>  #define SIFIVE_U_OTP_NUM_FUSES      0x1000

> +#define SIFIVE_U_OTP_FUSE_WORD      4

>  #define SIFIVE_U_OTP_SERIAL_ADDR    0xfc

>

>  #define SIFIVE_U_OTP_REG_SIZE       0x1000

> @@ -80,6 +81,7 @@ struct SiFiveUOTPState {

>      uint32_t fuse_wo[SIFIVE_U_OTP_NUM_FUSES];

>      /* config */

>      uint32_t serial;

> +    BlockBackend *blk;

>  };

>


Please add the serial number initialization for the block backend as
well in sifive_u_otp_reset().

The logic should be something like testing offset 0x3f0 and 0x3f4
numbers to see if they follow the rule: value 0x3f0 == ~(value 0x3f4).
If not, the data should be initialized per the `serial` property from
the QEMU object.

Regards,
Bin
diff mbox series

Patch

diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c
index 685c1f8e07..f2585c1ed7 100644
--- a/hw/misc/sifive_u_otp.c
+++ b/hw/misc/sifive_u_otp.c
@@ -19,11 +19,14 @@ 
  */
 
 #include "qemu/osdep.h"
+#include "qapi/error.h"
 #include "hw/qdev-properties.h"
 #include "hw/sysbus.h"
 #include "qemu/log.h"
 #include "qemu/module.h"
 #include "hw/misc/sifive_u_otp.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
 
 #define WRITTEN_BIT_ON 0x1
 
@@ -54,6 +57,16 @@  static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
         if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&
             (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&
             (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) {
+
+            /* read from backend */
+            if (s->blk) {
+                int32_t buf;
+
+                blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf,
+                          SIFIVE_U_OTP_FUSE_WORD);
+                return buf;
+            }
+
             return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
         } else {
             return 0xff;
@@ -145,6 +158,12 @@  static void sifive_u_otp_write(void *opaque, hwaddr addr,
             /* write bit data */
             SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin);
 
+            /* write to backend */
+            if (s->blk) {
+                blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &val32,
+                           SIFIVE_U_OTP_FUSE_WORD, 0);
+            }
+
             /* update written bit */
             SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON);
         }
@@ -168,16 +187,48 @@  static const MemoryRegionOps sifive_u_otp_ops = {
 
 static Property sifive_u_otp_properties[] = {
     DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),
+    DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk),
     DEFINE_PROP_END_OF_LIST(),
 };
 
 static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
 {
     SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
+    DriveInfo *dinfo;
 
     memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s,
                           TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+
+    dinfo = drive_get_next(IF_NONE);
+    if (dinfo) {
+        int ret;
+        uint64_t perm;
+        int filesize;
+        BlockBackend *blk;
+
+        blk = blk_by_legacy_dinfo(dinfo);
+        filesize = SIFIVE_U_OTP_NUM_FUSES * SIFIVE_U_OTP_FUSE_WORD;
+        if (blk_getlength(blk) < filesize) {
+            error_setg(errp, "OTP drive size < 16K");
+            return;
+        }
+
+        qdev_prop_set_drive_err(dev, "drive", blk, errp);
+
+        if (s->blk) {
+            perm = BLK_PERM_CONSISTENT_READ |
+                   (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);
+            ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
+            if (ret < 0) {
+                return;
+            }
+
+            if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) {
+                error_setg(errp, "failed to read the initial flash content");
+            }
+        }
+    }
 }
 
 static void sifive_u_otp_reset(DeviceState *dev)
diff --git a/include/hw/misc/sifive_u_otp.h b/include/hw/misc/sifive_u_otp.h
index ebffbc1fa5..5d0d7df455 100644
--- a/include/hw/misc/sifive_u_otp.h
+++ b/include/hw/misc/sifive_u_otp.h
@@ -46,6 +46,7 @@ 
 
 #define SIFIVE_U_OTP_PA_MASK        0xfff
 #define SIFIVE_U_OTP_NUM_FUSES      0x1000
+#define SIFIVE_U_OTP_FUSE_WORD      4
 #define SIFIVE_U_OTP_SERIAL_ADDR    0xfc
 
 #define SIFIVE_U_OTP_REG_SIZE       0x1000
@@ -80,6 +81,7 @@  struct SiFiveUOTPState {
     uint32_t fuse_wo[SIFIVE_U_OTP_NUM_FUSES];
     /* config */
     uint32_t serial;
+    BlockBackend *blk;
 };
 
 #endif /* HW_SIFIVE_U_OTP_H */