diff --git a/src/main.rs b/src/main.rs index 1905f44..1f12b2f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ #![doc(html_root_url = "https://docs.metta.systems/")] #![allow(dead_code)] #![allow(unused_assignments)] +#![allow(unused_must_use)] #[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))] use architecture_not_supported_sorry; @@ -27,7 +28,11 @@ pub mod arch; pub use arch::*; pub mod platform; -use platform::{display::Size2d, uart::MiniUart}; +use platform::{ + display::{Color, Size2d}, + uart::MiniUart, + vc::VC, +}; // User-facing kernel parts - syscalls and capability invocations. // pub mod vesper; -- no mod exported, because available through syscall interface @@ -48,6 +53,16 @@ pub fn kmain() -> ! { uart.init(); uart.puts("Hey there, mini uart talking!"); + if let Some(mut display) = VC::init_fb(Size2d { x: 800, y: 600 }) { + display.rect(100, 100, 200, 200, Color::rgb(255, 255, 255).0); + display.draw_text(50, 50, "Hello there!", Color::rgb(128, 192, 255).0); + // display.draw_text(50, 150, core::fmt("Display width {}", display.width), Color::rgb(255,0,0).0); + + display.draw_text(150, 50, "RED", Color::rgb(255, 0, 0).0); + display.draw_text(160, 60, "GREEN", Color::rgb(0, 255, 0).0); + display.draw_text(170, 70, "BLUE", Color::rgb(0, 0, 255).0); + } + uart.puts("Bye, going to sleep now"); endless_sleep() } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 15ce432..3b2df5c 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -3,3 +3,4 @@ pub mod gpio; pub mod mailbox; pub mod rpi3; pub mod uart; +pub mod vc; diff --git a/src/platform/vc.rs b/src/platform/vc.rs new file mode 100644 index 0000000..02bcfc8 --- /dev/null +++ b/src/platform/vc.rs @@ -0,0 +1,198 @@ +use platform::display::{Display, PixelOrder, Size2d, CHARSIZE_X, CHARSIZE_Y}; +use platform::mailbox::{self, channel, tag, GpuFb, Mailbox, response::VAL_LEN_FLAG}; +use platform::rpi3::bus2phys; + +pub struct VC; + +impl VC { + // Use mailbox framebuffer interface to initialize + pub fn init_fb(size: Size2d) -> Option { + let mut fb_info: GpuFb = GpuFb::new(size, 24); + + fb_info.call().map_err(|_| ()); + +// let mut pixel_order = Mailbox::new(); +// +// pixel_order.buffer[0] = 24; +// pixel_order.buffer[1] = mailbox::REQUEST; +// pixel_order.buffer[2] = tag::SetPixelOrder; +// pixel_order.buffer[3] = 4; +// pixel_order.buffer[4] = 4; +// pixel_order.buffer[5] = 0; // 0 - BGR, 1 - RGB +// +// pixel_order.call(channel::PropertyTagsArmToVc).map_err(|_| ()); + + /* Need to set up max_x/max_y before using Display::write */ + let max_x = fb_info.vwidth / CHARSIZE_X; + let max_y = fb_info.vheight / CHARSIZE_Y; + + Some(Display::new( + bus2phys(fb_info.pointer), + fb_info.size, + fb_info.pitch, + max_x, + max_y, + fb_info.vwidth, + fb_info.vheight, + PixelOrder::BGR, + )) + } + /* + fn get_display_size() -> Option { + let mut mbox = Mbox::new(); + + mbox.0[0] = 8 * 4; // Total size + mbox.0[1] = MAILBOX_REQ_CODE; // Request + mbox.0[2] = Tag::GetPhysicalWH as u32; // Display size // tag + mbox.0[3] = 8; // Buffer size // val buf size + mbox.0[4] = 0; // Request size // val size + mbox.0[5] = 0; // Space for horizontal resolution + mbox.0[6] = 0; // Space for vertical resolution + mbox.0[7] = Tag::End as u32; // End tag + + Mailbox::call(Channel::PropertyTagsArmToVc as u8, &mbox.0 as *const u32 as *const u8)?; + + if mbox.0[1] != MAILBOX_RESP_CODE_SUCCESS { + return None; + } + if mbox.0[5] == 0 && mbox.0[6] == 0 { + // Qemu emulation returns 0x0 + return Some(Size2d { x: 640, y: 480 }); + } + Some(Size2d { + x: mbox.0[5], + y: mbox.0[6], + }) + } + + fn set_display_size(size: Size2d) -> Option { + // @todo Make Display use VC functions internally instead + let mut mbox = Mbox::new(); + let mut count: usize = 0; + + count += 1; + mbox.0[count] = MAILBOX_REQ_CODE; // Request + count += 1; + mbox.0[count] = Tag::SetPhysicalWH as u32; + count += 1; + mbox.0[count] = 8; // Buffer size // val buf size + count += 1; + mbox.0[count] = 8; // Request size // val size + count += 1; + mbox.0[count] = size.x; // Space for horizontal resolution + count += 1; + mbox.0[count] = size.y; // Space for vertical resolution + count += 1; + mbox.0[count] = Tag::SetVirtualWH as u32; + count += 1; + mbox.0[count] = 8; // Buffer size // val buf size + count += 1; + mbox.0[count] = 8; // Request size // val size + count += 1; + mbox.0[count] = size.x; // Space for horizontal resolution + count += 1; + mbox.0[count] = size.y; // Space for vertical resolution + count += 1; + mbox.0[count] = Tag::SetDepth as u32; + count += 1; + mbox.0[count] = 4; // Buffer size // val buf size + count += 1; + mbox.0[count] = 4; // Request size // val size + count += 1; + mbox.0[count] = 16; // 16 bpp + count += 1; + mbox.0[count] = Tag::AllocateBuffer as u32; + count += 1; + mbox.0[count] = 8; // Buffer size // val buf size + count += 1; + mbox.0[count] = 4; // Request size // val size + count += 1; + mbox.0[count] = 4096; // Alignment = 4096 + count += 1; + mbox.0[count] = 0; // Space for response + count += 1; + mbox.0[count] = Tag::End as u32; + mbox.0[0] = (count * 4) as u32; // Total size + + let max_count = count; + + Mailbox::call(Channel::PropertyTagsArmToVc as u8, &mbox.0 as *const u32 as *const u8)?; + + if mbox.0[1] != MAILBOX_RESP_CODE_SUCCESS { + return None; + } + + count = 2; /* First tag */ + while mbox.0[count] != 0 { + if mbox.0[count] == Tag::AllocateBuffer as u32 { + break; + } + + /* Skip to next tag + * Advance count by 1 (tag) + 2 (buffer size/value size) + * + specified buffer size + */ + count += 3 + (mbox.0[count + 1] / 4) as usize; + + if count > max_count { + return None; + } + } + + /* Must be 8 bytes, plus MSB set to indicate a response */ + if mbox.0[count + 2] != 0x8000_0008 { + return None; + } + + /* Framebuffer address/size in response */ + let physical_screenbase = mbox.0[count + 3]; + let screensize = mbox.0[count + 4]; + + if physical_screenbase == 0 || screensize == 0 { + return None; + } + + /* physical_screenbase is the address of the screen in RAM + * screenbase needs to be the screen address in virtual memory + */ + // screenbase=mem_p2v(physical_screenbase); + let screenbase = physical_screenbase; + + /* Get the framebuffer pitch (bytes per line) */ + mbox.0[0] = 7 * 4; // Total size + mbox.0[1] = 0; // Request + mbox.0[2] = Tag::GetPitch as u32; // Display size + mbox.0[3] = 4; // Buffer size + mbox.0[4] = 0; // Request size + mbox.0[5] = 0; // Space for pitch + mbox.0[6] = Tag::End as u32; + + Mailbox::call(Channel::PropertyTagsArmToVc as u8, &mbox.0 as *const u32 as *const u8)?; + + if mbox.0[1] != MAILBOX_RESP_CODE_SUCCESS { + return None; + } + + /* Must be 4 bytes, plus MSB set to indicate a response */ + if mbox.0[4] != 0x8000_0004 { + return None; + } + + let pitch = mbox.0[5]; + if pitch == 0 { + return None; + } + + /* Need to set up max_x/max_y before using Display::write */ + let max_x = size.x / CHARSIZE_X; + let max_y = size.y / CHARSIZE_Y; + + Some(Display { + base: screenbase, + size: screensize, + pitch: pitch, + max_x: max_x, + max_y: max_y, + }) + }*/ +}