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