blob: 8763a9d71f86602c0d71ee35950fe6b1a5740a4b [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Taniya Das0e03aa22019-08-07 11:28:28 +05302
3#include <assert.h>
4#include <commonlib/helpers.h>
Elyes HAOUAS27718ac2020-09-19 09:32:36 +02005#include <console/console.h>
Taniya Das8ad0c862020-02-28 17:05:49 +05306#include <delay.h>
Taniya Das0e03aa22019-08-07 11:28:28 +05307#include <device/mmio.h>
8#include <soc/clock.h>
Taniya Das8ad0c862020-02-28 17:05:49 +05309#include <timer.h>
Taniya Das0e03aa22019-08-07 11:28:28 +053010#include <types.h>
11
12#define DIV(div) (2 * div - 1)
13
14struct clock_config qup_cfg[] = {
15 {
Taniya Das0e03aa22019-08-07 11:28:28 +053016 .hz = SRC_XO_HZ, /* 19.2KHz */
17 .src = SRC_XO_19_2MHZ,
18 .div = DIV(1),
19 }
20};
21
22struct clock_config qspi_core_cfg[] = {
23 {
24 .hz = SRC_XO_HZ, /* 19.2KHz */
25 .src = SRC_XO_19_2MHZ,
26 .div = DIV(1),
27 },
28 {
29 .hz = 100 * MHz,
30 .src = SRC_GPLL0_EVEN_300MHZ,
31 .div = DIV(3),
32 },
33 {
34 .hz = 150 * MHz,
35 .src = SRC_GPLL0_EVEN_300MHZ,
36 .div = DIV(2),
37 },
38 {
39 .hz = GPLL0_EVEN_HZ, /* 300MHz */
40 .src = SRC_GPLL0_EVEN_300MHZ,
41 .div = DIV(1),
42 }
43};
44
Taniya Dasece88ab2019-11-05 21:37:32 +053045struct clock_config qup_wrap_cfg[] = {
46 {
47 .hz = SRC_XO_HZ, /* 19.2KHz */
48 .src = SRC_XO_19_2MHZ,
49 .div = DIV(1),
50 },
51 {
52 .hz = 32 * MHz,
53 .src = SRC_GPLL0_EVEN_300MHZ,
54 .div = DIV(1),
55 .m = 8,
56 .n = 75,
Taniya Das91dc1e72019-12-19 16:41:02 +053057 .d_2 = 75,
Taniya Dasece88ab2019-11-05 21:37:32 +053058 },
59 {
60 .hz = 48 * MHz,
61 .src = SRC_GPLL0_EVEN_300MHZ,
62 .div = DIV(1),
63 .m = 4,
64 .n = 25,
Taniya Das91dc1e72019-12-19 16:41:02 +053065 .d_2 = 25,
Taniya Dasece88ab2019-11-05 21:37:32 +053066 },
67 {
68 .hz = 64 * MHz,
69 .src = SRC_GPLL0_EVEN_300MHZ,
70 .div = DIV(1),
71 .m = 16,
72 .n = 75,
Taniya Das91dc1e72019-12-19 16:41:02 +053073 .d_2 = 75,
Taniya Dasece88ab2019-11-05 21:37:32 +053074 },
75 {
76 .hz = 96 * MHz,
77 .src = SRC_GPLL0_EVEN_300MHZ,
78 .div = DIV(1),
79 .m = 8,
80 .n = 25,
Taniya Das91dc1e72019-12-19 16:41:02 +053081 .d_2 = 25,
Taniya Dasece88ab2019-11-05 21:37:32 +053082 },
83 {
84 .hz = 100 * MHz,
85 .src = SRC_GPLL0_EVEN_300MHZ,
86 .div = DIV(3),
87 },
88 {
89 .hz = SRC_XO_HZ, /* 19.2KHz */
90 .src = SRC_XO_19_2MHZ,
91 .div = DIV(1),
92 },
93 {
94 .hz = SRC_XO_HZ, /* 19.2KHz */
95 .src = SRC_XO_19_2MHZ,
96 .div = DIV(1),
97 },
98};
99
Taniya Dasdc92cea2019-07-08 12:00:51 +0530100static struct sc7180_mnd_clock *mdss_clock[MDSS_CLK_COUNT] = {
101 [MDSS_CLK_ESC0] = &mdss->esc0,
102 [MDSS_CLK_PCLK0] = &mdss->pclk0,
103 [MDSS_CLK_BYTE0] = &mdss->byte0,
104 [MDSS_CLK_BYTE0_INTF] = &mdss->byte0,
105};
106
107static u32 *mdss_cbcr[MDSS_CLK_COUNT] = {
108 [MDSS_CLK_ESC0] = &mdss->esc0_cbcr,
109 [MDSS_CLK_PCLK0] = &mdss->pclk0_cbcr,
110 [MDSS_CLK_BYTE0] = &mdss->byte0_cbcr,
111 [MDSS_CLK_BYTE0_INTF] = &mdss->byte0_intf_cbcr,
112};
113
Taniya Das0e03aa22019-08-07 11:28:28 +0530114static int clock_configure_gpll0(void)
115{
Patrick Georgib9d5b262019-12-05 19:56:53 +0100116 setbits32(&gcc->gpll0.user_ctl_u, 1 << SCALE_FREQ_SHFT);
Taniya Das0e03aa22019-08-07 11:28:28 +0530117
118 /* Keep existing GPLL0 configuration, in RUN mode @600Mhz. */
Patrick Georgib9d5b262019-12-05 19:56:53 +0100119 setbits32(&gcc->gpll0.user_ctl,
Taniya Das0e03aa22019-08-07 11:28:28 +0530120 1 << CLK_CTL_GPLL_PLLOUT_EVEN_SHFT |
121 1 << CLK_CTL_GPLL_PLLOUT_MAIN_SHFT |
122 1 << CLK_CTL_GPLL_PLLOUT_ODD_SHFT);
123
124 return 0;
125}
126
127static int clock_configure_mnd(struct sc7180_clock *clk, uint32_t m, uint32_t n,
128 uint32_t d_2)
129{
130 struct sc7180_mnd_clock *mnd = (struct sc7180_mnd_clock *)clk;
Patrick Georgib9d5b262019-12-05 19:56:53 +0100131 setbits32(&clk->rcg_cfg,
Taniya Das0e03aa22019-08-07 11:28:28 +0530132 RCG_MODE_DUAL_EDGE << CLK_CTL_CFG_MODE_SHFT);
133
134 write32(&mnd->m, m & CLK_CTL_RCG_MND_BMSK);
135 write32(&mnd->n, ~(n-m) & CLK_CTL_RCG_MND_BMSK);
136 write32(&mnd->d_2, ~(d_2) & CLK_CTL_RCG_MND_BMSK);
137
138 return 0;
139}
140
141static int clock_configure(struct sc7180_clock *clk,
142 struct clock_config *clk_cfg,
143 uint32_t hz, uint32_t num_perfs)
144{
145 uint32_t reg_val;
146 uint32_t idx;
147
148 for (idx = 0; idx < num_perfs; idx++)
149 if (hz <= clk_cfg[idx].hz)
150 break;
151
152 assert(hz == clk_cfg[idx].hz);
153
154 reg_val = (clk_cfg[idx].src << CLK_CTL_CFG_SRC_SEL_SHFT) |
155 (clk_cfg[idx].div << CLK_CTL_CFG_SRC_DIV_SHFT);
156
157 /* Set clock config */
158 write32(&clk->rcg_cfg, reg_val);
159
160 if (clk_cfg[idx].m != 0)
161 clock_configure_mnd(clk, clk_cfg[idx].m, clk_cfg[idx].n,
162 clk_cfg[idx].d_2);
163
164 /* Commit config to RCG*/
Patrick Georgib9d5b262019-12-05 19:56:53 +0100165 setbits32(&clk->rcg_cmd, BIT(CLK_CTL_CMD_UPDATE_SHFT));
Taniya Das0e03aa22019-08-07 11:28:28 +0530166
167 return 0;
168}
169
170static bool clock_is_off(u32 *cbcr_addr)
171{
172 return (read32(cbcr_addr) & CLK_CTL_CBC_CLK_OFF_BMSK);
173}
174
175static int clock_enable_vote(void *cbcr_addr, void *vote_addr,
176 uint32_t vote_bit)
177{
178 /* Set clock vote bit */
Patrick Georgib9d5b262019-12-05 19:56:53 +0100179 setbits32(vote_addr, BIT(vote_bit));
Taniya Das0e03aa22019-08-07 11:28:28 +0530180
181 /* Ensure clock is enabled */
182 while (clock_is_off(cbcr_addr))
183 ;
184
185 return 0;
186}
187
188static int clock_enable(void *cbcr_addr)
189{
190 /* Set clock enable bit */
Patrick Georgib9d5b262019-12-05 19:56:53 +0100191 setbits32(cbcr_addr, BIT(CLK_CTL_CBC_CLK_EN_SHFT));
Taniya Das0e03aa22019-08-07 11:28:28 +0530192
193 /* Ensure clock is enabled */
194 while (clock_is_off(cbcr_addr))
195 ;
196
197 return 0;
198}
199
200void clock_reset_aop(void)
201{
202 /* Bring AOP out of RESET */
Patrick Georgib9d5b262019-12-05 19:56:53 +0100203 clrbits32(&aoss->aoss_cc_apcs_misc, BIT(AOP_RESET_SHFT));
Taniya Das0e03aa22019-08-07 11:28:28 +0530204}
205
206void clock_configure_qspi(uint32_t hz)
207{
208 clock_configure(&gcc->qspi_core,
209 qspi_core_cfg, hz,
210 ARRAY_SIZE(qspi_core_cfg));
211 clock_enable(&gcc->qspi_cnoc_ahb_cbcr);
Taniya Dasdc92cea2019-07-08 12:00:51 +0530212 clock_enable(&gcc->qspi_core_cbcr);
Taniya Das0e03aa22019-08-07 11:28:28 +0530213}
214
215int clock_reset_bcr(void *bcr_addr, bool reset)
216{
217 struct sc7180_bcr *bcr = bcr_addr;
218
219 if (reset)
Patrick Georgib9d5b262019-12-05 19:56:53 +0100220 setbits32(bcr, BIT(CLK_CTL_BCR_BLK_ARES_SHFT));
Taniya Das0e03aa22019-08-07 11:28:28 +0530221 else
Patrick Georgib9d5b262019-12-05 19:56:53 +0100222 clrbits32(bcr, BIT(CLK_CTL_BCR_BLK_ARES_SHFT));
Taniya Das0e03aa22019-08-07 11:28:28 +0530223
224 return 0;
225}
226
Taniya Dasece88ab2019-11-05 21:37:32 +0530227void clock_configure_dfsr(int qup)
228{
229 int idx;
230 int s = qup % QUP_WRAP1_S0;
231 uint32_t reg_val;
232 struct sc7180_qupv3_clock *qup_clk = qup < QUP_WRAP1_S0 ?
233 &gcc->qup_wrap0_s[s] : &gcc->qup_wrap1_s[s];
234
Taniya Das91dc1e72019-12-19 16:41:02 +0530235 clrsetbits32(&qup_clk->dfsr_clk.cmd_dfsr,
236 BIT(CLK_CTL_CMD_RCG_SW_CTL_SHFT),
237 BIT(CLK_CTL_CMD_DFSR_SHFT));
Taniya Dasece88ab2019-11-05 21:37:32 +0530238
239 for (idx = 0; idx < ARRAY_SIZE(qup_wrap_cfg); idx++) {
240 reg_val = (qup_wrap_cfg[idx].src << CLK_CTL_CFG_SRC_SEL_SHFT) |
241 (qup_wrap_cfg[idx].div << CLK_CTL_CFG_SRC_DIV_SHFT);
242
243 write32(&qup_clk->dfsr_clk.perf_dfsr[idx], reg_val);
244
245 if (qup_wrap_cfg[idx].m == 0)
246 continue;
247
Taniya Das91dc1e72019-12-19 16:41:02 +0530248 setbits32(&qup_clk->dfsr_clk.perf_dfsr[idx],
Taniya Dasece88ab2019-11-05 21:37:32 +0530249 RCG_MODE_DUAL_EDGE << CLK_CTL_CFG_MODE_SHFT);
250
251 reg_val = qup_wrap_cfg[idx].m & CLK_CTL_RCG_MND_BMSK;
252 write32(&qup_clk->dfsr_clk.perf_m_dfsr[idx], reg_val);
253
254 reg_val = ~(qup_wrap_cfg[idx].n - qup_wrap_cfg[idx].m)
255 & CLK_CTL_RCG_MND_BMSK;
256 write32(&qup_clk->dfsr_clk.perf_n_dfsr[idx], reg_val);
257
258 reg_val = ~(qup_wrap_cfg[idx].d_2) & CLK_CTL_RCG_MND_BMSK;
259 write32(&qup_clk->dfsr_clk.perf_d_dfsr[idx], reg_val);
260 }
261}
262
Taniya Das0e03aa22019-08-07 11:28:28 +0530263void clock_configure_qup(int qup, uint32_t hz)
264{
265 int s = qup % QUP_WRAP1_S0;
266 struct sc7180_qupv3_clock *qup_clk = qup < QUP_WRAP1_S0 ?
267 &gcc->qup_wrap0_s[s] : &gcc->qup_wrap1_s[s];
268
269 clock_configure(&qup_clk->mnd_clk.clock, qup_cfg, hz,
270 ARRAY_SIZE(qup_cfg));
271}
272
273void clock_enable_qup(int qup)
274{
275 int s = qup % QUP_WRAP1_S0;
276 int clk_en_off = qup < QUP_WRAP1_S0 ?
277 QUPV3_WRAP0_CLK_ENA_S(s) : QUPV3_WRAP1_CLK_ENA_S(s);
278 struct sc7180_qupv3_clock *qup_clk = qup < QUP_WRAP1_S0 ?
279 &gcc->qup_wrap0_s[s] : &gcc->qup_wrap1_s[s];
280
281 clock_enable_vote(&qup_clk->mnd_clk, &gcc->apcs_clk_br_en1,
282 clk_en_off);
283}
284
Taniya Das8ad0c862020-02-28 17:05:49 +0530285static int pll_init_and_set(struct sc7180_apss_clock *apss, u32 l_val)
286{
287 u32 gfmux_val;
288
289 /* Configure and Enable PLL */
290 write32(&apss->pll.config_ctl_lo, 0x0);
291 setbits32(&apss->pll.config_ctl_lo, 0x2 << CTUNE_SHFT |
292 0x2 << K_I_SHFT | 0x5 << K_P_SHFT |
293 0x2 << PFA_MSB_SHFT | 0x2 << REF_CONT_SHFT);
294
295 write32(&apss->pll.config_ctl_hi, 0x0);
296 setbits32(&apss->pll.config_ctl_hi, 0x2 << CUR_ADJ_SHFT |
297 BIT(DMET_SHFT) | 0xF << RES_SHFT);
298
299 write32(&apss->pll.config_ctl_u1, 0x0);
300 write32(&apss->pll.l_val, l_val);
301
302 setbits32(&apss->pll.mode, BIT(BYPASSNL_SHFT));
303 udelay(5);
304 setbits32(&apss->pll.mode, BIT(RESET_SHFT));
305
306 setbits32(&apss->pll.opmode, RUN_MODE);
307
308 if (!wait_us(100, read32(&apss->pll.mode) & LOCK_DET_BMSK)) {
309 printk(BIOS_ERR, "ERROR: PLL did not lock!\n");
310 return -1;
311 }
312
313 setbits32(&apss->pll.mode, BIT(OUTCTRL_SHFT));
314
315 gfmux_val = read32(&apss->cfg_gfmux) & ~GFMUX_SRC_SEL_BMSK;
316 gfmux_val |= APCS_SRC_EARLY;
317 write32(&apss->cfg_gfmux, gfmux_val);
318
319 return 0;
320}
321
322static void speed_up_boot_cpu(void)
323{
324 /* 1516.8 MHz */
325 if (!pll_init_and_set(apss_silver, L_VAL_1516P8MHz))
326 printk(BIOS_DEBUG, "Silver Frequency bumped to 1.5168(GHz)\n");
327
328 /* 1209.6 MHz */
329 if (!pll_init_and_set(apss_l3, L_VAL_1209P6MHz))
330 printk(BIOS_DEBUG, "L3 Frequency bumped to 1.2096(GHz)\n");
331}
332
Taniya Dasdc92cea2019-07-08 12:00:51 +0530333int mdss_clock_configure(enum mdss_clock clk_type, uint32_t source,
334 uint32_t half_divider, uint32_t m,
335 uint32_t n, uint32_t d_2)
336{
337 struct clock_config mdss_clk_cfg;
338 uint32_t reg_val;
339
340 if (clk_type >= MDSS_CLK_COUNT)
341 return -1;
342
343 /* Initialize it with received arguments */
344 mdss_clk_cfg.hz = 0;
345 mdss_clk_cfg.src = source;
346
347 /*
348 * client is expected to provide 2n divider value,
349 * as the divider value in register is in form "2n-1"
350 */
351 mdss_clk_cfg.div = half_divider ? (half_divider - 1) : 0;
352 mdss_clk_cfg.m = m;
353 mdss_clk_cfg.n = n;
354 mdss_clk_cfg.d_2 = d_2;
355
356 /* configure and set the clock */
357 reg_val = (mdss_clk_cfg.src << CLK_CTL_CFG_SRC_SEL_SHFT) |
358 (mdss_clk_cfg.div << CLK_CTL_CFG_SRC_DIV_SHFT);
359
360 write32(&mdss_clock[clk_type]->clock.rcg_cfg, reg_val);
361
362 /* Set m/n/d values for a specific clock */
363 if (mdss_clk_cfg.m != 0)
364 clock_configure_mnd((struct sc7180_clock *)mdss_clock[clk_type],
365 mdss_clk_cfg.m, mdss_clk_cfg.n, mdss_clk_cfg.d_2);
366
367 /* Commit config to RCG */
368 setbits32(&mdss_clock[clk_type]->clock.rcg_cmd,
369 BIT(CLK_CTL_CMD_UPDATE_SHFT));
370
371 return 0;
372}
373
374int mdss_clock_enable(enum mdss_clock clk_type)
375{
376 if (clk_type >= MDSS_CLK_COUNT)
377 return -1;
378
379 /* Enable clock*/
380 clock_enable(mdss_cbcr[clk_type]);
381
382 return 0;
383}
384
Taniya Das0e03aa22019-08-07 11:28:28 +0530385void clock_init(void)
386{
387 clock_configure_gpll0();
388
Taniya Dasdc92cea2019-07-08 12:00:51 +0530389 clock_enable_vote(&gcc->qup_wrap0_core_2x_cbcr,
Taniya Das0e03aa22019-08-07 11:28:28 +0530390 &gcc->apcs_clk_br_en1,
391 QUPV3_WRAP0_CORE_2X_CLK_ENA);
392 clock_enable_vote(&gcc->qup_wrap0_core_cbcr,
393 &gcc->apcs_clk_br_en1,
394 QUPV3_WRAP0_CORE_CLK_ENA);
395 clock_enable_vote(&gcc->qup_wrap0_m_ahb_cbcr,
396 &gcc->apcs_clk_br_en1,
397 QUPV3_WRAP_0_M_AHB_CLK_ENA);
398 clock_enable_vote(&gcc->qup_wrap0_s_ahb_cbcr,
399 &gcc->apcs_clk_br_en1,
400 QUPV3_WRAP_0_S_AHB_CLK_ENA);
401
402 clock_enable_vote(&gcc->qup_wrap1_core_2x_cbcr,
403 &gcc->apcs_clk_br_en1,
404 QUPV3_WRAP1_CORE_2X_CLK_ENA);
405 clock_enable_vote(&gcc->qup_wrap1_core_cbcr,
406 &gcc->apcs_clk_br_en1,
407 QUPV3_WRAP1_CORE_CLK_ENA);
408 clock_enable_vote(&gcc->qup_wrap1_m_ahb_cbcr,
409 &gcc->apcs_clk_br_en1,
410 QUPV3_WRAP_1_M_AHB_CLK_ENA);
411 clock_enable_vote(&gcc->qup_wrap1_s_ahb_cbcr,
412 &gcc->apcs_clk_br_en1,
413 QUPV3_WRAP_1_S_AHB_CLK_ENA);
Taniya Das8ad0c862020-02-28 17:05:49 +0530414 speed_up_boot_cpu();
Taniya Das0e03aa22019-08-07 11:28:28 +0530415}