target-arm queue:

* allwinner-h3: Switch to SMC as PSCI conduit
  * arm: tcg: Adhere to SMCCC 1.3 section 5.2
  * xlnx-zcu102, xlnx-versal-virt: Support BBRAM and eFUSE devices
  * gdbstub related code cleanups
  * Don't put FPEXC and FPSID in org.gnu.gdb.arm.vfp XML
  * Use _init vs _new convention in bus creation function names
  * sabrelite: Connect SPI flash CS line to GPIO3_19
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmFV05gZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3kVoD/9rlpi81v6U2zPmW5s/lFB8
 m7eqtVpP2T1UwwGPw5jXZ4qAyDyCDXJxtW8B2ePxjXfrFT5f59hy9myBFqDebjNC
 Xwdwafc17lkUm0CrIEwhMhGYiXs6yak1YcGqEPZ3ceWt67kVByXGj89mLepogCHn
 LvcjQGC3PuDvDHWnOKdOBhxTu+rvQSDRXpVCuBAd3eJBn9jxG10cdaCr3/Z7VFA/
 bnc9bSU8qJ0hYCswHHld9R2Rk9zYDQmrtMpygN6pviCd5qWGEOh8b5vszmrSHYo9
 tn0bSp9d9k2wBXrPR5Ux3L0IMRBp7N88tSDw2QyatDltltjsCKw+ZMxjKHh0mxnr
 N1QF1FteIFliu5GQeMiEWPP87rVZ31quWZUIln6XYo9+aXus8jd88vxdpND1v767
 np/q6BW0g+Tuu2T+QRe5V8VBQJzgEAKT7AwCVHC+5Flyq8fWFcFdPp1dygWXdzW3
 Yhmq2JwwMq/3MjZY10aymohrvFPAQSx2bGGDS9yi8m5seaJvHjJW5fZQUVapy0vw
 andiIFNC9KxeQ23AZM0oKkW/d5EckKIkagfiq5+71QhvtbJrXbz+fs7UxHN0IVeX
 7px+ih0xJcz3uVxZtZ/kvpBMMe3WEMd9r2tZOhbJ9K8RlCcB11y1AnZaBs/2fess
 +DzTJOkZGu1oDP4IAAqGBg==
 =eAN3
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210930' into staging

target-arm queue:
 * allwinner-h3: Switch to SMC as PSCI conduit
 * arm: tcg: Adhere to SMCCC 1.3 section 5.2
 * xlnx-zcu102, xlnx-versal-virt: Support BBRAM and eFUSE devices
 * gdbstub related code cleanups
 * Don't put FPEXC and FPSID in org.gnu.gdb.arm.vfp XML
 * Use _init vs _new convention in bus creation function names
 * sabrelite: Connect SPI flash CS line to GPIO3_19

# gpg: Signature made Thu 30 Sep 2021 16:11:20 BST
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20210930: (22 commits)
  hw/arm: sabrelite: Connect SPI flash CS line to GPIO3_19
  ide: Rename ide_bus_new() to ide_bus_init()
  qbus: Rename qbus_create() to qbus_new()
  qbus: Rename qbus_create_inplace() to qbus_init()
  pci: Rename pci_root_bus_new_inplace() to pci_root_bus_init()
  ipack: Rename ipack_bus_new_inplace() to ipack_bus_init()
  scsi: Replace scsi_bus_new() with scsi_bus_init(), scsi_bus_init_named()
  target/arm: Don't put FPEXC and FPSID in org.gnu.gdb.arm.vfp XML
  target/arm: Move gdbstub related code out of helper.c
  target/arm: Fix coding style issues in gdbstub code in helper.c
  configs: Don't include 32-bit-only GDB XML in aarch64 linux configs
  docs/system/arm: xlnx-versal-virt: BBRAM and eFUSE Usage
  hw/arm: xlnx-zcu102: Add Xilinx eFUSE device
  hw/arm: xlnx-zcu102: Add Xilinx BBRAM device
  hw/arm: xlnx-versal-virt: Add Xilinx eFUSE device
  hw/arm: xlnx-versal-virt: Add Xilinx BBRAM device
  hw/nvram: Introduce Xilinx battery-backed ram
  hw/nvram: Introduce Xilinx ZynqMP eFuse device
  hw/nvram: Introduce Xilinx Versal eFuse device
  hw/nvram: Introduce Xilinx eFuse QOM
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-09-30 21:16:54 +01:00
commit bb4aa8f59e
108 changed files with 3806 additions and 447 deletions

View File

@ -1,5 +1,5 @@
TARGET_ARCH=aarch64
TARGET_BASE_ARCH=arm
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
TARGET_HAS_BFLT=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -1,5 +1,5 @@
TARGET_ARCH=aarch64
TARGET_BASE_ARCH=arm
TARGET_SUPPORTS_MTTCG=y
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_NEED_FDT=y

View File

@ -1,6 +1,6 @@
TARGET_ARCH=aarch64
TARGET_BASE_ARCH=arm
TARGET_WORDS_BIGENDIAN=y
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
TARGET_HAS_BFLT=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -1,6 +1,6 @@
TARGET_ARCH=arm
TARGET_SYSTBL_ABI=common,oabi
TARGET_SYSTBL=syscall.tbl
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_HAS_BFLT=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -1,4 +1,4 @@
TARGET_ARCH=arm
TARGET_SUPPORTS_MTTCG=y
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_NEED_FDT=y

View File

@ -2,6 +2,6 @@ TARGET_ARCH=arm
TARGET_SYSTBL_ABI=common,oabi
TARGET_SYSTBL=syscall.tbl
TARGET_WORDS_BIGENDIAN=y
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
TARGET_HAS_BFLT=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

View File

@ -32,6 +32,8 @@ Implemented devices:
- OCM (256KB of On Chip Memory)
- XRAM (4MB of on chip Accelerator RAM)
- DDR memory
- BBRAM (36 bytes of Battery-backed RAM)
- eFUSE (3072 bytes of one-time field-programmable bit array)
QEMU does not yet model any other devices, including the PL and the AI Engine.
@ -175,3 +177,50 @@ Run the following at the U-Boot prompt:
fdt set /chosen/dom0 reg <0x00000000 0x40000000 0x0 0x03100000>
booti 30000000 - 20000000
BBRAM File Backend
""""""""""""""""""
BBRAM can have an optional file backend, which must be a seekable
binary file with a size of 36 bytes or larger. A file with all
binary 0s is a 'blank'.
To add a file-backend for the BBRAM:
.. code-block:: bash
-drive if=pflash,index=0,file=versal-bbram.bin,format=raw
To use a different index value, N, from default of 0, add:
.. code-block:: bash
-global xlnx,bbram-ctrl.drive-index=N
eFUSE File Backend
""""""""""""""""""
eFUSE can have an optional file backend, which must be a seekable
binary file with a size of 3072 bytes or larger. A file with all
binary 0s is a 'blank'.
To add a file-backend for the eFUSE:
.. code-block:: bash
-drive if=pflash,index=1,file=versal-efuse.bin,format=raw
To use a different index value, N, from default of 1, add:
.. code-block:: bash
-global xlnx,efuse.drive-index=N
.. warning::
In actual physical Versal, BBRAM and eFUSE contain sensitive data.
The QEMU device models do **not** encrypt nor obfuscate any data
when holding them in models' memory or when writing them to their
file backends.
Thus, a file backend should be used with caution, and 'format=luks'
is highly recommended (albeit with usage complexity).
Better yet, do not use actual product data when running guest image
on this Xilinx Versal Virt board.

View File

@ -82,7 +82,5 @@
<reg name="q14" bitsize="128" type="neon_q"/>
<reg name="q15" bitsize="128" type="neon_q"/>
<reg name="fpsid" bitsize="32" type="int" group="float"/>
<reg name="fpscr" bitsize="32" type="int" group="float"/>
<reg name="fpexc" bitsize="32" type="int" group="float"/>
</feature>

View File

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2021 Linaro Ltd.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved.
These are A/R profile VFP system registers. Debugger users probably
don't really care about these, but because we used to (incorrectly)
provide them to gdb in the org.gnu.gdb.arm.vfp XML we continue
to do so via this separate XML.
-->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.qemu.gdb.arm.vfp-sysregs">
<reg name="fpsid" bitsize="32" type="int" group="float"/>
<reg name="fpexc" bitsize="32" type="int" group="float"/>
</feature>

View File

@ -23,7 +23,5 @@
<reg name="d14" bitsize="64" type="float"/>
<reg name="d15" bitsize="64" type="float"/>
<reg name="fpsid" bitsize="32" type="int" group="float"/>
<reg name="fpscr" bitsize="32" type="int" group="float"/>
<reg name="fpexc" bitsize="32" type="int" group="float"/>
</feature>

View File

@ -39,7 +39,5 @@
<reg name="d30" bitsize="64" type="float"/>
<reg name="d31" bitsize="64" type="float"/>
<reg name="fpsid" bitsize="32" type="int" group="float"/>
<reg name="fpscr" bitsize="32" type="int" group="float"/>
<reg name="fpexc" bitsize="32" type="int" group="float"/>
</feature>

View File

@ -81,3 +81,5 @@ config XLNX_ZYNQMP
select REGISTER
select CAN_BUS
select PTIMER
select XLNX_BBRAM
select XLNX_EFUSE_ZYNQMP

View File

@ -381,6 +381,8 @@ config XLNX_VERSAL
select XLNX_ZDMA
select XLNX_ZYNQMP
select OR_IRQ
select XLNX_BBRAM
select XLNX_EFUSE_VERSAL
config NPCM7XX
bool

View File

@ -237,7 +237,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
/* Provide Power State Coordination Interface */
qdev_prop_set_int32(DEVICE(&s->cpus[i]), "psci-conduit",
QEMU_PSCI_CONDUIT_HVC);
QEMU_PSCI_CONDUIT_SMC);
/* Disable secondary CPUs */
qdev_prop_set_bit(DEVICE(&s->cpus[i]), "start-powered-off",

View File

@ -87,7 +87,7 @@ static void sabrelite_init(MachineState *machine)
qdev_realize_and_unref(flash_dev, BUS(spi_bus), &error_fatal);
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
qdev_connect_gpio_out(DEVICE(&s->gpio[2]), 19, cs_line);
}
}
}

View File

@ -356,6 +356,61 @@ static void fdt_add_rtc_node(VersalVirt *s)
g_free(name);
}
static void fdt_add_bbram_node(VersalVirt *s)
{
const char compat[] = TYPE_XLNX_BBRAM;
const char interrupt_names[] = "bbram-error";
char *name = g_strdup_printf("/bbram@%x", MM_PMC_BBRAM_CTRL);
qemu_fdt_add_subnode(s->fdt, name);
qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
GIC_FDT_IRQ_TYPE_SPI, VERSAL_BBRAM_APB_IRQ_0,
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop(s->fdt, name, "interrupt-names",
interrupt_names, sizeof(interrupt_names));
qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
2, MM_PMC_BBRAM_CTRL,
2, MM_PMC_BBRAM_CTRL_SIZE);
qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
g_free(name);
}
static void fdt_add_efuse_ctrl_node(VersalVirt *s)
{
const char compat[] = TYPE_XLNX_VERSAL_EFUSE_CTRL;
const char interrupt_names[] = "pmc_efuse";
char *name = g_strdup_printf("/pmc_efuse@%x", MM_PMC_EFUSE_CTRL);
qemu_fdt_add_subnode(s->fdt, name);
qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
GIC_FDT_IRQ_TYPE_SPI, VERSAL_EFUSE_IRQ,
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop(s->fdt, name, "interrupt-names",
interrupt_names, sizeof(interrupt_names));
qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
2, MM_PMC_EFUSE_CTRL,
2, MM_PMC_EFUSE_CTRL_SIZE);
qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
g_free(name);
}
static void fdt_add_efuse_cache_node(VersalVirt *s)
{
const char compat[] = TYPE_XLNX_VERSAL_EFUSE_CACHE;
char *name = g_strdup_printf("/xlnx_pmc_efuse_cache@%x",
MM_PMC_EFUSE_CACHE);
qemu_fdt_add_subnode(s->fdt, name);
qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
2, MM_PMC_EFUSE_CACHE,
2, MM_PMC_EFUSE_CACHE_SIZE);
qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
g_free(name);
}
static void fdt_nop_memory_nodes(void *fdt, Error **errp)
{
Error *err = NULL;
@ -510,6 +565,30 @@ static void create_virtio_regions(VersalVirt *s)
}
}
static void bbram_attach_drive(XlnxBBRam *dev)
{
DriveInfo *dinfo;
BlockBackend *blk;
dinfo = drive_get_by_index(IF_PFLASH, 0);
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
if (blk) {
qdev_prop_set_drive(DEVICE(dev), "drive", blk);
}
}
static void efuse_attach_drive(XlnxEFuse *dev)
{
DriveInfo *dinfo;
BlockBackend *blk;
dinfo = drive_get_by_index(IF_PFLASH, 1);
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
if (blk) {
qdev_prop_set_drive(DEVICE(dev), "drive", blk);
}
}
static void sd_plugin_card(SDHCIState *sd, DriveInfo *di)
{
BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
@ -570,6 +649,9 @@ static void versal_virt_init(MachineState *machine)
fdt_add_usb_xhci_nodes(s);
fdt_add_sd_nodes(s);
fdt_add_rtc_node(s);
fdt_add_bbram_node(s);
fdt_add_efuse_ctrl_node(s);
fdt_add_efuse_cache_node(s);
fdt_add_cpu_nodes(s, psci_conduit);
fdt_add_clk_node(s, "/clk125", 125000000, s->phandle.clk_125Mhz);
fdt_add_clk_node(s, "/clk25", 25000000, s->phandle.clk_25Mhz);
@ -579,6 +661,12 @@ static void versal_virt_init(MachineState *machine)
memory_region_add_subregion_overlap(get_system_memory(),
0, &s->soc.fpd.apu.mr, 0);
/* Attach bbram backend, if given */
bbram_attach_drive(&s->soc.pmc.bbram);
/* Attach efuse backend, if given */
efuse_attach_drive(&s->soc.pmc.efuse);
/* Plugin SD cards. */
for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) {
sd_plugin_card(&s->soc.pmc.iou.sd[i], drive_get_next(IF_SD));

View File

@ -314,6 +314,61 @@ static void versal_create_xrams(Versal *s, qemu_irq *pic)
}
}
static void versal_create_bbram(Versal *s, qemu_irq *pic)
{
SysBusDevice *sbd;
object_initialize_child_with_props(OBJECT(s), "bbram", &s->pmc.bbram,
sizeof(s->pmc.bbram), TYPE_XLNX_BBRAM,
&error_fatal,
"crc-zpads", "0",
NULL);
sbd = SYS_BUS_DEVICE(&s->pmc.bbram);
sysbus_realize(sbd, &error_fatal);
memory_region_add_subregion(&s->mr_ps, MM_PMC_BBRAM_CTRL,
sysbus_mmio_get_region(sbd, 0));
sysbus_connect_irq(sbd, 0, pic[VERSAL_BBRAM_APB_IRQ_0]);
}
static void versal_realize_efuse_part(Versal *s, Object *dev, hwaddr base)
{
SysBusDevice *part = SYS_BUS_DEVICE(dev);
object_property_set_link(OBJECT(part), "efuse",
OBJECT(&s->pmc.efuse), &error_abort);
sysbus_realize(part, &error_abort);
memory_region_add_subregion(&s->mr_ps, base,
sysbus_mmio_get_region(part, 0));
}
static void versal_create_efuse(Versal *s, qemu_irq *pic)
{
Object *bits = OBJECT(&s->pmc.efuse);
Object *ctrl = OBJECT(&s->pmc.efuse_ctrl);
Object *cache = OBJECT(&s->pmc.efuse_cache);
object_initialize_child(OBJECT(s), "efuse-ctrl", &s->pmc.efuse_ctrl,
TYPE_XLNX_VERSAL_EFUSE_CTRL);
object_initialize_child(OBJECT(s), "efuse-cache", &s->pmc.efuse_cache,
TYPE_XLNX_VERSAL_EFUSE_CACHE);
object_initialize_child_with_props(ctrl, "xlnx-efuse@0", bits,
sizeof(s->pmc.efuse),
TYPE_XLNX_EFUSE, &error_abort,
"efuse-nr", "3",
"efuse-size", "8192",
NULL);
qdev_realize(DEVICE(bits), NULL, &error_abort);
versal_realize_efuse_part(s, ctrl, MM_PMC_EFUSE_CTRL);
versal_realize_efuse_part(s, cache, MM_PMC_EFUSE_CACHE);
sysbus_connect_irq(SYS_BUS_DEVICE(ctrl), 0, pic[VERSAL_EFUSE_IRQ]);
}
/* This takes the board allocated linear DDR memory and creates aliases
* for each split DDR range/aperture on the Versal address map.
*/
@ -402,6 +457,8 @@ static void versal_realize(DeviceState *dev, Error **errp)
versal_create_sds(s, pic);
versal_create_rtc(s, pic);
versal_create_xrams(s, pic);
versal_create_bbram(s, pic);
versal_create_efuse(s, pic);
versal_map_ddr(s);
versal_unimp(s);

View File

@ -98,6 +98,30 @@ static void zcu102_modify_dtb(const struct arm_boot_info *binfo, void *fdt)
}
}
static void bbram_attach_drive(XlnxBBRam *dev)
{
DriveInfo *dinfo;
BlockBackend *blk;
dinfo = drive_get_by_index(IF_PFLASH, 2);
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
if (blk) {
qdev_prop_set_drive(DEVICE(dev), "drive", blk);
}
}
static void efuse_attach_drive(XlnxEFuse *dev)
{
DriveInfo *dinfo;
BlockBackend *blk;
dinfo = drive_get_by_index(IF_PFLASH, 3);
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
if (blk) {
qdev_prop_set_drive(DEVICE(dev), "drive", blk);
}
}
static void xlnx_zcu102_init(MachineState *machine)
{
XlnxZCU102 *s = ZCU102_MACHINE(machine);
@ -136,6 +160,12 @@ static void xlnx_zcu102_init(MachineState *machine)
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
/* Attach bbram backend, if given */
bbram_attach_drive(&s->soc.bbram);
/* Attach efuse backend, if given */
efuse_attach_drive(&s->soc.efuse);
/* Create and plug in the SD cards */
for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
BusState *bus;

View File

@ -66,6 +66,12 @@
#define RTC_ADDR 0xffa60000
#define RTC_IRQ 26
#define BBRAM_ADDR 0xffcd0000
#define BBRAM_IRQ 11
#define EFUSE_ADDR 0xffcc0000
#define EFUSE_IRQ 87
#define SDHCI_CAPABILITIES 0x280737ec6481 /* Datasheet: UG1085 (v1.7) */
static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
@ -226,6 +232,47 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
qdev_realize(DEVICE(&s->rpu_cluster), NULL, &error_fatal);
}
static void xlnx_zynqmp_create_bbram(XlnxZynqMPState *s, qemu_irq *gic)
{
SysBusDevice *sbd;
object_initialize_child_with_props(OBJECT(s), "bbram", &s->bbram,
sizeof(s->bbram), TYPE_XLNX_BBRAM,
&error_fatal,
"crc-zpads", "1",
NULL);
sbd = SYS_BUS_DEVICE(&s->bbram);
sysbus_realize(sbd, &error_fatal);
sysbus_mmio_map(sbd, 0, BBRAM_ADDR);
sysbus_connect_irq(sbd, 0, gic[BBRAM_IRQ]);
}
static void xlnx_zynqmp_create_efuse(XlnxZynqMPState *s, qemu_irq *gic)
{
Object *bits = OBJECT(&s->efuse);
Object *ctrl = OBJECT(&s->efuse_ctrl);
SysBusDevice *sbd;
object_initialize_child(OBJECT(s), "efuse-ctrl", &s->efuse_ctrl,
TYPE_XLNX_ZYNQMP_EFUSE);
object_initialize_child_with_props(ctrl, "xlnx-efuse@0", bits,
sizeof(s->efuse),
TYPE_XLNX_EFUSE, &error_abort,
"efuse-nr", "3",
"efuse-size", "2048",
NULL);
qdev_realize(DEVICE(bits), NULL, &error_abort);
object_property_set_link(ctrl, "efuse", bits, &error_abort);
sbd = SYS_BUS_DEVICE(ctrl);
sysbus_realize(sbd, &error_abort);
sysbus_mmio_map(sbd, 0, EFUSE_ADDR);
sysbus_connect_irq(sbd, 0, gic[EFUSE_IRQ]);
}
static void xlnx_zynqmp_create_unimp_mmio(XlnxZynqMPState *s)
{
static const struct UnimpInfo {
@ -626,6 +673,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, RTC_ADDR);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, gic_spi[RTC_IRQ]);
xlnx_zynqmp_create_bbram(s, gic_spi);
xlnx_zynqmp_create_efuse(s, gic_spi);
xlnx_zynqmp_create_unimp_mmio(s);
for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) {

View File

@ -52,7 +52,7 @@ void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size,
hda_codec_response_func response,
hda_codec_xfer_func xfer)
{
qbus_create_inplace(bus, bus_size, TYPE_HDA_BUS, dev, NULL);
qbus_init(bus, bus_size, TYPE_HDA_BUS, dev, NULL);
bus->response = response;
bus->xfer = xfer;
}

