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                         USB_CLK_KHZ * KHZ,
25                         USB_CLK_KHZ * KHZ);
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                         USB_CLK_KHZ * KHZ,
35                         USB_CLK_KHZ * KHZ);
36     }
37 }
38 
39 // PICO_CONFIG: PICO_CLOCK_AJDUST_PERI_CLOCK_WITH_SYS_CLOCK, When the SYS clock PLL is changed keep the peripheral clock attached to it, type=bool, default=0, advanced=true, group=hardware_clocks
40 #ifndef PICO_CLOCK_AJDUST_PERI_CLOCK_WITH_SYS_CLOCK
41 // By default, when reconfiguring the system clock PLL settings after runtime initialization,
42 // the peripheral clock is switched to the 48MHz USB clock to ensure continuity of peripheral operation.
43 // Setting this value to 1 changes the behavior to have the peripheral clock re-configured
44 // to the system clock at it's new frequency.
45 #define PICO_CLOCK_AJDUST_PERI_CLOCK_WITH_SYS_CLOCK 0
46 #endif
47 
set_sys_clock_pll(uint32_t vco_freq,uint post_div1,uint post_div2)48 void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2) {
49     if (!running_on_fpga()) {
50         clock_configure(clk_sys,
51                         CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
52                         CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
53                         USB_CLK_KHZ * KHZ,
54                         USB_CLK_KHZ * KHZ);
55 
56         pll_init(pll_sys, PLL_COMMON_REFDIV, vco_freq, post_div1, post_div2);
57         uint32_t freq = vco_freq / (post_div1 * post_div2);
58 
59         // Configure clocks
60         // CLK_REF is the XOSC source
61         clock_configure(clk_ref,
62                         CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC,
63                         0, // No aux mux
64                         XOSC_KHZ * KHZ,
65                         XOSC_KHZ * KHZ);
66 
67         // CLK SYS = PLL SYS (usually) 125MHz / 1 = 125MHz
68         clock_configure(clk_sys,
69                         CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
70                         CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
71                         freq, freq);
72 
73 #if PICO_CLOCK_AJDUST_PERI_CLOCK_WITH_SYS_CLOCK
74         clock_configure(clk_peri,
75                         0,
76                         CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
77                         freq, freq);
78 #else
79         clock_configure(clk_peri,
80                         0, // Only AUX mux on ADC
81                         CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
82                         USB_CLK_KHZ * KHZ,
83                         USB_CLK_KHZ * KHZ);
84 #endif
85     }
86 }
87 
check_sys_clock_khz(uint32_t freq_khz,uint * vco_out,uint * postdiv1_out,uint * postdiv2_out)88 bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_out, uint *postdiv1_out, uint *postdiv2_out) {
89     uint reference_freq_khz = XOSC_KHZ / PLL_COMMON_REFDIV;
90     for (uint fbdiv = 320; fbdiv >= 16; fbdiv--) {
91         uint vco_khz = fbdiv * reference_freq_khz;
92         if (vco_khz < PICO_PLL_VCO_MIN_FREQ_KHZ  || vco_khz > PICO_PLL_VCO_MAX_FREQ_KHZ) continue;
93         for (uint postdiv1 = 7; postdiv1 >= 1; postdiv1--) {
94             for (uint postdiv2 = postdiv1; postdiv2 >= 1; postdiv2--) {
95                 uint out = vco_khz / (postdiv1 * postdiv2);
96                 if (out == freq_khz && !(vco_khz % (postdiv1 * postdiv2))) {
97                     *vco_out = vco_khz * KHZ;
98                     *postdiv1_out = postdiv1;
99                     *postdiv2_out = postdiv2;
100                     return true;
101                 }
102             }
103         }
104     }
105     return false;
106 }
107 
setup_default_uart()108 void setup_default_uart() {
109 #if LIB_PICO_STDIO_UART
110     stdio_uart_init();
111 #elif defined(PICO_DEFAULT_UART_BAUD_RATE) && defined(PICO_DEFAULT_UART_TX_PIN) && defined(PICO_DEFAULT_UART_RX_PIN)
112     // this is mostly for backwards compatibility - stdio_uart_init is a bit more nuanced, and usually likely to be present
113     uart_init(uart_default, PICO_DEFAULT_UART_BAUD_RATE);
114     if (PICO_DEFAULT_UART_TX_PIN >= 0)
115         gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
116     if (PICO_DEFAULT_UART_RX_PIN >= 0)
117         gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
118     bi_decl_if_func_used(bi_2pins_with_func(PICO_DEFAULT_UART_RX_PIN, PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART));
119 #endif
120 }
121