1e6e505b9SAlexander Graf /*
2e6e505b9SAlexander Graf * sun6i specific clock code
3e6e505b9SAlexander Graf *
4e6e505b9SAlexander Graf * (C) Copyright 2007-2012
5e6e505b9SAlexander Graf * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
6e6e505b9SAlexander Graf * Tom Cubie <tangliang@allwinnertech.com>
7e6e505b9SAlexander Graf *
8e6e505b9SAlexander Graf * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
9e6e505b9SAlexander Graf *
10e6e505b9SAlexander Graf * SPDX-License-Identifier: GPL-2.0+
11e6e505b9SAlexander Graf */
12e6e505b9SAlexander Graf
13e6e505b9SAlexander Graf #include <common.h>
14e6e505b9SAlexander Graf #include <asm/io.h>
15e6e505b9SAlexander Graf #include <asm/arch/clock.h>
16e6e505b9SAlexander Graf #include <asm/arch/prcm.h>
17e6e505b9SAlexander Graf #include <asm/arch/sys_proto.h>
18e6e505b9SAlexander Graf
19e6e505b9SAlexander Graf #ifdef CONFIG_SPL_BUILD
clock_init_safe(void)20e6e505b9SAlexander Graf void clock_init_safe(void)
21e6e505b9SAlexander Graf {
22e6e505b9SAlexander Graf struct sunxi_ccm_reg * const ccm =
23e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
242865433aSAndre Przywara
257b82a229SAndre Przywara #if !defined(CONFIG_MACH_SUNXI_H3_H5) && !defined(CONFIG_MACH_SUN50I)
26e6e505b9SAlexander Graf struct sunxi_prcm_reg * const prcm =
27e6e505b9SAlexander Graf (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
28e6e505b9SAlexander Graf
29e6e505b9SAlexander Graf /* Set PLL ldo voltage without this PLL6 does not work properly */
30e6e505b9SAlexander Graf clrsetbits_le32(&prcm->pll_ctrl1, PRCM_PLL_CTRL_LDO_KEY_MASK,
31e6e505b9SAlexander Graf PRCM_PLL_CTRL_LDO_KEY);
32e6e505b9SAlexander Graf clrsetbits_le32(&prcm->pll_ctrl1, ~PRCM_PLL_CTRL_LDO_KEY_MASK,
33e6e505b9SAlexander Graf PRCM_PLL_CTRL_LDO_DIGITAL_EN | PRCM_PLL_CTRL_LDO_ANALOG_EN |
34e6e505b9SAlexander Graf PRCM_PLL_CTRL_EXT_OSC_EN | PRCM_PLL_CTRL_LDO_OUT_L(1140));
35e6e505b9SAlexander Graf clrbits_le32(&prcm->pll_ctrl1, PRCM_PLL_CTRL_LDO_KEY_MASK);
362865433aSAndre Przywara #endif
37e6e505b9SAlexander Graf
381ae5def6SJernej Skrabec #if defined(CONFIG_MACH_SUN8I_R40) || defined(CONFIG_MACH_SUN50I)
39328ce7fdSChen-Yu Tsai /* Set PLL lock enable bits and switch to old lock mode */
40328ce7fdSChen-Yu Tsai writel(GENMASK(12, 0), &ccm->pll_lock_ctrl);
41328ce7fdSChen-Yu Tsai #endif
42328ce7fdSChen-Yu Tsai
43e6e505b9SAlexander Graf clock_set_pll1(408000000);
44e6e505b9SAlexander Graf
45e6e505b9SAlexander Graf writel(PLL6_CFG_DEFAULT, &ccm->pll6_cfg);
46e6e505b9SAlexander Graf while (!(readl(&ccm->pll6_cfg) & CCM_PLL6_CTRL_LOCK))
47e6e505b9SAlexander Graf ;
48e6e505b9SAlexander Graf
49e6e505b9SAlexander Graf writel(AHB1_ABP1_DIV_DEFAULT, &ccm->ahb1_apb1_div);
50e6e505b9SAlexander Graf
51e6e505b9SAlexander Graf writel(MBUS_CLK_DEFAULT, &ccm->mbus0_clk_cfg);
522865433aSAndre Przywara if (IS_ENABLED(CONFIG_MACH_SUN6I))
53e6e505b9SAlexander Graf writel(MBUS_CLK_DEFAULT, &ccm->mbus1_clk_cfg);
549946631aSIcenowy Zheng
559946631aSIcenowy Zheng #if defined(CONFIG_MACH_SUN8I_R40) && defined(CONFIG_SUNXI_AHCI)
569946631aSIcenowy Zheng setbits_le32(&ccm->sata_pll_cfg, CCM_SATA_PLL_DEFAULT);
579946631aSIcenowy Zheng setbits_le32(&ccm->ahb_reset0_cfg, 0x1 << AHB_GATE_OFFSET_SATA);
589946631aSIcenowy Zheng setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_SATA);
599946631aSIcenowy Zheng setbits_le32(&ccm->sata_clk_cfg, CCM_SATA_CTRL_ENABLE);
609946631aSIcenowy Zheng #endif
61e6e505b9SAlexander Graf }
62e6e505b9SAlexander Graf #endif
63e6e505b9SAlexander Graf
clock_init_sec(void)64e6e505b9SAlexander Graf void clock_init_sec(void)
65e6e505b9SAlexander Graf {
667b82a229SAndre Przywara #ifdef CONFIG_MACH_SUNXI_H3_H5
67e6e505b9SAlexander Graf struct sunxi_ccm_reg * const ccm =
68e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
69*e37a1b17SIcenowy Zheng struct sunxi_prcm_reg * const prcm =
70*e37a1b17SIcenowy Zheng (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
71e6e505b9SAlexander Graf
72e6e505b9SAlexander Graf setbits_le32(&ccm->ccu_sec_switch,
73e6e505b9SAlexander Graf CCM_SEC_SWITCH_MBUS_NONSEC |
74e6e505b9SAlexander Graf CCM_SEC_SWITCH_BUS_NONSEC |
75e6e505b9SAlexander Graf CCM_SEC_SWITCH_PLL_NONSEC);
76*e37a1b17SIcenowy Zheng setbits_le32(&prcm->prcm_sec_switch,
77*e37a1b17SIcenowy Zheng PRCM_SEC_SWITCH_APB0_CLK_NONSEC |
78*e37a1b17SIcenowy Zheng PRCM_SEC_SWITCH_PLL_CFG_NONSEC |
79*e37a1b17SIcenowy Zheng PRCM_SEC_SWITCH_PWR_GATE_NONSEC);
80e6e505b9SAlexander Graf #endif
81e6e505b9SAlexander Graf }
82e6e505b9SAlexander Graf
clock_init_uart(void)83e6e505b9SAlexander Graf void clock_init_uart(void)
84e6e505b9SAlexander Graf {
85e6e505b9SAlexander Graf #if CONFIG_CONS_INDEX < 5
86e6e505b9SAlexander Graf struct sunxi_ccm_reg *const ccm =
87e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
88e6e505b9SAlexander Graf
89e6e505b9SAlexander Graf /* uart clock source is apb2 */
90e6e505b9SAlexander Graf writel(APB2_CLK_SRC_OSC24M|
91e6e505b9SAlexander Graf APB2_CLK_RATE_N_1|
92e6e505b9SAlexander Graf APB2_CLK_RATE_M(1),
93e6e505b9SAlexander Graf &ccm->apb2_div);
94e6e505b9SAlexander Graf
95e6e505b9SAlexander Graf /* open the clock for uart */
96e6e505b9SAlexander Graf setbits_le32(&ccm->apb2_gate,
97e6e505b9SAlexander Graf CLK_GATE_OPEN << (APB2_GATE_UART_SHIFT +
98e6e505b9SAlexander Graf CONFIG_CONS_INDEX - 1));
99e6e505b9SAlexander Graf
100e6e505b9SAlexander Graf /* deassert uart reset */
101e6e505b9SAlexander Graf setbits_le32(&ccm->apb2_reset_cfg,
102e6e505b9SAlexander Graf 1 << (APB2_RESET_UART_SHIFT +
103e6e505b9SAlexander Graf CONFIG_CONS_INDEX - 1));
104e6e505b9SAlexander Graf #else
105e6e505b9SAlexander Graf /* enable R_PIO and R_UART clocks, and de-assert resets */
106e6e505b9SAlexander Graf prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_UART);
107e6e505b9SAlexander Graf #endif
108e6e505b9SAlexander Graf }
109e6e505b9SAlexander Graf
110e6e505b9SAlexander Graf #ifdef CONFIG_SPL_BUILD
clock_set_pll1(unsigned int clk)111e6e505b9SAlexander Graf void clock_set_pll1(unsigned int clk)
112e6e505b9SAlexander Graf {
113e6e505b9SAlexander Graf struct sunxi_ccm_reg * const ccm =
114e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
115e6e505b9SAlexander Graf const int p = 0;
116e6e505b9SAlexander Graf int k = 1;
117e6e505b9SAlexander Graf int m = 1;
118e6e505b9SAlexander Graf
119e6e505b9SAlexander Graf if (clk > 1152000000) {
120e6e505b9SAlexander Graf k = 2;
121e6e505b9SAlexander Graf } else if (clk > 768000000) {
122e6e505b9SAlexander Graf k = 3;
123e6e505b9SAlexander Graf m = 2;
124e6e505b9SAlexander Graf }
125e6e505b9SAlexander Graf
126e6e505b9SAlexander Graf /* Switch to 24MHz clock while changing PLL1 */
127e6e505b9SAlexander Graf writel(AXI_DIV_3 << AXI_DIV_SHIFT |
128e6e505b9SAlexander Graf ATB_DIV_2 << ATB_DIV_SHIFT |
129e6e505b9SAlexander Graf CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT,
130e6e505b9SAlexander Graf &ccm->cpu_axi_cfg);
131e6e505b9SAlexander Graf
132e6e505b9SAlexander Graf /*
133e6e505b9SAlexander Graf * sun6i: PLL1 rate = ((24000000 * n * k) >> 0) / m (p is ignored)
134e6e505b9SAlexander Graf * sun8i: PLL1 rate = ((24000000 * n * k) >> p) / m
135e6e505b9SAlexander Graf */
136e6e505b9SAlexander Graf writel(CCM_PLL1_CTRL_EN | CCM_PLL1_CTRL_P(p) |
137e6e505b9SAlexander Graf CCM_PLL1_CTRL_N(clk / (24000000 * k / m)) |
138e6e505b9SAlexander Graf CCM_PLL1_CTRL_K(k) | CCM_PLL1_CTRL_M(m), &ccm->pll1_cfg);
139e6e505b9SAlexander Graf sdelay(200);
140e6e505b9SAlexander Graf
141e6e505b9SAlexander Graf /* Switch CPU to PLL1 */
142e6e505b9SAlexander Graf writel(AXI_DIV_3 << AXI_DIV_SHIFT |
143e6e505b9SAlexander Graf ATB_DIV_2 << ATB_DIV_SHIFT |
144e6e505b9SAlexander Graf CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT,
145e6e505b9SAlexander Graf &ccm->cpu_axi_cfg);
146e6e505b9SAlexander Graf }
147e6e505b9SAlexander Graf #endif
148e6e505b9SAlexander Graf
clock_set_pll3(unsigned int clk)149e6e505b9SAlexander Graf void clock_set_pll3(unsigned int clk)
150e6e505b9SAlexander Graf {
151e6e505b9SAlexander Graf struct sunxi_ccm_reg * const ccm =
152e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
153e6e505b9SAlexander Graf const int m = 8; /* 3 MHz steps just like sun4i, sun5i and sun7i */
154e6e505b9SAlexander Graf
155e6e505b9SAlexander Graf if (clk == 0) {
156e6e505b9SAlexander Graf clrbits_le32(&ccm->pll3_cfg, CCM_PLL3_CTRL_EN);
157e6e505b9SAlexander Graf return;
158e6e505b9SAlexander Graf }
159e6e505b9SAlexander Graf
160e6e505b9SAlexander Graf /* PLL3 rate = 24000000 * n / m */
161e6e505b9SAlexander Graf writel(CCM_PLL3_CTRL_EN | CCM_PLL3_CTRL_INTEGER_MODE |
162e6e505b9SAlexander Graf CCM_PLL3_CTRL_N(clk / (24000000 / m)) | CCM_PLL3_CTRL_M(m),
163e6e505b9SAlexander Graf &ccm->pll3_cfg);
164e6e505b9SAlexander Graf }
165e6e505b9SAlexander Graf
1661ae5def6SJernej Skrabec #ifdef CONFIG_SUNXI_DE2
clock_set_pll3_factors(int m,int n)1671ae5def6SJernej Skrabec void clock_set_pll3_factors(int m, int n)
1681ae5def6SJernej Skrabec {
1691ae5def6SJernej Skrabec struct sunxi_ccm_reg * const ccm =
1701ae5def6SJernej Skrabec (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1711ae5def6SJernej Skrabec
1721ae5def6SJernej Skrabec /* PLL3 rate = 24000000 * n / m */
1731ae5def6SJernej Skrabec writel(CCM_PLL3_CTRL_EN | CCM_PLL3_CTRL_INTEGER_MODE |
1741ae5def6SJernej Skrabec CCM_PLL3_CTRL_N(n) | CCM_PLL3_CTRL_M(m),
1751ae5def6SJernej Skrabec &ccm->pll3_cfg);
1761ae5def6SJernej Skrabec
1771ae5def6SJernej Skrabec while (!(readl(&ccm->pll3_cfg) & CCM_PLL3_CTRL_LOCK))
1781ae5def6SJernej Skrabec ;
1791ae5def6SJernej Skrabec }
1801ae5def6SJernej Skrabec #endif
1811ae5def6SJernej Skrabec
clock_set_pll5(unsigned int clk,bool sigma_delta_enable)182e6e505b9SAlexander Graf void clock_set_pll5(unsigned int clk, bool sigma_delta_enable)
183e6e505b9SAlexander Graf {
184e6e505b9SAlexander Graf struct sunxi_ccm_reg * const ccm =
185e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
186e6e505b9SAlexander Graf const int max_n = 32;
187e6e505b9SAlexander Graf int k = 1, m = 2;
188e6e505b9SAlexander Graf
1897b82a229SAndre Przywara #ifdef CONFIG_MACH_SUNXI_H3_H5
190d5ac6eefSJens Kuske clrsetbits_le32(&ccm->pll5_tuning_cfg, CCM_PLL5_TUN_LOCK_TIME_MASK |
191d5ac6eefSJens Kuske CCM_PLL5_TUN_INIT_FREQ_MASK,
192d5ac6eefSJens Kuske CCM_PLL5_TUN_LOCK_TIME(2) | CCM_PLL5_TUN_INIT_FREQ(16));
193d5ac6eefSJens Kuske #endif
194d5ac6eefSJens Kuske
195e6e505b9SAlexander Graf if (sigma_delta_enable)
196e6e505b9SAlexander Graf writel(CCM_PLL5_PATTERN, &ccm->pll5_pattern_cfg);
197e6e505b9SAlexander Graf
198e6e505b9SAlexander Graf /* PLL5 rate = 24000000 * n * k / m */
199e6e505b9SAlexander Graf if (clk > 24000000 * k * max_n / m) {
200e6e505b9SAlexander Graf m = 1;
201e6e505b9SAlexander Graf if (clk > 24000000 * k * max_n / m)
202e6e505b9SAlexander Graf k = 2;
203e6e505b9SAlexander Graf }
204e6e505b9SAlexander Graf writel(CCM_PLL5_CTRL_EN |
205e6e505b9SAlexander Graf (sigma_delta_enable ? CCM_PLL5_CTRL_SIGMA_DELTA_EN : 0) |
206e6e505b9SAlexander Graf CCM_PLL5_CTRL_UPD |
207e6e505b9SAlexander Graf CCM_PLL5_CTRL_N(clk / (24000000 * k / m)) |
208e6e505b9SAlexander Graf CCM_PLL5_CTRL_K(k) | CCM_PLL5_CTRL_M(m), &ccm->pll5_cfg);
209e6e505b9SAlexander Graf
210e6e505b9SAlexander Graf udelay(5500);
211e6e505b9SAlexander Graf }
212e6e505b9SAlexander Graf
213e6e505b9SAlexander Graf #ifdef CONFIG_MACH_SUN6I
clock_set_mipi_pll(unsigned int clk)214e6e505b9SAlexander Graf void clock_set_mipi_pll(unsigned int clk)
215e6e505b9SAlexander Graf {
216e6e505b9SAlexander Graf struct sunxi_ccm_reg * const ccm =
217e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
218e6e505b9SAlexander Graf unsigned int k, m, n, value, diff;
219e6e505b9SAlexander Graf unsigned best_k = 0, best_m = 0, best_n = 0, best_diff = 0xffffffff;
220e6e505b9SAlexander Graf unsigned int src = clock_get_pll3();
221e6e505b9SAlexander Graf
222e6e505b9SAlexander Graf /* All calculations are in KHz to avoid overflows */
223e6e505b9SAlexander Graf clk /= 1000;
224e6e505b9SAlexander Graf src /= 1000;
225e6e505b9SAlexander Graf
226e6e505b9SAlexander Graf /* Pick the closest lower clock */
227e6e505b9SAlexander Graf for (k = 1; k <= 4; k++) {
228e6e505b9SAlexander Graf for (m = 1; m <= 16; m++) {
229e6e505b9SAlexander Graf for (n = 1; n <= 16; n++) {
230e6e505b9SAlexander Graf value = src * n * k / m;
231e6e505b9SAlexander Graf if (value > clk)
232e6e505b9SAlexander Graf continue;
233e6e505b9SAlexander Graf
234e6e505b9SAlexander Graf diff = clk - value;
235e6e505b9SAlexander Graf if (diff < best_diff) {
236e6e505b9SAlexander Graf best_diff = diff;
237e6e505b9SAlexander Graf best_k = k;
238e6e505b9SAlexander Graf best_m = m;
239e6e505b9SAlexander Graf best_n = n;
240e6e505b9SAlexander Graf }
241e6e505b9SAlexander Graf if (diff == 0)
242e6e505b9SAlexander Graf goto done;
243e6e505b9SAlexander Graf }
244e6e505b9SAlexander Graf }
245e6e505b9SAlexander Graf }
246e6e505b9SAlexander Graf
247e6e505b9SAlexander Graf done:
248e6e505b9SAlexander Graf writel(CCM_MIPI_PLL_CTRL_EN | CCM_MIPI_PLL_CTRL_LDO_EN |
249e6e505b9SAlexander Graf CCM_MIPI_PLL_CTRL_N(best_n) | CCM_MIPI_PLL_CTRL_K(best_k) |
250e6e505b9SAlexander Graf CCM_MIPI_PLL_CTRL_M(best_m), &ccm->mipi_pll_cfg);
251e6e505b9SAlexander Graf }
252e6e505b9SAlexander Graf #endif
253e6e505b9SAlexander Graf
2541ae5def6SJernej Skrabec #ifdef CONFIG_SUNXI_DE2
clock_set_pll10(unsigned int clk)2551ae5def6SJernej Skrabec void clock_set_pll10(unsigned int clk)
2561ae5def6SJernej Skrabec {
2571ae5def6SJernej Skrabec struct sunxi_ccm_reg * const ccm =
2581ae5def6SJernej Skrabec (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
2591ae5def6SJernej Skrabec const int m = 2; /* 12 MHz steps */
2601ae5def6SJernej Skrabec
2611ae5def6SJernej Skrabec if (clk == 0) {
2621ae5def6SJernej Skrabec clrbits_le32(&ccm->pll10_cfg, CCM_PLL10_CTRL_EN);
2631ae5def6SJernej Skrabec return;
2641ae5def6SJernej Skrabec }
2651ae5def6SJernej Skrabec
2661ae5def6SJernej Skrabec /* PLL10 rate = 24000000 * n / m */
2671ae5def6SJernej Skrabec writel(CCM_PLL10_CTRL_EN | CCM_PLL10_CTRL_INTEGER_MODE |
2681ae5def6SJernej Skrabec CCM_PLL10_CTRL_N(clk / (24000000 / m)) | CCM_PLL10_CTRL_M(m),
2691ae5def6SJernej Skrabec &ccm->pll10_cfg);
2701ae5def6SJernej Skrabec
2711ae5def6SJernej Skrabec while (!(readl(&ccm->pll10_cfg) & CCM_PLL10_CTRL_LOCK))
2721ae5def6SJernej Skrabec ;
2731ae5def6SJernej Skrabec }
2741ae5def6SJernej Skrabec #endif
2751ae5def6SJernej Skrabec
2768201188cSChen-Yu Tsai #if defined(CONFIG_MACH_SUN8I_A33) || \
2778201188cSChen-Yu Tsai defined(CONFIG_MACH_SUN8I_R40) || \
2788201188cSChen-Yu Tsai defined(CONFIG_MACH_SUN50I)
clock_set_pll11(unsigned int clk,bool sigma_delta_enable)279e6e505b9SAlexander Graf void clock_set_pll11(unsigned int clk, bool sigma_delta_enable)
280e6e505b9SAlexander Graf {
281e6e505b9SAlexander Graf struct sunxi_ccm_reg * const ccm =
282e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
283e6e505b9SAlexander Graf
284e6e505b9SAlexander Graf if (sigma_delta_enable)
285b5561590SPhilipp Tomsich writel(CCM_PLL11_PATTERN, &ccm->pll11_pattern_cfg0);
286e6e505b9SAlexander Graf
287e6e505b9SAlexander Graf writel(CCM_PLL11_CTRL_EN | CCM_PLL11_CTRL_UPD |
288e6e505b9SAlexander Graf (sigma_delta_enable ? CCM_PLL11_CTRL_SIGMA_DELTA_EN : 0) |
289e6e505b9SAlexander Graf CCM_PLL11_CTRL_N(clk / 24000000), &ccm->pll11_cfg);
290e6e505b9SAlexander Graf
291e6e505b9SAlexander Graf while (readl(&ccm->pll11_cfg) & CCM_PLL11_CTRL_UPD)
292e6e505b9SAlexander Graf ;
293e6e505b9SAlexander Graf }
294e6e505b9SAlexander Graf #endif
295e6e505b9SAlexander Graf
clock_get_pll3(void)296e6e505b9SAlexander Graf unsigned int clock_get_pll3(void)
297e6e505b9SAlexander Graf {
298e6e505b9SAlexander Graf struct sunxi_ccm_reg *const ccm =
299e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
300e6e505b9SAlexander Graf uint32_t rval = readl(&ccm->pll3_cfg);
301e6e505b9SAlexander Graf int n = ((rval & CCM_PLL3_CTRL_N_MASK) >> CCM_PLL3_CTRL_N_SHIFT) + 1;
302e6e505b9SAlexander Graf int m = ((rval & CCM_PLL3_CTRL_M_MASK) >> CCM_PLL3_CTRL_M_SHIFT) + 1;
303e6e505b9SAlexander Graf
304e6e505b9SAlexander Graf /* Multiply by 1000 after dividing by m to avoid integer overflows */
305e6e505b9SAlexander Graf return (24000 * n / m) * 1000;
306e6e505b9SAlexander Graf }
307e6e505b9SAlexander Graf
clock_get_pll6(void)308e6e505b9SAlexander Graf unsigned int clock_get_pll6(void)
309e6e505b9SAlexander Graf {
310e6e505b9SAlexander Graf struct sunxi_ccm_reg *const ccm =
311e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
312e6e505b9SAlexander Graf uint32_t rval = readl(&ccm->pll6_cfg);
313e6e505b9SAlexander Graf int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1;
314e6e505b9SAlexander Graf int k = ((rval & CCM_PLL6_CTRL_K_MASK) >> CCM_PLL6_CTRL_K_SHIFT) + 1;
315e6e505b9SAlexander Graf return 24000000 * n * k / 2;
316e6e505b9SAlexander Graf }
317e6e505b9SAlexander Graf
clock_get_mipi_pll(void)318e6e505b9SAlexander Graf unsigned int clock_get_mipi_pll(void)
319e6e505b9SAlexander Graf {
320e6e505b9SAlexander Graf struct sunxi_ccm_reg *const ccm =
321e6e505b9SAlexander Graf (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
322e6e505b9SAlexander Graf uint32_t rval = readl(&ccm->mipi_pll_cfg);
323e6e505b9SAlexander Graf unsigned int n = ((rval & CCM_MIPI_PLL_CTRL_N_MASK) >> CCM_MIPI_PLL_CTRL_N_SHIFT) + 1;
324e6e505b9SAlexander Graf unsigned int k = ((rval & CCM_MIPI_PLL_CTRL_K_MASK) >> CCM_MIPI_PLL_CTRL_K_SHIFT) + 1;
325e6e505b9SAlexander Graf unsigned int m = ((rval & CCM_MIPI_PLL_CTRL_M_MASK) >> CCM_MIPI_PLL_CTRL_M_SHIFT) + 1;
326e6e505b9SAlexander Graf unsigned int src = clock_get_pll3();
327e6e505b9SAlexander Graf
328e6e505b9SAlexander Graf /* Multiply by 1000 after dividing by m to avoid integer overflows */
329e6e505b9SAlexander Graf return ((src / 1000) * n * k / m) * 1000;
330e6e505b9SAlexander Graf }
331e6e505b9SAlexander Graf
clock_set_de_mod_clock(u32 * clk_cfg,unsigned int hz)332e6e505b9SAlexander Graf void clock_set_de_mod_clock(u32 *clk_cfg, unsigned int hz)
333e6e505b9SAlexander Graf {
334e6e505b9SAlexander Graf int pll = clock_get_pll6() * 2;
335e6e505b9SAlexander Graf int div = 1;
336e6e505b9SAlexander Graf
337e6e505b9SAlexander Graf while ((pll / div) > hz)
338e6e505b9SAlexander Graf div++;
339e6e505b9SAlexander Graf
340e6e505b9SAlexander Graf writel(CCM_DE_CTRL_GATE | CCM_DE_CTRL_PLL6_2X | CCM_DE_CTRL_M(div),
341e6e505b9SAlexander Graf clk_cfg);
342e6e505b9SAlexander Graf }
343