View File

@ -77,7 +77,7 @@ static const TypeInfo floppy_bus_info = {
static void floppy_bus_create(FDCtrl *fdc, FloppyBus *bus, DeviceState *dev)
{
qbus_create_inplace(bus, sizeof(FloppyBus), TYPE_FLOPPY_BUS, dev, NULL);
qbus_init(bus, sizeof(FloppyBus), TYPE_FLOPPY_BUS, dev, NULL);
bus->fdc = fdc;
}

View File

@ -421,8 +421,7 @@ static void sysbus_swim_realize(DeviceState *dev, Error **errp)
Swim *sys = SWIM(dev);
SWIMCtrl *swimctrl = &sys->ctrl;
qbus_create_inplace(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev,
NULL);
qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL);
swimctrl->bus.ctrl = swimctrl;
}

View File

@ -1048,8 +1048,8 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
config_size);
/* Spawn a new virtio-serial bus on which the ports will ride as devices */
qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
dev, vdev->bus_name);
qbus_init(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
dev, vdev->bus_name);
qbus_set_hotplug_handler(BUS(&vser->bus), OBJECT(vser));
vser->bus.vser = vser;
QTAILQ_INIT(&vser->ports);

View File

@ -99,7 +99,8 @@ static void bus_reset_child_foreach(Object *obj, ResettableChildCallback cb,
}
}
static void qbus_init(BusState *bus, DeviceState *parent, const char *name)
static void qbus_init_internal(BusState *bus, DeviceState *parent,
const char *name)
{
const char *typename = object_get_typename(OBJECT(bus));
BusClass *bc;
@ -151,19 +152,19 @@ static void bus_unparent(Object *obj)
bus->parent = NULL;
}
void qbus_create_inplace(void *bus, size_t size, const char *typename,
DeviceState *parent, const char *name)
void qbus_init(void *bus, size_t size, const char *typename,
DeviceState *parent, const char *name)
{
object_initialize(bus, size, typename);
qbus_init(bus, parent, name);
qbus_init_internal(bus, parent, name);
}
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
BusState *qbus_new(const char *typename, DeviceState *parent, const char *name)
{
BusState *bus;
bus = BUS(object_new(typename));
qbus_init(bus, parent, name);
qbus_init_internal(bus, parent, name);
return bus;
}

View File

@ -340,11 +340,13 @@ static BusState *main_system_bus;
static void main_system_bus_create(void)
{
/* assign main_system_bus before qbus_create_inplace()
* in order to make "if (bus != sysbus_get_default())" work */
/*
* assign main_system_bus before qbus_init()
* in order to make "if (bus != sysbus_get_default())" work
*/
main_system_bus = g_malloc0(system_bus_info.instance_size);
qbus_create_inplace(main_system_bus, system_bus_info.instance_size,
TYPE_SYSTEM_BUS, NULL, "main-system-bus");
qbus_init(main_system_bus, system_bus_info.instance_size,
TYPE_SYSTEM_BUS, NULL, "main-system-bus");
OBJECT(main_system_bus)->free = g_free;
}

View File

@ -299,8 +299,7 @@ static void bcm2835_gpio_init(Object *obj)
DeviceState *dev = DEVICE(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
TYPE_SD_BUS, DEVICE(s), "sd-bus");
qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(s), "sd-bus");
memory_region_init_io(&s->iomem, obj,
&bcm2835_gpio_ops, s, "bcm2835_gpio", 0x1000);

View File

@ -2729,7 +2729,7 @@ static void vmbus_bridge_realize(DeviceState *dev, Error **errp)
return;
}
bridge->bus = VMBUS(qbus_create(TYPE_VMBUS, dev, "vmbus"));
bridge->bus = VMBUS(qbus_new(TYPE_VMBUS, dev, "vmbus"));
}
static char *vmbus_bridge_ofw_unit_address(const SysBusDevice *dev)

View File

@ -60,7 +60,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name)
{
I2CBus *bus;
bus = I2C_BUS(qbus_create(TYPE_I2C_BUS, parent, name));
bus = I2C_BUS(qbus_new(TYPE_I2C_BUS, parent, name));
QLIST_INIT(&bus->current_devs);
vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus);
return bus;

View File

@ -1548,7 +1548,7 @@ void ahci_realize(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
for (i = 0; i < s->ports; i++) {
AHCIDevice *ad = &s->dev[i];
ide_bus_new(&ad->port, sizeof(ad->port), qdev, i, 1);
ide_bus_init(&ad->port, sizeof(ad->port), qdev, i, 1);
ide_init2(&ad->port, irqs[i]);
ad->hba = s;

View File

@ -293,7 +293,7 @@ static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp)
qdev_init_gpio_in(ds, cmd646_set_irq, 2);
for (i = 0; i < 2; i++) {
ide_bus_new(&d->bus[i], sizeof(d->bus[i]), ds, i, 2);
ide_bus_init(&d->bus[i], sizeof(d->bus[i]), ds, i, 2);
ide_init2(&d->bus[i], qdev_get_gpio_in(ds, i));
bmdma_init(&d->bus[i], &d->bmdma[i], d);

View File

@ -73,7 +73,7 @@ static void isa_ide_realizefn(DeviceState *dev, Error **errp)
ISADevice *isadev = ISA_DEVICE(dev);
ISAIDEState *s = ISA_IDE(dev);
ide_bus_new(&s->bus, sizeof(s->bus), dev, 0, 2);
ide_bus_init(&s->bus, sizeof(s->bus), dev, 0, 2);
ide_init_ioport(&s->bus, isadev, s->iobase, s->iobase2);
isa_init_irq(isadev, &s->irq, s->isairq);
ide_init2(&s->bus, s->irq);

View File

@ -449,7 +449,7 @@ static void macio_ide_initfn(Object *obj)
SysBusDevice *d = SYS_BUS_DEVICE(obj);
MACIOIDEState *s = MACIO_IDE(obj);
ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
ide_bus_init(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000);
sysbus_init_mmio(d, &s->mem);
sysbus_init_irq(d, &s->real_ide_irq);

View File

@ -605,7 +605,7 @@ static void microdrive_init(Object *obj)
{
MicroDriveState *md = MICRODRIVE(obj);
ide_bus_new(&md->bus, sizeof(md->bus), DEVICE(obj), 0, 1);
ide_bus_init(&md->bus, sizeof(md->bus), DEVICE(obj), 0, 1);
}
static void microdrive_class_init(ObjectClass *oc, void *data)

View File

@ -142,7 +142,7 @@ static void mmio_ide_initfn(Object *obj)
SysBusDevice *d = SYS_BUS_DEVICE(obj);
MMIOState *s = MMIO_IDE(obj);
ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
ide_bus_init(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
sysbus_init_irq(d, &s->irq);
}

View File

@ -137,7 +137,7 @@ static int pci_piix_init_ports(PCIIDEState *d)
int i, ret;
for (i = 0; i < 2; i++) {
ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
ide_bus_init(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
ret = ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
port_info[i].iobase2);
if (ret) {

View File

@ -68,10 +68,10 @@ static const TypeInfo ide_bus_info = {
.class_init = ide_bus_class_init,
};
void ide_bus_new(IDEBus *idebus, size_t idebus_size, DeviceState *dev,
void ide_bus_init(IDEBus *idebus, size_t idebus_size, DeviceState *dev,
int bus_id, int max_units)
{
qbus_create_inplace(idebus, idebus_size, TYPE_IDE_BUS, dev, NULL);
qbus_init(idebus, idebus_size, TYPE_IDE_BUS, dev, NULL);
idebus->bus_id = bus_id;
idebus->max_units = max_units;
}

View File

@ -283,7 +283,7 @@ static void sii3112_pci_realize(PCIDevice *dev, Error **errp)
qdev_init_gpio_in(ds, sii3112_set_irq, 2);
for (i = 0; i < 2; i++) {
ide_bus_new(&s->bus[i], sizeof(s->bus[i]), ds, i, 1);
ide_bus_init(&s->bus[i], sizeof(s->bus[i]), ds, i, 1);
ide_init2(&s->bus[i], qdev_get_gpio_in(ds, i));
bmdma_init(&s->bus[i], &s->bmdma[i], s);

View File

@ -190,7 +190,7 @@ static void via_ide_realize(PCIDevice *dev, Error **errp)
qdev_init_gpio_in(ds, via_ide_set_irq, 2);
for (i = 0; i < 2; i++) {
ide_bus_new(&d->bus[i], sizeof(d->bus[i]), ds, i, 2);
ide_bus_init(&d->bus[i], sizeof(d->bus[i]), ds, i, 2);
ide_init2(&d->bus[i], qdev_get_gpio_in(ds, i));
bmdma_init(&d->bus[i], &d->bmdma[i], d);

View File

@ -30,12 +30,12 @@ IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot)
return NULL;
}
void ipack_bus_new_inplace(IPackBus *bus, size_t bus_size,
DeviceState *parent,
const char *name, uint8_t n_slots,
qemu_irq_handler handler)
void ipack_bus_init(IPackBus *bus, size_t bus_size,
DeviceState *parent,
uint8_t n_slots,
qemu_irq_handler handler)
{
qbus_create_inplace(bus, bus_size, TYPE_IPACK_BUS, parent, name);
qbus_init(bus, bus_size, TYPE_IPACK_BUS, parent, NULL);
bus->n_slots = n_slots;
bus->set_irq = handler;
}

View File

@ -611,8 +611,8 @@ static void tpci200_realize(PCIDevice *pci_dev, Error **errp)
pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las2);
pci_register_bar(&s->dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las3);
ipack_bus_new_inplace(&s->bus, sizeof(s->bus), DEVICE(pci_dev), NULL,
N_MODULES, tpci200_set_irq);
ipack_bus_init(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
N_MODULES, tpci200_set_irq);
}
static const VMStateDescription vmstate_tpci200 = {

View File

@ -64,7 +64,7 @@ ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space,
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
}
isabus = ISA_BUS(qbus_create(TYPE_ISA_BUS, dev, NULL));
isabus = ISA_BUS(qbus_new(TYPE_ISA_BUS, dev, NULL));
isabus->address_space = address_space;
isabus->address_space_io = address_space_io;
return isabus;

View File

@ -65,7 +65,7 @@ AUXBus *aux_bus_init(DeviceState *parent, const char *name)
AUXBus *bus;
Object *auxtoi2c;
bus = AUX_BUS(qbus_create(TYPE_AUX_BUS, parent, name));
bus = AUX_BUS(qbus_new(TYPE_AUX_BUS, parent, name));
auxtoi2c = object_new_with_props(TYPE_AUXTOI2C, OBJECT(bus), "i2c",
&error_abort, NULL);

View File

@ -1038,8 +1038,8 @@ static void mos6522_q800_via1_init(Object *obj)
sysbus_init_mmio(sbd, &v1s->via_mem);
/* ADB */
qbus_create_inplace((BusState *)&v1s->adb_bus, sizeof(v1s->adb_bus),
TYPE_ADB_BUS, DEVICE(v1s), "adb.0");
qbus_init((BusState *)&v1s->adb_bus, sizeof(v1s->adb_bus),
TYPE_ADB_BUS, DEVICE(v1s), "adb.0");
qdev_init_gpio_in(DEVICE(obj), via1_irq_request, VIA1_IRQ_NB);
}

View File

@ -553,8 +553,8 @@ static void cuda_init(Object *obj)
memory_region_init_io(&s->mem, obj, &mos6522_cuda_ops, s, "cuda", 0x2000);
sysbus_init_mmio(sbd, &s->mem);
qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
DEVICE(obj), "adb.0");
qbus_init(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
DEVICE(obj), "adb.0");
}
static Property cuda_properties[] = {

View File

@ -387,8 +387,8 @@ static void macio_instance_init(Object *obj)
memory_region_init(&s->bar, obj, "macio", 0x80000);
qbus_create_inplace(&s->macio_bus, sizeof(s->macio_bus), TYPE_MACIO_BUS,
DEVICE(obj), "macio.0");
qbus_init(&s->macio_bus, sizeof(s->macio_bus), TYPE_MACIO_BUS,
DEVICE(obj), "macio.0");
object_initialize_child(OBJECT(s), "dbdma", &s->dbdma, TYPE_MAC_DBDMA);

View File

@ -754,8 +754,8 @@ static void pmu_realize(DeviceState *dev, Error **errp)
timer_mod(s->one_sec_timer, s->one_sec_target);
if (s->has_adb) {
qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
dev, "adb.0");
qbus_init(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
dev, "adb.0");
adb_register_autopoll_callback(adb_bus, pmu_adb_poll, s);
}
}

View File

@ -18,7 +18,7 @@ static void nubus_bridge_init(Object *obj)
NubusBridge *s = NUBUS_BRIDGE(obj);
NubusBus *bus = &s->bus;
qbus_create_inplace(bus, sizeof(s->bus), TYPE_NUBUS_BUS, DEVICE(s), NULL);
qbus_init(bus, sizeof(s->bus), TYPE_NUBUS_BUS, DEVICE(s), NULL);
qdev_init_gpio_out(DEVICE(s), bus->irqs, NUBUS_IRQS);
}

View File

