use core::slice; use crate::{ aarch64::mmu::GRANULARITY, configuration::memory_mapping::MAILBOX_PHYSICAL_ADDRESS, configuration::memory_mapping::MAILBOX_VIRTUAL_ADDRESS, read_address, write_address, }; use nova_error::NovaError; const MBOX_BASE: u32 = 0x3F00_0000 + 0xB880; // MB0 const MBOX_READ: u32 = MBOX_BASE; const MBOX_STATUS: u32 = MBOX_BASE + 0x18; // MB1 const MBOX_WRITE: u32 = MBOX_BASE + 0x20; // Status const MAIL_FULL: u32 = 0x80000000; const MAIL_EMPTY: u32 = 0x40000000; const HEADER_LENGTH: usize = 4 + 4 + 4 + 4 + 4; // Total Size + Request + Tag + MaxBufferLength + RequestLength const FOOTER_LENGTH: usize = 4; macro_rules! max { ($a:expr, $b:expr) => {{ const M: usize = if $a > $b { $a as usize } else { $b as usize }; M }}; } #[macro_export] macro_rules! mailbox_command { ($name:ident, $tag:expr, $request_len:expr,$response_len:expr) => { /// More information at: pub fn $name( request_data: [u32; $request_len / 4], ) -> Result<[u32; $response_len / 4], NovaError> { let mailbox = unsafe { slice::from_raw_parts_mut(MAILBOX_VIRTUAL_ADDRESS as *mut u32, GRANULARITY / 4) }; mailbox[0] = (HEADER_LENGTH + max!($request_len, $response_len) + FOOTER_LENGTH) as u32; // Total length in Bytes mailbox[1] = 0; // Request mailbox[2] = $tag; // Command Tag mailbox[3] = max!($request_len, $response_len) as u32; // Max value buffer size mailbox[4] = $request_len; mailbox[5..(5 + ($request_len / 4))].copy_from_slice(&request_data); mailbox[(5 + ($request_len / 4))..].fill(0); //let addr = core::ptr::addr_of!(mailbox[0]) as u32; write_mailbox(8, unsafe { MAILBOX_PHYSICAL_ADDRESS.unwrap() } as u32); let _ = read_mailbox(8); if mailbox[1] == 0 { return Err(NovaError::Mailbox); } let mut out = [0u32; $response_len / 4]; out.copy_from_slice(&mailbox[5..(5 + $response_len / 4)]); Ok(out) } }; } mailbox_command!(read_soc_temp, 0x0003_0006, 4, 8); // Framebuffer mailbox_command!(get_display_resolution, 0x0004_0003, 0, 8); pub fn read_mailbox(channel: u32) -> u32 { // Wait until mailbox is not empty loop { while unsafe { read_address(MBOX_STATUS) } & MAIL_EMPTY != 0 {} let mut data = unsafe { read_address(MBOX_READ) }; let read_channel = data & 0xF; data >>= 4; if channel == read_channel { return data; } } } pub fn write_mailbox(channel: u32, data: u32) { while unsafe { read_address(MBOX_STATUS) } & MAIL_FULL != 0 {} unsafe { write_address(MBOX_WRITE, (data & !0xF) | (channel & 0xF)) }; }