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 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 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 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 1105ee0abedSPeter Maydell static void pll_xosc_update(void *opaque, ClockEvent event) 1111e986e25SLuc Michel { 1121e986e25SLuc Michel pll_update(CPRMAN_PLL(opaque)); 1131e986e25SLuc Michel } 1141e986e25SLuc Michel 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 1341e986e25SLuc Michel static void pll_class_init(ObjectClass *klass, void *data) 1351e986e25SLuc Michel { 1361e986e25SLuc Michel DeviceClass *dc = DEVICE_CLASS(klass); 1371e986e25SLuc Michel 138e3d08143SPeter Maydell device_class_set_legacy_reset(dc, pll_reset); 1391e986e25SLuc Michel dc->vmsd = &pll_vmstate; 140*490aaae9SPhilippe Mathieu-Daudé /* Reason: Part of BCM2835CprmanState component */ 141*490aaae9SPhilippe Mathieu-Daudé dc->user_creatable = false; 1421e986e25SLuc Michel } 1431e986e25SLuc Michel 1441e986e25SLuc Michel static const TypeInfo cprman_pll_info = { 1451e986e25SLuc Michel .name = TYPE_CPRMAN_PLL, 1461e986e25SLuc Michel .parent = TYPE_DEVICE, 1471e986e25SLuc Michel .instance_size = sizeof(CprmanPllState), 1481e986e25SLuc Michel .class_init = pll_class_init, 1491e986e25SLuc Michel .instance_init = pll_init, 1501e986e25SLuc Michel }; 1511e986e25SLuc Michel 1521e986e25SLuc Michel 15309d56bbcSLuc Michel /* PLL channel */ 15409d56bbcSLuc Michel 15583ad4695SLuc Michel static void pll_channel_reset(DeviceState *dev) 15683ad4695SLuc Michel { 15783ad4695SLuc Michel CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(dev); 15883ad4695SLuc Michel const PLLChannelResetInfo *info = &PLL_CHANNEL_RESET_INFO[s->id]; 15983ad4695SLuc Michel 16083ad4695SLuc Michel *s->reg_a2w_ctrl = info->a2w_ctrl; 16183ad4695SLuc Michel } 16283ad4695SLuc Michel 16395745811SLuc Michel static bool pll_channel_is_enabled(CprmanPllChannelState *channel) 16495745811SLuc Michel { 16595745811SLuc Michel /* 16695745811SLuc Michel * XXX I'm not sure of the purpose of the LOAD field. The Linux driver does 16795745811SLuc Michel * not set it when enabling the channel, but does clear it when disabling 16895745811SLuc Michel * it. 16995745811SLuc Michel */ 17095745811SLuc Michel return !FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DISABLE) 17195745811SLuc Michel && !(*channel->reg_cm & channel->hold_mask); 17295745811SLuc Michel } 17395745811SLuc Michel 17409d56bbcSLuc Michel static void pll_channel_update(CprmanPllChannelState *channel) 17509d56bbcSLuc Michel { 17695745811SLuc Michel uint64_t freq, div; 17795745811SLuc Michel 17895745811SLuc Michel if (!pll_channel_is_enabled(channel)) { 17909d56bbcSLuc Michel clock_update(channel->out, 0); 18095745811SLuc Michel return; 18195745811SLuc Michel } 18295745811SLuc Michel 18395745811SLuc Michel div = FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DIV); 18495745811SLuc Michel 18595745811SLuc Michel if (!div) { 18695745811SLuc Michel /* 18795745811SLuc Michel * It seems that when the divider value is 0, it is considered as 18895745811SLuc Michel * being maximum by the hardware (see the Linux driver). 18995745811SLuc Michel */ 19095745811SLuc Michel div = R_A2W_PLLx_CHANNELy_DIV_MASK; 19195745811SLuc Michel } 19295745811SLuc Michel 19395745811SLuc Michel /* Some channels have an additional fixed divider */ 19495745811SLuc Michel freq = clock_get_hz(channel->pll_in) / (div * channel->fixed_divider); 19595745811SLuc Michel 19695745811SLuc Michel clock_update_hz(channel->out, freq); 19709d56bbcSLuc Michel } 19809d56bbcSLuc Michel 19909d56bbcSLuc Michel /* Update a PLL and all its channels */ 20009d56bbcSLuc Michel static void pll_update_all_channels(BCM2835CprmanState *s, 20109d56bbcSLuc Michel CprmanPllState *pll) 20209d56bbcSLuc Michel { 20309d56bbcSLuc Michel size_t i; 20409d56bbcSLuc Michel 20509d56bbcSLuc Michel pll_update(pll); 20609d56bbcSLuc Michel 20709d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { 20809d56bbcSLuc Michel CprmanPllChannelState *channel = &s->channels[i]; 20909d56bbcSLuc Michel if (channel->parent == pll->id) { 21009d56bbcSLuc Michel pll_channel_update(channel); 21109d56bbcSLuc Michel } 21209d56bbcSLuc Michel } 21309d56bbcSLuc Michel } 21409d56bbcSLuc Michel 2155ee0abedSPeter Maydell static void pll_channel_pll_in_update(void *opaque, ClockEvent event) 21609d56bbcSLuc Michel { 21709d56bbcSLuc Michel pll_channel_update(CPRMAN_PLL_CHANNEL(opaque)); 21809d56bbcSLuc Michel } 21909d56bbcSLuc Michel 22009d56bbcSLuc Michel static void pll_channel_init(Object *obj) 22109d56bbcSLuc Michel { 22209d56bbcSLuc Michel CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj); 22309d56bbcSLuc Michel 22409d56bbcSLuc Michel s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in", 2255ee0abedSPeter Maydell pll_channel_pll_in_update, s, 2265ee0abedSPeter Maydell ClockUpdate); 22709d56bbcSLuc Michel s->out = qdev_init_clock_out(DEVICE(s), "out"); 22809d56bbcSLuc Michel } 22909d56bbcSLuc Michel 23009d56bbcSLuc Michel static const VMStateDescription pll_channel_vmstate = { 23109d56bbcSLuc Michel .name = TYPE_CPRMAN_PLL_CHANNEL, 23209d56bbcSLuc Michel .version_id = 1, 23309d56bbcSLuc Michel .minimum_version_id = 1, 234e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 23509d56bbcSLuc Michel VMSTATE_CLOCK(pll_in, CprmanPllChannelState), 23609d56bbcSLuc Michel VMSTATE_END_OF_LIST() 23709d56bbcSLuc Michel } 23809d56bbcSLuc Michel }; 23909d56bbcSLuc Michel 24009d56bbcSLuc Michel static void pll_channel_class_init(ObjectClass *klass, void *data) 24109d56bbcSLuc Michel { 24209d56bbcSLuc Michel DeviceClass *dc = DEVICE_CLASS(klass); 24309d56bbcSLuc Michel 244e3d08143SPeter Maydell device_class_set_legacy_reset(dc, pll_channel_reset); 24509d56bbcSLuc Michel dc->vmsd = &pll_channel_vmstate; 246*490aaae9SPhilippe Mathieu-Daudé /* Reason: Part of BCM2835CprmanState component */ 247*490aaae9SPhilippe Mathieu-Daudé dc->user_creatable = false; 24809d56bbcSLuc Michel } 24909d56bbcSLuc Michel 25009d56bbcSLuc Michel static const TypeInfo cprman_pll_channel_info = { 25109d56bbcSLuc Michel .name = TYPE_CPRMAN_PLL_CHANNEL, 25209d56bbcSLuc Michel .parent = TYPE_DEVICE, 25309d56bbcSLuc Michel .instance_size = sizeof(CprmanPllChannelState), 25409d56bbcSLuc Michel .class_init = pll_channel_class_init, 25509d56bbcSLuc Michel .instance_init = pll_channel_init, 25609d56bbcSLuc Michel }; 25709d56bbcSLuc Michel 25809d56bbcSLuc Michel 25972813624SLuc Michel /* clock mux */ 26072813624SLuc Michel 261fc984085SLuc Michel static bool clock_mux_is_enabled(CprmanClockMuxState *mux) 262fc984085SLuc Michel { 263fc984085SLuc Michel return FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, ENABLE); 264fc984085SLuc Michel } 265fc984085SLuc Michel 26672813624SLuc Michel static void clock_mux_update(CprmanClockMuxState *mux) 26772813624SLuc Michel { 268fc984085SLuc Michel uint64_t freq; 269fc984085SLuc Michel uint32_t div, src = FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, SRC); 270fc984085SLuc Michel bool enabled = clock_mux_is_enabled(mux); 271fc984085SLuc Michel 272fc984085SLuc Michel *mux->reg_ctl = FIELD_DP32(*mux->reg_ctl, CM_CLOCKx_CTL, BUSY, enabled); 273fc984085SLuc Michel 274fc984085SLuc Michel if (!enabled) { 27572813624SLuc Michel clock_update(mux->out, 0); 276fc984085SLuc Michel return; 277fc984085SLuc Michel } 278fc984085SLuc Michel 279fc984085SLuc Michel freq = clock_get_hz(mux->srcs[src]); 280fc984085SLuc Michel 281fc984085SLuc Michel if (mux->int_bits == 0 && mux->frac_bits == 0) { 282fc984085SLuc Michel clock_update_hz(mux->out, freq); 283fc984085SLuc Michel return; 284fc984085SLuc Michel } 285fc984085SLuc Michel 286fc984085SLuc Michel /* 287fc984085SLuc Michel * The divider has an integer and a fractional part. The size of each part 288fc984085SLuc Michel * varies with the muxes (int_bits and frac_bits). Both parts are 289fc984085SLuc Michel * concatenated, with the integer part always starting at bit 12. 290fc984085SLuc Michel * 291fc984085SLuc Michel * 31 12 11 0 292fc984085SLuc Michel * ------------------------------ 293fc984085SLuc Michel * CM_DIV | | int | frac | | 294fc984085SLuc Michel * ------------------------------ 295fc984085SLuc Michel * <-----> <------> 296fc984085SLuc Michel * int_bits frac_bits 297fc984085SLuc Michel */ 298fc984085SLuc Michel div = extract32(*mux->reg_div, 299fc984085SLuc Michel R_CM_CLOCKx_DIV_FRAC_LENGTH - mux->frac_bits, 300fc984085SLuc Michel mux->int_bits + mux->frac_bits); 301fc984085SLuc Michel 302fc984085SLuc Michel if (!div) { 303fc984085SLuc Michel clock_update(mux->out, 0); 304fc984085SLuc Michel return; 305fc984085SLuc Michel } 306fc984085SLuc Michel 307fc984085SLuc Michel freq = muldiv64(freq, 1 << mux->frac_bits, div); 308fc984085SLuc Michel 309fc984085SLuc Michel clock_update_hz(mux->out, freq); 31072813624SLuc Michel } 31172813624SLuc Michel 3125ee0abedSPeter Maydell static void clock_mux_src_update(void *opaque, ClockEvent event) 31372813624SLuc Michel { 31472813624SLuc Michel CprmanClockMuxState **backref = opaque; 31572813624SLuc Michel CprmanClockMuxState *s = *backref; 316fc984085SLuc Michel CprmanClockMuxSource src = backref - s->backref; 317fc984085SLuc Michel 318fc984085SLuc Michel if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) { 319fc984085SLuc Michel return; 320fc984085SLuc Michel } 32172813624SLuc Michel 32272813624SLuc Michel clock_mux_update(s); 32372813624SLuc Michel } 32472813624SLuc Michel 32583ad4695SLuc Michel static void clock_mux_reset(DeviceState *dev) 32683ad4695SLuc Michel { 32783ad4695SLuc Michel CprmanClockMuxState *clock = CPRMAN_CLOCK_MUX(dev); 32883ad4695SLuc Michel const ClockMuxResetInfo *info = &CLOCK_MUX_RESET_INFO[clock->id]; 32983ad4695SLuc Michel 33083ad4695SLuc Michel *clock->reg_ctl = info->cm_ctl; 33183ad4695SLuc Michel *clock->reg_div = info->cm_div; 33283ad4695SLuc Michel } 33383ad4695SLuc Michel 33472813624SLuc Michel static void clock_mux_init(Object *obj) 33572813624SLuc Michel { 33672813624SLuc Michel CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj); 33772813624SLuc Michel size_t i; 33872813624SLuc Michel 33972813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) { 34072813624SLuc Michel char *name = g_strdup_printf("srcs[%zu]", i); 34172813624SLuc Michel s->backref[i] = s; 34272813624SLuc Michel s->srcs[i] = qdev_init_clock_in(DEVICE(s), name, 34372813624SLuc Michel clock_mux_src_update, 3445ee0abedSPeter Maydell &s->backref[i], 3455ee0abedSPeter Maydell ClockUpdate); 34672813624SLuc Michel g_free(name); 34772813624SLuc Michel } 34872813624SLuc Michel 34972813624SLuc Michel s->out = qdev_init_clock_out(DEVICE(s), "out"); 35072813624SLuc Michel } 35172813624SLuc Michel 35272813624SLuc Michel static const VMStateDescription clock_mux_vmstate = { 35372813624SLuc Michel .name = TYPE_CPRMAN_CLOCK_MUX, 35472813624SLuc Michel .version_id = 1, 35572813624SLuc Michel .minimum_version_id = 1, 356e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 35772813624SLuc Michel VMSTATE_ARRAY_CLOCK(srcs, CprmanClockMuxState, 35872813624SLuc Michel CPRMAN_NUM_CLOCK_MUX_SRC), 35972813624SLuc Michel VMSTATE_END_OF_LIST() 36072813624SLuc Michel } 36172813624SLuc Michel }; 36272813624SLuc Michel 36372813624SLuc Michel static void clock_mux_class_init(ObjectClass *klass, void *data) 36472813624SLuc Michel { 36572813624SLuc Michel DeviceClass *dc = DEVICE_CLASS(klass); 36672813624SLuc Michel 367e3d08143SPeter Maydell device_class_set_legacy_reset(dc, clock_mux_reset); 36872813624SLuc Michel dc->vmsd = &clock_mux_vmstate; 369*490aaae9SPhilippe Mathieu-Daudé /* Reason: Part of BCM2835CprmanState component */ 370*490aaae9SPhilippe Mathieu-Daudé dc->user_creatable = false; 37172813624SLuc Michel } 37272813624SLuc Michel 37372813624SLuc Michel static const TypeInfo cprman_clock_mux_info = { 37472813624SLuc Michel .name = TYPE_CPRMAN_CLOCK_MUX, 37572813624SLuc Michel .parent = TYPE_DEVICE, 37672813624SLuc Michel .instance_size = sizeof(CprmanClockMuxState), 37772813624SLuc Michel .class_init = clock_mux_class_init, 37872813624SLuc Michel .instance_init = clock_mux_init, 37972813624SLuc Michel }; 38072813624SLuc Michel 38172813624SLuc Michel 382502960caSLuc Michel /* DSI0HSCK mux */ 383502960caSLuc Michel 384502960caSLuc Michel static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s) 385502960caSLuc Michel { 386502960caSLuc Michel bool src_is_plld = FIELD_EX32(*s->reg_cm, CM_DSI0HSCK, SELPLLD); 387502960caSLuc Michel Clock *src = src_is_plld ? s->plld_in : s->plla_in; 388502960caSLuc Michel 389502960caSLuc Michel clock_update(s->out, clock_get(src)); 390502960caSLuc Michel } 391502960caSLuc Michel 3925ee0abedSPeter Maydell static void dsi0hsck_mux_in_update(void *opaque, ClockEvent event) 393502960caSLuc Michel { 394502960caSLuc Michel dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque)); 395502960caSLuc Michel } 396502960caSLuc Michel 397502960caSLuc Michel static void dsi0hsck_mux_init(Object *obj) 398502960caSLuc Michel { 399502960caSLuc Michel CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj); 400502960caSLuc Michel DeviceState *dev = DEVICE(obj); 401502960caSLuc Michel 4025ee0abedSPeter Maydell s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, 4035ee0abedSPeter Maydell s, ClockUpdate); 4045ee0abedSPeter Maydell s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, 4055ee0abedSPeter Maydell s, ClockUpdate); 406502960caSLuc Michel s->out = qdev_init_clock_out(DEVICE(s), "out"); 407502960caSLuc Michel } 408502960caSLuc Michel 409502960caSLuc Michel static const VMStateDescription dsi0hsck_mux_vmstate = { 410502960caSLuc Michel .name = TYPE_CPRMAN_DSI0HSCK_MUX, 411502960caSLuc Michel .version_id = 1, 412502960caSLuc Michel .minimum_version_id = 1, 413e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 414502960caSLuc Michel VMSTATE_CLOCK(plla_in, CprmanDsi0HsckMuxState), 415502960caSLuc Michel VMSTATE_CLOCK(plld_in, CprmanDsi0HsckMuxState), 416502960caSLuc Michel VMSTATE_END_OF_LIST() 417502960caSLuc Michel } 418502960caSLuc Michel }; 419502960caSLuc Michel 420502960caSLuc Michel static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data) 421502960caSLuc Michel { 422502960caSLuc Michel DeviceClass *dc = DEVICE_CLASS(klass); 423502960caSLuc Michel 424502960caSLuc Michel dc->vmsd = &dsi0hsck_mux_vmstate; 425*490aaae9SPhilippe Mathieu-Daudé /* Reason: Part of BCM2835CprmanState component */ 426*490aaae9SPhilippe Mathieu-Daudé dc->user_creatable = false; 427502960caSLuc Michel } 428502960caSLuc Michel 429502960caSLuc Michel static const TypeInfo cprman_dsi0hsck_mux_info = { 430502960caSLuc Michel .name = TYPE_CPRMAN_DSI0HSCK_MUX, 431502960caSLuc Michel .parent = TYPE_DEVICE, 432502960caSLuc Michel .instance_size = sizeof(CprmanDsi0HsckMuxState), 433502960caSLuc Michel .class_init = dsi0hsck_mux_class_init, 434502960caSLuc Michel .instance_init = dsi0hsck_mux_init, 435502960caSLuc Michel }; 436502960caSLuc Michel 437502960caSLuc Michel 438fc14176bSLuc Michel /* CPRMAN "top level" model */ 439fc14176bSLuc Michel 4406d2b874cSLuc Michel static uint32_t get_cm_lock(const BCM2835CprmanState *s) 4416d2b874cSLuc Michel { 4426d2b874cSLuc Michel static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = { 4436d2b874cSLuc Michel [CPRMAN_PLLA] = R_CM_LOCK_FLOCKA_SHIFT, 4446d2b874cSLuc Michel [CPRMAN_PLLC] = R_CM_LOCK_FLOCKC_SHIFT, 4456d2b874cSLuc Michel [CPRMAN_PLLD] = R_CM_LOCK_FLOCKD_SHIFT, 4466d2b874cSLuc Michel [CPRMAN_PLLH] = R_CM_LOCK_FLOCKH_SHIFT, 4476d2b874cSLuc Michel [CPRMAN_PLLB] = R_CM_LOCK_FLOCKB_SHIFT, 4486d2b874cSLuc Michel }; 4496d2b874cSLuc Michel 4506d2b874cSLuc Michel uint32_t r = 0; 4516d2b874cSLuc Michel size_t i; 4526d2b874cSLuc Michel 4536d2b874cSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) { 4546d2b874cSLuc Michel r |= pll_is_locked(&s->plls[i]) << CM_LOCK_MAPPING[i]; 4556d2b874cSLuc Michel } 4566d2b874cSLuc Michel 4576d2b874cSLuc Michel return r; 4586d2b874cSLuc Michel } 4596d2b874cSLuc Michel 460fc14176bSLuc Michel static uint64_t cprman_read(void *opaque, hwaddr offset, 461fc14176bSLuc Michel unsigned size) 462fc14176bSLuc Michel { 463fc14176bSLuc Michel BCM2835CprmanState *s = CPRMAN(opaque); 464fc14176bSLuc Michel uint64_t r = 0; 465fc14176bSLuc Michel size_t idx = offset / sizeof(uint32_t); 466fc14176bSLuc Michel 467fc14176bSLuc Michel switch (idx) { 4686d2b874cSLuc Michel case R_CM_LOCK: 4696d2b874cSLuc Michel r = get_cm_lock(s); 4706d2b874cSLuc Michel break; 4716d2b874cSLuc Michel 472fc14176bSLuc Michel default: 473fc14176bSLuc Michel r = s->regs[idx]; 474fc14176bSLuc Michel } 475fc14176bSLuc Michel 476fc14176bSLuc Michel trace_bcm2835_cprman_read(offset, r); 477fc14176bSLuc Michel return r; 478fc14176bSLuc Michel } 479fc14176bSLuc Michel 48009d56bbcSLuc Michel static inline void update_pll_and_channels_from_cm(BCM2835CprmanState *s, 48109d56bbcSLuc Michel size_t idx) 48209d56bbcSLuc Michel { 48309d56bbcSLuc Michel size_t i; 48409d56bbcSLuc Michel 48509d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) { 48609d56bbcSLuc Michel if (PLL_INIT_INFO[i].cm_offset == idx) { 48709d56bbcSLuc Michel pll_update_all_channels(s, &s->plls[i]); 48809d56bbcSLuc Michel return; 48909d56bbcSLuc Michel } 49009d56bbcSLuc Michel } 49109d56bbcSLuc Michel } 49209d56bbcSLuc Michel 49309d56bbcSLuc Michel static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx) 49409d56bbcSLuc Michel { 49509d56bbcSLuc Michel size_t i; 49609d56bbcSLuc Michel 49709d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { 49809d56bbcSLuc Michel if (PLL_CHANNEL_INIT_INFO[i].a2w_ctrl_offset == idx) { 49909d56bbcSLuc Michel pll_channel_update(&s->channels[i]); 50009d56bbcSLuc Michel return; 50109d56bbcSLuc Michel } 50209d56bbcSLuc Michel } 50309d56bbcSLuc Michel } 50409d56bbcSLuc Michel 50572813624SLuc Michel static inline void update_mux_from_cm(BCM2835CprmanState *s, size_t idx) 50672813624SLuc Michel { 50772813624SLuc Michel size_t i; 50872813624SLuc Michel 50972813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { 51072813624SLuc Michel if ((CLOCK_MUX_INIT_INFO[i].cm_offset == idx) || 51172813624SLuc Michel (CLOCK_MUX_INIT_INFO[i].cm_offset + 4 == idx)) { 51272813624SLuc Michel /* matches CM_CTL or CM_DIV mux register */ 51372813624SLuc Michel clock_mux_update(&s->clock_muxes[i]); 51472813624SLuc Michel return; 51572813624SLuc Michel } 51672813624SLuc Michel } 51772813624SLuc Michel } 51872813624SLuc Michel 51909d56bbcSLuc Michel #define CASE_PLL_A2W_REGS(pll_) \ 5201e986e25SLuc Michel case R_A2W_ ## pll_ ## _CTRL: \ 5211e986e25SLuc Michel case R_A2W_ ## pll_ ## _ANA0: \ 5221e986e25SLuc Michel case R_A2W_ ## pll_ ## _ANA1: \ 5231e986e25SLuc Michel case R_A2W_ ## pll_ ## _ANA2: \ 5241e986e25SLuc Michel case R_A2W_ ## pll_ ## _ANA3: \ 5251e986e25SLuc Michel case R_A2W_ ## pll_ ## _FRAC 5261e986e25SLuc Michel 527fc14176bSLuc Michel static void cprman_write(void *opaque, hwaddr offset, 528fc14176bSLuc Michel uint64_t value, unsigned size) 529fc14176bSLuc Michel { 530fc14176bSLuc Michel BCM2835CprmanState *s = CPRMAN(opaque); 531fc14176bSLuc Michel size_t idx = offset / sizeof(uint32_t); 532fc14176bSLuc Michel 533fc14176bSLuc Michel if (FIELD_EX32(value, CPRMAN, PASSWORD) != CPRMAN_PASSWORD) { 534fc14176bSLuc Michel trace_bcm2835_cprman_write_invalid_magic(offset, value); 535fc14176bSLuc Michel return; 536fc14176bSLuc Michel } 537fc14176bSLuc Michel 538fc14176bSLuc Michel value &= ~R_CPRMAN_PASSWORD_MASK; 539fc14176bSLuc Michel 540fc14176bSLuc Michel trace_bcm2835_cprman_write(offset, value); 541fc14176bSLuc Michel s->regs[idx] = value; 542fc14176bSLuc Michel 5431e986e25SLuc Michel switch (idx) { 54409d56bbcSLuc Michel case R_CM_PLLA ... R_CM_PLLH: 54509d56bbcSLuc Michel case R_CM_PLLB: 54609d56bbcSLuc Michel /* 54709d56bbcSLuc Michel * A given CM_PLLx register is shared by both the PLL and the channels 54809d56bbcSLuc Michel * of this PLL. 54909d56bbcSLuc Michel */ 55009d56bbcSLuc Michel update_pll_and_channels_from_cm(s, idx); 55109d56bbcSLuc Michel break; 55209d56bbcSLuc Michel 55309d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLA) : 5541e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLA]); 5551e986e25SLuc Michel break; 5561e986e25SLuc Michel 55709d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLC) : 5581e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLC]); 5591e986e25SLuc Michel break; 5601e986e25SLuc Michel 56109d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLD) : 5621e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLD]); 5631e986e25SLuc Michel break; 5641e986e25SLuc Michel 56509d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLH) : 5661e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLH]); 5671e986e25SLuc Michel break; 5681e986e25SLuc Michel 56909d56bbcSLuc Michel CASE_PLL_A2W_REGS(PLLB) : 5701e986e25SLuc Michel pll_update(&s->plls[CPRMAN_PLLB]); 5711e986e25SLuc Michel break; 57209d56bbcSLuc Michel 57309d56bbcSLuc Michel case R_A2W_PLLA_DSI0: 57409d56bbcSLuc Michel case R_A2W_PLLA_CORE: 57509d56bbcSLuc Michel case R_A2W_PLLA_PER: 57609d56bbcSLuc Michel case R_A2W_PLLA_CCP2: 57709d56bbcSLuc Michel case R_A2W_PLLC_CORE2: 57809d56bbcSLuc Michel case R_A2W_PLLC_CORE1: 57909d56bbcSLuc Michel case R_A2W_PLLC_PER: 58009d56bbcSLuc Michel case R_A2W_PLLC_CORE0: 58109d56bbcSLuc Michel case R_A2W_PLLD_DSI0: 58209d56bbcSLuc Michel case R_A2W_PLLD_CORE: 58309d56bbcSLuc Michel case R_A2W_PLLD_PER: 58409d56bbcSLuc Michel case R_A2W_PLLD_DSI1: 58509d56bbcSLuc Michel case R_A2W_PLLH_AUX: 58609d56bbcSLuc Michel case R_A2W_PLLH_RCAL: 58709d56bbcSLuc Michel case R_A2W_PLLH_PIX: 58809d56bbcSLuc Michel case R_A2W_PLLB_ARM: 58909d56bbcSLuc Michel update_channel_from_a2w(s, idx); 59009d56bbcSLuc Michel break; 59172813624SLuc Michel 59272813624SLuc Michel case R_CM_GNRICCTL ... R_CM_SMIDIV: 59372813624SLuc Michel case R_CM_TCNTCNT ... R_CM_VECDIV: 59472813624SLuc Michel case R_CM_PULSECTL ... R_CM_PULSEDIV: 59572813624SLuc Michel case R_CM_SDCCTL ... R_CM_ARMCTL: 59672813624SLuc Michel case R_CM_AVEOCTL ... R_CM_EMMCDIV: 59772813624SLuc Michel case R_CM_EMMC2CTL ... R_CM_EMMC2DIV: 59872813624SLuc Michel update_mux_from_cm(s, idx); 59972813624SLuc Michel break; 600502960caSLuc Michel 601502960caSLuc Michel case R_CM_DSI0HSCK: 602502960caSLuc Michel dsi0hsck_mux_update(&s->dsi0hsck_mux); 603502960caSLuc Michel break; 604fc14176bSLuc Michel } 6051e986e25SLuc Michel } 6061e986e25SLuc Michel 60709d56bbcSLuc Michel #undef CASE_PLL_A2W_REGS 608fc14176bSLuc Michel 609fc14176bSLuc Michel static const MemoryRegionOps cprman_ops = { 610fc14176bSLuc Michel .read = cprman_read, 611fc14176bSLuc Michel .write = cprman_write, 612fc14176bSLuc Michel .endianness = DEVICE_LITTLE_ENDIAN, 613fc14176bSLuc Michel .valid = { 614fc14176bSLuc Michel /* 615fc14176bSLuc Michel * Although this hasn't been checked against real hardware, nor the 616fc14176bSLuc Michel * information can be found in a datasheet, it seems reasonable because 617fc14176bSLuc Michel * of the "PASSWORD" magic value found in every registers. 618fc14176bSLuc Michel */ 619fc14176bSLuc Michel .min_access_size = 4, 620fc14176bSLuc Michel .max_access_size = 4, 621fc14176bSLuc Michel .unaligned = false, 622fc14176bSLuc Michel }, 623fc14176bSLuc Michel .impl = { 624fc14176bSLuc Michel .max_access_size = 4, 625fc14176bSLuc Michel }, 626fc14176bSLuc Michel }; 627fc14176bSLuc Michel 628fc14176bSLuc Michel static void cprman_reset(DeviceState *dev) 629fc14176bSLuc Michel { 630fc14176bSLuc Michel BCM2835CprmanState *s = CPRMAN(dev); 6311e986e25SLuc Michel size_t i; 632fc14176bSLuc Michel 633fc14176bSLuc Michel memset(s->regs, 0, sizeof(s->regs)); 634fc14176bSLuc Michel 6351e986e25SLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) { 6361e986e25SLuc Michel device_cold_reset(DEVICE(&s->plls[i])); 6371e986e25SLuc Michel } 6381e986e25SLuc Michel 63909d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { 64009d56bbcSLuc Michel device_cold_reset(DEVICE(&s->channels[i])); 64109d56bbcSLuc Michel } 64209d56bbcSLuc Michel 643502960caSLuc Michel device_cold_reset(DEVICE(&s->dsi0hsck_mux)); 644502960caSLuc Michel 64572813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { 64672813624SLuc Michel device_cold_reset(DEVICE(&s->clock_muxes[i])); 64772813624SLuc Michel } 64872813624SLuc Michel 649fc14176bSLuc Michel clock_update_hz(s->xosc, s->xosc_freq); 650fc14176bSLuc Michel } 651fc14176bSLuc Michel 652fc14176bSLuc Michel static void cprman_init(Object *obj) 653fc14176bSLuc Michel { 654fc14176bSLuc Michel BCM2835CprmanState *s = CPRMAN(obj); 6551e986e25SLuc Michel size_t i; 6561e986e25SLuc Michel 6571e986e25SLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) { 6581e986e25SLuc Michel object_initialize_child(obj, PLL_INIT_INFO[i].name, 6591e986e25SLuc Michel &s->plls[i], TYPE_CPRMAN_PLL); 6601e986e25SLuc Michel set_pll_init_info(s, &s->plls[i], i); 6611e986e25SLuc Michel } 662fc14176bSLuc Michel 66309d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { 66409d56bbcSLuc Michel object_initialize_child(obj, PLL_CHANNEL_INIT_INFO[i].name, 66509d56bbcSLuc Michel &s->channels[i], 66609d56bbcSLuc Michel TYPE_CPRMAN_PLL_CHANNEL); 66709d56bbcSLuc Michel set_pll_channel_init_info(s, &s->channels[i], i); 66809d56bbcSLuc Michel } 66909d56bbcSLuc Michel 670502960caSLuc Michel object_initialize_child(obj, "dsi0hsck-mux", 671502960caSLuc Michel &s->dsi0hsck_mux, TYPE_CPRMAN_DSI0HSCK_MUX); 672502960caSLuc Michel s->dsi0hsck_mux.reg_cm = &s->regs[R_CM_DSI0HSCK]; 673502960caSLuc Michel 67472813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { 67572813624SLuc Michel char *alias; 67672813624SLuc Michel 67772813624SLuc Michel object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name, 67872813624SLuc Michel &s->clock_muxes[i], 67972813624SLuc Michel TYPE_CPRMAN_CLOCK_MUX); 68072813624SLuc Michel set_clock_mux_init_info(s, &s->clock_muxes[i], i); 68172813624SLuc Michel 68272813624SLuc Michel /* Expose muxes output as CPRMAN outputs */ 68372813624SLuc Michel alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name); 68472813624SLuc Michel qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias); 68572813624SLuc Michel g_free(alias); 68672813624SLuc Michel } 68772813624SLuc Michel 688fc14176bSLuc Michel s->xosc = clock_new(obj, "xosc"); 68972813624SLuc Michel s->gnd = clock_new(obj, "gnd"); 69072813624SLuc Michel 69172813624SLuc Michel clock_set(s->gnd, 0); 692fc14176bSLuc Michel 693fc14176bSLuc Michel memory_region_init_io(&s->iomem, obj, &cprman_ops, 694fc14176bSLuc Michel s, "bcm2835-cprman", 0x2000); 695fc14176bSLuc Michel sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); 696fc14176bSLuc Michel } 697fc14176bSLuc Michel 69872813624SLuc Michel static void connect_mux_sources(BCM2835CprmanState *s, 69972813624SLuc Michel CprmanClockMuxState *mux, 70072813624SLuc Michel const CprmanPllChannel *clk_mapping) 70172813624SLuc Michel { 70272813624SLuc Michel size_t i; 70372813624SLuc Michel Clock *td0 = s->clock_muxes[CPRMAN_CLOCK_TD0].out; 70472813624SLuc Michel Clock *td1 = s->clock_muxes[CPRMAN_CLOCK_TD1].out; 70572813624SLuc Michel 70672813624SLuc Michel /* For sources from 0 to 3. Source 4 to 9 are mux specific */ 70772813624SLuc Michel Clock * const CLK_SRC_MAPPING[] = { 70872813624SLuc Michel [CPRMAN_CLOCK_SRC_GND] = s->gnd, 70972813624SLuc Michel [CPRMAN_CLOCK_SRC_XOSC] = s->xosc, 71072813624SLuc Michel [CPRMAN_CLOCK_SRC_TD0] = td0, 71172813624SLuc Michel [CPRMAN_CLOCK_SRC_TD1] = td1, 71272813624SLuc Michel }; 71372813624SLuc Michel 71472813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) { 71572813624SLuc Michel CprmanPllChannel mapping = clk_mapping[i]; 71672813624SLuc Michel Clock *src; 71772813624SLuc Michel 71872813624SLuc Michel if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) { 71972813624SLuc Michel src = s->gnd; 72072813624SLuc Michel } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) { 721502960caSLuc Michel src = s->dsi0hsck_mux.out; 72272813624SLuc Michel } else if (i < CPRMAN_CLOCK_SRC_PLLA) { 72372813624SLuc Michel src = CLK_SRC_MAPPING[i]; 72472813624SLuc Michel } else { 72572813624SLuc Michel src = s->channels[mapping].out; 72672813624SLuc Michel } 72772813624SLuc Michel 72872813624SLuc Michel clock_set_source(mux->srcs[i], src); 72972813624SLuc Michel } 73072813624SLuc Michel } 73172813624SLuc Michel 7321e986e25SLuc Michel static void cprman_realize(DeviceState *dev, Error **errp) 7331e986e25SLuc Michel { 7341e986e25SLuc Michel BCM2835CprmanState *s = CPRMAN(dev); 7351e986e25SLuc Michel size_t i; 7361e986e25SLuc Michel 7371e986e25SLuc Michel for (i = 0; i < CPRMAN_NUM_PLL; i++) { 7381e986e25SLuc Michel CprmanPllState *pll = &s->plls[i]; 7391e986e25SLuc Michel 7401e986e25SLuc Michel clock_set_source(pll->xosc_in, s->xosc); 7411e986e25SLuc Michel 7421e986e25SLuc Michel if (!qdev_realize(DEVICE(pll), NULL, errp)) { 7431e986e25SLuc Michel return; 7441e986e25SLuc Michel } 7451e986e25SLuc Michel } 74609d56bbcSLuc Michel 74709d56bbcSLuc Michel for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) { 74809d56bbcSLuc Michel CprmanPllChannelState *channel = &s->channels[i]; 74909d56bbcSLuc Michel CprmanPll parent = PLL_CHANNEL_INIT_INFO[i].parent; 75009d56bbcSLuc Michel Clock *parent_clk = s->plls[parent].out; 75109d56bbcSLuc Michel 75209d56bbcSLuc Michel clock_set_source(channel->pll_in, parent_clk); 75309d56bbcSLuc Michel 75409d56bbcSLuc Michel if (!qdev_realize(DEVICE(channel), NULL, errp)) { 75509d56bbcSLuc Michel return; 75609d56bbcSLuc Michel } 75709d56bbcSLuc Michel } 75872813624SLuc Michel 759502960caSLuc Michel clock_set_source(s->dsi0hsck_mux.plla_in, 760502960caSLuc Michel s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out); 761502960caSLuc Michel clock_set_source(s->dsi0hsck_mux.plld_in, 762502960caSLuc Michel s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out); 763502960caSLuc Michel 764502960caSLuc Michel if (!qdev_realize(DEVICE(&s->dsi0hsck_mux), NULL, errp)) { 765502960caSLuc Michel return; 766502960caSLuc Michel } 767502960caSLuc Michel 76872813624SLuc Michel for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) { 76972813624SLuc Michel CprmanClockMuxState *clock_mux = &s->clock_muxes[i]; 77072813624SLuc Michel 77172813624SLuc Michel connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping); 77272813624SLuc Michel 77372813624SLuc Michel if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) { 77472813624SLuc Michel return; 77572813624SLuc Michel } 77672813624SLuc Michel } 7771e986e25SLuc Michel } 7781e986e25SLuc Michel 779fc14176bSLuc Michel static const VMStateDescription cprman_vmstate = { 780fc14176bSLuc Michel .name = TYPE_BCM2835_CPRMAN, 781fc14176bSLuc Michel .version_id = 1, 782fc14176bSLuc Michel .minimum_version_id = 1, 783e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 784fc14176bSLuc Michel VMSTATE_UINT32_ARRAY(regs, BCM2835CprmanState, CPRMAN_NUM_REGS), 785fc14176bSLuc Michel VMSTATE_END_OF_LIST() 786fc14176bSLuc Michel } 787fc14176bSLuc Michel }; 788fc14176bSLuc Michel 78930029973SRichard Henderson static const Property cprman_properties[] = { 790fc14176bSLuc Michel DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000), 791fc14176bSLuc Michel }; 792fc14176bSLuc Michel 793fc14176bSLuc Michel static void cprman_class_init(ObjectClass *klass, void *data) 794fc14176bSLuc Michel { 795fc14176bSLuc Michel DeviceClass *dc = DEVICE_CLASS(klass); 796fc14176bSLuc Michel 7971e986e25SLuc Michel dc->realize = cprman_realize; 798e3d08143SPeter Maydell device_class_set_legacy_reset(dc, cprman_reset); 799fc14176bSLuc Michel dc->vmsd = &cprman_vmstate; 800fc14176bSLuc Michel device_class_set_props(dc, cprman_properties); 801fc14176bSLuc Michel } 802fc14176bSLuc Michel 803fc14176bSLuc Michel static const TypeInfo cprman_info = { 804fc14176bSLuc Michel .name = TYPE_BCM2835_CPRMAN, 805fc14176bSLuc Michel .parent = TYPE_SYS_BUS_DEVICE, 806fc14176bSLuc Michel .instance_size = sizeof(BCM2835CprmanState), 807fc14176bSLuc Michel .class_init = cprman_class_init, 808fc14176bSLuc Michel .instance_init = cprman_init, 809fc14176bSLuc Michel }; 810fc14176bSLuc Michel 811fc14176bSLuc Michel static void cprman_register_types(void) 812fc14176bSLuc Michel { 813fc14176bSLuc Michel type_register_static(&cprman_info); 8141e986e25SLuc Michel type_register_static(&cprman_pll_info); 81509d56bbcSLuc Michel type_register_static(&cprman_pll_channel_info); 81672813624SLuc Michel type_register_static(&cprman_clock_mux_info); 817502960caSLuc Michel type_register_static(&cprman_dsi0hsck_mux_info); 818fc14176bSLuc Michel } 819fc14176bSLuc Michel 820fc14176bSLuc Michel type_init(cprman_register_types); 821