@ -6539,8 +6539,8 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
return;
}
qbus_create_inplace(&n->bus, sizeof(NvmeBus), TYPE_NVME_BUS,
&pci_dev->qdev, n->parent_obj.qdev.id);
qbus_init(&n->bus, sizeof(NvmeBus), TYPE_NVME_BUS,
&pci_dev->qdev, n->parent_obj.qdev.id);
nvme_init_state(n);
if (nvme_init_pci(n, pci_dev, errp)) {

View File

@ -50,8 +50,7 @@ static void nvme_subsys_realize(DeviceState *dev, Error **errp)
{
NvmeSubsystem *subsys = NVME_SUBSYS(dev);
qbus_create_inplace(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev,
dev->id);
qbus_init(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id);
nvme_subsys_setup(subsys);
}

View File

@ -15,3 +15,22 @@ config NMC93XX_EEPROM
config CHRP_NVRAM
bool
config XLNX_EFUSE_CRC
bool
config XLNX_EFUSE
bool
select XLNX_EFUSE_CRC
config XLNX_EFUSE_VERSAL
bool
select XLNX_EFUSE
config XLNX_EFUSE_ZYNQMP
bool
select XLNX_EFUSE
config XLNX_BBRAM
bool
select XLNX_EFUSE_CRC

View File

@ -9,5 +9,13 @@ softmmu_ss.add(when: 'CONFIG_AT24C', if_true: files('eeprom_at24c.c'))
softmmu_ss.add(when: 'CONFIG_MAC_NVRAM', if_true: files('mac_nvram.c'))
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_otp.c'))
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_nvm.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_EFUSE_CRC', if_true: files('xlnx-efuse-crc.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_EFUSE', if_true: files('xlnx-efuse.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_EFUSE_VERSAL', if_true: files(
'xlnx-versal-efuse-cache.c',
'xlnx-versal-efuse-ctrl.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_EFUSE_ZYNQMP', if_true: files(
'xlnx-zynqmp-efuse.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_BBRAM', if_true: files('xlnx-bbram.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_nvram.c'))

545
hw/nvram/xlnx-bbram.c Normal file
View File

@ -0,0 +1,545 @@
/*
* QEMU model of the Xilinx BBRAM Battery Backed RAM
*
* Copyright (c) 2014-2021 Xilinx Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/nvram/xlnx-bbram.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "sysemu/blockdev.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/nvram/xlnx-efuse.h"
#ifndef XLNX_BBRAM_ERR_DEBUG
#define XLNX_BBRAM_ERR_DEBUG 0
#endif
REG32(BBRAM_STATUS, 0x0)
FIELD(BBRAM_STATUS, AES_CRC_PASS, 9, 1)
FIELD(BBRAM_STATUS, AES_CRC_DONE, 8, 1)
FIELD(BBRAM_STATUS, BBRAM_ZEROIZED, 4, 1)
FIELD(BBRAM_STATUS, PGM_MODE, 0, 1)
REG32(BBRAM_CTRL, 0x4)
FIELD(BBRAM_CTRL, ZEROIZE, 0, 1)
REG32(PGM_MODE, 0x8)
REG32(BBRAM_AES_CRC, 0xc)
REG32(BBRAM_0, 0x10)
REG32(BBRAM_1, 0x14)
REG32(BBRAM_2, 0x18)
REG32(BBRAM_3, 0x1c)
REG32(BBRAM_4, 0x20)
REG32(BBRAM_5, 0x24)
REG32(BBRAM_6, 0x28)
REG32(BBRAM_7, 0x2c)
REG32(BBRAM_8, 0x30)
REG32(BBRAM_SLVERR, 0x34)
FIELD(BBRAM_SLVERR, ENABLE, 0, 1)
REG32(BBRAM_ISR, 0x38)
FIELD(BBRAM_ISR, APB_SLVERR, 0, 1)
REG32(BBRAM_IMR, 0x3c)
FIELD(BBRAM_IMR, APB_SLVERR, 0, 1)
REG32(BBRAM_IER, 0x40)
FIELD(BBRAM_IER, APB_SLVERR, 0, 1)
REG32(BBRAM_IDR, 0x44)
FIELD(BBRAM_IDR, APB_SLVERR, 0, 1)
REG32(BBRAM_MSW_LOCK, 0x4c)
FIELD(BBRAM_MSW_LOCK, VAL, 0, 1)
#define R_MAX (R_BBRAM_MSW_LOCK + 1)
#define RAM_MAX (A_BBRAM_8 + 4 - A_BBRAM_0)
#define BBRAM_PGM_MAGIC 0x757bdf0d
QEMU_BUILD_BUG_ON(R_MAX != ARRAY_SIZE(((XlnxBBRam *)0)->regs));
static bool bbram_msw_locked(XlnxBBRam *s)
{
return ARRAY_FIELD_EX32(s->regs, BBRAM_MSW_LOCK, VAL) != 0;
}
static bool bbram_pgm_enabled(XlnxBBRam *s)
{
return ARRAY_FIELD_EX32(s->regs, BBRAM_STATUS, PGM_MODE) != 0;
}
static void bbram_bdrv_error(XlnxBBRam *s, int rc, gchar *detail)
{
Error *errp;
error_setg_errno(&errp, -rc, "%s: BBRAM backstore %s failed.",
blk_name(s->blk), detail);
error_report("%s", error_get_pretty(errp));
error_free(errp);
g_free(detail);
}
static void bbram_bdrv_read(XlnxBBRam *s, Error **errp)
{
uint32_t *ram = &s->regs[R_BBRAM_0];
int nr = RAM_MAX;
if (!s->blk) {
return;
}
s->blk_ro = !blk_supports_write_perm(s->blk);
if (!s->blk_ro) {
int rc;
rc = blk_set_perm(s->blk,
(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE),
BLK_PERM_ALL, NULL);
if (rc) {
s->blk_ro = true;
}
}
if (s->blk_ro) {
warn_report("%s: Skip saving updates to read-only BBRAM backstore.",
blk_name(s->blk));
}
if (blk_pread(s->blk, 0, ram, nr) < 0) {
error_setg(errp,
"%s: Failed to read %u bytes from BBRAM backstore.",
blk_name(s->blk), nr);
return;
}
/* Convert from little-endian backstore for each 32-bit word */
nr /= 4;
while (nr--) {
ram[nr] = le32_to_cpu(ram[nr]);
}
}
static void bbram_bdrv_sync(XlnxBBRam *s, uint64_t hwaddr)
{
uint32_t le32;
unsigned offset;
int rc;
assert(A_BBRAM_0 <= hwaddr && hwaddr <= A_BBRAM_8);
/* Backstore is always in little-endian */
le32 = cpu_to_le32(s->regs[hwaddr / 4]);
/* Update zeroized flag */
if (le32 && (hwaddr != A_BBRAM_8 || s->bbram8_wo)) {
ARRAY_FIELD_DP32(s->regs, BBRAM_STATUS, BBRAM_ZEROIZED, 0);
}
if (!s->blk || s->blk_ro) {
return;
}
offset = hwaddr - A_BBRAM_0;
rc = blk_pwrite(s->blk, offset, &le32, 4, 0);
if (rc < 0) {
bbram_bdrv_error(s, rc, g_strdup_printf("write to offset %u", offset));
}
}
static void bbram_bdrv_zero(XlnxBBRam *s)
{
int rc;
ARRAY_FIELD_DP32(s->regs, BBRAM_STATUS, BBRAM_ZEROIZED, 1);
if (!s->blk || s->blk_ro) {
return;
}
rc = blk_make_zero(s->blk, 0);
if (rc < 0) {
bbram_bdrv_error(s, rc, g_strdup("zeroizing"));
}
/* Restore bbram8 if it is non-zero */
if (s->regs[R_BBRAM_8]) {
bbram_bdrv_sync(s, A_BBRAM_8);
}
}
static void bbram_zeroize(XlnxBBRam *s)
{
int nr = RAM_MAX - (s->bbram8_wo ? 0 : 4); /* only wo bbram8 is cleared */
memset(&s->regs[R_BBRAM_0], 0, nr);
bbram_bdrv_zero(s);
}
static void bbram_update_irq(XlnxBBRam *s)
{
bool pending = s->regs[R_BBRAM_ISR] & ~s->regs[R_BBRAM_IMR];
qemu_set_irq(s->irq_bbram, pending);
}
static void bbram_ctrl_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
uint32_t val = val64;
if (val & R_BBRAM_CTRL_ZEROIZE_MASK) {
bbram_zeroize(s);
/* The bit is self clearing */
s->regs[R_BBRAM_CTRL] &= ~R_BBRAM_CTRL_ZEROIZE_MASK;
}
}
static void bbram_pgm_mode_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
uint32_t val = val64;
if (val == BBRAM_PGM_MAGIC) {
bbram_zeroize(s);
/* The status bit is cleared only by POR */
ARRAY_FIELD_DP32(s->regs, BBRAM_STATUS, PGM_MODE, 1);
}
}
static void bbram_aes_crc_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
uint32_t calc_crc;
if (!bbram_pgm_enabled(s)) {
/* We are not in programming mode, don't do anything */
return;
}
/* Perform the AES integrity check */
s->regs[R_BBRAM_STATUS] |= R_BBRAM_STATUS_AES_CRC_DONE_MASK;
/*
* Set check status.
*
* ZynqMP BBRAM check has a zero-u32 prepended; see:
* https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilskey/src/xilskey_bbramps_zynqmp.c#L311
*/
calc_crc = xlnx_efuse_calc_crc(&s->regs[R_BBRAM_0],
(R_BBRAM_8 - R_BBRAM_0), s->crc_zpads);
ARRAY_FIELD_DP32(s->regs, BBRAM_STATUS, AES_CRC_PASS,
(s->regs[R_BBRAM_AES_CRC] == calc_crc));
}
static uint64_t bbram_key_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
uint32_t original_data = *(uint32_t *) reg->data;
if (bbram_pgm_enabled(s)) {
return val64;
} else {
/* We are not in programming mode, don't do anything */
qemu_log_mask(LOG_GUEST_ERROR,
"Not in programming mode, dropping the write\n");
return original_data;
}
}
static void bbram_key_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
bbram_bdrv_sync(s, reg->access->addr);
}
static uint64_t bbram_wo_postr(RegisterInfo *reg, uint64_t val)
{
return 0;
}
static uint64_t bbram_r8_postr(RegisterInfo *reg, uint64_t val)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
return s->bbram8_wo ? bbram_wo_postr(reg, val) : val;
}
static bool bbram_r8_readonly(XlnxBBRam *s)
{
return !bbram_pgm_enabled(s) || bbram_msw_locked(s);
}
static uint64_t bbram_r8_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
if (bbram_r8_readonly(s)) {
val64 = *(uint32_t *)reg->data;
}
return val64;
}
static void bbram_r8_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
if (!bbram_r8_readonly(s)) {
bbram_bdrv_sync(s, A_BBRAM_8);
}
}
static uint64_t bbram_msw_lock_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
/* Never lock if bbram8 is wo; and, only POR can clear the lock */
if (s->bbram8_wo) {
val64 = 0;
} else {
val64 |= s->regs[R_BBRAM_MSW_LOCK];
}
return val64;
}
static void bbram_isr_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
bbram_update_irq(s);
}
static uint64_t bbram_ier_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
uint32_t val = val64;
s->regs[R_BBRAM_IMR] &= ~val;
bbram_update_irq(s);
return 0;
}
static uint64_t bbram_idr_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxBBRam *s = XLNX_BBRAM(reg->opaque);
uint32_t val = val64;
s->regs[R_BBRAM_IMR] |= val;
bbram_update_irq(s);
return 0;
}
static RegisterAccessInfo bbram_ctrl_regs_info[] = {
{ .name = "BBRAM_STATUS", .addr = A_BBRAM_STATUS,
.rsvd = 0xee,
.ro = 0x3ff,
},{ .name = "BBRAM_CTRL", .addr = A_BBRAM_CTRL,
.post_write = bbram_ctrl_postw,
},{ .name = "PGM_MODE", .addr = A_PGM_MODE,
.post_write = bbram_pgm_mode_postw,
},{ .name = "BBRAM_AES_CRC", .addr = A_BBRAM_AES_CRC,
.post_write = bbram_aes_crc_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_0", .addr = A_BBRAM_0,
.pre_write = bbram_key_prew,
.post_write = bbram_key_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_1", .addr = A_BBRAM_1,
.pre_write = bbram_key_prew,
.post_write = bbram_key_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_2", .addr = A_BBRAM_2,
.pre_write = bbram_key_prew,
.post_write = bbram_key_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_3", .addr = A_BBRAM_3,
.pre_write = bbram_key_prew,
.post_write = bbram_key_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_4", .addr = A_BBRAM_4,
.pre_write = bbram_key_prew,
.post_write = bbram_key_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_5", .addr = A_BBRAM_5,
.pre_write = bbram_key_prew,
.post_write = bbram_key_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_6", .addr = A_BBRAM_6,
.pre_write = bbram_key_prew,
.post_write = bbram_key_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_7", .addr = A_BBRAM_7,
.pre_write = bbram_key_prew,
.post_write = bbram_key_postw,
.post_read = bbram_wo_postr,
},{ .name = "BBRAM_8", .addr = A_BBRAM_8,
.pre_write = bbram_r8_prew,
.post_write = bbram_r8_postw,
.post_read = bbram_r8_postr,
},{ .name = "BBRAM_SLVERR", .addr = A_BBRAM_SLVERR,
.rsvd = ~1,
},{ .name = "BBRAM_ISR", .addr = A_BBRAM_ISR,
.w1c = 0x1,
.post_write = bbram_isr_postw,
},{ .name = "BBRAM_IMR", .addr = A_BBRAM_IMR,
.ro = 0x1,
},{ .name = "BBRAM_IER", .addr = A_BBRAM_IER,
.pre_write = bbram_ier_prew,
},{ .name = "BBRAM_IDR", .addr = A_BBRAM_IDR,
.pre_write = bbram_idr_prew,
},{ .name = "BBRAM_MSW_LOCK", .addr = A_BBRAM_MSW_LOCK,
.pre_write = bbram_msw_lock_prew,
.ro = ~R_BBRAM_MSW_LOCK_VAL_MASK,
}
};
static void bbram_ctrl_reset(DeviceState *dev)
{
XlnxBBRam *s = XLNX_BBRAM(dev);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
if (i < R_BBRAM_0 || i > R_BBRAM_8) {
register_reset(&s->regs_info[i]);
}
}
bbram_update_irq(s);
}
static const MemoryRegionOps bbram_ctrl_ops = {
.read = register_read_memory,
.write = register_write_memory,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void bbram_ctrl_realize(DeviceState *dev, Error **errp)
{
XlnxBBRam *s = XLNX_BBRAM(dev);
if (s->crc_zpads) {
s->bbram8_wo = true;
}
bbram_bdrv_read(s, errp);
}
static void bbram_ctrl_init(Object *obj)
{
XlnxBBRam *s = XLNX_BBRAM(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
RegisterInfoArray *reg_array;
reg_array =
register_init_block32(DEVICE(obj), bbram_ctrl_regs_info,
ARRAY_SIZE(bbram_ctrl_regs_info),
s->regs_info, s->regs,
&bbram_ctrl_ops,
XLNX_BBRAM_ERR_DEBUG,
R_MAX * 4);
sysbus_init_mmio(sbd, &reg_array->mem);
sysbus_init_irq(sbd, &s->irq_bbram);
}
static void bbram_prop_set_drive(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
qdev_prop_drive.set(obj, v, name, opaque, errp);
/* Fill initial data if backend is attached after realized */
if (dev->realized) {
bbram_bdrv_read(XLNX_BBRAM(obj), errp);
}
}
static void bbram_prop_get_drive(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
qdev_prop_drive.get(obj, v, name, opaque, errp);
}
static void bbram_prop_release_drive(Object *obj, const char *name,
void *opaque)
{
qdev_prop_drive.release(obj, name, opaque);
}
static const PropertyInfo bbram_prop_drive = {
.name = "str",
.description = "Node name or ID of a block device to use as BBRAM backend",
.realized_set_allowed = true,
.get = bbram_prop_get_drive,
.set = bbram_prop_set_drive,
.release = bbram_prop_release_drive,
};
static const VMStateDescription vmstate_bbram_ctrl = {
.name = TYPE_XLNX_BBRAM,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, XlnxBBRam, R_MAX),
VMSTATE_END_OF_LIST(),
}
};
static Property bbram_ctrl_props[] = {
DEFINE_PROP("drive", XlnxBBRam, blk, bbram_prop_drive, BlockBackend *),
DEFINE_PROP_UINT32("crc-zpads", XlnxBBRam, crc_zpads, 1),
DEFINE_PROP_END_OF_LIST(),
};
static void bbram_ctrl_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = bbram_ctrl_reset;
dc->realize = bbram_ctrl_realize;
dc->vmsd = &vmstate_bbram_ctrl;
device_class_set_props(dc, bbram_ctrl_props);
}
static const TypeInfo bbram_ctrl_info = {
.name = TYPE_XLNX_BBRAM,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(XlnxBBRam),
.class_init = bbram_ctrl_class_init,
.instance_init = bbram_ctrl_init,
};
static void bbram_ctrl_register_types(void)
{
type_register_static(&bbram_ctrl_info);
}
type_init(bbram_ctrl_register_types)

119
hw/nvram/xlnx-efuse-crc.c Normal file
View File

@ -0,0 +1,119 @@
/*
* Xilinx eFuse/bbram CRC calculator
*
* Copyright (c) 2021 Xilinx Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/nvram/xlnx-efuse.h"
static uint32_t xlnx_efuse_u37_crc(uint32_t prev_crc, uint32_t data,
uint32_t addr)
{
/* A table for 7-bit slicing */
static const uint32_t crc_tab[128] = {
0x00000000, 0xe13b70f7, 0xc79a971f, 0x26a1e7e8,
0x8ad958cf, 0x6be22838, 0x4d43cfd0, 0xac78bf27,
0x105ec76f, 0xf165b798, 0xd7c45070, 0x36ff2087,
0x9a879fa0, 0x7bbcef57, 0x5d1d08bf, 0xbc267848,
0x20bd8ede, 0xc186fe29, 0xe72719c1, 0x061c6936,
0xaa64d611, 0x4b5fa6e6, 0x6dfe410e, 0x8cc531f9,
0x30e349b1, 0xd1d83946, 0xf779deae, 0x1642ae59,
0xba3a117e, 0x5b016189, 0x7da08661, 0x9c9bf696,
0x417b1dbc, 0xa0406d4b, 0x86e18aa3, 0x67dafa54,
0xcba24573, 0x2a993584, 0x0c38d26c, 0xed03a29b,
0x5125dad3, 0xb01eaa24, 0x96bf4dcc, 0x77843d3b,
0xdbfc821c, 0x3ac7f2eb, 0x1c661503, 0xfd5d65f4,
0x61c69362, 0x80fde395, 0xa65c047d, 0x4767748a,
0xeb1fcbad, 0x0a24bb5a, 0x2c855cb2, 0xcdbe2c45,
0x7198540d, 0x90a324fa, 0xb602c312, 0x5739b3e5,
0xfb410cc2, 0x1a7a7c35, 0x3cdb9bdd, 0xdde0eb2a,
0x82f63b78, 0x63cd4b8f, 0x456cac67, 0xa457dc90,
0x082f63b7, 0xe9141340, 0xcfb5f4a8, 0x2e8e845f,
0x92a8fc17, 0x73938ce0, 0x55326b08, 0xb4091bff,
0x1871a4d8, 0xf94ad42f, 0xdfeb33c7, 0x3ed04330,
0xa24bb5a6, 0x4370c551, 0x65d122b9, 0x84ea524e,
0x2892ed69, 0xc9a99d9e, 0xef087a76, 0x0e330a81,
0xb21572c9, 0x532e023e, 0x758fe5d6, 0x94b49521,
0x38cc2a06, 0xd9f75af1, 0xff56bd19, 0x1e6dcdee,
0xc38d26c4, 0x22b65633, 0x0417b1db, 0xe52cc12c,
0x49547e0b, 0xa86f0efc, 0x8ecee914, 0x6ff599e3,
0xd3d3e1ab, 0x32e8915c, 0x144976b4, 0xf5720643,
0x590ab964, 0xb831c993, 0x9e902e7b, 0x7fab5e8c,
0xe330a81a, 0x020bd8ed, 0x24aa3f05, 0xc5914ff2,
0x69e9f0d5, 0x88d28022, 0xae7367ca, 0x4f48173d,
0xf36e6f75, 0x12551f82, 0x34f4f86a, 0xd5cf889d,
0x79b737ba, 0x988c474d, 0xbe2da0a5, 0x5f16d052
};
/*
* eFuse calculation is shown here:
* https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilskey/src/xilskey_utils.c#L1496
*
* Each u32 word is appended a 5-bit value, for a total of 37 bits; see:
* https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilskey/src/xilskey_utils.c#L1356
*/
uint32_t crc = prev_crc;
const unsigned rshf = 7;
const uint32_t im = (1 << rshf) - 1;
const uint32_t rm = (1 << (32 - rshf)) - 1;
const uint32_t i2 = (1 << 2) - 1;
const uint32_t r2 = (1 << 30) - 1;
unsigned j;
uint32_t i, r;
uint64_t w;
w = (uint64_t)(addr) << 32;
w |= data;
/* Feed 35 bits, in 5 rounds, each a slice of 7 bits */
for (j = 0; j < 5; j++) {
r = rm & (crc >> rshf);
i = im & (crc ^ w);
crc = crc_tab[i] ^ r;
w >>= rshf;
}
/* Feed the remaining 2 bits */
r = r2 & (crc >> 2);
i = i2 & (crc ^ w);
crc = crc_tab[i << (rshf - 2)] ^ r;
return crc;
}
uint32_t xlnx_efuse_calc_crc(const uint32_t *data, unsigned u32_cnt,
unsigned zpads)
{
uint32_t crc = 0;
unsigned index;
for (index = zpads; index; index--) {
crc = xlnx_efuse_u37_crc(crc, 0, (index + u32_cnt));
}
for (index = u32_cnt; index; index--) {
crc = xlnx_efuse_u37_crc(crc, data[index - 1], index);
}
return crc;
}

280
hw/nvram/xlnx-efuse.c Normal file
View File

