xref: /qemu/hw/misc/bcm2835_cprman.c (revision 6d2b874cf1a6f595df805835325e9124c26f3dbf)
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);
334