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.
4172813624SLuc Michel *
4272813624SLuc Michel * The CPRMAN exposes clock outputs with the name of the clock mux suffixed
4372813624SLuc Michel * with "-out" (e.g. "uart-out", "h264-out", ...).
44fc14176bSLuc Michel */
45fc14176bSLuc Michel
46fc14176bSLuc Michel #include "qemu/osdep.h"
47fc14176bSLuc Michel #include "qemu/log.h"
48fc14176bSLuc Michel #include "migration/vmstate.h"
49fc14176bSLuc Michel #include "hw/qdev-properties.h"
50fc14176bSLuc Michel #include "hw/misc/bcm2835_cprman.h"
51fc14176bSLuc Michel #include "hw/misc/bcm2835_cprman_internals.h"
52fc14176bSLuc Michel #include "trace.h"
53fc14176bSLuc Michel
541e986e25SLuc Michel /* PLL */
551e986e25SLuc Michel
pll_reset(DeviceState * dev)5683ad4695SLuc Michel static void pll_reset(DeviceState *dev)
5783ad4695SLuc Michel {
5883ad4695SLuc Michel CprmanPllState *s = CPRMAN_PLL(dev);
5983ad4695SLuc Michel const PLLResetInfo *info = &PLL_RESET_INFO[s->id];
6083ad4695SLuc Michel
6183ad4695SLuc Michel *s->reg_cm = info->cm;
6283ad4695SLuc Michel *s->reg_a2w_ctrl = info->a2w_ctrl;
6383ad4695SLuc Michel memcpy(s->reg_a2w_ana, info->a2w_ana, sizeof(info->a2w_ana));
6483ad4695SLuc Michel *s->reg_a2w_frac = info->a2w_frac;
6583ad4695SLuc Michel }
6683ad4695SLuc Michel
pll_is_locked(const CprmanPllState * pll)676d2b874cSLuc Michel static bool pll_is_locked(const CprmanPllState *pll)
686d2b874cSLuc Michel {
696d2b874cSLuc Michel return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
706d2b874cSLuc Michel && !FIELD_EX32(*pll->reg_cm, CM_PLLx, ANARST);
716d2b874cSLuc Michel }
726d2b874cSLuc Michel
pll_update(CprmanPllState * pll)731e986e25SLuc Michel static void pll_update(CprmanPllState *pll)
741e986e25SLuc Michel {
756d2b874cSLuc Michel uint64_t freq, ndiv, fdiv, pdiv;
766d2b874cSLuc Michel
776d2b874cSLuc Michel if (!pll_is_locked(pll)) {
781e986e25SLuc Michel clock_update(pll->out, 0);
796d2b874cSLuc Michel return;
806d2b874cSLuc Michel }
816d2b874cSLuc Michel
826d2b874cSLuc Michel pdiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PDIV);
836d2b874cSLuc Michel
846d2b874cSLuc Michel if (!pdiv) {
856d2b874cSLuc Michel clock_update(pll->out, 0);
866d2b874cSLuc Michel return;
876d2b874cSLuc Michel }
886d2b874cSLuc Michel
896d2b874cSLuc Michel ndiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, NDIV);
906d2b874cSLuc Michel fdiv = FIELD_EX32(*pll->reg_a2w_frac, A2W_PLLx_FRAC, FRAC);
916d2b874cSLuc Michel
926d2b874cSLuc Michel if (pll->reg_a2w_ana[1] & pll->prediv_mask) {
936d2b874cSLuc Michel /* The prescaler doubles the parent frequency */
946d2b874cSLuc Michel ndiv *= 2;
956d2b874cSLuc Michel fdiv *= 2;
966d2b874cSLuc Michel }
976d2b874cSLuc Michel
986d2b874cSLuc Michel /*
996d2b874cSLuc Michel * We have a multiplier with an integer part (ndiv) and a fractional part
1006d2b874cSLuc Michel * (fdiv), and a divider (pdiv).
1016d2b874cSLuc Michel */
1026d2b874cSLuc Michel freq = clock_get_hz(pll->xosc_in) *
1036d2b874cSLuc Michel ((ndiv << R_A2W_PLLx_FRAC_FRAC_LENGTH) + fdiv);
1046d2b874cSLuc Michel freq /= pdiv;
1056d2b874cSLuc Michel freq >>= R_A2W_PLLx_FRAC_FRAC_LENGTH;
1066d2b874cSLuc Michel
1076d2b874cSLuc Michel clock_update_hz(pll->out, freq);
1081e986e25SLuc Michel }
1091e986e25SLuc Michel
pll_xosc_update(void * opaque,ClockEvent event)1105ee0abedSPeter Maydell static void pll_xosc_update(void *opaque, ClockEvent event)
1111e986e25SLuc Michel {
1121e986e25SLuc Michel pll_update(CPRMAN_PLL(opaque));
1131e986e25SLuc Michel }
1141e986e25SLuc Michel
pll_init(Object * obj)1151e986e25SLuc Michel static void pll_init(Object *obj)
1161e986e25SLuc Michel {
1171e986e25SLuc Michel CprmanPllState *s = CPRMAN_PLL(obj);
1181e986e25SLuc Michel
1195ee0abedSPeter Maydell s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update,
1205ee0abedSPeter Maydell s, ClockUpdate);
1211e986e25SLuc Michel s->out = qdev_init_clock_out(DEVICE(s), "out");
1221e986e25SLuc Michel }
1231e986e25SLuc Michel
1241e986e25SLuc Michel static const VMStateDescription pll_vmstate = {
1251e986e25SLuc Michel .name = TYPE_CPRMAN_PLL,
1261e986e25SLuc Michel .version_id = 1,
1271e986e25SLuc Michel .minimum_version_id = 1,
128e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
1291e986e25SLuc Michel VMSTATE_CLOCK(xosc_in, CprmanPllState),
1301e986e25SLuc Michel VMSTATE_END_OF_LIST()
1311e986e25SLuc Michel }
1321e986e25SLuc Michel };
1331e986e25SLuc Michel
pll_class_init(ObjectClass * klass,void * data)1341e986e25SLuc Michel static void pll_class_init(ObjectClass *klass, void *data)
1351e986e25SLuc Michel {
1361e986e25SLuc Michel DeviceClass *dc = DEVICE_CLASS(klass);
1371e986e25SLuc Michel
138*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, pll_reset);
1391e986e25SLuc Michel dc->vmsd = &pll_vmstate;
1401e986e25SLuc Michel }
1411e986e25SLuc Michel
1421e986e25SLuc Michel static const TypeInfo cprman_pll_info = {
1431e986e25SLuc Michel .name = TYPE_CPRMAN_PLL,
1441e986e25SLuc Michel .parent = TYPE_DEVICE,
1451e986e25SLuc Michel .instance_size = sizeof(CprmanPllState),
1461e986e25SLuc Michel .class_init = pll_class_init,
1471e986e25SLuc Michel .instance_init = pll_init,
1481e986e25SLuc Michel };
1491e986e25SLuc Michel
1501e986e25SLuc Michel
15109d56bbcSLuc Michel /* PLL channel */
15209d56bbcSLuc Michel
pll_channel_reset(DeviceState * dev)15383ad4695SLuc Michel static void pll_channel_reset(DeviceState *dev)
15483ad4695SLuc Michel {
15583ad4695SLuc Michel CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(dev);
15683ad4695SLuc Michel const PLLChannelResetInfo *info = &PLL_CHANNEL_RESET_INFO[s->id];
15783ad4695SLuc Michel
15883ad4695SLuc Michel *s->reg_a2w_ctrl = info->a2w_ctrl;
15983ad4695SLuc Michel }
16083ad4695SLuc Michel
pll_channel_is_enabled(CprmanPllChannelState * channel)16195745811SLuc Michel static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
16295745811SLuc Michel {
16395745811SLuc Michel /*
16495745811SLuc Michel * XXX I'm not sure of the purpose of the LOAD field. The Linux driver does
16595745811SLuc Michel * not set it when enabling the channel, but does clear it when disabling
16695745811SLuc Michel * it.
16795745811SLuc Michel */
16895745811SLuc Michel return !FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DISABLE)
16995745811SLuc Michel && !(*channel->reg_cm & channel->hold_mask);
17095745811SLuc Michel }
17195745811SLuc Michel
pll_channel_update(CprmanPllChannelState * channel)17209d56bbcSLuc Michel static void pll_channel_update(CprmanPllChannelState *channel)
17309d56bbcSLuc Michel {
17495745811SLuc Michel uint64_t freq, div;
17595745811SLuc Michel
17695745811SLuc Michel if (!pll_channel_is_enabled(channel)) {
17709d56bbcSLuc Michel clock_update(channel->out, 0);
17895745811SLuc Michel return;
17995745811SLuc Michel }
18095745811SLuc Michel
18195745811SLuc Michel div = FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DIV);
18295745811SLuc Michel
18395745811SLuc Michel if (!div) {
18495745811SLuc Michel /*
18595745811SLuc Michel * It seems that when the divider value is 0, it is considered as
18695745811SLuc Michel * being maximum by the hardware (see the Linux driver).
18795745811SLuc Michel */
18895745811SLuc Michel div = R_A2W_PLLx_CHANNELy_DIV_MASK;
18995745811SLuc Michel }
19095745811SLuc Michel
19195745811SLuc Michel /* Some channels have an additional fixed divider */
19295745811SLuc Michel freq = clock_get_hz(channel->pll_in) / (div * channel->fixed_divider);
19395745811SLuc Michel
19495745811SLuc Michel clock_update_hz(channel->out, freq);
19509d56bbcSLuc Michel }
19609d56bbcSLuc Michel
19709d56bbcSLuc Michel /* Update a PLL and all its channels */
pll_update_all_channels(BCM2835CprmanState * s,CprmanPllState * pll)19809d56bbcSLuc Michel static void pll_update_all_channels(BCM2835CprmanState *s,
19909d56bbcSLuc Michel CprmanPllState *pll)
20009d56bbcSLuc Michel {
20109d56bbcSLuc Michel size_t i;
20209d56bbcSLuc Michel
20309d56bbcSLuc Michel pll_update(pll);
20409d56bbcSLuc Michel
20509d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
20609d56bbcSLuc Michel CprmanPllChannelState *channel = &s->channels[i];
20709d56bbcSLuc Michel if (channel->parent == pll->id) {
20809d56bbcSLuc Michel pll_channel_update(channel);
20909d56bbcSLuc Michel }
21009d56bbcSLuc Michel }
21109d56bbcSLuc Michel }
21209d56bbcSLuc Michel
pll_channel_pll_in_update(void * opaque,ClockEvent event)2135ee0abedSPeter Maydell static void pll_channel_pll_in_update(void *opaque, ClockEvent event)
21409d56bbcSLuc Michel {
21509d56bbcSLuc Michel pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
21609d56bbcSLuc Michel }
21709d56bbcSLuc Michel
pll_channel_init(Object * obj)21809d56bbcSLuc Michel static void pll_channel_init(Object *obj)
21909d56bbcSLuc Michel {
22009d56bbcSLuc Michel CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj);
22109d56bbcSLuc Michel
22209d56bbcSLuc Michel s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in",
2235ee0abedSPeter Maydell pll_channel_pll_in_update, s,
2245ee0abedSPeter Maydell ClockUpdate);
22509d56bbcSLuc Michel s->out = qdev_init_clock_out(DEVICE(s), "out");
22609d56bbcSLuc Michel }
22709d56bbcSLuc Michel
22809d56bbcSLuc Michel static const VMStateDescription pll_channel_vmstate = {
22909d56bbcSLuc Michel .name = TYPE_CPRMAN_PLL_CHANNEL,
23009d56bbcSLuc Michel .version_id = 1,
23109d56bbcSLuc Michel .minimum_version_id = 1,
232e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
23309d56bbcSLuc Michel VMSTATE_CLOCK(pll_in, CprmanPllChannelState),
23409d56bbcSLuc Michel VMSTATE_END_OF_LIST()
23509d56bbcSLuc Michel }
23609d56bbcSLuc Michel };
23709d56bbcSLuc Michel
pll_channel_class_init(ObjectClass * klass,void * data)23809d56bbcSLuc Michel static void pll_channel_class_init(ObjectClass *klass, void *data)
23909d56bbcSLuc Michel {
24009d56bbcSLuc Michel DeviceClass *dc = DEVICE_CLASS(klass);
24109d56bbcSLuc Michel
242*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, pll_channel_reset);
24309d56bbcSLuc Michel dc->vmsd = &pll_channel_vmstate;
24409d56bbcSLuc Michel }
24509d56bbcSLuc Michel
24609d56bbcSLuc Michel static const TypeInfo cprman_pll_channel_info = {
24709d56bbcSLuc Michel .name = TYPE_CPRMAN_PLL_CHANNEL,
24809d56bbcSLuc Michel .parent = TYPE_DEVICE,
24909d56bbcSLuc Michel .instance_size = sizeof(CprmanPllChannelState),
25009d56bbcSLuc Michel .class_init = pll_channel_class_init,
25109d56bbcSLuc Michel .instance_init = pll_channel_init,
25209d56bbcSLuc Michel };
25309d56bbcSLuc Michel
25409d56bbcSLuc Michel
25572813624SLuc Michel /* clock mux */
25672813624SLuc Michel
clock_mux_is_enabled(CprmanClockMuxState * mux)257fc984085SLuc Michel static bool clock_mux_is_enabled(CprmanClockMuxState *mux)
258fc984085SLuc Michel {
259fc984085SLuc Michel return FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, ENABLE);
260fc984085SLuc Michel }
261fc984085SLuc Michel
clock_mux_update(CprmanClockMuxState * mux)26272813624SLuc Michel static void clock_mux_update(CprmanClockMuxState *mux)
26372813624SLuc Michel {
264fc984085SLuc Michel uint64_t freq;
265fc984085SLuc Michel uint32_t div, src = FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, SRC);
266fc984085SLuc Michel bool enabled = clock_mux_is_enabled(mux);
267fc984085SLuc Michel
268fc984085SLuc Michel *mux->reg_ctl = FIELD_DP32(*mux->reg_ctl, CM_CLOCKx_CTL, BUSY, enabled);
269fc984085SLuc Michel
270fc984085SLuc Michel if (!enabled) {
27172813624SLuc Michel clock_update(mux->out, 0);
272fc984085SLuc Michel return;
273fc984085SLuc Michel }
274fc984085SLuc Michel
275fc984085SLuc Michel freq = clock_get_hz(mux->srcs[src]);
276fc984085SLuc Michel
277fc984085SLuc Michel if (mux->int_bits == 0 && mux->frac_bits == 0) {
278fc984085SLuc Michel clock_update_hz(mux->out, freq);
279fc984085SLuc Michel return;
280fc984085SLuc Michel }
281fc984085SLuc Michel
282fc984085SLuc Michel /*
283fc984085SLuc Michel * The divider has an integer and a fractional part. The size of each part
284fc984085SLuc Michel * varies with the muxes (int_bits and frac_bits). Both parts are
285fc984085SLuc Michel * concatenated, with the integer part always starting at bit 12.
286fc984085SLuc Michel *
287fc984085SLuc Michel * 31 12 11 0
288fc984085SLuc Michel * ------------------------------
289fc984085SLuc Michel * CM_DIV | | int | frac | |
290fc984085SLuc Michel * ------------------------------
291fc984085SLuc Michel * <-----> <------>
292fc984085SLuc Michel * int_bits frac_bits
293fc984085SLuc Michel */
294fc984085SLuc Michel div = extract32(*mux->reg_div,
295fc984085SLuc Michel R_CM_CLOCKx_DIV_FRAC_LENGTH - mux->frac_bits,
296fc984085SLuc Michel mux->int_bits + mux->frac_bits);
297fc984085SLuc Michel
298fc984085SLuc Michel if (!div) {
299fc984085SLuc Michel clock_update(mux->out, 0);
300fc984085SLuc Michel return;
301fc984085SLuc Michel }
302fc984085SLuc Michel
303fc984085SLuc Michel freq = muldiv64(freq, 1 << mux->frac_bits, div);
304fc984085SLuc Michel
305fc984085SLuc Michel clock_update_hz(mux->out, freq);
30672813624SLuc Michel }
30772813624SLuc Michel
clock_mux_src_update(void * opaque,ClockEvent event)3085ee0abedSPeter Maydell static void clock_mux_src_update(void *opaque, ClockEvent event)
30972813624SLuc Michel {
31072813624SLuc Michel CprmanClockMuxState **backref = opaque;
31172813624SLuc Michel CprmanClockMuxState *s = *backref;
312fc984085SLuc Michel CprmanClockMuxSource src = backref - s->backref;
313fc984085SLuc Michel
314fc984085SLuc Michel if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) {
315fc984085SLuc Michel return;
316fc984085SLuc Michel }
31772813624SLuc Michel
31872813624SLuc Michel clock_mux_update(s);
31972813624SLuc Michel }
32072813624SLuc Michel
clock_mux_reset(DeviceState * dev)32183ad4695SLuc Michel static void clock_mux_reset(DeviceState *dev)
32283ad4695SLuc Michel {
32383ad4695SLuc Michel CprmanClockMuxState *clock = CPRMAN_CLOCK_MUX(dev);
32483ad4695SLuc Michel const ClockMuxResetInfo *info = &CLOCK_MUX_RESET_INFO[clock->id];
32583ad4695SLuc Michel
32683ad4695SLuc Michel *clock->reg_ctl = info->cm_ctl;
32783ad4695SLuc Michel *clock->reg_div = info->cm_div;
32883ad4695SLuc Michel }
32983ad4695SLuc Michel
clock_mux_init(Object * obj)33072813624SLuc Michel static void clock_mux_init(Object *obj)
33172813624SLuc Michel {
33272813624SLuc Michel CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
33372813624SLuc Michel size_t i;
33472813624SLuc Michel
33572813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
33672813624SLuc Michel char *name = g_strdup_printf("srcs[%zu]", i);
33772813624SLuc Michel s->backref[i] = s;
33872813624SLuc Michel s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
33972813624SLuc Michel clock_mux_src_update,
3405ee0abedSPeter Maydell &s->backref[i],
3415ee0abedSPeter Maydell ClockUpdate);
34272813624SLuc Michel g_free(name);
34372813624SLuc Michel }
34472813624SLuc Michel
34572813624SLuc Michel s->out = qdev_init_clock_out(DEVICE(s), "out");
34672813624SLuc Michel }
34772813624SLuc Michel
34872813624SLuc Michel static const VMStateDescription clock_mux_vmstate = {
34972813624SLuc Michel .name = TYPE_CPRMAN_CLOCK_MUX,
35072813624SLuc Michel .version_id = 1,
35172813624SLuc Michel .minimum_version_id = 1,
352e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
35372813624SLuc Michel VMSTATE_ARRAY_CLOCK(srcs, CprmanClockMuxState,
35472813624SLuc Michel CPRMAN_NUM_CLOCK_MUX_SRC),
35572813624SLuc Michel VMSTATE_END_OF_LIST()
35672813624SLuc Michel }
35772813624SLuc Michel };
35872813624SLuc Michel
clock_mux_class_init(ObjectClass * klass,void * data)35972813624SLuc Michel static void clock_mux_class_init(ObjectClass *klass, void *data)
36072813624SLuc Michel {
36172813624SLuc Michel DeviceClass *dc = DEVICE_CLASS(klass);
36272813624SLuc Michel
363*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, clock_mux_reset);
36472813624SLuc Michel dc->vmsd = &clock_mux_vmstate;
36572813624SLuc Michel }
36672813624SLuc Michel
36772813624SLuc Michel static const TypeInfo cprman_clock_mux_info = {
36872813624SLuc Michel .name = TYPE_CPRMAN_CLOCK_MUX,
36972813624SLuc Michel .parent = TYPE_DEVICE,
37072813624SLuc Michel .instance_size = sizeof(CprmanClockMuxState),
37172813624SLuc Michel .class_init = clock_mux_class_init,
37272813624SLuc Michel .instance_init = clock_mux_init,
37372813624SLuc Michel };
37472813624SLuc Michel
37572813624SLuc Michel
376502960caSLuc Michel /* DSI0HSCK mux */
377502960caSLuc Michel
dsi0hsck_mux_update(CprmanDsi0HsckMuxState * s)378502960caSLuc Michel static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s)
379502960caSLuc Michel {
380502960caSLuc Michel bool src_is_plld = FIELD_EX32(*s->reg_cm, CM_DSI0HSCK, SELPLLD);
381502960caSLuc Michel Clock *src = src_is_plld ? s->plld_in : s->plla_in;
382502960caSLuc Michel
383502960caSLuc Michel clock_update(s->out, clock_get(src));
384502960caSLuc Michel }
385502960caSLuc Michel
dsi0hsck_mux_in_update(void * opaque,ClockEvent event)3865ee0abedSPeter Maydell static void dsi0hsck_mux_in_update(void *opaque, ClockEvent event)
387502960caSLuc Michel {
388502960caSLuc Michel dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
389502960caSLuc Michel }
390502960caSLuc Michel
dsi0hsck_mux_init(Object * obj)391502960caSLuc Michel static void dsi0hsck_mux_init(Object *obj)
392502960caSLuc Michel {
393502960caSLuc Michel CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
394502960caSLuc Michel DeviceState *dev = DEVICE(obj);
395502960caSLuc Michel
3965ee0abedSPeter Maydell s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update,
3975ee0abedSPeter Maydell s, ClockUpdate);
3985ee0abedSPeter Maydell s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update,
3995ee0abedSPeter Maydell s, ClockUpdate);
400502960caSLuc Michel s->out = qdev_init_clock_out(DEVICE(s), "out");
401502960caSLuc Michel }
402502960caSLuc Michel
403502960caSLuc Michel static const VMStateDescription dsi0hsck_mux_vmstate = {
404502960caSLuc Michel .name = TYPE_CPRMAN_DSI0HSCK_MUX,
405502960caSLuc Michel .version_id = 1,
406502960caSLuc Michel .minimum_version_id = 1,
407e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
408502960caSLuc Michel VMSTATE_CLOCK(plla_in, CprmanDsi0HsckMuxState),
409502960caSLuc Michel VMSTATE_CLOCK(plld_in, CprmanDsi0HsckMuxState),
410502960caSLuc Michel VMSTATE_END_OF_LIST()
411502960caSLuc Michel }
412502960caSLuc Michel };
413502960caSLuc Michel
dsi0hsck_mux_class_init(ObjectClass * klass,void * data)414502960caSLuc Michel static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data)
415502960caSLuc Michel {
416502960caSLuc Michel DeviceClass *dc = DEVICE_CLASS(klass);
417502960caSLuc Michel
418502960caSLuc Michel dc->vmsd = &dsi0hsck_mux_vmstate;
419502960caSLuc Michel }
420502960caSLuc Michel
421502960caSLuc Michel static const TypeInfo cprman_dsi0hsck_mux_info = {
422502960caSLuc Michel .name = TYPE_CPRMAN_DSI0HSCK_MUX,
423502960caSLuc Michel .parent = TYPE_DEVICE,
424502960caSLuc Michel .instance_size = sizeof(CprmanDsi0HsckMuxState),
425502960caSLuc Michel .class_init = dsi0hsck_mux_class_init,
426502960caSLuc Michel .instance_init = dsi0hsck_mux_init,
427502960caSLuc Michel };
428502960caSLuc Michel
429502960caSLuc Michel
430fc14176bSLuc Michel /* CPRMAN "top level" model */
431fc14176bSLuc Michel
get_cm_lock(const BCM2835CprmanState * s)4326d2b874cSLuc Michel static uint32_t get_cm_lock(const BCM2835CprmanState *s)
4336d2b874cSLuc Michel {
4346d2b874cSLuc Michel static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = {
4356d2b874cSLuc Michel [CPRMAN_PLLA] = R_CM_LOCK_FLOCKA_SHIFT,
4366d2b874cSLuc Michel [CPRMAN_PLLC] = R_CM_LOCK_FLOCKC_SHIFT,
4376d2b874cSLuc Michel [CPRMAN_PLLD] = R_CM_LOCK_FLOCKD_SHIFT,
4386d2b874cSLuc Michel [CPRMAN_PLLH] = R_CM_LOCK_FLOCKH_SHIFT,
4396d2b874cSLuc Michel [CPRMAN_PLLB] = R_CM_LOCK_FLOCKB_SHIFT,
4406d2b874cSLuc Michel };
4416d2b874cSLuc Michel
4426d2b874cSLuc Michel uint32_t r = 0;
4436d2b874cSLuc Michel size_t i;
4446d2b874cSLuc Michel
4456d2b874cSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) {
4466d2b874cSLuc Michel r |= pll_is_locked(&s->plls[i]) << CM_LOCK_MAPPING[i];
4476d2b874cSLuc Michel }
4486d2b874cSLuc Michel
4496d2b874cSLuc Michel return r;
4506d2b874cSLuc Michel }
4516d2b874cSLuc Michel
cprman_read(void * opaque,hwaddr offset,unsigned size)452fc14176bSLuc Michel static uint64_t cprman_read(void *opaque, hwaddr offset,
453fc14176bSLuc Michel unsigned size)
454fc14176bSLuc Michel {
455fc14176bSLuc Michel BCM2835CprmanState *s = CPRMAN(opaque);
456fc14176bSLuc Michel uint64_t r = 0;
457fc14176bSLuc Michel size_t idx = offset / sizeof(uint32_t);
458fc14176bSLuc Michel
459fc14176bSLuc Michel switch (idx) {
4606d2b874cSLuc Michel case R_CM_LOCK:
4616d2b874cSLuc Michel r = get_cm_lock(s);
4626d2b874cSLuc Michel break;
4636d2b874cSLuc Michel
464fc14176bSLuc Michel default:
465fc14176bSLuc Michel r = s->regs[idx];
466fc14176bSLuc Michel }
467fc14176bSLuc Michel
468fc14176bSLuc Michel trace_bcm2835_cprman_read(offset, r);
469fc14176bSLuc Michel return r;
470fc14176bSLuc Michel }
471fc14176bSLuc Michel
update_pll_and_channels_from_cm(BCM2835CprmanState * s,size_t idx)47209d56bbcSLuc Michel static inline void update_pll_and_channels_from_cm(BCM2835CprmanState *s,
47309d56bbcSLuc Michel size_t idx)
47409d56bbcSLuc Michel {
47509d56bbcSLuc Michel size_t i;
47609d56bbcSLuc Michel
47709d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) {
47809d56bbcSLuc Michel if (PLL_INIT_INFO[i].cm_offset == idx) {
47909d56bbcSLuc Michel pll_update_all_channels(s, &s->plls[i]);
48009d56bbcSLuc Michel return;
48109d56bbcSLuc Michel }
48209d56bbcSLuc Michel }
48309d56bbcSLuc Michel }
48409d56bbcSLuc Michel
update_channel_from_a2w(BCM2835CprmanState * s,size_t idx)48509d56bbcSLuc Michel static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
48609d56bbcSLuc Michel {
48709d56bbcSLuc Michel size_t i;
48809d56bbcSLuc Michel
48909d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
49009d56bbcSLuc Michel if (PLL_CHANNEL_INIT_INFO[i].a2w_ctrl_offset == idx) {
49109d56bbcSLuc Michel pll_channel_update(&s->channels[i]);
49209d56bbcSLuc Michel return;
49309d56bbcSLuc Michel }
49409d56bbcSLuc Michel }
49509d56bbcSLuc Michel }
49609d56bbcSLuc Michel
update_mux_from_cm(BCM2835CprmanState * s,size_t idx)49772813624SLuc Michel static inline void update_mux_from_cm(BCM2835CprmanState *s, size_t idx)
49872813624SLuc Michel {
49972813624SLuc Michel size_t i;
50072813624SLuc Michel
50172813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
50272813624SLuc Michel if ((CLOCK_MUX_INIT_INFO[i].cm_offset == idx) ||
50372813624SLuc Michel (CLOCK_MUX_INIT_INFO[i].cm_offset + 4 == idx)) {
50472813624SLuc Michel /* matches CM_CTL or CM_DIV mux register */
50572813624SLuc Michel clock_mux_update(&s->clock_muxes[i]);
50672813624SLuc Michel return;
50772813624SLuc Michel }
50872813624SLuc Michel }
50972813624SLuc Michel }
51072813624SLuc Michel
51109d56bbcSLuc Michel #define CASE_PLL_A2W_REGS(pll_) \
5121e986e25SLuc Michel case R_A2W_ ## pll_ ## _CTRL: \
5131e986e25SLuc Michel case R_A2W_ ## pll_ ## _ANA0: \
5141e986e25SLuc Michel case R_A2W_ ## pll_ ## _ANA1: \
5151e986e25SLuc Michel case R_A2W_ ## pll_ ## _ANA2: \
5161e986e25SLuc Michel case R_A2W_ ## pll_ ## _ANA3: \
5171e986e25SLuc Michel case R_A2W_ ## pll_ ## _FRAC
5181e986e25SLuc Michel
cprman_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)519fc14176bSLuc Michel static void cprman_write(void *opaque, hwaddr offset,
520fc14176bSLuc Michel uint64_t value, unsigned size)
521fc14176bSLuc Michel {
522fc14176bSLuc Michel BCM2835CprmanState *s = CPRMAN(opaque);
523fc14176bSLuc Michel size_t idx = offset / sizeof(uint32_t);
524fc14176bSLuc Michel
525fc14176bSLuc Michel if (FIELD_EX32(value, CPRMAN, PASSWORD) != CPRMAN_PASSWORD) {
526fc14176bSLuc Michel trace_bcm2835_cprman_write_invalid_magic(offset, value);
527fc14176bSLuc Michel return;
528fc14176bSLuc Michel }
529fc14176bSLuc Michel
530fc14176bSLuc Michel value &= ~R_CPRMAN_PASSWORD_MASK;
531fc14176bSLuc Michel
532fc14176bSLuc Michel trace_bcm2835_cprman_write(offset, value);
533fc14176bSLuc Michel s->regs[idx] = value;
534fc14176bSLuc Michel
5351e986e25SLuc Michel switch (idx) {
53609d56bbcSLuc Michel case R_CM_PLLA ... R_CM_PLLH:
53709d56bbcSLuc Michel case R_CM_PLLB:
53809d56bbcSLuc Michel /*
53909d56bbcSLuc Michel * A given CM_PLLx register is shared by both the PLL and the channels
54009d56bbcSLuc Michel * of this PLL.
54109d56bbcSLuc Michel */
54209d56bbcSLuc Michel update_pll_and_channels_from_cm(s, idx);
54309d56bbcSLuc Michel break;
54409d56bbcSLuc Michel
54509d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLA) :
5461e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLA]);
5471e986e25SLuc Michel break;
5481e986e25SLuc Michel
54909d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLC) :
5501e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLC]);
5511e986e25SLuc Michel break;
5521e986e25SLuc Michel
55309d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLD) :
5541e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLD]);
5551e986e25SLuc Michel break;
5561e986e25SLuc Michel
55709d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLH) :
5581e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLH]);
5591e986e25SLuc Michel break;
5601e986e25SLuc Michel
56109d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLB) :
5621e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLB]);
5631e986e25SLuc Michel break;
56409d56bbcSLuc Michel
56509d56bbcSLuc Michel case R_A2W_PLLA_DSI0:
56609d56bbcSLuc Michel case R_A2W_PLLA_CORE:
56709d56bbcSLuc Michel case R_A2W_PLLA_PER:
56809d56bbcSLuc Michel case R_A2W_PLLA_CCP2:
56909d56bbcSLuc Michel case R_A2W_PLLC_CORE2:
57009d56bbcSLuc Michel case R_A2W_PLLC_CORE1:
57109d56bbcSLuc Michel case R_A2W_PLLC_PER:
57209d56bbcSLuc Michel case R_A2W_PLLC_CORE0:
57309d56bbcSLuc Michel case R_A2W_PLLD_DSI0:
57409d56bbcSLuc Michel case R_A2W_PLLD_CORE:
57509d56bbcSLuc Michel case R_A2W_PLLD_PER:
57609d56bbcSLuc Michel case R_A2W_PLLD_DSI1:
57709d56bbcSLuc Michel case R_A2W_PLLH_AUX:
57809d56bbcSLuc Michel case R_A2W_PLLH_RCAL:
57909d56bbcSLuc Michel case R_A2W_PLLH_PIX:
58009d56bbcSLuc Michel case R_A2W_PLLB_ARM:
58109d56bbcSLuc Michel update_channel_from_a2w(s, idx);
58209d56bbcSLuc Michel break;
58372813624SLuc Michel
58472813624SLuc Michel case R_CM_GNRICCTL ... R_CM_SMIDIV:
58572813624SLuc Michel case R_CM_TCNTCNT ... R_CM_VECDIV:
58672813624SLuc Michel case R_CM_PULSECTL ... R_CM_PULSEDIV:
58772813624SLuc Michel case R_CM_SDCCTL ... R_CM_ARMCTL:
58872813624SLuc Michel case R_CM_AVEOCTL ... R_CM_EMMCDIV:
58972813624SLuc Michel case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
59072813624SLuc Michel update_mux_from_cm(s, idx);
59172813624SLuc Michel break;
592502960caSLuc Michel
593502960caSLuc Michel case R_CM_DSI0HSCK:
594502960caSLuc Michel dsi0hsck_mux_update(&s->dsi0hsck_mux);
595502960caSLuc Michel break;
596fc14176bSLuc Michel }
5971e986e25SLuc Michel }
5981e986e25SLuc Michel
59909d56bbcSLuc Michel #undef CASE_PLL_A2W_REGS
600fc14176bSLuc Michel
601fc14176bSLuc Michel static const MemoryRegionOps cprman_ops = {
602fc14176bSLuc Michel .read = cprman_read,
603fc14176bSLuc Michel .write = cprman_write,
604fc14176bSLuc Michel .endianness = DEVICE_LITTLE_ENDIAN,
605fc14176bSLuc Michel .valid = {
606fc14176bSLuc Michel /*
607fc14176bSLuc Michel * Although this hasn't been checked against real hardware, nor the
608fc14176bSLuc Michel * information can be found in a datasheet, it seems reasonable because
609fc14176bSLuc Michel * of the "PASSWORD" magic value found in every registers.
610fc14176bSLuc Michel */
611fc14176bSLuc Michel .min_access_size = 4,
612fc14176bSLuc Michel .max_access_size = 4,
613fc14176bSLuc Michel .unaligned = false,
614fc14176bSLuc Michel },
615fc14176bSLuc Michel .impl = {
616fc14176bSLuc Michel .max_access_size = 4,
617fc14176bSLuc Michel },
618fc14176bSLuc Michel };
619fc14176bSLuc Michel
cprman_reset(DeviceState * dev)620fc14176bSLuc Michel static void cprman_reset(DeviceState *dev)
621fc14176bSLuc Michel {
622fc14176bSLuc Michel BCM2835CprmanState *s = CPRMAN(dev);
6231e986e25SLuc Michel size_t i;
624fc14176bSLuc Michel
625fc14176bSLuc Michel memset(s->regs, 0, sizeof(s->regs));
626fc14176bSLuc Michel
6271e986e25SLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) {
6281e986e25SLuc Michel device_cold_reset(DEVICE(&s->plls[i]));
6291e986e25SLuc Michel }
6301e986e25SLuc Michel
63109d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
63209d56bbcSLuc Michel device_cold_reset(DEVICE(&s->channels[i]));
63309d56bbcSLuc Michel }
63409d56bbcSLuc Michel
635502960caSLuc Michel device_cold_reset(DEVICE(&s->dsi0hsck_mux));
636502960caSLuc Michel
63772813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
63872813624SLuc Michel device_cold_reset(DEVICE(&s->clock_muxes[i]));
63972813624SLuc Michel }
64072813624SLuc Michel
641fc14176bSLuc Michel clock_update_hz(s->xosc, s->xosc_freq);
642fc14176bSLuc Michel }
643fc14176bSLuc Michel
cprman_init(Object * obj)644fc14176bSLuc Michel static void cprman_init(Object *obj)
645fc14176bSLuc Michel {
646fc14176bSLuc Michel BCM2835CprmanState *s = CPRMAN(obj);
6471e986e25SLuc Michel size_t i;
6481e986e25SLuc Michel
6491e986e25SLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) {
6501e986e25SLuc Michel object_initialize_child(obj, PLL_INIT_INFO[i].name,
6511e986e25SLuc Michel &s->plls[i], TYPE_CPRMAN_PLL);
6521e986e25SLuc Michel set_pll_init_info(s, &s->plls[i], i);
6531e986e25SLuc Michel }
654fc14176bSLuc Michel
65509d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
65609d56bbcSLuc Michel object_initialize_child(obj, PLL_CHANNEL_INIT_INFO[i].name,
65709d56bbcSLuc Michel &s->channels[i],
65809d56bbcSLuc Michel TYPE_CPRMAN_PLL_CHANNEL);
65909d56bbcSLuc Michel set_pll_channel_init_info(s, &s->channels[i], i);
66009d56bbcSLuc Michel }
66109d56bbcSLuc Michel
662502960caSLuc Michel object_initialize_child(obj, "dsi0hsck-mux",
663502960caSLuc Michel &s->dsi0hsck_mux, TYPE_CPRMAN_DSI0HSCK_MUX);
664502960caSLuc Michel s->dsi0hsck_mux.reg_cm = &s->regs[R_CM_DSI0HSCK];
665502960caSLuc Michel
66672813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
66772813624SLuc Michel char *alias;
66872813624SLuc Michel
66972813624SLuc Michel object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name,
67072813624SLuc Michel &s->clock_muxes[i],
67172813624SLuc Michel TYPE_CPRMAN_CLOCK_MUX);
67272813624SLuc Michel set_clock_mux_init_info(s, &s->clock_muxes[i], i);
67372813624SLuc Michel
67472813624SLuc Michel /* Expose muxes output as CPRMAN outputs */
67572813624SLuc Michel alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name);
67672813624SLuc Michel qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias);
67772813624SLuc Michel g_free(alias);
67872813624SLuc Michel }
67972813624SLuc Michel
680fc14176bSLuc Michel s->xosc = clock_new(obj, "xosc");
68172813624SLuc Michel s->gnd = clock_new(obj, "gnd");
68272813624SLuc Michel
68372813624SLuc Michel clock_set(s->gnd, 0);
684fc14176bSLuc Michel
685fc14176bSLuc Michel memory_region_init_io(&s->iomem, obj, &cprman_ops,
686fc14176bSLuc Michel s, "bcm2835-cprman", 0x2000);
687fc14176bSLuc Michel sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
688fc14176bSLuc Michel }
689fc14176bSLuc Michel
connect_mux_sources(BCM2835CprmanState * s,CprmanClockMuxState * mux,const CprmanPllChannel * clk_mapping)69072813624SLuc Michel static void connect_mux_sources(BCM2835CprmanState *s,
69172813624SLuc Michel CprmanClockMuxState *mux,
69272813624SLuc Michel const CprmanPllChannel *clk_mapping)
69372813624SLuc Michel {
69472813624SLuc Michel size_t i;
69572813624SLuc Michel Clock *td0 = s->clock_muxes[CPRMAN_CLOCK_TD0].out;
69672813624SLuc Michel Clock *td1 = s->clock_muxes[CPRMAN_CLOCK_TD1].out;
69772813624SLuc Michel
69872813624SLuc Michel /* For sources from 0 to 3. Source 4 to 9 are mux specific */
69972813624SLuc Michel Clock * const CLK_SRC_MAPPING[] = {
70072813624SLuc Michel [CPRMAN_CLOCK_SRC_GND] = s->gnd,
70172813624SLuc Michel [CPRMAN_CLOCK_SRC_XOSC] = s->xosc,
70272813624SLuc Michel [CPRMAN_CLOCK_SRC_TD0] = td0,
70372813624SLuc Michel [CPRMAN_CLOCK_SRC_TD1] = td1,
70472813624SLuc Michel };
70572813624SLuc Michel
70672813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
70772813624SLuc Michel CprmanPllChannel mapping = clk_mapping[i];
70872813624SLuc Michel Clock *src;
70972813624SLuc Michel
71072813624SLuc Michel if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
71172813624SLuc Michel src = s->gnd;
71272813624SLuc Michel } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
713502960caSLuc Michel src = s->dsi0hsck_mux.out;
71472813624SLuc Michel } else if (i < CPRMAN_CLOCK_SRC_PLLA) {
71572813624SLuc Michel src = CLK_SRC_MAPPING[i];
71672813624SLuc Michel } else {
71772813624SLuc Michel src = s->channels[mapping].out;
71872813624SLuc Michel }
71972813624SLuc Michel
72072813624SLuc Michel clock_set_source(mux->srcs[i], src);
72172813624SLuc Michel }
72272813624SLuc Michel }
72372813624SLuc Michel
cprman_realize(DeviceState * dev,Error ** errp)7241e986e25SLuc Michel static void cprman_realize(DeviceState *dev, Error **errp)
7251e986e25SLuc Michel {
7261e986e25SLuc Michel BCM2835CprmanState *s = CPRMAN(dev);
7271e986e25SLuc Michel size_t i;
7281e986e25SLuc Michel
7291e986e25SLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) {
7301e986e25SLuc Michel CprmanPllState *pll = &s->plls[i];
7311e986e25SLuc Michel
7321e986e25SLuc Michel clock_set_source(pll->xosc_in, s->xosc);
7331e986e25SLuc Michel
7341e986e25SLuc Michel if (!qdev_realize(DEVICE(pll), NULL, errp)) {
7351e986e25SLuc Michel return;
7361e986e25SLuc Michel }
7371e986e25SLuc Michel }
73809d56bbcSLuc Michel
73909d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
74009d56bbcSLuc Michel CprmanPllChannelState *channel = &s->channels[i];
74109d56bbcSLuc Michel CprmanPll parent = PLL_CHANNEL_INIT_INFO[i].parent;
74209d56bbcSLuc Michel Clock *parent_clk = s->plls[parent].out;
74309d56bbcSLuc Michel
74409d56bbcSLuc Michel clock_set_source(channel->pll_in, parent_clk);
74509d56bbcSLuc Michel
74609d56bbcSLuc Michel if (!qdev_realize(DEVICE(channel), NULL, errp)) {
74709d56bbcSLuc Michel return;
74809d56bbcSLuc Michel }
74909d56bbcSLuc Michel }
75072813624SLuc Michel
751502960caSLuc Michel clock_set_source(s->dsi0hsck_mux.plla_in,
752502960caSLuc Michel s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out);
753502960caSLuc Michel clock_set_source(s->dsi0hsck_mux.plld_in,
754502960caSLuc Michel s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out);
755502960caSLuc Michel
756502960caSLuc Michel if (!qdev_realize(DEVICE(&s->dsi0hsck_mux), NULL, errp)) {
757502960caSLuc Michel return;
758502960caSLuc Michel }
759502960caSLuc Michel
76072813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
76172813624SLuc Michel CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
76272813624SLuc Michel
76372813624SLuc Michel connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping);
76472813624SLuc Michel
76572813624SLuc Michel if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) {
76672813624SLuc Michel return;
76772813624SLuc Michel }
76872813624SLuc Michel }
7691e986e25SLuc Michel }
7701e986e25SLuc Michel
771fc14176bSLuc Michel static const VMStateDescription cprman_vmstate = {
772fc14176bSLuc Michel .name = TYPE_BCM2835_CPRMAN,
773fc14176bSLuc Michel .version_id = 1,
774fc14176bSLuc Michel .minimum_version_id = 1,
775e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
776fc14176bSLuc Michel VMSTATE_UINT32_ARRAY(regs, BCM2835CprmanState, CPRMAN_NUM_REGS),
777fc14176bSLuc Michel VMSTATE_END_OF_LIST()
778fc14176bSLuc Michel }
779fc14176bSLuc Michel };
780fc14176bSLuc Michel
781fc14176bSLuc Michel static Property cprman_properties[] = {
782fc14176bSLuc Michel DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000),
783fc14176bSLuc Michel DEFINE_PROP_END_OF_LIST()
784fc14176bSLuc Michel };
785fc14176bSLuc Michel
cprman_class_init(ObjectClass * klass,void * data)786fc14176bSLuc Michel static void cprman_class_init(ObjectClass *klass, void *data)
787fc14176bSLuc Michel {
788fc14176bSLuc Michel DeviceClass *dc = DEVICE_CLASS(klass);
789fc14176bSLuc Michel
7901e986e25SLuc Michel dc->realize = cprman_realize;
791*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, cprman_reset);
792fc14176bSLuc Michel dc->vmsd = &cprman_vmstate;
793fc14176bSLuc Michel device_class_set_props(dc, cprman_properties);
794fc14176bSLuc Michel }
795fc14176bSLuc Michel
796fc14176bSLuc Michel static const TypeInfo cprman_info = {
797fc14176bSLuc Michel .name = TYPE_BCM2835_CPRMAN,
798fc14176bSLuc Michel .parent = TYPE_SYS_BUS_DEVICE,
799fc14176bSLuc Michel .instance_size = sizeof(BCM2835CprmanState),
800fc14176bSLuc Michel .class_init = cprman_class_init,
801fc14176bSLuc Michel .instance_init = cprman_init,
802fc14176bSLuc Michel };
803fc14176bSLuc Michel
cprman_register_types(void)804fc14176bSLuc Michel static void cprman_register_types(void)
805fc14176bSLuc Michel {
806fc14176bSLuc Michel type_register_static(&cprman_info);
8071e986e25SLuc Michel type_register_static(&cprman_pll_info);
80809d56bbcSLuc Michel type_register_static(&cprman_pll_channel_info);
80972813624SLuc Michel type_register_static(&cprman_clock_mux_info);
810502960caSLuc Michel type_register_static(&cprman_dsi0hsck_mux_info);
811fc14176bSLuc Michel }
812fc14176bSLuc Michel
813fc14176bSLuc Michel type_init(cprman_register_types);
814