xref: /openbmc/qemu/hw/misc/stm32l4x5_rcc.c (revision 6487653e)
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 
39ec7d83acSArnaud Minier static void clock_mux_update(RccClockMuxState *mux)
40ec7d83acSArnaud Minier {
41ec7d83acSArnaud Minier     uint64_t src_freq;
42ec7d83acSArnaud Minier     Clock *current_source = mux->srcs[mux->src];
43ec7d83acSArnaud Minier     uint32_t freq_multiplier = 0;
44ec7d83acSArnaud Minier     /*
45ec7d83acSArnaud Minier      * To avoid rounding errors, we use the clock period instead of the
46ec7d83acSArnaud Minier      * frequency.
47ec7d83acSArnaud Minier      * This means that the multiplier of the mux becomes the divider of
48ec7d83acSArnaud Minier      * the clock and the divider of the mux becomes the multiplier of the
49ec7d83acSArnaud Minier      * clock.
50ec7d83acSArnaud Minier      */
51ec7d83acSArnaud Minier     if (mux->enabled && mux->divider) {
52ec7d83acSArnaud Minier         freq_multiplier = mux->divider;
53ec7d83acSArnaud Minier     }
54ec7d83acSArnaud Minier 
55ec7d83acSArnaud Minier     clock_set_mul_div(mux->out, freq_multiplier, mux->multiplier);
56ec7d83acSArnaud Minier     clock_update(mux->out, clock_get(current_source));
57ec7d83acSArnaud Minier 
58ec7d83acSArnaud Minier     src_freq = clock_get_hz(current_source);
59ec7d83acSArnaud Minier     /* TODO: can we simply detect if the config changed so that we reduce log spam ? */
60ec7d83acSArnaud Minier     trace_stm32l4x5_rcc_mux_update(mux->id, mux->src, src_freq,
61ec7d83acSArnaud Minier                                    mux->multiplier, mux->divider);
62ec7d83acSArnaud Minier }
63ec7d83acSArnaud Minier 
64ec7d83acSArnaud Minier static void clock_mux_src_update(void *opaque, ClockEvent event)
65ec7d83acSArnaud Minier {
66ec7d83acSArnaud Minier     RccClockMuxState **backref = opaque;
67ec7d83acSArnaud Minier     RccClockMuxState *s = *backref;
68ec7d83acSArnaud Minier     /*
69ec7d83acSArnaud Minier      * The backref value is equal to:
70ec7d83acSArnaud Minier      * s->backref + (sizeof(RccClockMuxState *) * update_src).
71ec7d83acSArnaud Minier      * By subtracting we can get back the index of the updated clock.
72ec7d83acSArnaud Minier      */
73ec7d83acSArnaud Minier     const uint32_t update_src = backref - s->backref;
74ec7d83acSArnaud Minier     /* Only update if the clock that was updated is the current source */
75ec7d83acSArnaud Minier     if (update_src == s->src) {
76ec7d83acSArnaud Minier         clock_mux_update(s);
77ec7d83acSArnaud Minier     }
78ec7d83acSArnaud Minier }
79ec7d83acSArnaud Minier 
80ec7d83acSArnaud Minier static void clock_mux_init(Object *obj)
81ec7d83acSArnaud Minier {
82ec7d83acSArnaud Minier     RccClockMuxState *s = RCC_CLOCK_MUX(obj);
83ec7d83acSArnaud Minier     size_t i;
84ec7d83acSArnaud Minier 
85ec7d83acSArnaud Minier     for (i = 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) {
86ec7d83acSArnaud Minier         char *name = g_strdup_printf("srcs[%zu]", i);
87ec7d83acSArnaud Minier         s->backref[i] = s;
88ec7d83acSArnaud Minier         s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
89ec7d83acSArnaud Minier                                         clock_mux_src_update,
90ec7d83acSArnaud Minier                                         &s->backref[i],
91ec7d83acSArnaud Minier                                         ClockUpdate);
92ec7d83acSArnaud Minier         g_free(name);
93ec7d83acSArnaud Minier     }
94ec7d83acSArnaud Minier 
95ec7d83acSArnaud Minier     s->out = qdev_init_clock_out(DEVICE(s), "out");
96ec7d83acSArnaud Minier }
97ec7d83acSArnaud Minier 
98ec7d83acSArnaud Minier static void clock_mux_reset_hold(Object *obj)
99ec7d83acSArnaud Minier { }
100ec7d83acSArnaud Minier 
101ec7d83acSArnaud Minier static const VMStateDescription clock_mux_vmstate = {
102ec7d83acSArnaud Minier     .name = TYPE_RCC_CLOCK_MUX,
103ec7d83acSArnaud Minier     .version_id = 1,
104ec7d83acSArnaud Minier     .minimum_version_id = 1,
105ec7d83acSArnaud Minier     .fields = (VMStateField[]) {
106ec7d83acSArnaud Minier         VMSTATE_UINT32(id, RccClockMuxState),
107ec7d83acSArnaud Minier         VMSTATE_ARRAY_CLOCK(srcs, RccClockMuxState,
108ec7d83acSArnaud Minier                             RCC_NUM_CLOCK_MUX_SRC),
109ec7d83acSArnaud Minier         VMSTATE_BOOL(enabled, RccClockMuxState),
110ec7d83acSArnaud Minier         VMSTATE_UINT32(src, RccClockMuxState),
111ec7d83acSArnaud Minier         VMSTATE_UINT32(multiplier, RccClockMuxState),
112ec7d83acSArnaud Minier         VMSTATE_UINT32(divider, RccClockMuxState),
113ec7d83acSArnaud Minier         VMSTATE_END_OF_LIST()
114ec7d83acSArnaud Minier     }
115ec7d83acSArnaud Minier };
116ec7d83acSArnaud Minier 
117ec7d83acSArnaud Minier static void clock_mux_class_init(ObjectClass *klass, void *data)
118ec7d83acSArnaud Minier {
119ec7d83acSArnaud Minier     DeviceClass *dc = DEVICE_CLASS(klass);
120ec7d83acSArnaud Minier     ResettableClass *rc = RESETTABLE_CLASS(klass);
121ec7d83acSArnaud Minier 
122ec7d83acSArnaud Minier     rc->phases.hold = clock_mux_reset_hold;
123ec7d83acSArnaud Minier     dc->vmsd = &clock_mux_vmstate;
124ec7d83acSArnaud Minier }
125ec7d83acSArnaud Minier 
126ec7d83acSArnaud Minier static void clock_mux_set_enable(RccClockMuxState *mux, bool enabled)
127ec7d83acSArnaud Minier {
128ec7d83acSArnaud Minier     if (mux->enabled == enabled) {
129ec7d83acSArnaud Minier         return;
130ec7d83acSArnaud Minier     }
131ec7d83acSArnaud Minier 
132ec7d83acSArnaud Minier     if (enabled) {
133ec7d83acSArnaud Minier         trace_stm32l4x5_rcc_mux_enable(mux->id);
134ec7d83acSArnaud Minier     } else {
135ec7d83acSArnaud Minier         trace_stm32l4x5_rcc_mux_disable(mux->id);
136ec7d83acSArnaud Minier     }
137ec7d83acSArnaud Minier 
138ec7d83acSArnaud Minier     mux->enabled = enabled;
139ec7d83acSArnaud Minier     clock_mux_update(mux);
140ec7d83acSArnaud Minier }
141ec7d83acSArnaud Minier 
142ec7d83acSArnaud Minier static void clock_mux_set_factor(RccClockMuxState *mux,
143ec7d83acSArnaud Minier                                  uint32_t multiplier, uint32_t divider)
144ec7d83acSArnaud Minier {
145ec7d83acSArnaud Minier     if (mux->multiplier == multiplier && mux->divider == divider) {
146ec7d83acSArnaud Minier         return;
147ec7d83acSArnaud Minier     }
148ec7d83acSArnaud Minier     trace_stm32l4x5_rcc_mux_set_factor(mux->id,
149ec7d83acSArnaud Minier         mux->multiplier, multiplier, mux->divider, divider);
150ec7d83acSArnaud Minier 
151ec7d83acSArnaud Minier     mux->multiplier = multiplier;
152ec7d83acSArnaud Minier     mux->divider = divider;
153ec7d83acSArnaud Minier     clock_mux_update(mux);
154ec7d83acSArnaud Minier }
155ec7d83acSArnaud Minier 
156ec7d83acSArnaud Minier static void clock_mux_set_source(RccClockMuxState *mux, RccClockMuxSource src)
157ec7d83acSArnaud Minier {
158ec7d83acSArnaud Minier     if (mux->src == src) {
159ec7d83acSArnaud Minier         return;
160ec7d83acSArnaud Minier     }
161ec7d83acSArnaud Minier 
162ec7d83acSArnaud Minier     trace_stm32l4x5_rcc_mux_set_src(mux->id, mux->src, src);
163ec7d83acSArnaud Minier     mux->src = src;
164ec7d83acSArnaud Minier     clock_mux_update(mux);
165ec7d83acSArnaud Minier }
166ec7d83acSArnaud Minier 
167*6487653eSArnaud Minier static void pll_update(RccPllState *pll)
168*6487653eSArnaud Minier {
169*6487653eSArnaud Minier     uint64_t vco_freq, old_channel_freq, channel_freq;
170*6487653eSArnaud Minier     int i;
171*6487653eSArnaud Minier 
172*6487653eSArnaud Minier     /* The common PLLM factor is handled by the PLL mux */
173*6487653eSArnaud Minier     vco_freq = muldiv64(clock_get_hz(pll->in), pll->vco_multiplier, 1);
174*6487653eSArnaud Minier 
175*6487653eSArnaud Minier     for (i = 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) {
176*6487653eSArnaud Minier         if (!pll->channel_exists[i]) {
177*6487653eSArnaud Minier             continue;
178*6487653eSArnaud Minier         }
179*6487653eSArnaud Minier 
180*6487653eSArnaud Minier         old_channel_freq = clock_get_hz(pll->channels[i]);
181*6487653eSArnaud Minier         if (!pll->enabled ||
182*6487653eSArnaud Minier             !pll->channel_enabled[i] ||
183*6487653eSArnaud Minier             !pll->channel_divider[i]) {
184*6487653eSArnaud Minier             channel_freq = 0;
185*6487653eSArnaud Minier         } else {
186*6487653eSArnaud Minier             channel_freq = muldiv64(vco_freq,
187*6487653eSArnaud Minier                                     1,
188*6487653eSArnaud Minier                                     pll->channel_divider[i]);
189*6487653eSArnaud Minier         }
190*6487653eSArnaud Minier 
191*6487653eSArnaud Minier         /* No change, early continue to avoid log spam and useless propagation */
192*6487653eSArnaud Minier         if (old_channel_freq == channel_freq) {
193*6487653eSArnaud Minier             continue;
194*6487653eSArnaud Minier         }
195*6487653eSArnaud Minier 
196*6487653eSArnaud Minier         clock_update_hz(pll->channels[i], channel_freq);
197*6487653eSArnaud Minier         trace_stm32l4x5_rcc_pll_update(pll->id, i, vco_freq,
198*6487653eSArnaud Minier             old_channel_freq, channel_freq);
199*6487653eSArnaud Minier     }
200*6487653eSArnaud Minier }
201*6487653eSArnaud Minier 
202*6487653eSArnaud Minier static void pll_src_update(void *opaque, ClockEvent event)
203*6487653eSArnaud Minier {
204*6487653eSArnaud Minier     RccPllState *s = opaque;
205*6487653eSArnaud Minier     pll_update(s);
206*6487653eSArnaud Minier }
207*6487653eSArnaud Minier 
208*6487653eSArnaud Minier static void pll_init(Object *obj)
209*6487653eSArnaud Minier {
210*6487653eSArnaud Minier     RccPllState *s = RCC_PLL(obj);
211*6487653eSArnaud Minier     size_t i;
212*6487653eSArnaud Minier 
213*6487653eSArnaud Minier     s->in = qdev_init_clock_in(DEVICE(s), "in",
214*6487653eSArnaud Minier                                pll_src_update, s, ClockUpdate);
215*6487653eSArnaud Minier 
216*6487653eSArnaud Minier     const char *names[] = {
217*6487653eSArnaud Minier         "out-p", "out-q", "out-r",
218*6487653eSArnaud Minier     };
219*6487653eSArnaud Minier 
220*6487653eSArnaud Minier     for (i = 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) {
221*6487653eSArnaud Minier         s->channels[i] = qdev_init_clock_out(DEVICE(s), names[i]);
222*6487653eSArnaud Minier     }
223*6487653eSArnaud Minier }
224*6487653eSArnaud Minier 
225*6487653eSArnaud Minier static void pll_reset_hold(Object *obj)
226*6487653eSArnaud Minier { }
227*6487653eSArnaud Minier 
228*6487653eSArnaud Minier static const VMStateDescription pll_vmstate = {
229*6487653eSArnaud Minier     .name = TYPE_RCC_PLL,
230*6487653eSArnaud Minier     .version_id = 1,
231*6487653eSArnaud Minier     .minimum_version_id = 1,
232*6487653eSArnaud Minier     .fields = (VMStateField[]) {
233*6487653eSArnaud Minier         VMSTATE_UINT32(id, RccPllState),
234*6487653eSArnaud Minier         VMSTATE_CLOCK(in, RccPllState),
235*6487653eSArnaud Minier         VMSTATE_ARRAY_CLOCK(channels, RccPllState,
236*6487653eSArnaud Minier                             RCC_NUM_CHANNEL_PLL_OUT),
237*6487653eSArnaud Minier         VMSTATE_BOOL(enabled, RccPllState),
238*6487653eSArnaud Minier         VMSTATE_UINT32(vco_multiplier, RccPllState),
239*6487653eSArnaud Minier         VMSTATE_BOOL_ARRAY(channel_enabled, RccPllState, RCC_NUM_CHANNEL_PLL_OUT),
240*6487653eSArnaud Minier         VMSTATE_BOOL_ARRAY(channel_exists, RccPllState, RCC_NUM_CHANNEL_PLL_OUT),
241*6487653eSArnaud Minier         VMSTATE_UINT32_ARRAY(channel_divider, RccPllState, RCC_NUM_CHANNEL_PLL_OUT),
242*6487653eSArnaud Minier         VMSTATE_END_OF_LIST()
243*6487653eSArnaud Minier     }
244*6487653eSArnaud Minier };
245*6487653eSArnaud Minier 
246*6487653eSArnaud Minier static void pll_class_init(ObjectClass *klass, void *data)
247*6487653eSArnaud Minier {
248*6487653eSArnaud Minier     DeviceClass *dc = DEVICE_CLASS(klass);
249*6487653eSArnaud Minier     ResettableClass *rc = RESETTABLE_CLASS(klass);
250*6487653eSArnaud Minier 
251*6487653eSArnaud Minier     rc->phases.hold = pll_reset_hold;
252*6487653eSArnaud Minier     dc->vmsd = &pll_vmstate;
253*6487653eSArnaud Minier }
254*6487653eSArnaud Minier 
255*6487653eSArnaud Minier static void pll_set_vco_multiplier(RccPllState *pll, uint32_t vco_multiplier)
256*6487653eSArnaud Minier {
257*6487653eSArnaud Minier     if (pll->vco_multiplier == vco_multiplier) {
258*6487653eSArnaud Minier         return;
259*6487653eSArnaud Minier     }
260*6487653eSArnaud Minier 
261*6487653eSArnaud Minier     if (vco_multiplier < 8 || vco_multiplier > 86) {
262*6487653eSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
263*6487653eSArnaud Minier             "%s: VCO multiplier is out of bound (%u) for PLL %u\n",
264*6487653eSArnaud Minier             __func__, vco_multiplier, pll->id);
265*6487653eSArnaud Minier         return;
266*6487653eSArnaud Minier     }
267*6487653eSArnaud Minier 
268*6487653eSArnaud Minier     trace_stm32l4x5_rcc_pll_set_vco_multiplier(pll->id,
269*6487653eSArnaud Minier         pll->vco_multiplier, vco_multiplier);
270*6487653eSArnaud Minier 
271*6487653eSArnaud Minier     pll->vco_multiplier = vco_multiplier;
272*6487653eSArnaud Minier     pll_update(pll);
273*6487653eSArnaud Minier }
274*6487653eSArnaud Minier 
275*6487653eSArnaud Minier static void pll_set_enable(RccPllState *pll, bool enabled)
276*6487653eSArnaud Minier {
277*6487653eSArnaud Minier     if (pll->enabled == enabled) {
278*6487653eSArnaud Minier         return;
279*6487653eSArnaud Minier     }
280*6487653eSArnaud Minier 
281*6487653eSArnaud Minier     pll->enabled = enabled;
282*6487653eSArnaud Minier     pll_update(pll);
283*6487653eSArnaud Minier }
284*6487653eSArnaud Minier 
285*6487653eSArnaud Minier static void pll_set_channel_enable(RccPllState *pll,
286*6487653eSArnaud Minier                                    PllCommonChannels channel,
287*6487653eSArnaud Minier                                    bool enabled)
288*6487653eSArnaud Minier {
289*6487653eSArnaud Minier     if (pll->channel_enabled[channel] == enabled) {
290*6487653eSArnaud Minier         return;
291*6487653eSArnaud Minier     }
292*6487653eSArnaud Minier 
293*6487653eSArnaud Minier     if (enabled) {
294*6487653eSArnaud Minier         trace_stm32l4x5_rcc_pll_channel_enable(pll->id, channel);
295*6487653eSArnaud Minier     } else {
296*6487653eSArnaud Minier         trace_stm32l4x5_rcc_pll_channel_disable(pll->id, channel);
297*6487653eSArnaud Minier     }
298*6487653eSArnaud Minier 
299*6487653eSArnaud Minier     pll->channel_enabled[channel] = enabled;
300*6487653eSArnaud Minier     pll_update(pll);
301*6487653eSArnaud Minier }
302*6487653eSArnaud Minier 
303*6487653eSArnaud Minier static void pll_set_channel_divider(RccPllState *pll,
304*6487653eSArnaud Minier                                     PllCommonChannels channel,
305*6487653eSArnaud Minier                                     uint32_t divider)
306*6487653eSArnaud Minier {
307*6487653eSArnaud Minier     if (pll->channel_divider[channel] == divider) {
308*6487653eSArnaud Minier         return;
309*6487653eSArnaud Minier     }
310*6487653eSArnaud Minier 
311*6487653eSArnaud Minier     trace_stm32l4x5_rcc_pll_set_channel_divider(pll->id,
312*6487653eSArnaud Minier         channel, pll->channel_divider[channel], divider);
313*6487653eSArnaud Minier 
314*6487653eSArnaud Minier     pll->channel_divider[channel] = divider;
315*6487653eSArnaud Minier     pll_update(pll);
316*6487653eSArnaud Minier }
317*6487653eSArnaud Minier 
318d6b55a0fSArnaud Minier static void rcc_update_irq(Stm32l4x5RccState *s)
319d6b55a0fSArnaud Minier {
320d6b55a0fSArnaud Minier     if (s->cifr & CIFR_IRQ_MASK) {
321d6b55a0fSArnaud Minier         qemu_irq_raise(s->irq);
322d6b55a0fSArnaud Minier     } else {
323d6b55a0fSArnaud Minier         qemu_irq_lower(s->irq);
324d6b55a0fSArnaud Minier     }
325d6b55a0fSArnaud Minier }
326d6b55a0fSArnaud Minier 
327d6b55a0fSArnaud Minier static void stm32l4x5_rcc_reset_hold(Object *obj)
328d6b55a0fSArnaud Minier {
329d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(obj);
330d6b55a0fSArnaud Minier     s->cr = 0x00000063;
331d6b55a0fSArnaud Minier     /*
332d6b55a0fSArnaud Minier      * Factory-programmed calibration data
333d6b55a0fSArnaud Minier      * From the reference manual: 0x10XX 00XX
334d6b55a0fSArnaud Minier      * Value taken from a real card.
335d6b55a0fSArnaud Minier      */
336d6b55a0fSArnaud Minier     s->icscr = 0x106E0082;
337d6b55a0fSArnaud Minier     s->cfgr = 0x0;
338d6b55a0fSArnaud Minier     s->pllcfgr = 0x00001000;
339d6b55a0fSArnaud Minier     s->pllsai1cfgr = 0x00001000;
340d6b55a0fSArnaud Minier     s->pllsai2cfgr = 0x00001000;
341d6b55a0fSArnaud Minier     s->cier = 0x0;
342d6b55a0fSArnaud Minier     s->cifr = 0x0;
343d6b55a0fSArnaud Minier     s->ahb1rstr = 0x0;
344d6b55a0fSArnaud Minier     s->ahb2rstr = 0x0;
345d6b55a0fSArnaud Minier     s->ahb3rstr = 0x0;
346d6b55a0fSArnaud Minier     s->apb1rstr1 = 0x0;
347d6b55a0fSArnaud Minier     s->apb1rstr2 = 0x0;
348d6b55a0fSArnaud Minier     s->apb2rstr = 0x0;
349d6b55a0fSArnaud Minier     s->ahb1enr = 0x00000100;
350d6b55a0fSArnaud Minier     s->ahb2enr = 0x0;
351d6b55a0fSArnaud Minier     s->ahb3enr = 0x0;
352d6b55a0fSArnaud Minier     s->apb1enr1 = 0x0;
353d6b55a0fSArnaud Minier     s->apb1enr2 = 0x0;
354d6b55a0fSArnaud Minier     s->apb2enr = 0x0;
355d6b55a0fSArnaud Minier     s->ahb1smenr = 0x00011303;
356d6b55a0fSArnaud Minier     s->ahb2smenr = 0x000532FF;
357d6b55a0fSArnaud Minier     s->ahb3smenr =  0x00000101;
358d6b55a0fSArnaud Minier     s->apb1smenr1 = 0xF2FECA3F;
359d6b55a0fSArnaud Minier     s->apb1smenr2 = 0x00000025;
360d6b55a0fSArnaud Minier     s->apb2smenr = 0x01677C01;
361d6b55a0fSArnaud Minier     s->ccipr = 0x0;
362d6b55a0fSArnaud Minier     s->bdcr = 0x0;
363d6b55a0fSArnaud Minier     s->csr = 0x0C000600;
364d6b55a0fSArnaud Minier }
365d6b55a0fSArnaud Minier 
366d6b55a0fSArnaud Minier static uint64_t stm32l4x5_rcc_read(void *opaque, hwaddr addr,
367d6b55a0fSArnaud Minier                                      unsigned int size)
368d6b55a0fSArnaud Minier {
369d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = opaque;
370d6b55a0fSArnaud Minier     uint64_t retvalue = 0;
371d6b55a0fSArnaud Minier 
372d6b55a0fSArnaud Minier     switch (addr) {
373d6b55a0fSArnaud Minier     case A_CR:
374d6b55a0fSArnaud Minier         retvalue = s->cr;
375d6b55a0fSArnaud Minier         break;
376d6b55a0fSArnaud Minier     case A_ICSCR:
377d6b55a0fSArnaud Minier         retvalue = s->icscr;
378d6b55a0fSArnaud Minier         break;
379d6b55a0fSArnaud Minier     case A_CFGR:
380d6b55a0fSArnaud Minier         retvalue = s->cfgr;
381d6b55a0fSArnaud Minier         break;
382d6b55a0fSArnaud Minier     case A_PLLCFGR:
383d6b55a0fSArnaud Minier         retvalue = s->pllcfgr;
384d6b55a0fSArnaud Minier         break;
385d6b55a0fSArnaud Minier     case A_PLLSAI1CFGR:
386d6b55a0fSArnaud Minier         retvalue = s->pllsai1cfgr;
387d6b55a0fSArnaud Minier         break;
388d6b55a0fSArnaud Minier     case A_PLLSAI2CFGR:
389d6b55a0fSArnaud Minier         retvalue = s->pllsai2cfgr;
390d6b55a0fSArnaud Minier         break;
391d6b55a0fSArnaud Minier     case A_CIER:
392d6b55a0fSArnaud Minier         retvalue = s->cier;
393d6b55a0fSArnaud Minier         break;
394d6b55a0fSArnaud Minier     case A_CIFR:
395d6b55a0fSArnaud Minier         retvalue = s->cifr;
396d6b55a0fSArnaud Minier         break;
397d6b55a0fSArnaud Minier     case A_CICR:
398d6b55a0fSArnaud Minier         /* CICR is write only, return the reset value = 0 */
399d6b55a0fSArnaud Minier         break;
400d6b55a0fSArnaud Minier     case A_AHB1RSTR:
401d6b55a0fSArnaud Minier         retvalue = s->ahb1rstr;
402d6b55a0fSArnaud Minier         break;
403d6b55a0fSArnaud Minier     case A_AHB2RSTR:
404d6b55a0fSArnaud Minier         retvalue = s->ahb2rstr;
405d6b55a0fSArnaud Minier         break;
406d6b55a0fSArnaud Minier     case A_AHB3RSTR:
407d6b55a0fSArnaud Minier         retvalue = s->ahb3rstr;
408d6b55a0fSArnaud Minier         break;
409d6b55a0fSArnaud Minier     case A_APB1RSTR1:
410d6b55a0fSArnaud Minier         retvalue = s->apb1rstr1;
411d6b55a0fSArnaud Minier         break;
412d6b55a0fSArnaud Minier     case A_APB1RSTR2:
413d6b55a0fSArnaud Minier         retvalue = s->apb1rstr2;
414d6b55a0fSArnaud Minier         break;
415d6b55a0fSArnaud Minier     case A_APB2RSTR:
416d6b55a0fSArnaud Minier         retvalue = s->apb2rstr;
417d6b55a0fSArnaud Minier         break;
418d6b55a0fSArnaud Minier     case A_AHB1ENR:
419d6b55a0fSArnaud Minier         retvalue = s->ahb1enr;
420d6b55a0fSArnaud Minier         break;
421d6b55a0fSArnaud Minier     case A_AHB2ENR:
422d6b55a0fSArnaud Minier         retvalue = s->ahb2enr;
423d6b55a0fSArnaud Minier         break;
424d6b55a0fSArnaud Minier     case A_AHB3ENR:
425d6b55a0fSArnaud Minier         retvalue = s->ahb3enr;
426d6b55a0fSArnaud Minier         break;
427d6b55a0fSArnaud Minier     case A_APB1ENR1:
428d6b55a0fSArnaud Minier         retvalue = s->apb1enr1;
429d6b55a0fSArnaud Minier         break;
430d6b55a0fSArnaud Minier     case A_APB1ENR2:
431d6b55a0fSArnaud Minier         retvalue = s->apb1enr2;
432d6b55a0fSArnaud Minier         break;
433d6b55a0fSArnaud Minier     case A_APB2ENR:
434d6b55a0fSArnaud Minier         retvalue = s->apb2enr;
435d6b55a0fSArnaud Minier         break;
436d6b55a0fSArnaud Minier     case A_AHB1SMENR:
437d6b55a0fSArnaud Minier         retvalue = s->ahb1smenr;
438d6b55a0fSArnaud Minier         break;
439d6b55a0fSArnaud Minier     case A_AHB2SMENR:
440d6b55a0fSArnaud Minier         retvalue = s->ahb2smenr;
441d6b55a0fSArnaud Minier         break;
442d6b55a0fSArnaud Minier     case A_AHB3SMENR:
443d6b55a0fSArnaud Minier         retvalue = s->ahb3smenr;
444d6b55a0fSArnaud Minier         break;
445d6b55a0fSArnaud Minier     case A_APB1SMENR1:
446d6b55a0fSArnaud Minier         retvalue = s->apb1smenr1;
447d6b55a0fSArnaud Minier         break;
448d6b55a0fSArnaud Minier     case A_APB1SMENR2:
449d6b55a0fSArnaud Minier         retvalue = s->apb1smenr2;
450d6b55a0fSArnaud Minier         break;
451d6b55a0fSArnaud Minier     case A_APB2SMENR:
452d6b55a0fSArnaud Minier         retvalue = s->apb2smenr;
453d6b55a0fSArnaud Minier         break;
454d6b55a0fSArnaud Minier     case A_CCIPR:
455d6b55a0fSArnaud Minier         retvalue = s->ccipr;
456d6b55a0fSArnaud Minier         break;
457d6b55a0fSArnaud Minier     case A_BDCR:
458d6b55a0fSArnaud Minier         retvalue = s->bdcr;
459d6b55a0fSArnaud Minier         break;
460d6b55a0fSArnaud Minier     case A_CSR:
461d6b55a0fSArnaud Minier         retvalue = s->csr;
462d6b55a0fSArnaud Minier         break;
463d6b55a0fSArnaud Minier     default:
464d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
465d6b55a0fSArnaud Minier                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
466d6b55a0fSArnaud Minier         break;
467d6b55a0fSArnaud Minier     }
468d6b55a0fSArnaud Minier 
469d6b55a0fSArnaud Minier     trace_stm32l4x5_rcc_read(addr, retvalue);
470d6b55a0fSArnaud Minier 
471d6b55a0fSArnaud Minier     return retvalue;
472d6b55a0fSArnaud Minier }
473d6b55a0fSArnaud Minier 
474d6b55a0fSArnaud Minier static void stm32l4x5_rcc_write(void *opaque, hwaddr addr,
475d6b55a0fSArnaud Minier                                   uint64_t val64, unsigned int size)
476d6b55a0fSArnaud Minier {
477d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = opaque;
478d6b55a0fSArnaud Minier     const uint32_t value = val64;
479d6b55a0fSArnaud Minier 
480d6b55a0fSArnaud Minier     trace_stm32l4x5_rcc_write(addr, value);
481d6b55a0fSArnaud Minier 
482d6b55a0fSArnaud Minier     switch (addr) {
483d6b55a0fSArnaud Minier     case A_CR:
484d6b55a0fSArnaud Minier         s->cr = (s->cr & CR_READ_SET_MASK) |
485d6b55a0fSArnaud Minier                 (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK));
486d6b55a0fSArnaud Minier         break;
487d6b55a0fSArnaud Minier     case A_ICSCR:
488d6b55a0fSArnaud Minier         s->icscr = value & ~ICSCR_READ_ONLY_MASK;
489d6b55a0fSArnaud Minier         break;
490d6b55a0fSArnaud Minier     case A_CFGR:
491d6b55a0fSArnaud Minier         s->cfgr = value & ~CFGR_READ_ONLY_MASK;
492d6b55a0fSArnaud Minier         break;
493d6b55a0fSArnaud Minier     case A_PLLCFGR:
494d6b55a0fSArnaud Minier         s->pllcfgr = value;
495d6b55a0fSArnaud Minier         break;
496d6b55a0fSArnaud Minier     case A_PLLSAI1CFGR:
497d6b55a0fSArnaud Minier         s->pllsai1cfgr = value;
498d6b55a0fSArnaud Minier         break;
499d6b55a0fSArnaud Minier     case A_PLLSAI2CFGR:
500d6b55a0fSArnaud Minier         s->pllsai2cfgr = value;
501d6b55a0fSArnaud Minier         break;
502d6b55a0fSArnaud Minier     case A_CIER:
503d6b55a0fSArnaud Minier         s->cier = value;
504d6b55a0fSArnaud Minier         break;
505d6b55a0fSArnaud Minier     case A_CIFR:
506d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
507d6b55a0fSArnaud Minier             "%s: Write attempt into read-only register (CIFR) 0x%"PRIx32"\n",
508d6b55a0fSArnaud Minier             __func__, value);
509d6b55a0fSArnaud Minier         break;
510d6b55a0fSArnaud Minier     case A_CICR:
511d6b55a0fSArnaud Minier         /* Clear interrupt flags by writing a 1 to the CICR register */
512d6b55a0fSArnaud Minier         s->cifr &= ~value;
513d6b55a0fSArnaud Minier         rcc_update_irq(s);
514d6b55a0fSArnaud Minier         break;
515d6b55a0fSArnaud Minier     /* Reset behaviors are not implemented */
516d6b55a0fSArnaud Minier     case A_AHB1RSTR:
517d6b55a0fSArnaud Minier         s->ahb1rstr = value;
518d6b55a0fSArnaud Minier         break;
519d6b55a0fSArnaud Minier     case A_AHB2RSTR:
520d6b55a0fSArnaud Minier         s->ahb2rstr = value;
521d6b55a0fSArnaud Minier         break;
522d6b55a0fSArnaud Minier     case A_AHB3RSTR:
523d6b55a0fSArnaud Minier         s->ahb3rstr = value;
524d6b55a0fSArnaud Minier         break;
525d6b55a0fSArnaud Minier     case A_APB1RSTR1:
526d6b55a0fSArnaud Minier         s->apb1rstr1 = value;
527d6b55a0fSArnaud Minier         break;
528d6b55a0fSArnaud Minier     case A_APB1RSTR2:
529d6b55a0fSArnaud Minier         s->apb1rstr2 = value;
530d6b55a0fSArnaud Minier         break;
531d6b55a0fSArnaud Minier     case A_APB2RSTR:
532d6b55a0fSArnaud Minier         s->apb2rstr = value;
533d6b55a0fSArnaud Minier         break;
534d6b55a0fSArnaud Minier     case A_AHB1ENR:
535d6b55a0fSArnaud Minier         s->ahb1enr = value;
536d6b55a0fSArnaud Minier         break;
537d6b55a0fSArnaud Minier     case A_AHB2ENR:
538d6b55a0fSArnaud Minier         s->ahb2enr = value;
539d6b55a0fSArnaud Minier         break;
540d6b55a0fSArnaud Minier     case A_AHB3ENR:
541d6b55a0fSArnaud Minier         s->ahb3enr = value;
542d6b55a0fSArnaud Minier         break;
543d6b55a0fSArnaud Minier     case A_APB1ENR1:
544d6b55a0fSArnaud Minier         s->apb1enr1 = value;
545d6b55a0fSArnaud Minier         break;
546d6b55a0fSArnaud Minier     case A_APB1ENR2:
547d6b55a0fSArnaud Minier         s->apb1enr2 = value;
548d6b55a0fSArnaud Minier         break;
549d6b55a0fSArnaud Minier     case A_APB2ENR:
550d6b55a0fSArnaud Minier         s->apb2enr = (s->apb2enr & APB2ENR_READ_SET_MASK) | value;
551d6b55a0fSArnaud Minier         break;
552d6b55a0fSArnaud Minier     /* Behaviors for Sleep and Stop modes are not implemented */
553d6b55a0fSArnaud Minier     case A_AHB1SMENR:
554d6b55a0fSArnaud Minier         s->ahb1smenr = value;
555d6b55a0fSArnaud Minier         break;
556d6b55a0fSArnaud Minier     case A_AHB2SMENR:
557d6b55a0fSArnaud Minier         s->ahb2smenr = value;
558d6b55a0fSArnaud Minier         break;
559d6b55a0fSArnaud Minier     case A_AHB3SMENR:
560d6b55a0fSArnaud Minier         s->ahb3smenr = value;
561d6b55a0fSArnaud Minier         break;
562d6b55a0fSArnaud Minier     case A_APB1SMENR1:
563d6b55a0fSArnaud Minier         s->apb1smenr1 = value;
564d6b55a0fSArnaud Minier         break;
565d6b55a0fSArnaud Minier     case A_APB1SMENR2:
566d6b55a0fSArnaud Minier         s->apb1smenr2 = value;
567d6b55a0fSArnaud Minier         break;
568d6b55a0fSArnaud Minier     case A_APB2SMENR:
569d6b55a0fSArnaud Minier         s->apb2smenr = value;
570d6b55a0fSArnaud Minier         break;
571d6b55a0fSArnaud Minier     case A_CCIPR:
572d6b55a0fSArnaud Minier         s->ccipr = value;
573d6b55a0fSArnaud Minier         break;
574d6b55a0fSArnaud Minier     case A_BDCR:
575d6b55a0fSArnaud Minier         s->bdcr = value & ~BDCR_READ_ONLY_MASK;
576d6b55a0fSArnaud Minier         break;
577d6b55a0fSArnaud Minier     case A_CSR:
578d6b55a0fSArnaud Minier         s->csr = value & ~CSR_READ_ONLY_MASK;
579d6b55a0fSArnaud Minier         break;
580d6b55a0fSArnaud Minier     default:
581d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
582d6b55a0fSArnaud Minier                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
583d6b55a0fSArnaud Minier     }
584d6b55a0fSArnaud Minier }
585d6b55a0fSArnaud Minier 
586d6b55a0fSArnaud Minier static const MemoryRegionOps stm32l4x5_rcc_ops = {
587d6b55a0fSArnaud Minier     .read = stm32l4x5_rcc_read,
588d6b55a0fSArnaud Minier     .write = stm32l4x5_rcc_write,
589d6b55a0fSArnaud Minier     .endianness = DEVICE_NATIVE_ENDIAN,
590d6b55a0fSArnaud Minier     .valid = {
591d6b55a0fSArnaud Minier         .max_access_size = 4,
592d6b55a0fSArnaud Minier         .min_access_size = 4,
593d6b55a0fSArnaud Minier         .unaligned = false
594d6b55a0fSArnaud Minier     },
595d6b55a0fSArnaud Minier     .impl = {
596d6b55a0fSArnaud Minier         .max_access_size = 4,
597d6b55a0fSArnaud Minier         .min_access_size = 4,
598d6b55a0fSArnaud Minier         .unaligned = false
599d6b55a0fSArnaud Minier     },
600d6b55a0fSArnaud Minier };
601d6b55a0fSArnaud Minier 
602d6b55a0fSArnaud Minier static const ClockPortInitArray stm32l4x5_rcc_clocks = {
603d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, hsi16_rc, NULL, 0),
604d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, msi_rc, NULL, 0),
605d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, hse, NULL, 0),
606d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, lsi_rc, NULL, 0),
607d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, lse_crystal, NULL, 0),
608d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, sai1_extclk, NULL, 0),
609d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0),
610d6b55a0fSArnaud Minier     QDEV_CLOCK_END
611d6b55a0fSArnaud Minier };
612d6b55a0fSArnaud Minier 
613d6b55a0fSArnaud Minier 
614d6b55a0fSArnaud Minier static void stm32l4x5_rcc_init(Object *obj)
615d6b55a0fSArnaud Minier {
616d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(obj);
617ec7d83acSArnaud Minier     size_t i;
618d6b55a0fSArnaud Minier 
619d6b55a0fSArnaud Minier     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
620d6b55a0fSArnaud Minier 
621d6b55a0fSArnaud Minier     memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s,
622d6b55a0fSArnaud Minier                           TYPE_STM32L4X5_RCC, 0x400);
623d6b55a0fSArnaud Minier     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
624d6b55a0fSArnaud Minier 
625d6b55a0fSArnaud Minier     qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks);
626d6b55a0fSArnaud Minier 
627*6487653eSArnaud Minier     for (i = 0; i < RCC_NUM_PLL; i++) {
628*6487653eSArnaud Minier         object_initialize_child(obj, "pll[*]",
629*6487653eSArnaud Minier                                 &s->plls[i], TYPE_RCC_PLL);
630*6487653eSArnaud Minier     }
631*6487653eSArnaud Minier 
632ec7d83acSArnaud Minier     for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) {
633ec7d83acSArnaud Minier 
634ec7d83acSArnaud Minier         object_initialize_child(obj, "clock[*]",
635ec7d83acSArnaud Minier                                 &s->clock_muxes[i],
636ec7d83acSArnaud Minier                                 TYPE_RCC_CLOCK_MUX);
637ec7d83acSArnaud Minier 
638ec7d83acSArnaud Minier     }
639ec7d83acSArnaud Minier 
640d6b55a0fSArnaud Minier     s->gnd = clock_new(obj, "gnd");
641d6b55a0fSArnaud Minier }
642d6b55a0fSArnaud Minier 
643d6b55a0fSArnaud Minier static const VMStateDescription vmstate_stm32l4x5_rcc = {
644d6b55a0fSArnaud Minier     .name = TYPE_STM32L4X5_RCC,
645d6b55a0fSArnaud Minier     .version_id = 1,
646d6b55a0fSArnaud Minier     .minimum_version_id = 1,
647d6b55a0fSArnaud Minier     .fields = (VMStateField[]) {
648d6b55a0fSArnaud Minier         VMSTATE_UINT32(cr, Stm32l4x5RccState),
649d6b55a0fSArnaud Minier         VMSTATE_UINT32(icscr, Stm32l4x5RccState),
650d6b55a0fSArnaud Minier         VMSTATE_UINT32(cfgr, Stm32l4x5RccState),
651d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllcfgr, Stm32l4x5RccState),
652d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllsai1cfgr, Stm32l4x5RccState),
653d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllsai2cfgr, Stm32l4x5RccState),
654d6b55a0fSArnaud Minier         VMSTATE_UINT32(cier, Stm32l4x5RccState),
655d6b55a0fSArnaud Minier         VMSTATE_UINT32(cifr, Stm32l4x5RccState),
656d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1rstr, Stm32l4x5RccState),
657d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2rstr, Stm32l4x5RccState),
658d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3rstr, Stm32l4x5RccState),
659d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1rstr1, Stm32l4x5RccState),
660d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1rstr2, Stm32l4x5RccState),
661d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2rstr, Stm32l4x5RccState),
662d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1enr, Stm32l4x5RccState),
663d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2enr, Stm32l4x5RccState),
664d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3enr, Stm32l4x5RccState),
665d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1enr1, Stm32l4x5RccState),
666d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1enr2, Stm32l4x5RccState),
667d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2enr, Stm32l4x5RccState),
668d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1smenr, Stm32l4x5RccState),
669d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2smenr, Stm32l4x5RccState),
670d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3smenr, Stm32l4x5RccState),
671d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1smenr1, Stm32l4x5RccState),
672d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1smenr2, Stm32l4x5RccState),
673d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2smenr, Stm32l4x5RccState),
674d6b55a0fSArnaud Minier         VMSTATE_UINT32(ccipr, Stm32l4x5RccState),
675d6b55a0fSArnaud Minier         VMSTATE_UINT32(bdcr, Stm32l4x5RccState),
676d6b55a0fSArnaud Minier         VMSTATE_UINT32(csr, Stm32l4x5RccState),
677d6b55a0fSArnaud Minier         VMSTATE_CLOCK(hsi16_rc, Stm32l4x5RccState),
678d6b55a0fSArnaud Minier         VMSTATE_CLOCK(msi_rc, Stm32l4x5RccState),
679d6b55a0fSArnaud Minier         VMSTATE_CLOCK(hse, Stm32l4x5RccState),
680d6b55a0fSArnaud Minier         VMSTATE_CLOCK(lsi_rc, Stm32l4x5RccState),
681d6b55a0fSArnaud Minier         VMSTATE_CLOCK(lse_crystal, Stm32l4x5RccState),
682d6b55a0fSArnaud Minier         VMSTATE_CLOCK(sai1_extclk, Stm32l4x5RccState),
683d6b55a0fSArnaud Minier         VMSTATE_CLOCK(sai2_extclk, Stm32l4x5RccState),
684d6b55a0fSArnaud Minier         VMSTATE_END_OF_LIST()
685d6b55a0fSArnaud Minier     }
686d6b55a0fSArnaud Minier };
687d6b55a0fSArnaud Minier 
688d6b55a0fSArnaud Minier 
689d6b55a0fSArnaud Minier static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp)
690d6b55a0fSArnaud Minier {
691d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(dev);
692ec7d83acSArnaud Minier     size_t i;
693d6b55a0fSArnaud Minier 
694d6b55a0fSArnaud Minier     if (s->hse_frequency <  4000000ULL ||
695d6b55a0fSArnaud Minier         s->hse_frequency > 48000000ULL) {
696d6b55a0fSArnaud Minier             error_setg(errp,
697d6b55a0fSArnaud Minier                 "HSE frequency is outside of the allowed [4-48]Mhz range: %" PRIx64 "",
698d6b55a0fSArnaud Minier                 s->hse_frequency);
699d6b55a0fSArnaud Minier             return;
700d6b55a0fSArnaud Minier         }
701d6b55a0fSArnaud Minier 
702*6487653eSArnaud Minier     for (i = 0; i < RCC_NUM_PLL; i++) {
703*6487653eSArnaud Minier         RccPllState *pll = &s->plls[i];
704*6487653eSArnaud Minier 
705*6487653eSArnaud Minier         clock_set_source(pll->in, s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].out);
706*6487653eSArnaud Minier 
707*6487653eSArnaud Minier         if (!qdev_realize(DEVICE(pll), NULL, errp)) {
708*6487653eSArnaud Minier             return;
709*6487653eSArnaud Minier         }
710*6487653eSArnaud Minier     }
711*6487653eSArnaud Minier 
712ec7d83acSArnaud Minier     for (i = 0; i < RCC_NUM_CLOCK_MUX; i++) {
713ec7d83acSArnaud Minier         RccClockMuxState *clock_mux = &s->clock_muxes[i];
714ec7d83acSArnaud Minier 
715ec7d83acSArnaud Minier         if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) {
716ec7d83acSArnaud Minier             return;
717ec7d83acSArnaud Minier         }
718ec7d83acSArnaud Minier     }
719ec7d83acSArnaud Minier 
720d6b55a0fSArnaud Minier     clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ);
721d6b55a0fSArnaud Minier     clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency);
722d6b55a0fSArnaud Minier     clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency);
723d6b55a0fSArnaud Minier     clock_update(s->gnd, 0);
724ec7d83acSArnaud Minier 
725ec7d83acSArnaud Minier     /*
726ec7d83acSArnaud Minier      * Dummy values to make compilation pass.
727ec7d83acSArnaud Minier      * Removed in later commits.
728ec7d83acSArnaud Minier      */
729ec7d83acSArnaud Minier     clock_mux_set_source(&s->clock_muxes[0], RCC_CLOCK_MUX_SRC_GND);
730ec7d83acSArnaud Minier     clock_mux_set_enable(&s->clock_muxes[0], true);
731ec7d83acSArnaud Minier     clock_mux_set_factor(&s->clock_muxes[0], 1, 1);
732*6487653eSArnaud Minier     pll_set_channel_divider(&s->plls[0], 0, 1);
733*6487653eSArnaud Minier     pll_set_enable(&s->plls[0], true);
734*6487653eSArnaud Minier     pll_set_channel_enable(&s->plls[0], 0, true);
735*6487653eSArnaud Minier     pll_set_vco_multiplier(&s->plls[0], 1);
736d6b55a0fSArnaud Minier }
737d6b55a0fSArnaud Minier 
738d6b55a0fSArnaud Minier static Property stm32l4x5_rcc_properties[] = {
739d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState,
740d6b55a0fSArnaud Minier         hse_frequency, HSE_DEFAULT_FRQ),
741d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState,
742d6b55a0fSArnaud Minier         sai1_extclk_frequency, 0),
743d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState,
744d6b55a0fSArnaud Minier         sai2_extclk_frequency, 0),
745d6b55a0fSArnaud Minier     DEFINE_PROP_END_OF_LIST(),
746d6b55a0fSArnaud Minier };
747d6b55a0fSArnaud Minier 
748d6b55a0fSArnaud Minier static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data)
749d6b55a0fSArnaud Minier {
750d6b55a0fSArnaud Minier     DeviceClass *dc = DEVICE_CLASS(klass);
751d6b55a0fSArnaud Minier     ResettableClass *rc = RESETTABLE_CLASS(klass);
752d6b55a0fSArnaud Minier 
753d6b55a0fSArnaud Minier 
754d6b55a0fSArnaud Minier     rc->phases.hold = stm32l4x5_rcc_reset_hold;
755d6b55a0fSArnaud Minier     device_class_set_props(dc, stm32l4x5_rcc_properties);
756d6b55a0fSArnaud Minier     dc->realize = stm32l4x5_rcc_realize;
757d6b55a0fSArnaud Minier     dc->vmsd = &vmstate_stm32l4x5_rcc;
758d6b55a0fSArnaud Minier }
759d6b55a0fSArnaud Minier 
760d6b55a0fSArnaud Minier static const TypeInfo stm32l4x5_rcc_types[] = {
761d6b55a0fSArnaud Minier     {
762d6b55a0fSArnaud Minier         .name           = TYPE_STM32L4X5_RCC,
763d6b55a0fSArnaud Minier         .parent         = TYPE_SYS_BUS_DEVICE,
764d6b55a0fSArnaud Minier         .instance_size  = sizeof(Stm32l4x5RccState),
765d6b55a0fSArnaud Minier         .instance_init  = stm32l4x5_rcc_init,
766d6b55a0fSArnaud Minier         .class_init     = stm32l4x5_rcc_class_init,
767ec7d83acSArnaud Minier     }, {
768ec7d83acSArnaud Minier         .name = TYPE_RCC_CLOCK_MUX,
769ec7d83acSArnaud Minier         .parent = TYPE_DEVICE,
770ec7d83acSArnaud Minier         .instance_size = sizeof(RccClockMuxState),
771ec7d83acSArnaud Minier         .instance_init = clock_mux_init,
772ec7d83acSArnaud Minier         .class_init = clock_mux_class_init,
773*6487653eSArnaud Minier     }, {
774*6487653eSArnaud Minier         .name = TYPE_RCC_PLL,
775*6487653eSArnaud Minier         .parent = TYPE_DEVICE,
776*6487653eSArnaud Minier         .instance_size = sizeof(RccPllState),
777*6487653eSArnaud Minier         .instance_init = pll_init,
778*6487653eSArnaud Minier         .class_init = pll_class_init,
779d6b55a0fSArnaud Minier     }
780d6b55a0fSArnaud Minier };
781d6b55a0fSArnaud Minier 
782d6b55a0fSArnaud Minier DEFINE_TYPES(stm32l4x5_rcc_types)
783