Skip to main content

lpc55_hal/peripherals/
syscon.rs

1//! API for system configuration (SYSCON) - always on
2//!
3//! The entry point to this API is [`SYSCON`]. Please refer to [`SYSCON`]'s
4//! documentation for additional information.
5//!
6//! This module mostly provides infrastructure required by other parts of the
7//! HAL API. For this reason, only a small subset of SYSCON functionality is
8//! currently implemented.
9//!
10//! The SYSCON peripheral is described in the user manual, chapter 4.
11
12// use core::marker::PhantomData;
13
14// use crate::raw::syscon::{
15//     // pdruncfg, presetctrl, starterp1, sysahbclkctrl, PDRUNCFG, PRESETCTRL, STARTERP1, SYSAHBCLKCTRL,
16//     // UARTCLKDIV, UARTFRGDIV, UARTFRGMULT,
17// };
18
19// use cortex_m_semihosting::dbg;
20
21// use crate::raw;
22// use crate::{
23//     time::{
24//         self,
25//         clock,
26//     },
27//     typestates::init_state,
28// };
29
30crate::wrap_always_on_peripheral!(Syscon, SYSCON);
31
32impl Syscon {
33    // TODO: relocate
34    pub fn rev_id(&self) -> u8 {
35        self.raw.dieid.read().rev_id().bits()
36    }
37    pub fn mco_num_in_die_id(&self) -> u32 {
38        self.raw.dieid.read().mco_num_in_die_id().bits()
39    }
40}
41
42/// The main API for the SYSCON peripheral
43impl Syscon {
44    /// Enables the clock for a peripheral or other hardware component
45    pub fn enable_clock<P: ClockControl>(&mut self, peripheral: &mut P) {
46        peripheral.enable_clock(self);
47    }
48
49    /// Disable peripheral clock
50    pub fn disable_clock<P: ClockControl>(&mut self, peripheral: &mut P) {
51        peripheral.disable_clock(self);
52    }
53
54    /// Check if peripheral clock is enabled
55    pub fn is_clock_enabled<P: ClockControl>(&self, peripheral: &P) -> bool {
56        peripheral.is_clock_enabled(self)
57    }
58
59    /// Reset a peripheral
60    pub fn reset<P: ResetControl>(&mut self, peripheral: &mut P) {
61        peripheral.assert_reset(self);
62        peripheral.clear_reset(self);
63    }
64
65    /// Steals syscon and asserts reset to all peripherals that won't immediately cause a crash.
66    /// Flash, Fmc, and AnalogCtrl are not reset.
67    ///
68    /// # Safety
69    ///
70    /// Steals the syscon, must not be called if Syscon is owned
71    pub unsafe fn reset_all_noncritical_peripherals() -> Syscon {
72        let syscon = Syscon::steal().release();
73        syscon.presetctrl0.write(|w| {
74            w
75                // .flash_rst().asserted()  // crash
76                // .fmc_rst().asserted()    // crash
77                .sram_ctrl1_rst()
78                .asserted()
79                .sram_ctrl2_rst()
80                .asserted()
81                .sram_ctrl3_rst()
82                .asserted()
83                .sram_ctrl4_rst()
84                .asserted()
85                .mux_rst()
86                .asserted()
87                .iocon_rst()
88                .asserted()
89                .gpio0_rst()
90                .asserted()
91                .gpio1_rst()
92                .asserted()
93                .pint_rst()
94                .asserted()
95                .gint_rst()
96                .asserted()
97                .dma0_rst()
98                .asserted()
99                .crcgen_rst()
100                .asserted()
101                .wwdt_rst()
102                .asserted()
103                .rtc_rst()
104                .asserted()
105                .mailbox_rst()
106                .asserted()
107                .adc_rst()
108                .asserted()
109        });
110        syscon.presetctrl1.write(|w| {
111            w.mrt_rst()
112                .asserted()
113                .ostimer_rst()
114                .asserted()
115                .sct_rst()
116                .asserted()
117                .utick_rst()
118                .asserted()
119                .fc0_rst()
120                .asserted()
121                .fc1_rst()
122                .asserted()
123                .fc2_rst()
124                .asserted()
125                .fc3_rst()
126                .asserted()
127                .fc4_rst()
128                .asserted()
129                .fc5_rst()
130                .asserted()
131                .fc6_rst()
132                .asserted()
133                .fc7_rst()
134                .asserted()
135                .timer2_rst()
136                .asserted()
137                .usb0_dev_rst()
138                .asserted()
139                .timer0_rst()
140                .asserted()
141                .timer1_rst()
142                .asserted()
143        });
144        syscon.presetctrl2.write(|w| {
145            w.dma1_rst()
146                .asserted()
147                .comp_rst()
148                .asserted()
149                .sdio_rst()
150                .asserted()
151                .usb1_host_rst()
152                .asserted()
153                .usb1_dev_rst()
154                .asserted()
155                .usb1_ram_rst()
156                .asserted()
157                .usb1_phy_rst()
158                .asserted()
159                .freqme_rst()
160                .asserted()
161                .rng_rst()
162                .asserted()
163                .sysctl_rst()
164                .asserted()
165                .usb0_hostm_rst()
166                .asserted()
167                .usb0_hosts_rst()
168                .asserted()
169                .hash_aes_rst()
170                .asserted()
171                .pq_rst()
172                .asserted()
173                .plulut_rst()
174                .asserted()
175                .timer3_rst()
176                .asserted()
177                .timer4_rst()
178                .asserted()
179                .puf_rst()
180                .asserted()
181                .casper_rst()
182                .asserted()
183                // .analog_ctrl_rst().asserted()  // crash
184                .hs_lspi_rst()
185                .asserted()
186                .gpio_sec_rst()
187                .asserted()
188                .gpio_sec_int_rst()
189                .asserted()
190        });
191
192        // Release everything from reset.
193        syscon.presetctrl0.write(|w| w.bits(0x0));
194        syscon.presetctrl1.write(|w| w.bits(0x0));
195        syscon.presetctrl2.write(|w| w.bits(0x0));
196
197        Syscon::from(syscon)
198    }
199}
200
201/// TODO: do this systematically
202/// By default, fro_12m is enabled in MAINCLKSELA
203impl Syscon {
204    // pub fn get_main_clk(&self) -> u8 {
205    //     self.raw.mainclksela.read().sel().bits()
206    // }
207
208    // pub fn get_num_wait_states(&self) -> u8 {
209    //     self.raw.fmccr.read().flashtim().bits()
210    // }
211
212    // pub fn set_num_wait_states(&mut self, num_wait_states: u8) {
213    //     self.raw.fmccr.modify(|_, w| unsafe { w.flashtim().bits(num_wait_states) } );
214    // }
215
216    // pub fn set_ahbclkdiv(&self, div: u8) {
217    //     assert!(div >= 1);
218    //     // dbg!(self.raw.ahbclkdiv.read().div().bits());
219    //     self.raw.ahbclkdiv.modify(unsafe { |_, w| w.div().bits(div - 1) });
220    //     // dbg!(self.raw.ahbclkdiv.read().div().bits());
221    // }
222
223    // pub(crate) fn fro1mhz_as_main_clk(&mut self) {
224    //     self.raw.mainclksela.modify(|_, w| w.sel().enum_0x2());
225    // }
226
227    // pub(crate) fn fro12mz_as_main_clk(&mut self) {
228    //     // TODO: change these names in the PAC to their UM names
229    //     // e.g. enum_0x0 -> fro_12m etc.
230    //     self.raw.mainclksela.modify(|_, w| w.sel().enum_0x0());
231    // }
232
233    // pub(crate) fn fro96mhz_as_main_clk(&mut self) {
234    //     // 1. may have to anactrl_fro192m_ctrl_ena_96mhzclk
235
236    //     // 2. set voltage for 96MHz frequency
237
238    //     // 3. set flash access cycles
239    //     // formula is min(8, floor(9e-7*freq))
240    //     // /* see fsl_clock.c, CLOCK_SetFLASHAccessCyclesForFreq */
241    //     // in this case it's 8
242    //     let num_wait_states = 8;
243    //     self.set_num_wait_states(num_wait_states);
244
245    //     // TODO: change these names in the PAC to their UM names
246    //     // e.g. enum_0x0 -> fro_12m etc.
247    //     self.raw.mainclksela.modify(|_, w| w.sel().enum_0x3());
248    //     self.raw.mainclkselb.modify(|_, w| w.sel().enum_0x0());
249    // }
250
251    // /// TODO: Check if fro_hf is actually 96Mhz??
252    // /// UM ANACTRL.FRO192M_CTRL.ENA_96MHZCLK says the 96Mhz clock
253    // /// is disabled by default
254    // pub fn fro_hf_as_usbfs_clk(&mut self) {
255    //     // 96 Mhz via changing main clock and sourcing that
256    //     // self.fro_hf_as_main_clk();
257    //     // self.raw.usb0clksel.modify(|_, w| w.sel().enum_0x0());
258
259    //     // Divide by n = 2 to get 48 Mhz (i.e., write (n - 1))
260    //     dbg!(self.raw.usb0clkdiv.read().div().bits());
261    //     self.raw
262    //         .usb0clkdiv
263    //         .modify(unsafe { |_, w| w.div().bits(0) });
264    //     dbg!(self.raw.usb0clkdiv.read().div().bits());
265    //     // Wait until the clock is stable (fsl_clock.c doesn't do this)
266    //     while self.raw.usb0clkdiv.read().reqflag().is_ongoing() {}
267    //     dbg!(self.raw.usb0clkdiv.read().div().bits());
268
269    //     // Directly pick fro_hf as usbfs clock
270    //     self.raw.usb0clksel.modify(|_, w| w.sel().enum_0x3());
271    // }
272
273    // pub fn is_enabled_usb0_hostm(&self) -> bool {
274    //     self.raw.ahbclkctrl2.read().usb0_hostm().is_enable()
275    // }
276
277    // pub fn enable_usb0_hostm(&mut self) {
278    //     self.raw.ahbclkctrl2.modify(|_, w| w.usb0_hostm().enable());
279    // }
280
281    // pub fn is_enabled_usb0_hosts(&self) -> bool {
282    //     self.raw.ahbclkctrl2.read().usb0_hosts().is_enable()
283    // }
284
285    // pub fn enable_usb0_hosts(&mut self) {
286    //     self.raw.ahbclkctrl2.modify(|_, w| w.usb0_hosts().enable());
287    // }
288}
289
290/// Internal trait for controlling peripheral clocks
291///
292/// This trait is an internal implementation detail and should neither be
293/// implemented nor used outside of LPC82x HAL. Any changes to this trait won't
294/// be considered breaking changes.
295///
296/// Compared to https://git.io/fjpf9 (in lpc-rs/lpc8xx-hal/lpc8xx-hal-common)
297/// we use a less minimal API in order to hide the fact that there are three
298/// different AHLBCKLCTRL?, which a HAL user shouldn't really need to know about.
299pub trait ClockControl {
300    /// Internal method to enable a peripheral clock
301    fn enable_clock(&self, s: &mut Syscon);
302
303    /// Internal method to disable a peripheral clock
304    fn disable_clock(&self, s: &mut Syscon);
305
306    /// Check if peripheral clock is enabled
307    fn is_clock_enabled(&self, s: &Syscon) -> bool;
308}
309
310//
311// Unwrapped implementation for easier understanding
312//
313// impl ClockControl for raw::UTICK {
314//     fn enable_clock<'h>(&self, h: &'h mut Handle) -> &'h mut Handle {
315//         h.ahbclkctrl1.modify(|_, w| w.utick0().enable());
316//         h
317//     }
318
319//     fn disable_clock<'h>(&self, h: &'h mut Handle) -> &'h mut Handle {
320//         h.ahbclkctrl1.modify(|_, w| w.utick0().disable());
321//         h
322//     }
323
324//     fn is_clock_enabled(&self, h: &Handle) -> bool {
325//         h.ahbclkctrl1.read().utick0().is_enable()
326//     }
327// }
328
329macro_rules! impl_clock_control {
330    ($clock_control:ty, $clock:ident, $register:ident) => {
331        impl ClockControl for $clock_control {
332            fn enable_clock(&self, s: &mut Syscon) {
333                s.raw.$register.modify(|_, w| w.$clock().enable());
334                while s.raw.$register.read().$clock().is_disable() {}
335            }
336
337            fn disable_clock(&self, s: &mut Syscon) {
338                s.raw.$register.modify(|_, w| w.$clock().disable());
339            }
340
341            fn is_clock_enabled(&self, s: &Syscon) -> bool {
342                s.raw.$register.read().$clock().is_enable()
343            }
344        }
345    };
346
347    ($clock_control:ty, $clock1:ident, $clock2:ident, $register:ident) => {
348        impl ClockControl for $clock_control {
349            fn enable_clock(&self, s: &mut Syscon) {
350                s.raw.$register.modify(|_, w| w.$clock1().enable());
351                s.raw.$register.modify(|_, w| w.$clock2().enable());
352                while s.raw.$register.read().$clock1().is_disable() {}
353                while s.raw.$register.read().$clock2().is_disable() {}
354            }
355
356            fn disable_clock(&self, s: &mut Syscon) {
357                s.raw.$register.modify(|_, w| w.$clock1().disable());
358                s.raw.$register.modify(|_, w| w.$clock2().disable());
359            }
360
361            fn is_clock_enabled(&self, s: &Syscon) -> bool {
362                s.raw.$register.read().$clock1().is_enable()
363                    && s.raw.$register.read().$clock2().is_enable()
364            }
365        }
366    };
367}
368
369impl_clock_control!(raw::ADC0, adc, ahbclkctrl0);
370impl_clock_control!(raw::CTIMER0, timer0, ahbclkctrl1);
371impl_clock_control!(raw::CTIMER1, timer1, ahbclkctrl1);
372impl_clock_control!(raw::CTIMER2, timer2, ahbclkctrl1);
373impl_clock_control!(raw::CTIMER3, timer3, ahbclkctrl2);
374impl_clock_control!(raw::CTIMER4, timer4, ahbclkctrl2);
375impl_clock_control!(raw::DMA0, dma0, ahbclkctrl0);
376impl_clock_control!(raw::FLASH, flash, ahbclkctrl0);
377impl_clock_control!(raw::FLEXCOMM0, fc0, ahbclkctrl1);
378impl_clock_control!(raw::FLEXCOMM1, fc1, ahbclkctrl1);
379impl_clock_control!(raw::FLEXCOMM2, fc2, ahbclkctrl1);
380impl_clock_control!(raw::FLEXCOMM3, fc3, ahbclkctrl1);
381impl_clock_control!(raw::FLEXCOMM4, fc4, ahbclkctrl1);
382impl_clock_control!(raw::FLEXCOMM5, fc5, ahbclkctrl1);
383impl_clock_control!(raw::FLEXCOMM6, fc6, ahbclkctrl1);
384impl_clock_control!(raw::FLEXCOMM7, fc7, ahbclkctrl1);
385impl_clock_control!(raw::FLEXCOMM8, hs_lspi, ahbclkctrl2);
386impl_clock_control!(raw::HASHCRYPT, hash_aes, ahbclkctrl2);
387impl_clock_control!(raw::INPUTMUX, mux, ahbclkctrl0);
388impl_clock_control!(raw::IOCON, iocon, ahbclkctrl0);
389impl_clock_control!((&mut raw::GINT0, &mut raw::GINT1), gint, ahbclkctrl0);
390impl_clock_control!(raw::PINT, pint, ahbclkctrl0);
391
392impl_clock_control!(raw::USB0, usb0_dev, ahbclkctrl1);
393impl_clock_control!(raw::USBPHY, usb1_phy, ahbclkctrl2);
394impl_clock_control!(raw::USB1, usb1_dev, usb1_ram, ahbclkctrl2);
395impl_clock_control!(raw::USBFSH, usb0_hosts, ahbclkctrl2); // well what about usb0_hostm?
396impl_clock_control!(raw::USBHSH, usb1_host, ahbclkctrl2);
397impl_clock_control!(raw::UTICK0, utick, ahbclkctrl1);
398
399impl_clock_control!(raw::ANACTRL, analog_ctrl, ahbclkctrl2);
400impl_clock_control!(raw::CASPER, casper, ahbclkctrl2);
401// there is no GPIO_SEC. what to do? create a PhantomData one?
402// impl_clock_control!(raw::GPIO_SEC, gpio_sec, ahbclkctrl2);
403impl_clock_control!(raw::PUF, puf, ahbclkctrl2);
404impl_clock_control!(raw::RNG, rng, ahbclkctrl2);
405impl_clock_control!(raw::RTC, rtc, ahbclkctrl0);
406
407// GPIO needs a separate implementation
408impl ClockControl for raw::GPIO {
409    fn enable_clock(&self, s: &mut Syscon) {
410        s.raw.ahbclkctrl0.modify(|_, w| w.gpio0().enable());
411        s.raw.ahbclkctrl0.modify(|_, w| w.gpio1().enable());
412    }
413
414    fn disable_clock(&self, s: &mut Syscon) {
415        s.raw.ahbclkctrl0.modify(|_, w| w.gpio0().disable());
416        s.raw.ahbclkctrl0.modify(|_, w| w.gpio1().disable());
417    }
418
419    #[allow(clippy::nonminimal_bool)]
420    fn is_clock_enabled(&self, s: &Syscon) -> bool {
421        s.raw.ahbclkctrl0.read().gpio0().is_enable() && s.raw.ahbclkctrl0.read().gpio1().is_enable()
422    }
423}
424
425pub trait ResetControl {
426    /// Internal method to assert peripheral reset
427    fn assert_reset(&self, syscon: &mut Syscon);
428
429    /// Internal method to clear peripheral reset
430    fn clear_reset(&self, syscon: &mut Syscon);
431}
432
433macro_rules! impl_reset_control {
434    ($reset_control:ty, $field:ident, $register:ident) => {
435        impl<'a> ResetControl for $reset_control {
436            fn assert_reset(&self, syscon: &mut Syscon) {
437                syscon.raw.$register.modify(|_, w| w.$field().asserted());
438                while syscon.raw.$register.read().$field().is_released() {}
439            }
440
441            fn clear_reset(&self, syscon: &mut Syscon) {
442                syscon.raw.$register.modify(|_, w| w.$field().released());
443                while syscon.raw.$register.read().$field().is_asserted() {}
444            }
445        }
446    };
447    ($reset_control:ty, $field1:ident, $field2:ident, $register:ident) => {
448        impl<'a> ResetControl for $reset_control {
449            fn assert_reset(&self, syscon: &mut Syscon) {
450                syscon.raw.$register.modify(|_, w| w.$field1().asserted());
451                while syscon.raw.$register.read().$field1().is_released() {}
452                syscon.raw.$register.modify(|_, w| w.$field2().asserted());
453                while syscon.raw.$register.read().$field2().is_released() {}
454            }
455
456            fn clear_reset(&self, syscon: &mut Syscon) {
457                syscon.raw.$register.modify(|_, w| w.$field1().released());
458                while syscon.raw.$register.read().$field1().is_asserted() {}
459                syscon.raw.$register.modify(|_, w| w.$field2().released());
460                while syscon.raw.$register.read().$field2().is_asserted() {}
461            }
462        }
463    };
464}
465
466// to be completed
467impl_reset_control!(raw::ADC0, adc_rst, presetctrl0);
468impl_reset_control!(raw::CASPER, casper_rst, presetctrl2);
469impl_reset_control!(raw::CTIMER0, timer0_rst, presetctrl1);
470impl_reset_control!(raw::CTIMER1, timer1_rst, presetctrl1);
471impl_reset_control!(raw::CTIMER2, timer2_rst, presetctrl1);
472impl_reset_control!(raw::CTIMER3, timer3_rst, presetctrl2);
473impl_reset_control!(raw::CTIMER4, timer4_rst, presetctrl2);
474impl_reset_control!(raw::DMA0, dma0_rst, presetctrl0);
475impl_reset_control!(raw::FLEXCOMM0, fc0_rst, presetctrl1);
476impl_reset_control!(raw::FLEXCOMM1, fc1_rst, presetctrl1);
477impl_reset_control!(raw::FLEXCOMM2, fc2_rst, presetctrl1);
478impl_reset_control!(raw::FLEXCOMM3, fc3_rst, presetctrl1);
479impl_reset_control!(raw::FLEXCOMM4, fc4_rst, presetctrl1);
480impl_reset_control!(raw::FLEXCOMM5, fc5_rst, presetctrl1);
481impl_reset_control!(raw::FLEXCOMM6, fc6_rst, presetctrl1);
482impl_reset_control!(raw::FLEXCOMM7, fc7_rst, presetctrl1);
483impl_reset_control!(raw::FLEXCOMM8, hs_lspi_rst, presetctrl2);
484impl_reset_control!(raw::HASHCRYPT, hash_aes_rst, presetctrl2);
485impl_reset_control!(raw::USB0, usb0_dev_rst, presetctrl1);
486impl_reset_control!(raw::USBHSH, usb1_host_rst, presetctrl2);
487impl_reset_control!(raw::USBPHY, usb1_phy_rst, presetctrl2);
488impl_reset_control!(raw::UTICK0, utick_rst, presetctrl1);
489
490impl_reset_control!(raw::USBFSH, usb0_hostm_rst, usb0_hosts_rst, presetctrl2);
491impl_reset_control!(raw::USB1, usb1_dev_rst, usb1_ram_rst, presetctrl2);