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