1*069852d1SJackson Donaldson /*
2*069852d1SJackson Donaldson * MAX78000 True Random Number Generator
3*069852d1SJackson Donaldson *
4*069852d1SJackson Donaldson * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
5*069852d1SJackson Donaldson *
6*069852d1SJackson Donaldson * SPDX-License-Identifier: GPL-2.0-or-later
7*069852d1SJackson Donaldson */
8*069852d1SJackson Donaldson
9*069852d1SJackson Donaldson #include "qemu/osdep.h"
10*069852d1SJackson Donaldson #include "qemu/log.h"
11*069852d1SJackson Donaldson #include "trace.h"
12*069852d1SJackson Donaldson #include "hw/irq.h"
13*069852d1SJackson Donaldson #include "migration/vmstate.h"
14*069852d1SJackson Donaldson #include "hw/misc/max78000_trng.h"
15*069852d1SJackson Donaldson #include "qemu/guest-random.h"
16*069852d1SJackson Donaldson
max78000_trng_read(void * opaque,hwaddr addr,unsigned int size)17*069852d1SJackson Donaldson static uint64_t max78000_trng_read(void *opaque, hwaddr addr,
18*069852d1SJackson Donaldson unsigned int size)
19*069852d1SJackson Donaldson {
20*069852d1SJackson Donaldson uint32_t data;
21*069852d1SJackson Donaldson
22*069852d1SJackson Donaldson Max78000TrngState *s = opaque;
23*069852d1SJackson Donaldson switch (addr) {
24*069852d1SJackson Donaldson case CTRL:
25*069852d1SJackson Donaldson return s->ctrl;
26*069852d1SJackson Donaldson
27*069852d1SJackson Donaldson case STATUS:
28*069852d1SJackson Donaldson return 1;
29*069852d1SJackson Donaldson
30*069852d1SJackson Donaldson case DATA:
31*069852d1SJackson Donaldson /*
32*069852d1SJackson Donaldson * When interrupts are enabled, reading random data should cause a
33*069852d1SJackson Donaldson * new interrupt to be generated; since there's always a random number
34*069852d1SJackson Donaldson * available, we could qemu_set_irq(s->irq, s->ctrl & RND_IE). Because
35*069852d1SJackson Donaldson * of how trng_write is set up, this is always a noop, so don't
36*069852d1SJackson Donaldson */
37*069852d1SJackson Donaldson qemu_guest_getrandom_nofail(&data, sizeof(data));
38*069852d1SJackson Donaldson return data;
39*069852d1SJackson Donaldson
40*069852d1SJackson Donaldson default:
41*069852d1SJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
42*069852d1SJackson Donaldson HWADDR_PRIx "\n", __func__, addr);
43*069852d1SJackson Donaldson break;
44*069852d1SJackson Donaldson }
45*069852d1SJackson Donaldson return 0;
46*069852d1SJackson Donaldson }
47*069852d1SJackson Donaldson
max78000_trng_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)48*069852d1SJackson Donaldson static void max78000_trng_write(void *opaque, hwaddr addr,
49*069852d1SJackson Donaldson uint64_t val64, unsigned int size)
50*069852d1SJackson Donaldson {
51*069852d1SJackson Donaldson Max78000TrngState *s = opaque;
52*069852d1SJackson Donaldson uint32_t val = val64;
53*069852d1SJackson Donaldson switch (addr) {
54*069852d1SJackson Donaldson case CTRL:
55*069852d1SJackson Donaldson /* TODO: implement AES keygen */
56*069852d1SJackson Donaldson s->ctrl = val;
57*069852d1SJackson Donaldson
58*069852d1SJackson Donaldson /*
59*069852d1SJackson Donaldson * This device models random number generation as taking 0 time.
60*069852d1SJackson Donaldson * A new random number is always available, so the condition for the
61*069852d1SJackson Donaldson * RND interrupt is always fulfilled; we can just set irq to 1.
62*069852d1SJackson Donaldson */
63*069852d1SJackson Donaldson if (val & RND_IE) {
64*069852d1SJackson Donaldson qemu_set_irq(s->irq, 1);
65*069852d1SJackson Donaldson } else{
66*069852d1SJackson Donaldson qemu_set_irq(s->irq, 0);
67*069852d1SJackson Donaldson }
68*069852d1SJackson Donaldson break;
69*069852d1SJackson Donaldson
70*069852d1SJackson Donaldson default:
71*069852d1SJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
72*069852d1SJackson Donaldson HWADDR_PRIx "\n", __func__, addr);
73*069852d1SJackson Donaldson break;
74*069852d1SJackson Donaldson }
75*069852d1SJackson Donaldson }
76*069852d1SJackson Donaldson
max78000_trng_reset_hold(Object * obj,ResetType type)77*069852d1SJackson Donaldson static void max78000_trng_reset_hold(Object *obj, ResetType type)
78*069852d1SJackson Donaldson {
79*069852d1SJackson Donaldson Max78000TrngState *s = MAX78000_TRNG(obj);
80*069852d1SJackson Donaldson s->ctrl = 0;
81*069852d1SJackson Donaldson s->status = 0;
82*069852d1SJackson Donaldson s->data = 0;
83*069852d1SJackson Donaldson }
84*069852d1SJackson Donaldson
85*069852d1SJackson Donaldson static const MemoryRegionOps max78000_trng_ops = {
86*069852d1SJackson Donaldson .read = max78000_trng_read,
87*069852d1SJackson Donaldson .write = max78000_trng_write,
88*069852d1SJackson Donaldson .endianness = DEVICE_LITTLE_ENDIAN,
89*069852d1SJackson Donaldson .valid.min_access_size = 4,
90*069852d1SJackson Donaldson .valid.max_access_size = 4,
91*069852d1SJackson Donaldson };
92*069852d1SJackson Donaldson
93*069852d1SJackson Donaldson static const VMStateDescription max78000_trng_vmstate = {
94*069852d1SJackson Donaldson .name = TYPE_MAX78000_TRNG,
95*069852d1SJackson Donaldson .version_id = 1,
96*069852d1SJackson Donaldson .minimum_version_id = 1,
97*069852d1SJackson Donaldson .fields = (const VMStateField[]) {
98*069852d1SJackson Donaldson VMSTATE_UINT32(ctrl, Max78000TrngState),
99*069852d1SJackson Donaldson VMSTATE_UINT32(status, Max78000TrngState),
100*069852d1SJackson Donaldson VMSTATE_UINT32(data, Max78000TrngState),
101*069852d1SJackson Donaldson VMSTATE_END_OF_LIST()
102*069852d1SJackson Donaldson }
103*069852d1SJackson Donaldson };
104*069852d1SJackson Donaldson
max78000_trng_init(Object * obj)105*069852d1SJackson Donaldson static void max78000_trng_init(Object *obj)
106*069852d1SJackson Donaldson {
107*069852d1SJackson Donaldson Max78000TrngState *s = MAX78000_TRNG(obj);
108*069852d1SJackson Donaldson sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
109*069852d1SJackson Donaldson
110*069852d1SJackson Donaldson memory_region_init_io(&s->mmio, obj, &max78000_trng_ops, s,
111*069852d1SJackson Donaldson TYPE_MAX78000_TRNG, 0x1000);
112*069852d1SJackson Donaldson sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
113*069852d1SJackson Donaldson
114*069852d1SJackson Donaldson }
115*069852d1SJackson Donaldson
max78000_trng_class_init(ObjectClass * klass,const void * data)116*069852d1SJackson Donaldson static void max78000_trng_class_init(ObjectClass *klass, const void *data)
117*069852d1SJackson Donaldson {
118*069852d1SJackson Donaldson ResettableClass *rc = RESETTABLE_CLASS(klass);
119*069852d1SJackson Donaldson DeviceClass *dc = DEVICE_CLASS(klass);
120*069852d1SJackson Donaldson
121*069852d1SJackson Donaldson rc->phases.hold = max78000_trng_reset_hold;
122*069852d1SJackson Donaldson dc->vmsd = &max78000_trng_vmstate;
123*069852d1SJackson Donaldson
124*069852d1SJackson Donaldson }
125*069852d1SJackson Donaldson
126*069852d1SJackson Donaldson static const TypeInfo max78000_trng_info = {
127*069852d1SJackson Donaldson .name = TYPE_MAX78000_TRNG,
128*069852d1SJackson Donaldson .parent = TYPE_SYS_BUS_DEVICE,
129*069852d1SJackson Donaldson .instance_size = sizeof(Max78000TrngState),
130*069852d1SJackson Donaldson .instance_init = max78000_trng_init,
131*069852d1SJackson Donaldson .class_init = max78000_trng_class_init,
132*069852d1SJackson Donaldson };
133*069852d1SJackson Donaldson
max78000_trng_register_types(void)134*069852d1SJackson Donaldson static void max78000_trng_register_types(void)
135*069852d1SJackson Donaldson {
136*069852d1SJackson Donaldson type_register_static(&max78000_trng_info);
137*069852d1SJackson Donaldson }
138*069852d1SJackson Donaldson
139*069852d1SJackson Donaldson type_init(max78000_trng_register_types)
140