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 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 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 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 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 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 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