@ -0,0 +1,280 @@
/*
* QEMU model of the EFUSE eFuse
*
* Copyright (c) 2015 Xilinx Inc.
*
* Written by Edgar E. Iglesias <edgari@xilinx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/nvram/xlnx-efuse.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "sysemu/blockdev.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#define TBIT0_OFFSET 28
#define TBIT1_OFFSET 29
#define TBIT2_OFFSET 30
#define TBIT3_OFFSET 31
#define TBITS_PATTERN (0x0AU << TBIT0_OFFSET)
#define TBITS_MASK (0x0FU << TBIT0_OFFSET)
bool xlnx_efuse_get_bit(XlnxEFuse *s, unsigned int bit)
{
bool b = s->fuse32[bit / 32] & (1 << (bit % 32));
return b;
}
static int efuse_bytes(XlnxEFuse *s)
{
return ROUND_UP((s->efuse_nr * s->efuse_size) / 8, 4);
}
static int efuse_bdrv_read(XlnxEFuse *s, Error **errp)
{
uint32_t *ram = s->fuse32;
int nr = efuse_bytes(s);
if (!s->blk) {
return 0;
}
s->blk_ro = !blk_supports_write_perm(s->blk);
if (!s->blk_ro) {
int rc;
rc = blk_set_perm(s->blk,
(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE),
BLK_PERM_ALL, NULL);
if (rc) {
s->blk_ro = true;
}
}
if (s->blk_ro) {
warn_report("%s: Skip saving updates to read-only eFUSE backstore.",
blk_name(s->blk));
}
if (blk_pread(s->blk, 0, ram, nr) < 0) {
error_setg(errp, "%s: Failed to read %u bytes from eFUSE backstore.",
blk_name(s->blk), nr);
return -1;
}
/* Convert from little-endian backstore for each 32-bit row */
nr /= 4;
while (nr--) {
ram[nr] = le32_to_cpu(ram[nr]);
}
return 0;
}
static void efuse_bdrv_sync(XlnxEFuse *s, unsigned int bit)
{
unsigned int row_offset;
uint32_t le32;
if (!s->blk || s->blk_ro) {
return; /* Silent on read-only backend to avoid message flood */
}
/* Backstore is always in little-endian */
le32 = cpu_to_le32(xlnx_efuse_get_row(s, bit));
row_offset = (bit / 32) * 4;
if (blk_pwrite(s->blk, row_offset, &le32, 4, 0) < 0) {
error_report("%s: Failed to write offset %u of eFUSE backstore.",
blk_name(s->blk), row_offset);
}
}
static int efuse_ro_bits_cmp(const void *a, const void *b)
{
uint32_t i = *(const uint32_t *)a;
uint32_t j = *(const uint32_t *)b;
return (i > j) - (i < j);
}
static void efuse_ro_bits_sort(XlnxEFuse *s)
{
uint32_t *ary = s->ro_bits;
const uint32_t cnt = s->ro_bits_cnt;
if (ary && cnt > 1) {
qsort(ary, cnt, sizeof(ary[0]), efuse_ro_bits_cmp);
}
}
static bool efuse_ro_bits_find(XlnxEFuse *s, uint32_t k)
{
const uint32_t *ary = s->ro_bits;
const uint32_t cnt = s->ro_bits_cnt;
if (!ary || !cnt) {
return false;
}
return bsearch(&k, ary, cnt, sizeof(ary[0]), efuse_ro_bits_cmp) != NULL;
}
bool xlnx_efuse_set_bit(XlnxEFuse *s, unsigned int bit)
{
if (efuse_ro_bits_find(s, bit)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: WARN: "
"Ignored setting of readonly efuse bit<%u,%u>!\n",
object_get_canonical_path(OBJECT(s)),
(bit / 32), (bit % 32));
return false;
}
s->fuse32[bit / 32] |= 1 << (bit % 32);
efuse_bdrv_sync(s, bit);
return true;
}
bool xlnx_efuse_k256_check(XlnxEFuse *s, uint32_t crc, unsigned start)
{
uint32_t calc;
/* A key always occupies multiple of whole rows */
assert((start % 32) == 0);
calc = xlnx_efuse_calc_crc(&s->fuse32[start / 32], (256 / 32), 0);
return calc == crc;
}
uint32_t xlnx_efuse_tbits_check(XlnxEFuse *s)
{
int nr;
uint32_t check = 0;
for (nr = s->efuse_nr; nr-- > 0; ) {
int efuse_start_row_num = (s->efuse_size * nr) / 32;
uint32_t data = s->fuse32[efuse_start_row_num];
/*
* If the option is on, auto-init blank T-bits.
* (non-blank will still be reported as '0' in the check, e.g.,
* for error-injection tests)
*/
if ((data & TBITS_MASK) == 0 && s->init_tbits) {
data |= TBITS_PATTERN;
s->fuse32[efuse_start_row_num] = data;
efuse_bdrv_sync(s, (efuse_start_row_num * 32 + TBIT0_OFFSET));
}
check = (check << 1) | ((data & TBITS_MASK) == TBITS_PATTERN);
}
return check;
}
static void efuse_realize(DeviceState *dev, Error **errp)
{
XlnxEFuse *s = XLNX_EFUSE(dev);
/* Sort readonly-list for bsearch lookup */
efuse_ro_bits_sort(s);
if ((s->efuse_size % 32) != 0) {
error_setg(errp,
"%s.efuse-size: %u: property value not multiple of 32.",
object_get_canonical_path(OBJECT(dev)), s->efuse_size);
return;
}
s->fuse32 = g_malloc0(efuse_bytes(s));
if (efuse_bdrv_read(s, errp)) {
g_free(s->fuse32);
}
}
static void efuse_prop_set_drive(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
qdev_prop_drive.set(obj, v, name, opaque, errp);
/* Fill initial data if backend is attached after realized */
if (dev->realized) {
efuse_bdrv_read(XLNX_EFUSE(obj), errp);
}
}
static void efuse_prop_get_drive(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
qdev_prop_drive.get(obj, v, name, opaque, errp);
}
static void efuse_prop_release_drive(Object *obj, const char *name,
void *opaque)
{
qdev_prop_drive.release(obj, name, opaque);
}
static const PropertyInfo efuse_prop_drive = {
.name = "str",
.description = "Node name or ID of a block device to use as eFUSE backend",
.realized_set_allowed = true,
.get = efuse_prop_get_drive,
.set = efuse_prop_set_drive,
.release = efuse_prop_release_drive,
};
static Property efuse_properties[] = {
DEFINE_PROP("drive", XlnxEFuse, blk, efuse_prop_drive, BlockBackend *),
DEFINE_PROP_UINT8("efuse-nr", XlnxEFuse, efuse_nr, 3),
DEFINE_PROP_UINT32("efuse-size", XlnxEFuse, efuse_size, 64 * 32),
DEFINE_PROP_BOOL("init-factory-tbits", XlnxEFuse, init_tbits, true),
DEFINE_PROP_ARRAY("read-only", XlnxEFuse, ro_bits_cnt, ro_bits,
qdev_prop_uint32, uint32_t),
DEFINE_PROP_END_OF_LIST(),
};
static void efuse_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = efuse_realize;
device_class_set_props(dc, efuse_properties);
}
static const TypeInfo efuse_info = {
.name = TYPE_XLNX_EFUSE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(XlnxEFuse),
.class_init = efuse_class_init,
};
static void efuse_register_types(void)
{
type_register_static(&efuse_info);
}
type_init(efuse_register_types)

View File

@ -0,0 +1,114 @@
/*
* QEMU model of the EFuse_Cache
*
* Copyright (c) 2017 Xilinx Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/nvram/xlnx-versal-efuse.h"
#include "qemu/log.h"
#include "hw/qdev-properties.h"
#define MR_SIZE 0xC00
static uint64_t efuse_cache_read(void *opaque, hwaddr addr, unsigned size)
{
XlnxVersalEFuseCache *s = XLNX_VERSAL_EFUSE_CACHE(opaque);
unsigned int w0 = QEMU_ALIGN_DOWN(addr * 8, 32);
unsigned int w1 = QEMU_ALIGN_DOWN((addr + size - 1) * 8, 32);
uint64_t ret;
assert(w0 == w1 || (w0 + 32) == w1);
ret = xlnx_versal_efuse_read_row(s->efuse, w1, NULL);
if (w0 < w1) {
ret <<= 32;
ret |= xlnx_versal_efuse_read_row(s->efuse, w0, NULL);
}
/* If 'addr' unaligned, the guest is always assumed to be little-endian. */
addr &= 3;
if (addr) {
ret >>= 8 * addr;
}
return ret;
}
static void efuse_cache_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
/* No Register Writes allowed */
qemu_log_mask(LOG_GUEST_ERROR, "%s: efuse cache registers are read-only",
__func__);
}
static const MemoryRegionOps efuse_cache_ops = {
.read = efuse_cache_read,
.write = efuse_cache_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
};
static void efuse_cache_init(Object *obj)
{
XlnxVersalEFuseCache *s = XLNX_VERSAL_EFUSE_CACHE(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &efuse_cache_ops, s,
TYPE_XLNX_VERSAL_EFUSE_CACHE, MR_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
}
static Property efuse_cache_props[] = {
DEFINE_PROP_LINK("efuse",
XlnxVersalEFuseCache, efuse,
TYPE_XLNX_EFUSE, XlnxEFuse *),
DEFINE_PROP_END_OF_LIST(),
};
static void efuse_cache_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, efuse_cache_props);
}
static const TypeInfo efuse_cache_info = {
.name = TYPE_XLNX_VERSAL_EFUSE_CACHE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(XlnxVersalEFuseCache),
.class_init = efuse_cache_class_init,
.instance_init = efuse_cache_init,
};
static void efuse_cache_register_types(void)
{
type_register_static(&efuse_cache_info);
}
type_init(efuse_cache_register_types)

View File

