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