aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-06-30 23:45:07 +0200
committerDario Nieuwenhuis <[email protected]>2021-06-30 23:46:00 +0200
commit5fae5d20c01251f4287986c220a21beeade2f329 (patch)
tree8b28f70be31665deef8fc5fc923d298ef46da277
parent53c236fde8b4b96db855f7bb23255106c0917ff8 (diff)
rp/clocks: don't disrupt PLLs if already running.
This makes it possible to run under https://github.com/majbthrd/pico-debug
-rw-r--r--embassy-rp/Cargo.toml2
-rw-r--r--embassy-rp/src/clocks.rs92
2 files changed, 59 insertions, 35 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 3d435a559..2313c6432 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -22,6 +22,6 @@ cortex-m-rt = "0.6.13"
22cortex-m = "0.7.1" 22cortex-m = "0.7.1"
23critical-section = "0.2.1" 23critical-section = "0.2.1"
24 24
25rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="fbb1004086225c74ff3c02db9309767cebef5dce", features = ["rt"] } 25rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="91fa122b4923fdc02462a39ec109b161aedb29b4", features = ["rt"] }
26#rp2040-pac2 = { path = "../../rp/rp2040-pac2" } 26#rp2040-pac2 = { path = "../../rp/rp2040-pac2" }
27embedded-hal = { version = "0.2.4", features = [ "unproven" ] } 27embedded-hal = { version = "0.2.4", features = [ "unproven" ] }
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index c3ca4cf69..364cf452c 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -5,19 +5,21 @@ use crate::{pac, reset};
5const XOSC_MHZ: u32 = 12; 5const XOSC_MHZ: u32 = 12;
6 6
7pub unsafe fn init() { 7pub unsafe fn init() {
8 // Now reset all the peripherals, except QSPI and XIP (we're using those
9 // to execute from external flash!)
10
11 // Reset everything except: 8 // Reset everything except:
12 // - QSPI (we're using it to run this code!) 9 // - QSPI (we're using it to run this code!)
13 // - PLLs (it may be suicide if that's what's clocking us) 10 // - PLLs (it may be suicide if that's what's clocking us)
11 // - USB, SYSCFG (breaks usb-to-swd on core1)
14 let mut peris = reset::ALL_PERIPHERALS; 12 let mut peris = reset::ALL_PERIPHERALS;
15 peris.set_io_qspi(false); 13 peris.set_io_qspi(false);
16 peris.set_pads_qspi(false); 14 peris.set_pads_qspi(false);
17 peris.set_pll_sys(false); 15 peris.set_pll_sys(false);
18 peris.set_pll_usb(false); 16 peris.set_pll_usb(false);
17 peris.set_usbctrl(false);
18 peris.set_syscfg(false);
19 reset::reset(peris); 19 reset::reset(peris);
20 20
21 // Remove reset from peripherals which are clocked only by clk_sys and
22 // clk_ref. Other peripherals stay in reset until we've configured clocks.
21 let mut peris = reset::ALL_PERIPHERALS; 23 let mut peris = reset::ALL_PERIPHERALS;
22 peris.set_adc(false); 24 peris.set_adc(false);
23 peris.set_rtc(false); 25 peris.set_rtc(false);
@@ -28,31 +30,20 @@ pub unsafe fn init() {
28 peris.set_usbctrl(false); 30 peris.set_usbctrl(false);
29 reset::unreset_wait(peris); 31 reset::unreset_wait(peris);
30 32
33 // Start tick in watchdog
31 // xosc 12 mhz 34 // xosc 12 mhz
32 pac::WATCHDOG.tick().write(|w| { 35 pac::WATCHDOG.tick().write(|w| {
33 w.set_cycles(XOSC_MHZ as u16); 36 w.set_cycles(XOSC_MHZ as u16);
34 w.set_enable(true); 37 w.set_enable(true);
35 }); 38 });
36 39
40 // Disable resus that may be enabled from previous software
37 let c = pac::CLOCKS; 41 let c = pac::CLOCKS;
38 c.clk_sys_resus_ctrl() 42 c.clk_sys_resus_ctrl()
39 .write_value(pac::clocks::regs::ClkSysResusCtrl(0)); 43 .write_value(pac::clocks::regs::ClkSysResusCtrl(0));
40 44
41 // Enable XOSC 45 // start XOSC
42 const XOSC_MHZ: u32 = 12; 46 start_xosc();
43 pac::XOSC
44 .ctrl()
45 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
46
47 let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256;
48 pac::XOSC
49 .startup()
50 .write(|w| w.set_delay(startup_delay as u16));
51 pac::XOSC.ctrl().write(|w| {
52 w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ);
53 w.set_enable(pac::xosc::vals::Enable::ENABLE);
54 });
55 while !pac::XOSC.status().read().stable() {}
56 47
57 // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. 48 // Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
58 c.clk_sys_ctrl() 49 c.clk_sys_ctrl()
@@ -66,13 +57,6 @@ pub unsafe fn init() {
66 // REF FBDIV VCO POSTDIV 57 // REF FBDIV VCO POSTDIV
67 // PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz 58 // PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz
68 // PLL USB: 12 / 1 = 12MHz * 40 = 480 MHz / 5 / 2 = 48MHz 59 // PLL USB: 12 / 1 = 12MHz * 40 = 480 MHz / 5 / 2 = 48MHz
69
70 let mut peris = reset::Peripherals(0);
71 peris.set_pll_sys(true);
72 peris.set_pll_usb(true);
73 reset::reset(peris);
74 reset::unreset_wait(peris);
75
76 configure_pll(pac::PLL_SYS, 1, 1500_000_000, 6, 2); 60 configure_pll(pac::PLL_SYS, 1, 1500_000_000, 6, 2);
77 configure_pll(pac::PLL_USB, 1, 480_000_000, 5, 2); 61 configure_pll(pac::PLL_USB, 1, 480_000_000, 5, 2);
78 62
@@ -125,6 +109,10 @@ pub unsafe fn init() {
125 w.set_enable(true); 109 w.set_enable(true);
126 w.set_auxsrc(ClkPeriCtrlAuxsrc::CLK_SYS); 110 w.set_auxsrc(ClkPeriCtrlAuxsrc::CLK_SYS);
127 }); 111 });
112
113 // Peripheral clocks should now all be running
114 let peris = reset::ALL_PERIPHERALS;
115 reset::unreset_wait(peris);
128} 116}
129 117
130pub(crate) fn clk_sys_freq() -> u32 { 118pub(crate) fn clk_sys_freq() -> u32 {
@@ -139,6 +127,23 @@ pub(crate) fn clk_rtc_freq() -> u32 {
139 46875 127 46875
140} 128}
141 129
130unsafe fn start_xosc() {
131 const XOSC_MHZ: u32 = 12;
132 pac::XOSC
133 .ctrl()
134 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
135
136 let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256;
137 pac::XOSC
138 .startup()
139 .write(|w| w.set_delay(startup_delay as u16));
140 pac::XOSC.ctrl().write(|w| {
141 w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ);
142 w.set_enable(pac::xosc::vals::Enable::ENABLE);
143 });
144 while !pac::XOSC.status().read().stable() {}
145}
146
142unsafe fn configure_pll( 147unsafe fn configure_pll(
143 p: pac::pll::Pll, 148 p: pac::pll::Pll,
144 refdiv: u32, 149 refdiv: u32,
@@ -146,15 +151,6 @@ unsafe fn configure_pll(
146 post_div1: u8, 151 post_div1: u8,
147 post_div2: u8, 152 post_div2: u8,
148) { 153) {
149 // Power off in case it's already running
150 p.pwr().write(|w| {
151 w.set_vcopd(true);
152 w.set_postdivpd(true);
153 w.set_dsmpd(true);
154 w.set_pd(true);
155 });
156 p.fbdiv_int().write(|w| w.set_fbdiv_int(0));
157
158 let ref_freq = XOSC_MHZ * 1_000_000 / refdiv; 154 let ref_freq = XOSC_MHZ * 1_000_000 / refdiv;
159 155
160 let fbdiv = vco_freq / ref_freq; 156 let fbdiv = vco_freq / ref_freq;
@@ -164,20 +160,48 @@ unsafe fn configure_pll(
164 assert!(post_div2 <= post_div1); 160 assert!(post_div2 <= post_div1);
165 assert!(ref_freq <= (vco_freq / 16)); 161 assert!(ref_freq <= (vco_freq / 16));
166 162
163 // do not disrupt PLL that is already correctly configured and operating
164 let cs = p.cs().read();
165 let prim = p.prim().read();
166 if cs.lock()
167 && cs.refdiv() == refdiv as _
168 && p.fbdiv_int().read().fbdiv_int() == fbdiv as _
169 && prim.postdiv1() == post_div1
170 && prim.postdiv2() == post_div2
171 {
172 return;
173 }
174
175 // Reset it
176 let mut peris = reset::Peripherals(0);
177 match p {
178 pac::PLL_SYS => peris.set_pll_sys(true),
179 pac::PLL_USB => peris.set_pll_usb(true),
180 _ => unreachable!(),
181 }
182 reset::reset(peris);
183 reset::unreset_wait(peris);
184
185 // Load VCO-related dividers before starting VCO
167 p.cs().write(|w| w.set_refdiv(refdiv as _)); 186 p.cs().write(|w| w.set_refdiv(refdiv as _));
168 p.fbdiv_int().write(|w| w.set_fbdiv_int(fbdiv as _)); 187 p.fbdiv_int().write(|w| w.set_fbdiv_int(fbdiv as _));
169 188
189 // Turn on PLL
170 p.pwr().modify(|w| { 190 p.pwr().modify(|w| {
171 w.set_pd(false); 191 w.set_pd(false);
172 w.set_vcopd(false); 192 w.set_vcopd(false);
193 w.set_postdivpd(true);
173 }); 194 });
174 195
196 // Wait for PLL to lock
175 while !p.cs().read().lock() {} 197 while !p.cs().read().lock() {}
176 198
199 // Wait for PLL to lock
177 p.prim().write(|w| { 200 p.prim().write(|w| {
178 w.set_postdiv1(post_div1); 201 w.set_postdiv1(post_div1);
179 w.set_postdiv2(post_div2); 202 w.set_postdiv2(post_div2);
180 }); 203 });
181 204
205 // Turn on post divider
182 p.pwr().modify(|w| w.set_postdivpd(false)); 206 p.pwr().modify(|w| w.set_postdivpd(false));
183} 207}