Skip to main content

ws63_hal/
system.rs

1//! System control — clock enables, resets, and power management.
2
3use crate::peripherals::{CldoCrg, GlbCtlM, SysCtl0};
4
5/// System control handle.
6///
7/// Holds the SYS_CTL0, GLB_CTL_M, and CLDO_CRG peripherals for clock and
8/// reset configuration.
9pub struct System<'d> {
10    pub sys_ctl0: SysCtl0<'d>,
11    pub glb_ctl_m: GlbCtlM<'d>,
12    pub cldo_crg: CldoCrg<'d>,
13}
14
15impl<'d> System<'d> {
16    pub fn new(sys_ctl0: SysCtl0<'d>, glb_ctl_m: GlbCtlM<'d>, cldo_crg: CldoCrg<'d>) -> Self {
17        Self { sys_ctl0, glb_ctl_m, cldo_crg }
18    }
19}
20
21/// Reason for the last reset.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum ResetReason {
24    /// Power-on reset (cold boot).
25    PowerOn,
26    /// External reset pin.
27    ExternalPin,
28    /// Watchdog timer reset.
29    Watchdog,
30    /// Software reset.
31    Software,
32    /// Brown-out reset.
33    BrownOut,
34    /// Unknown reset reason.
35    Unknown,
36}
37
38// Reset registers, from fbb_ws63 drivers/chips/ws63/porting/reboot/reboot_porting.c:
39//   chip-reset trigger:  GLB_CTL_M (0x4000_2000) + 0x110, set bit 2 (HAL_CHIP_RESET_REG)
40//   reset-reason record: GLB_CTL   (0x4000_0000) + 0xA0    (SYS_RST_RECORD_0)
41//   reason-clear:        GLB_CTL   (0x4000_0000) + 0xA4    (SYS_DIAG_CLR_1)
42const CHIP_RESET_REG: *mut u32 = 0x4000_2110 as *mut u32;
43const CHIP_RESET_ENABLE_BIT: u32 = 1 << 2;
44const SYS_RST_RECORD_0: *mut u32 = 0x4000_00A0 as *mut u32;
45const SYS_DIAG_CLR_1: *mut u32 = 0x4000_00A4 as *mut u32;
46// History bits in SYS_RST_RECORD_0.
47const SYS_WDT_RST_HIS: u32 = 0x1;
48const SYS_SOFT_RST_HIS: u32 = 0x2;
49const POR_RST_FILTER_HIS: u32 = 0x8;
50
51impl System<'_> {
52    /// Read (and clear) the last reset reason from `SYS_RST_RECORD_0`.
53    ///
54    /// Decodes the WS63 reset-history record (`reboot_port_get_rst_reason`):
55    /// watchdog takes precedence over software over power-on. The matched bit is
56    /// cleared via `SYS_DIAG_CLR_1` so the next boot reports its own cause.
57    /// Reasons this SoC's record does not distinguish (`ExternalPin`, `BrownOut`)
58    /// are never returned here. An empty record reads back as [`ResetReason::Unknown`].
59    pub fn reset_reason(&self) -> ResetReason {
60        let val = unsafe { core::ptr::read_volatile(SYS_RST_RECORD_0) };
61        let (reason, clr) = if val & SYS_WDT_RST_HIS != 0 {
62            (ResetReason::Watchdog, SYS_WDT_RST_HIS)
63        } else if val & SYS_SOFT_RST_HIS != 0 {
64            (ResetReason::Software, SYS_SOFT_RST_HIS)
65        } else if val & POR_RST_FILTER_HIS != 0 {
66            (ResetReason::PowerOn, POR_RST_FILTER_HIS)
67        } else {
68            (ResetReason::Unknown, 0)
69        };
70        if clr != 0 {
71            unsafe { core::ptr::write_volatile(SYS_DIAG_CLR_1, clr) };
72        }
73        reason
74    }
75
76    /// Trigger a full software reset of the chip and never return.
77    ///
78    /// Sets the chip-reset enable bit (bit 2) of `GLB_CTL_M + 0x110`, the same
79    /// register `reboot_port_reboot_chip` uses. The CPU is reset before the
80    /// following spin loop completes.
81    pub fn software_reset(&self) -> ! {
82        unsafe {
83            let v = core::ptr::read_volatile(CHIP_RESET_REG);
84            core::ptr::write_volatile(CHIP_RESET_REG, v | CHIP_RESET_ENABLE_BIT);
85        }
86        loop {
87            core::hint::spin_loop();
88        }
89    }
90
91    /// Trigger a software reset and never return.
92    ///
93    /// WS63's porting layer exposes only a whole-chip reset, so this is an alias
94    /// of [`software_reset`](Self::software_reset).
95    pub fn software_reset_cpu(&self) -> ! {
96        self.software_reset()
97    }
98}
99
100/// Clocks after configuration.
101#[derive(Debug, Clone, Copy)]
102pub struct Clocks {
103    /// System (CPU) clock frequency in Hz.
104    pub sysclk: u32,
105    /// Peripheral bus clock frequency in Hz.
106    pub pclk: u32,
107}
108
109impl Default for Clocks {
110    fn default() -> Self {
111        Self { sysclk: crate::soc::ws63::SYSTEM_CLOCK_HZ, pclk: crate::soc::ws63::SYSTEM_CLOCK_HZ }
112    }
113}