hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation
[qemu.git] / include / hw / misc / bcm2835_cprman_internals.h
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