From d7511d81200e180a21210a81200a5ad9bb651375 Mon Sep 17 00:00:00 2001 From: equation314 Date: Fri, 14 Dec 2018 21:19:44 +0800 Subject: [PATCH] aarch64/fb: add mailbox property interfaces --- crate/bcm2837/src/mailbox.rs | 4 +- kernel/Cargo.lock | 2 +- kernel/src/arch/aarch64/board/raspi3/irq.rs | 1 - .../src/arch/aarch64/board/raspi3/mailbox.rs | 266 ++++++++++++++++++ kernel/src/arch/aarch64/board/raspi3/mod.rs | 1 + kernel/src/arch/aarch64/mod.rs | 4 +- 6 files changed, 273 insertions(+), 5 deletions(-) create mode 100644 kernel/src/arch/aarch64/board/raspi3/mailbox.rs diff --git a/crate/bcm2837/src/mailbox.rs b/crate/bcm2837/src/mailbox.rs index 89ca1d6..0e7d32f 100644 --- a/crate/bcm2837/src/mailbox.rs +++ b/crate/bcm2837/src/mailbox.rs @@ -61,7 +61,7 @@ impl Mailbox { } } - // Read from the requested channel of mailbox 0. + /// 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 {} @@ -72,7 +72,7 @@ impl Mailbox { } } - // Write to the requested channel of mailbox 1. + /// 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)); diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 064af4a..ecc04cb 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -1,7 +1,7 @@ [[package]] name = "aarch64" version = "2.2.2" -source = "git+https://github.com/equation314/aarch64#e3b60adb233ad34d05443e0b5ec34cac29253296" +source = "git+https://github.com/equation314/aarch64#06b2f5507dd5393e40c1506cd4414ef36864afc6" dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/kernel/src/arch/aarch64/board/raspi3/irq.rs b/kernel/src/arch/aarch64/board/raspi3/irq.rs index d8730dc..9575e29 100644 --- a/kernel/src/arch/aarch64/board/raspi3/irq.rs +++ b/kernel/src/arch/aarch64/board/raspi3/irq.rs @@ -1,6 +1,5 @@ use crate::arch::interrupt::TrapFrame; use bcm2837::interrupt::Controller; -use log::*; pub use bcm2837::interrupt::Interrupt; diff --git a/kernel/src/arch/aarch64/board/raspi3/mailbox.rs b/kernel/src/arch/aarch64/board/raspi3/mailbox.rs new file mode 100644 index 0000000..83e1557 --- /dev/null +++ b/kernel/src/arch/aarch64/board/raspi3/mailbox.rs @@ -0,0 +1,266 @@ +//! Mailbox property interface +//! +//! (ref: https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface) + +use bcm2837::mailbox::{Mailbox, MailboxChannel}; +use lazy_static::lazy_static; +use core::mem; +use spin::Mutex; +use aarch64::barrier; + +lazy_static! { + static ref MAILBOX: Mutex = Mutex::new(Mailbox::new()); +} + +#[derive(Debug)] +pub struct PropertyMailboxError(u32); +pub type PropertyMailboxResult = Result; + +/// Buffer request/response code. +/// Copied from `linux/include/soc/bcm2835/raspberrypi-firmware.h` +#[repr(u32)] +#[allow(dead_code)] +#[derive(Copy, Clone, Debug)] +#[allow(non_camel_case_types)] +enum PropertyMailboxStatus { + RPI_FIRMWARE_STATUS_REQUEST = 0, + RPI_FIRMWARE_STATUS_SUCCESS = 0x80000000, + RPI_FIRMWARE_STATUS_ERROR = 0x80000001, +} +use self::PropertyMailboxStatus::*; + +/// Tag identifier. +/// Copied from `linux/include/soc/bcm2835/raspberrypi-firmware.h` +#[repr(u32)] +#[allow(dead_code)] +#[derive(Copy, Clone, Debug)] +#[allow(non_camel_case_types)] +enum PropertyMailboxTagId { + RPI_FIRMWARE_PROPERTY_END = 0, + RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001, + + RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010, + RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011, + + RPI_FIRMWARE_GET_BOARD_MODEL = 0x00010001, + RPI_FIRMWARE_GET_BOARD_REVISION = 0x00010002, + RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS = 0x00010003, + RPI_FIRMWARE_GET_BOARD_SERIAL = 0x00010004, + RPI_FIRMWARE_GET_ARM_MEMORY = 0x00010005, + RPI_FIRMWARE_GET_VC_MEMORY = 0x00010006, + RPI_FIRMWARE_GET_CLOCKS = 0x00010007, + RPI_FIRMWARE_GET_POWER_STATE = 0x00020001, + RPI_FIRMWARE_GET_TIMING = 0x00020002, + RPI_FIRMWARE_SET_POWER_STATE = 0x00028001, + RPI_FIRMWARE_GET_CLOCK_STATE = 0x00030001, + RPI_FIRMWARE_GET_CLOCK_RATE = 0x00030002, + RPI_FIRMWARE_GET_VOLTAGE = 0x00030003, + RPI_FIRMWARE_GET_MAX_CLOCK_RATE = 0x00030004, + RPI_FIRMWARE_GET_MAX_VOLTAGE = 0x00030005, + RPI_FIRMWARE_GET_TEMPERATURE = 0x00030006, + RPI_FIRMWARE_GET_MIN_CLOCK_RATE = 0x00030007, + RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008, + RPI_FIRMWARE_GET_TURBO = 0x00030009, + RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a, + RPI_FIRMWARE_GET_STC = 0x0003000b, + RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c, + RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d, + RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e, + RPI_FIRMWARE_RELEASE_MEMORY = 0x0003000f, + RPI_FIRMWARE_EXECUTE_CODE = 0x00030010, + RPI_FIRMWARE_EXECUTE_QPU = 0x00030011, + RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012, + RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014, + RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020, + RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021, + RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030, + RPI_FIRMWARE_GET_THROTTLED = 0x00030046, + RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047, + RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048, + RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001, + RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002, + RPI_FIRMWARE_SET_VOLTAGE = 0x00038003, + RPI_FIRMWARE_SET_TURBO = 0x00038009, + RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021, + RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030, + RPI_FIRMWARE_GET_GPIO_STATE = 0x00030041, + RPI_FIRMWARE_SET_GPIO_STATE = 0x00038041, + RPI_FIRMWARE_SET_SDHOST_CLOCK = 0x00038042, + RPI_FIRMWARE_GET_GPIO_CONFIG = 0x00030043, + RPI_FIRMWARE_SET_GPIO_CONFIG = 0x00038043, + RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045, + RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045, + RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, + RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050, + + /* Dispmanx TAGS */ + RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, + RPI_FIRMWARE_FRAMEBUFFER_BLANK = 0x00040002, + RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003, + RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004, + RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH = 0x00040005, + RPI_FIRMWARE_FRAMEBUFFER_GET_PIXEL_ORDER = 0x00040006, + RPI_FIRMWARE_FRAMEBUFFER_GET_ALPHA_MODE = 0x00040007, + RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH = 0x00040008, + RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009, + RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a, + RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b, + RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f, + RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010, + RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001, + RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003, + RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004, + RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005, + RPI_FIRMWARE_FRAMEBUFFER_TEST_PIXEL_ORDER = 0x00044006, + RPI_FIRMWARE_FRAMEBUFFER_TEST_ALPHA_MODE = 0x00044007, + RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009, + RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a, + RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b, + RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e, + RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003, + RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004, + RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005, + RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006, + RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007, + RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009, + RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a, + RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b, + RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f, + RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020, + RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e, + RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, + + RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, + + RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, + RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, +} +use self::PropertyMailboxTagId::*; + +/// A property mailbox tag. +#[repr(C, packed)] +#[derive(Debug)] +#[allow(safe_packed_borrows)] +struct PropertyMailboxTag { + id: PropertyMailboxTagId, + buf_size: u32, + req_resp_size: u32, + buf: T, +} + +/// A request that contained a sequence of concatenated tags. The response +/// overwrites the request. +#[repr(C, packed)] +#[derive(Debug)] +#[allow(safe_packed_borrows)] +struct PropertyMailboxRequest { + buf_size: u32, + req_resp_code: PropertyMailboxStatus, + buf: T, + end_tag: PropertyMailboxTagId, +} + +/// Request buffer address must be 16-byte aligned. +#[repr(C, align(16))] +#[derive(Debug)] +struct Align16(PropertyMailboxRequest); + +/// Pack a sequence of concatenated tags into a request, and send the address +/// to the mailbox. +/// Returns PropertyMailboxResult. +macro_rules! send_request { + ($tags: ident) => {{ + let req = Align16(PropertyMailboxRequest { + buf_size: mem::size_of_val(&$tags) as u32, + req_resp_code: RPI_FIRMWARE_STATUS_REQUEST, + buf: $tags, + end_tag: RPI_FIRMWARE_PROPERTY_END, + }); + + unsafe { barrier::wmb() } + { + let mut mbox = MAILBOX.lock(); + mbox.write(MailboxChannel::Property, &req as *const _ as u32); + mbox.read(MailboxChannel::Property); + } + unsafe { barrier::rmb() } + + match req.0.req_resp_code { + RPI_FIRMWARE_STATUS_SUCCESS => Ok(req.0.buf), + other => Err(PropertyMailboxError(other as u32)), + } + }}; +} + +/// Send a tag to mailbox. Will call `send_request!`. +/// Returns PropertyMailboxResult. +macro_rules! send_one_tag { + ($id: expr, [$($arg: expr),*]) => {{ + let buf = [$($arg),*]; + let tag = PropertyMailboxTag { + id: $id, + buf_size: mem::size_of_val(&buf) as u32, + req_resp_size: 0, + buf, + }; + Ok(send_request!(tag)?.buf) + }}; +} + +/// Allocates contiguous memory on the GPU. `size` and `align` are in bytes. +/// Returns memory `handle`. +pub fn mem_alloc(size: u32, align: u32, flags: u32) -> PropertyMailboxResult { + let ret = send_one_tag!(RPI_FIRMWARE_LOCK_MEMORY, [size, align, flags])?; + Ok(ret[0]) +} + +/// Free the memory buffer of `handle`. status=0 is success. +pub fn mem_free(handle: u32) -> PropertyMailboxResult<()> { + let status = send_one_tag!(RPI_FIRMWARE_RELEASE_MEMORY, [handle])?; + match status[0] { + 0 => Ok(()), + other => Err(PropertyMailboxError(other)), + } +} + +/// Lock buffer in place, and return a `bus_address`. Must be done before memory +/// can be accessed. +pub fn mem_lock(handle: u32) -> PropertyMailboxResult { + let ret = send_one_tag!(RPI_FIRMWARE_LOCK_MEMORY, [handle])?; + Ok(ret[0]) +} + +/// Unlock buffer. It retains contents, but may move. Needs to be locked before +/// next use. status=0 is success. +pub fn mem_unlock(handle: u32) -> PropertyMailboxResult<()> { + let status = send_one_tag!(RPI_FIRMWARE_UNLOCK_MEMORY, [handle])?; + match status[0] { + 0 => Ok(()), + other => Err(PropertyMailboxError(other)), + } +} + +/// Get physical (display) width/height. Returns `(width, height)` in pixels. +/// Note that the "physical (display)" size is the size of the allocated buffer +/// in memory, not the resolution of the video signal sent to the display device. +pub fn framebuffer_get_physical_size() -> PropertyMailboxResult<(u32, u32)> { + let ret = send_one_tag!(RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT, [0, 0])?; + Ok((ret[0], ret[1])) +} + +/// Get depth. Returns bits per pixel. +pub fn framebuffer_get_depth() -> PropertyMailboxResult { + let ret = send_one_tag!(RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH, [0])?; + Ok(ret[0]) +} + +/// Set virtual offset. Returns `(X, Y)` in pixel. +/// The response may not be the same as the request so it must be checked. +/// May be the previous offset or 0 for unsupported. +pub fn framebuffer_set_virtual_offset(xoffset: u32, yoffset: u32) -> PropertyMailboxResult<(u32, u32)> { + let ret = send_one_tag!( + RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, + [xoffset, yoffset] + )?; + Ok((ret[0], ret[1])) +} diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index bfaa4f6..f62aad2 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -5,6 +5,7 @@ use once::*; pub mod irq; pub mod timer; pub mod serial; +pub mod mailbox; pub const IO_REMAP_BASE: usize = bcm2837::IO_BASE; pub const IO_REMAP_END: usize = 0x40001000; diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 1d9269f..3edf8cb 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -18,10 +18,12 @@ global_asm!(include_str!("boot/boot.S")); #[no_mangle] // don't mangle the name of this function pub extern "C" fn rust_main() -> ! { memory::init_mmu_early(); // Enable mmu and paging + + crate::logging::init(); + board::init_early(); println!("{}", LOGO); - crate::logging::init(); interrupt::init(); memory::init(); driver::init();