blob: 5f99071f21b5cd69eadfbda93fede7156e5121fd [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Philipp Tomsichd7c0efb2016-10-28 18:21:31 +08002
Hans de Goede29e04f82015-01-14 19:56:33 +01003/*
4 * sun9i specific clock code
5 *
6 * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
7 *
Philipp Tomsichd7c0efb2016-10-28 18:21:31 +08008 * (C) Copyright 2016 Theobroma Systems Design und Consulting GmbH
9 * Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Hans de Goede29e04f82015-01-14 19:56:33 +010010 */
11
Hans de Goede29e04f82015-01-14 19:56:33 +010012#include <asm/io.h>
13#include <asm/arch/clock.h>
14#include <asm/arch/prcm.h>
15#include <asm/arch/sys_proto.h>
16
Simon Glass85ed77d2024-09-29 19:49:46 -060017#ifdef CONFIG_XPL_BUILD
Philipp Tomsichd7c0efb2016-10-28 18:21:31 +080018
Andre Przywara21e279e2023-12-07 15:43:21 +000019static void clock_set_pll2(unsigned int clk)
20{
21 struct sunxi_ccm_reg * const ccm =
22 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
23 const int p = 0;
24
25 /* Switch cluster 1 to 24MHz clock while changing PLL2 */
26 clrsetbits_le32(&ccm->cpu_clk_source, C1_CPUX_CLK_SRC_MASK,
27 C1_CPUX_CLK_SRC_OSC24M);
28
29 writel(CCM_PLL2_CTRL_EN | CCM_PLL2_CTRL_P(p) |
30 CCM_PLL2_CLOCK_TIME_2 | CCM_PLL2_CTRL_N(clk / 24000000),
31 &ccm->pll2_c1_cfg);
32
33 sdelay(2000);
34
35 /* Switch cluster 1 back to PLL2 */
36 clrsetbits_le32(&ccm->cpu_clk_source, C1_CPUX_CLK_SRC_MASK,
37 C1_CPUX_CLK_SRC_PLL2);
38}
39
40static void clock_set_pll4(unsigned int clk)
41{
42 struct sunxi_ccm_reg * const ccm =
43 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
44
45 writel(CCM_PLL4_CTRL_EN | CCM_PLL4_CTRL_N(clk / 24000000),
46 &ccm->pll4_periph0_cfg);
47
48 sdelay(2000);
49}
50
51static void clock_set_pll12(unsigned int clk)
52{
53 struct sunxi_ccm_reg * const ccm =
54 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
55
56 if (readl(&ccm->pll12_periph1_cfg) & CCM_PLL12_CTRL_EN)
57 return;
58
59 writel(CCM_PLL12_CTRL_EN | CCM_PLL12_CTRL_N(clk / 24000000),
60 &ccm->pll12_periph1_cfg);
61
62 sdelay(2000);
63}
64
Philipp Tomsichd7c0efb2016-10-28 18:21:31 +080065void clock_init_safe(void)
66{
67 struct sunxi_ccm_reg * const ccm =
68 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
69
70 /* Set up PLL12 (peripheral 1) */
71 clock_set_pll12(1200000000);
72
73 /* Set up PLL1 (cluster 0) and PLL2 (cluster 1) */
74 clock_set_pll1(408000000);
75 clock_set_pll2(408000000);
76
77 /* Set up PLL4 (peripheral 0) */
78 clock_set_pll4(960000000);
79
80 /* Set up dividers for AXI0 and APB0 on cluster 0: PLL1 / 2 = 204MHz */
81 writel(C0_CFG_AXI0_CLK_DIV_RATIO(2) |
82 C0_CFG_APB0_CLK_DIV_RATIO(2), &ccm->c0_cfg);
83
84 /* AHB0: 120 MHz (PLL_PERIPH0 / 8) */
85 writel(AHBx_SRC_PLL_PERIPH0 | AHBx_CLK_DIV_RATIO(8),
86 &ccm->ahb0_cfg);
87 /* AHB1: 240 MHz (PLL_PERIPH0 / 4) */
88 writel(AHBx_SRC_PLL_PERIPH0 | AHBx_CLK_DIV_RATIO(4),
89 &ccm->ahb1_cfg);
90 /* AHB2: 120 MHz (PLL_PERIPH0 / 8) */
91 writel(AHBx_SRC_PLL_PERIPH0 | AHBx_CLK_DIV_RATIO(8),
92 &ccm->ahb2_cfg);
93 /* APB0: 120 MHz (PLL_PERIPH0 / 8) */
94 writel(APB0_SRC_PLL_PERIPH0 | APB0_CLK_DIV_RATIO(8),
95 &ccm->apb0_cfg);
96
97 /* GTBUS: 400MHz (PERIPH0 div 3) */
98 writel(GTBUS_SRC_PLL_PERIPH1 | GTBUS_CLK_DIV_RATIO(3),
99 &ccm->gtbus_cfg);
100 /* CCI400: 480MHz (PERIPH1 div 2) */
101 writel(CCI400_SRC_PLL_PERIPH0 | CCI400_CLK_DIV_RATIO(2),
102 &ccm->cci400_cfg);
103
104 /* Deassert DMA reset and open clock gating for DMA */
105 setbits_le32(&ccm->ahb_reset1_cfg, (1 << 24));
106 setbits_le32(&ccm->apb1_gate, (1 << 24));
107
108 /* set enable-bit in TSTAMP_CTRL_REG */
109 writel(1, 0x01720000);
110}
Philipp Tomsichd7c0efb2016-10-28 18:21:31 +0800111
Hans de Goede29e04f82015-01-14 19:56:33 +0100112void clock_init_uart(void)
113{
114 struct sunxi_ccm_reg *const ccm =
115 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
116
117 /* open the clock for uart */
118 setbits_le32(&ccm->apb1_gate,
119 CLK_GATE_OPEN << (APB1_GATE_UART_SHIFT +
120 CONFIG_CONS_INDEX - 1));
121 /* deassert uart reset */
122 setbits_le32(&ccm->apb1_reset_cfg,
123 1 << (APB1_RESET_UART_SHIFT +
124 CONFIG_CONS_INDEX - 1));
Philipp Tomsichd7c0efb2016-10-28 18:21:31 +0800125}
126
Philipp Tomsichd7c0efb2016-10-28 18:21:31 +0800127void clock_set_pll1(unsigned int clk)
128{
129 struct sunxi_ccm_reg * const ccm =
130 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
131 const int p = 0;
132
133 /* Switch cluster 0 to 24MHz clock while changing PLL1 */
134 clrsetbits_le32(&ccm->cpu_clk_source, C0_CPUX_CLK_SRC_MASK,
135 C0_CPUX_CLK_SRC_OSC24M);
136
137 writel(CCM_PLL1_CTRL_EN | CCM_PLL1_CTRL_P(p) |
138 CCM_PLL1_CLOCK_TIME_2 |
139 CCM_PLL1_CTRL_N(clk / 24000000),
140 &ccm->pll1_c0_cfg);
141 /*
142 * Don't bother with the stable-time registers, as it doesn't
143 * wait until the PLL is stable. Note, that even Allwinner
144 * just uses a delay loop (or rather the AVS timer) for this
145 * instead of the PLL_STABLE_STATUS register.
146 */
147 sdelay(2000);
148
149 /* Switch cluster 0 back to PLL1 */
150 clrsetbits_le32(&ccm->cpu_clk_source, C0_CPUX_CLK_SRC_MASK,
151 C0_CPUX_CLK_SRC_PLL1);
152}
153
Philipp Tomsichd7c0efb2016-10-28 18:21:31 +0800154void clock_set_pll6(unsigned int clk)
155{
156 struct sunxi_ccm_reg * const ccm =
157 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
158 const int p = 0;
159
160 writel(CCM_PLL6_CTRL_EN | CCM_PLL6_CFG_UPDATE | CCM_PLL6_CTRL_P(p)
161 | CCM_PLL6_CTRL_N(clk / 24000000),
162 &ccm->pll6_ddr_cfg);
163 do { } while (!(readl(&ccm->pll_stable_status) & PLL_DDR_STATUS));
164
165 sdelay(2000);
166}
167
Hans de Goede29e04f82015-01-14 19:56:33 +0100168int clock_twi_onoff(int port, int state)
169{
170 struct sunxi_ccm_reg *const ccm =
171 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
172
173 if (port > 4)
174 return -1;
175
176 /* set the apb reset and clock gate for twi */
177 if (state) {
178 setbits_le32(&ccm->apb1_gate,
179 CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT + port));
180 setbits_le32(&ccm->apb1_reset_cfg,
Hans de Goede47adc3d2016-03-16 20:58:41 +0100181 1 << (APB1_RESET_TWI_SHIFT + port));
Hans de Goede29e04f82015-01-14 19:56:33 +0100182 } else {
183 clrbits_le32(&ccm->apb1_reset_cfg,
Hans de Goede47adc3d2016-03-16 20:58:41 +0100184 1 << (APB1_RESET_TWI_SHIFT + port));
Hans de Goede29e04f82015-01-14 19:56:33 +0100185 clrbits_le32(&ccm->apb1_gate,
186 CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT + port));
187 }
188
189 return 0;
190}
Simon Glass85ed77d2024-09-29 19:49:46 -0600191#endif /* CONFIG_XPL_BUILD */
Hans de Goede29e04f82015-01-14 19:56:33 +0100192
Andre Przywara21e279e2023-12-07 15:43:21 +0000193/* PLL_PERIPH0 clock (used by the MMC driver) */
Hans de Goede29e04f82015-01-14 19:56:33 +0100194unsigned int clock_get_pll4_periph0(void)
195{
196 struct sunxi_ccm_reg *const ccm =
197 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
198 uint32_t rval = readl(&ccm->pll4_periph0_cfg);
199 int n = ((rval & CCM_PLL4_CTRL_N_MASK) >> CCM_PLL4_CTRL_N_SHIFT);
200 int p = ((rval & CCM_PLL4_CTRL_P_MASK) >> CCM_PLL4_CTRL_P_SHIFT);
201 int m = ((rval & CCM_PLL4_CTRL_M_MASK) >> CCM_PLL4_CTRL_M_SHIFT) + 1;
202 const int k = 1;
203
204 return ((24000000 * n * k) >> p) / m;
205}