xref: /openbmc/qemu/hw/misc/stm32_rcc.c (revision f774a677507966222624a9b2859f06ede7608100)
1*d1613f2aSRomán Cárdenas Rodríguez /*
2*d1613f2aSRomán Cárdenas Rodríguez  * STM32 RCC (only reset and enable registers are implemented)
3*d1613f2aSRomán Cárdenas Rodríguez  *
4*d1613f2aSRomán Cárdenas Rodríguez  * Copyright (c) 2024 Román Cárdenas <rcardenas.rod@gmail.com>
5*d1613f2aSRomán Cárdenas Rodríguez  *
6*d1613f2aSRomán Cárdenas Rodríguez  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*d1613f2aSRomán Cárdenas Rodríguez  * of this software and associated documentation files (the "Software"), to deal
8*d1613f2aSRomán Cárdenas Rodríguez  * in the Software without restriction, including without limitation the rights
9*d1613f2aSRomán Cárdenas Rodríguez  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10*d1613f2aSRomán Cárdenas Rodríguez  * copies of the Software, and to permit persons to whom the Software is
11*d1613f2aSRomán Cárdenas Rodríguez  * furnished to do so, subject to the following conditions:
12*d1613f2aSRomán Cárdenas Rodríguez  *
13*d1613f2aSRomán Cárdenas Rodríguez  * The above copyright notice and this permission notice shall be included in
14*d1613f2aSRomán Cárdenas Rodríguez  * all copies or substantial portions of the Software.
15*d1613f2aSRomán Cárdenas Rodríguez  *
16*d1613f2aSRomán Cárdenas Rodríguez  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*d1613f2aSRomán Cárdenas Rodríguez  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*d1613f2aSRomán Cárdenas Rodríguez  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19*d1613f2aSRomán Cárdenas Rodríguez  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*d1613f2aSRomán Cárdenas Rodríguez  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*d1613f2aSRomán Cárdenas Rodríguez  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22*d1613f2aSRomán Cárdenas Rodríguez  * THE SOFTWARE.
23*d1613f2aSRomán Cárdenas Rodríguez  */
24*d1613f2aSRomán Cárdenas Rodríguez 
25*d1613f2aSRomán Cárdenas Rodríguez #include "qemu/osdep.h"
26*d1613f2aSRomán Cárdenas Rodríguez #include "qemu/log.h"
27*d1613f2aSRomán Cárdenas Rodríguez #include "trace.h"
28*d1613f2aSRomán Cárdenas Rodríguez #include "hw/irq.h"
29*d1613f2aSRomán Cárdenas Rodríguez #include "migration/vmstate.h"
30*d1613f2aSRomán Cárdenas Rodríguez #include "hw/misc/stm32_rcc.h"
31*d1613f2aSRomán Cárdenas Rodríguez 
stm32_rcc_reset(DeviceState * dev)32*d1613f2aSRomán Cárdenas Rodríguez static void stm32_rcc_reset(DeviceState *dev)
33*d1613f2aSRomán Cárdenas Rodríguez {
34*d1613f2aSRomán Cárdenas Rodríguez     STM32RccState *s = STM32_RCC(dev);
35*d1613f2aSRomán Cárdenas Rodríguez 
36*d1613f2aSRomán Cárdenas Rodríguez     for (int i = 0; i < STM32_RCC_NREGS; i++) {
37*d1613f2aSRomán Cárdenas Rodríguez         s->regs[i] = 0;
38*d1613f2aSRomán Cárdenas Rodríguez     }
39*d1613f2aSRomán Cárdenas Rodríguez }
40*d1613f2aSRomán Cárdenas Rodríguez 
stm32_rcc_read(void * opaque,hwaddr addr,unsigned int size)41*d1613f2aSRomán Cárdenas Rodríguez static uint64_t stm32_rcc_read(void *opaque, hwaddr addr, unsigned int size)
42*d1613f2aSRomán Cárdenas Rodríguez {
43*d1613f2aSRomán Cárdenas Rodríguez     STM32RccState *s = STM32_RCC(opaque);
44*d1613f2aSRomán Cárdenas Rodríguez 
45*d1613f2aSRomán Cárdenas Rodríguez     uint32_t value = 0;
46*d1613f2aSRomán Cárdenas Rodríguez     if (addr > STM32_RCC_DCKCFGR2) {
47*d1613f2aSRomán Cárdenas Rodríguez         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
48*d1613f2aSRomán Cárdenas Rodríguez                       __func__, addr);
49*d1613f2aSRomán Cárdenas Rodríguez     } else {
50*d1613f2aSRomán Cárdenas Rodríguez         value = s->regs[addr >> 2];
51*d1613f2aSRomán Cárdenas Rodríguez     }
52*d1613f2aSRomán Cárdenas Rodríguez     trace_stm32_rcc_read(addr, value);
53*d1613f2aSRomán Cárdenas Rodríguez     return value;
54*d1613f2aSRomán Cárdenas Rodríguez }
55*d1613f2aSRomán Cárdenas Rodríguez 
stm32_rcc_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)56*d1613f2aSRomán Cárdenas Rodríguez static void stm32_rcc_write(void *opaque, hwaddr addr,
57*d1613f2aSRomán Cárdenas Rodríguez                             uint64_t val64, unsigned int size)
58*d1613f2aSRomán Cárdenas Rodríguez {
59*d1613f2aSRomán Cárdenas Rodríguez     STM32RccState *s = STM32_RCC(opaque);
60*d1613f2aSRomán Cárdenas Rodríguez     uint32_t value = val64;
61*d1613f2aSRomán Cárdenas Rodríguez     uint32_t prev_value, new_value, irq_offset;
62*d1613f2aSRomán Cárdenas Rodríguez 
63*d1613f2aSRomán Cárdenas Rodríguez     trace_stm32_rcc_write(value, addr);
64*d1613f2aSRomán Cárdenas Rodríguez 
65*d1613f2aSRomán Cárdenas Rodríguez     if (addr > STM32_RCC_DCKCFGR2) {
66*d1613f2aSRomán Cárdenas Rodríguez         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
67*d1613f2aSRomán Cárdenas Rodríguez                       __func__, addr);
68*d1613f2aSRomán Cárdenas Rodríguez         return;
69*d1613f2aSRomán Cárdenas Rodríguez     }
70*d1613f2aSRomán Cárdenas Rodríguez 
71*d1613f2aSRomán Cárdenas Rodríguez     switch (addr) {
72*d1613f2aSRomán Cárdenas Rodríguez     case STM32_RCC_AHB1_RSTR...STM32_RCC_APB2_RSTR:
73*d1613f2aSRomán Cárdenas Rodríguez         prev_value = s->regs[addr / 4];
74*d1613f2aSRomán Cárdenas Rodríguez         s->regs[addr / 4] = value;
75*d1613f2aSRomán Cárdenas Rodríguez 
76*d1613f2aSRomán Cárdenas Rodríguez         irq_offset = ((addr - STM32_RCC_AHB1_RSTR) / 4) * 32;
77*d1613f2aSRomán Cárdenas Rodríguez         for (int i = 0; i < 32; i++) {
78*d1613f2aSRomán Cárdenas Rodríguez             new_value = extract32(value, i, 1);
79*d1613f2aSRomán Cárdenas Rodríguez             if (extract32(prev_value, i, 1) && !new_value) {
80*d1613f2aSRomán Cárdenas Rodríguez                 trace_stm32_rcc_pulse_reset(irq_offset + i, new_value);
81*d1613f2aSRomán Cárdenas Rodríguez                 qemu_set_irq(s->reset_irq[irq_offset + i], new_value);
82*d1613f2aSRomán Cárdenas Rodríguez             }
83*d1613f2aSRomán Cárdenas Rodríguez         }
84*d1613f2aSRomán Cárdenas Rodríguez         return;
85*d1613f2aSRomán Cárdenas Rodríguez     case STM32_RCC_AHB1_ENR...STM32_RCC_APB2_ENR:
86*d1613f2aSRomán Cárdenas Rodríguez         prev_value = s->regs[addr / 4];
87*d1613f2aSRomán Cárdenas Rodríguez         s->regs[addr / 4] = value;
88*d1613f2aSRomán Cárdenas Rodríguez 
89*d1613f2aSRomán Cárdenas Rodríguez         irq_offset = ((addr - STM32_RCC_AHB1_ENR) / 4) * 32;
90*d1613f2aSRomán Cárdenas Rodríguez         for (int i = 0; i < 32; i++) {
91*d1613f2aSRomán Cárdenas Rodríguez             new_value = extract32(value, i, 1);
92*d1613f2aSRomán Cárdenas Rodríguez             if (!extract32(prev_value, i, 1) && new_value) {
93*d1613f2aSRomán Cárdenas Rodríguez                 trace_stm32_rcc_pulse_enable(irq_offset + i, new_value);
94*d1613f2aSRomán Cárdenas Rodríguez                 qemu_set_irq(s->enable_irq[irq_offset + i], new_value);
95*d1613f2aSRomán Cárdenas Rodríguez             }
96*d1613f2aSRomán Cárdenas Rodríguez         }
97*d1613f2aSRomán Cárdenas Rodríguez         return;
98*d1613f2aSRomán Cárdenas Rodríguez     default:
99*d1613f2aSRomán Cárdenas Rodríguez         qemu_log_mask(
100*d1613f2aSRomán Cárdenas Rodríguez             LOG_UNIMP,
101*d1613f2aSRomán Cárdenas Rodríguez             "%s: The RCC peripheral only supports enable and reset in QEMU\n",
102*d1613f2aSRomán Cárdenas Rodríguez             __func__
103*d1613f2aSRomán Cárdenas Rodríguez         );
104*d1613f2aSRomán Cárdenas Rodríguez         s->regs[addr >> 2] = value;
105*d1613f2aSRomán Cárdenas Rodríguez     }
106*d1613f2aSRomán Cárdenas Rodríguez }
107*d1613f2aSRomán Cárdenas Rodríguez 
108*d1613f2aSRomán Cárdenas Rodríguez static const MemoryRegionOps stm32_rcc_ops = {
109*d1613f2aSRomán Cárdenas Rodríguez     .read = stm32_rcc_read,
110*d1613f2aSRomán Cárdenas Rodríguez     .write = stm32_rcc_write,
111*d1613f2aSRomán Cárdenas Rodríguez     .endianness = DEVICE_NATIVE_ENDIAN,
112*d1613f2aSRomán Cárdenas Rodríguez };
113*d1613f2aSRomán Cárdenas Rodríguez 
stm32_rcc_init(Object * obj)114*d1613f2aSRomán Cárdenas Rodríguez static void stm32_rcc_init(Object *obj)
115*d1613f2aSRomán Cárdenas Rodríguez {
116*d1613f2aSRomán Cárdenas Rodríguez     STM32RccState *s = STM32_RCC(obj);
117*d1613f2aSRomán Cárdenas Rodríguez 
118*d1613f2aSRomán Cárdenas Rodríguez     memory_region_init_io(&s->mmio, obj, &stm32_rcc_ops, s,
119*d1613f2aSRomán Cárdenas Rodríguez                           TYPE_STM32_RCC, STM32_RCC_PERIPHERAL_SIZE);
120*d1613f2aSRomán Cárdenas Rodríguez     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
121*d1613f2aSRomán Cárdenas Rodríguez 
122*d1613f2aSRomán Cárdenas Rodríguez     qdev_init_gpio_out(DEVICE(obj), s->reset_irq, STM32_RCC_NIRQS);
123*d1613f2aSRomán Cárdenas Rodríguez     qdev_init_gpio_out(DEVICE(obj), s->enable_irq, STM32_RCC_NIRQS);
124*d1613f2aSRomán Cárdenas Rodríguez 
125*d1613f2aSRomán Cárdenas Rodríguez     for (int i = 0; i < STM32_RCC_NIRQS; i++) {
126*d1613f2aSRomán Cárdenas Rodríguez         sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->reset_irq[i]);
127*d1613f2aSRomán Cárdenas Rodríguez         sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->enable_irq[i]);
128*d1613f2aSRomán Cárdenas Rodríguez     }
129*d1613f2aSRomán Cárdenas Rodríguez }
130*d1613f2aSRomán Cárdenas Rodríguez 
131*d1613f2aSRomán Cárdenas Rodríguez static const VMStateDescription vmstate_stm32_rcc = {
132*d1613f2aSRomán Cárdenas Rodríguez     .name = TYPE_STM32_RCC,
133*d1613f2aSRomán Cárdenas Rodríguez     .version_id = 1,
134*d1613f2aSRomán Cárdenas Rodríguez     .minimum_version_id = 1,
135*d1613f2aSRomán Cárdenas Rodríguez     .fields = (const VMStateField[]) {
136*d1613f2aSRomán Cárdenas Rodríguez         VMSTATE_UINT32_ARRAY(regs, STM32RccState, STM32_RCC_NREGS),
137*d1613f2aSRomán Cárdenas Rodríguez         VMSTATE_END_OF_LIST()
138*d1613f2aSRomán Cárdenas Rodríguez     }
139*d1613f2aSRomán Cárdenas Rodríguez };
140*d1613f2aSRomán Cárdenas Rodríguez 
stm32_rcc_class_init(ObjectClass * klass,void * data)141*d1613f2aSRomán Cárdenas Rodríguez static void stm32_rcc_class_init(ObjectClass *klass, void *data)
142*d1613f2aSRomán Cárdenas Rodríguez {
143*d1613f2aSRomán Cárdenas Rodríguez     DeviceClass *dc = DEVICE_CLASS(klass);
144*d1613f2aSRomán Cárdenas Rodríguez 
145*d1613f2aSRomán Cárdenas Rodríguez     dc->vmsd = &vmstate_stm32_rcc;
146*d1613f2aSRomán Cárdenas Rodríguez     device_class_set_legacy_reset(dc, stm32_rcc_reset);
147*d1613f2aSRomán Cárdenas Rodríguez }
148*d1613f2aSRomán Cárdenas Rodríguez 
149*d1613f2aSRomán Cárdenas Rodríguez static const TypeInfo stm32_rcc_info = {
150*d1613f2aSRomán Cárdenas Rodríguez     .name          = TYPE_STM32_RCC,
151*d1613f2aSRomán Cárdenas Rodríguez     .parent        = TYPE_SYS_BUS_DEVICE,
152*d1613f2aSRomán Cárdenas Rodríguez     .instance_size = sizeof(STM32RccState),
153*d1613f2aSRomán Cárdenas Rodríguez     .instance_init = stm32_rcc_init,
154*d1613f2aSRomán Cárdenas Rodríguez     .class_init    = stm32_rcc_class_init,
155*d1613f2aSRomán Cárdenas Rodríguez };
156*d1613f2aSRomán Cárdenas Rodríguez 
stm32_rcc_register_types(void)157*d1613f2aSRomán Cárdenas Rodríguez static void stm32_rcc_register_types(void)
158*d1613f2aSRomán Cárdenas Rodríguez {
159*d1613f2aSRomán Cárdenas Rodríguez     type_register_static(&stm32_rcc_info);
160*d1613f2aSRomán Cárdenas Rodríguez }
161*d1613f2aSRomán Cárdenas Rodríguez 
162*d1613f2aSRomán Cárdenas Rodríguez type_init(stm32_rcc_register_types)
163