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