xref: /openbmc/qemu/hw/misc/max78000_trng.c (revision 0edc2afe0c8197bbcb98f948c609fb74c9b1ffd5)
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