xref: /openbmc/qemu/hw/misc/stm32l4x5_rcc.c (revision 20516e8d)
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  */
clock_mux_update(RccClockMuxState * mux,bool bypass_source)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 
6432da7e20SArnaud 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 
clock_mux_src_update(void * opaque,ClockEvent event)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 
clock_mux_init(Object * obj)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 
clock_mux_reset_enter(Object * obj,ResetType type)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 
clock_mux_reset_hold(Object * obj,ResetType type)116ad80e367SPeter Maydell static void clock_mux_reset_hold(Object *obj, ResetType type)
117141c29a2SArnaud Minier {
118141c29a2SArnaud Minier     RccClockMuxState *s = RCC_CLOCK_MUX(obj);
119141c29a2SArnaud Minier     clock_mux_update(s, true);
120141c29a2SArnaud Minier }
121141c29a2SArnaud Minier 
clock_mux_reset_exit(Object * obj,ResetType type)122ad80e367SPeter Maydell static void clock_mux_reset_exit(Object *obj, ResetType type)
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 
clock_mux_class_init(ObjectClass * klass,void * data)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 
clock_mux_set_enable(RccClockMuxState * mux,bool enabled)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 
clock_mux_set_factor(RccClockMuxState * mux,uint32_t multiplier,uint32_t divider)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 
clock_mux_set_source(RccClockMuxState * mux,RccClockMuxSource src)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  */
pll_update(RccPllState * pll,bool bypass_source)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 
pll_src_update(void * opaque,ClockEvent event)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 
pll_init(Object * obj)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 
pll_reset_enter(Object * obj,ResetType type)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 
pll_reset_hold(Object * obj,ResetType type)266ad80e367SPeter Maydell static void pll_reset_hold(Object *obj, ResetType type)
267141c29a2SArnaud Minier {
268141c29a2SArnaud Minier     RccPllState *s = RCC_PLL(obj);
269141c29a2SArnaud Minier     pll_update(s, true);
270141c29a2SArnaud Minier }
271141c29a2SArnaud Minier 
pll_reset_exit(Object * obj,ResetType type)272ad80e367SPeter Maydell static void pll_reset_exit(Object *obj, ResetType type)
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 
pll_class_init(ObjectClass * klass,void * data)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 
pll_set_vco_multiplier(RccPllState * pll,uint32_t vco_multiplier)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 
pll_set_enable(RccPllState * pll,bool enabled)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 
pll_set_channel_enable(RccPllState * pll,PllCommonChannels channel,bool enabled)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 
pll_set_channel_divider(RccPllState * pll,PllCommonChannels channel,uint32_t divider)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 
rcc_update_irq(Stm32l4x5RccState * s)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 
rcc_update_msi(Stm32l4x5RccState * s,uint32_t previous_value)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 
rcc_update_cr_register(Stm32l4x5RccState * s,uint32_t previous_value)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 
rcc_update_cfgr_register(Stm32l4x5RccState * s)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);
546*20516e8dSZheyu Ma     if (val > 0b100) {
547*20516e8dSZheyu Ma         qemu_log_mask(LOG_GUEST_ERROR,
548*20516e8dSZheyu Ma                       "%s: Invalid MCOPRE value: 0x%"PRIx32"\n",
549*20516e8dSZheyu Ma                       __func__, val);
550*20516e8dSZheyu Ma         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false);
551*20516e8dSZheyu Ma     } else {
5529c796d50SArnaud Minier         clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_MCO],
5539c796d50SArnaud Minier                              1, 1 << val);
554*20516e8dSZheyu Ma     }
5559c796d50SArnaud Minier 
5569c796d50SArnaud Minier     /* MCOSEL */
5579c796d50SArnaud Minier     val = FIELD_EX32(s->cfgr, CFGR, MCOSEL);
558*20516e8dSZheyu Ma     if (val > 0b111) {
559*20516e8dSZheyu Ma         qemu_log_mask(LOG_GUEST_ERROR,
560*20516e8dSZheyu Ma                       "%s: Invalid MCOSEL value: 0x%"PRIx32"\n",
561*20516e8dSZheyu Ma                       __func__, val);
562*20516e8dSZheyu Ma         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false);
563*20516e8dSZheyu Ma     } else {
5649c796d50SArnaud Minier         if (val == 0) {
5659c796d50SArnaud Minier             clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false);
5669c796d50SArnaud Minier         } else {
5679c796d50SArnaud Minier             clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], true);
5689c796d50SArnaud Minier             clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_MCO],
5699c796d50SArnaud Minier                                  val - 1);
5709c796d50SArnaud Minier         }
571*20516e8dSZheyu Ma     }
5729c796d50SArnaud Minier 
5739c796d50SArnaud Minier     /* STOPWUCK */
5749c796d50SArnaud Minier     /* TODO */
5759c796d50SArnaud Minier 
5769c796d50SArnaud Minier     /* PPRE2 */
5779c796d50SArnaud Minier     val = FIELD_EX32(s->cfgr, CFGR, PPRE2);
5789c796d50SArnaud Minier     if (val < 0b100) {
5799c796d50SArnaud Minier         clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK2],
5809c796d50SArnaud Minier                              1, 1);
5819c796d50SArnaud Minier     } else {
5829c796d50SArnaud Minier         clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK2],
5839c796d50SArnaud Minier                              1, 1 << (val - 0b11));
5849c796d50SArnaud Minier     }
5859c796d50SArnaud Minier 
5869c796d50SArnaud Minier     /* PPRE1 */
5879c796d50SArnaud Minier     val = FIELD_EX32(s->cfgr, CFGR, PPRE1);
5889c796d50SArnaud Minier     if (val < 0b100) {
5899c796d50SArnaud Minier         clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK1],
5909c796d50SArnaud Minier                              1, 1);
5919c796d50SArnaud Minier     } else {
5929c796d50SArnaud Minier         clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK1],
5939c796d50SArnaud Minier                              1, 1 << (val - 0b11));
5949c796d50SArnaud Minier     }
5959c796d50SArnaud Minier 
5969c796d50SArnaud Minier     /* HPRE */
5979c796d50SArnaud Minier     val = FIELD_EX32(s->cfgr, CFGR, HPRE);
5989c796d50SArnaud Minier     if (val < 0b1000) {
5999c796d50SArnaud Minier         clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_HCLK],
6009c796d50SArnaud Minier                              1, 1);
6019c796d50SArnaud Minier     } else {
6029c796d50SArnaud Minier         clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_HCLK],
6039c796d50SArnaud Minier                              1, 1 << (val - 0b111));
6049c796d50SArnaud Minier     }
6059c796d50SArnaud Minier 
6069c796d50SArnaud Minier     /* Update SWS */
6079c796d50SArnaud Minier     val = FIELD_EX32(s->cfgr, CFGR, SW);
6089c796d50SArnaud Minier     clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_SYSCLK],
6099c796d50SArnaud Minier                          val);
6109c796d50SArnaud Minier     s->cfgr &= ~R_CFGR_SWS_MASK;
6119c796d50SArnaud Minier     s->cfgr |= val << R_CFGR_SWS_SHIFT;
6129c796d50SArnaud Minier }
6139c796d50SArnaud Minier 
rcc_update_ahb1enr(Stm32l4x5RccState * s)6149c796d50SArnaud Minier static void rcc_update_ahb1enr(Stm32l4x5RccState *s)
6159c796d50SArnaud Minier {
6169c796d50SArnaud Minier     #define AHB1ENR_SET_ENABLE(_peripheral_name) \
6179c796d50SArnaud Minier         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \
6189c796d50SArnaud Minier             FIELD_EX32(s->ahb1enr, AHB1ENR, _peripheral_name##EN))
6199c796d50SArnaud Minier 
6209c796d50SArnaud Minier     /* DMA2DEN: reserved for STM32L475xx */
6219c796d50SArnaud Minier     AHB1ENR_SET_ENABLE(TSC);
6229c796d50SArnaud Minier     AHB1ENR_SET_ENABLE(CRC);
6239c796d50SArnaud Minier     AHB1ENR_SET_ENABLE(FLASH);
6249c796d50SArnaud Minier     AHB1ENR_SET_ENABLE(DMA2);
6259c796d50SArnaud Minier     AHB1ENR_SET_ENABLE(DMA1);
6269c796d50SArnaud Minier 
6279c796d50SArnaud Minier     #undef AHB1ENR_SET_ENABLE
6289c796d50SArnaud Minier }
6299c796d50SArnaud Minier 
rcc_update_ahb2enr(Stm32l4x5RccState * s)6309c796d50SArnaud Minier static void rcc_update_ahb2enr(Stm32l4x5RccState *s)
6319c796d50SArnaud Minier {
6329c796d50SArnaud Minier     #define AHB2ENR_SET_ENABLE(_peripheral_name) \
6339c796d50SArnaud Minier         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \
6349c796d50SArnaud Minier             FIELD_EX32(s->ahb2enr, AHB2ENR, _peripheral_name##EN))
6359c796d50SArnaud Minier 
6369c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(RNG);
6379c796d50SArnaud Minier     /* HASHEN: reserved for STM32L475xx */
6389c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(AES);
6399c796d50SArnaud Minier     /* DCMIEN: reserved for STM32L475xx */
6409c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(ADC);
6419c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(OTGFS);
6429c796d50SArnaud Minier     /* GPIOIEN: reserved for STM32L475xx */
6439c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(GPIOA);
6449c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(GPIOB);
6459c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(GPIOC);
6469c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(GPIOD);
6479c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(GPIOE);
6489c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(GPIOF);
6499c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(GPIOG);
6509c796d50SArnaud Minier     AHB2ENR_SET_ENABLE(GPIOH);
6519c796d50SArnaud Minier 
6529c796d50SArnaud Minier     #undef AHB2ENR_SET_ENABLE
6539c796d50SArnaud Minier }
6549c796d50SArnaud Minier 
rcc_update_ahb3enr(Stm32l4x5RccState * s)6559c796d50SArnaud Minier static void rcc_update_ahb3enr(Stm32l4x5RccState *s)
6569c796d50SArnaud Minier {
6579c796d50SArnaud Minier     #define AHB3ENR_SET_ENABLE(_peripheral_name) \
6589c796d50SArnaud Minier         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \
6599c796d50SArnaud Minier             FIELD_EX32(s->ahb3enr, AHB3ENR, _peripheral_name##EN))
6609c796d50SArnaud Minier 
6619c796d50SArnaud Minier     AHB3ENR_SET_ENABLE(QSPI);
6629c796d50SArnaud Minier     AHB3ENR_SET_ENABLE(FMC);
6639c796d50SArnaud Minier 
6649c796d50SArnaud Minier     #undef AHB3ENR_SET_ENABLE
6659c796d50SArnaud Minier }
6669c796d50SArnaud Minier 
rcc_update_apb1enr(Stm32l4x5RccState * s)6679c796d50SArnaud Minier static void rcc_update_apb1enr(Stm32l4x5RccState *s)
6689c796d50SArnaud Minier {
6699c796d50SArnaud Minier     #define APB1ENR1_SET_ENABLE(_peripheral_name) \
6709c796d50SArnaud Minier         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \
6719c796d50SArnaud Minier             FIELD_EX32(s->apb1enr1, APB1ENR1, _peripheral_name##EN))
6729c796d50SArnaud Minier     #define APB1ENR2_SET_ENABLE(_peripheral_name) \
6739c796d50SArnaud Minier         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \
6749c796d50SArnaud Minier             FIELD_EX32(s->apb1enr2, APB1ENR2, _peripheral_name##EN))
6759c796d50SArnaud Minier 
6769c796d50SArnaud Minier     /* APB1ENR1 */
6779c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(LPTIM1);
6789c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(OPAMP);
6799c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(DAC1);
6809c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(PWR);
6819c796d50SArnaud Minier     /* CAN2: reserved for STM32L4x5 */
6829c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(CAN1);
6839c796d50SArnaud Minier     /* CRSEN: reserved for STM32L4x5 */
6849c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(I2C3);
6859c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(I2C2);
6869c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(I2C1);
6879c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(UART5);
6889c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(UART4);
6899c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(USART3);
6909c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(USART2);
6919c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(SPI3);
6929c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(SPI2);
6939c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(WWDG);
6949c796d50SArnaud Minier     /* RTCAPB: reserved for STM32L4x5 */
6959c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(LCD);
6969c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(TIM7);
6979c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(TIM6);
6989c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(TIM5);
6999c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(TIM4);
7009c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(TIM3);
7019c796d50SArnaud Minier     APB1ENR1_SET_ENABLE(TIM2);
7029c796d50SArnaud Minier 
7039c796d50SArnaud Minier     /* APB1ENR2 */
7049c796d50SArnaud Minier     APB1ENR2_SET_ENABLE(LPTIM2);
7059c796d50SArnaud Minier     APB1ENR2_SET_ENABLE(SWPMI1);
7069c796d50SArnaud Minier     /* I2C4EN: reserved for STM32L4x5 */
7079c796d50SArnaud Minier     APB1ENR2_SET_ENABLE(LPUART1);
7089c796d50SArnaud Minier 
7099c796d50SArnaud Minier     #undef APB1ENR1_SET_ENABLE
7109c796d50SArnaud Minier     #undef APB1ENR2_SET_ENABLE
7119c796d50SArnaud Minier }
7129c796d50SArnaud Minier 
rcc_update_apb2enr(Stm32l4x5RccState * s)7139c796d50SArnaud Minier static void rcc_update_apb2enr(Stm32l4x5RccState *s)
7149c796d50SArnaud Minier {
7159c796d50SArnaud Minier     #define APB2ENR_SET_ENABLE(_peripheral_name) \
7169c796d50SArnaud Minier         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \
7179c796d50SArnaud Minier             FIELD_EX32(s->apb2enr, APB2ENR, _peripheral_name##EN))
7189c796d50SArnaud Minier 
7199c796d50SArnaud Minier     APB2ENR_SET_ENABLE(DFSDM1);
7209c796d50SArnaud Minier     APB2ENR_SET_ENABLE(SAI2);
7219c796d50SArnaud Minier     APB2ENR_SET_ENABLE(SAI1);
7229c796d50SArnaud Minier     APB2ENR_SET_ENABLE(TIM17);
7239c796d50SArnaud Minier     APB2ENR_SET_ENABLE(TIM16);
7249c796d50SArnaud Minier     APB2ENR_SET_ENABLE(TIM15);
7259c796d50SArnaud Minier     APB2ENR_SET_ENABLE(USART1);
7269c796d50SArnaud Minier     APB2ENR_SET_ENABLE(TIM8);
7279c796d50SArnaud Minier     APB2ENR_SET_ENABLE(SPI1);
7289c796d50SArnaud Minier     APB2ENR_SET_ENABLE(TIM1);
7299c796d50SArnaud Minier     APB2ENR_SET_ENABLE(SDMMC1);
7309c796d50SArnaud Minier     APB2ENR_SET_ENABLE(FW);
7319c796d50SArnaud Minier     APB2ENR_SET_ENABLE(SYSCFG);
7329c796d50SArnaud Minier 
7339c796d50SArnaud Minier     #undef APB2ENR_SET_ENABLE
7349c796d50SArnaud Minier }
7359c796d50SArnaud Minier 
7369c796d50SArnaud Minier /*
7379c796d50SArnaud Minier  * The 3 PLLs share the same register layout
7389c796d50SArnaud Minier  * so we can use the same function for all of them
7399c796d50SArnaud Minier  * Note: no frequency bounds checking is done here.
7409c796d50SArnaud Minier  */
rcc_update_pllsaixcfgr(Stm32l4x5RccState * s,RccPll pll_id)7419c796d50SArnaud Minier static void rcc_update_pllsaixcfgr(Stm32l4x5RccState *s, RccPll pll_id)
7429c796d50SArnaud Minier {
7439c796d50SArnaud Minier     uint32_t reg, val;
7449c796d50SArnaud Minier     switch (pll_id) {
7459c796d50SArnaud Minier     case RCC_PLL_PLL:
7469c796d50SArnaud Minier         reg = s->pllcfgr;
7479c796d50SArnaud Minier         break;
7489c796d50SArnaud Minier     case RCC_PLL_PLLSAI1:
7499c796d50SArnaud Minier         reg = s->pllsai1cfgr;
7509c796d50SArnaud Minier         break;
7519c796d50SArnaud Minier     case RCC_PLL_PLLSAI2:
7529c796d50SArnaud Minier         reg = s->pllsai2cfgr;
7539c796d50SArnaud Minier         break;
7549c796d50SArnaud Minier     default:
7559c796d50SArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
7569c796d50SArnaud Minier                       "%s: Invalid PLL ID: %u\n", __func__, pll_id);
7579c796d50SArnaud Minier         return;
7589c796d50SArnaud Minier     }
7599c796d50SArnaud Minier 
7609c796d50SArnaud Minier     /* PLLPDIV */
7619c796d50SArnaud Minier     val = FIELD_EX32(reg, PLLCFGR, PLLPDIV);
7629c796d50SArnaud Minier     /* 1 is a reserved value */
7639c796d50SArnaud Minier     if (val == 0) {
7649c796d50SArnaud Minier         /* Get PLLP value */
7659c796d50SArnaud Minier         val = FIELD_EX32(reg, PLLCFGR, PLLP);
7669c796d50SArnaud Minier         pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P,
7679c796d50SArnaud Minier             (val ? 17 : 7));
7689c796d50SArnaud Minier     } else if (val > 1) {
7699c796d50SArnaud Minier         pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P,
7709c796d50SArnaud Minier             val);
7719c796d50SArnaud Minier     }
7729c796d50SArnaud Minier 
7739c796d50SArnaud Minier 
7749c796d50SArnaud Minier     /* PLLR */
7759c796d50SArnaud Minier     val = FIELD_EX32(reg, PLLCFGR, PLLR);
7769c796d50SArnaud Minier     pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_R,
7779c796d50SArnaud Minier         2 * (val + 1));
7789c796d50SArnaud Minier 
7799c796d50SArnaud Minier     /* PLLREN */
7809c796d50SArnaud Minier     val = FIELD_EX32(reg, PLLCFGR, PLLREN);
7819c796d50SArnaud Minier     pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_R, val);
7829c796d50SArnaud Minier 
7839c796d50SArnaud Minier     /* PLLQ */
7849c796d50SArnaud Minier     val = FIELD_EX32(reg, PLLCFGR, PLLQ);
7859c796d50SArnaud Minier     pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_Q,
7869c796d50SArnaud Minier         2 * (val + 1));
7879c796d50SArnaud Minier 
7889c796d50SArnaud Minier     /* PLLQEN */
7899c796d50SArnaud Minier     val = FIELD_EX32(reg, PLLCFGR, PLLQEN);
7909c796d50SArnaud Minier     pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_Q, val);
7919c796d50SArnaud Minier 
7929c796d50SArnaud Minier     /* PLLPEN */
7939c796d50SArnaud Minier     val = FIELD_EX32(reg, PLLCFGR, PLLPEN);
7949c796d50SArnaud Minier     pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, val);
7959c796d50SArnaud Minier 
7969c796d50SArnaud Minier     /* PLLN */
7979c796d50SArnaud Minier     val = FIELD_EX32(reg, PLLCFGR, PLLN);
7989c796d50SArnaud Minier     pll_set_vco_multiplier(&s->plls[pll_id], val);
7999c796d50SArnaud Minier }
8009c796d50SArnaud Minier 
rcc_update_pllcfgr(Stm32l4x5RccState * s)8019c796d50SArnaud Minier static void rcc_update_pllcfgr(Stm32l4x5RccState *s)
8029c796d50SArnaud Minier {
8039c796d50SArnaud Minier     int val;
8049c796d50SArnaud Minier 
8059c796d50SArnaud Minier     /* Use common layout */
8069c796d50SArnaud Minier     rcc_update_pllsaixcfgr(s, RCC_PLL_PLL);
8079c796d50SArnaud Minier 
8089c796d50SArnaud Minier     /* Fetch specific fields for pllcfgr */
8099c796d50SArnaud Minier 
8109c796d50SArnaud Minier     /* PLLM */
8119c796d50SArnaud Minier     val = FIELD_EX32(s->pllcfgr, PLLCFGR, PLLM);
8129c796d50SArnaud Minier     clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], 1, (val + 1));
8139c796d50SArnaud Minier 
8149c796d50SArnaud Minier     /* PLLSRC */
8159c796d50SArnaud Minier     val = FIELD_EX32(s->pllcfgr, PLLCFGR, PLLSRC);
8169c796d50SArnaud Minier     if (val == 0) {
8179c796d50SArnaud Minier         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], false);
8189c796d50SArnaud Minier     } else {
8199c796d50SArnaud Minier         clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], val - 1);
8209c796d50SArnaud Minier         clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], true);
8219c796d50SArnaud Minier     }
8229c796d50SArnaud Minier }
8239c796d50SArnaud Minier 
rcc_update_ccipr(Stm32l4x5RccState * s)8249c796d50SArnaud Minier static void rcc_update_ccipr(Stm32l4x5RccState *s)
8259c796d50SArnaud Minier {
8269c796d50SArnaud Minier     #define CCIPR_SET_SOURCE(_peripheral_name) \
8279c796d50SArnaud Minier         clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_name], \
8289c796d50SArnaud Minier             FIELD_EX32(s->ccipr, CCIPR, _peripheral_name##SEL))
8299c796d50SArnaud Minier 
8309c796d50SArnaud Minier     CCIPR_SET_SOURCE(DFSDM1);
8319c796d50SArnaud Minier     CCIPR_SET_SOURCE(SWPMI1);
8329c796d50SArnaud Minier     CCIPR_SET_SOURCE(ADC);
8339c796d50SArnaud Minier     CCIPR_SET_SOURCE(CLK48);
8349c796d50SArnaud Minier     CCIPR_SET_SOURCE(SAI2);
8359c796d50SArnaud Minier     CCIPR_SET_SOURCE(SAI1);
8369c796d50SArnaud Minier     CCIPR_SET_SOURCE(LPTIM2);
8379c796d50SArnaud Minier     CCIPR_SET_SOURCE(LPTIM1);
8389c796d50SArnaud Minier     CCIPR_SET_SOURCE(I2C3);
8399c796d50SArnaud Minier     CCIPR_SET_SOURCE(I2C2);
8409c796d50SArnaud Minier     CCIPR_SET_SOURCE(I2C1);
8419c796d50SArnaud Minier     CCIPR_SET_SOURCE(LPUART1);
8429c796d50SArnaud Minier     CCIPR_SET_SOURCE(UART5);
8439c796d50SArnaud Minier     CCIPR_SET_SOURCE(UART4);
8449c796d50SArnaud Minier     CCIPR_SET_SOURCE(USART3);
8459c796d50SArnaud Minier     CCIPR_SET_SOURCE(USART2);
8469c796d50SArnaud Minier     CCIPR_SET_SOURCE(USART1);
8479c796d50SArnaud Minier 
8489c796d50SArnaud Minier     #undef CCIPR_SET_SOURCE
8499c796d50SArnaud Minier }
8509c796d50SArnaud Minier 
rcc_update_bdcr(Stm32l4x5RccState * s)8519c796d50SArnaud Minier static void rcc_update_bdcr(Stm32l4x5RccState *s)
8529c796d50SArnaud Minier {
8539c796d50SArnaud Minier     int val;
8549c796d50SArnaud Minier 
8559c796d50SArnaud Minier     /* LSCOSEL */
8569c796d50SArnaud Minier     val = FIELD_EX32(s->bdcr, BDCR, LSCOSEL);
8579c796d50SArnaud Minier     clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_LSCO], val);
8589c796d50SArnaud Minier 
8599c796d50SArnaud Minier     val = FIELD_EX32(s->bdcr, BDCR, LSCOEN);
8609c796d50SArnaud Minier     clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_LSCO], val);
8619c796d50SArnaud Minier 
8629c796d50SArnaud Minier     /* BDRST */
8639c796d50SArnaud Minier     /*
8649c796d50SArnaud Minier      * The documentation is not clear if the RTCEN flag disables the RTC and
8659c796d50SArnaud Minier      * the LCD common mux or if it only affects the RTC.
8669c796d50SArnaud Minier      * As the LCDEN flag exists, we assume here that it only affects the RTC.
8679c796d50SArnaud Minier      */
8689c796d50SArnaud Minier     val = FIELD_EX32(s->bdcr, BDCR, RTCEN);
8699c796d50SArnaud Minier     clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_RTC], val);
8709c796d50SArnaud Minier     /* LCD and RTC share the same clock */
8719c796d50SArnaud Minier     val = FIELD_EX32(s->bdcr, BDCR, RTCSEL);
8729c796d50SArnaud Minier     clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON], val);
8739c796d50SArnaud Minier 
8749c796d50SArnaud Minier     /* LSECSSON */
8759c796d50SArnaud Minier     /* LSEDRV[1:0] */
8769c796d50SArnaud Minier     /* LSEBYP */
8779c796d50SArnaud Minier 
8789c796d50SArnaud Minier     /* LSEON: Update LSERDY at the same time */
8799c796d50SArnaud Minier     val = FIELD_EX32(s->bdcr, BDCR, LSEON);
8809c796d50SArnaud Minier     if (val) {
8819c796d50SArnaud Minier         clock_update_hz(s->lse_crystal, LSE_FRQ);
8829c796d50SArnaud Minier         s->bdcr |= R_BDCR_LSERDY_MASK;
8839c796d50SArnaud Minier         if (s->cier & R_CIER_LSERDYIE_MASK) {
8849c796d50SArnaud Minier             s->cifr |= R_CIFR_LSERDYF_MASK;
8859c796d50SArnaud Minier         }
8869c796d50SArnaud Minier     } else {
8879c796d50SArnaud Minier         clock_update(s->lse_crystal, 0);
8889c796d50SArnaud Minier         s->bdcr &= ~R_BDCR_LSERDY_MASK;
8899c796d50SArnaud Minier     }
8909c796d50SArnaud Minier 
8919c796d50SArnaud Minier     rcc_update_irq(s);
8929c796d50SArnaud Minier }
8939c796d50SArnaud Minier 
rcc_update_csr(Stm32l4x5RccState * s)8949c796d50SArnaud Minier static void rcc_update_csr(Stm32l4x5RccState *s)
8959c796d50SArnaud Minier {
8969c796d50SArnaud Minier     int val;
8979c796d50SArnaud Minier 
8989c796d50SArnaud Minier     /* Reset flags: Not implemented */
8999c796d50SArnaud Minier     /* MSISRANGE: Not implemented after reset */
9009c796d50SArnaud Minier 
9019c796d50SArnaud Minier     /* LSION: Update LSIRDY at the same time */
9029c796d50SArnaud Minier     val = FIELD_EX32(s->csr, CSR, LSION);
9039c796d50SArnaud Minier     if (val) {
9049c796d50SArnaud Minier         clock_update_hz(s->lsi_rc, LSI_FRQ);
9059c796d50SArnaud Minier         s->csr |= R_CSR_LSIRDY_MASK;
9069c796d50SArnaud Minier         if (s->cier & R_CIER_LSIRDYIE_MASK) {
9079c796d50SArnaud Minier             s->cifr |= R_CIFR_LSIRDYF_MASK;
9089c796d50SArnaud Minier         }
9099c796d50SArnaud Minier     } else {
9109c796d50SArnaud Minier         /*
9119c796d50SArnaud Minier          * TODO: Handle when the LSI is set independently of LSION.
9129c796d50SArnaud Minier          * E.g. when the LSI is set by the RTC.
9139c796d50SArnaud Minier          * See the reference manual for more details.
9149c796d50SArnaud Minier          */
9159c796d50SArnaud Minier         clock_update(s->lsi_rc, 0);
9169c796d50SArnaud Minier         s->csr &= ~R_CSR_LSIRDY_MASK;
9179c796d50SArnaud Minier     }
9189c796d50SArnaud Minier 
9199c796d50SArnaud Minier     rcc_update_irq(s);
9209c796d50SArnaud Minier }
9219c796d50SArnaud Minier 
stm32l4x5_rcc_reset_hold(Object * obj,ResetType type)922ad80e367SPeter Maydell static void stm32l4x5_rcc_reset_hold(Object *obj, ResetType type)
923d6b55a0fSArnaud Minier {
924d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(obj);
925d6b55a0fSArnaud Minier     s->cr = 0x00000063;
926d6b55a0fSArnaud Minier     /*
927d6b55a0fSArnaud Minier      * Factory-programmed calibration data
928d6b55a0fSArnaud Minier      * From the reference manual: 0x10XX 00XX
929d6b55a0fSArnaud Minier      * Value taken from a real card.
930d6b55a0fSArnaud Minier      */
931d6b55a0fSArnaud Minier     s->icscr = 0x106E0082;
932d6b55a0fSArnaud Minier     s->cfgr = 0x0;
933d6b55a0fSArnaud Minier     s->pllcfgr = 0x00001000;
934d6b55a0fSArnaud Minier     s->pllsai1cfgr = 0x00001000;
935d6b55a0fSArnaud Minier     s->pllsai2cfgr = 0x00001000;
936d6b55a0fSArnaud Minier     s->cier = 0x0;
937d6b55a0fSArnaud Minier     s->cifr = 0x0;
938d6b55a0fSArnaud Minier     s->ahb1rstr = 0x0;
939d6b55a0fSArnaud Minier     s->ahb2rstr = 0x0;
940d6b55a0fSArnaud Minier     s->ahb3rstr = 0x0;
941d6b55a0fSArnaud Minier     s->apb1rstr1 = 0x0;
942d6b55a0fSArnaud Minier     s->apb1rstr2 = 0x0;
943d6b55a0fSArnaud Minier     s->apb2rstr = 0x0;
944d6b55a0fSArnaud Minier     s->ahb1enr = 0x00000100;
945d6b55a0fSArnaud Minier     s->ahb2enr = 0x0;
946d6b55a0fSArnaud Minier     s->ahb3enr = 0x0;
947d6b55a0fSArnaud Minier     s->apb1enr1 = 0x0;
948d6b55a0fSArnaud Minier     s->apb1enr2 = 0x0;
949d6b55a0fSArnaud Minier     s->apb2enr = 0x0;
950d6b55a0fSArnaud Minier     s->ahb1smenr = 0x00011303;
951d6b55a0fSArnaud Minier     s->ahb2smenr = 0x000532FF;
952d6b55a0fSArnaud Minier     s->ahb3smenr =  0x00000101;
953d6b55a0fSArnaud Minier     s->apb1smenr1 = 0xF2FECA3F;
954d6b55a0fSArnaud Minier     s->apb1smenr2 = 0x00000025;
955d6b55a0fSArnaud Minier     s->apb2smenr = 0x01677C01;
956d6b55a0fSArnaud Minier     s->ccipr = 0x0;
957d6b55a0fSArnaud Minier     s->bdcr = 0x0;
958d6b55a0fSArnaud Minier     s->csr = 0x0C000600;
959d6b55a0fSArnaud Minier }
960d6b55a0fSArnaud Minier 
stm32l4x5_rcc_read(void * opaque,hwaddr addr,unsigned int size)961d6b55a0fSArnaud Minier static uint64_t stm32l4x5_rcc_read(void *opaque, hwaddr addr,
962d6b55a0fSArnaud Minier                                      unsigned int size)
963d6b55a0fSArnaud Minier {
964d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = opaque;
965d6b55a0fSArnaud Minier     uint64_t retvalue = 0;
966d6b55a0fSArnaud Minier 
967d6b55a0fSArnaud Minier     switch (addr) {
968d6b55a0fSArnaud Minier     case A_CR:
969d6b55a0fSArnaud Minier         retvalue = s->cr;
970d6b55a0fSArnaud Minier         break;
971d6b55a0fSArnaud Minier     case A_ICSCR:
972d6b55a0fSArnaud Minier         retvalue = s->icscr;
973d6b55a0fSArnaud Minier         break;
974d6b55a0fSArnaud Minier     case A_CFGR:
975d6b55a0fSArnaud Minier         retvalue = s->cfgr;
976d6b55a0fSArnaud Minier         break;
977d6b55a0fSArnaud Minier     case A_PLLCFGR:
978d6b55a0fSArnaud Minier         retvalue = s->pllcfgr;
979d6b55a0fSArnaud Minier         break;
980d6b55a0fSArnaud Minier     case A_PLLSAI1CFGR:
981d6b55a0fSArnaud Minier         retvalue = s->pllsai1cfgr;
982d6b55a0fSArnaud Minier         break;
983d6b55a0fSArnaud Minier     case A_PLLSAI2CFGR:
984d6b55a0fSArnaud Minier         retvalue = s->pllsai2cfgr;
985d6b55a0fSArnaud Minier         break;
986d6b55a0fSArnaud Minier     case A_CIER:
987d6b55a0fSArnaud Minier         retvalue = s->cier;
988d6b55a0fSArnaud Minier         break;
989d6b55a0fSArnaud Minier     case A_CIFR:
990d6b55a0fSArnaud Minier         retvalue = s->cifr;
991d6b55a0fSArnaud Minier         break;
992d6b55a0fSArnaud Minier     case A_CICR:
993d6b55a0fSArnaud Minier         /* CICR is write only, return the reset value = 0 */
994d6b55a0fSArnaud Minier         break;
995d6b55a0fSArnaud Minier     case A_AHB1RSTR:
996d6b55a0fSArnaud Minier         retvalue = s->ahb1rstr;
997d6b55a0fSArnaud Minier         break;
998d6b55a0fSArnaud Minier     case A_AHB2RSTR:
999d6b55a0fSArnaud Minier         retvalue = s->ahb2rstr;
1000d6b55a0fSArnaud Minier         break;
1001d6b55a0fSArnaud Minier     case A_AHB3RSTR:
1002d6b55a0fSArnaud Minier         retvalue = s->ahb3rstr;
1003d6b55a0fSArnaud Minier         break;
1004d6b55a0fSArnaud Minier     case A_APB1RSTR1:
1005d6b55a0fSArnaud Minier         retvalue = s->apb1rstr1;
1006d6b55a0fSArnaud Minier         break;
1007d6b55a0fSArnaud Minier     case A_APB1RSTR2:
1008d6b55a0fSArnaud Minier         retvalue = s->apb1rstr2;
1009d6b55a0fSArnaud Minier         break;
1010d6b55a0fSArnaud Minier     case A_APB2RSTR:
1011d6b55a0fSArnaud Minier         retvalue = s->apb2rstr;
1012d6b55a0fSArnaud Minier         break;
1013d6b55a0fSArnaud Minier     case A_AHB1ENR:
1014d6b55a0fSArnaud Minier         retvalue = s->ahb1enr;
1015d6b55a0fSArnaud Minier         break;
1016d6b55a0fSArnaud Minier     case A_AHB2ENR:
1017d6b55a0fSArnaud Minier         retvalue = s->ahb2enr;
1018d6b55a0fSArnaud Minier         break;
1019d6b55a0fSArnaud Minier     case A_AHB3ENR:
1020d6b55a0fSArnaud Minier         retvalue = s->ahb3enr;
1021d6b55a0fSArnaud Minier         break;
1022d6b55a0fSArnaud Minier     case A_APB1ENR1:
1023d6b55a0fSArnaud Minier         retvalue = s->apb1enr1;
1024d6b55a0fSArnaud Minier         break;
1025d6b55a0fSArnaud Minier     case A_APB1ENR2:
1026d6b55a0fSArnaud Minier         retvalue = s->apb1enr2;
1027d6b55a0fSArnaud Minier         break;
1028d6b55a0fSArnaud Minier     case A_APB2ENR:
1029d6b55a0fSArnaud Minier         retvalue = s->apb2enr;
1030d6b55a0fSArnaud Minier         break;
1031d6b55a0fSArnaud Minier     case A_AHB1SMENR:
1032d6b55a0fSArnaud Minier         retvalue = s->ahb1smenr;
1033d6b55a0fSArnaud Minier         break;
1034d6b55a0fSArnaud Minier     case A_AHB2SMENR:
1035d6b55a0fSArnaud Minier         retvalue = s->ahb2smenr;
1036d6b55a0fSArnaud Minier         break;
1037d6b55a0fSArnaud Minier     case A_AHB3SMENR:
1038d6b55a0fSArnaud Minier         retvalue = s->ahb3smenr;
1039d6b55a0fSArnaud Minier         break;
1040d6b55a0fSArnaud Minier     case A_APB1SMENR1:
1041d6b55a0fSArnaud Minier         retvalue = s->apb1smenr1;
1042d6b55a0fSArnaud Minier         break;
1043d6b55a0fSArnaud Minier     case A_APB1SMENR2:
1044d6b55a0fSArnaud Minier         retvalue = s->apb1smenr2;
1045d6b55a0fSArnaud Minier         break;
1046d6b55a0fSArnaud Minier     case A_APB2SMENR:
1047d6b55a0fSArnaud Minier         retvalue = s->apb2smenr;
1048d6b55a0fSArnaud Minier         break;
1049d6b55a0fSArnaud Minier     case A_CCIPR:
1050d6b55a0fSArnaud Minier         retvalue = s->ccipr;
1051d6b55a0fSArnaud Minier         break;
1052d6b55a0fSArnaud Minier     case A_BDCR:
1053d6b55a0fSArnaud Minier         retvalue = s->bdcr;
1054d6b55a0fSArnaud Minier         break;
1055d6b55a0fSArnaud Minier     case A_CSR:
1056d6b55a0fSArnaud Minier         retvalue = s->csr;
1057d6b55a0fSArnaud Minier         break;
1058d6b55a0fSArnaud Minier     default:
1059d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
1060d6b55a0fSArnaud Minier                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
1061d6b55a0fSArnaud Minier         break;
1062d6b55a0fSArnaud Minier     }
1063d6b55a0fSArnaud Minier 
1064d6b55a0fSArnaud Minier     trace_stm32l4x5_rcc_read(addr, retvalue);
1065d6b55a0fSArnaud Minier 
1066d6b55a0fSArnaud Minier     return retvalue;
1067d6b55a0fSArnaud Minier }
1068d6b55a0fSArnaud Minier 
stm32l4x5_rcc_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)1069d6b55a0fSArnaud Minier static void stm32l4x5_rcc_write(void *opaque, hwaddr addr,
1070d6b55a0fSArnaud Minier                                   uint64_t val64, unsigned int size)
1071d6b55a0fSArnaud Minier {
1072d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = opaque;
10733b551477SArnaud Minier     uint32_t previous_value = 0;
1074d6b55a0fSArnaud Minier     const uint32_t value = val64;
1075d6b55a0fSArnaud Minier 
1076d6b55a0fSArnaud Minier     trace_stm32l4x5_rcc_write(addr, value);
1077d6b55a0fSArnaud Minier 
1078d6b55a0fSArnaud Minier     switch (addr) {
1079d6b55a0fSArnaud Minier     case A_CR:
10803b551477SArnaud Minier         previous_value = s->cr;
1081d6b55a0fSArnaud Minier         s->cr = (s->cr & CR_READ_SET_MASK) |
1082d6b55a0fSArnaud Minier                 (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK));
10833b551477SArnaud Minier         rcc_update_cr_register(s, previous_value);
1084d6b55a0fSArnaud Minier         break;
1085d6b55a0fSArnaud Minier     case A_ICSCR:
1086d6b55a0fSArnaud Minier         s->icscr = value & ~ICSCR_READ_ONLY_MASK;
10879c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
10889c796d50SArnaud Minier                 "%s: Side-effects not implemented for ICSCR\n", __func__);
1089d6b55a0fSArnaud Minier         break;
1090d6b55a0fSArnaud Minier     case A_CFGR:
1091d6b55a0fSArnaud Minier         s->cfgr = value & ~CFGR_READ_ONLY_MASK;
10929c796d50SArnaud Minier         rcc_update_cfgr_register(s);
1093d6b55a0fSArnaud Minier         break;
1094d6b55a0fSArnaud Minier     case A_PLLCFGR:
1095d6b55a0fSArnaud Minier         s->pllcfgr = value;
10969c796d50SArnaud Minier         rcc_update_pllcfgr(s);
1097d6b55a0fSArnaud Minier         break;
1098d6b55a0fSArnaud Minier     case A_PLLSAI1CFGR:
1099d6b55a0fSArnaud Minier         s->pllsai1cfgr = value;
11009c796d50SArnaud Minier         rcc_update_pllsaixcfgr(s, RCC_PLL_PLLSAI1);
1101d6b55a0fSArnaud Minier         break;
1102d6b55a0fSArnaud Minier     case A_PLLSAI2CFGR:
1103d6b55a0fSArnaud Minier         s->pllsai2cfgr = value;
11049c796d50SArnaud Minier         rcc_update_pllsaixcfgr(s, RCC_PLL_PLLSAI2);
1105d6b55a0fSArnaud Minier         break;
1106d6b55a0fSArnaud Minier     case A_CIER:
1107d6b55a0fSArnaud Minier         s->cier = value;
11089c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11099c796d50SArnaud Minier                 "%s: Side-effects not implemented for CIER\n", __func__);
1110d6b55a0fSArnaud Minier         break;
1111d6b55a0fSArnaud Minier     case A_CIFR:
1112d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
1113d6b55a0fSArnaud Minier             "%s: Write attempt into read-only register (CIFR) 0x%"PRIx32"\n",
1114d6b55a0fSArnaud Minier             __func__, value);
1115d6b55a0fSArnaud Minier         break;
1116d6b55a0fSArnaud Minier     case A_CICR:
1117d6b55a0fSArnaud Minier         /* Clear interrupt flags by writing a 1 to the CICR register */
1118d6b55a0fSArnaud Minier         s->cifr &= ~value;
1119d6b55a0fSArnaud Minier         rcc_update_irq(s);
1120d6b55a0fSArnaud Minier         break;
1121d6b55a0fSArnaud Minier     /* Reset behaviors are not implemented */
1122d6b55a0fSArnaud Minier     case A_AHB1RSTR:
1123d6b55a0fSArnaud Minier         s->ahb1rstr = value;
11249c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11259c796d50SArnaud Minier                 "%s: Side-effects not implemented for AHB1RSTR\n", __func__);
1126d6b55a0fSArnaud Minier         break;
1127d6b55a0fSArnaud Minier     case A_AHB2RSTR:
1128d6b55a0fSArnaud Minier         s->ahb2rstr = value;
11299c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11309c796d50SArnaud Minier                 "%s: Side-effects not implemented for AHB2RSTR\n", __func__);
1131d6b55a0fSArnaud Minier         break;
1132d6b55a0fSArnaud Minier     case A_AHB3RSTR:
1133d6b55a0fSArnaud Minier         s->ahb3rstr = value;
11349c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11359c796d50SArnaud Minier                 "%s: Side-effects not implemented for AHB3RSTR\n", __func__);
1136d6b55a0fSArnaud Minier         break;
1137d6b55a0fSArnaud Minier     case A_APB1RSTR1:
1138d6b55a0fSArnaud Minier         s->apb1rstr1 = value;
11399c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11409c796d50SArnaud Minier                 "%s: Side-effects not implemented for APB1RSTR1\n", __func__);
1141d6b55a0fSArnaud Minier         break;
1142d6b55a0fSArnaud Minier     case A_APB1RSTR2:
1143d6b55a0fSArnaud Minier         s->apb1rstr2 = value;
11449c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11459c796d50SArnaud Minier                 "%s: Side-effects not implemented for APB1RSTR2\n", __func__);
1146d6b55a0fSArnaud Minier         break;
1147d6b55a0fSArnaud Minier     case A_APB2RSTR:
1148d6b55a0fSArnaud Minier         s->apb2rstr = value;
11499c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11509c796d50SArnaud Minier                 "%s: Side-effects not implemented for APB2RSTR\n", __func__);
1151d6b55a0fSArnaud Minier         break;
1152d6b55a0fSArnaud Minier     case A_AHB1ENR:
1153d6b55a0fSArnaud Minier         s->ahb1enr = value;
11549c796d50SArnaud Minier         rcc_update_ahb1enr(s);
1155d6b55a0fSArnaud Minier         break;
1156d6b55a0fSArnaud Minier     case A_AHB2ENR:
1157d6b55a0fSArnaud Minier         s->ahb2enr = value;
11589c796d50SArnaud Minier         rcc_update_ahb2enr(s);
1159d6b55a0fSArnaud Minier         break;
1160d6b55a0fSArnaud Minier     case A_AHB3ENR:
1161d6b55a0fSArnaud Minier         s->ahb3enr = value;
11629c796d50SArnaud Minier         rcc_update_ahb3enr(s);
1163d6b55a0fSArnaud Minier         break;
1164d6b55a0fSArnaud Minier     case A_APB1ENR1:
1165d6b55a0fSArnaud Minier         s->apb1enr1 = value;
11669c796d50SArnaud Minier         rcc_update_apb1enr(s);
1167d6b55a0fSArnaud Minier         break;
1168d6b55a0fSArnaud Minier     case A_APB1ENR2:
1169d6b55a0fSArnaud Minier         s->apb1enr2 = value;
11709c796d50SArnaud Minier         rcc_update_apb1enr(s);
1171d6b55a0fSArnaud Minier         break;
1172d6b55a0fSArnaud Minier     case A_APB2ENR:
1173d6b55a0fSArnaud Minier         s->apb2enr = (s->apb2enr & APB2ENR_READ_SET_MASK) | value;
11749c796d50SArnaud Minier         rcc_update_apb2enr(s);
1175d6b55a0fSArnaud Minier         break;
1176d6b55a0fSArnaud Minier     /* Behaviors for Sleep and Stop modes are not implemented */
1177d6b55a0fSArnaud Minier     case A_AHB1SMENR:
1178d6b55a0fSArnaud Minier         s->ahb1smenr = value;
11799c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11809c796d50SArnaud Minier                 "%s: Side-effects not implemented for AHB1SMENR\n", __func__);
1181d6b55a0fSArnaud Minier         break;
1182d6b55a0fSArnaud Minier     case A_AHB2SMENR:
1183d6b55a0fSArnaud Minier         s->ahb2smenr = value;
11849c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11859c796d50SArnaud Minier                 "%s: Side-effects not implemented for AHB2SMENR\n", __func__);
1186d6b55a0fSArnaud Minier         break;
1187d6b55a0fSArnaud Minier     case A_AHB3SMENR:
1188d6b55a0fSArnaud Minier         s->ahb3smenr = value;
11899c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11909c796d50SArnaud Minier                 "%s: Side-effects not implemented for AHB3SMENR\n", __func__);
1191d6b55a0fSArnaud Minier         break;
1192d6b55a0fSArnaud Minier     case A_APB1SMENR1:
1193d6b55a0fSArnaud Minier         s->apb1smenr1 = value;
11949c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
11959c796d50SArnaud Minier                 "%s: Side-effects not implemented for APB1SMENR1\n", __func__);
1196d6b55a0fSArnaud Minier         break;
1197d6b55a0fSArnaud Minier     case A_APB1SMENR2:
1198d6b55a0fSArnaud Minier         s->apb1smenr2 = value;
11999c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
12009c796d50SArnaud Minier                 "%s: Side-effects not implemented for APB1SMENR2\n", __func__);
1201d6b55a0fSArnaud Minier         break;
1202d6b55a0fSArnaud Minier     case A_APB2SMENR:
1203d6b55a0fSArnaud Minier         s->apb2smenr = value;
12049c796d50SArnaud Minier         qemu_log_mask(LOG_UNIMP,
12059c796d50SArnaud Minier                 "%s: Side-effects not implemented for APB2SMENR\n", __func__);
1206d6b55a0fSArnaud Minier         break;
1207d6b55a0fSArnaud Minier     case A_CCIPR:
1208d6b55a0fSArnaud Minier         s->ccipr = value;
12099c796d50SArnaud Minier         rcc_update_ccipr(s);
1210d6b55a0fSArnaud Minier         break;
1211d6b55a0fSArnaud Minier     case A_BDCR:
1212d6b55a0fSArnaud Minier         s->bdcr = value & ~BDCR_READ_ONLY_MASK;
12139c796d50SArnaud Minier         rcc_update_bdcr(s);
1214d6b55a0fSArnaud Minier         break;
1215d6b55a0fSArnaud Minier     case A_CSR:
1216d6b55a0fSArnaud Minier         s->csr = value & ~CSR_READ_ONLY_MASK;
12179c796d50SArnaud Minier         rcc_update_csr(s);
1218d6b55a0fSArnaud Minier         break;
1219d6b55a0fSArnaud Minier     default:
1220d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
1221d6b55a0fSArnaud Minier                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
1222d6b55a0fSArnaud Minier     }
1223d6b55a0fSArnaud Minier }
1224d6b55a0fSArnaud Minier 
1225d6b55a0fSArnaud Minier static const MemoryRegionOps stm32l4x5_rcc_ops = {
1226d6b55a0fSArnaud Minier     .read = stm32l4x5_rcc_read,
1227d6b55a0fSArnaud Minier     .write = stm32l4x5_rcc_write,
1228d6b55a0fSArnaud Minier     .endianness = DEVICE_NATIVE_ENDIAN,
1229d6b55a0fSArnaud Minier     .valid = {
1230d6b55a0fSArnaud Minier         .max_access_size = 4,
1231d6b55a0fSArnaud Minier         .min_access_size = 4,
1232d6b55a0fSArnaud Minier         .unaligned = false
1233d6b55a0fSArnaud Minier     },
1234d6b55a0fSArnaud Minier     .impl = {
1235d6b55a0fSArnaud Minier         .max_access_size = 4,
1236d6b55a0fSArnaud Minier         .min_access_size = 4,
1237d6b55a0fSArnaud Minier         .unaligned = false
1238d6b55a0fSArnaud Minier     },
1239d6b55a0fSArnaud Minier };
1240d6b55a0fSArnaud Minier 
1241d6b55a0fSArnaud Minier static const ClockPortInitArray stm32l4x5_rcc_clocks = {
1242d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, hsi16_rc, NULL, 0),
1243d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, msi_rc, NULL, 0),
1244d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, hse, NULL, 0),
1245d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, lsi_rc, NULL, 0),
1246d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, lse_crystal, NULL, 0),
1247d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, sai1_extclk, NULL, 0),
1248d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0),
1249d6b55a0fSArnaud Minier     QDEV_CLOCK_END
1250d6b55a0fSArnaud Minier };
1251d6b55a0fSArnaud Minier 
1252d6b55a0fSArnaud Minier 
stm32l4x5_rcc_init(Object * obj)1253d6b55a0fSArnaud Minier static void stm32l4x5_rcc_init(Object *obj)
1254d6b55a0fSArnaud Minier {
1255d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(obj);
1256ec7d83acSArnaud Minier     size_t i;
1257d6b55a0fSArnaud Minier 
1258d6b55a0fSArnaud Minier     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
1259d6b55a0fSArnaud Minier 
1260d6b55a0fSArnaud Minier     memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s,
1261d6b55a0fSArnaud Minier                           TYPE_STM32L4X5_RCC, 0x400);
1262d6b55a0fSArnaud Minier     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
1263d6b55a0fSArnaud Minier 
1264d6b55a0fSArnaud Minier     qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks);
1265d6b55a0fSArnaud Minier 
12666487653eSArnaud Minier     for (i = 0; i < RCC_NUM_PLL; i++) {
1267141c29a2SArnaud Minier         object_initialize_child(obj, PLL_INIT_INFO[i].name,
12686487653eSArnaud Minier                                 &s->plls[i], TYPE_RCC_PLL);
1269141c29a2SArnaud Minier         set_pll_init_info(&s->plls[i], i);
12706487653eSArnaud Minier     }
12716487653eSArnaud Minier 
1272ec7d83acSArnaud Minier     for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) {
1273141c29a2SArnaud Minier         char *alias;
1274ec7d83acSArnaud Minier 
1275141c29a2SArnaud Minier         object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name,
1276ec7d83acSArnaud Minier                                 &s->clock_muxes[i],
1277ec7d83acSArnaud Minier                                 TYPE_RCC_CLOCK_MUX);
1278141c29a2SArnaud Minier         set_clock_mux_init_info(&s->clock_muxes[i], i);
1279ec7d83acSArnaud Minier 
1280141c29a2SArnaud Minier         if (!CLOCK_MUX_INIT_INFO[i].hidden) {
1281141c29a2SArnaud Minier             /* Expose muxes output as RCC outputs */
1282141c29a2SArnaud Minier             alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name);
1283141c29a2SArnaud Minier             qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias);
1284141c29a2SArnaud Minier             g_free(alias);
1285141c29a2SArnaud Minier         }
1286ec7d83acSArnaud Minier     }
1287ec7d83acSArnaud Minier 
1288d6b55a0fSArnaud Minier     s->gnd = clock_new(obj, "gnd");
1289d6b55a0fSArnaud Minier }
1290d6b55a0fSArnaud Minier 
connect_mux_sources(Stm32l4x5RccState * s,RccClockMuxState * mux,const RccClockMuxSource * clk_mapping)1291141c29a2SArnaud Minier static void connect_mux_sources(Stm32l4x5RccState *s,
1292141c29a2SArnaud Minier                                 RccClockMuxState *mux,
1293141c29a2SArnaud Minier                                 const RccClockMuxSource *clk_mapping)
1294141c29a2SArnaud Minier {
1295141c29a2SArnaud Minier     size_t i;
1296141c29a2SArnaud Minier 
1297141c29a2SArnaud Minier     Clock * const CLK_SRC_MAPPING[] = {
1298141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_GND] = s->gnd,
1299141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_HSI] = s->hsi16_rc,
1300141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_HSE] = s->hse,
1301141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_MSI] = s->msi_rc,
1302141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_LSI] = s->lsi_rc,
1303141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_LSE] = s->lse_crystal,
1304141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_SAI1_EXTCLK] = s->sai1_extclk,
1305141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_SAI2_EXTCLK] = s->sai2_extclk,
1306141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PLL] =
1307141c29a2SArnaud Minier             s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLCLK],
1308141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PLLSAI1] =
1309141c29a2SArnaud Minier             s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLSAI1CLK],
1310141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PLLSAI2] =
1311141c29a2SArnaud Minier             s->plls[RCC_PLL_PLLSAI2].channels[RCC_PLLSAI2_CHANNEL_PLLSAI2CLK],
1312141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PLLSAI3] =
1313141c29a2SArnaud Minier             s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLSAI3CLK],
1314141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PLL48M1] =
1315141c29a2SArnaud Minier             s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLL48M1CLK],
1316141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PLL48M2] =
1317141c29a2SArnaud Minier             s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLL48M2CLK],
1318141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PLLADC1] =
1319141c29a2SArnaud Minier             s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLADC1CLK],
1320141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PLLADC2] =
1321141c29a2SArnaud Minier             s->plls[RCC_PLL_PLLSAI2] .channels[RCC_PLLSAI2_CHANNEL_PLLADC2CLK],
1322141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_SYSCLK] = s->clock_muxes[RCC_CLOCK_MUX_SYSCLK].out,
1323141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_HCLK] = s->clock_muxes[RCC_CLOCK_MUX_HCLK].out,
1324141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PCLK1] = s->clock_muxes[RCC_CLOCK_MUX_PCLK1].out,
1325141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_PCLK2] = s->clock_muxes[RCC_CLOCK_MUX_PCLK2].out,
1326141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_HSE_OVER_32] = s->clock_muxes[RCC_CLOCK_MUX_HSE_OVER_32].out,
1327141c29a2SArnaud Minier         [RCC_CLOCK_MUX_SRC_LCD_AND_RTC_COMMON] =
1328141c29a2SArnaud Minier             s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON].out,
1329141c29a2SArnaud Minier     };
1330141c29a2SArnaud Minier 
1331141c29a2SArnaud Minier     assert(ARRAY_SIZE(CLK_SRC_MAPPING) == RCC_CLOCK_MUX_SRC_NUMBER);
1332141c29a2SArnaud Minier 
1333141c29a2SArnaud Minier     for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) {
1334141c29a2SArnaud Minier         RccClockMuxSource mapping = clk_mapping[i];
1335141c29a2SArnaud Minier         clock_set_source(mux->srcs[i], CLK_SRC_MAPPING[mapping]);
1336141c29a2SArnaud Minier     }
1337141c29a2SArnaud Minier }
1338141c29a2SArnaud Minier 
1339141c29a2SArnaud Minier 
1340d6b55a0fSArnaud Minier static const VMStateDescription vmstate_stm32l4x5_rcc = {
1341d6b55a0fSArnaud Minier     .name = TYPE_STM32L4X5_RCC,
1342d6b55a0fSArnaud Minier     .version_id = 1,
1343d6b55a0fSArnaud Minier     .minimum_version_id = 1,
1344d6b55a0fSArnaud Minier     .fields = (VMStateField[]) {
1345d6b55a0fSArnaud Minier         VMSTATE_UINT32(cr, Stm32l4x5RccState),
1346d6b55a0fSArnaud Minier         VMSTATE_UINT32(icscr, Stm32l4x5RccState),
1347d6b55a0fSArnaud Minier         VMSTATE_UINT32(cfgr, Stm32l4x5RccState),
1348d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllcfgr, Stm32l4x5RccState),
1349d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllsai1cfgr, Stm32l4x5RccState),
1350d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllsai2cfgr, Stm32l4x5RccState),
1351d6b55a0fSArnaud Minier         VMSTATE_UINT32(cier, Stm32l4x5RccState),
1352d6b55a0fSArnaud Minier         VMSTATE_UINT32(cifr, Stm32l4x5RccState),
1353d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1rstr, Stm32l4x5RccState),
1354d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2rstr, Stm32l4x5RccState),
1355d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3rstr, Stm32l4x5RccState),
1356d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1rstr1, Stm32l4x5RccState),
1357d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1rstr2, Stm32l4x5RccState),
1358d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2rstr, Stm32l4x5RccState),
1359d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1enr, Stm32l4x5RccState),
1360d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2enr, Stm32l4x5RccState),
1361d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3enr, Stm32l4x5RccState),
1362d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1enr1, Stm32l4x5RccState),
1363d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1enr2, Stm32l4x5RccState),
1364d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2enr, Stm32l4x5RccState),
1365d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1smenr, Stm32l4x5RccState),
1366d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2smenr, Stm32l4x5RccState),
1367d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3smenr, Stm32l4x5RccState),
1368d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1smenr1, Stm32l4x5RccState),
1369d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1smenr2, Stm32l4x5RccState),
1370d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2smenr, Stm32l4x5RccState),
1371d6b55a0fSArnaud Minier         VMSTATE_UINT32(ccipr, Stm32l4x5RccState),
1372d6b55a0fSArnaud Minier         VMSTATE_UINT32(bdcr, Stm32l4x5RccState),
1373d6b55a0fSArnaud Minier         VMSTATE_UINT32(csr, Stm32l4x5RccState),
1374d6b55a0fSArnaud Minier         VMSTATE_CLOCK(hsi16_rc, Stm32l4x5RccState),
1375d6b55a0fSArnaud Minier         VMSTATE_CLOCK(msi_rc, Stm32l4x5RccState),
1376d6b55a0fSArnaud Minier         VMSTATE_CLOCK(hse, Stm32l4x5RccState),
1377d6b55a0fSArnaud Minier         VMSTATE_CLOCK(lsi_rc, Stm32l4x5RccState),
1378d6b55a0fSArnaud Minier         VMSTATE_CLOCK(lse_crystal, Stm32l4x5RccState),
1379d6b55a0fSArnaud Minier         VMSTATE_CLOCK(sai1_extclk, Stm32l4x5RccState),
1380d6b55a0fSArnaud Minier         VMSTATE_CLOCK(sai2_extclk, Stm32l4x5RccState),
1381d6b55a0fSArnaud Minier         VMSTATE_END_OF_LIST()
1382d6b55a0fSArnaud Minier     }
1383d6b55a0fSArnaud Minier };
1384d6b55a0fSArnaud Minier 
1385d6b55a0fSArnaud Minier 
stm32l4x5_rcc_realize(DeviceState * dev,Error ** errp)1386d6b55a0fSArnaud Minier static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp)
1387d6b55a0fSArnaud Minier {
1388d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(dev);
1389ec7d83acSArnaud Minier     size_t i;
1390d6b55a0fSArnaud Minier 
1391d6b55a0fSArnaud Minier     if (s->hse_frequency <  4000000ULL ||
1392d6b55a0fSArnaud Minier         s->hse_frequency > 48000000ULL) {
1393d6b55a0fSArnaud Minier             error_setg(errp,
1394d6b55a0fSArnaud Minier                 "HSE frequency is outside of the allowed [4-48]Mhz range: %" PRIx64 "",
1395d6b55a0fSArnaud Minier                 s->hse_frequency);
1396d6b55a0fSArnaud Minier             return;
1397d6b55a0fSArnaud Minier         }
1398d6b55a0fSArnaud Minier 
13996487653eSArnaud Minier     for (i = 0; i < RCC_NUM_PLL; i++) {
14006487653eSArnaud Minier         RccPllState *pll = &s->plls[i];
14016487653eSArnaud Minier 
14026487653eSArnaud Minier         clock_set_source(pll->in, s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].out);
14036487653eSArnaud Minier 
14046487653eSArnaud Minier         if (!qdev_realize(DEVICE(pll), NULL, errp)) {
14056487653eSArnaud Minier             return;
14066487653eSArnaud Minier         }
14076487653eSArnaud Minier     }
14086487653eSArnaud Minier 
1409ec7d83acSArnaud Minier     for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) {
1410ec7d83acSArnaud Minier         RccClockMuxState *clock_mux = &s->clock_muxes[i];
1411ec7d83acSArnaud Minier 
1412141c29a2SArnaud Minier         connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping);
1413141c29a2SArnaud Minier 
1414ec7d83acSArnaud Minier         if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) {
1415ec7d83acSArnaud Minier             return;
1416ec7d83acSArnaud Minier         }
1417ec7d83acSArnaud Minier     }
1418ec7d83acSArnaud Minier 
1419141c29a2SArnaud Minier     /*
1420141c29a2SArnaud Minier      * Start clocks after everything is connected
1421141c29a2SArnaud Minier      * to propagate the frequencies along the tree.
1422141c29a2SArnaud Minier      */
1423d6b55a0fSArnaud Minier     clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ);
1424d6b55a0fSArnaud Minier     clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency);
1425d6b55a0fSArnaud Minier     clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency);
1426d6b55a0fSArnaud Minier     clock_update(s->gnd, 0);
1427d6b55a0fSArnaud Minier }
1428d6b55a0fSArnaud Minier 
1429d6b55a0fSArnaud Minier static Property stm32l4x5_rcc_properties[] = {
1430d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState,
1431d6b55a0fSArnaud Minier         hse_frequency, HSE_DEFAULT_FRQ),
1432d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState,
1433d6b55a0fSArnaud Minier         sai1_extclk_frequency, 0),
1434d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState,
1435d6b55a0fSArnaud Minier         sai2_extclk_frequency, 0),
1436d6b55a0fSArnaud Minier     DEFINE_PROP_END_OF_LIST(),
1437d6b55a0fSArnaud Minier };
1438d6b55a0fSArnaud Minier 
stm32l4x5_rcc_class_init(ObjectClass * klass,void * data)1439d6b55a0fSArnaud Minier static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data)
1440d6b55a0fSArnaud Minier {
1441d6b55a0fSArnaud Minier     DeviceClass *dc = DEVICE_CLASS(klass);
1442d6b55a0fSArnaud Minier     ResettableClass *rc = RESETTABLE_CLASS(klass);
1443d6b55a0fSArnaud Minier 
1444141c29a2SArnaud Minier     assert(ARRAY_SIZE(CLOCK_MUX_INIT_INFO) == RCC_NUM_CLOCK_MUX);
1445d6b55a0fSArnaud Minier 
1446d6b55a0fSArnaud Minier     rc->phases.hold = stm32l4x5_rcc_reset_hold;
1447d6b55a0fSArnaud Minier     device_class_set_props(dc, stm32l4x5_rcc_properties);
1448d6b55a0fSArnaud Minier     dc->realize = stm32l4x5_rcc_realize;
1449d6b55a0fSArnaud Minier     dc->vmsd = &vmstate_stm32l4x5_rcc;
1450d6b55a0fSArnaud Minier }
1451d6b55a0fSArnaud Minier 
1452d6b55a0fSArnaud Minier static const TypeInfo stm32l4x5_rcc_types[] = {
1453d6b55a0fSArnaud Minier     {
1454d6b55a0fSArnaud Minier         .name           = TYPE_STM32L4X5_RCC,
1455d6b55a0fSArnaud Minier         .parent         = TYPE_SYS_BUS_DEVICE,
1456d6b55a0fSArnaud Minier         .instance_size  = sizeof(Stm32l4x5RccState),
1457d6b55a0fSArnaud Minier         .instance_init  = stm32l4x5_rcc_init,
1458d6b55a0fSArnaud Minier         .class_init     = stm32l4x5_rcc_class_init,
1459ec7d83acSArnaud Minier     }, {
1460ec7d83acSArnaud Minier         .name = TYPE_RCC_CLOCK_MUX,
1461ec7d83acSArnaud Minier         .parent = TYPE_DEVICE,
1462ec7d83acSArnaud Minier         .instance_size = sizeof(RccClockMuxState),
1463ec7d83acSArnaud Minier         .instance_init = clock_mux_init,
1464ec7d83acSArnaud Minier         .class_init = clock_mux_class_init,
14656487653eSArnaud Minier     }, {
14666487653eSArnaud Minier         .name = TYPE_RCC_PLL,
14676487653eSArnaud Minier         .parent = TYPE_DEVICE,
14686487653eSArnaud Minier         .instance_size = sizeof(RccPllState),
14696487653eSArnaud Minier         .instance_init = pll_init,
14706487653eSArnaud Minier         .class_init = pll_class_init,
1471d6b55a0fSArnaud Minier     }
1472d6b55a0fSArnaud Minier };
1473d6b55a0fSArnaud Minier 
1474d6b55a0fSArnaud Minier DEFINE_TYPES(stm32l4x5_rcc_types)
1475