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" 319c796d50SArnaud Minier #include "hw/registerfields.h" 32d6b55a0fSArnaud Minier #include "trace.h" 33d6b55a0fSArnaud Minier 34d6b55a0fSArnaud Minier #define HSE_DEFAULT_FRQ 48000000ULL 35d6b55a0fSArnaud Minier #define HSI_FRQ 16000000ULL 36d6b55a0fSArnaud Minier #define MSI_DEFAULT_FRQ 4000000ULL 37d6b55a0fSArnaud Minier #define LSE_FRQ 32768ULL 38d6b55a0fSArnaud Minier #define LSI_FRQ 32000ULL 39d6b55a0fSArnaud Minier 40141c29a2SArnaud Minier /* 41141c29a2SArnaud Minier * Function to simply acknowledge and propagate changes in a clock mux 42141c29a2SArnaud Minier * frequency. 43141c29a2SArnaud Minier * `bypass_source` allows to bypass the period of the current source and just 44141c29a2SArnaud Minier * consider it equal to 0. This is useful during the hold phase of reset. 45141c29a2SArnaud Minier */ 46141c29a2SArnaud Minier static void clock_mux_update(RccClockMuxState *mux, bool bypass_source) 47ec7d83acSArnaud Minier { 48ec7d83acSArnaud Minier uint64_t src_freq; 49ec7d83acSArnaud Minier Clock *current_source = mux->srcs[mux->src]; 50ec7d83acSArnaud Minier uint32_t freq_multiplier = 0; 51ec7d83acSArnaud Minier /* 52ec7d83acSArnaud Minier * To avoid rounding errors, we use the clock period instead of the 53ec7d83acSArnaud Minier * frequency. 54ec7d83acSArnaud Minier * This means that the multiplier of the mux becomes the divider of 55ec7d83acSArnaud Minier * the clock and the divider of the mux becomes the multiplier of the 56ec7d83acSArnaud Minier * clock. 57ec7d83acSArnaud Minier */ 58141c29a2SArnaud Minier if (!bypass_source && mux->enabled && mux->divider) { 59ec7d83acSArnaud Minier freq_multiplier = mux->divider; 60ec7d83acSArnaud Minier } 61ec7d83acSArnaud Minier 62ec7d83acSArnaud Minier clock_set_mul_div(mux->out, freq_multiplier, mux->multiplier); 63ec7d83acSArnaud Minier clock_update(mux->out, clock_get(current_source)); 64ec7d83acSArnaud Minier 65ec7d83acSArnaud Minier src_freq = clock_get_hz(current_source); 66ec7d83acSArnaud Minier /* TODO: can we simply detect if the config changed so that we reduce log spam ? */ 67ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_update(mux->id, mux->src, src_freq, 68ec7d83acSArnaud Minier mux->multiplier, mux->divider); 69ec7d83acSArnaud Minier } 70ec7d83acSArnaud Minier 71ec7d83acSArnaud Minier static void clock_mux_src_update(void *opaque, ClockEvent event) 72ec7d83acSArnaud Minier { 73ec7d83acSArnaud Minier RccClockMuxState **backref = opaque; 74ec7d83acSArnaud Minier RccClockMuxState *s = *backref; 75ec7d83acSArnaud Minier /* 76ec7d83acSArnaud Minier * The backref value is equal to: 77ec7d83acSArnaud Minier * s->backref + (sizeof(RccClockMuxState *) * update_src). 78ec7d83acSArnaud Minier * By subtracting we can get back the index of the updated clock. 79ec7d83acSArnaud Minier */ 80ec7d83acSArnaud Minier const uint32_t update_src = backref - s->backref; 81ec7d83acSArnaud Minier /* Only update if the clock that was updated is the current source */ 82ec7d83acSArnaud Minier if (update_src == s->src) { 83141c29a2SArnaud Minier clock_mux_update(s, false); 84ec7d83acSArnaud Minier } 85ec7d83acSArnaud Minier } 86ec7d83acSArnaud Minier 87ec7d83acSArnaud Minier static void clock_mux_init(Object *obj) 88ec7d83acSArnaud Minier { 89ec7d83acSArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 90ec7d83acSArnaud Minier size_t i; 91ec7d83acSArnaud Minier 92ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { 93ec7d83acSArnaud Minier char *name = g_strdup_printf("srcs[%zu]", i); 94ec7d83acSArnaud Minier s->backref[i] = s; 95ec7d83acSArnaud Minier s->srcs[i] = qdev_init_clock_in(DEVICE(s), name, 96ec7d83acSArnaud Minier clock_mux_src_update, 97ec7d83acSArnaud Minier &s->backref[i], 98ec7d83acSArnaud Minier ClockUpdate); 99ec7d83acSArnaud Minier g_free(name); 100ec7d83acSArnaud Minier } 101ec7d83acSArnaud Minier 102ec7d83acSArnaud Minier s->out = qdev_init_clock_out(DEVICE(s), "out"); 103ec7d83acSArnaud Minier } 104ec7d83acSArnaud Minier 105141c29a2SArnaud Minier static void clock_mux_reset_enter(Object *obj, ResetType type) 106141c29a2SArnaud Minier { 107141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 108141c29a2SArnaud Minier set_clock_mux_init_info(s, s->id); 109141c29a2SArnaud Minier } 110141c29a2SArnaud Minier 111ec7d83acSArnaud Minier static void clock_mux_reset_hold(Object *obj) 112141c29a2SArnaud Minier { 113141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 114141c29a2SArnaud Minier clock_mux_update(s, true); 115141c29a2SArnaud Minier } 116141c29a2SArnaud Minier 117141c29a2SArnaud Minier static void clock_mux_reset_exit(Object *obj) 118141c29a2SArnaud Minier { 119141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 120141c29a2SArnaud Minier clock_mux_update(s, false); 121141c29a2SArnaud Minier } 122ec7d83acSArnaud Minier 123ec7d83acSArnaud Minier static const VMStateDescription clock_mux_vmstate = { 124ec7d83acSArnaud Minier .name = TYPE_RCC_CLOCK_MUX, 125ec7d83acSArnaud Minier .version_id = 1, 126ec7d83acSArnaud Minier .minimum_version_id = 1, 127ec7d83acSArnaud Minier .fields = (VMStateField[]) { 128ec7d83acSArnaud Minier VMSTATE_UINT32(id, RccClockMuxState), 129ec7d83acSArnaud Minier VMSTATE_ARRAY_CLOCK(srcs, RccClockMuxState, 130ec7d83acSArnaud Minier RCC_NUM_CLOCK_MUX_SRC), 131ec7d83acSArnaud Minier VMSTATE_BOOL(enabled, RccClockMuxState), 132ec7d83acSArnaud Minier VMSTATE_UINT32(src, RccClockMuxState), 133ec7d83acSArnaud Minier VMSTATE_UINT32(multiplier, RccClockMuxState), 134ec7d83acSArnaud Minier VMSTATE_UINT32(divider, RccClockMuxState), 135ec7d83acSArnaud Minier VMSTATE_END_OF_LIST() 136ec7d83acSArnaud Minier } 137ec7d83acSArnaud Minier }; 138ec7d83acSArnaud Minier 139ec7d83acSArnaud Minier static void clock_mux_class_init(ObjectClass *klass, void *data) 140ec7d83acSArnaud Minier { 141ec7d83acSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 142ec7d83acSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 143ec7d83acSArnaud Minier 144141c29a2SArnaud Minier rc->phases.enter = clock_mux_reset_enter; 145ec7d83acSArnaud Minier rc->phases.hold = clock_mux_reset_hold; 146141c29a2SArnaud Minier rc->phases.exit = clock_mux_reset_exit; 147ec7d83acSArnaud Minier dc->vmsd = &clock_mux_vmstate; 148ec7d83acSArnaud Minier } 149ec7d83acSArnaud Minier 150ec7d83acSArnaud Minier static void clock_mux_set_enable(RccClockMuxState *mux, bool enabled) 151ec7d83acSArnaud Minier { 152ec7d83acSArnaud Minier if (mux->enabled == enabled) { 153ec7d83acSArnaud Minier return; 154ec7d83acSArnaud Minier } 155ec7d83acSArnaud Minier 156ec7d83acSArnaud Minier if (enabled) { 157ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_enable(mux->id); 158ec7d83acSArnaud Minier } else { 159ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_disable(mux->id); 160ec7d83acSArnaud Minier } 161ec7d83acSArnaud Minier 162ec7d83acSArnaud Minier mux->enabled = enabled; 163141c29a2SArnaud Minier clock_mux_update(mux, false); 164ec7d83acSArnaud Minier } 165ec7d83acSArnaud Minier 166ec7d83acSArnaud Minier static void clock_mux_set_factor(RccClockMuxState *mux, 167ec7d83acSArnaud Minier uint32_t multiplier, uint32_t divider) 168ec7d83acSArnaud Minier { 169ec7d83acSArnaud Minier if (mux->multiplier == multiplier && mux->divider == divider) { 170ec7d83acSArnaud Minier return; 171ec7d83acSArnaud Minier } 172ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_set_factor(mux->id, 173ec7d83acSArnaud Minier mux->multiplier, multiplier, mux->divider, divider); 174ec7d83acSArnaud Minier 175ec7d83acSArnaud Minier mux->multiplier = multiplier; 176ec7d83acSArnaud Minier mux->divider = divider; 177141c29a2SArnaud Minier clock_mux_update(mux, false); 178ec7d83acSArnaud Minier } 179ec7d83acSArnaud Minier 180ec7d83acSArnaud Minier static void clock_mux_set_source(RccClockMuxState *mux, RccClockMuxSource src) 181ec7d83acSArnaud Minier { 182ec7d83acSArnaud Minier if (mux->src == src) { 183ec7d83acSArnaud Minier return; 184ec7d83acSArnaud Minier } 185ec7d83acSArnaud Minier 186ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_set_src(mux->id, mux->src, src); 187ec7d83acSArnaud Minier mux->src = src; 188141c29a2SArnaud Minier clock_mux_update(mux, false); 189ec7d83acSArnaud Minier } 190ec7d83acSArnaud Minier 191141c29a2SArnaud Minier /* 192141c29a2SArnaud Minier * Acknowledge and propagate changes in a PLL frequency. 193141c29a2SArnaud Minier * `bypass_source` allows to bypass the period of the current source and just 194141c29a2SArnaud Minier * consider it equal to 0. This is useful during the hold phase of reset. 195141c29a2SArnaud Minier */ 196141c29a2SArnaud Minier static void pll_update(RccPllState *pll, bool bypass_source) 1976487653eSArnaud Minier { 1986487653eSArnaud Minier uint64_t vco_freq, old_channel_freq, channel_freq; 1996487653eSArnaud Minier int i; 2006487653eSArnaud Minier 2016487653eSArnaud Minier /* The common PLLM factor is handled by the PLL mux */ 2026487653eSArnaud Minier vco_freq = muldiv64(clock_get_hz(pll->in), pll->vco_multiplier, 1); 2036487653eSArnaud Minier 2046487653eSArnaud Minier for (i = 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { 2056487653eSArnaud Minier if (!pll->channel_exists[i]) { 2066487653eSArnaud Minier continue; 2076487653eSArnaud Minier } 2086487653eSArnaud Minier 2096487653eSArnaud Minier old_channel_freq = clock_get_hz(pll->channels[i]); 210141c29a2SArnaud Minier if (bypass_source || 211141c29a2SArnaud Minier !pll->enabled || 2126487653eSArnaud Minier !pll->channel_enabled[i] || 2136487653eSArnaud Minier !pll->channel_divider[i]) { 2146487653eSArnaud Minier channel_freq = 0; 2156487653eSArnaud Minier } else { 2166487653eSArnaud Minier channel_freq = muldiv64(vco_freq, 2176487653eSArnaud Minier 1, 2186487653eSArnaud Minier pll->channel_divider[i]); 2196487653eSArnaud Minier } 2206487653eSArnaud Minier 2216487653eSArnaud Minier /* No change, early continue to avoid log spam and useless propagation */ 2226487653eSArnaud Minier if (old_channel_freq == channel_freq) { 2236487653eSArnaud Minier continue; 2246487653eSArnaud Minier } 2256487653eSArnaud Minier 2266487653eSArnaud Minier clock_update_hz(pll->channels[i], channel_freq); 2276487653eSArnaud Minier trace_stm32l4x5_rcc_pll_update(pll->id, i, vco_freq, 2286487653eSArnaud Minier old_channel_freq, channel_freq); 2296487653eSArnaud Minier } 2306487653eSArnaud Minier } 2316487653eSArnaud Minier 2326487653eSArnaud Minier static void pll_src_update(void *opaque, ClockEvent event) 2336487653eSArnaud Minier { 2346487653eSArnaud Minier RccPllState *s = opaque; 235141c29a2SArnaud Minier pll_update(s, false); 2366487653eSArnaud Minier } 2376487653eSArnaud Minier 2386487653eSArnaud Minier static void pll_init(Object *obj) 2396487653eSArnaud Minier { 2406487653eSArnaud Minier RccPllState *s = RCC_PLL(obj); 2416487653eSArnaud Minier size_t i; 2426487653eSArnaud Minier 2436487653eSArnaud Minier s->in = qdev_init_clock_in(DEVICE(s), "in", 2446487653eSArnaud Minier pll_src_update, s, ClockUpdate); 2456487653eSArnaud Minier 2466487653eSArnaud Minier const char *names[] = { 2476487653eSArnaud Minier "out-p", "out-q", "out-r", 2486487653eSArnaud Minier }; 2496487653eSArnaud Minier 2506487653eSArnaud Minier for (i = 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { 2516487653eSArnaud Minier s->channels[i] = qdev_init_clock_out(DEVICE(s), names[i]); 2526487653eSArnaud Minier } 2536487653eSArnaud Minier } 2546487653eSArnaud Minier 255141c29a2SArnaud Minier static void pll_reset_enter(Object *obj, ResetType type) 256141c29a2SArnaud Minier { 257141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 258141c29a2SArnaud Minier set_pll_init_info(s, s->id); 259141c29a2SArnaud Minier } 260141c29a2SArnaud Minier 2616487653eSArnaud Minier static void pll_reset_hold(Object *obj) 262141c29a2SArnaud Minier { 263141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 264141c29a2SArnaud Minier pll_update(s, true); 265141c29a2SArnaud Minier } 266141c29a2SArnaud Minier 267141c29a2SArnaud Minier static void pll_reset_exit(Object *obj) 268141c29a2SArnaud Minier { 269141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 270141c29a2SArnaud Minier pll_update(s, false); 271141c29a2SArnaud Minier } 2726487653eSArnaud Minier 2736487653eSArnaud Minier static const VMStateDescription pll_vmstate = { 2746487653eSArnaud Minier .name = TYPE_RCC_PLL, 2756487653eSArnaud Minier .version_id = 1, 2766487653eSArnaud Minier .minimum_version_id = 1, 2776487653eSArnaud Minier .fields = (VMStateField[]) { 2786487653eSArnaud Minier VMSTATE_UINT32(id, RccPllState), 2796487653eSArnaud Minier VMSTATE_CLOCK(in, RccPllState), 2806487653eSArnaud Minier VMSTATE_ARRAY_CLOCK(channels, RccPllState, 2816487653eSArnaud Minier RCC_NUM_CHANNEL_PLL_OUT), 2826487653eSArnaud Minier VMSTATE_BOOL(enabled, RccPllState), 2836487653eSArnaud Minier VMSTATE_UINT32(vco_multiplier, RccPllState), 2846487653eSArnaud Minier VMSTATE_BOOL_ARRAY(channel_enabled, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2856487653eSArnaud Minier VMSTATE_BOOL_ARRAY(channel_exists, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2866487653eSArnaud Minier VMSTATE_UINT32_ARRAY(channel_divider, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2876487653eSArnaud Minier VMSTATE_END_OF_LIST() 2886487653eSArnaud Minier } 2896487653eSArnaud Minier }; 2906487653eSArnaud Minier 2916487653eSArnaud Minier static void pll_class_init(ObjectClass *klass, void *data) 2926487653eSArnaud Minier { 2936487653eSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 2946487653eSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 2956487653eSArnaud Minier 296141c29a2SArnaud Minier rc->phases.enter = pll_reset_enter; 2976487653eSArnaud Minier rc->phases.hold = pll_reset_hold; 298141c29a2SArnaud Minier rc->phases.exit = pll_reset_exit; 2996487653eSArnaud Minier dc->vmsd = &pll_vmstate; 3006487653eSArnaud Minier } 3016487653eSArnaud Minier 3026487653eSArnaud Minier static void pll_set_vco_multiplier(RccPllState *pll, uint32_t vco_multiplier) 3036487653eSArnaud Minier { 3046487653eSArnaud Minier if (pll->vco_multiplier == vco_multiplier) { 3056487653eSArnaud Minier return; 3066487653eSArnaud Minier } 3076487653eSArnaud Minier 3086487653eSArnaud Minier if (vco_multiplier < 8 || vco_multiplier > 86) { 3096487653eSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 3106487653eSArnaud Minier "%s: VCO multiplier is out of bound (%u) for PLL %u\n", 3116487653eSArnaud Minier __func__, vco_multiplier, pll->id); 3126487653eSArnaud Minier return; 3136487653eSArnaud Minier } 3146487653eSArnaud Minier 3156487653eSArnaud Minier trace_stm32l4x5_rcc_pll_set_vco_multiplier(pll->id, 3166487653eSArnaud Minier pll->vco_multiplier, vco_multiplier); 3176487653eSArnaud Minier 3186487653eSArnaud Minier pll->vco_multiplier = vco_multiplier; 319141c29a2SArnaud Minier pll_update(pll, false); 3206487653eSArnaud Minier } 3216487653eSArnaud Minier 3226487653eSArnaud Minier static void pll_set_enable(RccPllState *pll, bool enabled) 3236487653eSArnaud Minier { 3246487653eSArnaud Minier if (pll->enabled == enabled) { 3256487653eSArnaud Minier return; 3266487653eSArnaud Minier } 3276487653eSArnaud Minier 3286487653eSArnaud Minier pll->enabled = enabled; 329141c29a2SArnaud Minier pll_update(pll, false); 3306487653eSArnaud Minier } 3316487653eSArnaud Minier 3326487653eSArnaud Minier static void pll_set_channel_enable(RccPllState *pll, 3336487653eSArnaud Minier PllCommonChannels channel, 3346487653eSArnaud Minier bool enabled) 3356487653eSArnaud Minier { 3366487653eSArnaud Minier if (pll->channel_enabled[channel] == enabled) { 3376487653eSArnaud Minier return; 3386487653eSArnaud Minier } 3396487653eSArnaud Minier 3406487653eSArnaud Minier if (enabled) { 3416487653eSArnaud Minier trace_stm32l4x5_rcc_pll_channel_enable(pll->id, channel); 3426487653eSArnaud Minier } else { 3436487653eSArnaud Minier trace_stm32l4x5_rcc_pll_channel_disable(pll->id, channel); 3446487653eSArnaud Minier } 3456487653eSArnaud Minier 3466487653eSArnaud Minier pll->channel_enabled[channel] = enabled; 347141c29a2SArnaud Minier pll_update(pll, false); 3486487653eSArnaud Minier } 3496487653eSArnaud Minier 3506487653eSArnaud Minier static void pll_set_channel_divider(RccPllState *pll, 3516487653eSArnaud Minier PllCommonChannels channel, 3526487653eSArnaud Minier uint32_t divider) 3536487653eSArnaud Minier { 3546487653eSArnaud Minier if (pll->channel_divider[channel] == divider) { 3556487653eSArnaud Minier return; 3566487653eSArnaud Minier } 3576487653eSArnaud Minier 3586487653eSArnaud Minier trace_stm32l4x5_rcc_pll_set_channel_divider(pll->id, 3596487653eSArnaud Minier channel, pll->channel_divider[channel], divider); 3606487653eSArnaud Minier 3616487653eSArnaud Minier pll->channel_divider[channel] = divider; 362141c29a2SArnaud Minier pll_update(pll, false); 3636487653eSArnaud Minier } 3646487653eSArnaud Minier 365d6b55a0fSArnaud Minier static void rcc_update_irq(Stm32l4x5RccState *s) 366d6b55a0fSArnaud Minier { 3679c796d50SArnaud Minier /* 3689c796d50SArnaud Minier * TODO: Handle LSECSSF and CSSF flags when the CSS is implemented. 3699c796d50SArnaud Minier */ 370d6b55a0fSArnaud Minier if (s->cifr & CIFR_IRQ_MASK) { 371d6b55a0fSArnaud Minier qemu_irq_raise(s->irq); 372d6b55a0fSArnaud Minier } else { 373d6b55a0fSArnaud Minier qemu_irq_lower(s->irq); 374d6b55a0fSArnaud Minier } 375d6b55a0fSArnaud Minier } 376d6b55a0fSArnaud Minier 377*3b551477SArnaud Minier static void rcc_update_msi(Stm32l4x5RccState *s, uint32_t previous_value) 378*3b551477SArnaud Minier { 379*3b551477SArnaud Minier uint32_t val; 380*3b551477SArnaud Minier 381*3b551477SArnaud Minier static const uint32_t msirange[] = { 382*3b551477SArnaud Minier 100000, 200000, 400000, 800000, 1000000, 2000000, 383*3b551477SArnaud Minier 4000000, 8000000, 16000000, 24000000, 32000000, 48000000 384*3b551477SArnaud Minier }; 385*3b551477SArnaud Minier /* MSIRANGE and MSIRGSEL */ 386*3b551477SArnaud Minier val = extract32(s->cr, R_CR_MSIRGSEL_SHIFT, R_CR_MSIRGSEL_LENGTH); 387*3b551477SArnaud Minier if (val) { 388*3b551477SArnaud Minier /* MSIRGSEL is set, use the MSIRANGE field */ 389*3b551477SArnaud Minier val = extract32(s->cr, R_CR_MSIRANGE_SHIFT, R_CR_MSIRANGE_LENGTH); 390*3b551477SArnaud Minier } else { 391*3b551477SArnaud Minier /* MSIRGSEL is not set, use the MSISRANGE field */ 392*3b551477SArnaud Minier val = extract32(s->csr, R_CSR_MSISRANGE_SHIFT, R_CSR_MSISRANGE_LENGTH); 393*3b551477SArnaud Minier } 394*3b551477SArnaud Minier 395*3b551477SArnaud Minier if (val < ARRAY_SIZE(msirange)) { 396*3b551477SArnaud Minier clock_update_hz(s->msi_rc, msirange[val]); 397*3b551477SArnaud Minier } else { 398*3b551477SArnaud Minier /* 399*3b551477SArnaud Minier * There is a hardware write protection if the value is out of bound. 400*3b551477SArnaud Minier * Restore the previous value. 401*3b551477SArnaud Minier */ 402*3b551477SArnaud Minier s->cr = (s->cr & ~R_CSR_MSISRANGE_MASK) | 403*3b551477SArnaud Minier (previous_value & R_CSR_MSISRANGE_MASK); 404*3b551477SArnaud Minier } 405*3b551477SArnaud Minier } 406*3b551477SArnaud Minier 407*3b551477SArnaud Minier /* 408*3b551477SArnaud Minier * TODO: Add write-protection for all registers: 409*3b551477SArnaud Minier * DONE: CR 410*3b551477SArnaud Minier */ 411*3b551477SArnaud Minier 412*3b551477SArnaud Minier static void rcc_update_cr_register(Stm32l4x5RccState *s, uint32_t previous_value) 4139c796d50SArnaud Minier { 4149c796d50SArnaud Minier int val; 415*3b551477SArnaud Minier const RccClockMuxSource current_pll_src = 416*3b551477SArnaud Minier CLOCK_MUX_INIT_INFO[RCC_CLOCK_MUX_PLL_INPUT].src_mapping[ 417*3b551477SArnaud Minier s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].src]; 4189c796d50SArnaud Minier 4199c796d50SArnaud Minier /* PLLSAI2ON and update PLLSAI2RDY */ 4209c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, PLLSAI2ON); 4219c796d50SArnaud Minier pll_set_enable(&s->plls[RCC_PLL_PLLSAI2], val); 4229c796d50SArnaud Minier s->cr = (s->cr & ~R_CR_PLLSAI2RDY_MASK) | 4239c796d50SArnaud Minier (val << R_CR_PLLSAI2RDY_SHIFT); 4249c796d50SArnaud Minier if (s->cier & R_CIER_PLLSAI2RDYIE_MASK) { 4259c796d50SArnaud Minier s->cifr |= R_CIFR_PLLSAI2RDYF_MASK; 4269c796d50SArnaud Minier } 4279c796d50SArnaud Minier 4289c796d50SArnaud Minier /* PLLSAI1ON and update PLLSAI1RDY */ 4299c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, PLLSAI1ON); 4309c796d50SArnaud Minier pll_set_enable(&s->plls[RCC_PLL_PLLSAI1], val); 4319c796d50SArnaud Minier s->cr = (s->cr & ~R_CR_PLLSAI1RDY_MASK) | 4329c796d50SArnaud Minier (val << R_CR_PLLSAI1RDY_SHIFT); 4339c796d50SArnaud Minier if (s->cier & R_CIER_PLLSAI1RDYIE_MASK) { 4349c796d50SArnaud Minier s->cifr |= R_CIFR_PLLSAI1RDYF_MASK; 4359c796d50SArnaud Minier } 4369c796d50SArnaud Minier 437*3b551477SArnaud Minier /* 438*3b551477SArnaud Minier * PLLON and update PLLRDY 439*3b551477SArnaud Minier * PLLON cannot be reset if the PLL clock is used as the system clock. 440*3b551477SArnaud Minier */ 4419c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, PLLON); 442*3b551477SArnaud Minier if (FIELD_EX32(s->cfgr, CFGR, SWS) != 0b11) { 4439c796d50SArnaud Minier pll_set_enable(&s->plls[RCC_PLL_PLL], val); 4449c796d50SArnaud Minier s->cr = (s->cr & ~R_CR_PLLRDY_MASK) | 4459c796d50SArnaud Minier (val << R_CR_PLLRDY_SHIFT); 4469c796d50SArnaud Minier if (s->cier & R_CIER_PLLRDYIE_MASK) { 4479c796d50SArnaud Minier s->cifr |= R_CIFR_PLLRDYF_MASK; 4489c796d50SArnaud Minier } 449*3b551477SArnaud Minier } else { 450*3b551477SArnaud Minier s->cr |= R_CR_PLLON_MASK; 451*3b551477SArnaud Minier } 4529c796d50SArnaud Minier 4539c796d50SArnaud Minier /* CSSON: TODO */ 4549c796d50SArnaud Minier /* HSEBYP: TODO */ 4559c796d50SArnaud Minier 456*3b551477SArnaud Minier /* 457*3b551477SArnaud Minier * HSEON and update HSERDY. 458*3b551477SArnaud Minier * HSEON cannot be reset if the HSE oscillator is used directly or 459*3b551477SArnaud Minier * indirectly as the system clock. 460*3b551477SArnaud Minier */ 4619c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, HSEON); 462*3b551477SArnaud Minier if (FIELD_EX32(s->cfgr, CFGR, SWS) != 0b10 && 463*3b551477SArnaud Minier current_pll_src != RCC_CLOCK_MUX_SRC_HSE) { 4649c796d50SArnaud Minier s->cr = (s->cr & ~R_CR_HSERDY_MASK) | 4659c796d50SArnaud Minier (val << R_CR_HSERDY_SHIFT); 4669c796d50SArnaud Minier if (val) { 4679c796d50SArnaud Minier clock_update_hz(s->hse, s->hse_frequency); 4689c796d50SArnaud Minier if (s->cier & R_CIER_HSERDYIE_MASK) { 4699c796d50SArnaud Minier s->cifr |= R_CIFR_HSERDYF_MASK; 4709c796d50SArnaud Minier } 4719c796d50SArnaud Minier } else { 4729c796d50SArnaud Minier clock_update(s->hse, 0); 4739c796d50SArnaud Minier } 474*3b551477SArnaud Minier } else { 475*3b551477SArnaud Minier s->cr |= R_CR_HSEON_MASK; 476*3b551477SArnaud Minier } 4779c796d50SArnaud Minier 4789c796d50SArnaud Minier /* HSIAFS: TODO*/ 4799c796d50SArnaud Minier /* HSIKERON: TODO*/ 4809c796d50SArnaud Minier 481*3b551477SArnaud Minier /* 482*3b551477SArnaud Minier * HSION and update HSIRDY 483*3b551477SArnaud Minier * HSION is set by hardware if the HSI16 is used directly 484*3b551477SArnaud Minier * or indirectly as system clock. 485*3b551477SArnaud Minier */ 486*3b551477SArnaud Minier if (FIELD_EX32(s->cfgr, CFGR, SWS) == 0b01 || 487*3b551477SArnaud Minier current_pll_src == RCC_CLOCK_MUX_SRC_HSI) { 488*3b551477SArnaud Minier s->cr |= (R_CR_HSION_MASK | R_CR_HSIRDY_MASK); 4899c796d50SArnaud Minier clock_update_hz(s->hsi16_rc, HSI_FRQ); 4909c796d50SArnaud Minier if (s->cier & R_CIER_HSIRDYIE_MASK) { 4919c796d50SArnaud Minier s->cifr |= R_CIFR_HSIRDYF_MASK; 4929c796d50SArnaud Minier } 4939c796d50SArnaud Minier } else { 494*3b551477SArnaud Minier val = FIELD_EX32(s->cr, CR, HSION); 4959c796d50SArnaud Minier if (val) { 496*3b551477SArnaud Minier clock_update_hz(s->hsi16_rc, HSI_FRQ); 497*3b551477SArnaud Minier s->cr |= R_CR_HSIRDY_MASK; 498*3b551477SArnaud Minier if (s->cier & R_CIER_HSIRDYIE_MASK) { 499*3b551477SArnaud Minier s->cifr |= R_CIFR_HSIRDYF_MASK; 500*3b551477SArnaud Minier } 5019c796d50SArnaud Minier } else { 502*3b551477SArnaud Minier clock_update(s->hsi16_rc, 0); 503*3b551477SArnaud Minier s->cr &= ~R_CR_HSIRDY_MASK; 504*3b551477SArnaud Minier } 5059c796d50SArnaud Minier } 5069c796d50SArnaud Minier 507*3b551477SArnaud Minier /* MSIPLLEN: TODO */ 508*3b551477SArnaud Minier 509*3b551477SArnaud Minier /* 510*3b551477SArnaud Minier * MSION and update MSIRDY 511*3b551477SArnaud Minier * Set by hardware when used directly or indirectly as system clock. 512*3b551477SArnaud Minier */ 513*3b551477SArnaud Minier if (FIELD_EX32(s->cfgr, CFGR, SWS) == 0b00 || 514*3b551477SArnaud Minier current_pll_src == RCC_CLOCK_MUX_SRC_MSI) { 515*3b551477SArnaud Minier s->cr |= (R_CR_MSION_MASK | R_CR_MSIRDY_MASK); 516*3b551477SArnaud Minier if (!(previous_value & R_CR_MSION_MASK) && (s->cier & R_CIER_MSIRDYIE_MASK)) { 517*3b551477SArnaud Minier s->cifr |= R_CIFR_MSIRDYF_MASK; 5189c796d50SArnaud Minier } 519*3b551477SArnaud Minier rcc_update_msi(s, previous_value); 520*3b551477SArnaud Minier } else { 5219c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, MSION); 522*3b551477SArnaud Minier if (val) { 523*3b551477SArnaud Minier s->cr |= R_CR_MSIRDY_MASK; 524*3b551477SArnaud Minier rcc_update_msi(s, previous_value); 5259c796d50SArnaud Minier if (s->cier & R_CIER_MSIRDYIE_MASK) { 5269c796d50SArnaud Minier s->cifr |= R_CIFR_MSIRDYF_MASK; 5279c796d50SArnaud Minier } 528*3b551477SArnaud Minier } else { 529*3b551477SArnaud Minier s->cr &= ~R_CR_MSIRDY_MASK; 530*3b551477SArnaud Minier clock_update(s->msi_rc, 0); 531*3b551477SArnaud Minier } 532*3b551477SArnaud Minier } 5339c796d50SArnaud Minier rcc_update_irq(s); 5349c796d50SArnaud Minier } 5359c796d50SArnaud Minier 5369c796d50SArnaud Minier static void rcc_update_cfgr_register(Stm32l4x5RccState *s) 5379c796d50SArnaud Minier { 5389c796d50SArnaud Minier uint32_t val; 5399c796d50SArnaud Minier /* MCOPRE */ 5409c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, MCOPRE); 5419c796d50SArnaud Minier assert(val <= 0b100); 5429c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_MCO], 5439c796d50SArnaud Minier 1, 1 << val); 5449c796d50SArnaud Minier 5459c796d50SArnaud Minier /* MCOSEL */ 5469c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, MCOSEL); 5479c796d50SArnaud Minier assert(val <= 0b111); 5489c796d50SArnaud Minier if (val == 0) { 5499c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false); 5509c796d50SArnaud Minier } else { 5519c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], true); 5529c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_MCO], 5539c796d50SArnaud Minier val - 1); 5549c796d50SArnaud Minier } 5559c796d50SArnaud Minier 5569c796d50SArnaud Minier /* STOPWUCK */ 5579c796d50SArnaud Minier /* TODO */ 5589c796d50SArnaud Minier 5599c796d50SArnaud Minier /* PPRE2 */ 5609c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, PPRE2); 5619c796d50SArnaud Minier if (val < 0b100) { 5629c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK2], 5639c796d50SArnaud Minier 1, 1); 5649c796d50SArnaud Minier } else { 5659c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK2], 5669c796d50SArnaud Minier 1, 1 << (val - 0b11)); 5679c796d50SArnaud Minier } 5689c796d50SArnaud Minier 5699c796d50SArnaud Minier /* PPRE1 */ 5709c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, PPRE1); 5719c796d50SArnaud Minier if (val < 0b100) { 5729c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK1], 5739c796d50SArnaud Minier 1, 1); 5749c796d50SArnaud Minier } else { 5759c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK1], 5769c796d50SArnaud Minier 1, 1 << (val - 0b11)); 5779c796d50SArnaud Minier } 5789c796d50SArnaud Minier 5799c796d50SArnaud Minier /* HPRE */ 5809c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, HPRE); 5819c796d50SArnaud Minier if (val < 0b1000) { 5829c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_HCLK], 5839c796d50SArnaud Minier 1, 1); 5849c796d50SArnaud Minier } else { 5859c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_HCLK], 5869c796d50SArnaud Minier 1, 1 << (val - 0b111)); 5879c796d50SArnaud Minier } 5889c796d50SArnaud Minier 5899c796d50SArnaud Minier /* Update SWS */ 5909c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, SW); 5919c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_SYSCLK], 5929c796d50SArnaud Minier val); 5939c796d50SArnaud Minier s->cfgr &= ~R_CFGR_SWS_MASK; 5949c796d50SArnaud Minier s->cfgr |= val << R_CFGR_SWS_SHIFT; 5959c796d50SArnaud Minier } 5969c796d50SArnaud Minier 5979c796d50SArnaud Minier static void rcc_update_ahb1enr(Stm32l4x5RccState *s) 5989c796d50SArnaud Minier { 5999c796d50SArnaud Minier #define AHB1ENR_SET_ENABLE(_peripheral_name) \ 6009c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6019c796d50SArnaud Minier FIELD_EX32(s->ahb1enr, AHB1ENR, _peripheral_name##EN)) 6029c796d50SArnaud Minier 6039c796d50SArnaud Minier /* DMA2DEN: reserved for STM32L475xx */ 6049c796d50SArnaud Minier AHB1ENR_SET_ENABLE(TSC); 6059c796d50SArnaud Minier AHB1ENR_SET_ENABLE(CRC); 6069c796d50SArnaud Minier AHB1ENR_SET_ENABLE(FLASH); 6079c796d50SArnaud Minier AHB1ENR_SET_ENABLE(DMA2); 6089c796d50SArnaud Minier AHB1ENR_SET_ENABLE(DMA1); 6099c796d50SArnaud Minier 6109c796d50SArnaud Minier #undef AHB1ENR_SET_ENABLE 6119c796d50SArnaud Minier } 6129c796d50SArnaud Minier 6139c796d50SArnaud Minier static void rcc_update_ahb2enr(Stm32l4x5RccState *s) 6149c796d50SArnaud Minier { 6159c796d50SArnaud Minier #define AHB2ENR_SET_ENABLE(_peripheral_name) \ 6169c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6179c796d50SArnaud Minier FIELD_EX32(s->ahb2enr, AHB2ENR, _peripheral_name##EN)) 6189c796d50SArnaud Minier 6199c796d50SArnaud Minier AHB2ENR_SET_ENABLE(RNG); 6209c796d50SArnaud Minier /* HASHEN: reserved for STM32L475xx */ 6219c796d50SArnaud Minier AHB2ENR_SET_ENABLE(AES); 6229c796d50SArnaud Minier /* DCMIEN: reserved for STM32L475xx */ 6239c796d50SArnaud Minier AHB2ENR_SET_ENABLE(ADC); 6249c796d50SArnaud Minier AHB2ENR_SET_ENABLE(OTGFS); 6259c796d50SArnaud Minier /* GPIOIEN: reserved for STM32L475xx */ 6269c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOA); 6279c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOB); 6289c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOC); 6299c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOD); 6309c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOE); 6319c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOF); 6329c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOG); 6339c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOH); 6349c796d50SArnaud Minier 6359c796d50SArnaud Minier #undef AHB2ENR_SET_ENABLE 6369c796d50SArnaud Minier } 6379c796d50SArnaud Minier 6389c796d50SArnaud Minier static void rcc_update_ahb3enr(Stm32l4x5RccState *s) 6399c796d50SArnaud Minier { 6409c796d50SArnaud Minier #define AHB3ENR_SET_ENABLE(_peripheral_name) \ 6419c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6429c796d50SArnaud Minier FIELD_EX32(s->ahb3enr, AHB3ENR, _peripheral_name##EN)) 6439c796d50SArnaud Minier 6449c796d50SArnaud Minier AHB3ENR_SET_ENABLE(QSPI); 6459c796d50SArnaud Minier AHB3ENR_SET_ENABLE(FMC); 6469c796d50SArnaud Minier 6479c796d50SArnaud Minier #undef AHB3ENR_SET_ENABLE 6489c796d50SArnaud Minier } 6499c796d50SArnaud Minier 6509c796d50SArnaud Minier static void rcc_update_apb1enr(Stm32l4x5RccState *s) 6519c796d50SArnaud Minier { 6529c796d50SArnaud Minier #define APB1ENR1_SET_ENABLE(_peripheral_name) \ 6539c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6549c796d50SArnaud Minier FIELD_EX32(s->apb1enr1, APB1ENR1, _peripheral_name##EN)) 6559c796d50SArnaud Minier #define APB1ENR2_SET_ENABLE(_peripheral_name) \ 6569c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6579c796d50SArnaud Minier FIELD_EX32(s->apb1enr2, APB1ENR2, _peripheral_name##EN)) 6589c796d50SArnaud Minier 6599c796d50SArnaud Minier /* APB1ENR1 */ 6609c796d50SArnaud Minier APB1ENR1_SET_ENABLE(LPTIM1); 6619c796d50SArnaud Minier APB1ENR1_SET_ENABLE(OPAMP); 6629c796d50SArnaud Minier APB1ENR1_SET_ENABLE(DAC1); 6639c796d50SArnaud Minier APB1ENR1_SET_ENABLE(PWR); 6649c796d50SArnaud Minier /* CAN2: reserved for STM32L4x5 */ 6659c796d50SArnaud Minier APB1ENR1_SET_ENABLE(CAN1); 6669c796d50SArnaud Minier /* CRSEN: reserved for STM32L4x5 */ 6679c796d50SArnaud Minier APB1ENR1_SET_ENABLE(I2C3); 6689c796d50SArnaud Minier APB1ENR1_SET_ENABLE(I2C2); 6699c796d50SArnaud Minier APB1ENR1_SET_ENABLE(I2C1); 6709c796d50SArnaud Minier APB1ENR1_SET_ENABLE(UART5); 6719c796d50SArnaud Minier APB1ENR1_SET_ENABLE(UART4); 6729c796d50SArnaud Minier APB1ENR1_SET_ENABLE(USART3); 6739c796d50SArnaud Minier APB1ENR1_SET_ENABLE(USART2); 6749c796d50SArnaud Minier APB1ENR1_SET_ENABLE(SPI3); 6759c796d50SArnaud Minier APB1ENR1_SET_ENABLE(SPI2); 6769c796d50SArnaud Minier APB1ENR1_SET_ENABLE(WWDG); 6779c796d50SArnaud Minier /* RTCAPB: reserved for STM32L4x5 */ 6789c796d50SArnaud Minier APB1ENR1_SET_ENABLE(LCD); 6799c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM7); 6809c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM6); 6819c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM5); 6829c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM4); 6839c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM3); 6849c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM2); 6859c796d50SArnaud Minier 6869c796d50SArnaud Minier /* APB1ENR2 */ 6879c796d50SArnaud Minier APB1ENR2_SET_ENABLE(LPTIM2); 6889c796d50SArnaud Minier APB1ENR2_SET_ENABLE(SWPMI1); 6899c796d50SArnaud Minier /* I2C4EN: reserved for STM32L4x5 */ 6909c796d50SArnaud Minier APB1ENR2_SET_ENABLE(LPUART1); 6919c796d50SArnaud Minier 6929c796d50SArnaud Minier #undef APB1ENR1_SET_ENABLE 6939c796d50SArnaud Minier #undef APB1ENR2_SET_ENABLE 6949c796d50SArnaud Minier } 6959c796d50SArnaud Minier 6969c796d50SArnaud Minier static void rcc_update_apb2enr(Stm32l4x5RccState *s) 6979c796d50SArnaud Minier { 6989c796d50SArnaud Minier #define APB2ENR_SET_ENABLE(_peripheral_name) \ 6999c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 7009c796d50SArnaud Minier FIELD_EX32(s->apb2enr, APB2ENR, _peripheral_name##EN)) 7019c796d50SArnaud Minier 7029c796d50SArnaud Minier APB2ENR_SET_ENABLE(DFSDM1); 7039c796d50SArnaud Minier APB2ENR_SET_ENABLE(SAI2); 7049c796d50SArnaud Minier APB2ENR_SET_ENABLE(SAI1); 7059c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM17); 7069c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM16); 7079c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM15); 7089c796d50SArnaud Minier APB2ENR_SET_ENABLE(USART1); 7099c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM8); 7109c796d50SArnaud Minier APB2ENR_SET_ENABLE(SPI1); 7119c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM1); 7129c796d50SArnaud Minier APB2ENR_SET_ENABLE(SDMMC1); 7139c796d50SArnaud Minier APB2ENR_SET_ENABLE(FW); 7149c796d50SArnaud Minier APB2ENR_SET_ENABLE(SYSCFG); 7159c796d50SArnaud Minier 7169c796d50SArnaud Minier #undef APB2ENR_SET_ENABLE 7179c796d50SArnaud Minier } 7189c796d50SArnaud Minier 7199c796d50SArnaud Minier /* 7209c796d50SArnaud Minier * The 3 PLLs share the same register layout 7219c796d50SArnaud Minier * so we can use the same function for all of them 7229c796d50SArnaud Minier * Note: no frequency bounds checking is done here. 7239c796d50SArnaud Minier */ 7249c796d50SArnaud Minier static void rcc_update_pllsaixcfgr(Stm32l4x5RccState *s, RccPll pll_id) 7259c796d50SArnaud Minier { 7269c796d50SArnaud Minier uint32_t reg, val; 7279c796d50SArnaud Minier switch (pll_id) { 7289c796d50SArnaud Minier case RCC_PLL_PLL: 7299c796d50SArnaud Minier reg = s->pllcfgr; 7309c796d50SArnaud Minier break; 7319c796d50SArnaud Minier case RCC_PLL_PLLSAI1: 7329c796d50SArnaud Minier reg = s->pllsai1cfgr; 7339c796d50SArnaud Minier break; 7349c796d50SArnaud Minier case RCC_PLL_PLLSAI2: 7359c796d50SArnaud Minier reg = s->pllsai2cfgr; 7369c796d50SArnaud Minier break; 7379c796d50SArnaud Minier default: 7389c796d50SArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 7399c796d50SArnaud Minier "%s: Invalid PLL ID: %u\n", __func__, pll_id); 7409c796d50SArnaud Minier return; 7419c796d50SArnaud Minier } 7429c796d50SArnaud Minier 7439c796d50SArnaud Minier /* PLLPDIV */ 7449c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLPDIV); 7459c796d50SArnaud Minier /* 1 is a reserved value */ 7469c796d50SArnaud Minier if (val == 0) { 7479c796d50SArnaud Minier /* Get PLLP value */ 7489c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLP); 7499c796d50SArnaud Minier pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, 7509c796d50SArnaud Minier (val ? 17 : 7)); 7519c796d50SArnaud Minier } else if (val > 1) { 7529c796d50SArnaud Minier pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, 7539c796d50SArnaud Minier val); 7549c796d50SArnaud Minier } 7559c796d50SArnaud Minier 7569c796d50SArnaud Minier 7579c796d50SArnaud Minier /* PLLR */ 7589c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLR); 7599c796d50SArnaud Minier pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_R, 7609c796d50SArnaud Minier 2 * (val + 1)); 7619c796d50SArnaud Minier 7629c796d50SArnaud Minier /* PLLREN */ 7639c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLREN); 7649c796d50SArnaud Minier pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_R, val); 7659c796d50SArnaud Minier 7669c796d50SArnaud Minier /* PLLQ */ 7679c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLQ); 7689c796d50SArnaud Minier pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_Q, 7699c796d50SArnaud Minier 2 * (val + 1)); 7709c796d50SArnaud Minier 7719c796d50SArnaud Minier /* PLLQEN */ 7729c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLQEN); 7739c796d50SArnaud Minier pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_Q, val); 7749c796d50SArnaud Minier 7759c796d50SArnaud Minier /* PLLPEN */ 7769c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLPEN); 7779c796d50SArnaud Minier pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, val); 7789c796d50SArnaud Minier 7799c796d50SArnaud Minier /* PLLN */ 7809c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLN); 7819c796d50SArnaud Minier pll_set_vco_multiplier(&s->plls[pll_id], val); 7829c796d50SArnaud Minier } 7839c796d50SArnaud Minier 7849c796d50SArnaud Minier static void rcc_update_pllcfgr(Stm32l4x5RccState *s) 7859c796d50SArnaud Minier { 7869c796d50SArnaud Minier int val; 7879c796d50SArnaud Minier 7889c796d50SArnaud Minier /* Use common layout */ 7899c796d50SArnaud Minier rcc_update_pllsaixcfgr(s, RCC_PLL_PLL); 7909c796d50SArnaud Minier 7919c796d50SArnaud Minier /* Fetch specific fields for pllcfgr */ 7929c796d50SArnaud Minier 7939c796d50SArnaud Minier /* PLLM */ 7949c796d50SArnaud Minier val = FIELD_EX32(s->pllcfgr, PLLCFGR, PLLM); 7959c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], 1, (val + 1)); 7969c796d50SArnaud Minier 7979c796d50SArnaud Minier /* PLLSRC */ 7989c796d50SArnaud Minier val = FIELD_EX32(s->pllcfgr, PLLCFGR, PLLSRC); 7999c796d50SArnaud Minier if (val == 0) { 8009c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], false); 8019c796d50SArnaud Minier } else { 8029c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], val - 1); 8039c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], true); 8049c796d50SArnaud Minier } 8059c796d50SArnaud Minier } 8069c796d50SArnaud Minier 8079c796d50SArnaud Minier static void rcc_update_ccipr(Stm32l4x5RccState *s) 8089c796d50SArnaud Minier { 8099c796d50SArnaud Minier #define CCIPR_SET_SOURCE(_peripheral_name) \ 8109c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 8119c796d50SArnaud Minier FIELD_EX32(s->ccipr, CCIPR, _peripheral_name##SEL)) 8129c796d50SArnaud Minier 8139c796d50SArnaud Minier CCIPR_SET_SOURCE(DFSDM1); 8149c796d50SArnaud Minier CCIPR_SET_SOURCE(SWPMI1); 8159c796d50SArnaud Minier CCIPR_SET_SOURCE(ADC); 8169c796d50SArnaud Minier CCIPR_SET_SOURCE(CLK48); 8179c796d50SArnaud Minier CCIPR_SET_SOURCE(SAI2); 8189c796d50SArnaud Minier CCIPR_SET_SOURCE(SAI1); 8199c796d50SArnaud Minier CCIPR_SET_SOURCE(LPTIM2); 8209c796d50SArnaud Minier CCIPR_SET_SOURCE(LPTIM1); 8219c796d50SArnaud Minier CCIPR_SET_SOURCE(I2C3); 8229c796d50SArnaud Minier CCIPR_SET_SOURCE(I2C2); 8239c796d50SArnaud Minier CCIPR_SET_SOURCE(I2C1); 8249c796d50SArnaud Minier CCIPR_SET_SOURCE(LPUART1); 8259c796d50SArnaud Minier CCIPR_SET_SOURCE(UART5); 8269c796d50SArnaud Minier CCIPR_SET_SOURCE(UART4); 8279c796d50SArnaud Minier CCIPR_SET_SOURCE(USART3); 8289c796d50SArnaud Minier CCIPR_SET_SOURCE(USART2); 8299c796d50SArnaud Minier CCIPR_SET_SOURCE(USART1); 8309c796d50SArnaud Minier 8319c796d50SArnaud Minier #undef CCIPR_SET_SOURCE 8329c796d50SArnaud Minier } 8339c796d50SArnaud Minier 8349c796d50SArnaud Minier static void rcc_update_bdcr(Stm32l4x5RccState *s) 8359c796d50SArnaud Minier { 8369c796d50SArnaud Minier int val; 8379c796d50SArnaud Minier 8389c796d50SArnaud Minier /* LSCOSEL */ 8399c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, LSCOSEL); 8409c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_LSCO], val); 8419c796d50SArnaud Minier 8429c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, LSCOEN); 8439c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_LSCO], val); 8449c796d50SArnaud Minier 8459c796d50SArnaud Minier /* BDRST */ 8469c796d50SArnaud Minier /* 8479c796d50SArnaud Minier * The documentation is not clear if the RTCEN flag disables the RTC and 8489c796d50SArnaud Minier * the LCD common mux or if it only affects the RTC. 8499c796d50SArnaud Minier * As the LCDEN flag exists, we assume here that it only affects the RTC. 8509c796d50SArnaud Minier */ 8519c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, RTCEN); 8529c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_RTC], val); 8539c796d50SArnaud Minier /* LCD and RTC share the same clock */ 8549c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, RTCSEL); 8559c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON], val); 8569c796d50SArnaud Minier 8579c796d50SArnaud Minier /* LSECSSON */ 8589c796d50SArnaud Minier /* LSEDRV[1:0] */ 8599c796d50SArnaud Minier /* LSEBYP */ 8609c796d50SArnaud Minier 8619c796d50SArnaud Minier /* LSEON: Update LSERDY at the same time */ 8629c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, LSEON); 8639c796d50SArnaud Minier if (val) { 8649c796d50SArnaud Minier clock_update_hz(s->lse_crystal, LSE_FRQ); 8659c796d50SArnaud Minier s->bdcr |= R_BDCR_LSERDY_MASK; 8669c796d50SArnaud Minier if (s->cier & R_CIER_LSERDYIE_MASK) { 8679c796d50SArnaud Minier s->cifr |= R_CIFR_LSERDYF_MASK; 8689c796d50SArnaud Minier } 8699c796d50SArnaud Minier } else { 8709c796d50SArnaud Minier clock_update(s->lse_crystal, 0); 8719c796d50SArnaud Minier s->bdcr &= ~R_BDCR_LSERDY_MASK; 8729c796d50SArnaud Minier } 8739c796d50SArnaud Minier 8749c796d50SArnaud Minier rcc_update_irq(s); 8759c796d50SArnaud Minier } 8769c796d50SArnaud Minier 8779c796d50SArnaud Minier static void rcc_update_csr(Stm32l4x5RccState *s) 8789c796d50SArnaud Minier { 8799c796d50SArnaud Minier int val; 8809c796d50SArnaud Minier 8819c796d50SArnaud Minier /* Reset flags: Not implemented */ 8829c796d50SArnaud Minier /* MSISRANGE: Not implemented after reset */ 8839c796d50SArnaud Minier 8849c796d50SArnaud Minier /* LSION: Update LSIRDY at the same time */ 8859c796d50SArnaud Minier val = FIELD_EX32(s->csr, CSR, LSION); 8869c796d50SArnaud Minier if (val) { 8879c796d50SArnaud Minier clock_update_hz(s->lsi_rc, LSI_FRQ); 8889c796d50SArnaud Minier s->csr |= R_CSR_LSIRDY_MASK; 8899c796d50SArnaud Minier if (s->cier & R_CIER_LSIRDYIE_MASK) { 8909c796d50SArnaud Minier s->cifr |= R_CIFR_LSIRDYF_MASK; 8919c796d50SArnaud Minier } 8929c796d50SArnaud Minier } else { 8939c796d50SArnaud Minier /* 8949c796d50SArnaud Minier * TODO: Handle when the LSI is set independently of LSION. 8959c796d50SArnaud Minier * E.g. when the LSI is set by the RTC. 8969c796d50SArnaud Minier * See the reference manual for more details. 8979c796d50SArnaud Minier */ 8989c796d50SArnaud Minier clock_update(s->lsi_rc, 0); 8999c796d50SArnaud Minier s->csr &= ~R_CSR_LSIRDY_MASK; 9009c796d50SArnaud Minier } 9019c796d50SArnaud Minier 9029c796d50SArnaud Minier rcc_update_irq(s); 9039c796d50SArnaud Minier } 9049c796d50SArnaud Minier 905d6b55a0fSArnaud Minier static void stm32l4x5_rcc_reset_hold(Object *obj) 906d6b55a0fSArnaud Minier { 907d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(obj); 908d6b55a0fSArnaud Minier s->cr = 0x00000063; 909d6b55a0fSArnaud Minier /* 910d6b55a0fSArnaud Minier * Factory-programmed calibration data 911d6b55a0fSArnaud Minier * From the reference manual: 0x10XX 00XX 912d6b55a0fSArnaud Minier * Value taken from a real card. 913d6b55a0fSArnaud Minier */ 914d6b55a0fSArnaud Minier s->icscr = 0x106E0082; 915d6b55a0fSArnaud Minier s->cfgr = 0x0; 916d6b55a0fSArnaud Minier s->pllcfgr = 0x00001000; 917d6b55a0fSArnaud Minier s->pllsai1cfgr = 0x00001000; 918d6b55a0fSArnaud Minier s->pllsai2cfgr = 0x00001000; 919d6b55a0fSArnaud Minier s->cier = 0x0; 920d6b55a0fSArnaud Minier s->cifr = 0x0; 921d6b55a0fSArnaud Minier s->ahb1rstr = 0x0; 922d6b55a0fSArnaud Minier s->ahb2rstr = 0x0; 923d6b55a0fSArnaud Minier s->ahb3rstr = 0x0; 924d6b55a0fSArnaud Minier s->apb1rstr1 = 0x0; 925d6b55a0fSArnaud Minier s->apb1rstr2 = 0x0; 926d6b55a0fSArnaud Minier s->apb2rstr = 0x0; 927d6b55a0fSArnaud Minier s->ahb1enr = 0x00000100; 928d6b55a0fSArnaud Minier s->ahb2enr = 0x0; 929d6b55a0fSArnaud Minier s->ahb3enr = 0x0; 930d6b55a0fSArnaud Minier s->apb1enr1 = 0x0; 931d6b55a0fSArnaud Minier s->apb1enr2 = 0x0; 932d6b55a0fSArnaud Minier s->apb2enr = 0x0; 933d6b55a0fSArnaud Minier s->ahb1smenr = 0x00011303; 934d6b55a0fSArnaud Minier s->ahb2smenr = 0x000532FF; 935d6b55a0fSArnaud Minier s->ahb3smenr = 0x00000101; 936d6b55a0fSArnaud Minier s->apb1smenr1 = 0xF2FECA3F; 937d6b55a0fSArnaud Minier s->apb1smenr2 = 0x00000025; 938d6b55a0fSArnaud Minier s->apb2smenr = 0x01677C01; 939d6b55a0fSArnaud Minier s->ccipr = 0x0; 940d6b55a0fSArnaud Minier s->bdcr = 0x0; 941d6b55a0fSArnaud Minier s->csr = 0x0C000600; 942d6b55a0fSArnaud Minier } 943d6b55a0fSArnaud Minier 944d6b55a0fSArnaud Minier static uint64_t stm32l4x5_rcc_read(void *opaque, hwaddr addr, 945d6b55a0fSArnaud Minier unsigned int size) 946d6b55a0fSArnaud Minier { 947d6b55a0fSArnaud Minier Stm32l4x5RccState *s = opaque; 948d6b55a0fSArnaud Minier uint64_t retvalue = 0; 949d6b55a0fSArnaud Minier 950d6b55a0fSArnaud Minier switch (addr) { 951d6b55a0fSArnaud Minier case A_CR: 952d6b55a0fSArnaud Minier retvalue = s->cr; 953d6b55a0fSArnaud Minier break; 954d6b55a0fSArnaud Minier case A_ICSCR: 955d6b55a0fSArnaud Minier retvalue = s->icscr; 956d6b55a0fSArnaud Minier break; 957d6b55a0fSArnaud Minier case A_CFGR: 958d6b55a0fSArnaud Minier retvalue = s->cfgr; 959d6b55a0fSArnaud Minier break; 960d6b55a0fSArnaud Minier case A_PLLCFGR: 961d6b55a0fSArnaud Minier retvalue = s->pllcfgr; 962d6b55a0fSArnaud Minier break; 963d6b55a0fSArnaud Minier case A_PLLSAI1CFGR: 964d6b55a0fSArnaud Minier retvalue = s->pllsai1cfgr; 965d6b55a0fSArnaud Minier break; 966d6b55a0fSArnaud Minier case A_PLLSAI2CFGR: 967d6b55a0fSArnaud Minier retvalue = s->pllsai2cfgr; 968d6b55a0fSArnaud Minier break; 969d6b55a0fSArnaud Minier case A_CIER: 970d6b55a0fSArnaud Minier retvalue = s->cier; 971d6b55a0fSArnaud Minier break; 972d6b55a0fSArnaud Minier case A_CIFR: 973d6b55a0fSArnaud Minier retvalue = s->cifr; 974d6b55a0fSArnaud Minier break; 975d6b55a0fSArnaud Minier case A_CICR: 976d6b55a0fSArnaud Minier /* CICR is write only, return the reset value = 0 */ 977d6b55a0fSArnaud Minier break; 978d6b55a0fSArnaud Minier case A_AHB1RSTR: 979d6b55a0fSArnaud Minier retvalue = s->ahb1rstr; 980d6b55a0fSArnaud Minier break; 981d6b55a0fSArnaud Minier case A_AHB2RSTR: 982d6b55a0fSArnaud Minier retvalue = s->ahb2rstr; 983d6b55a0fSArnaud Minier break; 984d6b55a0fSArnaud Minier case A_AHB3RSTR: 985d6b55a0fSArnaud Minier retvalue = s->ahb3rstr; 986d6b55a0fSArnaud Minier break; 987d6b55a0fSArnaud Minier case A_APB1RSTR1: 988d6b55a0fSArnaud Minier retvalue = s->apb1rstr1; 989d6b55a0fSArnaud Minier break; 990d6b55a0fSArnaud Minier case A_APB1RSTR2: 991d6b55a0fSArnaud Minier retvalue = s->apb1rstr2; 992d6b55a0fSArnaud Minier break; 993d6b55a0fSArnaud Minier case A_APB2RSTR: 994d6b55a0fSArnaud Minier retvalue = s->apb2rstr; 995d6b55a0fSArnaud Minier break; 996d6b55a0fSArnaud Minier case A_AHB1ENR: 997d6b55a0fSArnaud Minier retvalue = s->ahb1enr; 998d6b55a0fSArnaud Minier break; 999d6b55a0fSArnaud Minier case A_AHB2ENR: 1000d6b55a0fSArnaud Minier retvalue = s->ahb2enr; 1001d6b55a0fSArnaud Minier break; 1002d6b55a0fSArnaud Minier case A_AHB3ENR: 1003d6b55a0fSArnaud Minier retvalue = s->ahb3enr; 1004d6b55a0fSArnaud Minier break; 1005d6b55a0fSArnaud Minier case A_APB1ENR1: 1006d6b55a0fSArnaud Minier retvalue = s->apb1enr1; 1007d6b55a0fSArnaud Minier break; 1008d6b55a0fSArnaud Minier case A_APB1ENR2: 1009d6b55a0fSArnaud Minier retvalue = s->apb1enr2; 1010d6b55a0fSArnaud Minier break; 1011d6b55a0fSArnaud Minier case A_APB2ENR: 1012d6b55a0fSArnaud Minier retvalue = s->apb2enr; 1013d6b55a0fSArnaud Minier break; 1014d6b55a0fSArnaud Minier case A_AHB1SMENR: 1015d6b55a0fSArnaud Minier retvalue = s->ahb1smenr; 1016d6b55a0fSArnaud Minier break; 1017d6b55a0fSArnaud Minier case A_AHB2SMENR: 1018d6b55a0fSArnaud Minier retvalue = s->ahb2smenr; 1019d6b55a0fSArnaud Minier break; 1020d6b55a0fSArnaud Minier case A_AHB3SMENR: 1021d6b55a0fSArnaud Minier retvalue = s->ahb3smenr; 1022d6b55a0fSArnaud Minier break; 1023d6b55a0fSArnaud Minier case A_APB1SMENR1: 1024d6b55a0fSArnaud Minier retvalue = s->apb1smenr1; 1025d6b55a0fSArnaud Minier break; 1026d6b55a0fSArnaud Minier case A_APB1SMENR2: 1027d6b55a0fSArnaud Minier retvalue = s->apb1smenr2; 1028d6b55a0fSArnaud Minier break; 1029d6b55a0fSArnaud Minier case A_APB2SMENR: 1030d6b55a0fSArnaud Minier retvalue = s->apb2smenr; 1031d6b55a0fSArnaud Minier break; 1032d6b55a0fSArnaud Minier case A_CCIPR: 1033d6b55a0fSArnaud Minier retvalue = s->ccipr; 1034d6b55a0fSArnaud Minier break; 1035d6b55a0fSArnaud Minier case A_BDCR: 1036d6b55a0fSArnaud Minier retvalue = s->bdcr; 1037d6b55a0fSArnaud Minier break; 1038d6b55a0fSArnaud Minier case A_CSR: 1039d6b55a0fSArnaud Minier retvalue = s->csr; 1040d6b55a0fSArnaud Minier break; 1041d6b55a0fSArnaud Minier default: 1042d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 1043d6b55a0fSArnaud Minier "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 1044d6b55a0fSArnaud Minier break; 1045d6b55a0fSArnaud Minier } 1046d6b55a0fSArnaud Minier 1047d6b55a0fSArnaud Minier trace_stm32l4x5_rcc_read(addr, retvalue); 1048d6b55a0fSArnaud Minier 1049d6b55a0fSArnaud Minier return retvalue; 1050d6b55a0fSArnaud Minier } 1051d6b55a0fSArnaud Minier 1052d6b55a0fSArnaud Minier static void stm32l4x5_rcc_write(void *opaque, hwaddr addr, 1053d6b55a0fSArnaud Minier uint64_t val64, unsigned int size) 1054d6b55a0fSArnaud Minier { 1055d6b55a0fSArnaud Minier Stm32l4x5RccState *s = opaque; 1056*3b551477SArnaud Minier uint32_t previous_value = 0; 1057d6b55a0fSArnaud Minier const uint32_t value = val64; 1058d6b55a0fSArnaud Minier 1059d6b55a0fSArnaud Minier trace_stm32l4x5_rcc_write(addr, value); 1060d6b55a0fSArnaud Minier 1061d6b55a0fSArnaud Minier switch (addr) { 1062d6b55a0fSArnaud Minier case A_CR: 1063*3b551477SArnaud Minier previous_value = s->cr; 1064d6b55a0fSArnaud Minier s->cr = (s->cr & CR_READ_SET_MASK) | 1065d6b55a0fSArnaud Minier (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK)); 1066*3b551477SArnaud Minier rcc_update_cr_register(s, previous_value); 1067d6b55a0fSArnaud Minier break; 1068d6b55a0fSArnaud Minier case A_ICSCR: 1069d6b55a0fSArnaud Minier s->icscr = value & ~ICSCR_READ_ONLY_MASK; 10709c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 10719c796d50SArnaud Minier "%s: Side-effects not implemented for ICSCR\n", __func__); 1072d6b55a0fSArnaud Minier break; 1073d6b55a0fSArnaud Minier case A_CFGR: 1074d6b55a0fSArnaud Minier s->cfgr = value & ~CFGR_READ_ONLY_MASK; 10759c796d50SArnaud Minier rcc_update_cfgr_register(s); 1076d6b55a0fSArnaud Minier break; 1077d6b55a0fSArnaud Minier case A_PLLCFGR: 1078d6b55a0fSArnaud Minier s->pllcfgr = value; 10799c796d50SArnaud Minier rcc_update_pllcfgr(s); 1080d6b55a0fSArnaud Minier break; 1081d6b55a0fSArnaud Minier case A_PLLSAI1CFGR: 1082d6b55a0fSArnaud Minier s->pllsai1cfgr = value; 10839c796d50SArnaud Minier rcc_update_pllsaixcfgr(s, RCC_PLL_PLLSAI1); 1084d6b55a0fSArnaud Minier break; 1085d6b55a0fSArnaud Minier case A_PLLSAI2CFGR: 1086d6b55a0fSArnaud Minier s->pllsai2cfgr = value; 10879c796d50SArnaud Minier rcc_update_pllsaixcfgr(s, RCC_PLL_PLLSAI2); 1088d6b55a0fSArnaud Minier break; 1089d6b55a0fSArnaud Minier case A_CIER: 1090d6b55a0fSArnaud Minier s->cier = value; 10919c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 10929c796d50SArnaud Minier "%s: Side-effects not implemented for CIER\n", __func__); 1093d6b55a0fSArnaud Minier break; 1094d6b55a0fSArnaud Minier case A_CIFR: 1095d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 1096d6b55a0fSArnaud Minier "%s: Write attempt into read-only register (CIFR) 0x%"PRIx32"\n", 1097d6b55a0fSArnaud Minier __func__, value); 1098d6b55a0fSArnaud Minier break; 1099d6b55a0fSArnaud Minier case A_CICR: 1100d6b55a0fSArnaud Minier /* Clear interrupt flags by writing a 1 to the CICR register */ 1101d6b55a0fSArnaud Minier s->cifr &= ~value; 1102d6b55a0fSArnaud Minier rcc_update_irq(s); 1103d6b55a0fSArnaud Minier break; 1104d6b55a0fSArnaud Minier /* Reset behaviors are not implemented */ 1105d6b55a0fSArnaud Minier case A_AHB1RSTR: 1106d6b55a0fSArnaud Minier s->ahb1rstr = value; 11079c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11089c796d50SArnaud Minier "%s: Side-effects not implemented for AHB1RSTR\n", __func__); 1109d6b55a0fSArnaud Minier break; 1110d6b55a0fSArnaud Minier case A_AHB2RSTR: 1111d6b55a0fSArnaud Minier s->ahb2rstr = value; 11129c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11139c796d50SArnaud Minier "%s: Side-effects not implemented for AHB2RSTR\n", __func__); 1114d6b55a0fSArnaud Minier break; 1115d6b55a0fSArnaud Minier case A_AHB3RSTR: 1116d6b55a0fSArnaud Minier s->ahb3rstr = value; 11179c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11189c796d50SArnaud Minier "%s: Side-effects not implemented for AHB3RSTR\n", __func__); 1119d6b55a0fSArnaud Minier break; 1120d6b55a0fSArnaud Minier case A_APB1RSTR1: 1121d6b55a0fSArnaud Minier s->apb1rstr1 = value; 11229c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11239c796d50SArnaud Minier "%s: Side-effects not implemented for APB1RSTR1\n", __func__); 1124d6b55a0fSArnaud Minier break; 1125d6b55a0fSArnaud Minier case A_APB1RSTR2: 1126d6b55a0fSArnaud Minier s->apb1rstr2 = value; 11279c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11289c796d50SArnaud Minier "%s: Side-effects not implemented for APB1RSTR2\n", __func__); 1129d6b55a0fSArnaud Minier break; 1130d6b55a0fSArnaud Minier case A_APB2RSTR: 1131d6b55a0fSArnaud Minier s->apb2rstr = value; 11329c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11339c796d50SArnaud Minier "%s: Side-effects not implemented for APB2RSTR\n", __func__); 1134d6b55a0fSArnaud Minier break; 1135d6b55a0fSArnaud Minier case A_AHB1ENR: 1136d6b55a0fSArnaud Minier s->ahb1enr = value; 11379c796d50SArnaud Minier rcc_update_ahb1enr(s); 1138d6b55a0fSArnaud Minier break; 1139d6b55a0fSArnaud Minier case A_AHB2ENR: 1140d6b55a0fSArnaud Minier s->ahb2enr = value; 11419c796d50SArnaud Minier rcc_update_ahb2enr(s); 1142d6b55a0fSArnaud Minier break; 1143d6b55a0fSArnaud Minier case A_AHB3ENR: 1144d6b55a0fSArnaud Minier s->ahb3enr = value; 11459c796d50SArnaud Minier rcc_update_ahb3enr(s); 1146d6b55a0fSArnaud Minier break; 1147d6b55a0fSArnaud Minier case A_APB1ENR1: 1148d6b55a0fSArnaud Minier s->apb1enr1 = value; 11499c796d50SArnaud Minier rcc_update_apb1enr(s); 1150d6b55a0fSArnaud Minier break; 1151d6b55a0fSArnaud Minier case A_APB1ENR2: 1152d6b55a0fSArnaud Minier s->apb1enr2 = value; 11539c796d50SArnaud Minier rcc_update_apb1enr(s); 1154d6b55a0fSArnaud Minier break; 1155d6b55a0fSArnaud Minier case A_APB2ENR: 1156d6b55a0fSArnaud Minier s->apb2enr = (s->apb2enr & APB2ENR_READ_SET_MASK) | value; 11579c796d50SArnaud Minier rcc_update_apb2enr(s); 1158d6b55a0fSArnaud Minier break; 1159d6b55a0fSArnaud Minier /* Behaviors for Sleep and Stop modes are not implemented */ 1160d6b55a0fSArnaud Minier case A_AHB1SMENR: 1161d6b55a0fSArnaud Minier s->ahb1smenr = value; 11629c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11639c796d50SArnaud Minier "%s: Side-effects not implemented for AHB1SMENR\n", __func__); 1164d6b55a0fSArnaud Minier break; 1165d6b55a0fSArnaud Minier case A_AHB2SMENR: 1166d6b55a0fSArnaud Minier s->ahb2smenr = value; 11679c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11689c796d50SArnaud Minier "%s: Side-effects not implemented for AHB2SMENR\n", __func__); 1169d6b55a0fSArnaud Minier break; 1170d6b55a0fSArnaud Minier case A_AHB3SMENR: 1171d6b55a0fSArnaud Minier s->ahb3smenr = value; 11729c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11739c796d50SArnaud Minier "%s: Side-effects not implemented for AHB3SMENR\n", __func__); 1174d6b55a0fSArnaud Minier break; 1175d6b55a0fSArnaud Minier case A_APB1SMENR1: 1176d6b55a0fSArnaud Minier s->apb1smenr1 = value; 11779c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11789c796d50SArnaud Minier "%s: Side-effects not implemented for APB1SMENR1\n", __func__); 1179d6b55a0fSArnaud Minier break; 1180d6b55a0fSArnaud Minier case A_APB1SMENR2: 1181d6b55a0fSArnaud Minier s->apb1smenr2 = value; 11829c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11839c796d50SArnaud Minier "%s: Side-effects not implemented for APB1SMENR2\n", __func__); 1184d6b55a0fSArnaud Minier break; 1185d6b55a0fSArnaud Minier case A_APB2SMENR: 1186d6b55a0fSArnaud Minier s->apb2smenr = value; 11879c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11889c796d50SArnaud Minier "%s: Side-effects not implemented for APB2SMENR\n", __func__); 1189d6b55a0fSArnaud Minier break; 1190d6b55a0fSArnaud Minier case A_CCIPR: 1191d6b55a0fSArnaud Minier s->ccipr = value; 11929c796d50SArnaud Minier rcc_update_ccipr(s); 1193d6b55a0fSArnaud Minier break; 1194d6b55a0fSArnaud Minier case A_BDCR: 1195d6b55a0fSArnaud Minier s->bdcr = value & ~BDCR_READ_ONLY_MASK; 11969c796d50SArnaud Minier rcc_update_bdcr(s); 1197d6b55a0fSArnaud Minier break; 1198d6b55a0fSArnaud Minier case A_CSR: 1199d6b55a0fSArnaud Minier s->csr = value & ~CSR_READ_ONLY_MASK; 12009c796d50SArnaud Minier rcc_update_csr(s); 1201d6b55a0fSArnaud Minier break; 1202d6b55a0fSArnaud Minier default: 1203d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 1204d6b55a0fSArnaud Minier "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 1205d6b55a0fSArnaud Minier } 1206d6b55a0fSArnaud Minier } 1207d6b55a0fSArnaud Minier 1208d6b55a0fSArnaud Minier static const MemoryRegionOps stm32l4x5_rcc_ops = { 1209d6b55a0fSArnaud Minier .read = stm32l4x5_rcc_read, 1210d6b55a0fSArnaud Minier .write = stm32l4x5_rcc_write, 1211d6b55a0fSArnaud Minier .endianness = DEVICE_NATIVE_ENDIAN, 1212d6b55a0fSArnaud Minier .valid = { 1213d6b55a0fSArnaud Minier .max_access_size = 4, 1214d6b55a0fSArnaud Minier .min_access_size = 4, 1215d6b55a0fSArnaud Minier .unaligned = false 1216d6b55a0fSArnaud Minier }, 1217d6b55a0fSArnaud Minier .impl = { 1218d6b55a0fSArnaud Minier .max_access_size = 4, 1219d6b55a0fSArnaud Minier .min_access_size = 4, 1220d6b55a0fSArnaud Minier .unaligned = false 1221d6b55a0fSArnaud Minier }, 1222d6b55a0fSArnaud Minier }; 1223d6b55a0fSArnaud Minier 1224d6b55a0fSArnaud Minier static const ClockPortInitArray stm32l4x5_rcc_clocks = { 1225d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, hsi16_rc, NULL, 0), 1226d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, msi_rc, NULL, 0), 1227d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, hse, NULL, 0), 1228d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, lsi_rc, NULL, 0), 1229d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, lse_crystal, NULL, 0), 1230d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, sai1_extclk, NULL, 0), 1231d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0), 1232d6b55a0fSArnaud Minier QDEV_CLOCK_END 1233d6b55a0fSArnaud Minier }; 1234d6b55a0fSArnaud Minier 1235d6b55a0fSArnaud Minier 1236d6b55a0fSArnaud Minier static void stm32l4x5_rcc_init(Object *obj) 1237d6b55a0fSArnaud Minier { 1238d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(obj); 1239ec7d83acSArnaud Minier size_t i; 1240d6b55a0fSArnaud Minier 1241d6b55a0fSArnaud Minier sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 1242d6b55a0fSArnaud Minier 1243d6b55a0fSArnaud Minier memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s, 1244d6b55a0fSArnaud Minier TYPE_STM32L4X5_RCC, 0x400); 1245d6b55a0fSArnaud Minier sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 1246d6b55a0fSArnaud Minier 1247d6b55a0fSArnaud Minier qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); 1248d6b55a0fSArnaud Minier 12496487653eSArnaud Minier for (i = 0; i < RCC_NUM_PLL; i++) { 1250141c29a2SArnaud Minier object_initialize_child(obj, PLL_INIT_INFO[i].name, 12516487653eSArnaud Minier &s->plls[i], TYPE_RCC_PLL); 1252141c29a2SArnaud Minier set_pll_init_info(&s->plls[i], i); 12536487653eSArnaud Minier } 12546487653eSArnaud Minier 1255ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) { 1256141c29a2SArnaud Minier char *alias; 1257ec7d83acSArnaud Minier 1258141c29a2SArnaud Minier object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name, 1259ec7d83acSArnaud Minier &s->clock_muxes[i], 1260ec7d83acSArnaud Minier TYPE_RCC_CLOCK_MUX); 1261141c29a2SArnaud Minier set_clock_mux_init_info(&s->clock_muxes[i], i); 1262ec7d83acSArnaud Minier 1263141c29a2SArnaud Minier if (!CLOCK_MUX_INIT_INFO[i].hidden) { 1264141c29a2SArnaud Minier /* Expose muxes output as RCC outputs */ 1265141c29a2SArnaud Minier alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name); 1266141c29a2SArnaud Minier qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias); 1267141c29a2SArnaud Minier g_free(alias); 1268141c29a2SArnaud Minier } 1269ec7d83acSArnaud Minier } 1270ec7d83acSArnaud Minier 1271d6b55a0fSArnaud Minier s->gnd = clock_new(obj, "gnd"); 1272d6b55a0fSArnaud Minier } 1273d6b55a0fSArnaud Minier 1274141c29a2SArnaud Minier static void connect_mux_sources(Stm32l4x5RccState *s, 1275141c29a2SArnaud Minier RccClockMuxState *mux, 1276141c29a2SArnaud Minier const RccClockMuxSource *clk_mapping) 1277141c29a2SArnaud Minier { 1278141c29a2SArnaud Minier size_t i; 1279141c29a2SArnaud Minier 1280141c29a2SArnaud Minier Clock * const CLK_SRC_MAPPING[] = { 1281141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_GND] = s->gnd, 1282141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSI] = s->hsi16_rc, 1283141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSE] = s->hse, 1284141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_MSI] = s->msi_rc, 1285141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LSI] = s->lsi_rc, 1286141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LSE] = s->lse_crystal, 1287141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SAI1_EXTCLK] = s->sai1_extclk, 1288141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SAI2_EXTCLK] = s->sai2_extclk, 1289141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL] = 1290141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLCLK], 1291141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI1] = 1292141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLSAI1CLK], 1293141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI2] = 1294141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI2].channels[RCC_PLLSAI2_CHANNEL_PLLSAI2CLK], 1295141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI3] = 1296141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLSAI3CLK], 1297141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL48M1] = 1298141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLL48M1CLK], 1299141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL48M2] = 1300141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLL48M2CLK], 1301141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLADC1] = 1302141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLADC1CLK], 1303141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLADC2] = 1304141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI2] .channels[RCC_PLLSAI2_CHANNEL_PLLADC2CLK], 1305141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SYSCLK] = s->clock_muxes[RCC_CLOCK_MUX_SYSCLK].out, 1306141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HCLK] = s->clock_muxes[RCC_CLOCK_MUX_HCLK].out, 1307141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PCLK1] = s->clock_muxes[RCC_CLOCK_MUX_PCLK1].out, 1308141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PCLK2] = s->clock_muxes[RCC_CLOCK_MUX_PCLK2].out, 1309141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSE_OVER_32] = s->clock_muxes[RCC_CLOCK_MUX_HSE_OVER_32].out, 1310141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LCD_AND_RTC_COMMON] = 1311141c29a2SArnaud Minier s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON].out, 1312141c29a2SArnaud Minier }; 1313141c29a2SArnaud Minier 1314141c29a2SArnaud Minier assert(ARRAY_SIZE(CLK_SRC_MAPPING) == RCC_CLOCK_MUX_SRC_NUMBER); 1315141c29a2SArnaud Minier 1316141c29a2SArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { 1317141c29a2SArnaud Minier RccClockMuxSource mapping = clk_mapping[i]; 1318141c29a2SArnaud Minier clock_set_source(mux->srcs[i], CLK_SRC_MAPPING[mapping]); 1319141c29a2SArnaud Minier } 1320141c29a2SArnaud Minier } 1321141c29a2SArnaud Minier 1322141c29a2SArnaud Minier 1323d6b55a0fSArnaud Minier static const VMStateDescription vmstate_stm32l4x5_rcc = { 1324d6b55a0fSArnaud Minier .name = TYPE_STM32L4X5_RCC, 1325d6b55a0fSArnaud Minier .version_id = 1, 1326d6b55a0fSArnaud Minier .minimum_version_id = 1, 1327d6b55a0fSArnaud Minier .fields = (VMStateField[]) { 1328d6b55a0fSArnaud Minier VMSTATE_UINT32(cr, Stm32l4x5RccState), 1329d6b55a0fSArnaud Minier VMSTATE_UINT32(icscr, Stm32l4x5RccState), 1330d6b55a0fSArnaud Minier VMSTATE_UINT32(cfgr, Stm32l4x5RccState), 1331d6b55a0fSArnaud Minier VMSTATE_UINT32(pllcfgr, Stm32l4x5RccState), 1332d6b55a0fSArnaud Minier VMSTATE_UINT32(pllsai1cfgr, Stm32l4x5RccState), 1333d6b55a0fSArnaud Minier VMSTATE_UINT32(pllsai2cfgr, Stm32l4x5RccState), 1334d6b55a0fSArnaud Minier VMSTATE_UINT32(cier, Stm32l4x5RccState), 1335d6b55a0fSArnaud Minier VMSTATE_UINT32(cifr, Stm32l4x5RccState), 1336d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1rstr, Stm32l4x5RccState), 1337d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2rstr, Stm32l4x5RccState), 1338d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3rstr, Stm32l4x5RccState), 1339d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1rstr1, Stm32l4x5RccState), 1340d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1rstr2, Stm32l4x5RccState), 1341d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2rstr, Stm32l4x5RccState), 1342d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1enr, Stm32l4x5RccState), 1343d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2enr, Stm32l4x5RccState), 1344d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3enr, Stm32l4x5RccState), 1345d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1enr1, Stm32l4x5RccState), 1346d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1enr2, Stm32l4x5RccState), 1347d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2enr, Stm32l4x5RccState), 1348d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1smenr, Stm32l4x5RccState), 1349d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2smenr, Stm32l4x5RccState), 1350d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3smenr, Stm32l4x5RccState), 1351d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1smenr1, Stm32l4x5RccState), 1352d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1smenr2, Stm32l4x5RccState), 1353d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2smenr, Stm32l4x5RccState), 1354d6b55a0fSArnaud Minier VMSTATE_UINT32(ccipr, Stm32l4x5RccState), 1355d6b55a0fSArnaud Minier VMSTATE_UINT32(bdcr, Stm32l4x5RccState), 1356d6b55a0fSArnaud Minier VMSTATE_UINT32(csr, Stm32l4x5RccState), 1357d6b55a0fSArnaud Minier VMSTATE_CLOCK(hsi16_rc, Stm32l4x5RccState), 1358d6b55a0fSArnaud Minier VMSTATE_CLOCK(msi_rc, Stm32l4x5RccState), 1359d6b55a0fSArnaud Minier VMSTATE_CLOCK(hse, Stm32l4x5RccState), 1360d6b55a0fSArnaud Minier VMSTATE_CLOCK(lsi_rc, Stm32l4x5RccState), 1361d6b55a0fSArnaud Minier VMSTATE_CLOCK(lse_crystal, Stm32l4x5RccState), 1362d6b55a0fSArnaud Minier VMSTATE_CLOCK(sai1_extclk, Stm32l4x5RccState), 1363d6b55a0fSArnaud Minier VMSTATE_CLOCK(sai2_extclk, Stm32l4x5RccState), 1364d6b55a0fSArnaud Minier VMSTATE_END_OF_LIST() 1365d6b55a0fSArnaud Minier } 1366d6b55a0fSArnaud Minier }; 1367d6b55a0fSArnaud Minier 1368d6b55a0fSArnaud Minier 1369d6b55a0fSArnaud Minier static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp) 1370d6b55a0fSArnaud Minier { 1371d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(dev); 1372ec7d83acSArnaud Minier size_t i; 1373d6b55a0fSArnaud Minier 1374d6b55a0fSArnaud Minier if (s->hse_frequency < 4000000ULL || 1375d6b55a0fSArnaud Minier s->hse_frequency > 48000000ULL) { 1376d6b55a0fSArnaud Minier error_setg(errp, 1377d6b55a0fSArnaud Minier "HSE frequency is outside of the allowed [4-48]Mhz range: %" PRIx64 "", 1378d6b55a0fSArnaud Minier s->hse_frequency); 1379d6b55a0fSArnaud Minier return; 1380d6b55a0fSArnaud Minier } 1381d6b55a0fSArnaud Minier 13826487653eSArnaud Minier for (i = 0; i < RCC_NUM_PLL; i++) { 13836487653eSArnaud Minier RccPllState *pll = &s->plls[i]; 13846487653eSArnaud Minier 13856487653eSArnaud Minier clock_set_source(pll->in, s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].out); 13866487653eSArnaud Minier 13876487653eSArnaud Minier if (!qdev_realize(DEVICE(pll), NULL, errp)) { 13886487653eSArnaud Minier return; 13896487653eSArnaud Minier } 13906487653eSArnaud Minier } 13916487653eSArnaud Minier 1392ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) { 1393ec7d83acSArnaud Minier RccClockMuxState *clock_mux = &s->clock_muxes[i]; 1394ec7d83acSArnaud Minier 1395141c29a2SArnaud Minier connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping); 1396141c29a2SArnaud Minier 1397ec7d83acSArnaud Minier if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) { 1398ec7d83acSArnaud Minier return; 1399ec7d83acSArnaud Minier } 1400ec7d83acSArnaud Minier } 1401ec7d83acSArnaud Minier 1402141c29a2SArnaud Minier /* 1403141c29a2SArnaud Minier * Start clocks after everything is connected 1404141c29a2SArnaud Minier * to propagate the frequencies along the tree. 1405141c29a2SArnaud Minier */ 1406d6b55a0fSArnaud Minier clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); 1407d6b55a0fSArnaud Minier clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); 1408d6b55a0fSArnaud Minier clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); 1409d6b55a0fSArnaud Minier clock_update(s->gnd, 0); 1410d6b55a0fSArnaud Minier } 1411d6b55a0fSArnaud Minier 1412d6b55a0fSArnaud Minier static Property stm32l4x5_rcc_properties[] = { 1413d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState, 1414d6b55a0fSArnaud Minier hse_frequency, HSE_DEFAULT_FRQ), 1415d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState, 1416d6b55a0fSArnaud Minier sai1_extclk_frequency, 0), 1417d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState, 1418d6b55a0fSArnaud Minier sai2_extclk_frequency, 0), 1419d6b55a0fSArnaud Minier DEFINE_PROP_END_OF_LIST(), 1420d6b55a0fSArnaud Minier }; 1421d6b55a0fSArnaud Minier 1422d6b55a0fSArnaud Minier static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data) 1423d6b55a0fSArnaud Minier { 1424d6b55a0fSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 1425d6b55a0fSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 1426d6b55a0fSArnaud Minier 1427141c29a2SArnaud Minier assert(ARRAY_SIZE(CLOCK_MUX_INIT_INFO) == RCC_NUM_CLOCK_MUX); 1428d6b55a0fSArnaud Minier 1429d6b55a0fSArnaud Minier rc->phases.hold = stm32l4x5_rcc_reset_hold; 1430d6b55a0fSArnaud Minier device_class_set_props(dc, stm32l4x5_rcc_properties); 1431d6b55a0fSArnaud Minier dc->realize = stm32l4x5_rcc_realize; 1432d6b55a0fSArnaud Minier dc->vmsd = &vmstate_stm32l4x5_rcc; 1433d6b55a0fSArnaud Minier } 1434d6b55a0fSArnaud Minier 1435d6b55a0fSArnaud Minier static const TypeInfo stm32l4x5_rcc_types[] = { 1436d6b55a0fSArnaud Minier { 1437d6b55a0fSArnaud Minier .name = TYPE_STM32L4X5_RCC, 1438d6b55a0fSArnaud Minier .parent = TYPE_SYS_BUS_DEVICE, 1439d6b55a0fSArnaud Minier .instance_size = sizeof(Stm32l4x5RccState), 1440d6b55a0fSArnaud Minier .instance_init = stm32l4x5_rcc_init, 1441d6b55a0fSArnaud Minier .class_init = stm32l4x5_rcc_class_init, 1442ec7d83acSArnaud Minier }, { 1443ec7d83acSArnaud Minier .name = TYPE_RCC_CLOCK_MUX, 1444ec7d83acSArnaud Minier .parent = TYPE_DEVICE, 1445ec7d83acSArnaud Minier .instance_size = sizeof(RccClockMuxState), 1446ec7d83acSArnaud Minier .instance_init = clock_mux_init, 1447ec7d83acSArnaud Minier .class_init = clock_mux_class_init, 14486487653eSArnaud Minier }, { 14496487653eSArnaud Minier .name = TYPE_RCC_PLL, 14506487653eSArnaud Minier .parent = TYPE_DEVICE, 14516487653eSArnaud Minier .instance_size = sizeof(RccPllState), 14526487653eSArnaud Minier .instance_init = pll_init, 14536487653eSArnaud Minier .class_init = pll_class_init, 1454d6b55a0fSArnaud Minier } 1455d6b55a0fSArnaud Minier }; 1456d6b55a0fSArnaud Minier 1457d6b55a0fSArnaud Minier DEFINE_TYPES(stm32l4x5_rcc_types) 1458