xref: /openbmc/qemu/hw/misc/stm32l4x5_rcc.c (revision 3b551477172801bbfb78bf8f58c512307785fd9e)
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