@ -0,0 +1,783 @@
/*
* QEMU model of the Versal eFuse controller
*
* Copyright (c) 2020 Xilinx Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/nvram/xlnx-versal-efuse.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#ifndef XLNX_VERSAL_EFUSE_CTRL_ERR_DEBUG
#define XLNX_VERSAL_EFUSE_CTRL_ERR_DEBUG 0
#endif
REG32(WR_LOCK, 0x0)
FIELD(WR_LOCK, LOCK, 0, 16)
REG32(CFG, 0x4)
FIELD(CFG, SLVERR_ENABLE, 5, 1)
FIELD(CFG, MARGIN_RD, 2, 1)
FIELD(CFG, PGM_EN, 1, 1)
REG32(STATUS, 0x8)
FIELD(STATUS, AES_USER_KEY_1_CRC_PASS, 11, 1)
FIELD(STATUS, AES_USER_KEY_1_CRC_DONE, 10, 1)
FIELD(STATUS, AES_USER_KEY_0_CRC_PASS, 9, 1)
FIELD(STATUS, AES_USER_KEY_0_CRC_DONE, 8, 1)
FIELD(STATUS, AES_CRC_PASS, 7, 1)
FIELD(STATUS, AES_CRC_DONE, 6, 1)
FIELD(STATUS, CACHE_DONE, 5, 1)
FIELD(STATUS, CACHE_LOAD, 4, 1)
FIELD(STATUS, EFUSE_2_TBIT, 2, 1)
FIELD(STATUS, EFUSE_1_TBIT, 1, 1)
FIELD(STATUS, EFUSE_0_TBIT, 0, 1)
REG32(EFUSE_PGM_ADDR, 0xc)
FIELD(EFUSE_PGM_ADDR, PAGE, 13, 4)
FIELD(EFUSE_PGM_ADDR, ROW, 5, 8)
FIELD(EFUSE_PGM_ADDR, COLUMN, 0, 5)
REG32(EFUSE_RD_ADDR, 0x10)
FIELD(EFUSE_RD_ADDR, PAGE, 13, 4)
FIELD(EFUSE_RD_ADDR, ROW, 5, 8)
REG32(EFUSE_RD_DATA, 0x14)
REG32(TPGM, 0x18)
FIELD(TPGM, VALUE, 0, 16)
REG32(TRD, 0x1c)
FIELD(TRD, VALUE, 0, 8)
REG32(TSU_H_PS, 0x20)
FIELD(TSU_H_PS, VALUE, 0, 8)
REG32(TSU_H_PS_CS, 0x24)
FIELD(TSU_H_PS_CS, VALUE, 0, 8)
REG32(TRDM, 0x28)
FIELD(TRDM, VALUE, 0, 8)
REG32(TSU_H_CS, 0x2c)
FIELD(TSU_H_CS, VALUE, 0, 8)
REG32(EFUSE_ISR, 0x30)
FIELD(EFUSE_ISR, APB_SLVERR, 31, 1)
FIELD(EFUSE_ISR, CACHE_PARITY_E2, 14, 1)
FIELD(EFUSE_ISR, CACHE_PARITY_E1, 13, 1)
FIELD(EFUSE_ISR, CACHE_PARITY_E0S, 12, 1)
FIELD(EFUSE_ISR, CACHE_PARITY_E0R, 11, 1)
FIELD(EFUSE_ISR, CACHE_APB_SLVERR, 10, 1)
FIELD(EFUSE_ISR, CACHE_REQ_ERROR, 9, 1)
FIELD(EFUSE_ISR, MAIN_REQ_ERROR, 8, 1)
FIELD(EFUSE_ISR, READ_ON_CACHE_LD, 7, 1)
FIELD(EFUSE_ISR, CACHE_FSM_ERROR, 6, 1)
FIELD(EFUSE_ISR, MAIN_FSM_ERROR, 5, 1)
FIELD(EFUSE_ISR, CACHE_ERROR, 4, 1)
FIELD(EFUSE_ISR, RD_ERROR, 3, 1)
FIELD(EFUSE_ISR, RD_DONE, 2, 1)
FIELD(EFUSE_ISR, PGM_ERROR, 1, 1)
FIELD(EFUSE_ISR, PGM_DONE, 0, 1)
REG32(EFUSE_IMR, 0x34)
FIELD(EFUSE_IMR, APB_SLVERR, 31, 1)
FIELD(EFUSE_IMR, CACHE_PARITY_E2, 14, 1)
FIELD(EFUSE_IMR, CACHE_PARITY_E1, 13, 1)
FIELD(EFUSE_IMR, CACHE_PARITY_E0S, 12, 1)
FIELD(EFUSE_IMR, CACHE_PARITY_E0R, 11, 1)
FIELD(EFUSE_IMR, CACHE_APB_SLVERR, 10, 1)
FIELD(EFUSE_IMR, CACHE_REQ_ERROR, 9, 1)
FIELD(EFUSE_IMR, MAIN_REQ_ERROR, 8, 1)
FIELD(EFUSE_IMR, READ_ON_CACHE_LD, 7, 1)
FIELD(EFUSE_IMR, CACHE_FSM_ERROR, 6, 1)
FIELD(EFUSE_IMR, MAIN_FSM_ERROR, 5, 1)
FIELD(EFUSE_IMR, CACHE_ERROR, 4, 1)
FIELD(EFUSE_IMR, RD_ERROR, 3, 1)
FIELD(EFUSE_IMR, RD_DONE, 2, 1)
FIELD(EFUSE_IMR, PGM_ERROR, 1, 1)
FIELD(EFUSE_IMR, PGM_DONE, 0, 1)
REG32(EFUSE_IER, 0x38)
FIELD(EFUSE_IER, APB_SLVERR, 31, 1)
FIELD(EFUSE_IER, CACHE_PARITY_E2, 14, 1)
FIELD(EFUSE_IER, CACHE_PARITY_E1, 13, 1)
FIELD(EFUSE_IER, CACHE_PARITY_E0S, 12, 1)
FIELD(EFUSE_IER, CACHE_PARITY_E0R, 11, 1)
FIELD(EFUSE_IER, CACHE_APB_SLVERR, 10, 1)
FIELD(EFUSE_IER, CACHE_REQ_ERROR, 9, 1)
FIELD(EFUSE_IER, MAIN_REQ_ERROR, 8, 1)
FIELD(EFUSE_IER, READ_ON_CACHE_LD, 7, 1)
FIELD(EFUSE_IER, CACHE_FSM_ERROR, 6, 1)
FIELD(EFUSE_IER, MAIN_FSM_ERROR, 5, 1)
FIELD(EFUSE_IER, CACHE_ERROR, 4, 1)
FIELD(EFUSE_IER, RD_ERROR, 3, 1)
FIELD(EFUSE_IER, RD_DONE, 2, 1)
FIELD(EFUSE_IER, PGM_ERROR, 1, 1)
FIELD(EFUSE_IER, PGM_DONE, 0, 1)
REG32(EFUSE_IDR, 0x3c)
FIELD(EFUSE_IDR, APB_SLVERR, 31, 1)
FIELD(EFUSE_IDR, CACHE_PARITY_E2, 14, 1)
FIELD(EFUSE_IDR, CACHE_PARITY_E1, 13, 1)
FIELD(EFUSE_IDR, CACHE_PARITY_E0S, 12, 1)
FIELD(EFUSE_IDR, CACHE_PARITY_E0R, 11, 1)
FIELD(EFUSE_IDR, CACHE_APB_SLVERR, 10, 1)
FIELD(EFUSE_IDR, CACHE_REQ_ERROR, 9, 1)
FIELD(EFUSE_IDR, MAIN_REQ_ERROR, 8, 1)
FIELD(EFUSE_IDR, READ_ON_CACHE_LD, 7, 1)
FIELD(EFUSE_IDR, CACHE_FSM_ERROR, 6, 1)
FIELD(EFUSE_IDR, MAIN_FSM_ERROR, 5, 1)
FIELD(EFUSE_IDR, CACHE_ERROR, 4, 1)
FIELD(EFUSE_IDR, RD_ERROR, 3, 1)
FIELD(EFUSE_IDR, RD_DONE, 2, 1)
FIELD(EFUSE_IDR, PGM_ERROR, 1, 1)
FIELD(EFUSE_IDR, PGM_DONE, 0, 1)
REG32(EFUSE_CACHE_LOAD, 0x40)
FIELD(EFUSE_CACHE_LOAD, LOAD, 0, 1)
REG32(EFUSE_PGM_LOCK, 0x44)
FIELD(EFUSE_PGM_LOCK, SPK_ID_LOCK, 0, 1)
REG32(EFUSE_AES_CRC, 0x48)
REG32(EFUSE_AES_USR_KEY0_CRC, 0x4c)
REG32(EFUSE_AES_USR_KEY1_CRC, 0x50)
REG32(EFUSE_PD, 0x54)
REG32(EFUSE_ANLG_OSC_SW_1LP, 0x60)
REG32(EFUSE_TEST_CTRL, 0x100)
#define R_MAX (R_EFUSE_TEST_CTRL + 1)
#define R_WR_LOCK_UNLOCK_PASSCODE (0xDF0D)
/*
* eFuse layout references:
* https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilnvm/src/xnvm_efuse_hw.h
*/
#define BIT_POS_OF(A_) \
((uint32_t)((A_) & (R_EFUSE_PGM_ADDR_ROW_MASK | \
R_EFUSE_PGM_ADDR_COLUMN_MASK)))
#define BIT_POS(R_, C_) \
((uint32_t)((R_EFUSE_PGM_ADDR_ROW_MASK \
& ((R_) << R_EFUSE_PGM_ADDR_ROW_SHIFT)) \
| \
(R_EFUSE_PGM_ADDR_COLUMN_MASK \
& ((C_) << R_EFUSE_PGM_ADDR_COLUMN_SHIFT))))
#define EFUSE_TBIT_POS(A_) (BIT_POS_OF(A_) >= BIT_POS(0, 28))
#define EFUSE_ANCHOR_ROW (0)
#define EFUSE_ANCHOR_3_COL (27)
#define EFUSE_ANCHOR_1_COL (1)
#define EFUSE_AES_KEY_START BIT_POS(12, 0)
#define EFUSE_AES_KEY_END BIT_POS(19, 31)
#define EFUSE_USER_KEY_0_START BIT_POS(20, 0)
#define EFUSE_USER_KEY_0_END BIT_POS(27, 31)
#define EFUSE_USER_KEY_1_START BIT_POS(28, 0)
#define EFUSE_USER_KEY_1_END BIT_POS(35, 31)
#define EFUSE_RD_BLOCKED_START EFUSE_AES_KEY_START
#define EFUSE_RD_BLOCKED_END EFUSE_USER_KEY_1_END
#define EFUSE_GLITCH_DET_WR_LK BIT_POS(4, 31)
#define EFUSE_PPK0_WR_LK BIT_POS(43, 6)
#define EFUSE_PPK1_WR_LK BIT_POS(43, 7)
#define EFUSE_PPK2_WR_LK BIT_POS(43, 8)
#define EFUSE_AES_WR_LK BIT_POS(43, 11)
#define EFUSE_USER_KEY_0_WR_LK BIT_POS(43, 13)
#define EFUSE_USER_KEY_1_WR_LK BIT_POS(43, 15)
#define EFUSE_PUF_SYN_LK BIT_POS(43, 16)
#define EFUSE_DNA_WR_LK BIT_POS(43, 27)
#define EFUSE_BOOT_ENV_WR_LK BIT_POS(43, 28)
#define EFUSE_PGM_LOCKED_START BIT_POS(44, 0)
#define EFUSE_PGM_LOCKED_END BIT_POS(51, 31)
#define EFUSE_PUF_PAGE (2)
#define EFUSE_PUF_SYN_START BIT_POS(129, 0)
#define EFUSE_PUF_SYN_END BIT_POS(255, 27)
#define EFUSE_KEY_CRC_LK_ROW (43)
#define EFUSE_AES_KEY_CRC_LK_MASK ((1U << 9) | (1U << 10))
#define EFUSE_USER_KEY_0_CRC_LK_MASK (1U << 12)
#define EFUSE_USER_KEY_1_CRC_LK_MASK (1U << 14)
/*
* A handy macro to return value of an array element,
* or a specific default if given index is out of bound.
*/
#define ARRAY_GET(A_, I_, D_) \
((unsigned int)(I_) < ARRAY_SIZE(A_) ? (A_)[I_] : (D_))
QEMU_BUILD_BUG_ON(R_MAX != ARRAY_SIZE(((XlnxVersalEFuseCtrl *)0)->regs));
typedef struct XlnxEFuseLkSpec {
uint16_t row;
uint16_t lk_bit;
} XlnxEFuseLkSpec;
static void efuse_imr_update_irq(XlnxVersalEFuseCtrl *s)
{
bool pending = s->regs[R_EFUSE_ISR] & ~s->regs[R_EFUSE_IMR];
qemu_set_irq(s->irq_efuse_imr, pending);
}
static void efuse_isr_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(reg->opaque);
efuse_imr_update_irq(s);
}
static uint64_t efuse_ier_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(reg->opaque);
uint32_t val = val64;
s->regs[R_EFUSE_IMR] &= ~val;
efuse_imr_update_irq(s);
return 0;
}
static uint64_t efuse_idr_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(reg->opaque);
uint32_t val = val64;
s->regs[R_EFUSE_IMR] |= val;
efuse_imr_update_irq(s);
return 0;
}
static void efuse_status_tbits_sync(XlnxVersalEFuseCtrl *s)
{
uint32_t check = xlnx_efuse_tbits_check(s->efuse);
uint32_t val = s->regs[R_STATUS];
val = FIELD_DP32(val, STATUS, EFUSE_0_TBIT, !!(check & (1 << 0)));
val = FIELD_DP32(val, STATUS, EFUSE_1_TBIT, !!(check & (1 << 1)));
val = FIELD_DP32(val, STATUS, EFUSE_2_TBIT, !!(check & (1 << 2)));
s->regs[R_STATUS] = val;
}
static void efuse_anchor_bits_check(XlnxVersalEFuseCtrl *s)
{
unsigned page;
if (!s->efuse || !s->efuse->init_tbits) {
return;
}
for (page = 0; page < s->efuse->efuse_nr; page++) {
uint32_t row = 0, bit;
row = FIELD_DP32(row, EFUSE_PGM_ADDR, PAGE, page);
row = FIELD_DP32(row, EFUSE_PGM_ADDR, ROW, EFUSE_ANCHOR_ROW);
bit = FIELD_DP32(row, EFUSE_PGM_ADDR, COLUMN, EFUSE_ANCHOR_3_COL);
if (!xlnx_efuse_get_bit(s->efuse, bit)) {
xlnx_efuse_set_bit(s->efuse, bit);
}
bit = FIELD_DP32(row, EFUSE_PGM_ADDR, COLUMN, EFUSE_ANCHOR_1_COL);
if (!xlnx_efuse_get_bit(s->efuse, bit)) {
xlnx_efuse_set_bit(s->efuse, bit);
}
}
}
static void efuse_key_crc_check(RegisterInfo *reg, uint32_t crc,
uint32_t pass_mask, uint32_t done_mask,
unsigned first, uint32_t lk_mask)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(reg->opaque);
uint32_t r, lk_bits;
/*
* To start, assume both DONE and PASS, and clear PASS by xor
* if CRC-check fails or CRC-check disabled by lock fuse.
*/
r = s->regs[R_STATUS] | done_mask | pass_mask;
lk_bits = xlnx_efuse_get_row(s->efuse, EFUSE_KEY_CRC_LK_ROW) & lk_mask;
if (lk_bits == 0 && xlnx_efuse_k256_check(s->efuse, crc, first)) {
pass_mask = 0;
}
s->regs[R_STATUS] = r ^ pass_mask;
}
static void efuse_data_sync(XlnxVersalEFuseCtrl *s)
{
efuse_status_tbits_sync(s);
}
static int efuse_lk_spec_cmp(const void *a, const void *b)
{
uint16_t r1 = ((const XlnxEFuseLkSpec *)a)->row;
uint16_t r2 = ((const XlnxEFuseLkSpec *)b)->row;
return (r1 > r2) - (r1 < r2);
}
static void efuse_lk_spec_sort(XlnxVersalEFuseCtrl *s)
{
XlnxEFuseLkSpec *ary = s->extra_pg0_lock_spec;
const uint32_t n8 = s->extra_pg0_lock_n16 * 2;
const uint32_t sz = sizeof(ary[0]);
const uint32_t cnt = n8 / sz;
if (ary && cnt) {
qsort(ary, cnt, sz, efuse_lk_spec_cmp);
}
}
static uint32_t efuse_lk_spec_find(XlnxVersalEFuseCtrl *s, uint32_t row)
{
const XlnxEFuseLkSpec *ary = s->extra_pg0_lock_spec;
const uint32_t n8 = s->extra_pg0_lock_n16 * 2;
const uint32_t sz = sizeof(ary[0]);
const uint32_t cnt = n8 / sz;
const XlnxEFuseLkSpec *item = NULL;
if (ary && cnt) {
XlnxEFuseLkSpec k = { .row = row, };
item = bsearch(&k, ary, cnt, sz, efuse_lk_spec_cmp);
}
return item ? item->lk_bit : 0;
}
static uint32_t efuse_bit_locked(XlnxVersalEFuseCtrl *s, uint32_t bit)
{
/* Hard-coded locks */
static const uint16_t pg0_hard_lock[] = {
[4] = EFUSE_GLITCH_DET_WR_LK,
[37] = EFUSE_BOOT_ENV_WR_LK,
[8 ... 11] = EFUSE_DNA_WR_LK,
[12 ... 19] = EFUSE_AES_WR_LK,
[20 ... 27] = EFUSE_USER_KEY_0_WR_LK,
[28 ... 35] = EFUSE_USER_KEY_1_WR_LK,
[64 ... 71] = EFUSE_PPK0_WR_LK,
[72 ... 79] = EFUSE_PPK1_WR_LK,
[80 ... 87] = EFUSE_PPK2_WR_LK,
};
uint32_t row = FIELD_EX32(bit, EFUSE_PGM_ADDR, ROW);
uint32_t lk_bit = ARRAY_GET(pg0_hard_lock, row, 0);
return lk_bit ? lk_bit : efuse_lk_spec_find(s, row);
}
static bool efuse_pgm_locked(XlnxVersalEFuseCtrl *s, unsigned int bit)
{
unsigned int lock = 1;
/* Global lock */
if (!ARRAY_FIELD_EX32(s->regs, CFG, PGM_EN)) {
goto ret_lock;
}
/* Row lock */
switch (FIELD_EX32(bit, EFUSE_PGM_ADDR, PAGE)) {
case 0:
if (ARRAY_FIELD_EX32(s->regs, EFUSE_PGM_LOCK, SPK_ID_LOCK) &&
bit >= EFUSE_PGM_LOCKED_START && bit <= EFUSE_PGM_LOCKED_END) {
goto ret_lock;
}
lock = efuse_bit_locked(s, bit);
break;
case EFUSE_PUF_PAGE:
if (bit < EFUSE_PUF_SYN_START || bit > EFUSE_PUF_SYN_END) {
lock = 0;
goto ret_lock;
}
lock = EFUSE_PUF_SYN_LK;
break;
default:
lock = 0;
goto ret_lock;
}
/* Row lock by an efuse bit */
if (lock) {
lock = xlnx_efuse_get_bit(s->efuse, lock);
}
ret_lock:
return lock != 0;
}
static void efuse_pgm_addr_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(reg->opaque);
unsigned bit = val64;
bool ok = false;
/* Always zero out PGM_ADDR because it is write-only */
s->regs[R_EFUSE_PGM_ADDR] = 0;
/*
* Indicate error if bit is write-protected (or read-only
* as guarded by efuse_set_bit()).
*
* Keep it simple by not modeling program timing.
*
* Note: model must NEVER clear the PGM_ERROR bit; it is
* up to guest to do so (or by reset).
*/
if (efuse_pgm_locked(s, bit)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Denied setting of efuse<%u, %u, %u>\n",
object_get_canonical_path(OBJECT(s)),
FIELD_EX32(bit, EFUSE_PGM_ADDR, PAGE),
FIELD_EX32(bit, EFUSE_PGM_ADDR, ROW),
FIELD_EX32(bit, EFUSE_PGM_ADDR, COLUMN));
} else if (xlnx_efuse_set_bit(s->efuse, bit)) {
ok = true;
if (EFUSE_TBIT_POS(bit)) {
efuse_status_tbits_sync(s);
}
}
if (!ok) {
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, PGM_ERROR, 1);
}
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, PGM_DONE, 1);
efuse_imr_update_irq(s);
}
static void efuse_rd_addr_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(reg->opaque);
unsigned bit = val64;
bool denied;
/* Always zero out RD_ADDR because it is write-only */
s->regs[R_EFUSE_RD_ADDR] = 0;
/*
* Indicate error if row is read-blocked.
*
* Note: model must NEVER clear the RD_ERROR bit; it is
* up to guest to do so (or by reset).
*/
s->regs[R_EFUSE_RD_DATA] = xlnx_versal_efuse_read_row(s->efuse,
bit, &denied);
if (denied) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Denied reading of efuse<%u, %u>\n",
object_get_canonical_path(OBJECT(s)),
FIELD_EX32(bit, EFUSE_RD_ADDR, PAGE),
FIELD_EX32(bit, EFUSE_RD_ADDR, ROW));
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, RD_ERROR, 1);
}
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, RD_DONE, 1);
efuse_imr_update_irq(s);
return;
}
static uint64_t efuse_cache_load_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(reg->opaque);
if (val64 & R_EFUSE_CACHE_LOAD_LOAD_MASK) {
efuse_data_sync(s);
ARRAY_FIELD_DP32(s->regs, STATUS, CACHE_DONE, 1);
efuse_imr_update_irq(s);
}
return 0;
}
static uint64_t efuse_pgm_lock_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(reg->opaque);
/* Ignore all other bits */
val64 = FIELD_EX32(val64, EFUSE_PGM_LOCK, SPK_ID_LOCK);
/* Once the bit is written 1, only reset will clear it to 0 */
val64 |= ARRAY_FIELD_EX32(s->regs, EFUSE_PGM_LOCK, SPK_ID_LOCK);
return val64;
}
static void efuse_aes_crc_postw(RegisterInfo *reg, uint64_t val64)
{
efuse_key_crc_check(reg, val64,
R_STATUS_AES_CRC_PASS_MASK,
R_STATUS_AES_CRC_DONE_MASK,
EFUSE_AES_KEY_START,
EFUSE_AES_KEY_CRC_LK_MASK);
}
static void efuse_aes_u0_crc_postw(RegisterInfo *reg, uint64_t val64)
{
efuse_key_crc_check(reg, val64,
R_STATUS_AES_USER_KEY_0_CRC_PASS_MASK,
R_STATUS_AES_USER_KEY_0_CRC_DONE_MASK,
EFUSE_USER_KEY_0_START,
EFUSE_USER_KEY_0_CRC_LK_MASK);
}
static void efuse_aes_u1_crc_postw(RegisterInfo *reg, uint64_t val64)
{
efuse_key_crc_check(reg, val64,
R_STATUS_AES_USER_KEY_1_CRC_PASS_MASK,
R_STATUS_AES_USER_KEY_1_CRC_DONE_MASK,
EFUSE_USER_KEY_1_START,
EFUSE_USER_KEY_1_CRC_LK_MASK);
}
static uint64_t efuse_wr_lock_prew(RegisterInfo *reg, uint64_t val)
{
return val != R_WR_LOCK_UNLOCK_PASSCODE;
}
static const RegisterAccessInfo efuse_ctrl_regs_info[] = {
{ .name = "WR_LOCK", .addr = A_WR_LOCK,
.reset = 0x1,
.pre_write = efuse_wr_lock_prew,
},{ .name = "CFG", .addr = A_CFG,
.rsvd = 0x9,
},{ .name = "STATUS", .addr = A_STATUS,
.rsvd = 0x8,
.ro = 0xfff,
},{ .name = "EFUSE_PGM_ADDR", .addr = A_EFUSE_PGM_ADDR,
.post_write = efuse_pgm_addr_postw,
},{ .name = "EFUSE_RD_ADDR", .addr = A_EFUSE_RD_ADDR,
.rsvd = 0x1f,
.post_write = efuse_rd_addr_postw,
},{ .name = "EFUSE_RD_DATA", .addr = A_EFUSE_RD_DATA,
.ro = 0xffffffff,
},{ .name = "TPGM", .addr = A_TPGM,
},{ .name = "TRD", .addr = A_TRD,
.reset = 0x19,
},{ .name = "TSU_H_PS", .addr = A_TSU_H_PS,
.reset = 0xff,
},{ .name = "TSU_H_PS_CS", .addr = A_TSU_H_PS_CS,
.reset = 0x11,
},{ .name = "TRDM", .addr = A_TRDM,
.reset = 0x3a,
},{ .name = "TSU_H_CS", .addr = A_TSU_H_CS,
.reset = 0x16,
},{ .name = "EFUSE_ISR", .addr = A_EFUSE_ISR,
.rsvd = 0x7fff8000,
.w1c = 0x80007fff,
.post_write = efuse_isr_postw,
},{ .name = "EFUSE_IMR", .addr = A_EFUSE_IMR,
.reset = 0x80007fff,
.rsvd = 0x7fff8000,
.ro = 0xffffffff,
},{ .name = "EFUSE_IER", .addr = A_EFUSE_IER,
.rsvd = 0x7fff8000,
.pre_write = efuse_ier_prew,
},{ .name = "EFUSE_IDR", .addr = A_EFUSE_IDR,
.rsvd = 0x7fff8000,
.pre_write = efuse_idr_prew,
},{ .name = "EFUSE_CACHE_LOAD", .addr = A_EFUSE_CACHE_LOAD,
.pre_write = efuse_cache_load_prew,
},{ .name = "EFUSE_PGM_LOCK", .addr = A_EFUSE_PGM_LOCK,
.pre_write = efuse_pgm_lock_prew,
},{ .name = "EFUSE_AES_CRC", .addr = A_EFUSE_AES_CRC,
.post_write = efuse_aes_crc_postw,
},{ .name = "EFUSE_AES_USR_KEY0_CRC", .addr = A_EFUSE_AES_USR_KEY0_CRC,
.post_write = efuse_aes_u0_crc_postw,
},{ .name = "EFUSE_AES_USR_KEY1_CRC", .addr = A_EFUSE_AES_USR_KEY1_CRC,
.post_write = efuse_aes_u1_crc_postw,
},{ .name = "EFUSE_PD", .addr = A_EFUSE_PD,
.ro = 0xfffffffe,
},{ .name = "EFUSE_ANLG_OSC_SW_1LP", .addr = A_EFUSE_ANLG_OSC_SW_1LP,
},{ .name = "EFUSE_TEST_CTRL", .addr = A_EFUSE_TEST_CTRL,
.reset = 0x8,
}
};
static void efuse_ctrl_reg_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
RegisterInfoArray *reg_array = opaque;
XlnxVersalEFuseCtrl *s;
Object *dev;
assert(reg_array != NULL);
dev = reg_array->mem.owner;
assert(dev);
s = XLNX_VERSAL_EFUSE_CTRL(dev);
if (addr != A_WR_LOCK && s->regs[R_WR_LOCK]) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s[reg_0x%02lx]: Attempt to write locked register.\n",
object_get_canonical_path(OBJECT(s)), (long)addr);
} else {
register_write_memory(opaque, addr, data, size);
}
}
static void efuse_ctrl_register_reset(RegisterInfo *reg)
{
if (!reg->data || !reg->access) {
return;
}
/* Reset must not trigger some registers' writers */
switch (reg->access->addr) {
case A_EFUSE_AES_CRC:
case A_EFUSE_AES_USR_KEY0_CRC:
case A_EFUSE_AES_USR_KEY1_CRC:
*(uint32_t *)reg->data = reg->access->reset;
return;
}
register_reset(reg);
}
static void efuse_ctrl_reset(DeviceState *dev)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(dev);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
efuse_ctrl_register_reset(&s->regs_info[i]);
}
efuse_anchor_bits_check(s);
efuse_data_sync(s);
efuse_imr_update_irq(s);
}
static const MemoryRegionOps efuse_ctrl_ops = {
.read = register_read_memory,
.write = efuse_ctrl_reg_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void efuse_ctrl_realize(DeviceState *dev, Error **errp)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(dev);
const uint32_t lks_sz = sizeof(XlnxEFuseLkSpec) / 2;
if (!s->efuse) {
error_setg(errp, "%s.efuse: link property not connected to XLNX-EFUSE",
object_get_canonical_path(OBJECT(dev)));
return;
}
/* Sort property-defined pgm-locks for bsearch lookup */
if ((s->extra_pg0_lock_n16 % lks_sz) != 0) {
error_setg(errp,
"%s.pg0-lock: array property item-count not multiple of %u",
object_get_canonical_path(OBJECT(dev)), lks_sz);
return;
}
efuse_lk_spec_sort(s);
}
static void efuse_ctrl_init(Object *obj)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
RegisterInfoArray *reg_array;
reg_array =
register_init_block32(DEVICE(obj), efuse_ctrl_regs_info,
ARRAY_SIZE(efuse_ctrl_regs_info),
s->regs_info, s->regs,
&efuse_ctrl_ops,
XLNX_VERSAL_EFUSE_CTRL_ERR_DEBUG,
R_MAX * 4);
sysbus_init_mmio(sbd, &reg_array->mem);
sysbus_init_irq(sbd, &s->irq_efuse_imr);
}
static const VMStateDescription vmstate_efuse_ctrl = {
.name = TYPE_XLNX_VERSAL_EFUSE_CTRL,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, XlnxVersalEFuseCtrl, R_MAX),
VMSTATE_END_OF_LIST(),
}
};
static Property efuse_ctrl_props[] = {
DEFINE_PROP_LINK("efuse",
XlnxVersalEFuseCtrl, efuse,
TYPE_XLNX_EFUSE, XlnxEFuse *),
DEFINE_PROP_ARRAY("pg0-lock",
XlnxVersalEFuseCtrl, extra_pg0_lock_n16,
extra_pg0_lock_spec, qdev_prop_uint16, uint16_t),
DEFINE_PROP_END_OF_LIST(),
};
static void efuse_ctrl_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = efuse_ctrl_reset;
dc->realize = efuse_ctrl_realize;
dc->vmsd = &vmstate_efuse_ctrl;
device_class_set_props(dc, efuse_ctrl_props);
}
static const TypeInfo efuse_ctrl_info = {
.name = TYPE_XLNX_VERSAL_EFUSE_CTRL,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(XlnxVersalEFuseCtrl),
.class_init = efuse_ctrl_class_init,
.instance_init = efuse_ctrl_init,
};
static void efuse_ctrl_register_types(void)
{
type_register_static(&efuse_ctrl_info);
}
type_init(efuse_ctrl_register_types)
/*
* Retrieve a row, with unreadable bits returned as 0.
*/
uint32_t xlnx_versal_efuse_read_row(XlnxEFuse *efuse,
uint32_t bit, bool *denied)
{
bool dummy;
if (!denied) {
denied = &dummy;
}
if (bit >= EFUSE_RD_BLOCKED_START && bit <= EFUSE_RD_BLOCKED_END) {
*denied = true;
return 0;
}
*denied = false;
return xlnx_efuse_get_row(efuse, bit);
}

View File

