1d6b55a0fSArnaud Minier /* 2d6b55a0fSArnaud Minier * STM32L4X5 RCC (Reset and clock control) 3d6b55a0fSArnaud Minier * 4d6b55a0fSArnaud Minier * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr> 5d6b55a0fSArnaud Minier * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr> 6d6b55a0fSArnaud Minier * 7d6b55a0fSArnaud Minier * SPDX-License-Identifier: GPL-2.0-or-later 8d6b55a0fSArnaud Minier * 9d6b55a0fSArnaud Minier * This work is licensed under the terms of the GNU GPL, version 2 or later. 10d6b55a0fSArnaud Minier * See the COPYING file in the top-level directory. 11d6b55a0fSArnaud Minier * 12d6b55a0fSArnaud Minier * The reference used is the STMicroElectronics RM0351 Reference manual 13d6b55a0fSArnaud Minier * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs. 14d6b55a0fSArnaud Minier * 15d6b55a0fSArnaud Minier * Inspired by the BCM2835 CPRMAN clock manager implementation by Luc Michel. 16d6b55a0fSArnaud Minier */ 17d6b55a0fSArnaud Minier 18d6b55a0fSArnaud Minier #include "qemu/osdep.h" 19d6b55a0fSArnaud Minier #include "qemu/log.h" 20d6b55a0fSArnaud Minier #include "qemu/module.h" 21d6b55a0fSArnaud Minier #include "qemu/timer.h" 22d6b55a0fSArnaud Minier #include "qapi/error.h" 23d6b55a0fSArnaud Minier #include "migration/vmstate.h" 24d6b55a0fSArnaud Minier #include "hw/misc/stm32l4x5_rcc.h" 25d6b55a0fSArnaud Minier #include "hw/misc/stm32l4x5_rcc_internals.h" 26d6b55a0fSArnaud Minier #include "hw/clock.h" 27d6b55a0fSArnaud Minier #include "hw/irq.h" 28d6b55a0fSArnaud Minier #include "hw/qdev-clock.h" 29d6b55a0fSArnaud Minier #include "hw/qdev-properties.h" 30d6b55a0fSArnaud Minier #include "hw/qdev-properties-system.h" 31d6b55a0fSArnaud Minier #include "trace.h" 32d6b55a0fSArnaud Minier 33d6b55a0fSArnaud Minier #define HSE_DEFAULT_FRQ 48000000ULL 34d6b55a0fSArnaud Minier #define HSI_FRQ 16000000ULL 35d6b55a0fSArnaud Minier #define MSI_DEFAULT_FRQ 4000000ULL 36d6b55a0fSArnaud Minier #define LSE_FRQ 32768ULL 37d6b55a0fSArnaud Minier #define LSI_FRQ 32000ULL 38d6b55a0fSArnaud Minier 39*141c29a2SArnaud Minier /* 40*141c29a2SArnaud Minier * Function to simply acknowledge and propagate changes in a clock mux 41*141c29a2SArnaud Minier * frequency. 42*141c29a2SArnaud Minier * `bypass_source` allows to bypass the period of the current source and just 43*141c29a2SArnaud Minier * consider it equal to 0. This is useful during the hold phase of reset. 44*141c29a2SArnaud Minier */ 45*141c29a2SArnaud Minier static void clock_mux_update(RccClockMuxState *mux, bool bypass_source) 46ec7d83acSArnaud Minier { 47ec7d83acSArnaud Minier uint64_t src_freq; 48ec7d83acSArnaud Minier Clock *current_source = mux->srcs[mux->src]; 49ec7d83acSArnaud Minier uint32_t freq_multiplier = 0; 50ec7d83acSArnaud Minier /* 51ec7d83acSArnaud Minier * To avoid rounding errors, we use the clock period instead of the 52ec7d83acSArnaud Minier * frequency. 53ec7d83acSArnaud Minier * This means that the multiplier of the mux becomes the divider of 54ec7d83acSArnaud Minier * the clock and the divider of the mux becomes the multiplier of the 55ec7d83acSArnaud Minier * clock. 56ec7d83acSArnaud Minier */ 57*141c29a2SArnaud Minier if (!bypass_source && mux->enabled && mux->divider) { 58ec7d83acSArnaud Minier freq_multiplier = mux->divider; 59ec7d83acSArnaud Minier } 60ec7d83acSArnaud Minier 61ec7d83acSArnaud Minier clock_set_mul_div(mux->out, freq_multiplier, mux->multiplier); 62ec7d83acSArnaud Minier clock_update(mux->out, clock_get(current_source)); 63ec7d83acSArnaud Minier 64ec7d83acSArnaud Minier src_freq = clock_get_hz(current_source); 65ec7d83acSArnaud Minier /* TODO: can we simply detect if the config changed so that we reduce log spam ? */ 66ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_update(mux->id, mux->src, src_freq, 67ec7d83acSArnaud Minier mux->multiplier, mux->divider); 68ec7d83acSArnaud Minier } 69ec7d83acSArnaud Minier 70ec7d83acSArnaud Minier static void clock_mux_src_update(void *opaque, ClockEvent event) 71ec7d83acSArnaud Minier { 72ec7d83acSArnaud Minier RccClockMuxState **backref = opaque; 73ec7d83acSArnaud Minier RccClockMuxState *s = *backref; 74ec7d83acSArnaud Minier /* 75ec7d83acSArnaud Minier * The backref value is equal to: 76ec7d83acSArnaud Minier * s->backref + (sizeof(RccClockMuxState *) * update_src). 77ec7d83acSArnaud Minier * By subtracting we can get back the index of the updated clock. 78ec7d83acSArnaud Minier */ 79ec7d83acSArnaud Minier const uint32_t update_src = backref - s->backref; 80ec7d83acSArnaud Minier /* Only update if the clock that was updated is the current source */ 81ec7d83acSArnaud Minier if (update_src == s->src) { 82*141c29a2SArnaud Minier clock_mux_update(s, false); 83ec7d83acSArnaud Minier } 84ec7d83acSArnaud Minier } 85ec7d83acSArnaud Minier 86ec7d83acSArnaud Minier static void clock_mux_init(Object *obj) 87ec7d83acSArnaud Minier { 88ec7d83acSArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 89ec7d83acSArnaud Minier size_t i; 90ec7d83acSArnaud Minier 91ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { 92ec7d83acSArnaud Minier char *name = g_strdup_printf("srcs[%zu]", i); 93ec7d83acSArnaud Minier s->backref[i] = s; 94ec7d83acSArnaud Minier s->srcs[i] = qdev_init_clock_in(DEVICE(s), name, 95ec7d83acSArnaud Minier clock_mux_src_update, 96ec7d83acSArnaud Minier &s->backref[i], 97ec7d83acSArnaud Minier ClockUpdate); 98ec7d83acSArnaud Minier g_free(name); 99ec7d83acSArnaud Minier } 100ec7d83acSArnaud Minier 101ec7d83acSArnaud Minier s->out = qdev_init_clock_out(DEVICE(s), "out"); 102ec7d83acSArnaud Minier } 103ec7d83acSArnaud Minier 104*141c29a2SArnaud Minier static void clock_mux_reset_enter(Object *obj, ResetType type) 105*141c29a2SArnaud Minier { 106*141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 107*141c29a2SArnaud Minier set_clock_mux_init_info(s, s->id); 108*141c29a2SArnaud Minier } 109*141c29a2SArnaud Minier 110ec7d83acSArnaud Minier static void clock_mux_reset_hold(Object *obj) 111*141c29a2SArnaud Minier { 112*141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 113*141c29a2SArnaud Minier clock_mux_update(s, true); 114*141c29a2SArnaud Minier } 115*141c29a2SArnaud Minier 116*141c29a2SArnaud Minier static void clock_mux_reset_exit(Object *obj) 117*141c29a2SArnaud Minier { 118*141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 119*141c29a2SArnaud Minier clock_mux_update(s, false); 120*141c29a2SArnaud Minier } 121ec7d83acSArnaud Minier 122ec7d83acSArnaud Minier static const VMStateDescription clock_mux_vmstate = { 123ec7d83acSArnaud Minier .name = TYPE_RCC_CLOCK_MUX, 124ec7d83acSArnaud Minier .version_id = 1, 125ec7d83acSArnaud Minier .minimum_version_id = 1, 126ec7d83acSArnaud Minier .fields = (VMStateField[]) { 127ec7d83acSArnaud Minier VMSTATE_UINT32(id, RccClockMuxState), 128ec7d83acSArnaud Minier VMSTATE_ARRAY_CLOCK(srcs, RccClockMuxState, 129ec7d83acSArnaud Minier RCC_NUM_CLOCK_MUX_SRC), 130ec7d83acSArnaud Minier VMSTATE_BOOL(enabled, RccClockMuxState), 131ec7d83acSArnaud Minier VMSTATE_UINT32(src, RccClockMuxState), 132ec7d83acSArnaud Minier VMSTATE_UINT32(multiplier, RccClockMuxState), 133ec7d83acSArnaud Minier VMSTATE_UINT32(divider, RccClockMuxState), 134ec7d83acSArnaud Minier VMSTATE_END_OF_LIST() 135ec7d83acSArnaud Minier } 136ec7d83acSArnaud Minier }; 137ec7d83acSArnaud Minier 138ec7d83acSArnaud Minier static void clock_mux_class_init(ObjectClass *klass, void *data) 139ec7d83acSArnaud Minier { 140ec7d83acSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 141ec7d83acSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 142ec7d83acSArnaud Minier 143*141c29a2SArnaud Minier rc->phases.enter = clock_mux_reset_enter; 144ec7d83acSArnaud Minier rc->phases.hold = clock_mux_reset_hold; 145*141c29a2SArnaud Minier rc->phases.exit = clock_mux_reset_exit; 146ec7d83acSArnaud Minier dc->vmsd = &clock_mux_vmstate; 147ec7d83acSArnaud Minier } 148ec7d83acSArnaud Minier 149ec7d83acSArnaud Minier static void clock_mux_set_enable(RccClockMuxState *mux, bool enabled) 150ec7d83acSArnaud Minier { 151ec7d83acSArnaud Minier if (mux->enabled == enabled) { 152ec7d83acSArnaud Minier return; 153ec7d83acSArnaud Minier } 154ec7d83acSArnaud Minier 155ec7d83acSArnaud Minier if (enabled) { 156ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_enable(mux->id); 157ec7d83acSArnaud Minier } else { 158ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_disable(mux->id); 159ec7d83acSArnaud Minier } 160ec7d83acSArnaud Minier 161ec7d83acSArnaud Minier mux->enabled = enabled; 162*141c29a2SArnaud Minier clock_mux_update(mux, false); 163ec7d83acSArnaud Minier } 164ec7d83acSArnaud Minier 165ec7d83acSArnaud Minier static void clock_mux_set_factor(RccClockMuxState *mux, 166ec7d83acSArnaud Minier uint32_t multiplier, uint32_t divider) 167ec7d83acSArnaud Minier { 168ec7d83acSArnaud Minier if (mux->multiplier == multiplier && mux->divider == divider) { 169ec7d83acSArnaud Minier return; 170ec7d83acSArnaud Minier } 171ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_set_factor(mux->id, 172ec7d83acSArnaud Minier mux->multiplier, multiplier, mux->divider, divider); 173ec7d83acSArnaud Minier 174ec7d83acSArnaud Minier mux->multiplier = multiplier; 175ec7d83acSArnaud Minier mux->divider = divider; 176*141c29a2SArnaud Minier clock_mux_update(mux, false); 177ec7d83acSArnaud Minier } 178ec7d83acSArnaud Minier 179ec7d83acSArnaud Minier static void clock_mux_set_source(RccClockMuxState *mux, RccClockMuxSource src) 180ec7d83acSArnaud Minier { 181ec7d83acSArnaud Minier if (mux->src == src) { 182ec7d83acSArnaud Minier return; 183ec7d83acSArnaud Minier } 184ec7d83acSArnaud Minier 185ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_set_src(mux->id, mux->src, src); 186ec7d83acSArnaud Minier mux->src = src; 187*141c29a2SArnaud Minier clock_mux_update(mux, false); 188ec7d83acSArnaud Minier } 189ec7d83acSArnaud Minier 190*141c29a2SArnaud Minier /* 191*141c29a2SArnaud Minier * Acknowledge and propagate changes in a PLL frequency. 192*141c29a2SArnaud Minier * `bypass_source` allows to bypass the period of the current source and just 193*141c29a2SArnaud Minier * consider it equal to 0. This is useful during the hold phase of reset. 194*141c29a2SArnaud Minier */ 195*141c29a2SArnaud Minier static void pll_update(RccPllState *pll, bool bypass_source) 1966487653eSArnaud Minier { 1976487653eSArnaud Minier uint64_t vco_freq, old_channel_freq, channel_freq; 1986487653eSArnaud Minier int i; 1996487653eSArnaud Minier 2006487653eSArnaud Minier /* The common PLLM factor is handled by the PLL mux */ 2016487653eSArnaud Minier vco_freq = muldiv64(clock_get_hz(pll->in), pll->vco_multiplier, 1); 2026487653eSArnaud Minier 2036487653eSArnaud Minier for (i = 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { 2046487653eSArnaud Minier if (!pll->channel_exists[i]) { 2056487653eSArnaud Minier continue; 2066487653eSArnaud Minier } 2076487653eSArnaud Minier 2086487653eSArnaud Minier old_channel_freq = clock_get_hz(pll->channels[i]); 209*141c29a2SArnaud Minier if (bypass_source || 210*141c29a2SArnaud Minier !pll->enabled || 2116487653eSArnaud Minier !pll->channel_enabled[i] || 2126487653eSArnaud Minier !pll->channel_divider[i]) { 2136487653eSArnaud Minier channel_freq = 0; 2146487653eSArnaud Minier } else { 2156487653eSArnaud Minier channel_freq = muldiv64(vco_freq, 2166487653eSArnaud Minier 1, 2176487653eSArnaud Minier pll->channel_divider[i]); 2186487653eSArnaud Minier } 2196487653eSArnaud Minier 2206487653eSArnaud Minier /* No change, early continue to avoid log spam and useless propagation */ 2216487653eSArnaud Minier if (old_channel_freq == channel_freq) { 2226487653eSArnaud Minier continue; 2236487653eSArnaud Minier } 2246487653eSArnaud Minier 2256487653eSArnaud Minier clock_update_hz(pll->channels[i], channel_freq); 2266487653eSArnaud Minier trace_stm32l4x5_rcc_pll_update(pll->id, i, vco_freq, 2276487653eSArnaud Minier old_channel_freq, channel_freq); 2286487653eSArnaud Minier } 2296487653eSArnaud Minier } 2306487653eSArnaud Minier 2316487653eSArnaud Minier static void pll_src_update(void *opaque, ClockEvent event) 2326487653eSArnaud Minier { 2336487653eSArnaud Minier RccPllState *s = opaque; 234*141c29a2SArnaud Minier pll_update(s, false); 2356487653eSArnaud Minier } 2366487653eSArnaud Minier 2376487653eSArnaud Minier static void pll_init(Object *obj) 2386487653eSArnaud Minier { 2396487653eSArnaud Minier RccPllState *s = RCC_PLL(obj); 2406487653eSArnaud Minier size_t i; 2416487653eSArnaud Minier 2426487653eSArnaud Minier s->in = qdev_init_clock_in(DEVICE(s), "in", 2436487653eSArnaud Minier pll_src_update, s, ClockUpdate); 2446487653eSArnaud Minier 2456487653eSArnaud Minier const char *names[] = { 2466487653eSArnaud Minier "out-p", "out-q", "out-r", 2476487653eSArnaud Minier }; 2486487653eSArnaud Minier 2496487653eSArnaud Minier for (i = 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { 2506487653eSArnaud Minier s->channels[i] = qdev_init_clock_out(DEVICE(s), names[i]); 2516487653eSArnaud Minier } 2526487653eSArnaud Minier } 2536487653eSArnaud Minier 254*141c29a2SArnaud Minier static void pll_reset_enter(Object *obj, ResetType type) 255*141c29a2SArnaud Minier { 256*141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 257*141c29a2SArnaud Minier set_pll_init_info(s, s->id); 258*141c29a2SArnaud Minier } 259*141c29a2SArnaud Minier 2606487653eSArnaud Minier static void pll_reset_hold(Object *obj) 261*141c29a2SArnaud Minier { 262*141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 263*141c29a2SArnaud Minier pll_update(s, true); 264*141c29a2SArnaud Minier } 265*141c29a2SArnaud Minier 266*141c29a2SArnaud Minier static void pll_reset_exit(Object *obj) 267*141c29a2SArnaud Minier { 268*141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 269*141c29a2SArnaud Minier pll_update(s, false); 270*141c29a2SArnaud Minier } 2716487653eSArnaud Minier 2726487653eSArnaud Minier static const VMStateDescription pll_vmstate = { 2736487653eSArnaud Minier .name = TYPE_RCC_PLL, 2746487653eSArnaud Minier .version_id = 1, 2756487653eSArnaud Minier .minimum_version_id = 1, 2766487653eSArnaud Minier .fields = (VMStateField[]) { 2776487653eSArnaud Minier VMSTATE_UINT32(id, RccPllState), 2786487653eSArnaud Minier VMSTATE_CLOCK(in, RccPllState), 2796487653eSArnaud Minier VMSTATE_ARRAY_CLOCK(channels, RccPllState, 2806487653eSArnaud Minier RCC_NUM_CHANNEL_PLL_OUT), 2816487653eSArnaud Minier VMSTATE_BOOL(enabled, RccPllState), 2826487653eSArnaud Minier VMSTATE_UINT32(vco_multiplier, RccPllState), 2836487653eSArnaud Minier VMSTATE_BOOL_ARRAY(channel_enabled, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2846487653eSArnaud Minier VMSTATE_BOOL_ARRAY(channel_exists, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2856487653eSArnaud Minier VMSTATE_UINT32_ARRAY(channel_divider, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2866487653eSArnaud Minier VMSTATE_END_OF_LIST() 2876487653eSArnaud Minier } 2886487653eSArnaud Minier }; 2896487653eSArnaud Minier 2906487653eSArnaud Minier static void pll_class_init(ObjectClass *klass, void *data) 2916487653eSArnaud Minier { 2926487653eSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 2936487653eSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 2946487653eSArnaud Minier 295*141c29a2SArnaud Minier rc->phases.enter = pll_reset_enter; 2966487653eSArnaud Minier rc->phases.hold = pll_reset_hold; 297*141c29a2SArnaud Minier rc->phases.exit = pll_reset_exit; 2986487653eSArnaud Minier dc->vmsd = &pll_vmstate; 2996487653eSArnaud Minier } 3006487653eSArnaud Minier 3016487653eSArnaud Minier static void pll_set_vco_multiplier(RccPllState *pll, uint32_t vco_multiplier) 3026487653eSArnaud Minier { 3036487653eSArnaud Minier if (pll->vco_multiplier == vco_multiplier) { 3046487653eSArnaud Minier return; 3056487653eSArnaud Minier } 3066487653eSArnaud Minier 3076487653eSArnaud Minier if (vco_multiplier < 8 || vco_multiplier > 86) { 3086487653eSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 3096487653eSArnaud Minier "%s: VCO multiplier is out of bound (%u) for PLL %u\n", 3106487653eSArnaud Minier __func__, vco_multiplier, pll->id); 3116487653eSArnaud Minier return; 3126487653eSArnaud Minier } 3136487653eSArnaud Minier 3146487653eSArnaud Minier trace_stm32l4x5_rcc_pll_set_vco_multiplier(pll->id, 3156487653eSArnaud Minier pll->vco_multiplier, vco_multiplier); 3166487653eSArnaud Minier 3176487653eSArnaud Minier pll->vco_multiplier = vco_multiplier; 318*141c29a2SArnaud Minier pll_update(pll, false); 3196487653eSArnaud Minier } 3206487653eSArnaud Minier 3216487653eSArnaud Minier static void pll_set_enable(RccPllState *pll, bool enabled) 3226487653eSArnaud Minier { 3236487653eSArnaud Minier if (pll->enabled == enabled) { 3246487653eSArnaud Minier return; 3256487653eSArnaud Minier } 3266487653eSArnaud Minier 3276487653eSArnaud Minier pll->enabled = enabled; 328*141c29a2SArnaud Minier pll_update(pll, false); 3296487653eSArnaud Minier } 3306487653eSArnaud Minier 3316487653eSArnaud Minier static void pll_set_channel_enable(RccPllState *pll, 3326487653eSArnaud Minier PllCommonChannels channel, 3336487653eSArnaud Minier bool enabled) 3346487653eSArnaud Minier { 3356487653eSArnaud Minier if (pll->channel_enabled[channel] == enabled) { 3366487653eSArnaud Minier return; 3376487653eSArnaud Minier } 3386487653eSArnaud Minier 3396487653eSArnaud Minier if (enabled) { 3406487653eSArnaud Minier trace_stm32l4x5_rcc_pll_channel_enable(pll->id, channel); 3416487653eSArnaud Minier } else { 3426487653eSArnaud Minier trace_stm32l4x5_rcc_pll_channel_disable(pll->id, channel); 3436487653eSArnaud Minier } 3446487653eSArnaud Minier 3456487653eSArnaud Minier pll->channel_enabled[channel] = enabled; 346*141c29a2SArnaud Minier pll_update(pll, false); 3476487653eSArnaud Minier } 3486487653eSArnaud Minier 3496487653eSArnaud Minier static void pll_set_channel_divider(RccPllState *pll, 3506487653eSArnaud Minier PllCommonChannels channel, 3516487653eSArnaud Minier uint32_t divider) 3526487653eSArnaud Minier { 3536487653eSArnaud Minier if (pll->channel_divider[channel] == divider) { 3546487653eSArnaud Minier return; 3556487653eSArnaud Minier } 3566487653eSArnaud Minier 3576487653eSArnaud Minier trace_stm32l4x5_rcc_pll_set_channel_divider(pll->id, 3586487653eSArnaud Minier channel, pll->channel_divider[channel], divider); 3596487653eSArnaud Minier 3606487653eSArnaud Minier pll->channel_divider[channel] = divider; 361*141c29a2SArnaud Minier pll_update(pll, false); 3626487653eSArnaud Minier } 3636487653eSArnaud Minier 364d6b55a0fSArnaud Minier static void rcc_update_irq(Stm32l4x5RccState *s) 365d6b55a0fSArnaud Minier { 366d6b55a0fSArnaud Minier if (s->cifr & CIFR_IRQ_MASK) { 367d6b55a0fSArnaud Minier qemu_irq_raise(s->irq); 368d6b55a0fSArnaud Minier } else { 369d6b55a0fSArnaud Minier qemu_irq_lower(s->irq); 370d6b55a0fSArnaud Minier } 371d6b55a0fSArnaud Minier } 372d6b55a0fSArnaud Minier 373d6b55a0fSArnaud Minier static void stm32l4x5_rcc_reset_hold(Object *obj) 374d6b55a0fSArnaud Minier { 375d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(obj); 376d6b55a0fSArnaud Minier s->cr = 0x00000063; 377d6b55a0fSArnaud Minier /* 378d6b55a0fSArnaud Minier * Factory-programmed calibration data 379d6b55a0fSArnaud Minier * From the reference manual: 0x10XX 00XX 380d6b55a0fSArnaud Minier * Value taken from a real card. 381d6b55a0fSArnaud Minier */ 382d6b55a0fSArnaud Minier s->icscr = 0x106E0082; 383d6b55a0fSArnaud Minier s->cfgr = 0x0; 384d6b55a0fSArnaud Minier s->pllcfgr = 0x00001000; 385d6b55a0fSArnaud Minier s->pllsai1cfgr = 0x00001000; 386d6b55a0fSArnaud Minier s->pllsai2cfgr = 0x00001000; 387d6b55a0fSArnaud Minier s->cier = 0x0; 388d6b55a0fSArnaud Minier s->cifr = 0x0; 389d6b55a0fSArnaud Minier s->ahb1rstr = 0x0; 390d6b55a0fSArnaud Minier s->ahb2rstr = 0x0; 391d6b55a0fSArnaud Minier s->ahb3rstr = 0x0; 392d6b55a0fSArnaud Minier s->apb1rstr1 = 0x0; 393d6b55a0fSArnaud Minier s->apb1rstr2 = 0x0; 394d6b55a0fSArnaud Minier s->apb2rstr = 0x0; 395d6b55a0fSArnaud Minier s->ahb1enr = 0x00000100; 396d6b55a0fSArnaud Minier s->ahb2enr = 0x0; 397d6b55a0fSArnaud Minier s->ahb3enr = 0x0; 398d6b55a0fSArnaud Minier s->apb1enr1 = 0x0; 399d6b55a0fSArnaud Minier s->apb1enr2 = 0x0; 400d6b55a0fSArnaud Minier s->apb2enr = 0x0; 401d6b55a0fSArnaud Minier s->ahb1smenr = 0x00011303; 402d6b55a0fSArnaud Minier s->ahb2smenr = 0x000532FF; 403d6b55a0fSArnaud Minier s->ahb3smenr = 0x00000101; 404d6b55a0fSArnaud Minier s->apb1smenr1 = 0xF2FECA3F; 405d6b55a0fSArnaud Minier s->apb1smenr2 = 0x00000025; 406d6b55a0fSArnaud Minier s->apb2smenr = 0x01677C01; 407d6b55a0fSArnaud Minier s->ccipr = 0x0; 408d6b55a0fSArnaud Minier s->bdcr = 0x0; 409d6b55a0fSArnaud Minier s->csr = 0x0C000600; 410d6b55a0fSArnaud Minier } 411d6b55a0fSArnaud Minier 412d6b55a0fSArnaud Minier static uint64_t stm32l4x5_rcc_read(void *opaque, hwaddr addr, 413d6b55a0fSArnaud Minier unsigned int size) 414d6b55a0fSArnaud Minier { 415d6b55a0fSArnaud Minier Stm32l4x5RccState *s = opaque; 416d6b55a0fSArnaud Minier uint64_t retvalue = 0; 417d6b55a0fSArnaud Minier 418d6b55a0fSArnaud Minier switch (addr) { 419d6b55a0fSArnaud Minier case A_CR: 420d6b55a0fSArnaud Minier retvalue = s->cr; 421d6b55a0fSArnaud Minier break; 422d6b55a0fSArnaud Minier case A_ICSCR: 423d6b55a0fSArnaud Minier retvalue = s->icscr; 424d6b55a0fSArnaud Minier break; 425d6b55a0fSArnaud Minier case A_CFGR: 426d6b55a0fSArnaud Minier retvalue = s->cfgr; 427d6b55a0fSArnaud Minier break; 428d6b55a0fSArnaud Minier case A_PLLCFGR: 429d6b55a0fSArnaud Minier retvalue = s->pllcfgr; 430d6b55a0fSArnaud Minier break; 431d6b55a0fSArnaud Minier case A_PLLSAI1CFGR: 432d6b55a0fSArnaud Minier retvalue = s->pllsai1cfgr; 433d6b55a0fSArnaud Minier break; 434d6b55a0fSArnaud Minier case A_PLLSAI2CFGR: 435d6b55a0fSArnaud Minier retvalue = s->pllsai2cfgr; 436d6b55a0fSArnaud Minier break; 437d6b55a0fSArnaud Minier case A_CIER: 438d6b55a0fSArnaud Minier retvalue = s->cier; 439d6b55a0fSArnaud Minier break; 440d6b55a0fSArnaud Minier case A_CIFR: 441d6b55a0fSArnaud Minier retvalue = s->cifr; 442d6b55a0fSArnaud Minier break; 443d6b55a0fSArnaud Minier case A_CICR: 444d6b55a0fSArnaud Minier /* CICR is write only, return the reset value = 0 */ 445d6b55a0fSArnaud Minier break; 446d6b55a0fSArnaud Minier case A_AHB1RSTR: 447d6b55a0fSArnaud Minier retvalue = s->ahb1rstr; 448d6b55a0fSArnaud Minier break; 449d6b55a0fSArnaud Minier case A_AHB2RSTR: 450d6b55a0fSArnaud Minier retvalue = s->ahb2rstr; 451d6b55a0fSArnaud Minier break; 452d6b55a0fSArnaud Minier case A_AHB3RSTR: 453d6b55a0fSArnaud Minier retvalue = s->ahb3rstr; 454d6b55a0fSArnaud Minier break; 455d6b55a0fSArnaud Minier case A_APB1RSTR1: 456d6b55a0fSArnaud Minier retvalue = s->apb1rstr1; 457d6b55a0fSArnaud Minier break; 458d6b55a0fSArnaud Minier case A_APB1RSTR2: 459d6b55a0fSArnaud Minier retvalue = s->apb1rstr2; 460d6b55a0fSArnaud Minier break; 461d6b55a0fSArnaud Minier case A_APB2RSTR: 462d6b55a0fSArnaud Minier retvalue = s->apb2rstr; 463d6b55a0fSArnaud Minier break; 464d6b55a0fSArnaud Minier case A_AHB1ENR: 465d6b55a0fSArnaud Minier retvalue = s->ahb1enr; 466d6b55a0fSArnaud Minier break; 467d6b55a0fSArnaud Minier case A_AHB2ENR: 468d6b55a0fSArnaud Minier retvalue = s->ahb2enr; 469d6b55a0fSArnaud Minier break; 470d6b55a0fSArnaud Minier case A_AHB3ENR: 471d6b55a0fSArnaud Minier retvalue = s->ahb3enr; 472d6b55a0fSArnaud Minier break; 473d6b55a0fSArnaud Minier case A_APB1ENR1: 474d6b55a0fSArnaud Minier retvalue = s->apb1enr1; 475d6b55a0fSArnaud Minier break; 476d6b55a0fSArnaud Minier case A_APB1ENR2: 477d6b55a0fSArnaud Minier retvalue = s->apb1enr2; 478d6b55a0fSArnaud Minier break; 479d6b55a0fSArnaud Minier case A_APB2ENR: 480d6b55a0fSArnaud Minier retvalue = s->apb2enr; 481d6b55a0fSArnaud Minier break; 482d6b55a0fSArnaud Minier case A_AHB1SMENR: 483d6b55a0fSArnaud Minier retvalue = s->ahb1smenr; 484d6b55a0fSArnaud Minier break; 485d6b55a0fSArnaud Minier case A_AHB2SMENR: 486d6b55a0fSArnaud Minier retvalue = s->ahb2smenr; 487d6b55a0fSArnaud Minier break; 488d6b55a0fSArnaud Minier case A_AHB3SMENR: 489d6b55a0fSArnaud Minier retvalue = s->ahb3smenr; 490d6b55a0fSArnaud Minier break; 491d6b55a0fSArnaud Minier case A_APB1SMENR1: 492d6b55a0fSArnaud Minier retvalue = s->apb1smenr1; 493d6b55a0fSArnaud Minier break; 494d6b55a0fSArnaud Minier case A_APB1SMENR2: 495d6b55a0fSArnaud Minier retvalue = s->apb1smenr2; 496d6b55a0fSArnaud Minier break; 497d6b55a0fSArnaud Minier case A_APB2SMENR: 498d6b55a0fSArnaud Minier retvalue = s->apb2smenr; 499d6b55a0fSArnaud Minier break; 500d6b55a0fSArnaud Minier case A_CCIPR: 501d6b55a0fSArnaud Minier retvalue = s->ccipr; 502d6b55a0fSArnaud Minier break; 503d6b55a0fSArnaud Minier case A_BDCR: 504d6b55a0fSArnaud Minier retvalue = s->bdcr; 505d6b55a0fSArnaud Minier break; 506d6b55a0fSArnaud Minier case A_CSR: 507d6b55a0fSArnaud Minier retvalue = s->csr; 508d6b55a0fSArnaud Minier break; 509d6b55a0fSArnaud Minier default: 510d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 511d6b55a0fSArnaud Minier "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 512d6b55a0fSArnaud Minier break; 513d6b55a0fSArnaud Minier } 514d6b55a0fSArnaud Minier 515d6b55a0fSArnaud Minier trace_stm32l4x5_rcc_read(addr, retvalue); 516d6b55a0fSArnaud Minier 517d6b55a0fSArnaud Minier return retvalue; 518d6b55a0fSArnaud Minier } 519d6b55a0fSArnaud Minier 520d6b55a0fSArnaud Minier static void stm32l4x5_rcc_write(void *opaque, hwaddr addr, 521d6b55a0fSArnaud Minier uint64_t val64, unsigned int size) 522d6b55a0fSArnaud Minier { 523d6b55a0fSArnaud Minier Stm32l4x5RccState *s = opaque; 524d6b55a0fSArnaud Minier const uint32_t value = val64; 525d6b55a0fSArnaud Minier 526d6b55a0fSArnaud Minier trace_stm32l4x5_rcc_write(addr, value); 527d6b55a0fSArnaud Minier 528d6b55a0fSArnaud Minier switch (addr) { 529d6b55a0fSArnaud Minier case A_CR: 530d6b55a0fSArnaud Minier s->cr = (s->cr & CR_READ_SET_MASK) | 531d6b55a0fSArnaud Minier (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK)); 532d6b55a0fSArnaud Minier break; 533d6b55a0fSArnaud Minier case A_ICSCR: 534d6b55a0fSArnaud Minier s->icscr = value & ~ICSCR_READ_ONLY_MASK; 535d6b55a0fSArnaud Minier break; 536d6b55a0fSArnaud Minier case A_CFGR: 537d6b55a0fSArnaud Minier s->cfgr = value & ~CFGR_READ_ONLY_MASK; 538d6b55a0fSArnaud Minier break; 539d6b55a0fSArnaud Minier case A_PLLCFGR: 540d6b55a0fSArnaud Minier s->pllcfgr = value; 541d6b55a0fSArnaud Minier break; 542d6b55a0fSArnaud Minier case A_PLLSAI1CFGR: 543d6b55a0fSArnaud Minier s->pllsai1cfgr = value; 544d6b55a0fSArnaud Minier break; 545d6b55a0fSArnaud Minier case A_PLLSAI2CFGR: 546d6b55a0fSArnaud Minier s->pllsai2cfgr = value; 547d6b55a0fSArnaud Minier break; 548d6b55a0fSArnaud Minier case A_CIER: 549d6b55a0fSArnaud Minier s->cier = value; 550d6b55a0fSArnaud Minier break; 551d6b55a0fSArnaud Minier case A_CIFR: 552d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 553d6b55a0fSArnaud Minier "%s: Write attempt into read-only register (CIFR) 0x%"PRIx32"\n", 554d6b55a0fSArnaud Minier __func__, value); 555d6b55a0fSArnaud Minier break; 556d6b55a0fSArnaud Minier case A_CICR: 557d6b55a0fSArnaud Minier /* Clear interrupt flags by writing a 1 to the CICR register */ 558d6b55a0fSArnaud Minier s->cifr &= ~value; 559d6b55a0fSArnaud Minier rcc_update_irq(s); 560d6b55a0fSArnaud Minier break; 561d6b55a0fSArnaud Minier /* Reset behaviors are not implemented */ 562d6b55a0fSArnaud Minier case A_AHB1RSTR: 563d6b55a0fSArnaud Minier s->ahb1rstr = value; 564d6b55a0fSArnaud Minier break; 565d6b55a0fSArnaud Minier case A_AHB2RSTR: 566d6b55a0fSArnaud Minier s->ahb2rstr = value; 567d6b55a0fSArnaud Minier break; 568d6b55a0fSArnaud Minier case A_AHB3RSTR: 569d6b55a0fSArnaud Minier s->ahb3rstr = value; 570d6b55a0fSArnaud Minier break; 571d6b55a0fSArnaud Minier case A_APB1RSTR1: 572d6b55a0fSArnaud Minier s->apb1rstr1 = value; 573d6b55a0fSArnaud Minier break; 574d6b55a0fSArnaud Minier case A_APB1RSTR2: 575d6b55a0fSArnaud Minier s->apb1rstr2 = value; 576d6b55a0fSArnaud Minier break; 577d6b55a0fSArnaud Minier case A_APB2RSTR: 578d6b55a0fSArnaud Minier s->apb2rstr = value; 579d6b55a0fSArnaud Minier break; 580d6b55a0fSArnaud Minier case A_AHB1ENR: 581d6b55a0fSArnaud Minier s->ahb1enr = value; 582d6b55a0fSArnaud Minier break; 583d6b55a0fSArnaud Minier case A_AHB2ENR: 584d6b55a0fSArnaud Minier s->ahb2enr = value; 585d6b55a0fSArnaud Minier break; 586d6b55a0fSArnaud Minier case A_AHB3ENR: 587d6b55a0fSArnaud Minier s->ahb3enr = value; 588d6b55a0fSArnaud Minier break; 589d6b55a0fSArnaud Minier case A_APB1ENR1: 590d6b55a0fSArnaud Minier s->apb1enr1 = value; 591d6b55a0fSArnaud Minier break; 592d6b55a0fSArnaud Minier case A_APB1ENR2: 593d6b55a0fSArnaud Minier s->apb1enr2 = value; 594d6b55a0fSArnaud Minier break; 595d6b55a0fSArnaud Minier case A_APB2ENR: 596d6b55a0fSArnaud Minier s->apb2enr = (s->apb2enr & APB2ENR_READ_SET_MASK) | value; 597d6b55a0fSArnaud Minier break; 598d6b55a0fSArnaud Minier /* Behaviors for Sleep and Stop modes are not implemented */ 599d6b55a0fSArnaud Minier case A_AHB1SMENR: 600d6b55a0fSArnaud Minier s->ahb1smenr = value; 601d6b55a0fSArnaud Minier break; 602d6b55a0fSArnaud Minier case A_AHB2SMENR: 603d6b55a0fSArnaud Minier s->ahb2smenr = value; 604d6b55a0fSArnaud Minier break; 605d6b55a0fSArnaud Minier case A_AHB3SMENR: 606d6b55a0fSArnaud Minier s->ahb3smenr = value; 607d6b55a0fSArnaud Minier break; 608d6b55a0fSArnaud Minier case A_APB1SMENR1: 609d6b55a0fSArnaud Minier s->apb1smenr1 = value; 610d6b55a0fSArnaud Minier break; 611d6b55a0fSArnaud Minier case A_APB1SMENR2: 612d6b55a0fSArnaud Minier s->apb1smenr2 = value; 613d6b55a0fSArnaud Minier break; 614d6b55a0fSArnaud Minier case A_APB2SMENR: 615d6b55a0fSArnaud Minier s->apb2smenr = value; 616d6b55a0fSArnaud Minier break; 617d6b55a0fSArnaud Minier case A_CCIPR: 618d6b55a0fSArnaud Minier s->ccipr = value; 619d6b55a0fSArnaud Minier break; 620d6b55a0fSArnaud Minier case A_BDCR: 621d6b55a0fSArnaud Minier s->bdcr = value & ~BDCR_READ_ONLY_MASK; 622d6b55a0fSArnaud Minier break; 623d6b55a0fSArnaud Minier case A_CSR: 624d6b55a0fSArnaud Minier s->csr = value & ~CSR_READ_ONLY_MASK; 625d6b55a0fSArnaud Minier break; 626d6b55a0fSArnaud Minier default: 627d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 628d6b55a0fSArnaud Minier "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 629d6b55a0fSArnaud Minier } 630d6b55a0fSArnaud Minier } 631d6b55a0fSArnaud Minier 632d6b55a0fSArnaud Minier static const MemoryRegionOps stm32l4x5_rcc_ops = { 633d6b55a0fSArnaud Minier .read = stm32l4x5_rcc_read, 634d6b55a0fSArnaud Minier .write = stm32l4x5_rcc_write, 635d6b55a0fSArnaud Minier .endianness = DEVICE_NATIVE_ENDIAN, 636d6b55a0fSArnaud Minier .valid = { 637d6b55a0fSArnaud Minier .max_access_size = 4, 638d6b55a0fSArnaud Minier .min_access_size = 4, 639d6b55a0fSArnaud Minier .unaligned = false 640d6b55a0fSArnaud Minier }, 641d6b55a0fSArnaud Minier .impl = { 642d6b55a0fSArnaud Minier .max_access_size = 4, 643d6b55a0fSArnaud Minier .min_access_size = 4, 644d6b55a0fSArnaud Minier .unaligned = false 645d6b55a0fSArnaud Minier }, 646d6b55a0fSArnaud Minier }; 647d6b55a0fSArnaud Minier 648d6b55a0fSArnaud Minier static const ClockPortInitArray stm32l4x5_rcc_clocks = { 649d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, hsi16_rc, NULL, 0), 650d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, msi_rc, NULL, 0), 651d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, hse, NULL, 0), 652d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, lsi_rc, NULL, 0), 653d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, lse_crystal, NULL, 0), 654d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, sai1_extclk, NULL, 0), 655d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0), 656d6b55a0fSArnaud Minier QDEV_CLOCK_END 657d6b55a0fSArnaud Minier }; 658d6b55a0fSArnaud Minier 659d6b55a0fSArnaud Minier 660d6b55a0fSArnaud Minier static void stm32l4x5_rcc_init(Object *obj) 661d6b55a0fSArnaud Minier { 662d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(obj); 663ec7d83acSArnaud Minier size_t i; 664d6b55a0fSArnaud Minier 665d6b55a0fSArnaud Minier sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 666d6b55a0fSArnaud Minier 667d6b55a0fSArnaud Minier memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s, 668d6b55a0fSArnaud Minier TYPE_STM32L4X5_RCC, 0x400); 669d6b55a0fSArnaud Minier sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 670d6b55a0fSArnaud Minier 671d6b55a0fSArnaud Minier qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); 672d6b55a0fSArnaud Minier 6736487653eSArnaud Minier for (i = 0; i < RCC_NUM_PLL; i++) { 674*141c29a2SArnaud Minier object_initialize_child(obj, PLL_INIT_INFO[i].name, 6756487653eSArnaud Minier &s->plls[i], TYPE_RCC_PLL); 676*141c29a2SArnaud Minier set_pll_init_info(&s->plls[i], i); 6776487653eSArnaud Minier } 6786487653eSArnaud Minier 679ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) { 680*141c29a2SArnaud Minier char *alias; 681ec7d83acSArnaud Minier 682*141c29a2SArnaud Minier object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name, 683ec7d83acSArnaud Minier &s->clock_muxes[i], 684ec7d83acSArnaud Minier TYPE_RCC_CLOCK_MUX); 685*141c29a2SArnaud Minier set_clock_mux_init_info(&s->clock_muxes[i], i); 686ec7d83acSArnaud Minier 687*141c29a2SArnaud Minier if (!CLOCK_MUX_INIT_INFO[i].hidden) { 688*141c29a2SArnaud Minier /* Expose muxes output as RCC outputs */ 689*141c29a2SArnaud Minier alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name); 690*141c29a2SArnaud Minier qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias); 691*141c29a2SArnaud Minier g_free(alias); 692*141c29a2SArnaud Minier } 693ec7d83acSArnaud Minier } 694ec7d83acSArnaud Minier 695d6b55a0fSArnaud Minier s->gnd = clock_new(obj, "gnd"); 696d6b55a0fSArnaud Minier } 697d6b55a0fSArnaud Minier 698*141c29a2SArnaud Minier static void connect_mux_sources(Stm32l4x5RccState *s, 699*141c29a2SArnaud Minier RccClockMuxState *mux, 700*141c29a2SArnaud Minier const RccClockMuxSource *clk_mapping) 701*141c29a2SArnaud Minier { 702*141c29a2SArnaud Minier size_t i; 703*141c29a2SArnaud Minier 704*141c29a2SArnaud Minier Clock * const CLK_SRC_MAPPING[] = { 705*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_GND] = s->gnd, 706*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSI] = s->hsi16_rc, 707*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSE] = s->hse, 708*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_MSI] = s->msi_rc, 709*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LSI] = s->lsi_rc, 710*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LSE] = s->lse_crystal, 711*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SAI1_EXTCLK] = s->sai1_extclk, 712*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SAI2_EXTCLK] = s->sai2_extclk, 713*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL] = 714*141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLCLK], 715*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI1] = 716*141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLSAI1CLK], 717*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI2] = 718*141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI2].channels[RCC_PLLSAI2_CHANNEL_PLLSAI2CLK], 719*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI3] = 720*141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLSAI3CLK], 721*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL48M1] = 722*141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLL48M1CLK], 723*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL48M2] = 724*141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLL48M2CLK], 725*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLADC1] = 726*141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLADC1CLK], 727*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLADC2] = 728*141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI2] .channels[RCC_PLLSAI2_CHANNEL_PLLADC2CLK], 729*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SYSCLK] = s->clock_muxes[RCC_CLOCK_MUX_SYSCLK].out, 730*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HCLK] = s->clock_muxes[RCC_CLOCK_MUX_HCLK].out, 731*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PCLK1] = s->clock_muxes[RCC_CLOCK_MUX_PCLK1].out, 732*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PCLK2] = s->clock_muxes[RCC_CLOCK_MUX_PCLK2].out, 733*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSE_OVER_32] = s->clock_muxes[RCC_CLOCK_MUX_HSE_OVER_32].out, 734*141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LCD_AND_RTC_COMMON] = 735*141c29a2SArnaud Minier s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON].out, 736*141c29a2SArnaud Minier }; 737*141c29a2SArnaud Minier 738*141c29a2SArnaud Minier assert(ARRAY_SIZE(CLK_SRC_MAPPING) == RCC_CLOCK_MUX_SRC_NUMBER); 739*141c29a2SArnaud Minier 740*141c29a2SArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { 741*141c29a2SArnaud Minier RccClockMuxSource mapping = clk_mapping[i]; 742*141c29a2SArnaud Minier clock_set_source(mux->srcs[i], CLK_SRC_MAPPING[mapping]); 743*141c29a2SArnaud Minier } 744*141c29a2SArnaud Minier } 745*141c29a2SArnaud Minier 746*141c29a2SArnaud Minier 747d6b55a0fSArnaud Minier static const VMStateDescription vmstate_stm32l4x5_rcc = { 748d6b55a0fSArnaud Minier .name = TYPE_STM32L4X5_RCC, 749d6b55a0fSArnaud Minier .version_id = 1, 750d6b55a0fSArnaud Minier .minimum_version_id = 1, 751d6b55a0fSArnaud Minier .fields = (VMStateField[]) { 752d6b55a0fSArnaud Minier VMSTATE_UINT32(cr, Stm32l4x5RccState), 753d6b55a0fSArnaud Minier VMSTATE_UINT32(icscr, Stm32l4x5RccState), 754d6b55a0fSArnaud Minier VMSTATE_UINT32(cfgr, Stm32l4x5RccState), 755d6b55a0fSArnaud Minier VMSTATE_UINT32(pllcfgr, Stm32l4x5RccState), 756d6b55a0fSArnaud Minier VMSTATE_UINT32(pllsai1cfgr, Stm32l4x5RccState), 757d6b55a0fSArnaud Minier VMSTATE_UINT32(pllsai2cfgr, Stm32l4x5RccState), 758d6b55a0fSArnaud Minier VMSTATE_UINT32(cier, Stm32l4x5RccState), 759d6b55a0fSArnaud Minier VMSTATE_UINT32(cifr, Stm32l4x5RccState), 760d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1rstr, Stm32l4x5RccState), 761d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2rstr, Stm32l4x5RccState), 762d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3rstr, Stm32l4x5RccState), 763d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1rstr1, Stm32l4x5RccState), 764d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1rstr2, Stm32l4x5RccState), 765d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2rstr, Stm32l4x5RccState), 766d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1enr, Stm32l4x5RccState), 767d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2enr, Stm32l4x5RccState), 768d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3enr, Stm32l4x5RccState), 769d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1enr1, Stm32l4x5RccState), 770d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1enr2, Stm32l4x5RccState), 771d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2enr, Stm32l4x5RccState), 772d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1smenr, Stm32l4x5RccState), 773d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2smenr, Stm32l4x5RccState), 774d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3smenr, Stm32l4x5RccState), 775d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1smenr1, Stm32l4x5RccState), 776d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1smenr2, Stm32l4x5RccState), 777d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2smenr, Stm32l4x5RccState), 778d6b55a0fSArnaud Minier VMSTATE_UINT32(ccipr, Stm32l4x5RccState), 779d6b55a0fSArnaud Minier VMSTATE_UINT32(bdcr, Stm32l4x5RccState), 780d6b55a0fSArnaud Minier VMSTATE_UINT32(csr, Stm32l4x5RccState), 781d6b55a0fSArnaud Minier VMSTATE_CLOCK(hsi16_rc, Stm32l4x5RccState), 782d6b55a0fSArnaud Minier VMSTATE_CLOCK(msi_rc, Stm32l4x5RccState), 783d6b55a0fSArnaud Minier VMSTATE_CLOCK(hse, Stm32l4x5RccState), 784d6b55a0fSArnaud Minier VMSTATE_CLOCK(lsi_rc, Stm32l4x5RccState), 785d6b55a0fSArnaud Minier VMSTATE_CLOCK(lse_crystal, Stm32l4x5RccState), 786d6b55a0fSArnaud Minier VMSTATE_CLOCK(sai1_extclk, Stm32l4x5RccState), 787d6b55a0fSArnaud Minier VMSTATE_CLOCK(sai2_extclk, Stm32l4x5RccState), 788d6b55a0fSArnaud Minier VMSTATE_END_OF_LIST() 789d6b55a0fSArnaud Minier } 790d6b55a0fSArnaud Minier }; 791d6b55a0fSArnaud Minier 792d6b55a0fSArnaud Minier 793d6b55a0fSArnaud Minier static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp) 794d6b55a0fSArnaud Minier { 795d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(dev); 796ec7d83acSArnaud Minier size_t i; 797d6b55a0fSArnaud Minier 798d6b55a0fSArnaud Minier if (s->hse_frequency < 4000000ULL || 799d6b55a0fSArnaud Minier s->hse_frequency > 48000000ULL) { 800d6b55a0fSArnaud Minier error_setg(errp, 801d6b55a0fSArnaud Minier "HSE frequency is outside of the allowed [4-48]Mhz range: %" PRIx64 "", 802d6b55a0fSArnaud Minier s->hse_frequency); 803d6b55a0fSArnaud Minier return; 804d6b55a0fSArnaud Minier } 805d6b55a0fSArnaud Minier 8066487653eSArnaud Minier for (i = 0; i < RCC_NUM_PLL; i++) { 8076487653eSArnaud Minier RccPllState *pll = &s->plls[i]; 8086487653eSArnaud Minier 8096487653eSArnaud Minier clock_set_source(pll->in, s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].out); 8106487653eSArnaud Minier 8116487653eSArnaud Minier if (!qdev_realize(DEVICE(pll), NULL, errp)) { 8126487653eSArnaud Minier return; 8136487653eSArnaud Minier } 8146487653eSArnaud Minier } 8156487653eSArnaud Minier 816ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) { 817ec7d83acSArnaud Minier RccClockMuxState *clock_mux = &s->clock_muxes[i]; 818ec7d83acSArnaud Minier 819*141c29a2SArnaud Minier connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping); 820*141c29a2SArnaud Minier 821ec7d83acSArnaud Minier if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) { 822ec7d83acSArnaud Minier return; 823ec7d83acSArnaud Minier } 824ec7d83acSArnaud Minier } 825ec7d83acSArnaud Minier 826*141c29a2SArnaud Minier /* 827*141c29a2SArnaud Minier * Start clocks after everything is connected 828*141c29a2SArnaud Minier * to propagate the frequencies along the tree. 829*141c29a2SArnaud Minier */ 830d6b55a0fSArnaud Minier clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); 831d6b55a0fSArnaud Minier clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); 832d6b55a0fSArnaud Minier clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); 833d6b55a0fSArnaud Minier clock_update(s->gnd, 0); 834ec7d83acSArnaud Minier 835ec7d83acSArnaud Minier /* 836ec7d83acSArnaud Minier * Dummy values to make compilation pass. 837ec7d83acSArnaud Minier * Removed in later commits. 838ec7d83acSArnaud Minier */ 839ec7d83acSArnaud Minier clock_mux_set_source(&s->clock_muxes[0], RCC_CLOCK_MUX_SRC_GND); 840ec7d83acSArnaud Minier clock_mux_set_enable(&s->clock_muxes[0], true); 841ec7d83acSArnaud Minier clock_mux_set_factor(&s->clock_muxes[0], 1, 1); 8426487653eSArnaud Minier pll_set_channel_divider(&s->plls[0], 0, 1); 8436487653eSArnaud Minier pll_set_enable(&s->plls[0], true); 8446487653eSArnaud Minier pll_set_channel_enable(&s->plls[0], 0, true); 8456487653eSArnaud Minier pll_set_vco_multiplier(&s->plls[0], 1); 846d6b55a0fSArnaud Minier } 847d6b55a0fSArnaud Minier 848d6b55a0fSArnaud Minier static Property stm32l4x5_rcc_properties[] = { 849d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState, 850d6b55a0fSArnaud Minier hse_frequency, HSE_DEFAULT_FRQ), 851d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState, 852d6b55a0fSArnaud Minier sai1_extclk_frequency, 0), 853d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState, 854d6b55a0fSArnaud Minier sai2_extclk_frequency, 0), 855d6b55a0fSArnaud Minier DEFINE_PROP_END_OF_LIST(), 856d6b55a0fSArnaud Minier }; 857d6b55a0fSArnaud Minier 858d6b55a0fSArnaud Minier static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data) 859d6b55a0fSArnaud Minier { 860d6b55a0fSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 861d6b55a0fSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 862d6b55a0fSArnaud Minier 863*141c29a2SArnaud Minier assert(ARRAY_SIZE(CLOCK_MUX_INIT_INFO) == RCC_NUM_CLOCK_MUX); 864d6b55a0fSArnaud Minier 865d6b55a0fSArnaud Minier rc->phases.hold = stm32l4x5_rcc_reset_hold; 866d6b55a0fSArnaud Minier device_class_set_props(dc, stm32l4x5_rcc_properties); 867d6b55a0fSArnaud Minier dc->realize = stm32l4x5_rcc_realize; 868d6b55a0fSArnaud Minier dc->vmsd = &vmstate_stm32l4x5_rcc; 869d6b55a0fSArnaud Minier } 870d6b55a0fSArnaud Minier 871d6b55a0fSArnaud Minier static const TypeInfo stm32l4x5_rcc_types[] = { 872d6b55a0fSArnaud Minier { 873d6b55a0fSArnaud Minier .name = TYPE_STM32L4X5_RCC, 874d6b55a0fSArnaud Minier .parent = TYPE_SYS_BUS_DEVICE, 875d6b55a0fSArnaud Minier .instance_size = sizeof(Stm32l4x5RccState), 876d6b55a0fSArnaud Minier .instance_init = stm32l4x5_rcc_init, 877d6b55a0fSArnaud Minier .class_init = stm32l4x5_rcc_class_init, 878ec7d83acSArnaud Minier }, { 879ec7d83acSArnaud Minier .name = TYPE_RCC_CLOCK_MUX, 880ec7d83acSArnaud Minier .parent = TYPE_DEVICE, 881ec7d83acSArnaud Minier .instance_size = sizeof(RccClockMuxState), 882ec7d83acSArnaud Minier .instance_init = clock_mux_init, 883ec7d83acSArnaud Minier .class_init = clock_mux_class_init, 8846487653eSArnaud Minier }, { 8856487653eSArnaud Minier .name = TYPE_RCC_PLL, 8866487653eSArnaud Minier .parent = TYPE_DEVICE, 8876487653eSArnaud Minier .instance_size = sizeof(RccPllState), 8886487653eSArnaud Minier .instance_init = pll_init, 8896487653eSArnaud Minier .class_init = pll_class_init, 890d6b55a0fSArnaud Minier } 891d6b55a0fSArnaud Minier }; 892d6b55a0fSArnaud Minier 893d6b55a0fSArnaud Minier DEFINE_TYPES(stm32l4x5_rcc_types) 894