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