@ -0,0 +1,855 @@
/*
* QEMU model of the ZynqMP eFuse
*
* Copyright (c) 2015 Xilinx Inc.
*
* Written by Edgar E. Iglesias <edgari@xilinx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/nvram/xlnx-zynqmp-efuse.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#ifndef ZYNQMP_EFUSE_ERR_DEBUG
#define ZYNQMP_EFUSE_ERR_DEBUG 0
#endif
REG32(WR_LOCK, 0x0)
FIELD(WR_LOCK, LOCK, 0, 16)
REG32(CFG, 0x4)
FIELD(CFG, SLVERR_ENABLE, 5, 1)
FIELD(CFG, MARGIN_RD, 2, 2)
FIELD(CFG, PGM_EN, 1, 1)
FIELD(CFG, EFUSE_CLK_SEL, 0, 1)
REG32(STATUS, 0x8)
FIELD(STATUS, AES_CRC_PASS, 7, 1)
FIELD(STATUS, AES_CRC_DONE, 6, 1)
FIELD(STATUS, CACHE_DONE, 5, 1)
FIELD(STATUS, CACHE_LOAD, 4, 1)
FIELD(STATUS, EFUSE_3_TBIT, 2, 1)
FIELD(STATUS, EFUSE_2_TBIT, 1, 1)
FIELD(STATUS, EFUSE_0_TBIT, 0, 1)
REG32(EFUSE_PGM_ADDR, 0xc)
FIELD(EFUSE_PGM_ADDR, EFUSE, 11, 2)
FIELD(EFUSE_PGM_ADDR, ROW, 5, 6)
FIELD(EFUSE_PGM_ADDR, COLUMN, 0, 5)
REG32(EFUSE_RD_ADDR, 0x10)
FIELD(EFUSE_RD_ADDR, EFUSE, 11, 2)
FIELD(EFUSE_RD_ADDR, ROW, 5, 6)
REG32(EFUSE_RD_DATA, 0x14)
REG32(TPGM, 0x18)
FIELD(TPGM, VALUE, 0, 16)
REG32(TRD, 0x1c)
FIELD(TRD, VALUE, 0, 8)
REG32(TSU_H_PS, 0x20)
FIELD(TSU_H_PS, VALUE, 0, 8)
REG32(TSU_H_PS_CS, 0x24)
FIELD(TSU_H_PS_CS, VALUE, 0, 8)
REG32(TSU_H_CS, 0x2c)
FIELD(TSU_H_CS, VALUE, 0, 4)
REG32(EFUSE_ISR, 0x30)
FIELD(EFUSE_ISR, APB_SLVERR, 31, 1)
FIELD(EFUSE_ISR, CACHE_ERROR, 4, 1)
FIELD(EFUSE_ISR, RD_ERROR, 3, 1)
FIELD(EFUSE_ISR, RD_DONE, 2, 1)
FIELD(EFUSE_ISR, PGM_ERROR, 1, 1)
FIELD(EFUSE_ISR, PGM_DONE, 0, 1)
REG32(EFUSE_IMR, 0x34)
FIELD(EFUSE_IMR, APB_SLVERR, 31, 1)
FIELD(EFUSE_IMR, CACHE_ERROR, 4, 1)
FIELD(EFUSE_IMR, RD_ERROR, 3, 1)
FIELD(EFUSE_IMR, RD_DONE, 2, 1)
FIELD(EFUSE_IMR, PGM_ERROR, 1, 1)
FIELD(EFUSE_IMR, PGM_DONE, 0, 1)
REG32(EFUSE_IER, 0x38)
FIELD(EFUSE_IER, APB_SLVERR, 31, 1)
FIELD(EFUSE_IER, CACHE_ERROR, 4, 1)
FIELD(EFUSE_IER, RD_ERROR, 3, 1)
FIELD(EFUSE_IER, RD_DONE, 2, 1)
FIELD(EFUSE_IER, PGM_ERROR, 1, 1)
FIELD(EFUSE_IER, PGM_DONE, 0, 1)
REG32(EFUSE_IDR, 0x3c)
FIELD(EFUSE_IDR, APB_SLVERR, 31, 1)
FIELD(EFUSE_IDR, CACHE_ERROR, 4, 1)
FIELD(EFUSE_IDR, RD_ERROR, 3, 1)
FIELD(EFUSE_IDR, RD_DONE, 2, 1)
FIELD(EFUSE_IDR, PGM_ERROR, 1, 1)
FIELD(EFUSE_IDR, PGM_DONE, 0, 1)
REG32(EFUSE_CACHE_LOAD, 0x40)
FIELD(EFUSE_CACHE_LOAD, LOAD, 0, 1)
REG32(EFUSE_PGM_LOCK, 0x44)
FIELD(EFUSE_PGM_LOCK, SPK_ID_LOCK, 0, 1)
REG32(EFUSE_AES_CRC, 0x48)
REG32(EFUSE_TBITS_PRGRMG_EN, 0x100)
FIELD(EFUSE_TBITS_PRGRMG_EN, TBITS_PRGRMG_EN, 3, 1)
REG32(DNA_0, 0x100c)
REG32(DNA_1, 0x1010)
REG32(DNA_2, 0x1014)
REG32(IPDISABLE, 0x1018)
FIELD(IPDISABLE, VCU_DIS, 8, 1)
FIELD(IPDISABLE, GPU_DIS, 5, 1)
FIELD(IPDISABLE, APU3_DIS, 3, 1)
FIELD(IPDISABLE, APU2_DIS, 2, 1)
FIELD(IPDISABLE, APU1_DIS, 1, 1)
FIELD(IPDISABLE, APU0_DIS, 0, 1)
REG32(SYSOSC_CTRL, 0x101c)
FIELD(SYSOSC_CTRL, SYSOSC_EN, 0, 1)
REG32(USER_0, 0x1020)
REG32(USER_1, 0x1024)
REG32(USER_2, 0x1028)
REG32(USER_3, 0x102c)
REG32(USER_4, 0x1030)
REG32(USER_5, 0x1034)
REG32(USER_6, 0x1038)
REG32(USER_7, 0x103c)
REG32(MISC_USER_CTRL, 0x1040)
FIELD(MISC_USER_CTRL, FPD_SC_EN_0, 14, 1)
FIELD(MISC_USER_CTRL, LPD_SC_EN_0, 11, 1)
FIELD(MISC_USER_CTRL, LBIST_EN, 10, 1)
FIELD(MISC_USER_CTRL, USR_WRLK_7, 7, 1)
FIELD(MISC_USER_CTRL, USR_WRLK_6, 6, 1)
FIELD(MISC_USER_CTRL, USR_WRLK_5, 5, 1)
FIELD(MISC_USER_CTRL, USR_WRLK_4, 4, 1)
FIELD(MISC_USER_CTRL, USR_WRLK_3, 3, 1)
FIELD(MISC_USER_CTRL, USR_WRLK_2, 2, 1)
FIELD(MISC_USER_CTRL, USR_WRLK_1, 1, 1)
FIELD(MISC_USER_CTRL, USR_WRLK_0, 0, 1)
REG32(ROM_RSVD, 0x1044)
FIELD(ROM_RSVD, PBR_BOOT_ERROR, 0, 3)
REG32(PUF_CHASH, 0x1050)
REG32(PUF_MISC, 0x1054)
FIELD(PUF_MISC, REGISTER_DIS, 31, 1)
FIELD(PUF_MISC, SYN_WRLK, 30, 1)
FIELD(PUF_MISC, SYN_INVLD, 29, 1)
FIELD(PUF_MISC, TEST2_DIS, 28, 1)
FIELD(PUF_MISC, UNUSED27, 27, 1)
FIELD(PUF_MISC, UNUSED26, 26, 1)
FIELD(PUF_MISC, UNUSED25, 25, 1)
FIELD(PUF_MISC, UNUSED24, 24, 1)
FIELD(PUF_MISC, AUX, 0, 24)
REG32(SEC_CTRL, 0x1058)
FIELD(SEC_CTRL, PPK1_INVLD, 30, 2)
FIELD(SEC_CTRL, PPK1_WRLK, 29, 1)
FIELD(SEC_CTRL, PPK0_INVLD, 27, 2)
FIELD(SEC_CTRL, PPK0_WRLK, 26, 1)
FIELD(SEC_CTRL, RSA_EN, 11, 15)
FIELD(SEC_CTRL, SEC_LOCK, 10, 1)
FIELD(SEC_CTRL, PROG_GATE_2, 9, 1)
FIELD(SEC_CTRL, PROG_GATE_1, 8, 1)
FIELD(SEC_CTRL, PROG_GATE_0, 7, 1)
FIELD(SEC_CTRL, DFT_DIS, 6, 1)
FIELD(SEC_CTRL, JTAG_DIS, 5, 1)
FIELD(SEC_CTRL, ERROR_DIS, 4, 1)
FIELD(SEC_CTRL, BBRAM_DIS, 3, 1)
FIELD(SEC_CTRL, ENC_ONLY, 2, 1)
FIELD(SEC_CTRL, AES_WRLK, 1, 1)
FIELD(SEC_CTRL, AES_RDLK, 0, 1)
REG32(SPK_ID, 0x105c)
REG32(PPK0_0, 0x10a0)
REG32(PPK0_1, 0x10a4)
REG32(PPK0_2, 0x10a8)
REG32(PPK0_3, 0x10ac)
REG32(PPK0_4, 0x10b0)
REG32(PPK0_5, 0x10b4)
REG32(PPK0_6, 0x10b8)
REG32(PPK0_7, 0x10bc)
REG32(PPK0_8, 0x10c0)
REG32(PPK0_9, 0x10c4)
REG32(PPK0_10, 0x10c8)
REG32(PPK0_11, 0x10cc)
REG32(PPK1_0, 0x10d0)
REG32(PPK1_1, 0x10d4)
REG32(PPK1_2, 0x10d8)
REG32(PPK1_3, 0x10dc)
REG32(PPK1_4, 0x10e0)
REG32(PPK1_5, 0x10e4)
REG32(PPK1_6, 0x10e8)
REG32(PPK1_7, 0x10ec)
REG32(PPK1_8, 0x10f0)
REG32(PPK1_9, 0x10f4)
REG32(PPK1_10, 0x10f8)
REG32(PPK1_11, 0x10fc)
#define BIT_POS(ROW, COLUMN) (ROW * 32 + COLUMN)
#define R_MAX (R_PPK1_11 + 1)
/* #define EFUSE_XOSC 26 */
/*
* eFUSE layout references:
* ZynqMP: UG1085 (v2.1) August 21, 2019, p.277, Table 12-13
*/
#define EFUSE_AES_RDLK BIT_POS(22, 0)
#define EFUSE_AES_WRLK BIT_POS(22, 1)
#define EFUSE_ENC_ONLY BIT_POS(22, 2)
#define EFUSE_BBRAM_DIS BIT_POS(22, 3)
#define EFUSE_ERROR_DIS BIT_POS(22, 4)
#define EFUSE_JTAG_DIS BIT_POS(22, 5)
#define EFUSE_DFT_DIS BIT_POS(22, 6)
#define EFUSE_PROG_GATE_0 BIT_POS(22, 7)
#define EFUSE_PROG_GATE_1 BIT_POS(22, 7)
#define EFUSE_PROG_GATE_2 BIT_POS(22, 9)
#define EFUSE_SEC_LOCK BIT_POS(22, 10)
#define EFUSE_RSA_EN BIT_POS(22, 11)
#define EFUSE_RSA_EN14 BIT_POS(22, 25)
#define EFUSE_PPK0_WRLK BIT_POS(22, 26)
#define EFUSE_PPK0_INVLD BIT_POS(22, 27)
#define EFUSE_PPK0_INVLD_1 BIT_POS(22, 28)
#define EFUSE_PPK1_WRLK BIT_POS(22, 29)
#define EFUSE_PPK1_INVLD BIT_POS(22, 30)
#define EFUSE_PPK1_INVLD_1 BIT_POS(22, 31)
/* Areas. */
#define EFUSE_TRIM_START BIT_POS(1, 0)
#define EFUSE_TRIM_END BIT_POS(1, 30)
#define EFUSE_DNA_START BIT_POS(3, 0)
#define EFUSE_DNA_END BIT_POS(5, 31)
#define EFUSE_AES_START BIT_POS(24, 0)
#define EFUSE_AES_END BIT_POS(31, 31)
#define EFUSE_ROM_START BIT_POS(17, 0)
#define EFUSE_ROM_END BIT_POS(17, 31)
#define EFUSE_IPDIS_START BIT_POS(6, 0)
#define EFUSE_IPDIS_END BIT_POS(6, 31)
#define EFUSE_USER_START BIT_POS(8, 0)
#define EFUSE_USER_END BIT_POS(15, 31)
#define EFUSE_BISR_START BIT_POS(32, 0)
#define EFUSE_BISR_END BIT_POS(39, 31)
#define EFUSE_USER_CTRL_START BIT_POS(16, 0)
#define EFUSE_USER_CTRL_END BIT_POS(16, 16)
#define EFUSE_USER_CTRL_MASK ((uint32_t)MAKE_64BIT_MASK(0, 17))
#define EFUSE_PUF_CHASH_START BIT_POS(20, 0)
#define EFUSE_PUF_CHASH_END BIT_POS(20, 31)
#define EFUSE_PUF_MISC_START BIT_POS(21, 0)
#define EFUSE_PUF_MISC_END BIT_POS(21, 31)
#define EFUSE_PUF_SYN_WRLK BIT_POS(21, 30)
#define EFUSE_SPK_START BIT_POS(23, 0)
#define EFUSE_SPK_END BIT_POS(23, 31)
#define EFUSE_PPK0_START BIT_POS(40, 0)
#define EFUSE_PPK0_END BIT_POS(51, 31)
#define EFUSE_PPK1_START BIT_POS(52, 0)
#define EFUSE_PPK1_END BIT_POS(63, 31)
#define EFUSE_CACHE_FLD(s, reg, field) \
ARRAY_FIELD_DP32((s)->regs, reg, field, \
(xlnx_efuse_get_row((s->efuse), EFUSE_ ## field) \
>> (EFUSE_ ## field % 32)))
#define EFUSE_CACHE_BIT(s, reg, field) \
ARRAY_FIELD_DP32((s)->regs, reg, field, xlnx_efuse_get_bit((s->efuse), \
EFUSE_ ## field))
#define FBIT_UNKNOWN (~0)
QEMU_BUILD_BUG_ON(R_MAX != ARRAY_SIZE(((XlnxZynqMPEFuse *)0)->regs));
static void update_tbit_status(XlnxZynqMPEFuse *s)
{
unsigned int check = xlnx_efuse_tbits_check(s->efuse);
uint32_t val = s->regs[R_STATUS];
val = FIELD_DP32(val, STATUS, EFUSE_0_TBIT, !!(check & (1 << 0)));
val = FIELD_DP32(val, STATUS, EFUSE_2_TBIT, !!(check & (1 << 1)));
val = FIELD_DP32(val, STATUS, EFUSE_3_TBIT, !!(check & (1 << 2)));
s->regs[R_STATUS] = val;
}
/* Update the u32 array from efuse bits. Slow but simple approach. */
static void cache_sync_u32(XlnxZynqMPEFuse *s, unsigned int r_start,
unsigned int f_start, unsigned int f_end,
unsigned int f_written)
{
uint32_t *u32 = &s->regs[r_start];
unsigned int fbit, wbits = 0, u32_off = 0;
/* Avoid working on bits that are not relevant. */
if (f_written != FBIT_UNKNOWN
&& (f_written < f_start || f_written > f_end)) {
return;
}
for (fbit = f_start; fbit <= f_end; fbit++, wbits++) {
if (wbits == 32) {
/* Update the key offset. */
u32_off += 1;
wbits = 0;
}
u32[u32_off] |= xlnx_efuse_get_bit(s->efuse, fbit) << wbits;
}
}
/*
* Keep the syncs in bit order so we can bail out for the
* slower ones.
*/
static void zynqmp_efuse_sync_cache(XlnxZynqMPEFuse *s, unsigned int bit)
{
EFUSE_CACHE_BIT(s, SEC_CTRL, AES_RDLK);
EFUSE_CACHE_BIT(s, SEC_CTRL, AES_WRLK);
EFUSE_CACHE_BIT(s, SEC_CTRL, ENC_ONLY);
EFUSE_CACHE_BIT(s, SEC_CTRL, BBRAM_DIS);
EFUSE_CACHE_BIT(s, SEC_CTRL, ERROR_DIS);
EFUSE_CACHE_BIT(s, SEC_CTRL, JTAG_DIS);
EFUSE_CACHE_BIT(s, SEC_CTRL, DFT_DIS);
EFUSE_CACHE_BIT(s, SEC_CTRL, PROG_GATE_0);
EFUSE_CACHE_BIT(s, SEC_CTRL, PROG_GATE_1);
EFUSE_CACHE_BIT(s, SEC_CTRL, PROG_GATE_2);
EFUSE_CACHE_BIT(s, SEC_CTRL, SEC_LOCK);
EFUSE_CACHE_BIT(s, SEC_CTRL, PPK0_WRLK);
EFUSE_CACHE_BIT(s, SEC_CTRL, PPK1_WRLK);
EFUSE_CACHE_FLD(s, SEC_CTRL, RSA_EN);
EFUSE_CACHE_FLD(s, SEC_CTRL, PPK0_INVLD);
EFUSE_CACHE_FLD(s, SEC_CTRL, PPK1_INVLD);
/* Update the tbits. */
update_tbit_status(s);
/* Sync the various areas. */
s->regs[R_MISC_USER_CTRL] = xlnx_efuse_get_row(s->efuse,
EFUSE_USER_CTRL_START)
& EFUSE_USER_CTRL_MASK;
s->regs[R_PUF_CHASH] = xlnx_efuse_get_row(s->efuse, EFUSE_PUF_CHASH_START);
s->regs[R_PUF_MISC] = xlnx_efuse_get_row(s->efuse, EFUSE_PUF_MISC_START);
cache_sync_u32(s, R_DNA_0, EFUSE_DNA_START, EFUSE_DNA_END, bit);
if (bit < EFUSE_AES_START) {
return;
}
cache_sync_u32(s, R_ROM_RSVD, EFUSE_ROM_START, EFUSE_ROM_END, bit);
cache_sync_u32(s, R_IPDISABLE, EFUSE_IPDIS_START, EFUSE_IPDIS_END, bit);
cache_sync_u32(s, R_USER_0, EFUSE_USER_START, EFUSE_USER_END, bit);
cache_sync_u32(s, R_SPK_ID, EFUSE_SPK_START, EFUSE_SPK_END, bit);
cache_sync_u32(s, R_PPK0_0, EFUSE_PPK0_START, EFUSE_PPK0_END, bit);
cache_sync_u32(s, R_PPK1_0, EFUSE_PPK1_START, EFUSE_PPK1_END, bit);
}
static void zynqmp_efuse_update_irq(XlnxZynqMPEFuse *s)
{
bool pending = s->regs[R_EFUSE_ISR] & s->regs[R_EFUSE_IMR];
qemu_set_irq(s->irq, pending);
}
static void zynqmp_efuse_isr_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(reg->opaque);
zynqmp_efuse_update_irq(s);
}
static uint64_t zynqmp_efuse_ier_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(reg->opaque);
uint32_t val = val64;
s->regs[R_EFUSE_IMR] |= val;
zynqmp_efuse_update_irq(s);
return 0;
}
static uint64_t zynqmp_efuse_idr_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(reg->opaque);
uint32_t val = val64;
s->regs[R_EFUSE_IMR] &= ~val;
zynqmp_efuse_update_irq(s);
return 0;
}
static void zynqmp_efuse_pgm_addr_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(reg->opaque);
unsigned bit = val64;
unsigned page = FIELD_EX32(bit, EFUSE_PGM_ADDR, EFUSE);
bool puf_prot = false;
const char *errmsg = NULL;
/* Allow only valid array, and adjust for skipped array 1 */
switch (page) {
case 0:
break;
case 2 ... 3:
bit = FIELD_DP32(bit, EFUSE_PGM_ADDR, EFUSE, page - 1);
puf_prot = xlnx_efuse_get_bit(s->efuse, EFUSE_PUF_SYN_WRLK);
break;
default:
errmsg = "Invalid address";
goto pgm_done;
}
if (ARRAY_FIELD_EX32(s->regs, WR_LOCK, LOCK)) {
errmsg = "Array write-locked";
goto pgm_done;
}
if (!ARRAY_FIELD_EX32(s->regs, CFG, PGM_EN)) {
errmsg = "Array pgm-disabled";
goto pgm_done;
}
if (puf_prot) {
errmsg = "PUF_HD-store write-locked";
goto pgm_done;
}
if (ARRAY_FIELD_EX32(s->regs, SEC_CTRL, AES_WRLK)
&& bit >= EFUSE_AES_START && bit <= EFUSE_AES_END) {
errmsg = "AES key-store Write-locked";
goto pgm_done;
}
if (!xlnx_efuse_set_bit(s->efuse, bit)) {
errmsg = "Write failed";
}
pgm_done:
if (!errmsg) {
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, PGM_ERROR, 0);
} else {
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, PGM_ERROR, 1);
qemu_log_mask(LOG_GUEST_ERROR,
"%s - eFuse write error: %s; addr=0x%x\n",
object_get_canonical_path(OBJECT(s)),
errmsg, (unsigned)val64);
}
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, PGM_DONE, 1);
zynqmp_efuse_update_irq(s);
}
static void zynqmp_efuse_rd_addr_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(reg->opaque);
/*
* Grant reads only to allowed bits; reference sources:
* 1/ XilSKey - XilSKey_ZynqMp_EfusePs_ReadRow()
* 2/ UG1085, v2.0, table 12-13
* (note: enumerates the masks as <first, last> per described in
* references to avoid mental translation).
*/
#define COL_MASK(L_, H_) \
((uint32_t)MAKE_64BIT_MASK((L_), (1 + (H_) - (L_))))
static const uint32_t ary0_col_mask[] = {
/* XilSKey - XSK_ZYNQMP_EFUSEPS_TBITS_ROW */
[0] = COL_MASK(28, 31),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_USR{0:7}_FUSE_ROW */
[8] = COL_MASK(0, 31), [9] = COL_MASK(0, 31),
[10] = COL_MASK(0, 31), [11] = COL_MASK(0, 31),
[12] = COL_MASK(0, 31), [13] = COL_MASK(0, 31),
[14] = COL_MASK(0, 31), [15] = COL_MASK(0, 31),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_MISC_USR_CTRL_ROW */
[16] = COL_MASK(0, 7) | COL_MASK(10, 16),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_PBR_BOOT_ERR_ROW */
[17] = COL_MASK(0, 2),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_PUF_CHASH_ROW */
[20] = COL_MASK(0, 31),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_PUF_AUX_ROW */
[21] = COL_MASK(0, 23) | COL_MASK(29, 31),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_SEC_CTRL_ROW */
[22] = COL_MASK(0, 31),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_SPK_ID_ROW */
[23] = COL_MASK(0, 31),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_PPK0_START_ROW */
[40] = COL_MASK(0, 31), [41] = COL_MASK(0, 31),
[42] = COL_MASK(0, 31), [43] = COL_MASK(0, 31),
[44] = COL_MASK(0, 31), [45] = COL_MASK(0, 31),
[46] = COL_MASK(0, 31), [47] = COL_MASK(0, 31),
[48] = COL_MASK(0, 31), [49] = COL_MASK(0, 31),
[50] = COL_MASK(0, 31), [51] = COL_MASK(0, 31),
/* XilSKey - XSK_ZYNQMP_EFUSEPS_PPK1_START_ROW */
[52] = COL_MASK(0, 31), [53] = COL_MASK(0, 31),
[54] = COL_MASK(0, 31), [55] = COL_MASK(0, 31),
[56] = COL_MASK(0, 31), [57] = COL_MASK(0, 31),
[58] = COL_MASK(0, 31), [59] = COL_MASK(0, 31),
[60] = COL_MASK(0, 31), [61] = COL_MASK(0, 31),
[62] = COL_MASK(0, 31), [63] = COL_MASK(0, 31),
};
uint32_t col_mask = COL_MASK(0, 31);
#undef COL_MASK
uint32_t efuse_idx = s->regs[R_EFUSE_RD_ADDR];
uint32_t efuse_ary = FIELD_EX32(efuse_idx, EFUSE_RD_ADDR, EFUSE);
uint32_t efuse_row = FIELD_EX32(efuse_idx, EFUSE_RD_ADDR, ROW);
switch (efuse_ary) {
case 0: /* Various */
if (efuse_row >= ARRAY_SIZE(ary0_col_mask)) {
goto denied;
}
col_mask = ary0_col_mask[efuse_row];
if (!col_mask) {
goto denied;
}
break;
case 2: /* PUF helper data, adjust for skipped array 1 */
case 3:
val64 = FIELD_DP32(efuse_idx, EFUSE_RD_ADDR, EFUSE, efuse_ary - 1);
break;
default:
goto denied;
}
s->regs[R_EFUSE_RD_DATA] = xlnx_efuse_get_row(s->efuse, val64) & col_mask;
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, RD_ERROR, 0);
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, RD_DONE, 1);
zynqmp_efuse_update_irq(s);
return;
denied:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Denied efuse read from array %u, row %u\n",
object_get_canonical_path(OBJECT(s)),
efuse_ary, efuse_row);
s->regs[R_EFUSE_RD_DATA] = 0;
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, RD_ERROR, 1);
ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, RD_DONE, 0);
zynqmp_efuse_update_irq(s);
}
static void zynqmp_efuse_aes_crc_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(reg->opaque);
bool ok;
ok = xlnx_efuse_k256_check(s->efuse, (uint32_t)val64, EFUSE_AES_START);
ARRAY_FIELD_DP32(s->regs, STATUS, AES_CRC_PASS, (ok ? 1 : 0));
ARRAY_FIELD_DP32(s->regs, STATUS, AES_CRC_DONE, 1);
s->regs[R_EFUSE_AES_CRC] = 0; /* crc value is write-only */
}
static uint64_t zynqmp_efuse_cache_load_prew(RegisterInfo *reg,
uint64_t valu64)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(reg->opaque);
if (valu64 & R_EFUSE_CACHE_LOAD_LOAD_MASK) {
zynqmp_efuse_sync_cache(s, FBIT_UNKNOWN);
ARRAY_FIELD_DP32(s->regs, STATUS, CACHE_DONE, 1);
zynqmp_efuse_update_irq(s);
}
return 0;
}
static uint64_t zynqmp_efuse_wr_lock_prew(RegisterInfo *reg, uint64_t val)
{
return val == 0xDF0D ? 0 : 1;
}
static RegisterAccessInfo zynqmp_efuse_regs_info[] = {
{ .name = "WR_LOCK", .addr = A_WR_LOCK,
.reset = 0x1,
.pre_write = zynqmp_efuse_wr_lock_prew,
},{ .name = "CFG", .addr = A_CFG,
},{ .name = "STATUS", .addr = A_STATUS,
.rsvd = 0x8,
.ro = 0xff,
},{ .name = "EFUSE_PGM_ADDR", .addr = A_EFUSE_PGM_ADDR,
.post_write = zynqmp_efuse_pgm_addr_postw
},{ .name = "EFUSE_RD_ADDR", .addr = A_EFUSE_RD_ADDR,
.rsvd = 0x1f,
.post_write = zynqmp_efuse_rd_addr_postw,
},{ .name = "EFUSE_RD_DATA", .addr = A_EFUSE_RD_DATA,
.ro = 0xffffffff,
},{ .name = "TPGM", .addr = A_TPGM,
},{ .name = "TRD", .addr = A_TRD,
.reset = 0x1b,
},{ .name = "TSU_H_PS", .addr = A_TSU_H_PS,
.reset = 0xff,
},{ .name = "TSU_H_PS_CS", .addr = A_TSU_H_PS_CS,
.reset = 0xb,
},{ .name = "TSU_H_CS", .addr = A_TSU_H_CS,
.reset = 0x7,
},{ .name = "EFUSE_ISR", .addr = A_EFUSE_ISR,
.rsvd = 0x7fffffe0,
.w1c = 0x8000001f,
.post_write = zynqmp_efuse_isr_postw,
},{ .name = "EFUSE_IMR", .addr = A_EFUSE_IMR,
.reset = 0x8000001f,
.rsvd = 0x7fffffe0,
.ro = 0xffffffff,
},{ .name = "EFUSE_IER", .addr = A_EFUSE_IER,
.rsvd = 0x7fffffe0,
.pre_write = zynqmp_efuse_ier_prew,
},{ .name = "EFUSE_IDR", .addr = A_EFUSE_IDR,
.rsvd = 0x7fffffe0,
.pre_write = zynqmp_efuse_idr_prew,
},{ .name = "EFUSE_CACHE_LOAD", .addr = A_EFUSE_CACHE_LOAD,
.pre_write = zynqmp_efuse_cache_load_prew,
},{ .name = "EFUSE_PGM_LOCK", .addr = A_EFUSE_PGM_LOCK,
},{ .name = "EFUSE_AES_CRC", .addr = A_EFUSE_AES_CRC,
.post_write = zynqmp_efuse_aes_crc_postw,
},{ .name = "EFUSE_TBITS_PRGRMG_EN", .addr = A_EFUSE_TBITS_PRGRMG_EN,
.reset = R_EFUSE_TBITS_PRGRMG_EN_TBITS_PRGRMG_EN_MASK,
},{ .name = "DNA_0", .addr = A_DNA_0,
.ro = 0xffffffff,
},{ .name = "DNA_1", .addr = A_DNA_1,
.ro = 0xffffffff,
},{ .name = "DNA_2", .addr = A_DNA_2,
.ro = 0xffffffff,
},{ .name = "IPDISABLE", .addr = A_IPDISABLE,
.ro = 0xffffffff,
},{ .name = "SYSOSC_CTRL", .addr = A_SYSOSC_CTRL,
.ro = 0xffffffff,
},{ .name = "USER_0", .addr = A_USER_0,
.ro = 0xffffffff,
},{ .name = "USER_1", .addr = A_USER_1,
.ro = 0xffffffff,
},{ .name = "USER_2", .addr = A_USER_2,
.ro = 0xffffffff,
},{ .name = "USER_3", .addr = A_USER_3,
.ro = 0xffffffff,
},{ .name = "USER_4", .addr = A_USER_4,
.ro = 0xffffffff,
},{ .name = "USER_5", .addr = A_USER_5,
.ro = 0xffffffff,
},{ .name = "USER_6", .addr = A_USER_6,
.ro = 0xffffffff,
},{ .name = "USER_7", .addr = A_USER_7,
.ro = 0xffffffff,
},{ .name = "MISC_USER_CTRL", .addr = A_MISC_USER_CTRL,
.ro = 0xffffffff,
},{ .name = "ROM_RSVD", .addr = A_ROM_RSVD,
.ro = 0xffffffff,
},{ .name = "PUF_CHASH", .addr = A_PUF_CHASH,
.ro = 0xffffffff,
},{ .name = "PUF_MISC", .addr = A_PUF_MISC,
.ro = 0xffffffff,
},{ .name = "SEC_CTRL", .addr = A_SEC_CTRL,
.ro = 0xffffffff,
},{ .name = "SPK_ID", .addr = A_SPK_ID,
.ro = 0xffffffff,
},{ .name = "PPK0_0", .addr = A_PPK0_0,
.ro = 0xffffffff,
},{ .name = "PPK0_1", .addr = A_PPK0_1,
.ro = 0xffffffff,
},{ .name = "PPK0_2", .addr = A_PPK0_2,
.ro = 0xffffffff,
},{ .name = "PPK0_3", .addr = A_PPK0_3,
.ro = 0xffffffff,
},{ .name = "PPK0_4", .addr = A_PPK0_4,
.ro = 0xffffffff,
},{ .name = "PPK0_5", .addr = A_PPK0_5,
.ro = 0xffffffff,
},{ .name = "PPK0_6", .addr = A_PPK0_6,
.ro = 0xffffffff,
},{ .name = "PPK0_7", .addr = A_PPK0_7,
.ro = 0xffffffff,
},{ .name = "PPK0_8", .addr = A_PPK0_8,
.ro = 0xffffffff,
},{ .name = "PPK0_9", .addr = A_PPK0_9,
.ro = 0xffffffff,
},{ .name = "PPK0_10", .addr = A_PPK0_10,
.ro = 0xffffffff,
},{ .name = "PPK0_11", .addr = A_PPK0_11,
.ro = 0xffffffff,
},{ .name = "PPK1_0", .addr = A_PPK1_0,
.ro = 0xffffffff,
},{ .name = "PPK1_1", .addr = A_PPK1_1,
.ro = 0xffffffff,
},{ .name = "PPK1_2", .addr = A_PPK1_2,
.ro = 0xffffffff,
},{ .name = "PPK1_3", .addr = A_PPK1_3,
.ro = 0xffffffff,
},{ .name = "PPK1_4", .addr = A_PPK1_4,
.ro = 0xffffffff,
},{ .name = "PPK1_5", .addr = A_PPK1_5,
.ro = 0xffffffff,
},{ .name = "PPK1_6", .addr = A_PPK1_6,
.ro = 0xffffffff,
},{ .name = "PPK1_7", .addr = A_PPK1_7,
.ro = 0xffffffff,
},{ .name = "PPK1_8", .addr = A_PPK1_8,
.ro = 0xffffffff,
},{ .name = "PPK1_9", .addr = A_PPK1_9,
.ro = 0xffffffff,
},{ .name = "PPK1_10", .addr = A_PPK1_10,
.ro = 0xffffffff,
},{ .name = "PPK1_11", .addr = A_PPK1_11,
.ro = 0xffffffff,
}
};
static void zynqmp_efuse_reg_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
RegisterInfoArray *reg_array = opaque;
XlnxZynqMPEFuse *s;
Object *dev;
assert(reg_array != NULL);
dev = reg_array->mem.owner;
assert(dev);
s = XLNX_ZYNQMP_EFUSE(dev);
if (addr != A_WR_LOCK && s->regs[R_WR_LOCK]) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s[reg_0x%02lx]: Attempt to write locked register.\n",
object_get_canonical_path(OBJECT(s)), (long)addr);
} else {
register_write_memory(opaque, addr, data, size);
}
}
static const MemoryRegionOps zynqmp_efuse_ops = {
.read = register_read_memory,
.write = zynqmp_efuse_reg_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void zynqmp_efuse_register_reset(RegisterInfo *reg)
{
if (!reg->data || !reg->access) {
return;
}
/* Reset must not trigger some registers' writers */
switch (reg->access->addr) {
case A_EFUSE_AES_CRC:
*(uint32_t *)reg->data = reg->access->reset;
return;
}
register_reset(reg);
}
static void zynqmp_efuse_reset(DeviceState *dev)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(dev);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
zynqmp_efuse_register_reset(&s->regs_info[i]);
}
zynqmp_efuse_sync_cache(s, FBIT_UNKNOWN);
ARRAY_FIELD_DP32(s->regs, STATUS, CACHE_DONE, 1);
zynqmp_efuse_update_irq(s);
}
static void zynqmp_efuse_realize(DeviceState *dev, Error **errp)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(dev);
if (!s->efuse) {
error_setg(errp, "%s.efuse: link property not connected to XLNX-EFUSE",
object_get_canonical_path(OBJECT(dev)));
return;
}
s->efuse->dev = dev;
}
static void zynqmp_efuse_init(Object *obj)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
RegisterInfoArray *reg_array;
reg_array =
register_init_block32(DEVICE(obj), zynqmp_efuse_regs_info,
ARRAY_SIZE(zynqmp_efuse_regs_info),
s->regs_info, s->regs,
&zynqmp_efuse_ops,
ZYNQMP_EFUSE_ERR_DEBUG,
R_MAX * 4);
sysbus_init_mmio(sbd, &reg_array->mem);
sysbus_init_irq(sbd, &s->irq);
}
static const VMStateDescription vmstate_efuse = {
.name = TYPE_XLNX_ZYNQMP_EFUSE,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPEFuse, R_MAX),
VMSTATE_END_OF_LIST(),
}
};
static Property zynqmp_efuse_props[] = {
DEFINE_PROP_LINK("efuse",
XlnxZynqMPEFuse, efuse,
TYPE_XLNX_EFUSE, XlnxEFuse *),
DEFINE_PROP_END_OF_LIST(),
};
static void zynqmp_efuse_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = zynqmp_efuse_reset;
dc->realize = zynqmp_efuse_realize;
dc->vmsd = &vmstate_efuse;
device_class_set_props(dc, zynqmp_efuse_props);
}
static const TypeInfo efuse_info = {
.name = TYPE_XLNX_ZYNQMP_EFUSE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(XlnxZynqMPEFuse),
.class_init = zynqmp_efuse_class_init,
.instance_init = zynqmp_efuse_init,
};
static void efuse_register_types(void)
{
type_register_static(&efuse_info);
}
type_init(efuse_register_types)

