* [PATCH v5 00/11] MAX78000FTHR Implementation
@ 2025-07-15 0:00 Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 01/11] MAX78000: Add MAX78000FTHR Machine Jackson Donaldson
` (11 more replies)
0 siblings, 12 replies; 13+ messages in thread
From: Jackson Donaldson @ 2025-07-15 0:00 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell
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.
- Jackson
v4:
Spacing and style standard changes in GCR SOC, TRNG SOC, and AES SOC
v3:
Addresses a few more comments by Peter. Really appreciate the review, thank you.
ICC SOC:
Gave each device a unique name
UART SOC:
Removed references to DeviceState and gave each device a unique name
GCR SOC:
Set object property links statically, instead of by reference to device id
TRNG:
Added comments explaining interrupt generation logic. See further rationale under v2.
It's certainly possible I'm missing something here, but I think what I have is correct.
TRNG SOC:
Removed reference to DeviceState
AES:
Simplified integer load & stores, added assertion before writing to memory_region_init_ram
AES SOC:
Removed reference to DeviceState
v2:
Addresses comments by Peter.
For each device:
- Switched soc to use sysbus_realize
- Standardized switch case bracing, indentation, and error case
- Added valid min and max access size
- Changed endianness to DEVICE_LITTLE_ENDIAN
- Added reset method, if not already implemented
- Added migration support
- Split soc integration into separate commit
Machine Implementation:
Added user guide URL
Removed refclk. According to https://developer.arm.com/documentation/ddi0403/d/System-Level-Architecture/System-Address-Map/The-system-timer--SysTick/SysTick-Control-and-Status-Register--SYST-CSR the systick clock can be either the processor clock or an implementation defined external reference clock. As far as I can tell based on the user guide, the MAX78000 does not define an external reference clock. I have not confirmed this in hardware.
Changed IRQ count to 120 and noted that the user guide is unclear on this number
Fixed unimplemented device lengths and names
ICC:
Removed ICC_Invalidate
Added number to device names
UART:
Fixed interrupts, allowing async UART
Added number to device names
GCR:
Changed string-based device search to prop links for device reset
Changed cpu_physical_memory_write to address_space_write
TRNG:
Changed source of randomness to qemu_guest_getrandom_nofail
Did not change interrupt generation
> Your interrupt generation code in this device doesn't look
> right: the interrupt is supposed to be generated when each
> new random number is ready, so in our "generation takes
> zero time" model a read from DATA should provoke a new
> interrupt immediately (assuming the interrupt is enabled):
> you need to simulate the ready status bit going low and
> then high again.
I believe the interrupt generation is fine in this case;
by latching it high so long as the interrupt is enabled,
the interrupt handler gets called repeatedly until it
receives the desired amount of data and disables the interrupt.
I've tested this and it works with the maxim sdk's
implementation of asynchronous trng.
> See also my comments on an earlier patch about the usual
> logic being to have an update function which does
> "set interrupt to (condition && enabled)".
In this case there is only one possible interrupt condition
(is there random data ready), which is always true when enabled.
As such I don't think a handler function is really necessary
v1:
This patch series implements basic support for the MAX78000FTHR machine
https://github.com/JacksonDonaldson/max78000Test
Contains instructions for building a test program against the MAX78000FTHR
as well as results of the test suite run on QEMU and hardware.
Jackson Donaldson (11):
MAX78000: Add MAX78000FTHR Machine
MAX78000: ICC Implementation
MAX78000: Add ICC to SOC
MAX78000: UART Implementation
MAX78000: Add UART to SOC
MAX78000: GCR Implementation
MAX78000: Add GCR to SOC
MAX78000: TRNG Implementation
MAX78000: Add TRNG to SOC
MAX78000: AES implementation
MAX78000: Add AES to SOC
hw/arm/Kconfig | 15 ++
hw/arm/max78000_soc.c | 232 +++++++++++++++++++++
hw/arm/max78000fthr.c | 50 +++++
hw/arm/meson.build | 2 +
hw/char/Kconfig | 3 +
hw/char/max78000_uart.c | 285 ++++++++++++++++++++++++++
hw/char/meson.build | 1 +
hw/misc/Kconfig | 12 ++
hw/misc/max78000_aes.c | 229 +++++++++++++++++++++
hw/misc/max78000_gcr.c | 351 ++++++++++++++++++++++++++++++++
hw/misc/max78000_icc.c | 120 +++++++++++
hw/misc/max78000_trng.c | 139 +++++++++++++
hw/misc/meson.build | 4 +
include/hw/arm/max78000_soc.h | 50 +++++
include/hw/char/max78000_uart.h | 78 +++++++
include/hw/misc/max78000_aes.h | 68 +++++++
include/hw/misc/max78000_gcr.h | 131 ++++++++++++
include/hw/misc/max78000_icc.h | 33 +++
include/hw/misc/max78000_trng.h | 35 ++++
19 files changed, 1838 insertions(+)
create mode 100644 hw/arm/max78000_soc.c
create mode 100644 hw/arm/max78000fthr.c
create mode 100644 hw/char/max78000_uart.c
create mode 100644 hw/misc/max78000_aes.c
create mode 100644 hw/misc/max78000_gcr.c
create mode 100644 hw/misc/max78000_icc.c
create mode 100644 hw/misc/max78000_trng.c
create mode 100644 include/hw/arm/max78000_soc.h
create mode 100644 include/hw/char/max78000_uart.h
create mode 100644 include/hw/misc/max78000_aes.h
create mode 100644 include/hw/misc/max78000_gcr.h
create mode 100644 include/hw/misc/max78000_icc.h
create mode 100644 include/hw/misc/max78000_trng.h
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [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
end of thread, other threads:[~2025-07-15 8:48 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH v5 03/11] MAX78000: Add ICC to SOC Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 04/11] MAX78000: UART Implementation Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 05/11] MAX78000: Add UART to SOC Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 06/11] MAX78000: GCR Implementation Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 07/11] MAX78000: Add GCR to SOC Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 08/11] MAX78000: TRNG Implementation Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 09/11] MAX78000: Add TRNG to SOC Jackson Donaldson
2025-07-15 0:00 ` [PATCH v5 10/11] MAX78000: AES implementation 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).