1 /* 2 * BCM2835 CPRMAN clock manager 3 * 4 * Copyright (c) 2020 Luc Michel <luc@lmichel.fr> 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #ifndef HW_MISC_CPRMAN_INTERNALS_H 10 #define HW_MISC_CPRMAN_INTERNALS_H 11 12 #include "hw/registerfields.h" 13 #include "hw/misc/bcm2835_cprman.h" 14 15 #define TYPE_CPRMAN_PLL "bcm2835-cprman-pll" 16 #define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel" 17 18 DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL, 19 TYPE_CPRMAN_PLL) 20 DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL, 21 TYPE_CPRMAN_PLL_CHANNEL) 22 23 /* Register map */ 24 25 /* PLLs */ 26 REG32(CM_PLLA, 0x104) 27 FIELD(CM_PLLA, LOADDSI0, 0, 1) 28 FIELD(CM_PLLA, HOLDDSI0, 1, 1) 29 FIELD(CM_PLLA, LOADCCP2, 2, 1) 30 FIELD(CM_PLLA, HOLDCCP2, 3, 1) 31 FIELD(CM_PLLA, LOADCORE, 4, 1) 32 FIELD(CM_PLLA, HOLDCORE, 5, 1) 33 FIELD(CM_PLLA, LOADPER, 6, 1) 34 FIELD(CM_PLLA, HOLDPER, 7, 1) 35 FIELD(CM_PLLx, ANARST, 8, 1) 36 REG32(CM_PLLC, 0x108) 37 FIELD(CM_PLLC, LOADCORE0, 0, 1) 38 FIELD(CM_PLLC, HOLDCORE0, 1, 1) 39 FIELD(CM_PLLC, LOADCORE1, 2, 1) 40 FIELD(CM_PLLC, HOLDCORE1, 3, 1) 41 FIELD(CM_PLLC, LOADCORE2, 4, 1) 42 FIELD(CM_PLLC, HOLDCORE2, 5, 1) 43 FIELD(CM_PLLC, LOADPER, 6, 1) 44 FIELD(CM_PLLC, HOLDPER, 7, 1) 45 REG32(CM_PLLD, 0x10c) 46 FIELD(CM_PLLD, LOADDSI0, 0, 1) 47 FIELD(CM_PLLD, HOLDDSI0, 1, 1) 48 FIELD(CM_PLLD, LOADDSI1, 2, 1) 49 FIELD(CM_PLLD, HOLDDSI1, 3, 1) 50 FIELD(CM_PLLD, LOADCORE, 4, 1) 51 FIELD(CM_PLLD, HOLDCORE, 5, 1) 52 FIELD(CM_PLLD, LOADPER, 6, 1) 53 FIELD(CM_PLLD, HOLDPER, 7, 1) 54 REG32(CM_PLLH, 0x110) 55 FIELD(CM_PLLH, LOADPIX, 0, 1) 56 FIELD(CM_PLLH, LOADAUX, 1, 1) 57 FIELD(CM_PLLH, LOADRCAL, 2, 1) 58 REG32(CM_PLLB, 0x170) 59 FIELD(CM_PLLB, LOADARM, 0, 1) 60 FIELD(CM_PLLB, HOLDARM, 1, 1) 61 62 REG32(A2W_PLLA_CTRL, 0x1100) 63 FIELD(A2W_PLLx_CTRL, NDIV, 0, 10) 64 FIELD(A2W_PLLx_CTRL, PDIV, 12, 3) 65 FIELD(A2W_PLLx_CTRL, PWRDN, 16, 1) 66 FIELD(A2W_PLLx_CTRL, PRST_DISABLE, 17, 1) 67 REG32(A2W_PLLC_CTRL, 0x1120) 68 REG32(A2W_PLLD_CTRL, 0x1140) 69 REG32(A2W_PLLH_CTRL, 0x1160) 70 REG32(A2W_PLLB_CTRL, 0x11e0) 71 72 REG32(A2W_PLLA_ANA0, 0x1010) 73 REG32(A2W_PLLA_ANA1, 0x1014) 74 FIELD(A2W_PLLx_ANA1, FB_PREDIV, 14, 1) 75 REG32(A2W_PLLA_ANA2, 0x1018) 76 REG32(A2W_PLLA_ANA3, 0x101c) 77 78 REG32(A2W_PLLC_ANA0, 0x1030) 79 REG32(A2W_PLLC_ANA1, 0x1034) 80 REG32(A2W_PLLC_ANA2, 0x1038) 81 REG32(A2W_PLLC_ANA3, 0x103c) 82 83 REG32(A2W_PLLD_ANA0, 0x1050) 84 REG32(A2W_PLLD_ANA1, 0x1054) 85 REG32(A2W_PLLD_ANA2, 0x1058) 86 REG32(A2W_PLLD_ANA3, 0x105c) 87 88 REG32(A2W_PLLH_ANA0, 0x1070) 89 REG32(A2W_PLLH_ANA1, 0x1074) 90 FIELD(A2W_PLLH_ANA1, FB_PREDIV, 11, 1) 91 REG32(A2W_PLLH_ANA2, 0x1078) 92 REG32(A2W_PLLH_ANA3, 0x107c) 93 94 REG32(A2W_PLLB_ANA0, 0x10f0) 95 REG32(A2W_PLLB_ANA1, 0x10f4) 96 REG32(A2W_PLLB_ANA2, 0x10f8) 97 REG32(A2W_PLLB_ANA3, 0x10fc) 98 99 REG32(A2W_PLLA_FRAC, 0x1200) 100 FIELD(A2W_PLLx_FRAC, FRAC, 0, 20) 101 REG32(A2W_PLLC_FRAC, 0x1220) 102 REG32(A2W_PLLD_FRAC, 0x1240) 103 REG32(A2W_PLLH_FRAC, 0x1260) 104 REG32(A2W_PLLB_FRAC, 0x12e0) 105 106 /* PLL channels */ 107 REG32(A2W_PLLA_DSI0, 0x1300) 108 FIELD(A2W_PLLx_CHANNELy, DIV, 0, 8) 109 FIELD(A2W_PLLx_CHANNELy, DISABLE, 8, 1) 110 REG32(A2W_PLLA_CORE, 0x1400) 111 REG32(A2W_PLLA_PER, 0x1500) 112 REG32(A2W_PLLA_CCP2, 0x1600) 113 114 REG32(A2W_PLLC_CORE2, 0x1320) 115 REG32(A2W_PLLC_CORE1, 0x1420) 116 REG32(A2W_PLLC_PER, 0x1520) 117 REG32(A2W_PLLC_CORE0, 0x1620) 118 119 REG32(A2W_PLLD_DSI0, 0x1340) 120 REG32(A2W_PLLD_CORE, 0x1440) 121 REG32(A2W_PLLD_PER, 0x1540) 122 REG32(A2W_PLLD_DSI1, 0x1640) 123 124 REG32(A2W_PLLH_AUX, 0x1360) 125 REG32(A2W_PLLH_RCAL, 0x1460) 126 REG32(A2W_PLLH_PIX, 0x1560) 127 REG32(A2W_PLLH_STS, 0x1660) 128 129 REG32(A2W_PLLB_ARM, 0x13e0) 130 131 /* misc registers */ 132 REG32(CM_LOCK, 0x114) 133 FIELD(CM_LOCK, FLOCKH, 12, 1) 134 FIELD(CM_LOCK, FLOCKD, 11, 1) 135 FIELD(CM_LOCK, FLOCKC, 10, 1) 136 FIELD(CM_LOCK, FLOCKB, 9, 1) 137 FIELD(CM_LOCK, FLOCKA, 8, 1) 138 139 /* 140 * This field is common to all registers. Each register write value must match 141 * the CPRMAN_PASSWORD magic value in its 8 MSB. 142 */ 143 FIELD(CPRMAN, PASSWORD, 24, 8) 144 #define CPRMAN_PASSWORD 0x5a 145 146 /* PLL init info */ 147 typedef struct PLLInitInfo { 148 const char *name; 149 size_t cm_offset; 150 size_t a2w_ctrl_offset; 151 size_t a2w_ana_offset; 152 uint32_t prediv_mask; /* Prediv bit in ana[1] */ 153 size_t a2w_frac_offset; 154 } PLLInitInfo; 155 156 #define FILL_PLL_INIT_INFO(pll_) \ 157 .cm_offset = R_CM_ ## pll_, \ 158 .a2w_ctrl_offset = R_A2W_ ## pll_ ## _CTRL, \ 159 .a2w_ana_offset = R_A2W_ ## pll_ ## _ANA0, \ 160 .a2w_frac_offset = R_A2W_ ## pll_ ## _FRAC 161 162 static const PLLInitInfo PLL_INIT_INFO[] = { 163 [CPRMAN_PLLA] = { 164 .name = "plla", 165 .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK, 166 FILL_PLL_INIT_INFO(PLLA), 167 }, 168 [CPRMAN_PLLC] = { 169 .name = "pllc", 170 .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK, 171 FILL_PLL_INIT_INFO(PLLC), 172 }, 173 [CPRMAN_PLLD] = { 174 .name = "plld", 175 .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK, 176 FILL_PLL_INIT_INFO(PLLD), 177 }, 178 [CPRMAN_PLLH] = { 179 .name = "pllh", 180 .prediv_mask = R_A2W_PLLH_ANA1_FB_PREDIV_MASK, 181 FILL_PLL_INIT_INFO(PLLH), 182 }, 183 [CPRMAN_PLLB] = { 184 .name = "pllb", 185 .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK, 186 FILL_PLL_INIT_INFO(PLLB), 187 }, 188 }; 189 190 #undef FILL_PLL_CHANNEL_INIT_INFO 191 192 static inline void set_pll_init_info(BCM2835CprmanState *s, 193 CprmanPllState *pll, 194 CprmanPll id) 195 { 196 pll->id = id; 197 pll->reg_cm = &s->regs[PLL_INIT_INFO[id].cm_offset]; 198 pll->reg_a2w_ctrl = &s->regs[PLL_INIT_INFO[id].a2w_ctrl_offset]; 199 pll->reg_a2w_ana = &s->regs[PLL_INIT_INFO[id].a2w_ana_offset]; 200 pll->prediv_mask = PLL_INIT_INFO[id].prediv_mask; 201 pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset]; 202 } 203 204 205 /* PLL channel init info */ 206 typedef struct PLLChannelInitInfo { 207 const char *name; 208 CprmanPll parent; 209 size_t cm_offset; 210 uint32_t cm_hold_mask; 211 uint32_t cm_load_mask; 212 size_t a2w_ctrl_offset; 213 unsigned int fixed_divider; 214 } PLLChannelInitInfo; 215 216 #define FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_) \ 217 .parent = CPRMAN_ ## pll_, \ 218 .cm_offset = R_CM_ ## pll_, \ 219 .cm_load_mask = R_CM_ ## pll_ ## _ ## LOAD ## channel_ ## _MASK, \ 220 .a2w_ctrl_offset = R_A2W_ ## pll_ ## _ ## channel_ 221 222 #define FILL_PLL_CHANNEL_INIT_INFO(pll_, channel_) \ 223 FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \ 224 .cm_hold_mask = R_CM_ ## pll_ ## _ ## HOLD ## channel_ ## _MASK, \ 225 .fixed_divider = 1 226 227 #define FILL_PLL_CHANNEL_INIT_INFO_nohold(pll_, channel_) \ 228 FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \ 229 .cm_hold_mask = 0 230 231 static PLLChannelInitInfo PLL_CHANNEL_INIT_INFO[] = { 232 [CPRMAN_PLLA_CHANNEL_DSI0] = { 233 .name = "plla-dsi0", 234 FILL_PLL_CHANNEL_INIT_INFO(PLLA, DSI0), 235 }, 236 [CPRMAN_PLLA_CHANNEL_CORE] = { 237 .name = "plla-core", 238 FILL_PLL_CHANNEL_INIT_INFO(PLLA, CORE), 239 }, 240 [CPRMAN_PLLA_CHANNEL_PER] = { 241 .name = "plla-per", 242 FILL_PLL_CHANNEL_INIT_INFO(PLLA, PER), 243 }, 244 [CPRMAN_PLLA_CHANNEL_CCP2] = { 245 .name = "plla-ccp2", 246 FILL_PLL_CHANNEL_INIT_INFO(PLLA, CCP2), 247 }, 248 249 [CPRMAN_PLLC_CHANNEL_CORE2] = { 250 .name = "pllc-core2", 251 FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE2), 252 }, 253 [CPRMAN_PLLC_CHANNEL_CORE1] = { 254 .name = "pllc-core1", 255 FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE1), 256 }, 257 [CPRMAN_PLLC_CHANNEL_PER] = { 258 .name = "pllc-per", 259 FILL_PLL_CHANNEL_INIT_INFO(PLLC, PER), 260 }, 261 [CPRMAN_PLLC_CHANNEL_CORE0] = { 262 .name = "pllc-core0", 263 FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE0), 264 }, 265 266 [CPRMAN_PLLD_CHANNEL_DSI0] = { 267 .name = "plld-dsi0", 268 FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI0), 269 }, 270 [CPRMAN_PLLD_CHANNEL_CORE] = { 271 .name = "plld-core", 272 FILL_PLL_CHANNEL_INIT_INFO(PLLD, CORE), 273 }, 274 [CPRMAN_PLLD_CHANNEL_PER] = { 275 .name = "plld-per", 276 FILL_PLL_CHANNEL_INIT_INFO(PLLD, PER), 277 }, 278 [CPRMAN_PLLD_CHANNEL_DSI1] = { 279 .name = "plld-dsi1", 280 FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI1), 281 }, 282 283 [CPRMAN_PLLH_CHANNEL_AUX] = { 284 .name = "pllh-aux", 285 .fixed_divider = 1, 286 FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, AUX), 287 }, 288 [CPRMAN_PLLH_CHANNEL_RCAL] = { 289 .name = "pllh-rcal", 290 .fixed_divider = 10, 291 FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, RCAL), 292 }, 293 [CPRMAN_PLLH_CHANNEL_PIX] = { 294 .name = "pllh-pix", 295 .fixed_divider = 10, 296 FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, PIX), 297 }, 298 299 [CPRMAN_PLLB_CHANNEL_ARM] = { 300 .name = "pllb-arm", 301 FILL_PLL_CHANNEL_INIT_INFO(PLLB, ARM), 302 }, 303 }; 304 305 #undef FILL_PLL_CHANNEL_INIT_INFO_nohold 306 #undef FILL_PLL_CHANNEL_INIT_INFO 307 #undef FILL_PLL_CHANNEL_INIT_INFO_common 308 309 static inline void set_pll_channel_init_info(BCM2835CprmanState *s, 310 CprmanPllChannelState *channel, 311 CprmanPllChannel id) 312 { 313 channel->id = id; 314 channel->parent = PLL_CHANNEL_INIT_INFO[id].parent; 315 channel->reg_cm = &s->regs[PLL_CHANNEL_INIT_INFO[id].cm_offset]; 316 channel->hold_mask = PLL_CHANNEL_INIT_INFO[id].cm_hold_mask; 317 channel->load_mask = PLL_CHANNEL_INIT_INFO[id].cm_load_mask; 318 channel->reg_a2w_ctrl = &s->regs[PLL_CHANNEL_INIT_INFO[id].a2w_ctrl_offset]; 319 channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider; 320 } 321 322 #endif 323