View File

@ -300,8 +300,8 @@ static void raven_pcihost_initfn(Object *obj)
memory_region_add_subregion_overlap(address_space_mem, PCI_IO_BASE_ADDR,
&s->pci_io_non_contiguous, 1);
memory_region_add_subregion(address_space_mem, 0xc0000000, &s->pci_memory);
pci_root_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
&s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS);
pci_root_bus_init(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
&s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS);
/* Bus master address space */
memory_region_init(&s->bm, obj, "bm-raven", 4 * GiB);

View File

@ -405,9 +405,9 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp)
memory_region_init(&s->pci_io_space, OBJECT(s), "pci_io", 4 * GiB);
memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 4 * GiB);
pci_root_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), dev, "pci",
&s->pci_mem_space, &s->pci_io_space,
PCI_DEVFN(11, 0), TYPE_PCI_BUS);
pci_root_bus_init(&s->pci_bus, sizeof(s->pci_bus), dev, "pci",
&s->pci_mem_space, &s->pci_io_space,
PCI_DEVFN(11, 0), TYPE_PCI_BUS);
h->bus = &s->pci_bus;
object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_VERSATILE_PCI_HOST);

View File

@ -432,10 +432,10 @@ bool pci_bus_bypass_iommu(PCIBus *bus)
return host_bridge->bypass_iommu;
}
static void pci_root_bus_init(PCIBus *bus, DeviceState *parent,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min)
static void pci_root_bus_internal_init(PCIBus *bus, DeviceState *parent,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min)
{
assert(PCI_FUNC(devfn_min) == 0);
bus->devfn_min = devfn_min;
@ -460,15 +460,15 @@ bool pci_bus_is_express(PCIBus *bus)
return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
}
void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent,
const char *name,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min, const char *typename)
void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent,
const char *name,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min, const char *typename)
{
qbus_create_inplace(bus, bus_size, typename, parent, name);
pci_root_bus_init(bus, parent, address_space_mem, address_space_io,
devfn_min);
qbus_init(bus, bus_size, typename, parent, name);
pci_root_bus_internal_init(bus, parent, address_space_mem,
address_space_io, devfn_min);
}
PCIBus *pci_root_bus_new(DeviceState *parent, const char *name,
@ -478,9 +478,9 @@ PCIBus *pci_root_bus_new(DeviceState *parent, const char *name,
{
PCIBus *bus;
bus = PCI_BUS(qbus_create(typename, parent, name));
pci_root_bus_init(bus, parent, address_space_mem, address_space_io,
devfn_min);
bus = PCI_BUS(qbus_new(typename, parent, name));
pci_root_bus_internal_init(bus, parent, address_space_mem,
address_space_io, devfn_min);
return bus;
}

View File

@ -374,8 +374,8 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename)
br->bus_name = dev->qdev.id;
}
qbus_create_inplace(sec_bus, sizeof(br->sec_bus), typename, DEVICE(dev),
br->bus_name);
qbus_init(sec_bus, sizeof(br->sec_bus), typename, DEVICE(dev),
br->bus_name);
sec_bus->parent_dev = dev;
sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn;
sec_bus->address_space_mem = &br->address_space_mem;

View File

@ -577,7 +577,7 @@ SpaprVioBus *spapr_vio_bus_init(void)
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
/* Create bus on bridge device */
qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
qbus = qbus_new(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
bus = SPAPR_VIO_BUS(qbus);
bus->next_reg = SPAPR_VIO_REG_BASE;

View File

@ -55,7 +55,7 @@ void s390_init_ap(void)
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
/* Create bus on bridge device */
bus = qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS);
bus = qbus_new(TYPE_AP_BUS, dev, TYPE_AP_BUS);
/* Enable hotplugging */
qbus_set_hotplug_handler(bus, OBJECT(dev));

View File

@ -106,7 +106,7 @@ VirtualCssBus *virtual_css_bus_init(void)
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
/* Create bus on bridge device */
bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
bus = qbus_new(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
cbus = VIRTUAL_CSS_BUS(bus);
/* Enable hotplugging */

View File

@ -427,8 +427,8 @@ static void init_event_facility(Object *obj)
sclp_event_set_allow_all_mask_sizes);
/* Spawn a new bus for SCLP events */
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
TYPE_SCLP_EVENTS_BUS, sdev, NULL);
qbus_init(&event_facility->sbus, sizeof(event_facility->sbus),
TYPE_SCLP_EVENTS_BUS, sdev, NULL);
object_initialize_child(obj, TYPE_SCLP_QUIESCE,
&event_facility->quiesce,

View File

@ -813,7 +813,7 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp)
qbus_set_hotplug_handler(bus, OBJECT(dev));
phb->bus = b;
s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, dev, NULL));
s->bus = S390_PCI_BUS(qbus_new(TYPE_S390_PCI_BUS, dev, NULL));
qbus_set_hotplug_handler(BUS(s->bus), OBJECT(dev));
s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal,

View File

@ -1261,8 +1261,7 @@ static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
DeviceState *qdev = DEVICE(dev);
char virtio_bus_name[] = "virtio-bus";
qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS,
qdev, virtio_bus_name);
qbus_init(bus, bus_size, TYPE_VIRTIO_CCW_BUS, qdev, virtio_bus_name);
}
static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)

View File

