hw/misc/bcm2835_cprman: implement PLLs behaviour
[qemu.git] / hw / misc / bcm2835_cprman.c
1 /*
2 * BCM2835 CPRMAN clock manager
3 *
4 * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 /*
10 * This peripheral is roughly divided into 3 main parts:
11 * - the PLLs
12 * - the PLL channels
13 * - the clock muxes
14 *
15 * A main oscillator (xosc) feeds all the PLLs. Each PLLs has one or more
16 * channels. Those channel are then connected to the clock muxes. Each mux has
17 * multiples sources (usually the xosc, some of the PLL channels and some "test
18 * debug" clocks). A mux is configured to select a given source through its
19 * control register. Each mux has one output clock that also goes out of the
20 * CPRMAN. This output clock usually connects to another peripheral in the SoC
21 * (so a given mux is dedicated to a peripheral).
22 *
23 * At each level (PLL, channel and mux), the clock can be altered through
24 * dividers (and multipliers in case of the PLLs), and can be disabled (in this
25 * case, the next levels see no clock).
26 *
27 * This can be sum-up as follows (this is an example and not the actual BCM2835
28 * clock tree):
29 *
30 * /-->[PLL]-|->[PLL channel]--... [mux]--> to peripherals
31 * | |->[PLL channel] muxes takes [mux]
32 * | \->[PLL channel] inputs from [mux]
33 * | some channels [mux]
34 * [xosc]---|-->[PLL]-|->[PLL channel] and other srcs [mux]
35 * | \->[PLL channel] ...-->[mux]
36 * | [mux]
37 * \-->[PLL]--->[PLL channel] [mux]
38 *
39 * The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
40 * tree configuration.
41 */
42
43 #include "qemu/osdep.h"
44 #include "qemu/log.h"
45 #include "migration/vmstate.h"
46 #include "hw/qdev-properties.h"
47 #include "hw/misc/bcm2835_cprman.h"
48 #include "hw/misc/bcm2835_cprman_internals.h"
49 #include "trace.h"
50
51 /* PLL */
52
53 static bool pll_is_locked(const CprmanPllState *pll)
54 {
55 return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
56 && !FIELD_EX32(*pll->reg_cm, CM_PLLx, ANARST);
57 }
58
59 static void pll_update(CprmanPllState *pll)
60 {
61 uint64_t freq, ndiv, fdiv, pdiv;
62
63 if (!pll_is_locked(pll)) {
64 clock_update(pll->out, 0);
65 return;
66 }
67
68 pdiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PDIV);
69
70 if (!pdiv) {
71 clock_update(pll->out, 0);
72 return;
73 }
74
75 ndiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, NDIV);
76 fdiv = FIELD_EX32(*pll->reg_a2w_frac, A2W_PLLx_FRAC, FRAC);
77
78 if (pll->reg_a2w_ana[1] & pll->prediv_mask) {
79 /* The prescaler doubles the parent frequency */
80 ndiv *= 2;
81 fdiv *= 2;
82 }
83
84 /*
85 * We have a multiplier with an integer part (ndiv) and a fractional part
86 * (fdiv), and a divider (pdiv).
87 */
88 freq = clock_get_hz(pll->xosc_in) *
89 ((ndiv << R_A2W_PLLx_FRAC_FRAC_LENGTH) + fdiv);
90 freq /= pdiv;
91 freq >>= R_A2W_PLLx_FRAC_FRAC_LENGTH;
92
93 clock_update_hz(pll->out, freq);
94 }
95
96 static void pll_xosc_update(void *opaque)
97 {
98 pll_update(CPRMAN_PLL(opaque));
99 }
100
101 static void pll_init(Object *obj)
102 {
103 CprmanPllState *s = CPRMAN_PLL(obj);
104
105 s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update, s);
106 s->out = qdev_init_clock_out(DEVICE(s), "out");
107 }
108
109 static const VMStateDescription pll_vmstate = {
110 .name = TYPE_CPRMAN_PLL,
111 .version_id = 1,
112 .minimum_version_id = 1,
113 .fields = (VMStateField[]) {
114 VMSTATE_CLOCK(xosc_in, CprmanPllState),
115 VMSTATE_END_OF_LIST()
116 }
117 };
118
119 static void pll_class_init(ObjectClass *klass, void *data)
120 {
121 DeviceClass *dc = DEVICE_CLASS(klass);
122
123 dc->vmsd = &pll_vmstate;
124 }
125
126 static const TypeInfo cprman_pll_info = {
127 .name = TYPE_CPRMAN_PLL,
128 .parent = TYPE_DEVICE,
129 .instance_size = sizeof(CprmanPllState),
130 .class_init = pll_class_init,
131 .instance_init = pll_init,
132 };
133
134
135 /* CPRMAN "top level" model */
136
137 static uint32_t get_cm_lock(const BCM2835CprmanState *s)
138 {
139 static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = {
140 [CPRMAN_PLLA] = R_CM_LOCK_FLOCKA_SHIFT,
141 [CPRMAN_PLLC] = R_CM_LOCK_FLOCKC_SHIFT,
142 [CPRMAN_PLLD] = R_CM_LOCK_FLOCKD_SHIFT,
143 [CPRMAN_PLLH] = R_CM_LOCK_FLOCKH_SHIFT,
144 [CPRMAN_PLLB] = R_CM_LOCK_FLOCKB_SHIFT,
145 };
146
147 uint32_t r = 0;
148 size_t i;
149
150 for (i = 0; i < CPRMAN_NUM_PLL; i++) {
151 r |= pll_is_locked(&s->plls[i]) << CM_LOCK_MAPPING[i];
152 }
153
154 return r;
155 }
156
157 static uint64_t cprman_read(void *opaque, hwaddr offset,
158 unsigned size)
159 {
160 BCM2835CprmanState *s = CPRMAN(opaque);
161 uint64_t r = 0;
162 size_t idx = offset / sizeof(uint32_t);
163
164 switch (idx) {
165 case R_CM_LOCK:
166 r = get_cm_lock(s);
167 break;
168
169 default:
170 r = s->regs[idx];
171 }
172
173 trace_bcm2835_cprman_read(offset, r);
174 return r;
175 }
176
177 #define CASE_PLL_REGS(pll_) \
178 case R_CM_ ## pll_: \
179 case R_A2W_ ## pll_ ## _CTRL: \
180 case R_A2W_ ## pll_ ## _ANA0: \
181 case R_A2W_ ## pll_ ## _ANA1: \
182 case R_A2W_ ## pll_ ## _ANA2: \
183 case R_A2W_ ## pll_ ## _ANA3: \
184 case R_A2W_ ## pll_ ## _FRAC
185
186 static void cprman_write(void *opaque, hwaddr offset,
187 uint64_t value, unsigned size)
188 {
189 BCM2835CprmanState *s = CPRMAN(opaque);
190 size_t idx = offset / sizeof(uint32_t);
191
192 if (FIELD_EX32(value, CPRMAN, PASSWORD) != CPRMAN_PASSWORD) {
193 trace_bcm2835_cprman_write_invalid_magic(offset, value);
194 return;
195 }
196
197 value &= ~R_CPRMAN_PASSWORD_MASK;
198
199 trace_bcm2835_cprman_write(offset, value);
200 s->regs[idx] = value;
201
202 switch (idx) {
203 CASE_PLL_REGS(PLLA) :
204 pll_update(&s->plls[CPRMAN_PLLA]);
205 break;
206
207 CASE_PLL_REGS(PLLC) :
208 pll_update(&s->plls[CPRMAN_PLLC]);
209 break;
210
211 CASE_PLL_REGS(PLLD) :
212 pll_update(&s->plls[CPRMAN_PLLD]);
213 break;
214
215 CASE_PLL_REGS(PLLH) :
216 pll_update(&s->plls[CPRMAN_PLLH]);
217 break;
218
219 CASE_PLL_REGS(PLLB) :
220 pll_update(&s->plls[CPRMAN_PLLB]);
221 break;
222 }
223 }
224
225 #undef CASE_PLL_REGS
226
227 static const MemoryRegionOps cprman_ops = {
228 .read = cprman_read,
229 .write = cprman_write,
230 .endianness = DEVICE_LITTLE_ENDIAN,
231 .valid = {
232 /*
233 * Although this hasn't been checked against real hardware, nor the
234 * information can be found in a datasheet, it seems reasonable because
235 * of the "PASSWORD" magic value found in every registers.
236 */
237 .min_access_size = 4,
238 .max_access_size = 4,
239 .unaligned = false,
240 },
241 .impl = {
242 .max_access_size = 4,
243 },
244 };
245
246 static void cprman_reset(DeviceState *dev)
247 {
248 BCM2835CprmanState *s = CPRMAN(dev);
249 size_t i;
250
251 memset(s->regs, 0, sizeof(s->regs));
252
253 for (i = 0; i < CPRMAN_NUM_PLL; i++) {
254 device_cold_reset(DEVICE(&s->plls[i]));
255 }
256
257 clock_update_hz(s->xosc, s->xosc_freq);
258 }
259
260 static void cprman_init(Object *obj)
261 {
262 BCM2835CprmanState *s = CPRMAN(obj);
263 size_t i;
264
265 for (i = 0; i < CPRMAN_NUM_PLL; i++) {
266 object_initialize_child(obj, PLL_INIT_INFO[i].name,
267 &s->plls[i], TYPE_CPRMAN_PLL);
268 set_pll_init_info(s, &s->plls[i], i);
269 }
270
271 s->xosc = clock_new(obj, "xosc");
272
273 memory_region_init_io(&s->iomem, obj, &cprman_ops,
274 s, "bcm2835-cprman", 0x2000);
275 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
276 }
277
278 static void cprman_realize(DeviceState *dev, Error **errp)
279 {
280 BCM2835CprmanState *s = CPRMAN(dev);
281 size_t i;
282
283 for (i = 0; i < CPRMAN_NUM_PLL; i++) {
284 CprmanPllState *pll = &s->plls[i];
285
286 clock_set_source(pll->xosc_in, s->xosc);
287
288 if (!qdev_realize(DEVICE(pll), NULL, errp)) {
289 return;
290 }
291 }
292 }
293
294 static const VMStateDescription cprman_vmstate = {
295 .name = TYPE_BCM2835_CPRMAN,
296 .version_id = 1,
297 .minimum_version_id = 1,
298 .fields = (VMStateField[]) {
299 VMSTATE_UINT32_ARRAY(regs, BCM2835CprmanState, CPRMAN_NUM_REGS),
300 VMSTATE_END_OF_LIST()
301 }
302 };
303
304 static Property cprman_properties[] = {
305 DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000),
306 DEFINE_PROP_END_OF_LIST()
307 };
308
309 static void cprman_class_init(ObjectClass *klass, void *data)
310 {
311 DeviceClass *dc = DEVICE_CLASS(klass);
312
313 dc->realize = cprman_realize;
314 dc->reset = cprman_reset;
315 dc->vmsd = &cprman_vmstate;
316 device_class_set_props(dc, cprman_properties);
317 }
318
319 static const TypeInfo cprman_info = {
320 .name = TYPE_BCM2835_CPRMAN,
321 .parent = TYPE_SYS_BUS_DEVICE,
322 .instance_size = sizeof(BCM2835CprmanState),
323 .class_init = cprman_class_init,
324 .instance_init = cprman_init,
325 };
326
327 static void cprman_register_types(void)
328 {
329 type_register_static(&cprman_info);
330 type_register_static(&cprman_pll_info);
331 }
332
333 type_init(cprman_register_types);