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
//! ARM System Control Block
//!
//! <http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CIHFDJCA.html>

use kernel::common::VolatileCell;

#[repr(C)]
struct ScbRegisters {
    cpuid: VolatileCell<u32>,
    icsr: VolatileCell<u32>,
    vtor: VolatileCell<u32>,
    aircr: VolatileCell<u32>,
    scr: VolatileCell<u32>,
    ccr: VolatileCell<u32>,
    shp: [VolatileCell<u32>; 12],
    shcsr: VolatileCell<u32>,
    cfsr: VolatileCell<u32>,
    hfsr: VolatileCell<u32>,
    dfsr: VolatileCell<u32>,
    mmfar: VolatileCell<u32>,
    bfar: VolatileCell<u32>,
    afsr: VolatileCell<u32>,
    pfr: [VolatileCell<u32>; 2],
    dfr: VolatileCell<u32>,
    adr: VolatileCell<u32>,
    mmfr: [VolatileCell<u32>; 4],
    isar: [VolatileCell<u32>; 5],
    _reserved0: [u32; 5],
    cpacr: VolatileCell<u32>,
}

const SCB_BASE: usize = 0xE000ED00;

static mut SCB: *mut ScbRegisters = SCB_BASE as *mut ScbRegisters;

/// Allow the core to go into deep sleep on WFI.
///
/// The specific definition of "deep sleep" is chip specific.
pub unsafe fn set_sleepdeep() {
    let scr = (*SCB).scr.get();
    (*SCB).scr.set(scr | 1 << 2);
}

/// Do not allow the core to go into deep sleep on WFI.
///
/// The specific definition of "deep sleep" is chip specific.
pub unsafe fn unset_sleepdeep() {
    let scr = (*SCB).scr.get();
    (*SCB).scr.set(scr & !(1 << 2));
}

/// Software reset using the ARM System Control Block
pub unsafe fn reset() {
    let aircr = (*SCB).aircr.get();
    let reset = (0x5FA << 16) | (aircr & (0x7 << 8)) | (1 << 2);
    (*SCB).aircr.set(reset);
}