@ -388,7 +388,7 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
s->irq = pci_allocate_irq(dev);
scsi_bus_new(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info);
}
static void esp_pci_scsi_exit(PCIDevice *d)

View File

@ -1348,7 +1348,7 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2);
scsi_bus_new(&s->bus, sizeof(s->bus), dev, &esp_scsi_info, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), dev, &esp_scsi_info);
}
static void sysbus_esp_hard_reset(DeviceState *dev)

View File

@ -2309,7 +2309,7 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
QTAILQ_INIT(&s->queue);
scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), d, &lsi_scsi_info);
}
static void lsi_scsi_exit(PCIDevice *dev)

View File

@ -2416,8 +2416,7 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
s->frames[i].state = s;
}
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
&megasas_scsi_info, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev), &megasas_scsi_info);
}
static Property megasas_properties_gen1[] = {

View File

@ -1315,7 +1315,7 @@ static void mptsas_scsi_realize(PCIDevice *dev, Error **errp)
s->request_bh = qemu_bh_new(mptsas_fetch_requests, s);
scsi_bus_new(&s->bus, sizeof(s->bus), &dev->qdev, &mptsas_scsi_info, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), &dev->qdev, &mptsas_scsi_info);
}
static void mptsas_scsi_uninit(PCIDevice *dev)

View File

@ -134,10 +134,10 @@ void scsi_device_unit_attention_reported(SCSIDevice *s)
}
/* Create a scsi bus, and attach devices to it. */
void scsi_bus_new(SCSIBus *bus, size_t bus_size, DeviceState *host,
const SCSIBusInfo *info, const char *bus_name)
void scsi_bus_init_named(SCSIBus *bus, size_t bus_size, DeviceState *host,
const SCSIBusInfo *info, const char *bus_name)
{
qbus_create_inplace(bus, bus_size, TYPE_SCSI_BUS, host, bus_name);
qbus_init(bus, bus_size, TYPE_SCSI_BUS, host, bus_name);
bus->busnr = next_scsi_bus++;
bus->info = info;
qbus_set_bus_hotplug_handler(BUS(bus));

View File

@ -1216,8 +1216,7 @@ static void spapr_vscsi_realize(SpaprVioDevice *dev, Error **errp)
dev->crq.SendFunc = vscsi_do_crq;
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
&vscsi_scsi_info, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev), &vscsi_scsi_info);
/* ibmvscsi SCSI bus does not allow hotplug. */
qbus_set_hotplug_handler(BUS(&s->bus), NULL);

View File

@ -1019,8 +1019,8 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
return;
}
scsi_bus_new(&s->bus, sizeof(s->bus), dev,
&virtio_scsi_scsi_info, vdev->bus_name);
scsi_bus_init_named(&s->bus, sizeof(s->bus), dev,
&virtio_scsi_scsi_info, vdev->bus_name);
/* override default SCSI bus hotplug-handler, with virtio-scsi's one */
qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev));

View File

@ -1180,8 +1180,7 @@ pvscsi_realizefn(PCIDevice *pci_dev, Error **errp)
s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s);
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
&pvscsi_scsi_info, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(pci_dev), &pvscsi_scsi_info);
/* override default SCSI bus hotplug-handler, with pvscsi's one */
qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(s));
pvscsi_reset_state(s);

View File

@ -738,8 +738,8 @@ static void allwinner_sdhost_init(Object *obj)
{
AwSdHostState *s = AW_SDHOST(obj);
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
TYPE_AW_SDHOST_BUS, DEVICE(s), "sd-bus");
qbus_init(&s->sdbus, sizeof(s->sdbus),
TYPE_AW_SDHOST_BUS, DEVICE(s), "sd-bus");
memory_region_init_io(&s->iomem, obj, &allwinner_sdhost_ops, s,
TYPE_AW_SDHOST, 4 * KiB);

View File

@ -403,8 +403,8 @@ static void bcm2835_sdhost_init(Object *obj)
{
BCM2835SDHostState *s = BCM2835_SDHOST(obj);
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
TYPE_BCM2835_SDHOST_BUS, DEVICE(s), "sd-bus");
qbus_init(&s->sdbus, sizeof(s->sdbus),
TYPE_BCM2835_SDHOST_BUS, DEVICE(s), "sd-bus");
memory_region_init_io(&s->iomem, obj, &bcm2835_sdhost_ops, s,
TYPE_BCM2835_SDHOST, 0x1000);

View File

@ -506,8 +506,7 @@ static void pl181_init(Object *obj)
qdev_init_gpio_out_named(dev, &s->card_readonly, "card-read-only", 1);
qdev_init_gpio_out_named(dev, &s->card_inserted, "card-inserted", 1);
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
TYPE_PL181_BUS, dev, "sd-bus");
qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_PL181_BUS, dev, "sd-bus");
}
static void pl181_class_init(ObjectClass *klass, void *data)

View File

@ -560,8 +560,8 @@ static void pxa2xx_mmci_instance_init(Object *obj)
qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1);
qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1);
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
qbus_init(&s->sdbus, sizeof(s->sdbus),
TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
}
static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data)

View File

@ -1337,8 +1337,7 @@ static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp)
void sdhci_initfn(SDHCIState *s)
{
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
TYPE_SDHCI_BUS, DEVICE(s), "sd-bus");
qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SDHCI_BUS, DEVICE(s), "sd-bus");
s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s);
s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);

View File

@ -373,8 +373,7 @@ static void ssi_sd_realize(SSIPeripheral *d, Error **errp)
DeviceState *carddev;
DriveInfo *dinfo;
qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
DEVICE(d), "sd-bus");
qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(d), "sd-bus");
/* Create and plug in the sd card */
/* FIXME use a qdev drive property instead of drive_get_next() */

View File

@ -107,7 +107,7 @@ DeviceState *ssi_create_peripheral(SSIBus *bus, const char *name)
SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
{
BusState *bus;
bus = qbus_create(TYPE_SSI_BUS, parent, name);
bus = qbus_new(TYPE_SSI_BUS, parent, name);
return SSI_BUS(bus);
}

View File

@ -82,7 +82,7 @@ const VMStateDescription vmstate_usb_device = {
void usb_bus_new(USBBus *bus, size_t bus_size,
USBBusOps *ops, DeviceState *host)
{
qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL);
qbus_init(bus, bus_size, TYPE_USB_BUS, host, NULL);
qbus_set_bus_hotplug_handler(BUS(bus));
bus->ops = ops;
bus->busnr = next_usb_bus++;

View File

@ -1320,8 +1320,7 @@ static void ccid_realize(USBDevice *dev, Error **errp)
usb_desc_create_serial(dev);
usb_desc_init(dev);
qbus_create_inplace(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev),
NULL);
qbus_init(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev), NULL);
qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev));
s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
s->bulk = usb_ep_get(dev, USB_TOKEN_IN, CCID_BULK_IN_EP);

View File

@ -37,8 +37,7 @@ static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
s->dev.auto_attach = 0;
}
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
&usb_msd_scsi_info_bot, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev), &usb_msd_scsi_info_bot);
usb_msd_handle_reset(dev);
}

View File

@ -65,8 +65,8 @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
usb_desc_create_serial(dev);
usb_desc_init(dev);
dev->flags |= (1 << USB_DEV_FLAG_IS_SCSI_STORAGE);
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
&usb_msd_scsi_info_storage, NULL);
scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev),
&usb_msd_scsi_info_storage);
scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
s->conf.bootindex, s->conf.share_rw,
s->conf.rerror, s->conf.werror,

View File

@ -938,8 +938,7 @@ static void usb_uas_realize(USBDevice *dev, Error **errp)
uas->status_bh = qemu_bh_new(usb_uas_send_status_bh, uas);
dev->flags |= (1 << USB_DEV_FLAG_IS_SCSI_STORAGE);
scsi_bus_new(&uas->bus, sizeof(uas->bus), DEVICE(dev),
&usb_uas_scsi_info, NULL);
scsi_bus_init(&uas->bus, sizeof(uas->bus), DEVICE(dev), &usb_uas_scsi_info);
}
static const VMStateDescription vmstate_usb_uas = {

View File

@ -733,8 +733,7 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
SysBusDevice *sbd = SYS_BUS_DEVICE(d);
qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS,
d, NULL);
qbus_init(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS, d, NULL);
sysbus_init_irq(sbd, &proxy->irq);
if (!kvm_eventfds_enabled()) {

View File

@ -2187,8 +2187,7 @@ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
DeviceState *qdev = DEVICE(dev);
char virtio_bus_name[] = "virtio-bus";
qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
virtio_bus_name);
qbus_init(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev, virtio_bus_name);
}
static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)

View File

@ -1398,7 +1398,7 @@ type_init(xen_register_types)
void xen_bus_init(void)
{
DeviceState *dev = qdev_new(TYPE_XEN_BRIDGE);
BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
BusState *bus = qbus_new(TYPE_XEN_BUS, dev, NULL);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
qbus_set_bus_hotplug_handler(bus);

View File

@ -702,7 +702,7 @@ int xen_be_init(void)
xen_sysdev = qdev_new(TYPE_XENSYSDEV);
sysbus_realize_and_unref(SYS_BUS_DEVICE(xen_sysdev), &error_fatal);
xen_sysbus = qbus_create(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus");
xen_sysbus = qbus_new(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus");
qbus_set_bus_hotplug_handler(xen_sysbus);
return 0;

View File

@ -24,6 +24,8 @@
#include "qom/object.h"
#include "hw/usb/xlnx-usb-subsystem.h"
#include "hw/misc/xlnx-versal-xramc.h"
#include "hw/nvram/xlnx-bbram.h"
#include "hw/nvram/xlnx-versal-efuse.h"
#define TYPE_XLNX_VERSAL "xlnx-versal"
OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
@ -79,6 +81,10 @@ struct Versal {
} iou;
XlnxZynqMPRTC rtc;
XlnxBBRam bbram;
XlnxEFuse efuse;
XlnxVersalEFuseCtrl efuse_ctrl;
XlnxVersalEFuseCache efuse_cache;
} pmc;
struct {
@ -105,8 +111,10 @@ struct Versal {
#define VERSAL_GEM1_WAKE_IRQ_0 59
#define VERSAL_ADMA_IRQ_0 60
#define VERSAL_XRAM_IRQ_0 79
#define VERSAL_BBRAM_APB_IRQ_0 121
#define VERSAL_RTC_APB_ERR_IRQ 121
#define VERSAL_SD0_IRQ_0 126
#define VERSAL_EFUSE_IRQ 139
#define VERSAL_RTC_ALARM_IRQ 142
#define VERSAL_RTC_SECONDS_IRQ 143
@ -172,6 +180,13 @@ struct Versal {
#define MM_PMC_SD0 0xf1040000U
#define MM_PMC_SD0_SIZE 0x10000
#define MM_PMC_BBRAM_CTRL 0xf11f0000
#define MM_PMC_BBRAM_CTRL_SIZE 0x00050
#define MM_PMC_EFUSE_CTRL 0xf1240000
#define MM_PMC_EFUSE_CTRL_SIZE 0x00104
#define MM_PMC_EFUSE_CACHE 0xf1250000
#define MM_PMC_EFUSE_CACHE_SIZE 0x00C00
#define MM_PMC_CRP 0xf1260000U
#define MM_PMC_CRP_SIZE 0x10000
#define MM_PMC_RTC 0xf12a0000

View File

@ -36,6 +36,8 @@
#include "qom/object.h"
#include "net/can_emu.h"
#include "hw/dma/xlnx_csu_dma.h"
#include "hw/nvram/xlnx-bbram.h"
#include "hw/nvram/xlnx-zynqmp-efuse.h"
#define TYPE_XLNX_ZYNQMP "xlnx-zynqmp"
OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP)
@ -100,6 +102,9 @@ struct XlnxZynqMPState {
MemoryRegion *ddr_ram;
MemoryRegion ddr_ram_low, ddr_ram_high;
XlnxBBRam bbram;
XlnxEFuse efuse;
XlnxZynqMPEFuse efuse_ctrl;
MemoryRegion mr_unimp[XLNX_ZYNQMP_NUM_UNIMP_AREAS];

View File

@ -648,8 +648,8 @@ void ide_atapi_cmd(IDEState *s);
void ide_atapi_cmd_reply_end(IDEState *s);
/* hw/ide/qdev.c */
void ide_bus_new(IDEBus *idebus, size_t idebus_size, DeviceState *dev,
int bus_id, int max_units);
void ide_bus_init(IDEBus *idebus, size_t idebus_size, DeviceState *dev,
int bus_id, int max_units);
IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
int ide_handle_rw_error(IDEState *s, int error, int op);

View File

@ -73,9 +73,9 @@ extern const VMStateDescription vmstate_ipack_device;
VMSTATE_STRUCT(_field, _state, 1, vmstate_ipack_device, IPackDevice)
IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot);
void ipack_bus_new_inplace(IPackBus *bus, size_t bus_size,
DeviceState *parent,
const char *name, uint8_t n_slots,
qemu_irq_handler handler);
void ipack_bus_init(IPackBus *bus, size_t bus_size,
DeviceState *parent,
uint8_t n_slots,
qemu_irq_handler handler);
#endif

View File

@ -0,0 +1,54 @@
/*
* QEMU model of the Xilinx BBRAM Battery Backed RAM
*
* Copyright (c) 2015-2021 Xilinx Inc.
*
* Written by Edgar E. Iglesias <edgari@xilinx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef XLNX_BBRAM_H
#define XLNX_BBRAM_H
#include "sysemu/block-backend.h"
#include "hw/qdev-core.h"
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/register.h"
#define RMAX_XLNX_BBRAM ((0x4c / 4) + 1)
#define TYPE_XLNX_BBRAM "xlnx,bbram-ctrl"
OBJECT_DECLARE_SIMPLE_TYPE(XlnxBBRam, XLNX_BBRAM);
struct XlnxBBRam {
SysBusDevice parent_obj;
qemu_irq irq_bbram;
BlockBackend *blk;
uint32_t crc_zpads;
bool bbram8_wo;
bool blk_ro;
uint32_t regs[RMAX_XLNX_BBRAM];
RegisterInfo regs_info[RMAX_XLNX_BBRAM];
};
#endif

View File

@ -0,0 +1,132 @@
/*
* QEMU model of the Xilinx eFuse core
*
* Copyright (c) 2015 Xilinx Inc.
*
* Written by Edgar E. Iglesias <edgari@xilinx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef XLNX_EFUSE_H
#define XLNX_EFUSE_H
#include "sysemu/block-backend.h"
#include "hw/qdev-core.h"
#define TYPE_XLNX_EFUSE "xlnx,efuse"
OBJECT_DECLARE_SIMPLE_TYPE(XlnxEFuse, XLNX_EFUSE);
struct XlnxEFuse {
DeviceState parent_obj;
BlockBackend *blk;
bool blk_ro;
uint32_t *fuse32;
DeviceState *dev;
bool init_tbits;
uint8_t efuse_nr;
uint32_t efuse_size;
uint32_t *ro_bits;
uint32_t ro_bits_cnt;
};
/**
* xlnx_efuse_calc_crc:
* @data: an array of 32-bit words for which the CRC should be computed
* @u32_cnt: the array size in number of 32-bit words
* @zpads: the number of 32-bit zeros prepended to @data before computation
*
* This function is used to compute the CRC for an array of 32-bit words,
* using a Xilinx-specific data padding.
*
* Returns: the computed 32-bit CRC
*/
uint32_t xlnx_efuse_calc_crc(const uint32_t *data, unsigned u32_cnt,
unsigned zpads);
/**
* xlnx_efuse_get_bit:
* @s: the efuse object
* @bit: the efuse bit-address to read the data
*
* Returns: the bit, 0 or 1, at @bit of object @s
*/
bool xlnx_efuse_get_bit(XlnxEFuse *s, unsigned int bit);
/**
* xlnx_efuse_set_bit:
* @s: the efuse object
* @bit: the efuse bit-address to be written a value of 1
*
* Returns: true on success, false on failure
*/
bool xlnx_efuse_set_bit(XlnxEFuse *s, unsigned int bit);
/**
* xlnx_efuse_k256_check:
* @s: the efuse object
* @crc: the 32-bit CRC to be compared with
* @start: the efuse bit-address (which must be multiple of 32) of the
* start of a 256-bit array
*
* This function computes the CRC of a 256-bit array starting at @start
* then compares to the given @crc
*
* Returns: true of @crc == computed, false otherwise
*/
bool xlnx_efuse_k256_check(XlnxEFuse *s, uint32_t crc, unsigned start);
/**
* xlnx_efuse_tbits_check:
* @s: the efuse object
*
* This function inspects a number of efuse bits at specific addresses
* to see if they match a validation pattern. Each pattern is a group
* of 4 bits, and there are 3 groups.
*
* Returns: a 3-bit mask, where a bit of '1' means the corresponding
* group has a valid pattern.
*/
uint32_t xlnx_efuse_tbits_check(XlnxEFuse *s);
/**
* xlnx_efuse_get_row:
* @s: the efuse object
* @bit: the efuse bit address for which a 32-bit value is read
*
* Returns: the entire 32 bits of the efuse, starting at a bit
* address that is multiple of 32 and contains the bit at @bit
*/
static inline uint32_t xlnx_efuse_get_row(XlnxEFuse *s, unsigned int bit)
{
if (!(s->fuse32)) {
return 0;
} else {
unsigned int row_idx = bit / 32;
assert(row_idx < (s->efuse_size * s->efuse_nr / 32));
return s->fuse32[row_idx];
}
}
#endif

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2020 Xilinx Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef XLNX_VERSAL_EFUSE_H
#define XLNX_VERSAL_EFUSE_H
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/register.h"
#include "hw/nvram/xlnx-efuse.h"
#define XLNX_VERSAL_EFUSE_CTRL_R_MAX ((0x100 / 4) + 1)
#define TYPE_XLNX_VERSAL_EFUSE_CTRL "xlnx,versal-efuse"
#define TYPE_XLNX_VERSAL_EFUSE_CACHE "xlnx,pmc-efuse-cache"
OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalEFuseCtrl, XLNX_VERSAL_EFUSE_CTRL);
OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalEFuseCache, XLNX_VERSAL_EFUSE_CACHE);
struct XlnxVersalEFuseCtrl {
SysBusDevice parent_obj;
qemu_irq irq_efuse_imr;
XlnxEFuse *efuse;
void *extra_pg0_lock_spec; /* Opaque property */
uint32_t extra_pg0_lock_n16;
uint32_t regs[XLNX_VERSAL_EFUSE_CTRL_R_MAX];
RegisterInfo regs_info[XLNX_VERSAL_EFUSE_CTRL_R_MAX];
};
struct XlnxVersalEFuseCache {
SysBusDevice parent_obj;
MemoryRegion iomem;
XlnxEFuse *efuse;
};
/**
* xlnx_versal_efuse_read_row:
* @s: the efuse object
* @bit: the bit-address within the 32-bit row to be read
* @denied: if non-NULL, to receive true if the row is write-only
*
* Returns: the 32-bit word containing address @bit; 0 if @denies is true
*/
uint32_t xlnx_versal_efuse_read_row(XlnxEFuse *s, uint32_t bit, bool *denied);
#endif

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2021 Xilinx Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef XLNX_ZYNQMP_EFUSE_H
#define XLNX_ZYNQMP_EFUSE_H
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/register.h"
#include "hw/nvram/xlnx-efuse.h"
#define XLNX_ZYNQMP_EFUSE_R_MAX ((0x10fc / 4) + 1)
#define TYPE_XLNX_ZYNQMP_EFUSE "xlnx,zynqmp-efuse"
OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPEFuse, XLNX_ZYNQMP_EFUSE);
struct XlnxZynqMPEFuse {
SysBusDevice parent_obj;
qemu_irq irq;
XlnxEFuse *efuse;
uint32_t regs[XLNX_ZYNQMP_EFUSE_R_MAX];
RegisterInfo regs_info[XLNX_ZYNQMP_EFUSE_R_MAX];
};
#endif

Some files were not shown because too many files have changed in this diff Show More