1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "pico/stdlib.h"
8 #include "hardware/pll.h"
9 #include "hardware/clocks.h"
10 #if LIB_PICO_STDIO_UART
11 #include "pico/stdio_uart.h"
12 #else
13 #include "pico/binary_info.h"
14 #endif
15 
16 // everything running off the USB oscillator
set_sys_clock_48mhz()17 void set_sys_clock_48mhz() {
18     if (!running_on_fpga()) {
19         // Change clk_sys to be 48MHz. The simplest way is to take this from PLL_USB
20         // which has a source frequency of 48MHz
21         clock_configure(clk_sys,
22                         CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
23                         CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
24                         48 * MHZ,
25                         48 * MHZ);
26 
27         // Turn off PLL sys for good measure
28         pll_deinit(pll_sys);
29 
30         // CLK peri is clocked from clk_sys so need to change clk_peri's freq
31         clock_configure(clk_peri,
32                         0,
33                         CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
34                         48 * MHZ,
35                         48 * MHZ);
36     }
37 }
38 
set_sys_clock_pll(uint32_t vco_freq,uint post_div1,uint post_div2)39 void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2) {
40     if (!running_on_fpga()) {
41         clock_configure(clk_sys,
42                         CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
43                         CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
44                         48 * MHZ,
45                         48 * MHZ);
46 
47         pll_init(pll_sys, 1, vco_freq, post_div1, post_div2);
48         uint32_t freq = vco_freq / (post_div1 * post_div2);
49 
50         // Configure clocks
51         // CLK_REF = XOSC (12MHz) / 1 = 12MHz
52         clock_configure(clk_ref,
53                         CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC,
54                         0, // No aux mux
55                         12 * MHZ,
56                         12 * MHZ);
57 
58         // CLK SYS = PLL SYS (125MHz) / 1 = 125MHz
59         clock_configure(clk_sys,
60                         CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
61                         CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
62                         freq, freq);
63 
64         clock_configure(clk_peri,
65                         0, // Only AUX mux on ADC
66                         CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
67                         48 * MHZ,
68                         48 * MHZ);
69     }
70 }
71 
check_sys_clock_khz(uint32_t freq_khz,uint * vco_out,uint * postdiv1_out,uint * postdiv_out)72 bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_out, uint *postdiv1_out, uint *postdiv_out) {
73     uint crystal_freq_khz = clock_get_hz(clk_ref) / 1000;
74     for (uint fbdiv = 320; fbdiv >= 16; fbdiv--) {
75         uint vco = fbdiv * crystal_freq_khz;
76         if (vco < PICO_PLL_VCO_MIN_FREQ_MHZ * 1000  || vco > PICO_PLL_VCO_MAX_FREQ_MHZ * 1000) continue;
77         for (uint postdiv1 = 7; postdiv1 >= 1; postdiv1--) {
78             for (uint postdiv2 = postdiv1; postdiv2 >= 1; postdiv2--) {
79                 uint out = vco / (postdiv1 * postdiv2);
80                 if (out == freq_khz && !(vco % (postdiv1 * postdiv2))) {
81                     *vco_out = vco * 1000;
82                     *postdiv1_out = postdiv1;
83                     *postdiv_out = postdiv2;
84                     return true;
85                 }
86             }
87         }
88     }
89     return false;
90 }
91 
setup_default_uart()92 void setup_default_uart() {
93 #if LIB_PICO_STDIO_UART
94     stdio_uart_init();
95 #elif defined(PICO_DEFAULT_UART_BAUD_RATE) && defined(PICO_DEFAULT_UART_TX_PIN) && defined(PICO_DEFAULT_UART_RX_PIN)
96     // this is mostly for backwards compatibility - stdio_uart_init is a bit more nuanced, and usually likely to be present
97     uart_init(uart_default, PICO_DEFAULT_UART_BAUD_RATE);
98     if (PICO_DEFAULT_UART_TX_PIN >= 0)
99         gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
100     if (PICO_DEFAULT_UART_RX_PIN >= 0)
101         gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
102     bi_decl_if_func_used(bi_2pins_with_func(PICO_DEFAULT_UART_RX_PIN, PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART));
103 #endif
104 }
105