* [PATCH v5 01/11] MAX78000: Add MAX78000FTHR Machine
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 02/11] MAX78000: ICC Implementation Jackson Donaldson
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This patch adds support for the MAX78000FTHR machine.
The MAX78000FTHR contains a MAX78000 and a RISC-V core. This patch
implements only the MAX78000, which is Cortex-M4 based.
Details can be found at:
https://www.analog.com/media/en/technical-documentation/user-guides/max78000-user-guide.pdf
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/Kconfig | 10 ++
hw/arm/max78000_soc.c | 172 ++++++++++++++++++++++++++++++++++
hw/arm/max78000fthr.c | 50 ++++++++++
hw/arm/meson.build | 2 +
include/hw/arm/max78000_soc.h | 35 +++++++
5 files changed, 269 insertions(+)
create mode 100644 hw/arm/max78000_soc.c
create mode 100644 hw/arm/max78000fthr.c
create mode 100644 include/hw/arm/max78000_soc.h
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index f543d944c3..ddaafa8faa 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -95,6 +95,12 @@ config INTEGRATOR
select PL181 # display
select SMC91C111
+config MAX78000FTHR
+ bool
+ default y
+ depends on TCG && ARM
+ select MAX78000_SOC
+
config MPS3R
bool
default y
@@ -357,6 +363,10 @@ config ALLWINNER_R40
select USB_EHCI_SYSBUS
select SD
+config MAX78000_SOC
+ bool
+ select ARM_V7M
+
config RASPI
bool
default y
diff --git a/hw/arm/max78000_soc.c b/hw/arm/max78000_soc.c
new file mode 100644
index 0000000000..9676ada6a2
--- /dev/null
+++ b/hw/arm/max78000_soc.c
@@ -0,0 +1,172 @@
+/*
+ * MAX78000 SOC
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Implementation based on stm32f205 and Max78000 user guide at
+ * https://www.analog.com/media/en/technical-documentation/user-guides/max78000-user-guide.pdf
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "system/address-spaces.h"
+#include "system/system.h"
+#include "hw/arm/max78000_soc.h"
+#include "hw/qdev-clock.h"
+#include "hw/misc/unimp.h"
+
+static void max78000_soc_initfn(Object *obj)
+{
+ MAX78000State *s = MAX78000_SOC(obj);
+
+ object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
+
+ s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
+}
+
+static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+ MAX78000State *s = MAX78000_SOC(dev_soc);
+ MemoryRegion *system_memory = get_system_memory();
+ DeviceState *armv7m;
+ Error *err = NULL;
+
+ if (!clock_has_source(s->sysclk)) {
+ error_setg(errp, "sysclk clock must be wired up by the board code");
+ return;
+ }
+
+ memory_region_init_rom(&s->flash, OBJECT(dev_soc), "MAX78000.flash",
+ FLASH_SIZE, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash);
+
+ memory_region_init_ram(&s->sram, NULL, "MAX78000.sram", SRAM_SIZE,
+ &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);
+
+ armv7m = DEVICE(&s->armv7m);
+
+ /*
+ * The MAX78000 user guide's Interrupt Vector Table section
+ * suggests that there are 120 IRQs in the text, while only listing
+ * 104 in table 5-1. Implement the more generous of the two.
+ * This has not been tested in hardware.
+ */
+ qdev_prop_set_uint32(armv7m, "num-irq", 120);
+ qdev_prop_set_uint8(armv7m, "num-prio-bits", 3);
+ qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
+ qdev_prop_set_bit(armv7m, "enable-bitband", true);
+ qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
+ object_property_set_link(OBJECT(&s->armv7m), "memory",
+ OBJECT(system_memory), &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
+ return;
+ }
+
+ create_unimplemented_device("globalControl", 0x40000000, 0x400);
+ create_unimplemented_device("systemInterface", 0x40000400, 0x400);
+ create_unimplemented_device("functionControl", 0x40000800, 0x400);
+ create_unimplemented_device("watchdogTimer0", 0x40003000, 0x400);
+ create_unimplemented_device("dynamicVoltScale", 0x40003c00, 0x40);
+ create_unimplemented_device("SIMO", 0x40004400, 0x400);
+ create_unimplemented_device("trimSystemInit", 0x40005400, 0x400);
+ create_unimplemented_device("generalCtrlFunc", 0x40005800, 0x400);
+ create_unimplemented_device("wakeupTimer", 0x40006400, 0x400);
+ create_unimplemented_device("powerSequencer", 0x40006800, 0x400);
+ create_unimplemented_device("miscControl", 0x40006c00, 0x400);
+
+ create_unimplemented_device("aes", 0x40007400, 0x400);
+ create_unimplemented_device("aesKey", 0x40007800, 0x400);
+
+ create_unimplemented_device("gpio0", 0x40008000, 0x1000);
+ create_unimplemented_device("gpio1", 0x40009000, 0x1000);
+
+ create_unimplemented_device("parallelCamInterface", 0x4000e000, 0x1000);
+ create_unimplemented_device("CRC", 0x4000f000, 0x1000);
+
+ create_unimplemented_device("timer0", 0x40010000, 0x1000);
+ create_unimplemented_device("timer1", 0x40011000, 0x1000);
+ create_unimplemented_device("timer2", 0x40012000, 0x1000);
+ create_unimplemented_device("timer3", 0x40013000, 0x1000);
+
+ create_unimplemented_device("i2c0", 0x4001d000, 0x1000);
+ create_unimplemented_device("i2c1", 0x4001e000, 0x1000);
+ create_unimplemented_device("i2c2", 0x4001f000, 0x1000);
+
+ create_unimplemented_device("standardDMA", 0x40028000, 0x1000);
+ create_unimplemented_device("flashController0", 0x40029000, 0x400);
+
+ create_unimplemented_device("icc0", 0x4002a000, 0x800);
+ create_unimplemented_device("icc1", 0x4002a800, 0x800);
+
+ create_unimplemented_device("adc", 0x40034000, 0x1000);
+ create_unimplemented_device("pulseTrainEngine", 0x4003c000, 0xa0);
+ create_unimplemented_device("oneWireMaster", 0x4003d000, 0x1000);
+ create_unimplemented_device("semaphore", 0x4003e000, 0x1000);
+
+ create_unimplemented_device("uart0", 0x40042000, 0x1000);
+ create_unimplemented_device("uart1", 0x40043000, 0x1000);
+ create_unimplemented_device("uart2", 0x40044000, 0x1000);
+
+ create_unimplemented_device("spi1", 0x40046000, 0x2000);
+ create_unimplemented_device("trng", 0x4004d000, 0x1000);
+ create_unimplemented_device("i2s", 0x40060000, 0x1000);
+ create_unimplemented_device("lowPowerControl", 0x40080000, 0x400);
+ create_unimplemented_device("gpio2", 0x40080400, 0x200);
+ create_unimplemented_device("lowPowerWatchdogTimer", 0x40080800, 0x400);
+ create_unimplemented_device("lowPowerTimer4", 0x40080c00, 0x400);
+
+ create_unimplemented_device("lowPowerTimer5", 0x40081000, 0x400);
+ create_unimplemented_device("lowPowerUART0", 0x40081400, 0x400);
+ create_unimplemented_device("lowPowerComparator", 0x40088000, 0x400);
+
+ create_unimplemented_device("spi0", 0x400be000, 0x400);
+
+ /*
+ * The MAX78000 user guide's base address map lists the CNN TX FIFO as
+ * beginning at 0x400c0400 and ending at 0x400c0400. Given that CNN_FIFO
+ * is listed as having data accessible up to offset 0x1000, the user
+ * guide is likely incorrect.
+ */
+ create_unimplemented_device("cnnTxFIFO", 0x400c0400, 0x2000);
+
+ create_unimplemented_device("cnnGlobalControl", 0x50000000, 0x10000);
+ create_unimplemented_device("cnnx16quad0", 0x50100000, 0x40000);
+ create_unimplemented_device("cnnx16quad1", 0x50500000, 0x40000);
+ create_unimplemented_device("cnnx16quad2", 0x50900000, 0x40000);
+ create_unimplemented_device("cnnx16quad3", 0x50d00000, 0x40000);
+
+}
+
+static void max78000_soc_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = max78000_soc_realize;
+}
+
+static const TypeInfo max78000_soc_info = {
+ .name = TYPE_MAX78000_SOC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MAX78000State),
+ .instance_init = max78000_soc_initfn,
+ .class_init = max78000_soc_class_init,
+};
+
+static void max78000_soc_types(void)
+{
+ type_register_static(&max78000_soc_info);
+}
+
+type_init(max78000_soc_types)
diff --git a/hw/arm/max78000fthr.c b/hw/arm/max78000fthr.c
new file mode 100644
index 0000000000..c4f6b5b1b0
--- /dev/null
+++ b/hw/arm/max78000fthr.c
@@ -0,0 +1,50 @@
+/*
+ * MAX78000FTHR Evaluation Board
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
+#include "qemu/error-report.h"
+#include "hw/arm/max78000_soc.h"
+#include "hw/arm/boot.h"
+
+/* 60MHz is the default, but other clocks can be selected. */
+#define SYSCLK_FRQ 60000000ULL
+static void max78000_init(MachineState *machine)
+{
+ DeviceState *dev;
+ Clock *sysclk;
+
+ sysclk = clock_new(OBJECT(machine), "SYSCLK");
+ clock_set_hz(sysclk, SYSCLK_FRQ);
+
+ dev = qdev_new(TYPE_MAX78000_SOC);
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(dev));
+ qdev_connect_clock_in(dev, "sysclk", sysclk);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ armv7m_load_kernel(ARM_CPU(first_cpu),
+ machine->kernel_filename,
+ 0x00000000, FLASH_SIZE);
+}
+
+static void max78000_machine_init(MachineClass *mc)
+{
+ static const char * const valid_cpu_types[] = {
+ ARM_CPU_TYPE_NAME("cortex-m4"),
+ NULL
+ };
+
+ mc->desc = "MAX78000FTHR Board (Cortex-M4 / (Unimplemented) RISC-V)";
+ mc->init = max78000_init;
+ mc->valid_cpu_types = valid_cpu_types;
+}
+
+DEFINE_MACHINE("max78000fthr", max78000_machine_init)
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index d90be8f4c9..dc68391305 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -27,6 +27,7 @@ arm_common_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c'))
arm_common_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
arm_common_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c'))
arm_common_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40.c', 'bananapi_m2u.c'))
+arm_common_ss.add(when: 'CONFIG_MAX78000_SOC', if_true: files('max78000_soc.c'))
arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.c'))
arm_common_ss.add(when: ['CONFIG_RASPI', 'TARGET_AARCH64'], if_true: files('bcm2838.c', 'raspi4b.c'))
arm_common_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c'))
@@ -71,6 +72,7 @@ arm_ss.add(when: 'CONFIG_XEN', if_true: files(
arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
arm_common_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c'))
arm_common_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
+arm_common_ss.add(when: 'CONFIG_MAX78000FTHR', if_true: files('max78000fthr.c'))
arm_common_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c'))
arm_common_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
arm_common_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c'))
diff --git a/include/hw/arm/max78000_soc.h b/include/hw/arm/max78000_soc.h
new file mode 100644
index 0000000000..97bf4099c9
--- /dev/null
+++ b/include/hw/arm/max78000_soc.h
@@ -0,0 +1,35 @@
+/*
+ * MAX78000 SOC
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_ARM_MAX78000_SOC_H
+#define HW_ARM_MAX78000_SOC_H
+
+#include "hw/or-irq.h"
+#include "hw/arm/armv7m.h"
+#include "qom/object.h"
+
+#define TYPE_MAX78000_SOC "max78000-soc"
+OBJECT_DECLARE_SIMPLE_TYPE(MAX78000State, MAX78000_SOC)
+
+#define FLASH_BASE_ADDRESS 0x10000000
+#define FLASH_SIZE (512 * 1024)
+#define SRAM_BASE_ADDRESS 0x20000000
+#define SRAM_SIZE (128 * 1024)
+
+struct MAX78000State {
+ SysBusDevice parent_obj;
+
+ ARMv7MState armv7m;
+
+ MemoryRegion sram;
+ MemoryRegion flash;
+
+ Clock *sysclk;
+};
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 02/11] MAX78000: ICC Implementation
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 01/11] MAX78000: Add MAX78000FTHR Machine Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 03/11] MAX78000: Add ICC to SOC Jackson Donaldson
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit implements the Instruction Cache Controller
for the MAX78000
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/Kconfig | 1 +
hw/misc/Kconfig | 3 +
hw/misc/max78000_icc.c | 120 +++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
include/hw/misc/max78000_icc.h | 33 +++++++++
5 files changed, 158 insertions(+)
create mode 100644 hw/misc/max78000_icc.c
create mode 100644 include/hw/misc/max78000_icc.h
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index ddaafa8faa..e3b419b468 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -366,6 +366,7 @@ config ALLWINNER_R40
config MAX78000_SOC
bool
select ARM_V7M
+ select MAX78000_ICC
config RASPI
bool
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index ec0fa5aa9f..781bcf74cc 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -47,6 +47,9 @@ config A9SCU
config ARM11SCU
bool
+config MAX78000_ICC
+ bool
+
config MOS6522
bool
diff --git a/hw/misc/max78000_icc.c b/hw/misc/max78000_icc.c
new file mode 100644
index 0000000000..6f7d2b20bf
--- /dev/null
+++ b/hw/misc/max78000_icc.c
@@ -0,0 +1,120 @@
+/*
+ * MAX78000 Instruction Cache
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/max78000_icc.h"
+
+
+static uint64_t max78000_icc_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ Max78000IccState *s = opaque;
+ switch (addr) {
+ case ICC_INFO:
+ return s->info;
+
+ case ICC_SZ:
+ return s->sz;
+
+ case ICC_CTRL:
+ return s->ctrl;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ return 0;
+
+ }
+}
+
+static void max78000_icc_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ Max78000IccState *s = opaque;
+
+ switch (addr) {
+ case ICC_CTRL:
+ s->ctrl = 0x10000 | (val64 & 1);
+ break;
+
+ case ICC_INVALIDATE:
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps max78000_icc_ops = {
+ .read = max78000_icc_read,
+ .write = max78000_icc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static const VMStateDescription max78000_icc_vmstate = {
+ .name = TYPE_MAX78000_ICC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(info, Max78000IccState),
+ VMSTATE_UINT32(sz, Max78000IccState),
+ VMSTATE_UINT32(ctrl, Max78000IccState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void max78000_icc_reset_hold(Object *obj, ResetType type)
+{
+ Max78000IccState *s = MAX78000_ICC(obj);
+ s->info = 0;
+ s->sz = 0x10000010;
+ s->ctrl = 0x10000;
+}
+
+static void max78000_icc_init(Object *obj)
+{
+ Max78000IccState *s = MAX78000_ICC(obj);
+
+ memory_region_init_io(&s->mmio, obj, &max78000_icc_ops, s,
+ TYPE_MAX78000_ICC, 0x800);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void max78000_icc_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = max78000_icc_reset_hold;
+ dc->vmsd = &max78000_icc_vmstate;
+}
+
+static const TypeInfo max78000_icc_info = {
+ .name = TYPE_MAX78000_ICC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Max78000IccState),
+ .instance_init = max78000_icc_init,
+ .class_init = max78000_icc_class_init,
+};
+
+static void max78000_icc_register_types(void)
+{
+ type_register_static(&max78000_icc_info);
+}
+
+type_init(max78000_icc_register_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 6d47de482c..a21a994ff8 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -70,6 +70,7 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx_ccm.c',
'imx_rngc.c',
))
+system_ss.add(when: 'CONFIG_MAX78000_ICC', if_true: files('max78000_icc.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
'npcm_clk.c',
'npcm_gcr.c',
diff --git a/include/hw/misc/max78000_icc.h b/include/hw/misc/max78000_icc.h
new file mode 100644
index 0000000000..6fe2bb7a15
--- /dev/null
+++ b/include/hw/misc/max78000_icc.h
@@ -0,0 +1,33 @@
+/*
+ * MAX78000 Instruction Cache
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MAX78000_ICC_H
+#define HW_MAX78000_ICC_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_MAX78000_ICC "max78000-icc"
+OBJECT_DECLARE_SIMPLE_TYPE(Max78000IccState, MAX78000_ICC)
+
+#define ICC_INFO 0x0
+#define ICC_SZ 0x4
+#define ICC_CTRL 0x100
+#define ICC_INVALIDATE 0x700
+
+struct Max78000IccState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+
+ uint32_t info;
+ uint32_t sz;
+ uint32_t ctrl;
+};
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 03/11] MAX78000: Add ICC to SOC
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 01/11] MAX78000: Add MAX78000FTHR Machine Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 02/11] MAX78000: ICC Implementation Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 04/11] MAX78000: UART Implementation Jackson Donaldson
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit adds the instruction cache controller
to max78000_soc
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/max78000_soc.c | 20 ++++++++++++++++----
include/hw/arm/max78000_soc.h | 6 ++++++
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/hw/arm/max78000_soc.c b/hw/arm/max78000_soc.c
index 9676ada6a2..0c83b08eca 100644
--- a/hw/arm/max78000_soc.c
+++ b/hw/arm/max78000_soc.c
@@ -17,12 +17,20 @@
#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
+static const uint32_t max78000_icc_addr[] = {0x4002a000, 0x4002a800};
+
static void max78000_soc_initfn(Object *obj)
{
MAX78000State *s = MAX78000_SOC(obj);
+ int i;
object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
+ for (i = 0; i < MAX78000_NUM_ICC; i++) {
+ g_autofree char *name = g_strdup_printf("icc%d", i);
+ object_initialize_child(obj, name, &s->icc[i], TYPE_MAX78000_ICC);
+ }
+
s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
}
@@ -30,8 +38,9 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
{
MAX78000State *s = MAX78000_SOC(dev_soc);
MemoryRegion *system_memory = get_system_memory();
- DeviceState *armv7m;
+ DeviceState *dev, *armv7m;
Error *err = NULL;
+ int i;
if (!clock_has_source(s->sysclk)) {
error_setg(errp, "sysclk clock must be wired up by the board code");
@@ -74,6 +83,12 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
return;
}
+ for (i = 0; i < MAX78000_NUM_ICC; i++) {
+ dev = DEVICE(&(s->icc[i]));
+ sysbus_realize(SYS_BUS_DEVICE(dev), errp);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, max78000_icc_addr[i]);
+ }
+
create_unimplemented_device("globalControl", 0x40000000, 0x400);
create_unimplemented_device("systemInterface", 0x40000400, 0x400);
create_unimplemented_device("functionControl", 0x40000800, 0x400);
@@ -107,9 +122,6 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("standardDMA", 0x40028000, 0x1000);
create_unimplemented_device("flashController0", 0x40029000, 0x400);
- create_unimplemented_device("icc0", 0x4002a000, 0x800);
- create_unimplemented_device("icc1", 0x4002a800, 0x800);
-
create_unimplemented_device("adc", 0x40034000, 0x1000);
create_unimplemented_device("pulseTrainEngine", 0x4003c000, 0xa0);
create_unimplemented_device("oneWireMaster", 0x4003d000, 0x1000);
diff --git a/include/hw/arm/max78000_soc.h b/include/hw/arm/max78000_soc.h
index 97bf4099c9..27b506d6ee 100644
--- a/include/hw/arm/max78000_soc.h
+++ b/include/hw/arm/max78000_soc.h
@@ -11,6 +11,7 @@
#include "hw/or-irq.h"
#include "hw/arm/armv7m.h"
+#include "hw/misc/max78000_icc.h"
#include "qom/object.h"
#define TYPE_MAX78000_SOC "max78000-soc"
@@ -21,6 +22,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(MAX78000State, MAX78000_SOC)
#define SRAM_BASE_ADDRESS 0x20000000
#define SRAM_SIZE (128 * 1024)
+/* The MAX78k has 2 instruction caches; only icc0 matters, icc1 is for RISC */
+#define MAX78000_NUM_ICC 2
+
struct MAX78000State {
SysBusDevice parent_obj;
@@ -29,6 +33,8 @@ struct MAX78000State {
MemoryRegion sram;
MemoryRegion flash;
+ Max78000IccState icc[MAX78000_NUM_ICC];
+
Clock *sysclk;
};
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 04/11] MAX78000: UART Implementation
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (2 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 03/11] MAX78000: Add ICC to SOC Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 05/11] MAX78000: Add UART to SOC Jackson Donaldson
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit implements UART support for the MAX78000
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/Kconfig | 1 +
hw/char/Kconfig | 3 +
hw/char/max78000_uart.c | 285 ++++++++++++++++++++++++++++++++
hw/char/meson.build | 1 +
include/hw/char/max78000_uart.h | 78 +++++++++
5 files changed, 368 insertions(+)
create mode 100644 hw/char/max78000_uart.c
create mode 100644 include/hw/char/max78000_uart.h
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index e3b419b468..031e0bf59e 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -367,6 +367,7 @@ config MAX78000_SOC
bool
select ARM_V7M
select MAX78000_ICC
+ select MAX78000_UART
config RASPI
bool
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 9d517f3e28..020c0a84bb 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -48,6 +48,9 @@ config VIRTIO_SERIAL
default y
depends on VIRTIO
+config MAX78000_UART
+ bool
+
config STM32F2XX_USART
bool
diff --git a/hw/char/max78000_uart.c b/hw/char/max78000_uart.c
new file mode 100644
index 0000000000..19506d52ef
--- /dev/null
+++ b/hw/char/max78000_uart.c
@@ -0,0 +1,285 @@
+/*
+ * MAX78000 UART
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/max78000_uart.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+
+static int max78000_uart_can_receive(void *opaque)
+{
+ Max78000UartState *s = opaque;
+ if (!(s->ctrl & UART_BCLKEN)) {
+ return 0;
+ }
+ return fifo8_num_free(&s->rx_fifo);
+}
+
+static void max78000_update_irq(Max78000UartState *s)
+{
+ int interrupt_level;
+
+ interrupt_level = s->int_fl & s->int_en;
+ qemu_set_irq(s->irq, interrupt_level);
+}
+
+static void max78000_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ Max78000UartState *s = opaque;
+
+ assert(size <= fifo8_num_free(&s->rx_fifo));
+
+ fifo8_push_all(&s->rx_fifo, buf, size);
+
+ uint32_t rx_threshold = s->ctrl & 0xf;
+
+ if (fifo8_num_used(&s->rx_fifo) >= rx_threshold) {
+ s->int_fl |= UART_RX_THD;
+ }
+
+ max78000_update_irq(s);
+}
+
+static void max78000_uart_reset_hold(Object *obj, ResetType type)
+{
+ Max78000UartState *s = MAX78000_UART(obj);
+
+ s->ctrl = 0;
+ s->status = UART_TX_EM | UART_RX_EM;
+ s->int_en = 0;
+ s->int_fl = 0;
+ s->osr = 0;
+ s->txpeek = 0;
+ s->pnr = UART_RTS;
+ s->fifo = 0;
+ s->dma = 0;
+ s->wken = 0;
+ s->wkfl = 0;
+ fifo8_reset(&s->rx_fifo);
+}
+
+static uint64_t max78000_uart_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ Max78000UartState *s = opaque;
+ uint64_t retvalue = 0;
+ switch (addr) {
+ case UART_CTRL:
+ retvalue = s->ctrl;
+ break;
+ case UART_STATUS:
+ retvalue = (fifo8_num_used(&s->rx_fifo) << UART_RX_LVL) |
+ UART_TX_EM |
+ (fifo8_is_empty(&s->rx_fifo) ? UART_RX_EM : 0);
+ break;
+ case UART_INT_EN:
+ retvalue = s->int_en;
+ break;
+ case UART_INT_FL:
+ retvalue = s->int_fl;
+ break;
+ case UART_CLKDIV:
+ retvalue = s->clkdiv;
+ break;
+ case UART_OSR:
+ retvalue = s->osr;
+ break;
+ case UART_TXPEEK:
+ if (!fifo8_is_empty(&s->rx_fifo)) {
+ retvalue = fifo8_peek(&s->rx_fifo);
+ }
+ break;
+ case UART_PNR:
+ retvalue = s->pnr;
+ break;
+ case UART_FIFO:
+ if (!fifo8_is_empty(&s->rx_fifo)) {
+ retvalue = fifo8_pop(&s->rx_fifo);
+ max78000_update_irq(s);
+ }
+ break;
+ case UART_DMA:
+ /* DMA not implemented */
+ retvalue = s->dma;
+ break;
+ case UART_WKEN:
+ retvalue = s->wken;
+ break;
+ case UART_WKFL:
+ retvalue = s->wkfl;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ break;
+ }
+
+ return retvalue;
+}
+
+static void max78000_uart_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ Max78000UartState *s = opaque;
+
+ uint32_t value = val64;
+ uint8_t data;
+
+ switch (addr) {
+ case UART_CTRL:
+ if (value & UART_FLUSH_RX) {
+ fifo8_reset(&s->rx_fifo);
+ }
+ if (value & UART_BCLKEN) {
+ value = value | UART_BCLKRDY;
+ }
+ s->ctrl = value & ~(UART_FLUSH_RX | UART_FLUSH_TX);
+
+ /*
+ * Software can manage UART flow control manually by setting hfc_en
+ * in UART_CTRL. This would require emulating uart at a lower level,
+ * and is currently unimplemented.
+ */
+
+ return;
+ case UART_STATUS:
+ /* UART_STATUS is read only */
+ return;
+ case UART_INT_EN:
+ s->int_en = value;
+ return;
+ case UART_INT_FL:
+ s->int_fl = s->int_fl & ~(value);
+ max78000_update_irq(s);
+ return;
+ case UART_CLKDIV:
+ s->clkdiv = value;
+ return;
+ case UART_OSR:
+ s->osr = value;
+ return;
+ case UART_PNR:
+ s->pnr = value;
+ return;
+ case UART_FIFO:
+ data = value & 0xff;
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &data, 1);
+
+ /* TX is always empty */
+ s->int_fl |= UART_TX_HE;
+ max78000_update_irq(s);
+
+ return;
+ case UART_DMA:
+ /* DMA not implemented */
+ s->dma = value;
+ return;
+ case UART_WKEN:
+ s->wken = value;
+ return;
+ case UART_WKFL:
+ s->wkfl = value;
+ return;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ }
+}
+
+static const MemoryRegionOps max78000_uart_ops = {
+ .read = max78000_uart_read,
+ .write = max78000_uart_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static const Property max78000_uart_properties[] = {
+ DEFINE_PROP_CHR("chardev", Max78000UartState, chr),
+};
+
+static const VMStateDescription max78000_uart_vmstate = {
+ .name = TYPE_MAX78000_UART,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ctrl, Max78000UartState),
+ VMSTATE_UINT32(status, Max78000UartState),
+ VMSTATE_UINT32(int_en, Max78000UartState),
+ VMSTATE_UINT32(int_fl, Max78000UartState),
+ VMSTATE_UINT32(clkdiv, Max78000UartState),
+ VMSTATE_UINT32(osr, Max78000UartState),
+ VMSTATE_UINT32(txpeek, Max78000UartState),
+ VMSTATE_UINT32(pnr, Max78000UartState),
+ VMSTATE_UINT32(fifo, Max78000UartState),
+ VMSTATE_UINT32(dma, Max78000UartState),
+ VMSTATE_UINT32(wken, Max78000UartState),
+ VMSTATE_UINT32(wkfl, Max78000UartState),
+ VMSTATE_FIFO8(rx_fifo, Max78000UartState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void max78000_uart_init(Object *obj)
+{
+ Max78000UartState *s = MAX78000_UART(obj);
+ fifo8_create(&s->rx_fifo, 8);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &max78000_uart_ops, s,
+ TYPE_MAX78000_UART, 0x400);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void max78000_uart_realize(DeviceState *dev, Error **errp)
+{
+ Max78000UartState *s = MAX78000_UART(dev);
+
+ qemu_chr_fe_set_handlers(&s->chr, max78000_uart_can_receive,
+ max78000_uart_receive, NULL, NULL,
+ s, NULL, true);
+}
+
+static void max78000_uart_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = max78000_uart_reset_hold;
+
+ device_class_set_props(dc, max78000_uart_properties);
+ dc->realize = max78000_uart_realize;
+
+ dc->vmsd = &max78000_uart_vmstate;
+}
+
+static const TypeInfo max78000_uart_info = {
+ .name = TYPE_MAX78000_UART,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Max78000UartState),
+ .instance_init = max78000_uart_init,
+ .class_init = max78000_uart_class_init,
+};
+
+static void max78000_uart_register_types(void)
+{
+ type_register_static(&max78000_uart_info);
+}
+
+type_init(max78000_uart_register_types)
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 4e439da8b9..a9e1dc26c0 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -26,6 +26,7 @@ system_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c'))
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_uart.c'))
system_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic-uart.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_uart.c'))
+system_ss.add(when: 'CONFIG_MAX78000_UART', if_true: files('max78000_uart.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_uart.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_aux.c'))
system_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c'))
diff --git a/include/hw/char/max78000_uart.h b/include/hw/char/max78000_uart.h
new file mode 100644
index 0000000000..cf90d51dbf
--- /dev/null
+++ b/include/hw/char/max78000_uart.h
@@ -0,0 +1,78 @@
+/*
+ * MAX78000 UART
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MAX78000_UART_H
+#define HW_MAX78000_UART_H
+
+#include "hw/sysbus.h"
+#include "chardev/char-fe.h"
+#include "qemu/fifo8.h"
+#include "qom/object.h"
+
+#define UART_CTRL 0x0
+#define UART_STATUS 0x4
+#define UART_INT_EN 0x8
+#define UART_INT_FL 0xc
+#define UART_CLKDIV 0x10
+#define UART_OSR 0x14
+#define UART_TXPEEK 0x18
+#define UART_PNR 0x1c
+#define UART_FIFO 0x20
+#define UART_DMA 0x30
+#define UART_WKEN 0x34
+#define UART_WKFL 0x38
+
+/* CTRL */
+#define UART_CTF_DIS (1 << 7)
+#define UART_FLUSH_TX (1 << 8)
+#define UART_FLUSH_RX (1 << 9)
+#define UART_BCLKEN (1 << 15)
+#define UART_BCLKRDY (1 << 19)
+
+/* STATUS */
+#define UART_RX_LVL 8
+#define UART_TX_EM (1 << 6)
+#define UART_RX_FULL (1 << 5)
+#define UART_RX_EM (1 << 4)
+
+/* PNR (Pin Control Register) */
+#define UART_CTS 1
+#define UART_RTS (1 << 1)
+
+/* INT_EN / INT_FL */
+#define UART_RX_THD (1 << 4)
+#define UART_TX_HE (1 << 6)
+
+#define UART_RXBUFLEN 0x100
+#define TYPE_MAX78000_UART "max78000-uart"
+OBJECT_DECLARE_SIMPLE_TYPE(Max78000UartState, MAX78000_UART)
+
+struct Max78000UartState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t int_en;
+ uint32_t int_fl;
+ uint32_t clkdiv;
+ uint32_t osr;
+ uint32_t txpeek;
+ uint32_t pnr;
+ uint32_t fifo;
+ uint32_t dma;
+ uint32_t wken;
+ uint32_t wkfl;
+
+ Fifo8 rx_fifo;
+
+ CharBackend chr;
+ qemu_irq irq;
+};
+#endif /* HW_STM32F2XX_USART_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 05/11] MAX78000: Add UART to SOC
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (3 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 04/11] MAX78000: UART Implementation Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 06/11] MAX78000: GCR Implementation Jackson Donaldson
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit adds UART to max78000_soc
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/max78000_soc.c | 28 ++++++++++++++++++++++++----
include/hw/arm/max78000_soc.h | 3 +++
2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/hw/arm/max78000_soc.c b/hw/arm/max78000_soc.c
index 0c83b08eca..2f93ab882d 100644
--- a/hw/arm/max78000_soc.c
+++ b/hw/arm/max78000_soc.c
@@ -18,6 +18,10 @@
#include "hw/misc/unimp.h"
static const uint32_t max78000_icc_addr[] = {0x4002a000, 0x4002a800};
+static const uint32_t max78000_uart_addr[] = {0x40042000, 0x40043000,
+ 0x40044000};
+
+static const int max78000_uart_irq[] = {14, 15, 34};
static void max78000_soc_initfn(Object *obj)
{
@@ -31,6 +35,12 @@ static void max78000_soc_initfn(Object *obj)
object_initialize_child(obj, name, &s->icc[i], TYPE_MAX78000_ICC);
}
+ for (i = 0; i < MAX78000_NUM_UART; i++) {
+ g_autofree char *name = g_strdup_printf("uart%d", i);
+ object_initialize_child(obj, name, &s->uart[i],
+ TYPE_MAX78000_UART);
+ }
+
s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
}
@@ -39,6 +49,7 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
MAX78000State *s = MAX78000_SOC(dev_soc);
MemoryRegion *system_memory = get_system_memory();
DeviceState *dev, *armv7m;
+ SysBusDevice *busdev;
Error *err = NULL;
int i;
@@ -89,6 +100,19 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, max78000_icc_addr[i]);
}
+ for (i = 0; i < MAX78000_NUM_UART; i++) {
+ dev = DEVICE(&(s->uart[i]));
+ qdev_prop_set_chr(dev, "chardev", serial_hd(i));
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
+ return;
+ }
+
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, max78000_uart_addr[i]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m,
+ max78000_uart_irq[i]));
+ }
+
create_unimplemented_device("globalControl", 0x40000000, 0x400);
create_unimplemented_device("systemInterface", 0x40000400, 0x400);
create_unimplemented_device("functionControl", 0x40000800, 0x400);
@@ -127,10 +151,6 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("oneWireMaster", 0x4003d000, 0x1000);
create_unimplemented_device("semaphore", 0x4003e000, 0x1000);
- create_unimplemented_device("uart0", 0x40042000, 0x1000);
- create_unimplemented_device("uart1", 0x40043000, 0x1000);
- create_unimplemented_device("uart2", 0x40044000, 0x1000);
-
create_unimplemented_device("spi1", 0x40046000, 0x2000);
create_unimplemented_device("trng", 0x4004d000, 0x1000);
create_unimplemented_device("i2s", 0x40060000, 0x1000);
diff --git a/include/hw/arm/max78000_soc.h b/include/hw/arm/max78000_soc.h
index 27b506d6ee..57894f0035 100644
--- a/include/hw/arm/max78000_soc.h
+++ b/include/hw/arm/max78000_soc.h
@@ -12,6 +12,7 @@
#include "hw/or-irq.h"
#include "hw/arm/armv7m.h"
#include "hw/misc/max78000_icc.h"
+#include "hw/char/max78000_uart.h"
#include "qom/object.h"
#define TYPE_MAX78000_SOC "max78000-soc"
@@ -24,6 +25,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(MAX78000State, MAX78000_SOC)
/* The MAX78k has 2 instruction caches; only icc0 matters, icc1 is for RISC */
#define MAX78000_NUM_ICC 2
+#define MAX78000_NUM_UART 3
struct MAX78000State {
SysBusDevice parent_obj;
@@ -34,6 +36,7 @@ struct MAX78000State {
MemoryRegion flash;
Max78000IccState icc[MAX78000_NUM_ICC];
+ Max78000UartState uart[MAX78000_NUM_UART];
Clock *sysclk;
};
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 06/11] MAX78000: GCR Implementation
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (4 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 05/11] MAX78000: Add UART to SOC Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 07/11] MAX78000: Add GCR to SOC Jackson Donaldson
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit implements the Global Control Register
for the MAX78000
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/Kconfig | 1 +
hw/misc/Kconfig | 3 +
hw/misc/max78000_gcr.c | 339 +++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
include/hw/misc/max78000_gcr.h | 129 +++++++++++++
5 files changed, 473 insertions(+)
create mode 100644 hw/misc/max78000_gcr.c
create mode 100644 include/hw/misc/max78000_gcr.h
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 031e0bf59e..41bb64458f 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -368,6 +368,7 @@ config MAX78000_SOC
select ARM_V7M
select MAX78000_ICC
select MAX78000_UART
+ select MAX78000_GCR
config RASPI
bool
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 781bcf74cc..fde2266b8f 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -47,6 +47,9 @@ config A9SCU
config ARM11SCU
bool
+config MAX78000_GCR
+ bool
+
config MAX78000_ICC
bool
diff --git a/hw/misc/max78000_gcr.c b/hw/misc/max78000_gcr.c
new file mode 100644
index 0000000000..8c282f3916
--- /dev/null
+++ b/hw/misc/max78000_gcr.c
@@ -0,0 +1,339 @@
+/*
+ * MAX78000 Global Control Registers
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "system/runstate.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "hw/char/max78000_uart.h"
+#include "hw/misc/max78000_gcr.h"
+
+
+static void max78000_gcr_reset_hold(Object *obj, ResetType type)
+{
+ DeviceState *dev = DEVICE(obj);
+ Max78000GcrState *s = MAX78000_GCR(dev);
+ s->sysctrl = 0x21002;
+ s->rst0 = 0;
+ /* All clocks are always ready */
+ s->clkctrl = 0x3e140008;
+ s->pm = 0x3f000;
+ s->pclkdiv = 0;
+ s->pclkdis0 = 0xffffffff;
+ s->memctrl = 0x5;
+ s->memz = 0;
+ s->sysst = 0;
+ s->rst1 = 0;
+ s->pckdis1 = 0xffffffff;
+ s->eventen = 0;
+ s->revision = 0xa1;
+ s->sysie = 0;
+ s->eccerr = 0;
+ s->ecced = 0;
+ s->eccie = 0;
+ s->eccaddr = 0;
+}
+
+static uint64_t max78000_gcr_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ Max78000GcrState *s = opaque;
+
+ switch (addr) {
+ case SYSCTRL:
+ return s->sysctrl;
+
+ case RST0:
+ return s->rst0;
+
+ case CLKCTRL:
+ return s->clkctrl;
+
+ case PM:
+ return s->pm;
+
+ case PCLKDIV:
+ return s->pclkdiv;
+
+ case PCLKDIS0:
+ return s->pclkdis0;
+
+ case MEMCTRL:
+ return s->memctrl;
+
+ case MEMZ:
+ return s->memz;
+
+ case SYSST:
+ return s->sysst;
+
+ case RST1:
+ return s->rst1;
+
+ case PCKDIS1:
+ return s->pckdis1;
+
+ case EVENTEN:
+ return s->eventen;
+
+ case REVISION:
+ return s->revision;
+
+ case SYSIE:
+ return s->sysie;
+
+ case ECCERR:
+ return s->eccerr;
+
+ case ECCED:
+ return s->ecced;
+
+ case ECCIE:
+ return s->eccie;
+
+ case ECCADDR:
+ return s->eccaddr;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return 0;
+
+ }
+}
+
+static void max78000_gcr_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ Max78000GcrState *s = opaque;
+ uint32_t val = val64;
+ uint8_t zero[0xc000] = {0};
+ switch (addr) {
+ case SYSCTRL:
+ /* Checksum calculations always pass immediately */
+ s->sysctrl = (val & 0x30000) | 0x1002;
+ break;
+
+ case RST0:
+ if (val & SYSTEM_RESET) {
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ }
+ if (val & PERIPHERAL_RESET) {
+ /*
+ * Peripheral reset resets all peripherals. The CPU
+ * retains its state. The GPIO, watchdog timers, AoD,
+ * RAM retention, and general control registers (GCR),
+ * including the clock configuration, are unaffected.
+ */
+ val = UART2_RESET | UART1_RESET | UART0_RESET |
+ ADC_RESET | CNN_RESET | TRNG_RESET |
+ RTC_RESET | I2C0_RESET | SPI1_RESET |
+ TMR3_RESET | TMR2_RESET | TMR1_RESET |
+ TMR0_RESET | WDT0_RESET | DMA_RESET;
+ }
+ if (val & SOFT_RESET) {
+ /* Soft reset also resets GPIO */
+ val = UART2_RESET | UART1_RESET | UART0_RESET |
+ ADC_RESET | CNN_RESET | TRNG_RESET |
+ RTC_RESET | I2C0_RESET | SPI1_RESET |
+ TMR3_RESET | TMR2_RESET | TMR1_RESET |
+ TMR0_RESET | GPIO1_RESET | GPIO0_RESET |
+ DMA_RESET;
+ }
+ if (val & UART2_RESET) {
+ device_cold_reset(s->uart2);
+ }
+ if (val & UART1_RESET) {
+ device_cold_reset(s->uart1);
+ }
+ if (val & UART0_RESET) {
+ device_cold_reset(s->uart0);
+ }
+ /* TODO: As other devices are implemented, add them here */
+ break;
+
+ case CLKCTRL:
+ s->clkctrl = val | SYSCLK_RDY;
+ break;
+
+ case PM:
+ s->pm = val;
+ break;
+
+ case PCLKDIV:
+ s->pclkdiv = val;
+ break;
+
+ case PCLKDIS0:
+ s->pclkdis0 = val;
+ break;
+
+ case MEMCTRL:
+ s->memctrl = val;
+ break;
+
+ case MEMZ:
+ if (val & ram0) {
+ address_space_write(&s->sram_as, SYSRAM0_START,
+ MEMTXATTRS_UNSPECIFIED, zero, 0x8000);
+ }
+ if (val & ram1) {
+ address_space_write(&s->sram_as, SYSRAM1_START,
+ MEMTXATTRS_UNSPECIFIED, zero, 0x8000);
+ }
+ if (val & ram2) {
+ address_space_write(&s->sram_as, SYSRAM2_START,
+ MEMTXATTRS_UNSPECIFIED, zero, 0xC000);
+ }
+ if (val & ram3) {
+ address_space_write(&s->sram_as, SYSRAM3_START,
+ MEMTXATTRS_UNSPECIFIED, zero, 0x4000);
+ }
+ break;
+
+ case SYSST:
+ s->sysst = val;
+ break;
+
+ case RST1:
+ /* TODO: As other devices are implemented, add them here */
+ s->rst1 = val;
+ break;
+
+ case PCKDIS1:
+ s->pckdis1 = val;
+ break;
+
+ case EVENTEN:
+ s->eventen = val;
+ break;
+
+ case REVISION:
+ s->revision = val;
+ break;
+
+ case SYSIE:
+ s->sysie = val;
+ break;
+
+ case ECCERR:
+ s->eccerr = val;
+ break;
+
+ case ECCED:
+ s->ecced = val;
+ break;
+
+ case ECCIE:
+ s->eccie = val;
+ break;
+
+ case ECCADDR:
+ s->eccaddr = val;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ break;
+
+ }
+}
+
+static const Property max78000_gcr_properties[] = {
+ DEFINE_PROP_LINK("sram", Max78000GcrState, sram,
+ TYPE_MEMORY_REGION, MemoryRegion*),
+ DEFINE_PROP_LINK("uart0", Max78000GcrState, uart0,
+ TYPE_MAX78000_UART, DeviceState*),
+ DEFINE_PROP_LINK("uart1", Max78000GcrState, uart1,
+ TYPE_MAX78000_UART, DeviceState*),
+ DEFINE_PROP_LINK("uart2", Max78000GcrState, uart2,
+ TYPE_MAX78000_UART, DeviceState*),
+};
+
+static const MemoryRegionOps max78000_gcr_ops = {
+ .read = max78000_gcr_read,
+ .write = max78000_gcr_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static const VMStateDescription vmstate_max78000_gcr = {
+ .name = TYPE_MAX78000_GCR,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(sysctrl, Max78000GcrState),
+ VMSTATE_UINT32(rst0, Max78000GcrState),
+ VMSTATE_UINT32(clkctrl, Max78000GcrState),
+ VMSTATE_UINT32(pm, Max78000GcrState),
+ VMSTATE_UINT32(pclkdiv, Max78000GcrState),
+ VMSTATE_UINT32(pclkdis0, Max78000GcrState),
+ VMSTATE_UINT32(memctrl, Max78000GcrState),
+ VMSTATE_UINT32(memz, Max78000GcrState),
+ VMSTATE_UINT32(sysst, Max78000GcrState),
+ VMSTATE_UINT32(rst1, Max78000GcrState),
+ VMSTATE_UINT32(pckdis1, Max78000GcrState),
+ VMSTATE_UINT32(eventen, Max78000GcrState),
+ VMSTATE_UINT32(revision, Max78000GcrState),
+ VMSTATE_UINT32(sysie, Max78000GcrState),
+ VMSTATE_UINT32(eccerr, Max78000GcrState),
+ VMSTATE_UINT32(ecced, Max78000GcrState),
+ VMSTATE_UINT32(eccie, Max78000GcrState),
+ VMSTATE_UINT32(eccaddr, Max78000GcrState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void max78000_gcr_init(Object *obj)
+{
+ Max78000GcrState *s = MAX78000_GCR(obj);
+
+ memory_region_init_io(&s->mmio, obj, &max78000_gcr_ops, s,
+ TYPE_MAX78000_GCR, 0x400);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+}
+
+static void max78000_gcr_realize(DeviceState *dev, Error **errp)
+{
+ Max78000GcrState *s = MAX78000_GCR(dev);
+
+ address_space_init(&s->sram_as, s->sram, "sram");
+}
+
+static void max78000_gcr_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ device_class_set_props(dc, max78000_gcr_properties);
+
+ dc->realize = max78000_gcr_realize;
+ dc->vmsd = &vmstate_max78000_gcr;
+ rc->phases.hold = max78000_gcr_reset_hold;
+}
+
+static const TypeInfo max78000_gcr_info = {
+ .name = TYPE_MAX78000_GCR,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Max78000GcrState),
+ .instance_init = max78000_gcr_init,
+ .class_init = max78000_gcr_class_init,
+};
+
+static void max78000_gcr_register_types(void)
+{
+ type_register_static(&max78000_gcr_info);
+}
+
+type_init(max78000_gcr_register_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index a21a994ff8..283d06dad4 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -70,6 +70,7 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx_ccm.c',
'imx_rngc.c',
))
+system_ss.add(when: 'CONFIG_MAX78000_GCR', if_true: files('max78000_gcr.c'))
system_ss.add(when: 'CONFIG_MAX78000_ICC', if_true: files('max78000_icc.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
'npcm_clk.c',
diff --git a/include/hw/misc/max78000_gcr.h b/include/hw/misc/max78000_gcr.h
new file mode 100644
index 0000000000..f04c8a3ee7
--- /dev/null
+++ b/include/hw/misc/max78000_gcr.h
@@ -0,0 +1,129 @@
+/*
+ * MAX78000 Global Control Register
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HW_MAX78000_GCR_H
+#define HW_MAX78000_GCR_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_MAX78000_GCR "max78000-gcr"
+OBJECT_DECLARE_SIMPLE_TYPE(Max78000GcrState, MAX78000_GCR)
+
+#define SYSCTRL 0x0
+#define RST0 0x4
+#define CLKCTRL 0x8
+#define PM 0xc
+#define PCLKDIV 0x18
+#define PCLKDIS0 0x24
+#define MEMCTRL 0x28
+#define MEMZ 0x2c
+#define SYSST 0x40
+#define RST1 0x44
+#define PCKDIS1 0x48
+#define EVENTEN 0x4c
+#define REVISION 0x50
+#define SYSIE 0x54
+#define ECCERR 0x64
+#define ECCED 0x68
+#define ECCIE 0x6c
+#define ECCADDR 0x70
+
+/* RST0 */
+#define SYSTEM_RESET (1 << 31)
+#define PERIPHERAL_RESET (1 << 30)
+#define SOFT_RESET (1 << 29)
+#define UART2_RESET (1 << 28)
+
+#define ADC_RESET (1 << 26)
+#define CNN_RESET (1 << 25)
+#define TRNG_RESET (1 << 24)
+
+#define RTC_RESET (1 << 17)
+#define I2C0_RESET (1 << 16)
+
+#define SPI1_RESET (1 << 13)
+#define UART1_RESET (1 << 12)
+#define UART0_RESET (1 << 11)
+
+#define TMR3_RESET (1 << 8)
+#define TMR2_RESET (1 << 7)
+#define TMR1_RESET (1 << 6)
+#define TMR0_RESET (1 << 5)
+
+#define GPIO1_RESET (1 << 3)
+#define GPIO0_RESET (1 << 2)
+#define WDT0_RESET (1 << 1)
+#define DMA_RESET (1 << 0)
+
+/* CLKCTRL */
+#define SYSCLK_RDY (1 << 13)
+
+/* MEMZ */
+#define ram0 (1 << 0)
+#define ram1 (1 << 1)
+#define ram2 (1 << 2)
+#define ram3 (1 << 3)
+
+/* RST1 */
+#define CPU1_RESET (1 << 31)
+
+#define SIMO_RESET (1 << 25)
+#define DVS_RESET (1 << 24)
+
+#define I2C2_RESET (1 << 20)
+#define I2S_RESET (1 << 19)
+
+#define SMPHR_RESET (1 << 16)
+
+#define SPI0_RESET (1 << 11)
+#define AES_RESET (1 << 10)
+#define CRC_RESET (1 << 9)
+
+#define PT_RESET (1 << 1)
+#define I2C1_RESET (1 << 0)
+
+
+#define SYSRAM0_START 0x20000000
+#define SYSRAM1_START 0x20008000
+#define SYSRAM2_START 0x20010000
+#define SYSRAM3_START 0x2001C000
+
+struct Max78000GcrState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+
+ uint32_t sysctrl;
+ uint32_t rst0;
+ uint32_t clkctrl;
+ uint32_t pm;
+ uint32_t pclkdiv;
+ uint32_t pclkdis0;
+ uint32_t memctrl;
+ uint32_t memz;
+ uint32_t sysst;
+ uint32_t rst1;
+ uint32_t pckdis1;
+ uint32_t eventen;
+ uint32_t revision;
+ uint32_t sysie;
+ uint32_t eccerr;
+ uint32_t ecced;
+ uint32_t eccie;
+ uint32_t eccaddr;
+
+ MemoryRegion *sram;
+ AddressSpace sram_as;
+
+ DeviceState *uart0;
+ DeviceState *uart1;
+ DeviceState *uart2;
+
+};
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 07/11] MAX78000: Add GCR to SOC
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (5 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 06/11] MAX78000: GCR Implementation Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 08/11] MAX78000: TRNG Implementation Jackson Donaldson
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit adds the Global Control Register to
max78000_soc
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/max78000_soc.c | 18 ++++++++++++++++--
include/hw/arm/max78000_soc.h | 2 ++
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/hw/arm/max78000_soc.c b/hw/arm/max78000_soc.c
index 2f93ab882d..45c6088312 100644
--- a/hw/arm/max78000_soc.c
+++ b/hw/arm/max78000_soc.c
@@ -30,6 +30,8 @@ static void max78000_soc_initfn(Object *obj)
object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
+ object_initialize_child(obj, "gcr", &s->gcr, TYPE_MAX78000_GCR);
+
for (i = 0; i < MAX78000_NUM_ICC; i++) {
g_autofree char *name = g_strdup_printf("icc%d", i);
object_initialize_child(obj, name, &s->icc[i], TYPE_MAX78000_ICC);
@@ -48,7 +50,7 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
{
MAX78000State *s = MAX78000_SOC(dev_soc);
MemoryRegion *system_memory = get_system_memory();
- DeviceState *dev, *armv7m;
+ DeviceState *dev, *gcrdev, *armv7m;
SysBusDevice *busdev;
Error *err = NULL;
int i;
@@ -69,6 +71,11 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
memory_region_init_ram(&s->sram, NULL, "MAX78000.sram", SRAM_SIZE,
&err);
+
+ gcrdev = DEVICE(&s->gcr);
+ object_property_set_link(OBJECT(gcrdev), "sram", OBJECT(&s->sram),
+ &err);
+
if (err != NULL) {
error_propagate(errp, err);
return;
@@ -101,19 +108,26 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
}
for (i = 0; i < MAX78000_NUM_UART; i++) {
+ g_autofree char *link = g_strdup_printf("uart%d", i);
dev = DEVICE(&(s->uart[i]));
qdev_prop_set_chr(dev, "chardev", serial_hd(i));
if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
return;
}
+ object_property_set_link(OBJECT(gcrdev), link, OBJECT(dev),
+ &err);
+
busdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(busdev, 0, max78000_uart_addr[i]);
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m,
max78000_uart_irq[i]));
}
- create_unimplemented_device("globalControl", 0x40000000, 0x400);
+ dev = DEVICE(&s->gcr);
+ sysbus_realize(SYS_BUS_DEVICE(dev), errp);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x40000000);
+
create_unimplemented_device("systemInterface", 0x40000400, 0x400);
create_unimplemented_device("functionControl", 0x40000800, 0x400);
create_unimplemented_device("watchdogTimer0", 0x40003000, 0x400);
diff --git a/include/hw/arm/max78000_soc.h b/include/hw/arm/max78000_soc.h
index 57894f0035..919aca0855 100644
--- a/include/hw/arm/max78000_soc.h
+++ b/include/hw/arm/max78000_soc.h
@@ -11,6 +11,7 @@
#include "hw/or-irq.h"
#include "hw/arm/armv7m.h"
+#include "hw/misc/max78000_gcr.h"
#include "hw/misc/max78000_icc.h"
#include "hw/char/max78000_uart.h"
#include "qom/object.h"
@@ -35,6 +36,7 @@ struct MAX78000State {
MemoryRegion sram;
MemoryRegion flash;
+ Max78000GcrState gcr;
Max78000IccState icc[MAX78000_NUM_ICC];
Max78000UartState uart[MAX78000_NUM_UART];
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 08/11] MAX78000: TRNG Implementation
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (6 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 07/11] MAX78000: Add GCR to SOC Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 09/11] MAX78000: Add TRNG to SOC Jackson Donaldson
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit implements the True Random Number
Generator for the MAX78000
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/Kconfig | 1 +
hw/misc/Kconfig | 3 +
hw/misc/max78000_gcr.c | 6 ++
hw/misc/max78000_trng.c | 139 ++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
include/hw/misc/max78000_gcr.h | 1 +
include/hw/misc/max78000_trng.h | 35 ++++++++
7 files changed, 186 insertions(+)
create mode 100644 hw/misc/max78000_trng.c
create mode 100644 include/hw/misc/max78000_trng.h
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 41bb64458f..fcac62be6f 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -369,6 +369,7 @@ config MAX78000_SOC
select MAX78000_ICC
select MAX78000_UART
select MAX78000_GCR
+ select MAX78000_TRNG
config RASPI
bool
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index fde2266b8f..dd6a6e54da 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -53,6 +53,9 @@ config MAX78000_GCR
config MAX78000_ICC
bool
+config MAX78000_TRNG
+ bool
+
config MOS6522
bool
diff --git a/hw/misc/max78000_gcr.c b/hw/misc/max78000_gcr.c
index 8c282f3916..5916ee615a 100644
--- a/hw/misc/max78000_gcr.c
+++ b/hw/misc/max78000_gcr.c
@@ -14,6 +14,7 @@
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/char/max78000_uart.h"
+#include "hw/misc/max78000_trng.h"
#include "hw/misc/max78000_gcr.h"
@@ -157,6 +158,9 @@ static void max78000_gcr_write(void *opaque, hwaddr addr,
if (val & UART0_RESET) {
device_cold_reset(s->uart0);
}
+ if (val & TRNG_RESET) {
+ device_cold_reset(s->trng);
+ }
/* TODO: As other devices are implemented, add them here */
break;
@@ -257,6 +261,8 @@ static const Property max78000_gcr_properties[] = {
TYPE_MAX78000_UART, DeviceState*),
DEFINE_PROP_LINK("uart2", Max78000GcrState, uart2,
TYPE_MAX78000_UART, DeviceState*),
+ DEFINE_PROP_LINK("trng", Max78000GcrState, trng,
+ TYPE_MAX78000_TRNG, DeviceState*),
};
static const MemoryRegionOps max78000_gcr_ops = {
diff --git a/hw/misc/max78000_trng.c b/hw/misc/max78000_trng.c
new file mode 100644
index 0000000000..ecdaef53b6
--- /dev/null
+++ b/hw/misc/max78000_trng.c
@@ -0,0 +1,139 @@
+/*
+ * MAX78000 True Random Number Generator
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/max78000_trng.h"
+#include "qemu/guest-random.h"
+
+static uint64_t max78000_trng_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ uint32_t data;
+
+ Max78000TrngState *s = opaque;
+ switch (addr) {
+ case CTRL:
+ return s->ctrl;
+
+ case STATUS:
+ return 1;
+
+ case DATA:
+ /*
+ * When interrupts are enabled, reading random data should cause a
+ * new interrupt to be generated; since there's always a random number
+ * available, we could qemu_set_irq(s->irq, s->ctrl & RND_IE). Because
+ * of how trng_write is set up, this is always a noop, so don't
+ */
+ qemu_guest_getrandom_nofail(&data, sizeof(data));
+ return data;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void max78000_trng_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ Max78000TrngState *s = opaque;
+ uint32_t val = val64;
+ switch (addr) {
+ case CTRL:
+ /* TODO: implement AES keygen */
+ s->ctrl = val;
+
+ /*
+ * This device models random number generation as taking 0 time.
+ * A new random number is always available, so the condition for the
+ * RND interrupt is always fulfilled; we can just set irq to 1.
+ */
+ if (val & RND_IE) {
+ qemu_set_irq(s->irq, 1);
+ } else{
+ qemu_set_irq(s->irq, 0);
+ }
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+ }
+}
+
+static void max78000_trng_reset_hold(Object *obj, ResetType type)
+{
+ Max78000TrngState *s = MAX78000_TRNG(obj);
+ s->ctrl = 0;
+ s->status = 0;
+ s->data = 0;
+}
+
+static const MemoryRegionOps max78000_trng_ops = {
+ .read = max78000_trng_read,
+ .write = max78000_trng_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static const VMStateDescription max78000_trng_vmstate = {
+ .name = TYPE_MAX78000_TRNG,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(ctrl, Max78000TrngState),
+ VMSTATE_UINT32(status, Max78000TrngState),
+ VMSTATE_UINT32(data, Max78000TrngState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void max78000_trng_init(Object *obj)
+{
+ Max78000TrngState *s = MAX78000_TRNG(obj);
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &max78000_trng_ops, s,
+ TYPE_MAX78000_TRNG, 0x1000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+}
+
+static void max78000_trng_class_init(ObjectClass *klass, const void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ rc->phases.hold = max78000_trng_reset_hold;
+ dc->vmsd = &max78000_trng_vmstate;
+
+}
+
+static const TypeInfo max78000_trng_info = {
+ .name = TYPE_MAX78000_TRNG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Max78000TrngState),
+ .instance_init = max78000_trng_init,
+ .class_init = max78000_trng_class_init,
+};
+
+static void max78000_trng_register_types(void)
+{
+ type_register_static(&max78000_trng_info);
+}
+
+type_init(max78000_trng_register_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 283d06dad4..c7c57d924b 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -72,6 +72,7 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
))
system_ss.add(when: 'CONFIG_MAX78000_GCR', if_true: files('max78000_gcr.c'))
system_ss.add(when: 'CONFIG_MAX78000_ICC', if_true: files('max78000_icc.c'))
+system_ss.add(when: 'CONFIG_MAX78000_TRNG', if_true: files('max78000_trng.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
'npcm_clk.c',
'npcm_gcr.c',
diff --git a/include/hw/misc/max78000_gcr.h b/include/hw/misc/max78000_gcr.h
index f04c8a3ee7..23ddf0885b 100644
--- a/include/hw/misc/max78000_gcr.h
+++ b/include/hw/misc/max78000_gcr.h
@@ -123,6 +123,7 @@ struct Max78000GcrState {
DeviceState *uart0;
DeviceState *uart1;
DeviceState *uart2;
+ DeviceState *trng;
};
diff --git a/include/hw/misc/max78000_trng.h b/include/hw/misc/max78000_trng.h
new file mode 100644
index 0000000000..c5a8129b6a
--- /dev/null
+++ b/include/hw/misc/max78000_trng.h
@@ -0,0 +1,35 @@
+/*
+ * MAX78000 True Random Number Generator
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HW_MAX78000_TRNG_H
+#define HW_MAX78000_TRNG_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_MAX78000_TRNG "max78000-trng"
+OBJECT_DECLARE_SIMPLE_TYPE(Max78000TrngState, MAX78000_TRNG)
+
+#define CTRL 0
+#define STATUS 4
+#define DATA 8
+
+#define RND_IE (1 << 1)
+
+struct Max78000TrngState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t data;
+
+ qemu_irq irq;
+};
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 09/11] MAX78000: Add TRNG to SOC
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (7 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 08/11] MAX78000: TRNG Implementation Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 10/11] MAX78000: AES implementation Jackson Donaldson
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit adds TRNG to max78000_soc
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/max78000_soc.c | 10 +++++++++-
include/hw/arm/max78000_soc.h | 2 ++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/hw/arm/max78000_soc.c b/hw/arm/max78000_soc.c
index 45c6088312..3f2069fb03 100644
--- a/hw/arm/max78000_soc.c
+++ b/hw/arm/max78000_soc.c
@@ -43,6 +43,8 @@ static void max78000_soc_initfn(Object *obj)
TYPE_MAX78000_UART);
}
+ object_initialize_child(obj, "trng", &s->trng, TYPE_MAX78000_TRNG);
+
s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
}
@@ -124,6 +126,13 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
max78000_uart_irq[i]));
}
+ dev = DEVICE(&s->trng);
+ sysbus_realize(SYS_BUS_DEVICE(dev), errp);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x4004d000);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(armv7m, 4));
+
+ object_property_set_link(OBJECT(gcrdev), "trng", OBJECT(dev), &err);
+
dev = DEVICE(&s->gcr);
sysbus_realize(SYS_BUS_DEVICE(dev), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x40000000);
@@ -166,7 +175,6 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("semaphore", 0x4003e000, 0x1000);
create_unimplemented_device("spi1", 0x40046000, 0x2000);
- create_unimplemented_device("trng", 0x4004d000, 0x1000);
create_unimplemented_device("i2s", 0x40060000, 0x1000);
create_unimplemented_device("lowPowerControl", 0x40080000, 0x400);
create_unimplemented_device("gpio2", 0x40080400, 0x200);
diff --git a/include/hw/arm/max78000_soc.h b/include/hw/arm/max78000_soc.h
index 919aca0855..528598cfcb 100644
--- a/include/hw/arm/max78000_soc.h
+++ b/include/hw/arm/max78000_soc.h
@@ -14,6 +14,7 @@
#include "hw/misc/max78000_gcr.h"
#include "hw/misc/max78000_icc.h"
#include "hw/char/max78000_uart.h"
+#include "hw/misc/max78000_trng.h"
#include "qom/object.h"
#define TYPE_MAX78000_SOC "max78000-soc"
@@ -39,6 +40,7 @@ struct MAX78000State {
Max78000GcrState gcr;
Max78000IccState icc[MAX78000_NUM_ICC];
Max78000UartState uart[MAX78000_NUM_UART];
+ Max78000TrngState trng;
Clock *sysclk;
};
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 10/11] MAX78000: AES implementation
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (8 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 09/11] MAX78000: Add TRNG to SOC Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 11/11] MAX78000: Add AES to SOC Jackson Donaldson
2025-07-15 8:47 ` [PATCH v5 00/11] MAX78000FTHR Implementation Peter Maydell
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit implements AES for the MAX78000
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
---
hw/arm/Kconfig | 1 +
hw/misc/Kconfig | 3 +
hw/misc/max78000_aes.c | 229 +++++++++++++++++++++++++++++++++
hw/misc/max78000_gcr.c | 6 +
hw/misc/meson.build | 1 +
include/hw/misc/max78000_aes.h | 68 ++++++++++
include/hw/misc/max78000_gcr.h | 1 +
7 files changed, 309 insertions(+)
create mode 100644 hw/misc/max78000_aes.c
create mode 100644 include/hw/misc/max78000_aes.h
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index fcac62be6f..3e41120c89 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -370,6 +370,7 @@ config MAX78000_SOC
select MAX78000_UART
select MAX78000_GCR
select MAX78000_TRNG
+ select MAX78000_AES
config RASPI
bool
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index dd6a6e54da..c27285b47a 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -47,6 +47,9 @@ config A9SCU
config ARM11SCU
bool
+config MAX78000_AES
+ bool
+
config MAX78000_GCR
bool
diff --git a/hw/misc/max78000_aes.c b/hw/misc/max78000_aes.c
new file mode 100644
index 0000000000..d883ddd2b6
--- /dev/null
+++ b/hw/misc/max78000_aes.c
@@ -0,0 +1,229 @@
+/*
+ * MAX78000 AES
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/max78000_aes.h"
+#include "crypto/aes.h"
+
+static void max78000_aes_set_status(Max78000AesState *s)
+{
+ s->status = 0;
+ if (s->result_index >= 16) {
+ s->status |= OUTPUT_FULL;
+ }
+ if (s->result_index == 0) {
+ s->status |= OUTPUT_EMPTY;
+ }
+ if (s->data_index >= 16) {
+ s->status |= INPUT_FULL;
+ }
+ if (s->data_index == 0) {
+ s->status |= INPUT_EMPTY;
+ }
+}
+
+static uint64_t max78000_aes_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ Max78000AesState *s = opaque;
+ switch (addr) {
+ case CTRL:
+ return s->ctrl;
+
+ case STATUS:
+ return s->status;
+
+ case INTFL:
+ return s->intfl;
+
+ case INTEN:
+ return s->inten;
+
+ case FIFO:
+ if (s->result_index >= 4) {
+ s->intfl &= ~DONE;
+ s->result_index -= 4;
+ max78000_aes_set_status(s);
+ return ldl_be_p(&s->result[s->result_index]);
+ } else{
+ return 0;
+ }
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+
+ }
+ return 0;
+}
+
+static void max78000_aes_do_crypto(Max78000AesState *s)
+{
+ int keylen = 256;
+ uint8_t *keydata = s->key;
+ if ((s->ctrl & KEY_SIZE) == 0) {
+ keylen = 128;
+ keydata += 16;
+ } else if ((s->ctrl & KEY_SIZE) == 1 << 6) {
+ keylen = 192;
+ keydata += 8;
+ }
+
+ /*
+ * The MAX78000 AES engine stores an internal key, which it uses only
+ * for decryption. This results in the slighly odd looking pairs of
+ * set_encrypt and set_decrypt calls below; s->internal_key is
+ * being stored for later use in both cases.
+ */
+ AES_KEY key;
+ if ((s->ctrl & TYPE) == 0) {
+ AES_set_encrypt_key(keydata, keylen, &key);
+ AES_set_decrypt_key(keydata, keylen, &s->internal_key);
+ AES_encrypt(s->data, s->result, &key);
+ s->result_index = 16;
+ } else if ((s->ctrl & TYPE) == 1 << 8) {
+ AES_set_decrypt_key(keydata, keylen, &key);
+ AES_set_decrypt_key(keydata, keylen, &s->internal_key);
+ AES_decrypt(s->data, s->result, &key);
+ s->result_index = 16;
+ } else{
+ AES_decrypt(s->data, s->result, &s->internal_key);
+ s->result_index = 16;
+ }
+ s->intfl |= DONE;
+}
+
+static void max78000_aes_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ Max78000AesState *s = opaque;
+ uint32_t val = val64;
+ switch (addr) {
+ case CTRL:
+ if (val & OUTPUT_FLUSH) {
+ s->result_index = 0;
+ val &= ~OUTPUT_FLUSH;
+ }
+ if (val & INPUT_FLUSH) {
+ s->data_index = 0;
+ val &= ~INPUT_FLUSH;
+ }
+ if (val & START) {
+ max78000_aes_do_crypto(s);
+ }
+
+ /* Hardware appears to stay enabled even if 0 written */
+ s->ctrl = val | (s->ctrl & AES_EN);
+ break;
+
+ case FIFO:
+ assert(s->data_index <= 12);
+ stl_be_p(&s->data[12 - s->data_index], val);
+ s->data_index += 4;
+ if (s->data_index >= 16) {
+ s->data_index = 0;
+ max78000_aes_do_crypto(s);
+ }
+ break;
+
+ case KEY_BASE ... KEY_END - 4:
+ stl_be_p(&s->key[(KEY_END - KEY_BASE - 4) - (addr - KEY_BASE)], val);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ break;
+
+ }
+ max78000_aes_set_status(s);
+}
+
+static void max78000_aes_reset_hold(Object *obj, ResetType type)
+{
+ Max78000AesState *s = MAX78000_AES(obj);
+ s->ctrl = 0;
+ s->status = 0;
+ s->intfl = 0;
+ s->inten = 0;
+
+ s->data_index = 0;
+ s->result_index = 0;
+
+ memset(s->data, 0, sizeof(s->data));
+ memset(s->key, 0, sizeof(s->key));
+ memset(s->result, 0, sizeof(s->result));
+ memset(&s->internal_key, 0, sizeof(s->internal_key));
+}
+
+static const MemoryRegionOps max78000_aes_ops = {
+ .read = max78000_aes_read,
+ .write = max78000_aes_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static const VMStateDescription vmstate_max78000_aes = {
+ .name = TYPE_MAX78000_AES,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(ctrl, Max78000AesState),
+ VMSTATE_UINT32(status, Max78000AesState),
+ VMSTATE_UINT32(intfl, Max78000AesState),
+ VMSTATE_UINT32(inten, Max78000AesState),
+ VMSTATE_UINT8_ARRAY(data, Max78000AesState, 16),
+ VMSTATE_UINT8_ARRAY(key, Max78000AesState, 32),
+ VMSTATE_UINT8_ARRAY(result, Max78000AesState, 16),
+ VMSTATE_UINT32_ARRAY(internal_key.rd_key, Max78000AesState, 60),
+ VMSTATE_INT32(internal_key.rounds, Max78000AesState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void max78000_aes_init(Object *obj)
+{
+ Max78000AesState *s = MAX78000_AES(obj);
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &max78000_aes_ops, s,
+ TYPE_MAX78000_AES, 0xc00);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+}
+
+static void max78000_aes_class_init(ObjectClass *klass, const void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ rc->phases.hold = max78000_aes_reset_hold;
+ dc->vmsd = &vmstate_max78000_aes;
+
+}
+
+static const TypeInfo max78000_aes_info = {
+ .name = TYPE_MAX78000_AES,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Max78000AesState),
+ .instance_init = max78000_aes_init,
+ .class_init = max78000_aes_class_init,
+};
+
+static void max78000_aes_register_types(void)
+{
+ type_register_static(&max78000_aes_info);
+}
+
+type_init(max78000_aes_register_types)
diff --git a/hw/misc/max78000_gcr.c b/hw/misc/max78000_gcr.c
index 5916ee615a..fbbc92cca3 100644
--- a/hw/misc/max78000_gcr.c
+++ b/hw/misc/max78000_gcr.c
@@ -15,6 +15,7 @@
#include "hw/qdev-properties.h"
#include "hw/char/max78000_uart.h"
#include "hw/misc/max78000_trng.h"
+#include "hw/misc/max78000_aes.h"
#include "hw/misc/max78000_gcr.h"
@@ -161,6 +162,9 @@ static void max78000_gcr_write(void *opaque, hwaddr addr,
if (val & TRNG_RESET) {
device_cold_reset(s->trng);
}
+ if (val & AES_RESET) {
+ device_cold_reset(s->aes);
+ }
/* TODO: As other devices are implemented, add them here */
break;
@@ -263,6 +267,8 @@ static const Property max78000_gcr_properties[] = {
TYPE_MAX78000_UART, DeviceState*),
DEFINE_PROP_LINK("trng", Max78000GcrState, trng,
TYPE_MAX78000_TRNG, DeviceState*),
+ DEFINE_PROP_LINK("aes", Max78000GcrState, aes,
+ TYPE_MAX78000_AES, DeviceState*),
};
static const MemoryRegionOps max78000_gcr_ops = {
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index c7c57d924b..b1d8d8e5d2 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -70,6 +70,7 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx_ccm.c',
'imx_rngc.c',
))
+system_ss.add(when: 'CONFIG_MAX78000_AES', if_true: files('max78000_aes.c'))
system_ss.add(when: 'CONFIG_MAX78000_GCR', if_true: files('max78000_gcr.c'))
system_ss.add(when: 'CONFIG_MAX78000_ICC', if_true: files('max78000_icc.c'))
system_ss.add(when: 'CONFIG_MAX78000_TRNG', if_true: files('max78000_trng.c'))
diff --git a/include/hw/misc/max78000_aes.h b/include/hw/misc/max78000_aes.h
new file mode 100644
index 0000000000..407c45ef61
--- /dev/null
+++ b/include/hw/misc/max78000_aes.h
@@ -0,0 +1,68 @@
+/*
+ * MAX78000 AES
+ *
+ * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HW_MAX78000_AES_H
+#define HW_MAX78000_AES_H
+
+#include "hw/sysbus.h"
+#include "crypto/aes.h"
+#include "qom/object.h"
+
+#define TYPE_MAX78000_AES "max78000-aes"
+OBJECT_DECLARE_SIMPLE_TYPE(Max78000AesState, MAX78000_AES)
+
+#define CTRL 0
+#define STATUS 4
+#define INTFL 8
+#define INTEN 0xc
+#define FIFO 0x10
+
+#define KEY_BASE 0x400
+#define KEY_END 0x420
+
+/* CTRL */
+#define TYPE (1 << 9 | 1 << 8)
+#define KEY_SIZE (1 << 7 | 1 << 6)
+#define OUTPUT_FLUSH (1 << 5)
+#define INPUT_FLUSH (1 << 4)
+#define START (1 << 3)
+
+#define AES_EN (1 << 0)
+
+/* STATUS */
+#define OUTPUT_FULL (1 << 4)
+#define OUTPUT_EMPTY (1 << 3)
+#define INPUT_FULL (1 << 2)
+#define INPUT_EMPTY (1 << 1)
+#define BUSY (1 << 0)
+
+/* INTFL*/
+#define DONE (1 << 0)
+
+struct Max78000AesState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t intfl;
+ uint32_t inten;
+ uint32_t data_index;
+ uint8_t data[16];
+
+ uint8_t key[32];
+ AES_KEY internal_key;
+
+ uint32_t result_index;
+ uint8_t result[16];
+
+
+ qemu_irq irq;
+};
+
+#endif
diff --git a/include/hw/misc/max78000_gcr.h b/include/hw/misc/max78000_gcr.h
index 23ddf0885b..d5858a40f3 100644
--- a/include/hw/misc/max78000_gcr.h
+++ b/include/hw/misc/max78000_gcr.h
@@ -124,6 +124,7 @@ struct Max78000GcrState {
DeviceState *uart1;
DeviceState *uart2;
DeviceState *trng;
+ DeviceState *aes;
};
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 11/11] MAX78000: Add AES to SOC
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (9 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 10/11] MAX78000: AES implementation Jackson Donaldson
@ 2025-07-15 0:00 ` Jackson Donaldson
2025-07-15 8:47 ` [PATCH v5 00/11] MAX78000FTHR Implementation Peter Maydell
11 siblings, 0 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
This commit adds AES to max78000_soc
Signed-off-by: Jackson Donaldson <jcksn@duck.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/max78000_soc.c | 12 +++++++++---
include/hw/arm/max78000_soc.h | 2 ++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/hw/arm/max78000_soc.c b/hw/arm/max78000_soc.c
index 3f2069fb03..7f1856f5ba 100644
--- a/hw/arm/max78000_soc.c
+++ b/hw/arm/max78000_soc.c
@@ -45,6 +45,8 @@ static void max78000_soc_initfn(Object *obj)
object_initialize_child(obj, "trng", &s->trng, TYPE_MAX78000_TRNG);
+ object_initialize_child(obj, "aes", &s->aes, TYPE_MAX78000_AES);
+
s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
}
@@ -133,6 +135,13 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
object_property_set_link(OBJECT(gcrdev), "trng", OBJECT(dev), &err);
+ dev = DEVICE(&s->aes);
+ sysbus_realize(SYS_BUS_DEVICE(dev), errp);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x40007400);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(armv7m, 5));
+
+ object_property_set_link(OBJECT(gcrdev), "aes", OBJECT(dev), &err);
+
dev = DEVICE(&s->gcr);
sysbus_realize(SYS_BUS_DEVICE(dev), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x40000000);
@@ -148,9 +157,6 @@ static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("powerSequencer", 0x40006800, 0x400);
create_unimplemented_device("miscControl", 0x40006c00, 0x400);
- create_unimplemented_device("aes", 0x40007400, 0x400);
- create_unimplemented_device("aesKey", 0x40007800, 0x400);
-
create_unimplemented_device("gpio0", 0x40008000, 0x1000);
create_unimplemented_device("gpio1", 0x40009000, 0x1000);
diff --git a/include/hw/arm/max78000_soc.h b/include/hw/arm/max78000_soc.h
index 528598cfcb..a203079ee9 100644
--- a/include/hw/arm/max78000_soc.h
+++ b/include/hw/arm/max78000_soc.h
@@ -11,6 +11,7 @@
#include "hw/or-irq.h"
#include "hw/arm/armv7m.h"
+#include "hw/misc/max78000_aes.h"
#include "hw/misc/max78000_gcr.h"
#include "hw/misc/max78000_icc.h"
#include "hw/char/max78000_uart.h"
@@ -41,6 +42,7 @@ struct MAX78000State {
Max78000IccState icc[MAX78000_NUM_ICC];
Max78000UartState uart[MAX78000_NUM_UART];
Max78000TrngState trng;
+ Max78000AesState aes;
Clock *sysclk;
};
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v5 00/11] MAX78000FTHR Implementation
2025-07-15 0:00 [PATCH v5 00/11] MAX78000FTHR Implementation Jackson Donaldson
` (10 preceding siblings ...)
2025-07-15 0:00 ` [PATCH v5 11/11] MAX78000: Add AES to SOC Jackson Donaldson
@ 2025-07-15 8:47 ` Peter Maydell
11 siblings, 0 replies; 13+ messages in thread
From: Peter Maydell @ 2025-07-15 8:47 UTC (permalink / raw)
To: Jackson Donaldson; +Cc: qemu-devel
On Tue, 15 Jul 2025 at 01:00, Jackson Donaldson <jackson88044@gmail.com> wrote:
>
> v5:
>
> > > + AES_KEY key;
> > > + if ((s->ctrl & TYPE) == 0) {
> > > + AES_set_encrypt_key(keydata, keylen, &key);
> > > + AES_set_decrypt_key(keydata, keylen, &s->internal_key);
> > > + AES_encrypt(s->data, s->result, &key);
> > Here we call AES_set_encrypt_key() and AES_set_decrypt_key()
> > before calling AES_encrypt()...
>
> > > + s->result_index = 16;
> > > + } else if ((s->ctrl & TYPE) == 1 << 8) {
> > > + AES_set_decrypt_key(keydata, keylen, &key);
> > > + AES_set_decrypt_key(keydata, keylen, &s->internal_key);
> > > + AES_decrypt(s->data, s->result, &key);
> >
> > ...here we call AES_set_decrypt_key() twice before
> > calling AES_decrypt(). This looks a bit odd: should we either
> > (a) call both AES_set_decrypt_key() and AES_set_encrypt_key()
> > in each half of the if(), or (b) call AES_set_encyrypt_key()
> > twice in the AES_encrypt() code path ?
> >
> > (Coverity is sometimes wrong, as it's only using a heuristic
> > here, so the other option is "the code as written is correct",
> > but in that case a comment might be helpful for human readers.)
>
> > thanks
> > -- PMM
>
> The AES engine stores an internal key which it uses only for decryption
> when in the last TYPE. This results in the odd-looking call pairs.
> I've added the requested comment.
Your patches are already upstream, so rather than sending
a new version of the whole series, please rebase on
current head-of-git and just send a patch that adds the comment.
thnaks
-- PMM
^ permalink raw reply [flat|nested] 13+ messages in thread