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