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
#![no_std]
#![feature(pointer_byte_offsets)]
#![feature(never_type)]

use log::{log, Level};

static mut MMIO: mmio::VolBox<u32, mmio::Deny, mmio::Allow> = unsafe {mmio::VolBox::new(core::ptr::null_mut())};
static mut OFF: u32 = 0;
static mut REBOOT: u32 = 0;

pub fn init(fdt_ptr: *const u8) ->  Option<()> {
    unsafe {
        let fdt = fdt::Fdt::from_ptr(fdt_ptr).expect("Invalid Fdt pointer");

        let node = fdt.find_compatible(&["syscon-poweroff"])?;
        let offset = node.property("offset")?.as_usize()?;
        OFF = node.property("value")?.as_usize()? as u32;

        let node = fdt.find_compatible(&["syscon-reboot"])?;
        let offset = node.property("offset")?.as_usize()?;
        REBOOT = node.property("value")?.as_usize()? as u32;

        let syscon_phandle = node.property("regmap")?.as_usize()? as u32;
        let syscon_node = fdt.find_phandle(syscon_phandle)?;
        let syscon_mmio = syscon_node.reg()?.next()?.starting_address.cast::<u32>().cast_mut();

        let mmio: mmio::VolBox<u32, mmio::Deny, mmio::Allow> = mmio::VolBox::new(syscon_mmio);

        MMIO = mmio;
    }

    Some(())
}

pub fn power_off() -> ! {
    log!(Level::Info, "Power off requested");

    unsafe {
        MMIO.write(OFF);
    }

    unreachable!("ERROR OCCURED WHILE POWERING OFF");
}

pub fn reboot() -> ! {
    log!(Level::Info, "Reboot requested");
    
    unsafe {
        MMIO.write(REBOOT);
    }

    unreachable!("ERROR OCCURED WHILE REBOOTING");
}