blob: 660f941dea1769f3777e2b08634cbbda65cb2a90 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2014 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <reg.h>
24#include <bits.h>
25#include <stdio.h>
26#include <assert.h>
27#include <trace.h>
28#include <err.h>
29#include <kernel/thread.h>
30#include <platform/debug.h>
31#include <platform/zynq.h>
32#include <target/debugconfig.h>
33#include <reg.h>
34
35#define LOCAL_TRACE 0
36
37static uint32_t get_arm_pll_freq(void)
38{
39 LTRACEF("ARM_PLL_CTRL 0x%x\n", SLCR_REG(ARM_PLL_CTRL));
40
41 // XXX test that the pll is actually enabled
42
43 uint32_t fdiv = BITS_SHIFT(SLCR_REG(ARM_PLL_CTRL), 18, 12);
44
45 return EXTERNAL_CLOCK_FREQ * fdiv;
46}
47
48static uint32_t get_ddr_pll_freq(void)
49{
50 LTRACEF("DDR_PLL_CTRL 0x%x\n", SLCR_REG(DDR_PLL_CTRL));
51
52 // XXX test that the pll is actually enabled
53
54 uint32_t fdiv = BITS_SHIFT(SLCR_REG(DDR_PLL_CTRL), 18, 12);
55
56 return EXTERNAL_CLOCK_FREQ * fdiv;
57}
58
59static uint32_t get_io_pll_freq(void)
60{
61 LTRACEF("IO_PLL_CTRL 0x%x\n", SLCR_REG(IO_PLL_CTRL));
62
63 // XXX test that the pll is actually enabled
64
65 uint32_t fdiv = BITS_SHIFT(SLCR_REG(IO_PLL_CTRL), 18, 12);
66
67 return EXTERNAL_CLOCK_FREQ * fdiv;
68}
69
70static uint32_t get_cpu_input_freq(void)
71{
72 LTRACEF("ARM_CLK_CTRL 0x%x\n", SLCR_REG(ARM_CLK_CTRL));
73
74 uint32_t divisor = BITS_SHIFT(SLCR_REG(ARM_CLK_CTRL), 13, 8);
75 uint32_t srcsel = BITS_SHIFT(SLCR_REG(ARM_CLK_CTRL), 5, 4);
76
77 uint32_t srcclk;
78 switch (srcsel) {
79 default: case 0: case 1: // arm pll
80 srcclk = get_arm_pll_freq();
81 break;
82 case 2: // ddr pll
83 srcclk = get_ddr_pll_freq();
84 break;
85 case 3: // io pll
86 srcclk = get_io_pll_freq();
87 break;
88 }
89
90 // cpu 6x4x
91 return srcclk / divisor;
92}
93
94static uint32_t get_cpu_6x4x_freq(void)
95{
96 // cpu 6x4x is the post divided frequency in the cpu clock block
97 return get_cpu_input_freq();
98}
99
100static uint32_t get_cpu_3x2x_freq(void)
101{
102 // cpu 3x2x is always half the speed of 6x4x
103 return get_cpu_input_freq() / 2;
104}
105
106static uint32_t get_cpu_2x_freq(void)
107{
108 // cpu 2x is either /3 or /2 the speed of 6x4x
109 return get_cpu_input_freq() / ((SLCR_REG(CLK_621_TRUE) & 1) ? 3 : 2);
110}
111
112static uint32_t get_cpu_1x_freq(void)
113{
114 // cpu 1x is either /6 or /4 the speed of 6x4x
115 return get_cpu_input_freq() / ((SLCR_REG(CLK_621_TRUE) & 1) ? 6 : 4);
116}
117
118uint32_t zynq_get_arm_freq(void)
119{
120 return get_cpu_6x4x_freq();
121}
122
123uint32_t zynq_get_arm_timer_freq(void)
124{
125 return get_cpu_3x2x_freq();
126}
127
128uint32_t zynq_get_swdt_freq(void)
129{
130 return get_cpu_1x_freq();
131}
132
133struct periph_clock {
134 addr_t clk_ctrl_reg;
135 uint enable_bit_pos;
136};
137
138static addr_t periph_clk_ctrl_reg(enum zynq_periph periph)
139{
140 DEBUG_ASSERT(periph < _PERIPH_MAX);
141
142 switch (periph) {
143 case PERIPH_USB0: return (uintptr_t)&SLCR->USB0_CLK_CTRL;
144 case PERIPH_USB1: return (uintptr_t)&SLCR->USB1_CLK_CTRL;
145 case PERIPH_GEM0: return (uintptr_t)&SLCR->GEM0_CLK_CTRL;
146 case PERIPH_GEM1: return (uintptr_t)&SLCR->GEM1_CLK_CTRL;
147 case PERIPH_SMC: return (uintptr_t)&SLCR->SMC_CLK_CTRL;
148 case PERIPH_LQSPI: return (uintptr_t)&SLCR->LQSPI_CLK_CTRL;
149 case PERIPH_SDIO0: return (uintptr_t)&SLCR->SDIO_CLK_CTRL;
150 case PERIPH_SDIO1: return (uintptr_t)&SLCR->SDIO_CLK_CTRL;
151 case PERIPH_UART0: return (uintptr_t)&SLCR->UART_CLK_CTRL;
152 case PERIPH_UART1: return (uintptr_t)&SLCR->UART_CLK_CTRL;
153 case PERIPH_SPI0: return (uintptr_t)&SLCR->SPI_CLK_CTRL;
154 case PERIPH_SPI1: return (uintptr_t)&SLCR->SPI_CLK_CTRL;
155 case PERIPH_CAN0: return (uintptr_t)&SLCR->CAN_CLK_CTRL;
156 case PERIPH_CAN1: return (uintptr_t)&SLCR->CAN_CLK_CTRL;
157 case PERIPH_DBG: return (uintptr_t)&SLCR->DBG_CLK_CTRL;
158 case PERIPH_PCAP: return (uintptr_t)&SLCR->PCAP_CLK_CTRL;
159 case PERIPH_FPGA0: return (uintptr_t)&SLCR->FPGA0_CLK_CTRL;
160 case PERIPH_FPGA1: return (uintptr_t)&SLCR->FPGA1_CLK_CTRL;
161 case PERIPH_FPGA2: return (uintptr_t)&SLCR->FPGA2_CLK_CTRL;
162 case PERIPH_FPGA3: return (uintptr_t)&SLCR->FPGA3_CLK_CTRL;
163 default: return 0;
164 }
165}
166
167static int periph_clk_ctrl_enable_bitpos(enum zynq_periph periph)
168{
169 switch (periph) {
170 case PERIPH_SDIO1:
171 case PERIPH_UART1:
172 case PERIPH_SPI1:
173 case PERIPH_CAN1:
174 return 1;
175 case PERIPH_FPGA0:
176 case PERIPH_FPGA1:
177 case PERIPH_FPGA2:
178 case PERIPH_FPGA3:
179 return -1; // enable bit is more complicated on fpga
180 default:
181 // most peripherals have the enable bit in bit0
182 return 0;
183 }
184}
185
186static uint periph_clk_ctrl_divisor_count(enum zynq_periph periph)
187{
188 switch (periph) {
189 case PERIPH_GEM0:
190 case PERIPH_GEM1:
191 case PERIPH_CAN0:
192 case PERIPH_CAN1:
193 case PERIPH_FPGA0:
194 case PERIPH_FPGA1:
195 case PERIPH_FPGA2:
196 case PERIPH_FPGA3:
197 return 2;
198 default:
199 // most peripherals have a single divisor
200 return 1;
201 }
202}
203
204static const char *periph_to_name(enum zynq_periph periph)
205{
206 switch (periph) {
207 case PERIPH_USB0: return "USB0";
208 case PERIPH_USB1: return "USB1";
209 case PERIPH_GEM0: return "GEM0";
210 case PERIPH_GEM1: return "GEM1";
211 case PERIPH_SMC: return "SMC";
212 case PERIPH_LQSPI: return "LQSPI";
213 case PERIPH_SDIO0: return "SDIO0";
214 case PERIPH_SDIO1: return "SDIO1";
215 case PERIPH_UART0: return "UART0";
216 case PERIPH_UART1: return "UART1";
217 case PERIPH_SPI0: return "SPI0";
218 case PERIPH_SPI1: return "SPI1";
219 case PERIPH_CAN0: return "CAN0";
220 case PERIPH_CAN1: return "CAN1";
221 case PERIPH_DBG: return "DBG";
222 case PERIPH_PCAP: return "PCAP";
223 case PERIPH_FPGA0: return "FPGA0";
224 case PERIPH_FPGA1: return "FPGA1";
225 case PERIPH_FPGA2: return "FPGA2";
226 case PERIPH_FPGA3: return "FPGA3";
227 default: return "unknown";
228 }
229}
230
231status_t zynq_set_clock(enum zynq_periph periph, bool enable, enum zynq_clock_source source, uint32_t divisor, uint32_t divisor2)
232{
233 DEBUG_ASSERT(periph < _PERIPH_MAX);
234 DEBUG_ASSERT(!enable || (divisor > 0 && divisor <= 0x3f));
235 DEBUG_ASSERT(source < 4);
236
237 // get the clock control register base
238 addr_t clk_reg = periph_clk_ctrl_reg(periph);
239 DEBUG_ASSERT(clk_reg != 0);
240
241 int enable_bitpos = periph_clk_ctrl_enable_bitpos(periph);
242
243 zynq_slcr_unlock();
244
245 // if we're enabling
246 if (enable) {
247 uint32_t ctrl = *REG32(clk_reg);
248
249 // set the divisor, divisor2 (if applicable), source, and enable
250 ctrl = (ctrl & ~(0x3f << 20)) | (divisor2 << 20);
251 ctrl = (ctrl & ~(0x3f << 8)) | (divisor << 8);
252 ctrl = (ctrl & ~(0x3 << 4)) | (source << 4);
253
254 if (enable_bitpos >= 0)
255 ctrl |= (1 << enable_bitpos);
256
257 *REG32(clk_reg) = ctrl;
258 } else {
259 if (enable_bitpos >= 0) {
260 // disabling
261 uint32_t ctrl = *REG32(clk_reg);
262
263 ctrl &= ~(1 << enable_bitpos);
264
265 *REG32(clk_reg) = ctrl;
266 }
267 }
268
269 zynq_slcr_lock();
270
271 return NO_ERROR;
272}
273
274uint32_t zynq_get_clock(enum zynq_periph periph)
275{
276 DEBUG_ASSERT(periph < _PERIPH_MAX);
277
278 // get the clock control register base
279 addr_t clk_reg = periph_clk_ctrl_reg(periph);
280 DEBUG_ASSERT(clk_reg != 0);
281
282 int enable_bitpos = periph_clk_ctrl_enable_bitpos(periph);
283
284 LTRACEF("clkreg 0x%x\n", *REG32(clk_reg));
285
286 // see if it's enabled
287 if (enable_bitpos >= 0) {
288 if ((*REG32(clk_reg) & (1 << enable_bitpos)) == 0) {
289 // not enabled
290 return 0;
291 }
292 }
293
294 // get the source clock
295 uint32_t srcclk;
296 switch (BITS_SHIFT(*REG32(clk_reg), 5, 4)) {
297 case 0: case 1:
298 srcclk = get_io_pll_freq();
299 break;
300 case 2:
301 srcclk = get_arm_pll_freq();
302 break;
303 case 3:
304 srcclk = get_ddr_pll_freq();
305 break;
306 }
307
308 // get the divisor out of the register
309 uint32_t divisor = BITS_SHIFT(*REG32(clk_reg), 13, 8);
310 if (divisor == 0)
311 return 0;
312
313 uint32_t divisor2 = 1;
314 if (periph_clk_ctrl_divisor_count(periph) == 2) {
315 divisor2 = BITS_SHIFT(*REG32(clk_reg), 25, 20);
316 if (divisor2 == 0)
317 return 0;
318 }
319
320 uint32_t clk = srcclk / divisor / divisor2;
321
322 return clk;
323}
324
325void zynq_dump_clocks(void)
326{
327 printf("zynq clocks:\n");
328 printf("\tarm pll %d\n", get_arm_pll_freq());
329 printf("\tddr pll %d\n", get_ddr_pll_freq());
330 printf("\tio pll %d\n", get_io_pll_freq());
331
332 printf("\tarm clock %d\n", zynq_get_arm_freq());
333 printf("\tarm timer clock %d\n", zynq_get_arm_timer_freq());
334 printf("\tcpu6x4x clock %d\n", get_cpu_6x4x_freq());
335 printf("\tcpu3x2x clock %d\n", get_cpu_3x2x_freq());
336 printf("\tcpu2x clock %d\n", get_cpu_2x_freq());
337 printf("\tcpu1x clock %d\n", get_cpu_1x_freq());
338
339 printf("peripheral clocks:\n");
340 for (uint i = 0; i < _PERIPH_MAX; i++) {
341 printf("\tperiph %d (%s) clock %u\n", i, periph_to_name(i), zynq_get_clock(i));
342 }
343}
344