#![no_std]
#![no_main]
use core::fmt::Write;
use rpi_hal::halt;
use rpi_hal::mailbox::{Mailbox, Overscan, PixelOrder};
use rpi_hal::{pac, uart::Uart};
const FALLBACK_WIDTH: u32 = 800;
const FALLBACK_HEIGHT: u32 = 480;
const DEPTH_BITS: u32 = 32;
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
let peripherals = unsafe { pac::Peripherals::steal() };
let mut uart = Uart::init(&peripherals.GPIO, peripherals.UART0);
let _ = writeln!(uart, "PANIC: {info}");
halt();
}
#[no_mangle]
pub extern "C" fn kmain() -> ! {
let peripherals = unsafe { pac::Peripherals::steal() };
let mut uart = Uart::init(&peripherals.GPIO, peripherals.UART0);
let mut mailbox = Mailbox::new(peripherals.VCMAILBOX);
let (width, height) = display_resolution(&mut mailbox, &mut uart);
let framebuffer = match mailbox.allocate_framebuffer(width, height, DEPTH_BITS, PixelOrder::Bgr)
{
Ok(framebuffer) => framebuffer,
Err(e) => {
let _ = writeln!(uart, "framebuffer allocation failed: {e:?}");
halt();
}
};
let _ = writeln!(
uart,
"framebuffer: {}x{} @ {}bpp, address 0x{:08x}, pitch {} bytes, size {} bytes",
framebuffer.width,
framebuffer.height,
framebuffer.depth_bits,
framebuffer.address,
framebuffer.pitch_bytes,
framebuffer.size_bytes
);
draw_color_bars(&framebuffer);
framebuffer.flush();
let _ = writeln!(uart, "pattern drawn -- check the display");
halt();
}
fn display_resolution(mailbox: &mut Mailbox, uart: &mut Uart) -> (u32, u32) {
let border = match mailbox.overscan() {
Ok(border) => {
let _ = writeln!(
uart,
"overscan: top {} bottom {} left {} right {}",
border.top, border.bottom, border.left, border.right
);
border
}
Err(e) => {
let _ = writeln!(uart, "overscan: not reported ({e:?}), assuming none");
Overscan {
top: 0,
bottom: 0,
left: 0,
right: 0,
}
}
};
let inner = match mailbox.display_size() {
Ok(size) if size.width > 0 && size.height > 0 => {
let _ = writeln!(
uart,
"display: firmware reports {}x{} inside the border",
size.width, size.height
);
size
}
other => {
let _ = writeln!(
uart,
"display: no usable size from firmware ({other:?}), \
falling back to {FALLBACK_WIDTH}x{FALLBACK_HEIGHT}"
);
return (FALLBACK_WIDTH, FALLBACK_HEIGHT);
}
};
if border.is_zero() {
return (inner.width, inner.height);
}
let cleared = Overscan {
top: 0,
bottom: 0,
left: 0,
right: 0,
};
if mailbox.set_overscan(cleared).is_err() || !mailbox.overscan().is_ok_and(|o| o.is_zero()) {
let _ = writeln!(
uart,
"overscan: border stayed, drawing inside it at {}x{}",
inner.width, inner.height
);
return (inner.width, inner.height);
}
let full = (
inner.width + border.left + border.right,
inner.height + border.top + border.bottom,
);
let _ = writeln!(
uart,
"overscan: cleared, full mode is {}x{}",
full.0, full.1
);
full
}
fn draw_color_bars(framebuffer: &rpi_hal::mailbox::Framebuffer) {
const COLORS: [u32; 8] = [
0x00FF_FFFF, 0x00FF_FF00, 0x0000_FFFF, 0x0000_FF00, 0x00FF_00FF, 0x00FF_0000, 0x0000_00FF, 0x0000_0000, ];
let base = framebuffer.address as *mut u32;
let pitch_pixels = framebuffer.pitch_bytes / 4;
let bar_width = framebuffer.width / COLORS.len() as u32;
for y in 0..framebuffer.height {
for x in 0..framebuffer.width {
let bar = (x / bar_width).min(COLORS.len() as u32 - 1) as usize;
let offset = y * pitch_pixels + x;
unsafe { base.add(offset as usize).write_volatile(COLORS[bar]) };
}
}
}