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