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; 511f439706SPhilippe Mathieu-Daudé bool clk_changed = false; 521f439706SPhilippe Mathieu-Daudé 53ec7d83acSArnaud Minier /* 54ec7d83acSArnaud Minier * To avoid rounding errors, we use the clock period instead of the 55ec7d83acSArnaud Minier * frequency. 56ec7d83acSArnaud Minier * This means that the multiplier of the mux becomes the divider of 57ec7d83acSArnaud Minier * the clock and the divider of the mux becomes the multiplier of the 58ec7d83acSArnaud Minier * clock. 59ec7d83acSArnaud Minier */ 60141c29a2SArnaud Minier if (!bypass_source && mux->enabled && mux->divider) { 61ec7d83acSArnaud Minier freq_multiplier = mux->divider; 62ec7d83acSArnaud Minier } 63ec7d83acSArnaud Minier 64*32da7e20SArnaud Minier clk_changed |= clock_set_mul_div(mux->out, freq_multiplier, mux->multiplier); 651f439706SPhilippe Mathieu-Daudé clk_changed |= clock_set(mux->out, clock_get(current_source)); 661f439706SPhilippe Mathieu-Daudé if (clk_changed) { 671f439706SPhilippe Mathieu-Daudé clock_propagate(mux->out); 681f439706SPhilippe Mathieu-Daudé } 69ec7d83acSArnaud Minier 70ec7d83acSArnaud Minier src_freq = clock_get_hz(current_source); 71ec7d83acSArnaud Minier /* TODO: can we simply detect if the config changed so that we reduce log spam ? */ 72ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_update(mux->id, mux->src, src_freq, 73ec7d83acSArnaud Minier mux->multiplier, mux->divider); 74ec7d83acSArnaud Minier } 75ec7d83acSArnaud Minier 76ec7d83acSArnaud Minier static void clock_mux_src_update(void *opaque, ClockEvent event) 77ec7d83acSArnaud Minier { 78ec7d83acSArnaud Minier RccClockMuxState **backref = opaque; 79ec7d83acSArnaud Minier RccClockMuxState *s = *backref; 80ec7d83acSArnaud Minier /* 81ec7d83acSArnaud Minier * The backref value is equal to: 82ec7d83acSArnaud Minier * s->backref + (sizeof(RccClockMuxState *) * update_src). 83ec7d83acSArnaud Minier * By subtracting we can get back the index of the updated clock. 84ec7d83acSArnaud Minier */ 85ec7d83acSArnaud Minier const uint32_t update_src = backref - s->backref; 86ec7d83acSArnaud Minier /* Only update if the clock that was updated is the current source */ 87ec7d83acSArnaud Minier if (update_src == s->src) { 88141c29a2SArnaud Minier clock_mux_update(s, false); 89ec7d83acSArnaud Minier } 90ec7d83acSArnaud Minier } 91ec7d83acSArnaud Minier 92ec7d83acSArnaud Minier static void clock_mux_init(Object *obj) 93ec7d83acSArnaud Minier { 94ec7d83acSArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 95ec7d83acSArnaud Minier size_t i; 96ec7d83acSArnaud Minier 97ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { 98ec7d83acSArnaud Minier char *name = g_strdup_printf("srcs[%zu]", i); 99ec7d83acSArnaud Minier s->backref[i] = s; 100ec7d83acSArnaud Minier s->srcs[i] = qdev_init_clock_in(DEVICE(s), name, 101ec7d83acSArnaud Minier clock_mux_src_update, 102ec7d83acSArnaud Minier &s->backref[i], 103ec7d83acSArnaud Minier ClockUpdate); 104ec7d83acSArnaud Minier g_free(name); 105ec7d83acSArnaud Minier } 106ec7d83acSArnaud Minier 107ec7d83acSArnaud Minier s->out = qdev_init_clock_out(DEVICE(s), "out"); 108ec7d83acSArnaud Minier } 109ec7d83acSArnaud Minier 110141c29a2SArnaud Minier static void clock_mux_reset_enter(Object *obj, ResetType type) 111141c29a2SArnaud Minier { 112141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 113141c29a2SArnaud Minier set_clock_mux_init_info(s, s->id); 114141c29a2SArnaud Minier } 115141c29a2SArnaud Minier 116ec7d83acSArnaud Minier static void clock_mux_reset_hold(Object *obj) 117141c29a2SArnaud Minier { 118141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 119141c29a2SArnaud Minier clock_mux_update(s, true); 120141c29a2SArnaud Minier } 121141c29a2SArnaud Minier 122141c29a2SArnaud Minier static void clock_mux_reset_exit(Object *obj) 123141c29a2SArnaud Minier { 124141c29a2SArnaud Minier RccClockMuxState *s = RCC_CLOCK_MUX(obj); 125141c29a2SArnaud Minier clock_mux_update(s, false); 126141c29a2SArnaud Minier } 127ec7d83acSArnaud Minier 128ec7d83acSArnaud Minier static const VMStateDescription clock_mux_vmstate = { 129ec7d83acSArnaud Minier .name = TYPE_RCC_CLOCK_MUX, 130ec7d83acSArnaud Minier .version_id = 1, 131ec7d83acSArnaud Minier .minimum_version_id = 1, 132ec7d83acSArnaud Minier .fields = (VMStateField[]) { 133ec7d83acSArnaud Minier VMSTATE_UINT32(id, RccClockMuxState), 134ec7d83acSArnaud Minier VMSTATE_ARRAY_CLOCK(srcs, RccClockMuxState, 135ec7d83acSArnaud Minier RCC_NUM_CLOCK_MUX_SRC), 136ec7d83acSArnaud Minier VMSTATE_BOOL(enabled, RccClockMuxState), 137ec7d83acSArnaud Minier VMSTATE_UINT32(src, RccClockMuxState), 138ec7d83acSArnaud Minier VMSTATE_UINT32(multiplier, RccClockMuxState), 139ec7d83acSArnaud Minier VMSTATE_UINT32(divider, RccClockMuxState), 140ec7d83acSArnaud Minier VMSTATE_END_OF_LIST() 141ec7d83acSArnaud Minier } 142ec7d83acSArnaud Minier }; 143ec7d83acSArnaud Minier 144ec7d83acSArnaud Minier static void clock_mux_class_init(ObjectClass *klass, void *data) 145ec7d83acSArnaud Minier { 146ec7d83acSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 147ec7d83acSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 148ec7d83acSArnaud Minier 149141c29a2SArnaud Minier rc->phases.enter = clock_mux_reset_enter; 150ec7d83acSArnaud Minier rc->phases.hold = clock_mux_reset_hold; 151141c29a2SArnaud Minier rc->phases.exit = clock_mux_reset_exit; 152ec7d83acSArnaud Minier dc->vmsd = &clock_mux_vmstate; 153ec7d83acSArnaud Minier } 154ec7d83acSArnaud Minier 155ec7d83acSArnaud Minier static void clock_mux_set_enable(RccClockMuxState *mux, bool enabled) 156ec7d83acSArnaud Minier { 157ec7d83acSArnaud Minier if (mux->enabled == enabled) { 158ec7d83acSArnaud Minier return; 159ec7d83acSArnaud Minier } 160ec7d83acSArnaud Minier 161ec7d83acSArnaud Minier if (enabled) { 162ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_enable(mux->id); 163ec7d83acSArnaud Minier } else { 164ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_disable(mux->id); 165ec7d83acSArnaud Minier } 166ec7d83acSArnaud Minier 167ec7d83acSArnaud Minier mux->enabled = enabled; 168141c29a2SArnaud Minier clock_mux_update(mux, false); 169ec7d83acSArnaud Minier } 170ec7d83acSArnaud Minier 171ec7d83acSArnaud Minier static void clock_mux_set_factor(RccClockMuxState *mux, 172ec7d83acSArnaud Minier uint32_t multiplier, uint32_t divider) 173ec7d83acSArnaud Minier { 174ec7d83acSArnaud Minier if (mux->multiplier == multiplier && mux->divider == divider) { 175ec7d83acSArnaud Minier return; 176ec7d83acSArnaud Minier } 177ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_set_factor(mux->id, 178ec7d83acSArnaud Minier mux->multiplier, multiplier, mux->divider, divider); 179ec7d83acSArnaud Minier 180ec7d83acSArnaud Minier mux->multiplier = multiplier; 181ec7d83acSArnaud Minier mux->divider = divider; 182141c29a2SArnaud Minier clock_mux_update(mux, false); 183ec7d83acSArnaud Minier } 184ec7d83acSArnaud Minier 185ec7d83acSArnaud Minier static void clock_mux_set_source(RccClockMuxState *mux, RccClockMuxSource src) 186ec7d83acSArnaud Minier { 187ec7d83acSArnaud Minier if (mux->src == src) { 188ec7d83acSArnaud Minier return; 189ec7d83acSArnaud Minier } 190ec7d83acSArnaud Minier 191ec7d83acSArnaud Minier trace_stm32l4x5_rcc_mux_set_src(mux->id, mux->src, src); 192ec7d83acSArnaud Minier mux->src = src; 193141c29a2SArnaud Minier clock_mux_update(mux, false); 194ec7d83acSArnaud Minier } 195ec7d83acSArnaud Minier 196141c29a2SArnaud Minier /* 197141c29a2SArnaud Minier * Acknowledge and propagate changes in a PLL frequency. 198141c29a2SArnaud Minier * `bypass_source` allows to bypass the period of the current source and just 199141c29a2SArnaud Minier * consider it equal to 0. This is useful during the hold phase of reset. 200141c29a2SArnaud Minier */ 201141c29a2SArnaud Minier static void pll_update(RccPllState *pll, bool bypass_source) 2026487653eSArnaud Minier { 2036487653eSArnaud Minier uint64_t vco_freq, old_channel_freq, channel_freq; 2046487653eSArnaud Minier int i; 2056487653eSArnaud Minier 2066487653eSArnaud Minier /* The common PLLM factor is handled by the PLL mux */ 2076487653eSArnaud Minier vco_freq = muldiv64(clock_get_hz(pll->in), pll->vco_multiplier, 1); 2086487653eSArnaud Minier 2096487653eSArnaud Minier for (i = 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { 2106487653eSArnaud Minier if (!pll->channel_exists[i]) { 2116487653eSArnaud Minier continue; 2126487653eSArnaud Minier } 2136487653eSArnaud Minier 2146487653eSArnaud Minier old_channel_freq = clock_get_hz(pll->channels[i]); 215141c29a2SArnaud Minier if (bypass_source || 216141c29a2SArnaud Minier !pll->enabled || 2176487653eSArnaud Minier !pll->channel_enabled[i] || 2186487653eSArnaud Minier !pll->channel_divider[i]) { 2196487653eSArnaud Minier channel_freq = 0; 2206487653eSArnaud Minier } else { 2216487653eSArnaud Minier channel_freq = muldiv64(vco_freq, 2226487653eSArnaud Minier 1, 2236487653eSArnaud Minier pll->channel_divider[i]); 2246487653eSArnaud Minier } 2256487653eSArnaud Minier 2266487653eSArnaud Minier /* No change, early continue to avoid log spam and useless propagation */ 2276487653eSArnaud Minier if (old_channel_freq == channel_freq) { 2286487653eSArnaud Minier continue; 2296487653eSArnaud Minier } 2306487653eSArnaud Minier 2316487653eSArnaud Minier clock_update_hz(pll->channels[i], channel_freq); 2326487653eSArnaud Minier trace_stm32l4x5_rcc_pll_update(pll->id, i, vco_freq, 2336487653eSArnaud Minier old_channel_freq, channel_freq); 2346487653eSArnaud Minier } 2356487653eSArnaud Minier } 2366487653eSArnaud Minier 2376487653eSArnaud Minier static void pll_src_update(void *opaque, ClockEvent event) 2386487653eSArnaud Minier { 2396487653eSArnaud Minier RccPllState *s = opaque; 240141c29a2SArnaud Minier pll_update(s, false); 2416487653eSArnaud Minier } 2426487653eSArnaud Minier 2436487653eSArnaud Minier static void pll_init(Object *obj) 2446487653eSArnaud Minier { 2456487653eSArnaud Minier RccPllState *s = RCC_PLL(obj); 2466487653eSArnaud Minier size_t i; 2476487653eSArnaud Minier 2486487653eSArnaud Minier s->in = qdev_init_clock_in(DEVICE(s), "in", 2496487653eSArnaud Minier pll_src_update, s, ClockUpdate); 2506487653eSArnaud Minier 2516487653eSArnaud Minier const char *names[] = { 2526487653eSArnaud Minier "out-p", "out-q", "out-r", 2536487653eSArnaud Minier }; 2546487653eSArnaud Minier 2556487653eSArnaud Minier for (i = 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { 2566487653eSArnaud Minier s->channels[i] = qdev_init_clock_out(DEVICE(s), names[i]); 2576487653eSArnaud Minier } 2586487653eSArnaud Minier } 2596487653eSArnaud Minier 260141c29a2SArnaud Minier static void pll_reset_enter(Object *obj, ResetType type) 261141c29a2SArnaud Minier { 262141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 263141c29a2SArnaud Minier set_pll_init_info(s, s->id); 264141c29a2SArnaud Minier } 265141c29a2SArnaud Minier 2666487653eSArnaud Minier static void pll_reset_hold(Object *obj) 267141c29a2SArnaud Minier { 268141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 269141c29a2SArnaud Minier pll_update(s, true); 270141c29a2SArnaud Minier } 271141c29a2SArnaud Minier 272141c29a2SArnaud Minier static void pll_reset_exit(Object *obj) 273141c29a2SArnaud Minier { 274141c29a2SArnaud Minier RccPllState *s = RCC_PLL(obj); 275141c29a2SArnaud Minier pll_update(s, false); 276141c29a2SArnaud Minier } 2776487653eSArnaud Minier 2786487653eSArnaud Minier static const VMStateDescription pll_vmstate = { 2796487653eSArnaud Minier .name = TYPE_RCC_PLL, 2806487653eSArnaud Minier .version_id = 1, 2816487653eSArnaud Minier .minimum_version_id = 1, 2826487653eSArnaud Minier .fields = (VMStateField[]) { 2836487653eSArnaud Minier VMSTATE_UINT32(id, RccPllState), 2846487653eSArnaud Minier VMSTATE_CLOCK(in, RccPllState), 2856487653eSArnaud Minier VMSTATE_ARRAY_CLOCK(channels, RccPllState, 2866487653eSArnaud Minier RCC_NUM_CHANNEL_PLL_OUT), 2876487653eSArnaud Minier VMSTATE_BOOL(enabled, RccPllState), 2886487653eSArnaud Minier VMSTATE_UINT32(vco_multiplier, RccPllState), 2896487653eSArnaud Minier VMSTATE_BOOL_ARRAY(channel_enabled, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2906487653eSArnaud Minier VMSTATE_BOOL_ARRAY(channel_exists, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2916487653eSArnaud Minier VMSTATE_UINT32_ARRAY(channel_divider, RccPllState, RCC_NUM_CHANNEL_PLL_OUT), 2926487653eSArnaud Minier VMSTATE_END_OF_LIST() 2936487653eSArnaud Minier } 2946487653eSArnaud Minier }; 2956487653eSArnaud Minier 2966487653eSArnaud Minier static void pll_class_init(ObjectClass *klass, void *data) 2976487653eSArnaud Minier { 2986487653eSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 2996487653eSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 3006487653eSArnaud Minier 301141c29a2SArnaud Minier rc->phases.enter = pll_reset_enter; 3026487653eSArnaud Minier rc->phases.hold = pll_reset_hold; 303141c29a2SArnaud Minier rc->phases.exit = pll_reset_exit; 3046487653eSArnaud Minier dc->vmsd = &pll_vmstate; 3056487653eSArnaud Minier } 3066487653eSArnaud Minier 3076487653eSArnaud Minier static void pll_set_vco_multiplier(RccPllState *pll, uint32_t vco_multiplier) 3086487653eSArnaud Minier { 3096487653eSArnaud Minier if (pll->vco_multiplier == vco_multiplier) { 3106487653eSArnaud Minier return; 3116487653eSArnaud Minier } 3126487653eSArnaud Minier 3136487653eSArnaud Minier if (vco_multiplier < 8 || vco_multiplier > 86) { 3146487653eSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 3156487653eSArnaud Minier "%s: VCO multiplier is out of bound (%u) for PLL %u\n", 3166487653eSArnaud Minier __func__, vco_multiplier, pll->id); 3176487653eSArnaud Minier return; 3186487653eSArnaud Minier } 3196487653eSArnaud Minier 3206487653eSArnaud Minier trace_stm32l4x5_rcc_pll_set_vco_multiplier(pll->id, 3216487653eSArnaud Minier pll->vco_multiplier, vco_multiplier); 3226487653eSArnaud Minier 3236487653eSArnaud Minier pll->vco_multiplier = vco_multiplier; 324141c29a2SArnaud Minier pll_update(pll, false); 3256487653eSArnaud Minier } 3266487653eSArnaud Minier 3276487653eSArnaud Minier static void pll_set_enable(RccPllState *pll, bool enabled) 3286487653eSArnaud Minier { 3296487653eSArnaud Minier if (pll->enabled == enabled) { 3306487653eSArnaud Minier return; 3316487653eSArnaud Minier } 3326487653eSArnaud Minier 3336487653eSArnaud Minier pll->enabled = enabled; 334141c29a2SArnaud Minier pll_update(pll, false); 3356487653eSArnaud Minier } 3366487653eSArnaud Minier 3376487653eSArnaud Minier static void pll_set_channel_enable(RccPllState *pll, 3386487653eSArnaud Minier PllCommonChannels channel, 3396487653eSArnaud Minier bool enabled) 3406487653eSArnaud Minier { 3416487653eSArnaud Minier if (pll->channel_enabled[channel] == enabled) { 3426487653eSArnaud Minier return; 3436487653eSArnaud Minier } 3446487653eSArnaud Minier 3456487653eSArnaud Minier if (enabled) { 3466487653eSArnaud Minier trace_stm32l4x5_rcc_pll_channel_enable(pll->id, channel); 3476487653eSArnaud Minier } else { 3486487653eSArnaud Minier trace_stm32l4x5_rcc_pll_channel_disable(pll->id, channel); 3496487653eSArnaud Minier } 3506487653eSArnaud Minier 3516487653eSArnaud Minier pll->channel_enabled[channel] = enabled; 352141c29a2SArnaud Minier pll_update(pll, false); 3536487653eSArnaud Minier } 3546487653eSArnaud Minier 3556487653eSArnaud Minier static void pll_set_channel_divider(RccPllState *pll, 3566487653eSArnaud Minier PllCommonChannels channel, 3576487653eSArnaud Minier uint32_t divider) 3586487653eSArnaud Minier { 3596487653eSArnaud Minier if (pll->channel_divider[channel] == divider) { 3606487653eSArnaud Minier return; 3616487653eSArnaud Minier } 3626487653eSArnaud Minier 3636487653eSArnaud Minier trace_stm32l4x5_rcc_pll_set_channel_divider(pll->id, 3646487653eSArnaud Minier channel, pll->channel_divider[channel], divider); 3656487653eSArnaud Minier 3666487653eSArnaud Minier pll->channel_divider[channel] = divider; 367141c29a2SArnaud Minier pll_update(pll, false); 3686487653eSArnaud Minier } 3696487653eSArnaud Minier 370d6b55a0fSArnaud Minier static void rcc_update_irq(Stm32l4x5RccState *s) 371d6b55a0fSArnaud Minier { 3729c796d50SArnaud Minier /* 3739c796d50SArnaud Minier * TODO: Handle LSECSSF and CSSF flags when the CSS is implemented. 3749c796d50SArnaud Minier */ 375d6b55a0fSArnaud Minier if (s->cifr & CIFR_IRQ_MASK) { 376d6b55a0fSArnaud Minier qemu_irq_raise(s->irq); 377d6b55a0fSArnaud Minier } else { 378d6b55a0fSArnaud Minier qemu_irq_lower(s->irq); 379d6b55a0fSArnaud Minier } 380d6b55a0fSArnaud Minier } 381d6b55a0fSArnaud Minier 3823b551477SArnaud Minier static void rcc_update_msi(Stm32l4x5RccState *s, uint32_t previous_value) 3833b551477SArnaud Minier { 3843b551477SArnaud Minier uint32_t val; 3853b551477SArnaud Minier 3863b551477SArnaud Minier static const uint32_t msirange[] = { 3873b551477SArnaud Minier 100000, 200000, 400000, 800000, 1000000, 2000000, 3883b551477SArnaud Minier 4000000, 8000000, 16000000, 24000000, 32000000, 48000000 3893b551477SArnaud Minier }; 3903b551477SArnaud Minier /* MSIRANGE and MSIRGSEL */ 3913b551477SArnaud Minier val = extract32(s->cr, R_CR_MSIRGSEL_SHIFT, R_CR_MSIRGSEL_LENGTH); 3923b551477SArnaud Minier if (val) { 3933b551477SArnaud Minier /* MSIRGSEL is set, use the MSIRANGE field */ 3943b551477SArnaud Minier val = extract32(s->cr, R_CR_MSIRANGE_SHIFT, R_CR_MSIRANGE_LENGTH); 3953b551477SArnaud Minier } else { 3963b551477SArnaud Minier /* MSIRGSEL is not set, use the MSISRANGE field */ 3973b551477SArnaud Minier val = extract32(s->csr, R_CSR_MSISRANGE_SHIFT, R_CSR_MSISRANGE_LENGTH); 3983b551477SArnaud Minier } 3993b551477SArnaud Minier 4003b551477SArnaud Minier if (val < ARRAY_SIZE(msirange)) { 4013b551477SArnaud Minier clock_update_hz(s->msi_rc, msirange[val]); 4023b551477SArnaud Minier } else { 4033b551477SArnaud Minier /* 4043b551477SArnaud Minier * There is a hardware write protection if the value is out of bound. 4053b551477SArnaud Minier * Restore the previous value. 4063b551477SArnaud Minier */ 4073b551477SArnaud Minier s->cr = (s->cr & ~R_CSR_MSISRANGE_MASK) | 4083b551477SArnaud Minier (previous_value & R_CSR_MSISRANGE_MASK); 4093b551477SArnaud Minier } 4103b551477SArnaud Minier } 4113b551477SArnaud Minier 4123b551477SArnaud Minier /* 4133b551477SArnaud Minier * TODO: Add write-protection for all registers: 4143b551477SArnaud Minier * DONE: CR 4153b551477SArnaud Minier */ 4163b551477SArnaud Minier 4173b551477SArnaud Minier static void rcc_update_cr_register(Stm32l4x5RccState *s, uint32_t previous_value) 4189c796d50SArnaud Minier { 4199c796d50SArnaud Minier int val; 4203b551477SArnaud Minier const RccClockMuxSource current_pll_src = 4213b551477SArnaud Minier CLOCK_MUX_INIT_INFO[RCC_CLOCK_MUX_PLL_INPUT].src_mapping[ 4223b551477SArnaud Minier s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].src]; 4239c796d50SArnaud Minier 4249c796d50SArnaud Minier /* PLLSAI2ON and update PLLSAI2RDY */ 4259c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, PLLSAI2ON); 4269c796d50SArnaud Minier pll_set_enable(&s->plls[RCC_PLL_PLLSAI2], val); 4279c796d50SArnaud Minier s->cr = (s->cr & ~R_CR_PLLSAI2RDY_MASK) | 4289c796d50SArnaud Minier (val << R_CR_PLLSAI2RDY_SHIFT); 4299c796d50SArnaud Minier if (s->cier & R_CIER_PLLSAI2RDYIE_MASK) { 4309c796d50SArnaud Minier s->cifr |= R_CIFR_PLLSAI2RDYF_MASK; 4319c796d50SArnaud Minier } 4329c796d50SArnaud Minier 4339c796d50SArnaud Minier /* PLLSAI1ON and update PLLSAI1RDY */ 4349c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, PLLSAI1ON); 4359c796d50SArnaud Minier pll_set_enable(&s->plls[RCC_PLL_PLLSAI1], val); 4369c796d50SArnaud Minier s->cr = (s->cr & ~R_CR_PLLSAI1RDY_MASK) | 4379c796d50SArnaud Minier (val << R_CR_PLLSAI1RDY_SHIFT); 4389c796d50SArnaud Minier if (s->cier & R_CIER_PLLSAI1RDYIE_MASK) { 4399c796d50SArnaud Minier s->cifr |= R_CIFR_PLLSAI1RDYF_MASK; 4409c796d50SArnaud Minier } 4419c796d50SArnaud Minier 4423b551477SArnaud Minier /* 4433b551477SArnaud Minier * PLLON and update PLLRDY 4443b551477SArnaud Minier * PLLON cannot be reset if the PLL clock is used as the system clock. 4453b551477SArnaud Minier */ 4469c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, PLLON); 4473b551477SArnaud Minier if (FIELD_EX32(s->cfgr, CFGR, SWS) != 0b11) { 4489c796d50SArnaud Minier pll_set_enable(&s->plls[RCC_PLL_PLL], val); 4499c796d50SArnaud Minier s->cr = (s->cr & ~R_CR_PLLRDY_MASK) | 4509c796d50SArnaud Minier (val << R_CR_PLLRDY_SHIFT); 4519c796d50SArnaud Minier if (s->cier & R_CIER_PLLRDYIE_MASK) { 4529c796d50SArnaud Minier s->cifr |= R_CIFR_PLLRDYF_MASK; 4539c796d50SArnaud Minier } 4543b551477SArnaud Minier } else { 4553b551477SArnaud Minier s->cr |= R_CR_PLLON_MASK; 4563b551477SArnaud Minier } 4579c796d50SArnaud Minier 4589c796d50SArnaud Minier /* CSSON: TODO */ 4599c796d50SArnaud Minier /* HSEBYP: TODO */ 4609c796d50SArnaud Minier 4613b551477SArnaud Minier /* 4623b551477SArnaud Minier * HSEON and update HSERDY. 4633b551477SArnaud Minier * HSEON cannot be reset if the HSE oscillator is used directly or 4643b551477SArnaud Minier * indirectly as the system clock. 4653b551477SArnaud Minier */ 4669c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, HSEON); 4673b551477SArnaud Minier if (FIELD_EX32(s->cfgr, CFGR, SWS) != 0b10 && 4683b551477SArnaud Minier current_pll_src != RCC_CLOCK_MUX_SRC_HSE) { 4699c796d50SArnaud Minier s->cr = (s->cr & ~R_CR_HSERDY_MASK) | 4709c796d50SArnaud Minier (val << R_CR_HSERDY_SHIFT); 4719c796d50SArnaud Minier if (val) { 4729c796d50SArnaud Minier clock_update_hz(s->hse, s->hse_frequency); 4739c796d50SArnaud Minier if (s->cier & R_CIER_HSERDYIE_MASK) { 4749c796d50SArnaud Minier s->cifr |= R_CIFR_HSERDYF_MASK; 4759c796d50SArnaud Minier } 4769c796d50SArnaud Minier } else { 4779c796d50SArnaud Minier clock_update(s->hse, 0); 4789c796d50SArnaud Minier } 4793b551477SArnaud Minier } else { 4803b551477SArnaud Minier s->cr |= R_CR_HSEON_MASK; 4813b551477SArnaud Minier } 4829c796d50SArnaud Minier 4839c796d50SArnaud Minier /* HSIAFS: TODO*/ 4849c796d50SArnaud Minier /* HSIKERON: TODO*/ 4859c796d50SArnaud Minier 4863b551477SArnaud Minier /* 4873b551477SArnaud Minier * HSION and update HSIRDY 4883b551477SArnaud Minier * HSION is set by hardware if the HSI16 is used directly 4893b551477SArnaud Minier * or indirectly as system clock. 4903b551477SArnaud Minier */ 4913b551477SArnaud Minier if (FIELD_EX32(s->cfgr, CFGR, SWS) == 0b01 || 4923b551477SArnaud Minier current_pll_src == RCC_CLOCK_MUX_SRC_HSI) { 4933b551477SArnaud Minier s->cr |= (R_CR_HSION_MASK | R_CR_HSIRDY_MASK); 4949c796d50SArnaud Minier clock_update_hz(s->hsi16_rc, HSI_FRQ); 4959c796d50SArnaud Minier if (s->cier & R_CIER_HSIRDYIE_MASK) { 4969c796d50SArnaud Minier s->cifr |= R_CIFR_HSIRDYF_MASK; 4979c796d50SArnaud Minier } 4989c796d50SArnaud Minier } else { 4993b551477SArnaud Minier val = FIELD_EX32(s->cr, CR, HSION); 5009c796d50SArnaud Minier if (val) { 5013b551477SArnaud Minier clock_update_hz(s->hsi16_rc, HSI_FRQ); 5023b551477SArnaud Minier s->cr |= R_CR_HSIRDY_MASK; 5033b551477SArnaud Minier if (s->cier & R_CIER_HSIRDYIE_MASK) { 5043b551477SArnaud Minier s->cifr |= R_CIFR_HSIRDYF_MASK; 5053b551477SArnaud Minier } 5069c796d50SArnaud Minier } else { 5073b551477SArnaud Minier clock_update(s->hsi16_rc, 0); 5083b551477SArnaud Minier s->cr &= ~R_CR_HSIRDY_MASK; 5093b551477SArnaud Minier } 5109c796d50SArnaud Minier } 5119c796d50SArnaud Minier 5123b551477SArnaud Minier /* MSIPLLEN: TODO */ 5133b551477SArnaud Minier 5143b551477SArnaud Minier /* 5153b551477SArnaud Minier * MSION and update MSIRDY 5163b551477SArnaud Minier * Set by hardware when used directly or indirectly as system clock. 5173b551477SArnaud Minier */ 5183b551477SArnaud Minier if (FIELD_EX32(s->cfgr, CFGR, SWS) == 0b00 || 5193b551477SArnaud Minier current_pll_src == RCC_CLOCK_MUX_SRC_MSI) { 5203b551477SArnaud Minier s->cr |= (R_CR_MSION_MASK | R_CR_MSIRDY_MASK); 5213b551477SArnaud Minier if (!(previous_value & R_CR_MSION_MASK) && (s->cier & R_CIER_MSIRDYIE_MASK)) { 5223b551477SArnaud Minier s->cifr |= R_CIFR_MSIRDYF_MASK; 5239c796d50SArnaud Minier } 5243b551477SArnaud Minier rcc_update_msi(s, previous_value); 5253b551477SArnaud Minier } else { 5269c796d50SArnaud Minier val = FIELD_EX32(s->cr, CR, MSION); 5273b551477SArnaud Minier if (val) { 5283b551477SArnaud Minier s->cr |= R_CR_MSIRDY_MASK; 5293b551477SArnaud Minier rcc_update_msi(s, previous_value); 5309c796d50SArnaud Minier if (s->cier & R_CIER_MSIRDYIE_MASK) { 5319c796d50SArnaud Minier s->cifr |= R_CIFR_MSIRDYF_MASK; 5329c796d50SArnaud Minier } 5333b551477SArnaud Minier } else { 5343b551477SArnaud Minier s->cr &= ~R_CR_MSIRDY_MASK; 5353b551477SArnaud Minier clock_update(s->msi_rc, 0); 5363b551477SArnaud Minier } 5373b551477SArnaud Minier } 5389c796d50SArnaud Minier rcc_update_irq(s); 5399c796d50SArnaud Minier } 5409c796d50SArnaud Minier 5419c796d50SArnaud Minier static void rcc_update_cfgr_register(Stm32l4x5RccState *s) 5429c796d50SArnaud Minier { 5439c796d50SArnaud Minier uint32_t val; 5449c796d50SArnaud Minier /* MCOPRE */ 5459c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, MCOPRE); 5469c796d50SArnaud Minier assert(val <= 0b100); 5479c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_MCO], 5489c796d50SArnaud Minier 1, 1 << val); 5499c796d50SArnaud Minier 5509c796d50SArnaud Minier /* MCOSEL */ 5519c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, MCOSEL); 5529c796d50SArnaud Minier assert(val <= 0b111); 5539c796d50SArnaud Minier if (val == 0) { 5549c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false); 5559c796d50SArnaud Minier } else { 5569c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], true); 5579c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_MCO], 5589c796d50SArnaud Minier val - 1); 5599c796d50SArnaud Minier } 5609c796d50SArnaud Minier 5619c796d50SArnaud Minier /* STOPWUCK */ 5629c796d50SArnaud Minier /* TODO */ 5639c796d50SArnaud Minier 5649c796d50SArnaud Minier /* PPRE2 */ 5659c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, PPRE2); 5669c796d50SArnaud Minier if (val < 0b100) { 5679c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK2], 5689c796d50SArnaud Minier 1, 1); 5699c796d50SArnaud Minier } else { 5709c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK2], 5719c796d50SArnaud Minier 1, 1 << (val - 0b11)); 5729c796d50SArnaud Minier } 5739c796d50SArnaud Minier 5749c796d50SArnaud Minier /* PPRE1 */ 5759c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, PPRE1); 5769c796d50SArnaud Minier if (val < 0b100) { 5779c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK1], 5789c796d50SArnaud Minier 1, 1); 5799c796d50SArnaud Minier } else { 5809c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK1], 5819c796d50SArnaud Minier 1, 1 << (val - 0b11)); 5829c796d50SArnaud Minier } 5839c796d50SArnaud Minier 5849c796d50SArnaud Minier /* HPRE */ 5859c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, HPRE); 5869c796d50SArnaud Minier if (val < 0b1000) { 5879c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_HCLK], 5889c796d50SArnaud Minier 1, 1); 5899c796d50SArnaud Minier } else { 5909c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_HCLK], 5919c796d50SArnaud Minier 1, 1 << (val - 0b111)); 5929c796d50SArnaud Minier } 5939c796d50SArnaud Minier 5949c796d50SArnaud Minier /* Update SWS */ 5959c796d50SArnaud Minier val = FIELD_EX32(s->cfgr, CFGR, SW); 5969c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_SYSCLK], 5979c796d50SArnaud Minier val); 5989c796d50SArnaud Minier s->cfgr &= ~R_CFGR_SWS_MASK; 5999c796d50SArnaud Minier s->cfgr |= val << R_CFGR_SWS_SHIFT; 6009c796d50SArnaud Minier } 6019c796d50SArnaud Minier 6029c796d50SArnaud Minier static void rcc_update_ahb1enr(Stm32l4x5RccState *s) 6039c796d50SArnaud Minier { 6049c796d50SArnaud Minier #define AHB1ENR_SET_ENABLE(_peripheral_name) \ 6059c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6069c796d50SArnaud Minier FIELD_EX32(s->ahb1enr, AHB1ENR, _peripheral_name##EN)) 6079c796d50SArnaud Minier 6089c796d50SArnaud Minier /* DMA2DEN: reserved for STM32L475xx */ 6099c796d50SArnaud Minier AHB1ENR_SET_ENABLE(TSC); 6109c796d50SArnaud Minier AHB1ENR_SET_ENABLE(CRC); 6119c796d50SArnaud Minier AHB1ENR_SET_ENABLE(FLASH); 6129c796d50SArnaud Minier AHB1ENR_SET_ENABLE(DMA2); 6139c796d50SArnaud Minier AHB1ENR_SET_ENABLE(DMA1); 6149c796d50SArnaud Minier 6159c796d50SArnaud Minier #undef AHB1ENR_SET_ENABLE 6169c796d50SArnaud Minier } 6179c796d50SArnaud Minier 6189c796d50SArnaud Minier static void rcc_update_ahb2enr(Stm32l4x5RccState *s) 6199c796d50SArnaud Minier { 6209c796d50SArnaud Minier #define AHB2ENR_SET_ENABLE(_peripheral_name) \ 6219c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6229c796d50SArnaud Minier FIELD_EX32(s->ahb2enr, AHB2ENR, _peripheral_name##EN)) 6239c796d50SArnaud Minier 6249c796d50SArnaud Minier AHB2ENR_SET_ENABLE(RNG); 6259c796d50SArnaud Minier /* HASHEN: reserved for STM32L475xx */ 6269c796d50SArnaud Minier AHB2ENR_SET_ENABLE(AES); 6279c796d50SArnaud Minier /* DCMIEN: reserved for STM32L475xx */ 6289c796d50SArnaud Minier AHB2ENR_SET_ENABLE(ADC); 6299c796d50SArnaud Minier AHB2ENR_SET_ENABLE(OTGFS); 6309c796d50SArnaud Minier /* GPIOIEN: reserved for STM32L475xx */ 6319c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOA); 6329c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOB); 6339c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOC); 6349c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOD); 6359c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOE); 6369c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOF); 6379c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOG); 6389c796d50SArnaud Minier AHB2ENR_SET_ENABLE(GPIOH); 6399c796d50SArnaud Minier 6409c796d50SArnaud Minier #undef AHB2ENR_SET_ENABLE 6419c796d50SArnaud Minier } 6429c796d50SArnaud Minier 6439c796d50SArnaud Minier static void rcc_update_ahb3enr(Stm32l4x5RccState *s) 6449c796d50SArnaud Minier { 6459c796d50SArnaud Minier #define AHB3ENR_SET_ENABLE(_peripheral_name) \ 6469c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6479c796d50SArnaud Minier FIELD_EX32(s->ahb3enr, AHB3ENR, _peripheral_name##EN)) 6489c796d50SArnaud Minier 6499c796d50SArnaud Minier AHB3ENR_SET_ENABLE(QSPI); 6509c796d50SArnaud Minier AHB3ENR_SET_ENABLE(FMC); 6519c796d50SArnaud Minier 6529c796d50SArnaud Minier #undef AHB3ENR_SET_ENABLE 6539c796d50SArnaud Minier } 6549c796d50SArnaud Minier 6559c796d50SArnaud Minier static void rcc_update_apb1enr(Stm32l4x5RccState *s) 6569c796d50SArnaud Minier { 6579c796d50SArnaud Minier #define APB1ENR1_SET_ENABLE(_peripheral_name) \ 6589c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6599c796d50SArnaud Minier FIELD_EX32(s->apb1enr1, APB1ENR1, _peripheral_name##EN)) 6609c796d50SArnaud Minier #define APB1ENR2_SET_ENABLE(_peripheral_name) \ 6619c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 6629c796d50SArnaud Minier FIELD_EX32(s->apb1enr2, APB1ENR2, _peripheral_name##EN)) 6639c796d50SArnaud Minier 6649c796d50SArnaud Minier /* APB1ENR1 */ 6659c796d50SArnaud Minier APB1ENR1_SET_ENABLE(LPTIM1); 6669c796d50SArnaud Minier APB1ENR1_SET_ENABLE(OPAMP); 6679c796d50SArnaud Minier APB1ENR1_SET_ENABLE(DAC1); 6689c796d50SArnaud Minier APB1ENR1_SET_ENABLE(PWR); 6699c796d50SArnaud Minier /* CAN2: reserved for STM32L4x5 */ 6709c796d50SArnaud Minier APB1ENR1_SET_ENABLE(CAN1); 6719c796d50SArnaud Minier /* CRSEN: reserved for STM32L4x5 */ 6729c796d50SArnaud Minier APB1ENR1_SET_ENABLE(I2C3); 6739c796d50SArnaud Minier APB1ENR1_SET_ENABLE(I2C2); 6749c796d50SArnaud Minier APB1ENR1_SET_ENABLE(I2C1); 6759c796d50SArnaud Minier APB1ENR1_SET_ENABLE(UART5); 6769c796d50SArnaud Minier APB1ENR1_SET_ENABLE(UART4); 6779c796d50SArnaud Minier APB1ENR1_SET_ENABLE(USART3); 6789c796d50SArnaud Minier APB1ENR1_SET_ENABLE(USART2); 6799c796d50SArnaud Minier APB1ENR1_SET_ENABLE(SPI3); 6809c796d50SArnaud Minier APB1ENR1_SET_ENABLE(SPI2); 6819c796d50SArnaud Minier APB1ENR1_SET_ENABLE(WWDG); 6829c796d50SArnaud Minier /* RTCAPB: reserved for STM32L4x5 */ 6839c796d50SArnaud Minier APB1ENR1_SET_ENABLE(LCD); 6849c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM7); 6859c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM6); 6869c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM5); 6879c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM4); 6889c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM3); 6899c796d50SArnaud Minier APB1ENR1_SET_ENABLE(TIM2); 6909c796d50SArnaud Minier 6919c796d50SArnaud Minier /* APB1ENR2 */ 6929c796d50SArnaud Minier APB1ENR2_SET_ENABLE(LPTIM2); 6939c796d50SArnaud Minier APB1ENR2_SET_ENABLE(SWPMI1); 6949c796d50SArnaud Minier /* I2C4EN: reserved for STM32L4x5 */ 6959c796d50SArnaud Minier APB1ENR2_SET_ENABLE(LPUART1); 6969c796d50SArnaud Minier 6979c796d50SArnaud Minier #undef APB1ENR1_SET_ENABLE 6989c796d50SArnaud Minier #undef APB1ENR2_SET_ENABLE 6999c796d50SArnaud Minier } 7009c796d50SArnaud Minier 7019c796d50SArnaud Minier static void rcc_update_apb2enr(Stm32l4x5RccState *s) 7029c796d50SArnaud Minier { 7039c796d50SArnaud Minier #define APB2ENR_SET_ENABLE(_peripheral_name) \ 7049c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 7059c796d50SArnaud Minier FIELD_EX32(s->apb2enr, APB2ENR, _peripheral_name##EN)) 7069c796d50SArnaud Minier 7079c796d50SArnaud Minier APB2ENR_SET_ENABLE(DFSDM1); 7089c796d50SArnaud Minier APB2ENR_SET_ENABLE(SAI2); 7099c796d50SArnaud Minier APB2ENR_SET_ENABLE(SAI1); 7109c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM17); 7119c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM16); 7129c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM15); 7139c796d50SArnaud Minier APB2ENR_SET_ENABLE(USART1); 7149c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM8); 7159c796d50SArnaud Minier APB2ENR_SET_ENABLE(SPI1); 7169c796d50SArnaud Minier APB2ENR_SET_ENABLE(TIM1); 7179c796d50SArnaud Minier APB2ENR_SET_ENABLE(SDMMC1); 7189c796d50SArnaud Minier APB2ENR_SET_ENABLE(FW); 7199c796d50SArnaud Minier APB2ENR_SET_ENABLE(SYSCFG); 7209c796d50SArnaud Minier 7219c796d50SArnaud Minier #undef APB2ENR_SET_ENABLE 7229c796d50SArnaud Minier } 7239c796d50SArnaud Minier 7249c796d50SArnaud Minier /* 7259c796d50SArnaud Minier * The 3 PLLs share the same register layout 7269c796d50SArnaud Minier * so we can use the same function for all of them 7279c796d50SArnaud Minier * Note: no frequency bounds checking is done here. 7289c796d50SArnaud Minier */ 7299c796d50SArnaud Minier static void rcc_update_pllsaixcfgr(Stm32l4x5RccState *s, RccPll pll_id) 7309c796d50SArnaud Minier { 7319c796d50SArnaud Minier uint32_t reg, val; 7329c796d50SArnaud Minier switch (pll_id) { 7339c796d50SArnaud Minier case RCC_PLL_PLL: 7349c796d50SArnaud Minier reg = s->pllcfgr; 7359c796d50SArnaud Minier break; 7369c796d50SArnaud Minier case RCC_PLL_PLLSAI1: 7379c796d50SArnaud Minier reg = s->pllsai1cfgr; 7389c796d50SArnaud Minier break; 7399c796d50SArnaud Minier case RCC_PLL_PLLSAI2: 7409c796d50SArnaud Minier reg = s->pllsai2cfgr; 7419c796d50SArnaud Minier break; 7429c796d50SArnaud Minier default: 7439c796d50SArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 7449c796d50SArnaud Minier "%s: Invalid PLL ID: %u\n", __func__, pll_id); 7459c796d50SArnaud Minier return; 7469c796d50SArnaud Minier } 7479c796d50SArnaud Minier 7489c796d50SArnaud Minier /* PLLPDIV */ 7499c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLPDIV); 7509c796d50SArnaud Minier /* 1 is a reserved value */ 7519c796d50SArnaud Minier if (val == 0) { 7529c796d50SArnaud Minier /* Get PLLP value */ 7539c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLP); 7549c796d50SArnaud Minier pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, 7559c796d50SArnaud Minier (val ? 17 : 7)); 7569c796d50SArnaud Minier } else if (val > 1) { 7579c796d50SArnaud Minier pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, 7589c796d50SArnaud Minier val); 7599c796d50SArnaud Minier } 7609c796d50SArnaud Minier 7619c796d50SArnaud Minier 7629c796d50SArnaud Minier /* PLLR */ 7639c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLR); 7649c796d50SArnaud Minier pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_R, 7659c796d50SArnaud Minier 2 * (val + 1)); 7669c796d50SArnaud Minier 7679c796d50SArnaud Minier /* PLLREN */ 7689c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLREN); 7699c796d50SArnaud Minier pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_R, val); 7709c796d50SArnaud Minier 7719c796d50SArnaud Minier /* PLLQ */ 7729c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLQ); 7739c796d50SArnaud Minier pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_Q, 7749c796d50SArnaud Minier 2 * (val + 1)); 7759c796d50SArnaud Minier 7769c796d50SArnaud Minier /* PLLQEN */ 7779c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLQEN); 7789c796d50SArnaud Minier pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_Q, val); 7799c796d50SArnaud Minier 7809c796d50SArnaud Minier /* PLLPEN */ 7819c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLPEN); 7829c796d50SArnaud Minier pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, val); 7839c796d50SArnaud Minier 7849c796d50SArnaud Minier /* PLLN */ 7859c796d50SArnaud Minier val = FIELD_EX32(reg, PLLCFGR, PLLN); 7869c796d50SArnaud Minier pll_set_vco_multiplier(&s->plls[pll_id], val); 7879c796d50SArnaud Minier } 7889c796d50SArnaud Minier 7899c796d50SArnaud Minier static void rcc_update_pllcfgr(Stm32l4x5RccState *s) 7909c796d50SArnaud Minier { 7919c796d50SArnaud Minier int val; 7929c796d50SArnaud Minier 7939c796d50SArnaud Minier /* Use common layout */ 7949c796d50SArnaud Minier rcc_update_pllsaixcfgr(s, RCC_PLL_PLL); 7959c796d50SArnaud Minier 7969c796d50SArnaud Minier /* Fetch specific fields for pllcfgr */ 7979c796d50SArnaud Minier 7989c796d50SArnaud Minier /* PLLM */ 7999c796d50SArnaud Minier val = FIELD_EX32(s->pllcfgr, PLLCFGR, PLLM); 8009c796d50SArnaud Minier clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], 1, (val + 1)); 8019c796d50SArnaud Minier 8029c796d50SArnaud Minier /* PLLSRC */ 8039c796d50SArnaud Minier val = FIELD_EX32(s->pllcfgr, PLLCFGR, PLLSRC); 8049c796d50SArnaud Minier if (val == 0) { 8059c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], false); 8069c796d50SArnaud Minier } else { 8079c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], val - 1); 8089c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], true); 8099c796d50SArnaud Minier } 8109c796d50SArnaud Minier } 8119c796d50SArnaud Minier 8129c796d50SArnaud Minier static void rcc_update_ccipr(Stm32l4x5RccState *s) 8139c796d50SArnaud Minier { 8149c796d50SArnaud Minier #define CCIPR_SET_SOURCE(_peripheral_name) \ 8159c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \ 8169c796d50SArnaud Minier FIELD_EX32(s->ccipr, CCIPR, _peripheral_name##SEL)) 8179c796d50SArnaud Minier 8189c796d50SArnaud Minier CCIPR_SET_SOURCE(DFSDM1); 8199c796d50SArnaud Minier CCIPR_SET_SOURCE(SWPMI1); 8209c796d50SArnaud Minier CCIPR_SET_SOURCE(ADC); 8219c796d50SArnaud Minier CCIPR_SET_SOURCE(CLK48); 8229c796d50SArnaud Minier CCIPR_SET_SOURCE(SAI2); 8239c796d50SArnaud Minier CCIPR_SET_SOURCE(SAI1); 8249c796d50SArnaud Minier CCIPR_SET_SOURCE(LPTIM2); 8259c796d50SArnaud Minier CCIPR_SET_SOURCE(LPTIM1); 8269c796d50SArnaud Minier CCIPR_SET_SOURCE(I2C3); 8279c796d50SArnaud Minier CCIPR_SET_SOURCE(I2C2); 8289c796d50SArnaud Minier CCIPR_SET_SOURCE(I2C1); 8299c796d50SArnaud Minier CCIPR_SET_SOURCE(LPUART1); 8309c796d50SArnaud Minier CCIPR_SET_SOURCE(UART5); 8319c796d50SArnaud Minier CCIPR_SET_SOURCE(UART4); 8329c796d50SArnaud Minier CCIPR_SET_SOURCE(USART3); 8339c796d50SArnaud Minier CCIPR_SET_SOURCE(USART2); 8349c796d50SArnaud Minier CCIPR_SET_SOURCE(USART1); 8359c796d50SArnaud Minier 8369c796d50SArnaud Minier #undef CCIPR_SET_SOURCE 8379c796d50SArnaud Minier } 8389c796d50SArnaud Minier 8399c796d50SArnaud Minier static void rcc_update_bdcr(Stm32l4x5RccState *s) 8409c796d50SArnaud Minier { 8419c796d50SArnaud Minier int val; 8429c796d50SArnaud Minier 8439c796d50SArnaud Minier /* LSCOSEL */ 8449c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, LSCOSEL); 8459c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_LSCO], val); 8469c796d50SArnaud Minier 8479c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, LSCOEN); 8489c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_LSCO], val); 8499c796d50SArnaud Minier 8509c796d50SArnaud Minier /* BDRST */ 8519c796d50SArnaud Minier /* 8529c796d50SArnaud Minier * The documentation is not clear if the RTCEN flag disables the RTC and 8539c796d50SArnaud Minier * the LCD common mux or if it only affects the RTC. 8549c796d50SArnaud Minier * As the LCDEN flag exists, we assume here that it only affects the RTC. 8559c796d50SArnaud Minier */ 8569c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, RTCEN); 8579c796d50SArnaud Minier clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_RTC], val); 8589c796d50SArnaud Minier /* LCD and RTC share the same clock */ 8599c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, RTCSEL); 8609c796d50SArnaud Minier clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON], val); 8619c796d50SArnaud Minier 8629c796d50SArnaud Minier /* LSECSSON */ 8639c796d50SArnaud Minier /* LSEDRV[1:0] */ 8649c796d50SArnaud Minier /* LSEBYP */ 8659c796d50SArnaud Minier 8669c796d50SArnaud Minier /* LSEON: Update LSERDY at the same time */ 8679c796d50SArnaud Minier val = FIELD_EX32(s->bdcr, BDCR, LSEON); 8689c796d50SArnaud Minier if (val) { 8699c796d50SArnaud Minier clock_update_hz(s->lse_crystal, LSE_FRQ); 8709c796d50SArnaud Minier s->bdcr |= R_BDCR_LSERDY_MASK; 8719c796d50SArnaud Minier if (s->cier & R_CIER_LSERDYIE_MASK) { 8729c796d50SArnaud Minier s->cifr |= R_CIFR_LSERDYF_MASK; 8739c796d50SArnaud Minier } 8749c796d50SArnaud Minier } else { 8759c796d50SArnaud Minier clock_update(s->lse_crystal, 0); 8769c796d50SArnaud Minier s->bdcr &= ~R_BDCR_LSERDY_MASK; 8779c796d50SArnaud Minier } 8789c796d50SArnaud Minier 8799c796d50SArnaud Minier rcc_update_irq(s); 8809c796d50SArnaud Minier } 8819c796d50SArnaud Minier 8829c796d50SArnaud Minier static void rcc_update_csr(Stm32l4x5RccState *s) 8839c796d50SArnaud Minier { 8849c796d50SArnaud Minier int val; 8859c796d50SArnaud Minier 8869c796d50SArnaud Minier /* Reset flags: Not implemented */ 8879c796d50SArnaud Minier /* MSISRANGE: Not implemented after reset */ 8889c796d50SArnaud Minier 8899c796d50SArnaud Minier /* LSION: Update LSIRDY at the same time */ 8909c796d50SArnaud Minier val = FIELD_EX32(s->csr, CSR, LSION); 8919c796d50SArnaud Minier if (val) { 8929c796d50SArnaud Minier clock_update_hz(s->lsi_rc, LSI_FRQ); 8939c796d50SArnaud Minier s->csr |= R_CSR_LSIRDY_MASK; 8949c796d50SArnaud Minier if (s->cier & R_CIER_LSIRDYIE_MASK) { 8959c796d50SArnaud Minier s->cifr |= R_CIFR_LSIRDYF_MASK; 8969c796d50SArnaud Minier } 8979c796d50SArnaud Minier } else { 8989c796d50SArnaud Minier /* 8999c796d50SArnaud Minier * TODO: Handle when the LSI is set independently of LSION. 9009c796d50SArnaud Minier * E.g. when the LSI is set by the RTC. 9019c796d50SArnaud Minier * See the reference manual for more details. 9029c796d50SArnaud Minier */ 9039c796d50SArnaud Minier clock_update(s->lsi_rc, 0); 9049c796d50SArnaud Minier s->csr &= ~R_CSR_LSIRDY_MASK; 9059c796d50SArnaud Minier } 9069c796d50SArnaud Minier 9079c796d50SArnaud Minier rcc_update_irq(s); 9089c796d50SArnaud Minier } 9099c796d50SArnaud Minier 910d6b55a0fSArnaud Minier static void stm32l4x5_rcc_reset_hold(Object *obj) 911d6b55a0fSArnaud Minier { 912d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(obj); 913d6b55a0fSArnaud Minier s->cr = 0x00000063; 914d6b55a0fSArnaud Minier /* 915d6b55a0fSArnaud Minier * Factory-programmed calibration data 916d6b55a0fSArnaud Minier * From the reference manual: 0x10XX 00XX 917d6b55a0fSArnaud Minier * Value taken from a real card. 918d6b55a0fSArnaud Minier */ 919d6b55a0fSArnaud Minier s->icscr = 0x106E0082; 920d6b55a0fSArnaud Minier s->cfgr = 0x0; 921d6b55a0fSArnaud Minier s->pllcfgr = 0x00001000; 922d6b55a0fSArnaud Minier s->pllsai1cfgr = 0x00001000; 923d6b55a0fSArnaud Minier s->pllsai2cfgr = 0x00001000; 924d6b55a0fSArnaud Minier s->cier = 0x0; 925d6b55a0fSArnaud Minier s->cifr = 0x0; 926d6b55a0fSArnaud Minier s->ahb1rstr = 0x0; 927d6b55a0fSArnaud Minier s->ahb2rstr = 0x0; 928d6b55a0fSArnaud Minier s->ahb3rstr = 0x0; 929d6b55a0fSArnaud Minier s->apb1rstr1 = 0x0; 930d6b55a0fSArnaud Minier s->apb1rstr2 = 0x0; 931d6b55a0fSArnaud Minier s->apb2rstr = 0x0; 932d6b55a0fSArnaud Minier s->ahb1enr = 0x00000100; 933d6b55a0fSArnaud Minier s->ahb2enr = 0x0; 934d6b55a0fSArnaud Minier s->ahb3enr = 0x0; 935d6b55a0fSArnaud Minier s->apb1enr1 = 0x0; 936d6b55a0fSArnaud Minier s->apb1enr2 = 0x0; 937d6b55a0fSArnaud Minier s->apb2enr = 0x0; 938d6b55a0fSArnaud Minier s->ahb1smenr = 0x00011303; 939d6b55a0fSArnaud Minier s->ahb2smenr = 0x000532FF; 940d6b55a0fSArnaud Minier s->ahb3smenr = 0x00000101; 941d6b55a0fSArnaud Minier s->apb1smenr1 = 0xF2FECA3F; 942d6b55a0fSArnaud Minier s->apb1smenr2 = 0x00000025; 943d6b55a0fSArnaud Minier s->apb2smenr = 0x01677C01; 944d6b55a0fSArnaud Minier s->ccipr = 0x0; 945d6b55a0fSArnaud Minier s->bdcr = 0x0; 946d6b55a0fSArnaud Minier s->csr = 0x0C000600; 947d6b55a0fSArnaud Minier } 948d6b55a0fSArnaud Minier 949d6b55a0fSArnaud Minier static uint64_t stm32l4x5_rcc_read(void *opaque, hwaddr addr, 950d6b55a0fSArnaud Minier unsigned int size) 951d6b55a0fSArnaud Minier { 952d6b55a0fSArnaud Minier Stm32l4x5RccState *s = opaque; 953d6b55a0fSArnaud Minier uint64_t retvalue = 0; 954d6b55a0fSArnaud Minier 955d6b55a0fSArnaud Minier switch (addr) { 956d6b55a0fSArnaud Minier case A_CR: 957d6b55a0fSArnaud Minier retvalue = s->cr; 958d6b55a0fSArnaud Minier break; 959d6b55a0fSArnaud Minier case A_ICSCR: 960d6b55a0fSArnaud Minier retvalue = s->icscr; 961d6b55a0fSArnaud Minier break; 962d6b55a0fSArnaud Minier case A_CFGR: 963d6b55a0fSArnaud Minier retvalue = s->cfgr; 964d6b55a0fSArnaud Minier break; 965d6b55a0fSArnaud Minier case A_PLLCFGR: 966d6b55a0fSArnaud Minier retvalue = s->pllcfgr; 967d6b55a0fSArnaud Minier break; 968d6b55a0fSArnaud Minier case A_PLLSAI1CFGR: 969d6b55a0fSArnaud Minier retvalue = s->pllsai1cfgr; 970d6b55a0fSArnaud Minier break; 971d6b55a0fSArnaud Minier case A_PLLSAI2CFGR: 972d6b55a0fSArnaud Minier retvalue = s->pllsai2cfgr; 973d6b55a0fSArnaud Minier break; 974d6b55a0fSArnaud Minier case A_CIER: 975d6b55a0fSArnaud Minier retvalue = s->cier; 976d6b55a0fSArnaud Minier break; 977d6b55a0fSArnaud Minier case A_CIFR: 978d6b55a0fSArnaud Minier retvalue = s->cifr; 979d6b55a0fSArnaud Minier break; 980d6b55a0fSArnaud Minier case A_CICR: 981d6b55a0fSArnaud Minier /* CICR is write only, return the reset value = 0 */ 982d6b55a0fSArnaud Minier break; 983d6b55a0fSArnaud Minier case A_AHB1RSTR: 984d6b55a0fSArnaud Minier retvalue = s->ahb1rstr; 985d6b55a0fSArnaud Minier break; 986d6b55a0fSArnaud Minier case A_AHB2RSTR: 987d6b55a0fSArnaud Minier retvalue = s->ahb2rstr; 988d6b55a0fSArnaud Minier break; 989d6b55a0fSArnaud Minier case A_AHB3RSTR: 990d6b55a0fSArnaud Minier retvalue = s->ahb3rstr; 991d6b55a0fSArnaud Minier break; 992d6b55a0fSArnaud Minier case A_APB1RSTR1: 993d6b55a0fSArnaud Minier retvalue = s->apb1rstr1; 994d6b55a0fSArnaud Minier break; 995d6b55a0fSArnaud Minier case A_APB1RSTR2: 996d6b55a0fSArnaud Minier retvalue = s->apb1rstr2; 997d6b55a0fSArnaud Minier break; 998d6b55a0fSArnaud Minier case A_APB2RSTR: 999d6b55a0fSArnaud Minier retvalue = s->apb2rstr; 1000d6b55a0fSArnaud Minier break; 1001d6b55a0fSArnaud Minier case A_AHB1ENR: 1002d6b55a0fSArnaud Minier retvalue = s->ahb1enr; 1003d6b55a0fSArnaud Minier break; 1004d6b55a0fSArnaud Minier case A_AHB2ENR: 1005d6b55a0fSArnaud Minier retvalue = s->ahb2enr; 1006d6b55a0fSArnaud Minier break; 1007d6b55a0fSArnaud Minier case A_AHB3ENR: 1008d6b55a0fSArnaud Minier retvalue = s->ahb3enr; 1009d6b55a0fSArnaud Minier break; 1010d6b55a0fSArnaud Minier case A_APB1ENR1: 1011d6b55a0fSArnaud Minier retvalue = s->apb1enr1; 1012d6b55a0fSArnaud Minier break; 1013d6b55a0fSArnaud Minier case A_APB1ENR2: 1014d6b55a0fSArnaud Minier retvalue = s->apb1enr2; 1015d6b55a0fSArnaud Minier break; 1016d6b55a0fSArnaud Minier case A_APB2ENR: 1017d6b55a0fSArnaud Minier retvalue = s->apb2enr; 1018d6b55a0fSArnaud Minier break; 1019d6b55a0fSArnaud Minier case A_AHB1SMENR: 1020d6b55a0fSArnaud Minier retvalue = s->ahb1smenr; 1021d6b55a0fSArnaud Minier break; 1022d6b55a0fSArnaud Minier case A_AHB2SMENR: 1023d6b55a0fSArnaud Minier retvalue = s->ahb2smenr; 1024d6b55a0fSArnaud Minier break; 1025d6b55a0fSArnaud Minier case A_AHB3SMENR: 1026d6b55a0fSArnaud Minier retvalue = s->ahb3smenr; 1027d6b55a0fSArnaud Minier break; 1028d6b55a0fSArnaud Minier case A_APB1SMENR1: 1029d6b55a0fSArnaud Minier retvalue = s->apb1smenr1; 1030d6b55a0fSArnaud Minier break; 1031d6b55a0fSArnaud Minier case A_APB1SMENR2: 1032d6b55a0fSArnaud Minier retvalue = s->apb1smenr2; 1033d6b55a0fSArnaud Minier break; 1034d6b55a0fSArnaud Minier case A_APB2SMENR: 1035d6b55a0fSArnaud Minier retvalue = s->apb2smenr; 1036d6b55a0fSArnaud Minier break; 1037d6b55a0fSArnaud Minier case A_CCIPR: 1038d6b55a0fSArnaud Minier retvalue = s->ccipr; 1039d6b55a0fSArnaud Minier break; 1040d6b55a0fSArnaud Minier case A_BDCR: 1041d6b55a0fSArnaud Minier retvalue = s->bdcr; 1042d6b55a0fSArnaud Minier break; 1043d6b55a0fSArnaud Minier case A_CSR: 1044d6b55a0fSArnaud Minier retvalue = s->csr; 1045d6b55a0fSArnaud Minier break; 1046d6b55a0fSArnaud Minier default: 1047d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 1048d6b55a0fSArnaud Minier "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 1049d6b55a0fSArnaud Minier break; 1050d6b55a0fSArnaud Minier } 1051d6b55a0fSArnaud Minier 1052d6b55a0fSArnaud Minier trace_stm32l4x5_rcc_read(addr, retvalue); 1053d6b55a0fSArnaud Minier 1054d6b55a0fSArnaud Minier return retvalue; 1055d6b55a0fSArnaud Minier } 1056d6b55a0fSArnaud Minier 1057d6b55a0fSArnaud Minier static void stm32l4x5_rcc_write(void *opaque, hwaddr addr, 1058d6b55a0fSArnaud Minier uint64_t val64, unsigned int size) 1059d6b55a0fSArnaud Minier { 1060d6b55a0fSArnaud Minier Stm32l4x5RccState *s = opaque; 10613b551477SArnaud Minier uint32_t previous_value = 0; 1062d6b55a0fSArnaud Minier const uint32_t value = val64; 1063d6b55a0fSArnaud Minier 1064d6b55a0fSArnaud Minier trace_stm32l4x5_rcc_write(addr, value); 1065d6b55a0fSArnaud Minier 1066d6b55a0fSArnaud Minier switch (addr) { 1067d6b55a0fSArnaud Minier case A_CR: 10683b551477SArnaud Minier previous_value = s->cr; 1069d6b55a0fSArnaud Minier s->cr = (s->cr & CR_READ_SET_MASK) | 1070d6b55a0fSArnaud Minier (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK)); 10713b551477SArnaud Minier rcc_update_cr_register(s, previous_value); 1072d6b55a0fSArnaud Minier break; 1073d6b55a0fSArnaud Minier case A_ICSCR: 1074d6b55a0fSArnaud Minier s->icscr = value & ~ICSCR_READ_ONLY_MASK; 10759c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 10769c796d50SArnaud Minier "%s: Side-effects not implemented for ICSCR\n", __func__); 1077d6b55a0fSArnaud Minier break; 1078d6b55a0fSArnaud Minier case A_CFGR: 1079d6b55a0fSArnaud Minier s->cfgr = value & ~CFGR_READ_ONLY_MASK; 10809c796d50SArnaud Minier rcc_update_cfgr_register(s); 1081d6b55a0fSArnaud Minier break; 1082d6b55a0fSArnaud Minier case A_PLLCFGR: 1083d6b55a0fSArnaud Minier s->pllcfgr = value; 10849c796d50SArnaud Minier rcc_update_pllcfgr(s); 1085d6b55a0fSArnaud Minier break; 1086d6b55a0fSArnaud Minier case A_PLLSAI1CFGR: 1087d6b55a0fSArnaud Minier s->pllsai1cfgr = value; 10889c796d50SArnaud Minier rcc_update_pllsaixcfgr(s, RCC_PLL_PLLSAI1); 1089d6b55a0fSArnaud Minier break; 1090d6b55a0fSArnaud Minier case A_PLLSAI2CFGR: 1091d6b55a0fSArnaud Minier s->pllsai2cfgr = value; 10929c796d50SArnaud Minier rcc_update_pllsaixcfgr(s, RCC_PLL_PLLSAI2); 1093d6b55a0fSArnaud Minier break; 1094d6b55a0fSArnaud Minier case A_CIER: 1095d6b55a0fSArnaud Minier s->cier = value; 10969c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 10979c796d50SArnaud Minier "%s: Side-effects not implemented for CIER\n", __func__); 1098d6b55a0fSArnaud Minier break; 1099d6b55a0fSArnaud Minier case A_CIFR: 1100d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 1101d6b55a0fSArnaud Minier "%s: Write attempt into read-only register (CIFR) 0x%"PRIx32"\n", 1102d6b55a0fSArnaud Minier __func__, value); 1103d6b55a0fSArnaud Minier break; 1104d6b55a0fSArnaud Minier case A_CICR: 1105d6b55a0fSArnaud Minier /* Clear interrupt flags by writing a 1 to the CICR register */ 1106d6b55a0fSArnaud Minier s->cifr &= ~value; 1107d6b55a0fSArnaud Minier rcc_update_irq(s); 1108d6b55a0fSArnaud Minier break; 1109d6b55a0fSArnaud Minier /* Reset behaviors are not implemented */ 1110d6b55a0fSArnaud Minier case A_AHB1RSTR: 1111d6b55a0fSArnaud Minier s->ahb1rstr = value; 11129c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11139c796d50SArnaud Minier "%s: Side-effects not implemented for AHB1RSTR\n", __func__); 1114d6b55a0fSArnaud Minier break; 1115d6b55a0fSArnaud Minier case A_AHB2RSTR: 1116d6b55a0fSArnaud Minier s->ahb2rstr = value; 11179c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11189c796d50SArnaud Minier "%s: Side-effects not implemented for AHB2RSTR\n", __func__); 1119d6b55a0fSArnaud Minier break; 1120d6b55a0fSArnaud Minier case A_AHB3RSTR: 1121d6b55a0fSArnaud Minier s->ahb3rstr = value; 11229c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11239c796d50SArnaud Minier "%s: Side-effects not implemented for AHB3RSTR\n", __func__); 1124d6b55a0fSArnaud Minier break; 1125d6b55a0fSArnaud Minier case A_APB1RSTR1: 1126d6b55a0fSArnaud Minier s->apb1rstr1 = value; 11279c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11289c796d50SArnaud Minier "%s: Side-effects not implemented for APB1RSTR1\n", __func__); 1129d6b55a0fSArnaud Minier break; 1130d6b55a0fSArnaud Minier case A_APB1RSTR2: 1131d6b55a0fSArnaud Minier s->apb1rstr2 = value; 11329c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11339c796d50SArnaud Minier "%s: Side-effects not implemented for APB1RSTR2\n", __func__); 1134d6b55a0fSArnaud Minier break; 1135d6b55a0fSArnaud Minier case A_APB2RSTR: 1136d6b55a0fSArnaud Minier s->apb2rstr = value; 11379c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11389c796d50SArnaud Minier "%s: Side-effects not implemented for APB2RSTR\n", __func__); 1139d6b55a0fSArnaud Minier break; 1140d6b55a0fSArnaud Minier case A_AHB1ENR: 1141d6b55a0fSArnaud Minier s->ahb1enr = value; 11429c796d50SArnaud Minier rcc_update_ahb1enr(s); 1143d6b55a0fSArnaud Minier break; 1144d6b55a0fSArnaud Minier case A_AHB2ENR: 1145d6b55a0fSArnaud Minier s->ahb2enr = value; 11469c796d50SArnaud Minier rcc_update_ahb2enr(s); 1147d6b55a0fSArnaud Minier break; 1148d6b55a0fSArnaud Minier case A_AHB3ENR: 1149d6b55a0fSArnaud Minier s->ahb3enr = value; 11509c796d50SArnaud Minier rcc_update_ahb3enr(s); 1151d6b55a0fSArnaud Minier break; 1152d6b55a0fSArnaud Minier case A_APB1ENR1: 1153d6b55a0fSArnaud Minier s->apb1enr1 = value; 11549c796d50SArnaud Minier rcc_update_apb1enr(s); 1155d6b55a0fSArnaud Minier break; 1156d6b55a0fSArnaud Minier case A_APB1ENR2: 1157d6b55a0fSArnaud Minier s->apb1enr2 = value; 11589c796d50SArnaud Minier rcc_update_apb1enr(s); 1159d6b55a0fSArnaud Minier break; 1160d6b55a0fSArnaud Minier case A_APB2ENR: 1161d6b55a0fSArnaud Minier s->apb2enr = (s->apb2enr & APB2ENR_READ_SET_MASK) | value; 11629c796d50SArnaud Minier rcc_update_apb2enr(s); 1163d6b55a0fSArnaud Minier break; 1164d6b55a0fSArnaud Minier /* Behaviors for Sleep and Stop modes are not implemented */ 1165d6b55a0fSArnaud Minier case A_AHB1SMENR: 1166d6b55a0fSArnaud Minier s->ahb1smenr = value; 11679c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11689c796d50SArnaud Minier "%s: Side-effects not implemented for AHB1SMENR\n", __func__); 1169d6b55a0fSArnaud Minier break; 1170d6b55a0fSArnaud Minier case A_AHB2SMENR: 1171d6b55a0fSArnaud Minier s->ahb2smenr = value; 11729c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11739c796d50SArnaud Minier "%s: Side-effects not implemented for AHB2SMENR\n", __func__); 1174d6b55a0fSArnaud Minier break; 1175d6b55a0fSArnaud Minier case A_AHB3SMENR: 1176d6b55a0fSArnaud Minier s->ahb3smenr = value; 11779c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11789c796d50SArnaud Minier "%s: Side-effects not implemented for AHB3SMENR\n", __func__); 1179d6b55a0fSArnaud Minier break; 1180d6b55a0fSArnaud Minier case A_APB1SMENR1: 1181d6b55a0fSArnaud Minier s->apb1smenr1 = value; 11829c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11839c796d50SArnaud Minier "%s: Side-effects not implemented for APB1SMENR1\n", __func__); 1184d6b55a0fSArnaud Minier break; 1185d6b55a0fSArnaud Minier case A_APB1SMENR2: 1186d6b55a0fSArnaud Minier s->apb1smenr2 = value; 11879c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11889c796d50SArnaud Minier "%s: Side-effects not implemented for APB1SMENR2\n", __func__); 1189d6b55a0fSArnaud Minier break; 1190d6b55a0fSArnaud Minier case A_APB2SMENR: 1191d6b55a0fSArnaud Minier s->apb2smenr = value; 11929c796d50SArnaud Minier qemu_log_mask(LOG_UNIMP, 11939c796d50SArnaud Minier "%s: Side-effects not implemented for APB2SMENR\n", __func__); 1194d6b55a0fSArnaud Minier break; 1195d6b55a0fSArnaud Minier case A_CCIPR: 1196d6b55a0fSArnaud Minier s->ccipr = value; 11979c796d50SArnaud Minier rcc_update_ccipr(s); 1198d6b55a0fSArnaud Minier break; 1199d6b55a0fSArnaud Minier case A_BDCR: 1200d6b55a0fSArnaud Minier s->bdcr = value & ~BDCR_READ_ONLY_MASK; 12019c796d50SArnaud Minier rcc_update_bdcr(s); 1202d6b55a0fSArnaud Minier break; 1203d6b55a0fSArnaud Minier case A_CSR: 1204d6b55a0fSArnaud Minier s->csr = value & ~CSR_READ_ONLY_MASK; 12059c796d50SArnaud Minier rcc_update_csr(s); 1206d6b55a0fSArnaud Minier break; 1207d6b55a0fSArnaud Minier default: 1208d6b55a0fSArnaud Minier qemu_log_mask(LOG_GUEST_ERROR, 1209d6b55a0fSArnaud Minier "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 1210d6b55a0fSArnaud Minier } 1211d6b55a0fSArnaud Minier } 1212d6b55a0fSArnaud Minier 1213d6b55a0fSArnaud Minier static const MemoryRegionOps stm32l4x5_rcc_ops = { 1214d6b55a0fSArnaud Minier .read = stm32l4x5_rcc_read, 1215d6b55a0fSArnaud Minier .write = stm32l4x5_rcc_write, 1216d6b55a0fSArnaud Minier .endianness = DEVICE_NATIVE_ENDIAN, 1217d6b55a0fSArnaud Minier .valid = { 1218d6b55a0fSArnaud Minier .max_access_size = 4, 1219d6b55a0fSArnaud Minier .min_access_size = 4, 1220d6b55a0fSArnaud Minier .unaligned = false 1221d6b55a0fSArnaud Minier }, 1222d6b55a0fSArnaud Minier .impl = { 1223d6b55a0fSArnaud Minier .max_access_size = 4, 1224d6b55a0fSArnaud Minier .min_access_size = 4, 1225d6b55a0fSArnaud Minier .unaligned = false 1226d6b55a0fSArnaud Minier }, 1227d6b55a0fSArnaud Minier }; 1228d6b55a0fSArnaud Minier 1229d6b55a0fSArnaud Minier static const ClockPortInitArray stm32l4x5_rcc_clocks = { 1230d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, hsi16_rc, NULL, 0), 1231d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, msi_rc, NULL, 0), 1232d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, hse, NULL, 0), 1233d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, lsi_rc, NULL, 0), 1234d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, lse_crystal, NULL, 0), 1235d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, sai1_extclk, NULL, 0), 1236d6b55a0fSArnaud Minier QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0), 1237d6b55a0fSArnaud Minier QDEV_CLOCK_END 1238d6b55a0fSArnaud Minier }; 1239d6b55a0fSArnaud Minier 1240d6b55a0fSArnaud Minier 1241d6b55a0fSArnaud Minier static void stm32l4x5_rcc_init(Object *obj) 1242d6b55a0fSArnaud Minier { 1243d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(obj); 1244ec7d83acSArnaud Minier size_t i; 1245d6b55a0fSArnaud Minier 1246d6b55a0fSArnaud Minier sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 1247d6b55a0fSArnaud Minier 1248d6b55a0fSArnaud Minier memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s, 1249d6b55a0fSArnaud Minier TYPE_STM32L4X5_RCC, 0x400); 1250d6b55a0fSArnaud Minier sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 1251d6b55a0fSArnaud Minier 1252d6b55a0fSArnaud Minier qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); 1253d6b55a0fSArnaud Minier 12546487653eSArnaud Minier for (i = 0; i < RCC_NUM_PLL; i++) { 1255141c29a2SArnaud Minier object_initialize_child(obj, PLL_INIT_INFO[i].name, 12566487653eSArnaud Minier &s->plls[i], TYPE_RCC_PLL); 1257141c29a2SArnaud Minier set_pll_init_info(&s->plls[i], i); 12586487653eSArnaud Minier } 12596487653eSArnaud Minier 1260ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) { 1261141c29a2SArnaud Minier char *alias; 1262ec7d83acSArnaud Minier 1263141c29a2SArnaud Minier object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name, 1264ec7d83acSArnaud Minier &s->clock_muxes[i], 1265ec7d83acSArnaud Minier TYPE_RCC_CLOCK_MUX); 1266141c29a2SArnaud Minier set_clock_mux_init_info(&s->clock_muxes[i], i); 1267ec7d83acSArnaud Minier 1268141c29a2SArnaud Minier if (!CLOCK_MUX_INIT_INFO[i].hidden) { 1269141c29a2SArnaud Minier /* Expose muxes output as RCC outputs */ 1270141c29a2SArnaud Minier alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name); 1271141c29a2SArnaud Minier qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias); 1272141c29a2SArnaud Minier g_free(alias); 1273141c29a2SArnaud Minier } 1274ec7d83acSArnaud Minier } 1275ec7d83acSArnaud Minier 1276d6b55a0fSArnaud Minier s->gnd = clock_new(obj, "gnd"); 1277d6b55a0fSArnaud Minier } 1278d6b55a0fSArnaud Minier 1279141c29a2SArnaud Minier static void connect_mux_sources(Stm32l4x5RccState *s, 1280141c29a2SArnaud Minier RccClockMuxState *mux, 1281141c29a2SArnaud Minier const RccClockMuxSource *clk_mapping) 1282141c29a2SArnaud Minier { 1283141c29a2SArnaud Minier size_t i; 1284141c29a2SArnaud Minier 1285141c29a2SArnaud Minier Clock * const CLK_SRC_MAPPING[] = { 1286141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_GND] = s->gnd, 1287141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSI] = s->hsi16_rc, 1288141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSE] = s->hse, 1289141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_MSI] = s->msi_rc, 1290141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LSI] = s->lsi_rc, 1291141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LSE] = s->lse_crystal, 1292141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SAI1_EXTCLK] = s->sai1_extclk, 1293141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SAI2_EXTCLK] = s->sai2_extclk, 1294141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL] = 1295141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLCLK], 1296141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI1] = 1297141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLSAI1CLK], 1298141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI2] = 1299141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI2].channels[RCC_PLLSAI2_CHANNEL_PLLSAI2CLK], 1300141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLSAI3] = 1301141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLSAI3CLK], 1302141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL48M1] = 1303141c29a2SArnaud Minier s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLL48M1CLK], 1304141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLL48M2] = 1305141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLL48M2CLK], 1306141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLADC1] = 1307141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLADC1CLK], 1308141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PLLADC2] = 1309141c29a2SArnaud Minier s->plls[RCC_PLL_PLLSAI2] .channels[RCC_PLLSAI2_CHANNEL_PLLADC2CLK], 1310141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_SYSCLK] = s->clock_muxes[RCC_CLOCK_MUX_SYSCLK].out, 1311141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HCLK] = s->clock_muxes[RCC_CLOCK_MUX_HCLK].out, 1312141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PCLK1] = s->clock_muxes[RCC_CLOCK_MUX_PCLK1].out, 1313141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_PCLK2] = s->clock_muxes[RCC_CLOCK_MUX_PCLK2].out, 1314141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_HSE_OVER_32] = s->clock_muxes[RCC_CLOCK_MUX_HSE_OVER_32].out, 1315141c29a2SArnaud Minier [RCC_CLOCK_MUX_SRC_LCD_AND_RTC_COMMON] = 1316141c29a2SArnaud Minier s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON].out, 1317141c29a2SArnaud Minier }; 1318141c29a2SArnaud Minier 1319141c29a2SArnaud Minier assert(ARRAY_SIZE(CLK_SRC_MAPPING) == RCC_CLOCK_MUX_SRC_NUMBER); 1320141c29a2SArnaud Minier 1321141c29a2SArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { 1322141c29a2SArnaud Minier RccClockMuxSource mapping = clk_mapping[i]; 1323141c29a2SArnaud Minier clock_set_source(mux->srcs[i], CLK_SRC_MAPPING[mapping]); 1324141c29a2SArnaud Minier } 1325141c29a2SArnaud Minier } 1326141c29a2SArnaud Minier 1327141c29a2SArnaud Minier 1328d6b55a0fSArnaud Minier static const VMStateDescription vmstate_stm32l4x5_rcc = { 1329d6b55a0fSArnaud Minier .name = TYPE_STM32L4X5_RCC, 1330d6b55a0fSArnaud Minier .version_id = 1, 1331d6b55a0fSArnaud Minier .minimum_version_id = 1, 1332d6b55a0fSArnaud Minier .fields = (VMStateField[]) { 1333d6b55a0fSArnaud Minier VMSTATE_UINT32(cr, Stm32l4x5RccState), 1334d6b55a0fSArnaud Minier VMSTATE_UINT32(icscr, Stm32l4x5RccState), 1335d6b55a0fSArnaud Minier VMSTATE_UINT32(cfgr, Stm32l4x5RccState), 1336d6b55a0fSArnaud Minier VMSTATE_UINT32(pllcfgr, Stm32l4x5RccState), 1337d6b55a0fSArnaud Minier VMSTATE_UINT32(pllsai1cfgr, Stm32l4x5RccState), 1338d6b55a0fSArnaud Minier VMSTATE_UINT32(pllsai2cfgr, Stm32l4x5RccState), 1339d6b55a0fSArnaud Minier VMSTATE_UINT32(cier, Stm32l4x5RccState), 1340d6b55a0fSArnaud Minier VMSTATE_UINT32(cifr, Stm32l4x5RccState), 1341d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1rstr, Stm32l4x5RccState), 1342d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2rstr, Stm32l4x5RccState), 1343d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3rstr, Stm32l4x5RccState), 1344d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1rstr1, Stm32l4x5RccState), 1345d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1rstr2, Stm32l4x5RccState), 1346d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2rstr, Stm32l4x5RccState), 1347d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1enr, Stm32l4x5RccState), 1348d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2enr, Stm32l4x5RccState), 1349d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3enr, Stm32l4x5RccState), 1350d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1enr1, Stm32l4x5RccState), 1351d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1enr2, Stm32l4x5RccState), 1352d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2enr, Stm32l4x5RccState), 1353d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb1smenr, Stm32l4x5RccState), 1354d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb2smenr, Stm32l4x5RccState), 1355d6b55a0fSArnaud Minier VMSTATE_UINT32(ahb3smenr, Stm32l4x5RccState), 1356d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1smenr1, Stm32l4x5RccState), 1357d6b55a0fSArnaud Minier VMSTATE_UINT32(apb1smenr2, Stm32l4x5RccState), 1358d6b55a0fSArnaud Minier VMSTATE_UINT32(apb2smenr, Stm32l4x5RccState), 1359d6b55a0fSArnaud Minier VMSTATE_UINT32(ccipr, Stm32l4x5RccState), 1360d6b55a0fSArnaud Minier VMSTATE_UINT32(bdcr, Stm32l4x5RccState), 1361d6b55a0fSArnaud Minier VMSTATE_UINT32(csr, Stm32l4x5RccState), 1362d6b55a0fSArnaud Minier VMSTATE_CLOCK(hsi16_rc, Stm32l4x5RccState), 1363d6b55a0fSArnaud Minier VMSTATE_CLOCK(msi_rc, Stm32l4x5RccState), 1364d6b55a0fSArnaud Minier VMSTATE_CLOCK(hse, Stm32l4x5RccState), 1365d6b55a0fSArnaud Minier VMSTATE_CLOCK(lsi_rc, Stm32l4x5RccState), 1366d6b55a0fSArnaud Minier VMSTATE_CLOCK(lse_crystal, Stm32l4x5RccState), 1367d6b55a0fSArnaud Minier VMSTATE_CLOCK(sai1_extclk, Stm32l4x5RccState), 1368d6b55a0fSArnaud Minier VMSTATE_CLOCK(sai2_extclk, Stm32l4x5RccState), 1369d6b55a0fSArnaud Minier VMSTATE_END_OF_LIST() 1370d6b55a0fSArnaud Minier } 1371d6b55a0fSArnaud Minier }; 1372d6b55a0fSArnaud Minier 1373d6b55a0fSArnaud Minier 1374d6b55a0fSArnaud Minier static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp) 1375d6b55a0fSArnaud Minier { 1376d6b55a0fSArnaud Minier Stm32l4x5RccState *s = STM32L4X5_RCC(dev); 1377ec7d83acSArnaud Minier size_t i; 1378d6b55a0fSArnaud Minier 1379d6b55a0fSArnaud Minier if (s->hse_frequency < 4000000ULL || 1380d6b55a0fSArnaud Minier s->hse_frequency > 48000000ULL) { 1381d6b55a0fSArnaud Minier error_setg(errp, 1382d6b55a0fSArnaud Minier "HSE frequency is outside of the allowed [4-48]Mhz range: %" PRIx64 "", 1383d6b55a0fSArnaud Minier s->hse_frequency); 1384d6b55a0fSArnaud Minier return; 1385d6b55a0fSArnaud Minier } 1386d6b55a0fSArnaud Minier 13876487653eSArnaud Minier for (i = 0; i < RCC_NUM_PLL; i++) { 13886487653eSArnaud Minier RccPllState *pll = &s->plls[i]; 13896487653eSArnaud Minier 13906487653eSArnaud Minier clock_set_source(pll->in, s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].out); 13916487653eSArnaud Minier 13926487653eSArnaud Minier if (!qdev_realize(DEVICE(pll), NULL, errp)) { 13936487653eSArnaud Minier return; 13946487653eSArnaud Minier } 13956487653eSArnaud Minier } 13966487653eSArnaud Minier 1397ec7d83acSArnaud Minier for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) { 1398ec7d83acSArnaud Minier RccClockMuxState *clock_mux = &s->clock_muxes[i]; 1399ec7d83acSArnaud Minier 1400141c29a2SArnaud Minier connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping); 1401141c29a2SArnaud Minier 1402ec7d83acSArnaud Minier if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) { 1403ec7d83acSArnaud Minier return; 1404ec7d83acSArnaud Minier } 1405ec7d83acSArnaud Minier } 1406ec7d83acSArnaud Minier 1407141c29a2SArnaud Minier /* 1408141c29a2SArnaud Minier * Start clocks after everything is connected 1409141c29a2SArnaud Minier * to propagate the frequencies along the tree. 1410141c29a2SArnaud Minier */ 1411d6b55a0fSArnaud Minier clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); 1412d6b55a0fSArnaud Minier clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); 1413d6b55a0fSArnaud Minier clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); 1414d6b55a0fSArnaud Minier clock_update(s->gnd, 0); 1415d6b55a0fSArnaud Minier } 1416d6b55a0fSArnaud Minier 1417d6b55a0fSArnaud Minier static Property stm32l4x5_rcc_properties[] = { 1418d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState, 1419d6b55a0fSArnaud Minier hse_frequency, HSE_DEFAULT_FRQ), 1420d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState, 1421d6b55a0fSArnaud Minier sai1_extclk_frequency, 0), 1422d6b55a0fSArnaud Minier DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState, 1423d6b55a0fSArnaud Minier sai2_extclk_frequency, 0), 1424d6b55a0fSArnaud Minier DEFINE_PROP_END_OF_LIST(), 1425d6b55a0fSArnaud Minier }; 1426d6b55a0fSArnaud Minier 1427d6b55a0fSArnaud Minier static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data) 1428d6b55a0fSArnaud Minier { 1429d6b55a0fSArnaud Minier DeviceClass *dc = DEVICE_CLASS(klass); 1430d6b55a0fSArnaud Minier ResettableClass *rc = RESETTABLE_CLASS(klass); 1431d6b55a0fSArnaud Minier 1432141c29a2SArnaud Minier assert(ARRAY_SIZE(CLOCK_MUX_INIT_INFO) == RCC_NUM_CLOCK_MUX); 1433d6b55a0fSArnaud Minier 1434d6b55a0fSArnaud Minier rc->phases.hold = stm32l4x5_rcc_reset_hold; 1435d6b55a0fSArnaud Minier device_class_set_props(dc, stm32l4x5_rcc_properties); 1436d6b55a0fSArnaud Minier dc->realize = stm32l4x5_rcc_realize; 1437d6b55a0fSArnaud Minier dc->vmsd = &vmstate_stm32l4x5_rcc; 1438d6b55a0fSArnaud Minier } 1439d6b55a0fSArnaud Minier 1440d6b55a0fSArnaud Minier static const TypeInfo stm32l4x5_rcc_types[] = { 1441d6b55a0fSArnaud Minier { 1442d6b55a0fSArnaud Minier .name = TYPE_STM32L4X5_RCC, 1443d6b55a0fSArnaud Minier .parent = TYPE_SYS_BUS_DEVICE, 1444d6b55a0fSArnaud Minier .instance_size = sizeof(Stm32l4x5RccState), 1445d6b55a0fSArnaud Minier .instance_init = stm32l4x5_rcc_init, 1446d6b55a0fSArnaud Minier .class_init = stm32l4x5_rcc_class_init, 1447ec7d83acSArnaud Minier }, { 1448ec7d83acSArnaud Minier .name = TYPE_RCC_CLOCK_MUX, 1449ec7d83acSArnaud Minier .parent = TYPE_DEVICE, 1450ec7d83acSArnaud Minier .instance_size = sizeof(RccClockMuxState), 1451ec7d83acSArnaud Minier .instance_init = clock_mux_init, 1452ec7d83acSArnaud Minier .class_init = clock_mux_class_init, 14536487653eSArnaud Minier }, { 14546487653eSArnaud Minier .name = TYPE_RCC_PLL, 14556487653eSArnaud Minier .parent = TYPE_DEVICE, 14566487653eSArnaud Minier .instance_size = sizeof(RccPllState), 14576487653eSArnaud Minier .instance_init = pll_init, 14586487653eSArnaud Minier .class_init = pll_class_init, 1459d6b55a0fSArnaud Minier } 1460d6b55a0fSArnaud Minier }; 1461d6b55a0fSArnaud Minier 1462d6b55a0fSArnaud Minier DEFINE_TYPES(stm32l4x5_rcc_types) 1463