aarch64/fb: add bcm2837 mailbox

master
equation314 6 years ago
parent 81af2c82fd
commit 4257b76183

@ -5,6 +5,7 @@ extern crate volatile;
pub mod gpio;
pub mod timer;
pub mod mailbox;
pub mod mini_uart;
pub mod interrupt;

@ -0,0 +1,80 @@
use crate::IO_BASE;
use volatile::{ReadOnly, Volatile, WriteOnly};
/// The base address for the `MU` registers.
const MAILBOX_BASE: usize = IO_BASE + 0xB000 + 0x880;
/// Available mailbox channels
///
/// (ref: https://github.com/raspberrypi/firmware/wiki/Mailboxes)
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum MailboxChannel {
Framebuffer = 1,
Property = 8,
}
/// Read from mailbox status register (MAILx_STA).
#[repr(u32)]
enum MailboxStatus {
MailboxEmpty = 1 << 30,
MailboxFull = 1 << 31,
}
/// Mailbox registers. We basically only support mailbox 0 & 1. We
/// deliver to the VC in mailbox 1, it delivers to us in mailbox 0. See
/// BCM2835-ARM-Peripherals.pdf section 1.3 for an explanation about
/// the placement of memory barriers.
///
/// (ref: https://github.com/raspberrypi/firmware/wiki/Mailboxes)
#[repr(C)]
#[allow(non_snake_case)]
struct Registers {
MAIL0_RD: ReadOnly<u32>, // 0x00
__reserved0: [u32; 3],
MAIL0_POL: ReadOnly<u32>, // 0x10
MAIL0_SND: ReadOnly<u32>, // 0x14
MAIL0_STA: ReadOnly<u32>, // 0x18
MAIL0_CNF: Volatile<u32>, // 0x1c
MAIL1_WRT: WriteOnly<u32>, // 0x20
__reserved1: [u32; 3],
_MAIL1_POL: ReadOnly<u32>, // 0x30
_MAIL1_SND: ReadOnly<u32>, // 0x34
MAIL1_STA: ReadOnly<u32>, // 0x38
_MAIL1_CNF: Volatile<u32>, // 0x3c
}
/// The Raspberry Pi's mailbox.
///
/// (ref: https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes)
pub struct Mailbox {
registers: &'static mut Registers,
}
impl Mailbox {
/// Returns a new instance of `Mailbox`.
#[inline]
pub fn new() -> Mailbox {
Mailbox {
registers: unsafe { &mut *(MAILBOX_BASE as *mut Registers) },
}
}
// Read from the requested channel of mailbox 0.
pub fn read(&self, channel: MailboxChannel) -> u32 {
loop {
while self.registers.MAIL0_STA.read() & (MailboxStatus::MailboxEmpty as u32) != 0 {}
let data = self.registers.MAIL0_RD.read();
if data & 0xF == channel as u32 {
return data & !0xF;
}
}
}
// Write to the requested channel of mailbox 1.
pub fn write(&mut self, channel: MailboxChannel, data: u32) {
while self.registers.MAIL1_STA.read() & (MailboxStatus::MailboxFull as u32) != 0 {}
self.registers.MAIL1_WRT.write((data & !0xF) | (channel as u32));
}
}

@ -2,12 +2,12 @@ use crate::IO_BASE;
use crate::gpio::{Function, Gpio};
use volatile::{ReadOnly, Volatile};
/// The base address for the `MU` registers.
const MU_REG_BASE: usize = IO_BASE + 0x215040;
/// The `AUXENB` register from page 9 of the BCM2837 documentation.
const AUX_ENABLES: *mut Volatile<u8> = (IO_BASE + 0x215004) as *mut Volatile<u8>;
/// The base address for the `MU` registers.
const MU_REG_BASE: usize = IO_BASE + 0x215040;
/// Enum representing bit fields of the `AUX_MU_IIR_REG` register.
#[repr(u8)]
pub enum MiniUartInterruptId {
@ -55,19 +55,10 @@ pub struct MiniUart {
}
impl MiniUart {
/// Initializes the mini UART by enabling it as an auxiliary peripheral,
/// setting the data size to 8 bits, setting the BAUD rate to ~115200 (baud
/// divider of 270), setting GPIO pins 14 and 15 to alternative function 5
/// (TXD1/RDXD1), and finally enabling the UART transmitter and receiver.
///
/// By default, reads will never time out. To set a read timeout, use
/// `set_read_timeout()`.
/// Returns a new instance of `MiniUart`.
#[inline]
pub fn new() -> MiniUart {
let registers = unsafe {
// Enable the mini UART as an auxiliary device.
(*AUX_ENABLES).write(1);
&mut *(MU_REG_BASE as *mut Registers)
};
let registers = unsafe { &mut *(MU_REG_BASE as *mut Registers) };
MiniUart {
registers: registers,
@ -75,7 +66,17 @@ impl MiniUart {
}
}
/// Initializes the mini UART by enabling it as an auxiliary peripheral,
/// setting the data size to 8 bits, setting the BAUD rate to ~115200 (baud
/// divider of 270), setting GPIO pins 14 and 15 to alternative function 5
/// (TXD1/RDXD1), and finally enabling the UART transmitter and receiver.
///
/// By default, reads will never time out. To set a read timeout, use
/// `set_read_timeout()`.
pub fn init(&mut self) {
// Enable the mini UART as an auxiliary device.
unsafe { (*AUX_ENABLES).write(1) }
Gpio::new(14).into_alt(Function::Alt5).set_gpio_pd(0);
Gpio::new(15).into_alt(Function::Alt5).set_gpio_pd(0);

Loading…
Cancel
Save