xref: /openbmc/qemu/hw/misc/stm32l4x5_rcc.c (revision d6b55a0fe9920b46d380f50d7da48ff43de21324)
1*d6b55a0fSArnaud Minier /*
2*d6b55a0fSArnaud Minier  * STM32L4X5 RCC (Reset and clock control)
3*d6b55a0fSArnaud Minier  *
4*d6b55a0fSArnaud Minier  * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
5*d6b55a0fSArnaud Minier  * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
6*d6b55a0fSArnaud Minier  *
7*d6b55a0fSArnaud Minier  * SPDX-License-Identifier: GPL-2.0-or-later
8*d6b55a0fSArnaud Minier  *
9*d6b55a0fSArnaud Minier  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10*d6b55a0fSArnaud Minier  * See the COPYING file in the top-level directory.
11*d6b55a0fSArnaud Minier  *
12*d6b55a0fSArnaud Minier  * The reference used is the STMicroElectronics RM0351 Reference manual
13*d6b55a0fSArnaud Minier  * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
14*d6b55a0fSArnaud Minier  *
15*d6b55a0fSArnaud Minier  * Inspired by the BCM2835 CPRMAN clock manager implementation by Luc Michel.
16*d6b55a0fSArnaud Minier  */
17*d6b55a0fSArnaud Minier 
18*d6b55a0fSArnaud Minier #include "qemu/osdep.h"
19*d6b55a0fSArnaud Minier #include "qemu/log.h"
20*d6b55a0fSArnaud Minier #include "qemu/module.h"
21*d6b55a0fSArnaud Minier #include "qemu/timer.h"
22*d6b55a0fSArnaud Minier #include "qapi/error.h"
23*d6b55a0fSArnaud Minier #include "migration/vmstate.h"
24*d6b55a0fSArnaud Minier #include "hw/misc/stm32l4x5_rcc.h"
25*d6b55a0fSArnaud Minier #include "hw/misc/stm32l4x5_rcc_internals.h"
26*d6b55a0fSArnaud Minier #include "hw/clock.h"
27*d6b55a0fSArnaud Minier #include "hw/irq.h"
28*d6b55a0fSArnaud Minier #include "hw/qdev-clock.h"
29*d6b55a0fSArnaud Minier #include "hw/qdev-properties.h"
30*d6b55a0fSArnaud Minier #include "hw/qdev-properties-system.h"
31*d6b55a0fSArnaud Minier #include "trace.h"
32*d6b55a0fSArnaud Minier 
33*d6b55a0fSArnaud Minier #define HSE_DEFAULT_FRQ 48000000ULL
34*d6b55a0fSArnaud Minier #define HSI_FRQ 16000000ULL
35*d6b55a0fSArnaud Minier #define MSI_DEFAULT_FRQ 4000000ULL
36*d6b55a0fSArnaud Minier #define LSE_FRQ 32768ULL
37*d6b55a0fSArnaud Minier #define LSI_FRQ 32000ULL
38*d6b55a0fSArnaud Minier 
39*d6b55a0fSArnaud Minier static void rcc_update_irq(Stm32l4x5RccState *s)
40*d6b55a0fSArnaud Minier {
41*d6b55a0fSArnaud Minier     if (s->cifr & CIFR_IRQ_MASK) {
42*d6b55a0fSArnaud Minier         qemu_irq_raise(s->irq);
43*d6b55a0fSArnaud Minier     } else {
44*d6b55a0fSArnaud Minier         qemu_irq_lower(s->irq);
45*d6b55a0fSArnaud Minier     }
46*d6b55a0fSArnaud Minier }
47*d6b55a0fSArnaud Minier 
48*d6b55a0fSArnaud Minier static void stm32l4x5_rcc_reset_hold(Object *obj)
49*d6b55a0fSArnaud Minier {
50*d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(obj);
51*d6b55a0fSArnaud Minier     s->cr = 0x00000063;
52*d6b55a0fSArnaud Minier     /*
53*d6b55a0fSArnaud Minier      * Factory-programmed calibration data
54*d6b55a0fSArnaud Minier      * From the reference manual: 0x10XX 00XX
55*d6b55a0fSArnaud Minier      * Value taken from a real card.
56*d6b55a0fSArnaud Minier      */
57*d6b55a0fSArnaud Minier     s->icscr = 0x106E0082;
58*d6b55a0fSArnaud Minier     s->cfgr = 0x0;
59*d6b55a0fSArnaud Minier     s->pllcfgr = 0x00001000;
60*d6b55a0fSArnaud Minier     s->pllsai1cfgr = 0x00001000;
61*d6b55a0fSArnaud Minier     s->pllsai2cfgr = 0x00001000;
62*d6b55a0fSArnaud Minier     s->cier = 0x0;
63*d6b55a0fSArnaud Minier     s->cifr = 0x0;
64*d6b55a0fSArnaud Minier     s->ahb1rstr = 0x0;
65*d6b55a0fSArnaud Minier     s->ahb2rstr = 0x0;
66*d6b55a0fSArnaud Minier     s->ahb3rstr = 0x0;
67*d6b55a0fSArnaud Minier     s->apb1rstr1 = 0x0;
68*d6b55a0fSArnaud Minier     s->apb1rstr2 = 0x0;
69*d6b55a0fSArnaud Minier     s->apb2rstr = 0x0;
70*d6b55a0fSArnaud Minier     s->ahb1enr = 0x00000100;
71*d6b55a0fSArnaud Minier     s->ahb2enr = 0x0;
72*d6b55a0fSArnaud Minier     s->ahb3enr = 0x0;
73*d6b55a0fSArnaud Minier     s->apb1enr1 = 0x0;
74*d6b55a0fSArnaud Minier     s->apb1enr2 = 0x0;
75*d6b55a0fSArnaud Minier     s->apb2enr = 0x0;
76*d6b55a0fSArnaud Minier     s->ahb1smenr = 0x00011303;
77*d6b55a0fSArnaud Minier     s->ahb2smenr = 0x000532FF;
78*d6b55a0fSArnaud Minier     s->ahb3smenr =  0x00000101;
79*d6b55a0fSArnaud Minier     s->apb1smenr1 = 0xF2FECA3F;
80*d6b55a0fSArnaud Minier     s->apb1smenr2 = 0x00000025;
81*d6b55a0fSArnaud Minier     s->apb2smenr = 0x01677C01;
82*d6b55a0fSArnaud Minier     s->ccipr = 0x0;
83*d6b55a0fSArnaud Minier     s->bdcr = 0x0;
84*d6b55a0fSArnaud Minier     s->csr = 0x0C000600;
85*d6b55a0fSArnaud Minier }
86*d6b55a0fSArnaud Minier 
87*d6b55a0fSArnaud Minier static uint64_t stm32l4x5_rcc_read(void *opaque, hwaddr addr,
88*d6b55a0fSArnaud Minier                                      unsigned int size)
89*d6b55a0fSArnaud Minier {
90*d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = opaque;
91*d6b55a0fSArnaud Minier     uint64_t retvalue = 0;
92*d6b55a0fSArnaud Minier 
93*d6b55a0fSArnaud Minier     switch (addr) {
94*d6b55a0fSArnaud Minier     case A_CR:
95*d6b55a0fSArnaud Minier         retvalue = s->cr;
96*d6b55a0fSArnaud Minier         break;
97*d6b55a0fSArnaud Minier     case A_ICSCR:
98*d6b55a0fSArnaud Minier         retvalue = s->icscr;
99*d6b55a0fSArnaud Minier         break;
100*d6b55a0fSArnaud Minier     case A_CFGR:
101*d6b55a0fSArnaud Minier         retvalue = s->cfgr;
102*d6b55a0fSArnaud Minier         break;
103*d6b55a0fSArnaud Minier     case A_PLLCFGR:
104*d6b55a0fSArnaud Minier         retvalue = s->pllcfgr;
105*d6b55a0fSArnaud Minier         break;
106*d6b55a0fSArnaud Minier     case A_PLLSAI1CFGR:
107*d6b55a0fSArnaud Minier         retvalue = s->pllsai1cfgr;
108*d6b55a0fSArnaud Minier         break;
109*d6b55a0fSArnaud Minier     case A_PLLSAI2CFGR:
110*d6b55a0fSArnaud Minier         retvalue = s->pllsai2cfgr;
111*d6b55a0fSArnaud Minier         break;
112*d6b55a0fSArnaud Minier     case A_CIER:
113*d6b55a0fSArnaud Minier         retvalue = s->cier;
114*d6b55a0fSArnaud Minier         break;
115*d6b55a0fSArnaud Minier     case A_CIFR:
116*d6b55a0fSArnaud Minier         retvalue = s->cifr;
117*d6b55a0fSArnaud Minier         break;
118*d6b55a0fSArnaud Minier     case A_CICR:
119*d6b55a0fSArnaud Minier         /* CICR is write only, return the reset value = 0 */
120*d6b55a0fSArnaud Minier         break;
121*d6b55a0fSArnaud Minier     case A_AHB1RSTR:
122*d6b55a0fSArnaud Minier         retvalue = s->ahb1rstr;
123*d6b55a0fSArnaud Minier         break;
124*d6b55a0fSArnaud Minier     case A_AHB2RSTR:
125*d6b55a0fSArnaud Minier         retvalue = s->ahb2rstr;
126*d6b55a0fSArnaud Minier         break;
127*d6b55a0fSArnaud Minier     case A_AHB3RSTR:
128*d6b55a0fSArnaud Minier         retvalue = s->ahb3rstr;
129*d6b55a0fSArnaud Minier         break;
130*d6b55a0fSArnaud Minier     case A_APB1RSTR1:
131*d6b55a0fSArnaud Minier         retvalue = s->apb1rstr1;
132*d6b55a0fSArnaud Minier         break;
133*d6b55a0fSArnaud Minier     case A_APB1RSTR2:
134*d6b55a0fSArnaud Minier         retvalue = s->apb1rstr2;
135*d6b55a0fSArnaud Minier         break;
136*d6b55a0fSArnaud Minier     case A_APB2RSTR:
137*d6b55a0fSArnaud Minier         retvalue = s->apb2rstr;
138*d6b55a0fSArnaud Minier         break;
139*d6b55a0fSArnaud Minier     case A_AHB1ENR:
140*d6b55a0fSArnaud Minier         retvalue = s->ahb1enr;
141*d6b55a0fSArnaud Minier         break;
142*d6b55a0fSArnaud Minier     case A_AHB2ENR:
143*d6b55a0fSArnaud Minier         retvalue = s->ahb2enr;
144*d6b55a0fSArnaud Minier         break;
145*d6b55a0fSArnaud Minier     case A_AHB3ENR:
146*d6b55a0fSArnaud Minier         retvalue = s->ahb3enr;
147*d6b55a0fSArnaud Minier         break;
148*d6b55a0fSArnaud Minier     case A_APB1ENR1:
149*d6b55a0fSArnaud Minier         retvalue = s->apb1enr1;
150*d6b55a0fSArnaud Minier         break;
151*d6b55a0fSArnaud Minier     case A_APB1ENR2:
152*d6b55a0fSArnaud Minier         retvalue = s->apb1enr2;
153*d6b55a0fSArnaud Minier         break;
154*d6b55a0fSArnaud Minier     case A_APB2ENR:
155*d6b55a0fSArnaud Minier         retvalue = s->apb2enr;
156*d6b55a0fSArnaud Minier         break;
157*d6b55a0fSArnaud Minier     case A_AHB1SMENR:
158*d6b55a0fSArnaud Minier         retvalue = s->ahb1smenr;
159*d6b55a0fSArnaud Minier         break;
160*d6b55a0fSArnaud Minier     case A_AHB2SMENR:
161*d6b55a0fSArnaud Minier         retvalue = s->ahb2smenr;
162*d6b55a0fSArnaud Minier         break;
163*d6b55a0fSArnaud Minier     case A_AHB3SMENR:
164*d6b55a0fSArnaud Minier         retvalue = s->ahb3smenr;
165*d6b55a0fSArnaud Minier         break;
166*d6b55a0fSArnaud Minier     case A_APB1SMENR1:
167*d6b55a0fSArnaud Minier         retvalue = s->apb1smenr1;
168*d6b55a0fSArnaud Minier         break;
169*d6b55a0fSArnaud Minier     case A_APB1SMENR2:
170*d6b55a0fSArnaud Minier         retvalue = s->apb1smenr2;
171*d6b55a0fSArnaud Minier         break;
172*d6b55a0fSArnaud Minier     case A_APB2SMENR:
173*d6b55a0fSArnaud Minier         retvalue = s->apb2smenr;
174*d6b55a0fSArnaud Minier         break;
175*d6b55a0fSArnaud Minier     case A_CCIPR:
176*d6b55a0fSArnaud Minier         retvalue = s->ccipr;
177*d6b55a0fSArnaud Minier         break;
178*d6b55a0fSArnaud Minier     case A_BDCR:
179*d6b55a0fSArnaud Minier         retvalue = s->bdcr;
180*d6b55a0fSArnaud Minier         break;
181*d6b55a0fSArnaud Minier     case A_CSR:
182*d6b55a0fSArnaud Minier         retvalue = s->csr;
183*d6b55a0fSArnaud Minier         break;
184*d6b55a0fSArnaud Minier     default:
185*d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
186*d6b55a0fSArnaud Minier                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
187*d6b55a0fSArnaud Minier         break;
188*d6b55a0fSArnaud Minier     }
189*d6b55a0fSArnaud Minier 
190*d6b55a0fSArnaud Minier     trace_stm32l4x5_rcc_read(addr, retvalue);
191*d6b55a0fSArnaud Minier 
192*d6b55a0fSArnaud Minier     return retvalue;
193*d6b55a0fSArnaud Minier }
194*d6b55a0fSArnaud Minier 
195*d6b55a0fSArnaud Minier static void stm32l4x5_rcc_write(void *opaque, hwaddr addr,
196*d6b55a0fSArnaud Minier                                   uint64_t val64, unsigned int size)
197*d6b55a0fSArnaud Minier {
198*d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = opaque;
199*d6b55a0fSArnaud Minier     const uint32_t value = val64;
200*d6b55a0fSArnaud Minier 
201*d6b55a0fSArnaud Minier     trace_stm32l4x5_rcc_write(addr, value);
202*d6b55a0fSArnaud Minier 
203*d6b55a0fSArnaud Minier     switch (addr) {
204*d6b55a0fSArnaud Minier     case A_CR:
205*d6b55a0fSArnaud Minier         s->cr = (s->cr & CR_READ_SET_MASK) |
206*d6b55a0fSArnaud Minier                 (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK));
207*d6b55a0fSArnaud Minier         break;
208*d6b55a0fSArnaud Minier     case A_ICSCR:
209*d6b55a0fSArnaud Minier         s->icscr = value & ~ICSCR_READ_ONLY_MASK;
210*d6b55a0fSArnaud Minier         break;
211*d6b55a0fSArnaud Minier     case A_CFGR:
212*d6b55a0fSArnaud Minier         s->cfgr = value & ~CFGR_READ_ONLY_MASK;
213*d6b55a0fSArnaud Minier         break;
214*d6b55a0fSArnaud Minier     case A_PLLCFGR:
215*d6b55a0fSArnaud Minier         s->pllcfgr = value;
216*d6b55a0fSArnaud Minier         break;
217*d6b55a0fSArnaud Minier     case A_PLLSAI1CFGR:
218*d6b55a0fSArnaud Minier         s->pllsai1cfgr = value;
219*d6b55a0fSArnaud Minier         break;
220*d6b55a0fSArnaud Minier     case A_PLLSAI2CFGR:
221*d6b55a0fSArnaud Minier         s->pllsai2cfgr = value;
222*d6b55a0fSArnaud Minier         break;
223*d6b55a0fSArnaud Minier     case A_CIER:
224*d6b55a0fSArnaud Minier         s->cier = value;
225*d6b55a0fSArnaud Minier         break;
226*d6b55a0fSArnaud Minier     case A_CIFR:
227*d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
228*d6b55a0fSArnaud Minier             "%s: Write attempt into read-only register (CIFR) 0x%"PRIx32"\n",
229*d6b55a0fSArnaud Minier             __func__, value);
230*d6b55a0fSArnaud Minier         break;
231*d6b55a0fSArnaud Minier     case A_CICR:
232*d6b55a0fSArnaud Minier         /* Clear interrupt flags by writing a 1 to the CICR register */
233*d6b55a0fSArnaud Minier         s->cifr &= ~value;
234*d6b55a0fSArnaud Minier         rcc_update_irq(s);
235*d6b55a0fSArnaud Minier         break;
236*d6b55a0fSArnaud Minier     /* Reset behaviors are not implemented */
237*d6b55a0fSArnaud Minier     case A_AHB1RSTR:
238*d6b55a0fSArnaud Minier         s->ahb1rstr = value;
239*d6b55a0fSArnaud Minier         break;
240*d6b55a0fSArnaud Minier     case A_AHB2RSTR:
241*d6b55a0fSArnaud Minier         s->ahb2rstr = value;
242*d6b55a0fSArnaud Minier         break;
243*d6b55a0fSArnaud Minier     case A_AHB3RSTR:
244*d6b55a0fSArnaud Minier         s->ahb3rstr = value;
245*d6b55a0fSArnaud Minier         break;
246*d6b55a0fSArnaud Minier     case A_APB1RSTR1:
247*d6b55a0fSArnaud Minier         s->apb1rstr1 = value;
248*d6b55a0fSArnaud Minier         break;
249*d6b55a0fSArnaud Minier     case A_APB1RSTR2:
250*d6b55a0fSArnaud Minier         s->apb1rstr2 = value;
251*d6b55a0fSArnaud Minier         break;
252*d6b55a0fSArnaud Minier     case A_APB2RSTR:
253*d6b55a0fSArnaud Minier         s->apb2rstr = value;
254*d6b55a0fSArnaud Minier         break;
255*d6b55a0fSArnaud Minier     case A_AHB1ENR:
256*d6b55a0fSArnaud Minier         s->ahb1enr = value;
257*d6b55a0fSArnaud Minier         break;
258*d6b55a0fSArnaud Minier     case A_AHB2ENR:
259*d6b55a0fSArnaud Minier         s->ahb2enr = value;
260*d6b55a0fSArnaud Minier         break;
261*d6b55a0fSArnaud Minier     case A_AHB3ENR:
262*d6b55a0fSArnaud Minier         s->ahb3enr = value;
263*d6b55a0fSArnaud Minier         break;
264*d6b55a0fSArnaud Minier     case A_APB1ENR1:
265*d6b55a0fSArnaud Minier         s->apb1enr1 = value;
266*d6b55a0fSArnaud Minier         break;
267*d6b55a0fSArnaud Minier     case A_APB1ENR2:
268*d6b55a0fSArnaud Minier         s->apb1enr2 = value;
269*d6b55a0fSArnaud Minier         break;
270*d6b55a0fSArnaud Minier     case A_APB2ENR:
271*d6b55a0fSArnaud Minier         s->apb2enr = (s->apb2enr & APB2ENR_READ_SET_MASK) | value;
272*d6b55a0fSArnaud Minier         break;
273*d6b55a0fSArnaud Minier     /* Behaviors for Sleep and Stop modes are not implemented */
274*d6b55a0fSArnaud Minier     case A_AHB1SMENR:
275*d6b55a0fSArnaud Minier         s->ahb1smenr = value;
276*d6b55a0fSArnaud Minier         break;
277*d6b55a0fSArnaud Minier     case A_AHB2SMENR:
278*d6b55a0fSArnaud Minier         s->ahb2smenr = value;
279*d6b55a0fSArnaud Minier         break;
280*d6b55a0fSArnaud Minier     case A_AHB3SMENR:
281*d6b55a0fSArnaud Minier         s->ahb3smenr = value;
282*d6b55a0fSArnaud Minier         break;
283*d6b55a0fSArnaud Minier     case A_APB1SMENR1:
284*d6b55a0fSArnaud Minier         s->apb1smenr1 = value;
285*d6b55a0fSArnaud Minier         break;
286*d6b55a0fSArnaud Minier     case A_APB1SMENR2:
287*d6b55a0fSArnaud Minier         s->apb1smenr2 = value;
288*d6b55a0fSArnaud Minier         break;
289*d6b55a0fSArnaud Minier     case A_APB2SMENR:
290*d6b55a0fSArnaud Minier         s->apb2smenr = value;
291*d6b55a0fSArnaud Minier         break;
292*d6b55a0fSArnaud Minier     case A_CCIPR:
293*d6b55a0fSArnaud Minier         s->ccipr = value;
294*d6b55a0fSArnaud Minier         break;
295*d6b55a0fSArnaud Minier     case A_BDCR:
296*d6b55a0fSArnaud Minier         s->bdcr = value & ~BDCR_READ_ONLY_MASK;
297*d6b55a0fSArnaud Minier         break;
298*d6b55a0fSArnaud Minier     case A_CSR:
299*d6b55a0fSArnaud Minier         s->csr = value & ~CSR_READ_ONLY_MASK;
300*d6b55a0fSArnaud Minier         break;
301*d6b55a0fSArnaud Minier     default:
302*d6b55a0fSArnaud Minier         qemu_log_mask(LOG_GUEST_ERROR,
303*d6b55a0fSArnaud Minier                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
304*d6b55a0fSArnaud Minier     }
305*d6b55a0fSArnaud Minier }
306*d6b55a0fSArnaud Minier 
307*d6b55a0fSArnaud Minier static const MemoryRegionOps stm32l4x5_rcc_ops = {
308*d6b55a0fSArnaud Minier     .read = stm32l4x5_rcc_read,
309*d6b55a0fSArnaud Minier     .write = stm32l4x5_rcc_write,
310*d6b55a0fSArnaud Minier     .endianness = DEVICE_NATIVE_ENDIAN,
311*d6b55a0fSArnaud Minier     .valid = {
312*d6b55a0fSArnaud Minier         .max_access_size = 4,
313*d6b55a0fSArnaud Minier         .min_access_size = 4,
314*d6b55a0fSArnaud Minier         .unaligned = false
315*d6b55a0fSArnaud Minier     },
316*d6b55a0fSArnaud Minier     .impl = {
317*d6b55a0fSArnaud Minier         .max_access_size = 4,
318*d6b55a0fSArnaud Minier         .min_access_size = 4,
319*d6b55a0fSArnaud Minier         .unaligned = false
320*d6b55a0fSArnaud Minier     },
321*d6b55a0fSArnaud Minier };
322*d6b55a0fSArnaud Minier 
323*d6b55a0fSArnaud Minier static const ClockPortInitArray stm32l4x5_rcc_clocks = {
324*d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, hsi16_rc, NULL, 0),
325*d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, msi_rc, NULL, 0),
326*d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, hse, NULL, 0),
327*d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, lsi_rc, NULL, 0),
328*d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, lse_crystal, NULL, 0),
329*d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, sai1_extclk, NULL, 0),
330*d6b55a0fSArnaud Minier     QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0),
331*d6b55a0fSArnaud Minier     QDEV_CLOCK_END
332*d6b55a0fSArnaud Minier };
333*d6b55a0fSArnaud Minier 
334*d6b55a0fSArnaud Minier 
335*d6b55a0fSArnaud Minier static void stm32l4x5_rcc_init(Object *obj)
336*d6b55a0fSArnaud Minier {
337*d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(obj);
338*d6b55a0fSArnaud Minier 
339*d6b55a0fSArnaud Minier     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
340*d6b55a0fSArnaud Minier 
341*d6b55a0fSArnaud Minier     memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s,
342*d6b55a0fSArnaud Minier                           TYPE_STM32L4X5_RCC, 0x400);
343*d6b55a0fSArnaud Minier     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
344*d6b55a0fSArnaud Minier 
345*d6b55a0fSArnaud Minier     qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks);
346*d6b55a0fSArnaud Minier 
347*d6b55a0fSArnaud Minier     s->gnd = clock_new(obj, "gnd");
348*d6b55a0fSArnaud Minier }
349*d6b55a0fSArnaud Minier 
350*d6b55a0fSArnaud Minier static const VMStateDescription vmstate_stm32l4x5_rcc = {
351*d6b55a0fSArnaud Minier     .name = TYPE_STM32L4X5_RCC,
352*d6b55a0fSArnaud Minier     .version_id = 1,
353*d6b55a0fSArnaud Minier     .minimum_version_id = 1,
354*d6b55a0fSArnaud Minier     .fields = (VMStateField[]) {
355*d6b55a0fSArnaud Minier         VMSTATE_UINT32(cr, Stm32l4x5RccState),
356*d6b55a0fSArnaud Minier         VMSTATE_UINT32(icscr, Stm32l4x5RccState),
357*d6b55a0fSArnaud Minier         VMSTATE_UINT32(cfgr, Stm32l4x5RccState),
358*d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllcfgr, Stm32l4x5RccState),
359*d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllsai1cfgr, Stm32l4x5RccState),
360*d6b55a0fSArnaud Minier         VMSTATE_UINT32(pllsai2cfgr, Stm32l4x5RccState),
361*d6b55a0fSArnaud Minier         VMSTATE_UINT32(cier, Stm32l4x5RccState),
362*d6b55a0fSArnaud Minier         VMSTATE_UINT32(cifr, Stm32l4x5RccState),
363*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1rstr, Stm32l4x5RccState),
364*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2rstr, Stm32l4x5RccState),
365*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3rstr, Stm32l4x5RccState),
366*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1rstr1, Stm32l4x5RccState),
367*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1rstr2, Stm32l4x5RccState),
368*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2rstr, Stm32l4x5RccState),
369*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1enr, Stm32l4x5RccState),
370*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2enr, Stm32l4x5RccState),
371*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3enr, Stm32l4x5RccState),
372*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1enr1, Stm32l4x5RccState),
373*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1enr2, Stm32l4x5RccState),
374*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2enr, Stm32l4x5RccState),
375*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb1smenr, Stm32l4x5RccState),
376*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb2smenr, Stm32l4x5RccState),
377*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ahb3smenr, Stm32l4x5RccState),
378*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1smenr1, Stm32l4x5RccState),
379*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb1smenr2, Stm32l4x5RccState),
380*d6b55a0fSArnaud Minier         VMSTATE_UINT32(apb2smenr, Stm32l4x5RccState),
381*d6b55a0fSArnaud Minier         VMSTATE_UINT32(ccipr, Stm32l4x5RccState),
382*d6b55a0fSArnaud Minier         VMSTATE_UINT32(bdcr, Stm32l4x5RccState),
383*d6b55a0fSArnaud Minier         VMSTATE_UINT32(csr, Stm32l4x5RccState),
384*d6b55a0fSArnaud Minier         VMSTATE_CLOCK(hsi16_rc, Stm32l4x5RccState),
385*d6b55a0fSArnaud Minier         VMSTATE_CLOCK(msi_rc, Stm32l4x5RccState),
386*d6b55a0fSArnaud Minier         VMSTATE_CLOCK(hse, Stm32l4x5RccState),
387*d6b55a0fSArnaud Minier         VMSTATE_CLOCK(lsi_rc, Stm32l4x5RccState),
388*d6b55a0fSArnaud Minier         VMSTATE_CLOCK(lse_crystal, Stm32l4x5RccState),
389*d6b55a0fSArnaud Minier         VMSTATE_CLOCK(sai1_extclk, Stm32l4x5RccState),
390*d6b55a0fSArnaud Minier         VMSTATE_CLOCK(sai2_extclk, Stm32l4x5RccState),
391*d6b55a0fSArnaud Minier         VMSTATE_END_OF_LIST()
392*d6b55a0fSArnaud Minier     }
393*d6b55a0fSArnaud Minier };
394*d6b55a0fSArnaud Minier 
395*d6b55a0fSArnaud Minier 
396*d6b55a0fSArnaud Minier static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp)
397*d6b55a0fSArnaud Minier {
398*d6b55a0fSArnaud Minier     Stm32l4x5RccState *s = STM32L4X5_RCC(dev);
399*d6b55a0fSArnaud Minier 
400*d6b55a0fSArnaud Minier     if (s->hse_frequency <  4000000ULL ||
401*d6b55a0fSArnaud Minier         s->hse_frequency > 48000000ULL) {
402*d6b55a0fSArnaud Minier             error_setg(errp,
403*d6b55a0fSArnaud Minier                 "HSE frequency is outside of the allowed [4-48]Mhz range: %" PRIx64 "",
404*d6b55a0fSArnaud Minier                 s->hse_frequency);
405*d6b55a0fSArnaud Minier             return;
406*d6b55a0fSArnaud Minier         }
407*d6b55a0fSArnaud Minier 
408*d6b55a0fSArnaud Minier     clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ);
409*d6b55a0fSArnaud Minier     clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency);
410*d6b55a0fSArnaud Minier     clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency);
411*d6b55a0fSArnaud Minier     clock_update(s->gnd, 0);
412*d6b55a0fSArnaud Minier }
413*d6b55a0fSArnaud Minier 
414*d6b55a0fSArnaud Minier static Property stm32l4x5_rcc_properties[] = {
415*d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState,
416*d6b55a0fSArnaud Minier         hse_frequency, HSE_DEFAULT_FRQ),
417*d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState,
418*d6b55a0fSArnaud Minier         sai1_extclk_frequency, 0),
419*d6b55a0fSArnaud Minier     DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState,
420*d6b55a0fSArnaud Minier         sai2_extclk_frequency, 0),
421*d6b55a0fSArnaud Minier     DEFINE_PROP_END_OF_LIST(),
422*d6b55a0fSArnaud Minier };
423*d6b55a0fSArnaud Minier 
424*d6b55a0fSArnaud Minier static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data)
425*d6b55a0fSArnaud Minier {
426*d6b55a0fSArnaud Minier     DeviceClass *dc = DEVICE_CLASS(klass);
427*d6b55a0fSArnaud Minier     ResettableClass *rc = RESETTABLE_CLASS(klass);
428*d6b55a0fSArnaud Minier 
429*d6b55a0fSArnaud Minier 
430*d6b55a0fSArnaud Minier     rc->phases.hold = stm32l4x5_rcc_reset_hold;
431*d6b55a0fSArnaud Minier     device_class_set_props(dc, stm32l4x5_rcc_properties);
432*d6b55a0fSArnaud Minier     dc->realize = stm32l4x5_rcc_realize;
433*d6b55a0fSArnaud Minier     dc->vmsd = &vmstate_stm32l4x5_rcc;
434*d6b55a0fSArnaud Minier }
435*d6b55a0fSArnaud Minier 
436*d6b55a0fSArnaud Minier static const TypeInfo stm32l4x5_rcc_types[] = {
437*d6b55a0fSArnaud Minier     {
438*d6b55a0fSArnaud Minier         .name           = TYPE_STM32L4X5_RCC,
439*d6b55a0fSArnaud Minier         .parent         = TYPE_SYS_BUS_DEVICE,
440*d6b55a0fSArnaud Minier         .instance_size  = sizeof(Stm32l4x5RccState),
441*d6b55a0fSArnaud Minier         .instance_init  = stm32l4x5_rcc_init,
442*d6b55a0fSArnaud Minier         .class_init     = stm32l4x5_rcc_class_init,
443*d6b55a0fSArnaud Minier     }
444*d6b55a0fSArnaud Minier };
445*d6b55a0fSArnaud Minier 
446*d6b55a0fSArnaud Minier DEFINE_TYPES(stm32l4x5_rcc_types)
447