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
/*********************************************************************************************************************** 
 * Copyright (c) 2019 by the authors
 * 
 * Author: André Borrmann 
 * License: Apache License 2.0
 **********************************************************************************************************************/
#![doc(html_root_url = "https://docs.rs/ruspiro-mailbox/0.1.0")]
#![no_std]
#![feature(asm)]

//! # Mailbox property tag interface
//! 
//! This crate provides an abstraction on the mailbox property tag interface available in the Raspberry Pi.
//! There are currently a limmited number of functions for the following property tag messages implemented:
//! - GetArmMemory
//! - GetClockRate
//! - SetClockRate
//! 
//! Check the [official documentation](https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface) of those property tags and their purpose.
//! 
//! # Usage
//! 
//! The crate provides a singleton wrapper to call the different Raspberry Pi mailbox property tag messages. The
//! following example demonstrates the usage with the GetClockRate message.
//! ```
//! use ruspiro_mailbox::*;
//! 
//! fn demo() {
//!     // use the mailbox to retrieve the core clock rate
//!     if let Ok(core_rate) = MAILBOX.take_for(|mb| mb.get_clockrate(ArmClockId::Core)) {
//!         // here we know the core clock rate do something with it...
//!         // remeber - println is just a show case here as it might not be available in bare metal environment
//!         println!("Core clock rate {}", core_rate);
//!     }
//! }
//! ```

use ruspiro_singleton::Singleton;

mod interface;
mod propertytags;
use interface::*;

/// static "singleton" accessor to the MAILBOX peripheral
pub static MAILBOX: Singleton<Mailbox> = Singleton::new(Mailbox::new());

/// Definition of the different ARM clock id's used in the mailbox interface
#[repr(u32)]
pub enum ArmClockId {
    Emmc   = 0x1,
    Uart   = 0x2,
    Arm    = 0x3,
    Core   = 0x4
}

/// MAILBOX peripheral representation
pub struct Mailbox;

impl Mailbox {
    pub(crate) const fn new() -> Self {
        Mailbox
    }

    /// Get the ARM memory base address and size as configured in the boot config file
    pub fn get_arm_memory(&self) -> MailboxResult<(u32, u32)> {
        send_message(
            MailboxChannel::PropertyTagsVc,
            &propertytags::ArmMemoryGet::new()
        ).and_then(|tag| {
            let response = tag.get_response();
            Ok((response.base_address, response.size))
        })
    }

    /// Get the clock rate via mailbox interface for the clockId given
    pub fn get_clockrate(&self, clock_id: ArmClockId) -> MailboxResult<u32> {
        send_message(
            MailboxChannel::PropertyTagsVc,
            &propertytags::ClockrateGet::new(clock_id as u32)
        ).and_then(|clock_rate_get| {
            Ok(clock_rate_get.get_response().clock_rate)
        })
    }

    /// Set the clock rate via the mailbox interface for the clockId given. The rate will be set to the closest valid value.
    pub fn set_clockrate(&self, clock_id: ArmClockId, rate: u32) -> MailboxResult<u32> {
        send_message(
            MailboxChannel::PropertyTagsVc,
            &propertytags::ClockrateSet::new(clock_id as u32, rate, 0x0)
        ).and_then(|clock_rate_set| {
            Ok(clock_rate_set.get_response().clock_rate)
        })
    }
}