From 8bc00324c8aaa2d631f45f543f9bb8ad8ac03bcb Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Thu, 4 Apr 2019 00:10:18 +0800 Subject: [PATCH] Extract common framebuffer driver from aarch64 Signed-off-by: Harry Chen --- kernel/build.rs | 2 +- kernel/src/arch/aarch64/board/raspi3/mod.rs | 45 ++++ kernel/src/arch/mipsel/board/thinpad/fb.rs | 232 ------------------ kernel/src/arch/mipsel/board/thinpad/mod.rs | 17 ++ kernel/src/drivers/console/color.rs | 14 ++ kernel/src/drivers/console/mod.rs | 4 + .../board/raspi3 => drivers/gpu}/fb.rs | 78 +++--- 7 files changed, 117 insertions(+), 275 deletions(-) delete mode 100644 kernel/src/arch/mipsel/board/thinpad/fb.rs rename kernel/src/{arch/aarch64/board/raspi3 => drivers/gpu}/fb.rs (78%) diff --git a/kernel/build.rs b/kernel/build.rs index 3a0945f..3efcadb 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -53,7 +53,7 @@ fn gen_vector_asm() -> Result<()> { } -fn gen_dtb_asm(arch: &String, board: &String) -> Result<()> { +fn gen_dtb_asm(arch: &String, _board: &String) -> Result<()> { let dtb = std::env::var("DTB").unwrap(); if !Path::new(&dtb).is_file() { diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index 713c725..9b2a66b 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -2,13 +2,18 @@ use bcm2837::atags::Atags; use once::*; +use alloc::string::String; + +#[path = "../../../../drivers/gpu/fb.rs"] pub mod fb; pub mod irq; pub mod mailbox; pub mod serial; pub mod timer; +use fb::FramebufferInfo; + pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE; pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000; @@ -41,3 +46,43 @@ pub fn probe_memory() -> Option<(usize, usize)> { } None } + +pub fn probe_fb_info(width: u32, height: u32, depth: u32) -> Result<(FramebufferInfo, usize), String> { + + let (width, height) = if width == 0 || height == 0 { + mailbox::framebuffer_get_physical_size()? + } else { + (width, height) + }; + + let depth = if depth == 0 { + mailbox::framebuffer_get_depth()? + } else { + depth + }; + + let info = mailbox::framebuffer_alloc(width, height, depth)?; + + if info.bus_addr == 0 || info.screen_size == 0 { + Err(format!("mailbox call returned an invalid address/size"))?; + } + if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 { + Err(format!( + "mailbox call returned an invalid pitch value {}", + info.pitch + ))?; + } + + use crate::arch::memory; + let paddr = info.bus_addr & !0xC0000000; + let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb"); + if vaddr == 0 { + Err(format!( + "cannot remap memory range [{:#x?}..{:#x?}]", + paddr, + paddr + info.screen_size + ))?; + } + + Ok((info, vaddr)) +} \ No newline at end of file diff --git a/kernel/src/arch/mipsel/board/thinpad/fb.rs b/kernel/src/arch/mipsel/board/thinpad/fb.rs deleted file mode 100644 index ff3b31f..0000000 --- a/kernel/src/arch/mipsel/board/thinpad/fb.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! Framebuffer - -use super::mailbox; -use alloc::string::String; -use core::fmt; -use lazy_static::lazy_static; -use log::*; -use once::*; -use spin::Mutex; - -/// Framebuffer information -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct FramebufferInfo { - /// visible width - pub xres: u32, - /// visible height - pub yres: u32, - /// virtual width - pub xres_virtual: u32, - /// virtual height - pub yres_virtual: u32, - /// virtual offset x - pub xoffset: u32, - /// virtual offset y - pub yoffset: u32, - - /// bits per pixel - pub depth: u32, - /// bytes per line - pub pitch: u32, - - /// bus address, starts from 0xC0000000/0x40000000 - /// (see https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes) - pub bus_addr: u32, - /// screen buffer size - pub screen_size: u32, -} - -#[repr(u32)] -#[derive(Debug, Clone, Copy)] -pub enum ColorDepth { - ColorDepth16 = 16, - ColorDepth32 = 32, -} -use self::ColorDepth::*; - -#[repr(C)] -union ColorBuffer { - base_addr: usize, - buf16: &'static mut [u16], - buf32: &'static mut [u32], -} - -impl ColorBuffer { - fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer { - unsafe { - match color_depth { - ColorDepth16 => ColorBuffer { - buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2), - }, - ColorDepth32 => ColorBuffer { - buf32: core::slice::from_raw_parts_mut(base_addr as *mut u32, size / 4), - }, - } - } - } - - #[inline] - fn read16(&self, index: u32) -> u16 { - unsafe { self.buf16[index as usize] } - } - - #[inline] - fn read32(&self, index: u32) -> u32 { - unsafe { self.buf32[index as usize] } - } - - #[inline] - fn write16(&mut self, index: u32, pixel: u16) { - unsafe { self.buf16[index as usize] = pixel } - } - - #[inline] - fn write32(&mut self, index: u32, pixel: u32) { - unsafe { self.buf32[index as usize] = pixel } - } -} - -/// Frambuffer structure -pub struct Framebuffer { - pub fb_info: FramebufferInfo, - pub color_depth: ColorDepth, - buf: ColorBuffer, -} - -impl fmt::Debug for Framebuffer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut f = f.debug_struct("Framebuffer"); - f.field("fb_info", &self.fb_info); - f.field("color_depth", &self.color_depth); - f.field("base_addr", unsafe { &self.buf.base_addr }); - f.finish() - } -} - -impl Framebuffer { - fn new(width: u32, height: u32, depth: u32) -> Result { - assert_has_not_been_called!("Framebuffer::new must be called only once"); - - let (width, height) = if width == 0 || height == 0 { - mailbox::framebuffer_get_physical_size()? - } else { - (width, height) - }; - let depth = if depth == 0 { - mailbox::framebuffer_get_depth()? - } else { - depth - }; - - let info = mailbox::framebuffer_alloc(width, height, depth)?; - let color_depth = match info.depth { - 16 => ColorDepth16, - 32 => ColorDepth32, - _ => Err(format!("unsupported color depth {}", info.depth))?, - }; - - if info.bus_addr == 0 || info.screen_size == 0 { - Err(format!("mailbox call returned an invalid address/size"))?; - } - if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 { - Err(format!( - "mailbox call returned an invalid pitch value {}", - info.pitch - ))?; - } - - use crate::arch::memory; - let paddr = info.bus_addr & !0xC0000000; - let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb"); - if vaddr == 0 { - Err(format!( - "cannot remap memory range [{:#x?}..{:#x?}]", - paddr, - paddr + info.screen_size - ))?; - } - Ok(Framebuffer { - buf: ColorBuffer::new(color_depth, vaddr, info.screen_size as usize), - color_depth, - fb_info: info, - }) - } - - #[inline] - pub fn base_addr(&self) -> usize { - unsafe { self.buf.base_addr } - } - - /// Read pixel at `(x, y)`. - #[inline] - pub fn read(&self, x: u32, y: u32) -> u32 { - match self.color_depth { - ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32, - ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x), - } - } - - /// Write pixel at `(x, y)`. - #[inline] - pub fn write(&mut self, x: u32, y: u32, pixel: u32) { - match self.color_depth { - ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16), - ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel), - } - } - - /// Copy buffer `[src_off .. src_off + size]` to `[dst_off .. dst_off + size]`. - /// `dst_off`, `src_off` and `size` must be aligned with `usize`. - pub fn copy(&mut self, dst_off: usize, src_off: usize, size: usize) { - const USIZE: usize = core::mem::size_of::(); - let mut dst = self.base_addr() + dst_off; - let mut src = self.base_addr() + src_off; - let src_end = src + size; - while src < src_end { - unsafe { *(dst as *mut usize) = *(src as *mut usize) } - dst += USIZE; - src += USIZE; - } - } - - /// Fill buffer `[offset .. offset + size]` with `pixel`. - /// `offset` and `size` must be aligned with `usize`. - pub fn fill(&mut self, offset: usize, size: usize, pixel: u32) { - const USIZE: usize = core::mem::size_of::(); - let mut value: usize = 0; - let repeat = USIZE * 8 / self.fb_info.depth as usize; - let mask = ((1u64 << self.fb_info.depth) - 1) as usize; - for _i in 0..repeat { - value <<= self.fb_info.depth; - value += pixel as usize & mask; - } - - let mut start = self.base_addr() + offset; - let end = start + size; - while start < end { - unsafe { *(start as *mut usize) = value } - start += USIZE; - } - } - - /// Fill the entire buffer with `0`. - pub fn clear(&mut self) { - self.fill(0, self.fb_info.screen_size as usize, 0); - } -} - -lazy_static! { - pub static ref FRAME_BUFFER: Mutex> = Mutex::new(None); -} - -/// Initialize framebuffer -pub fn init() { - match Framebuffer::new(0, 0, 0) { - Ok(fb) => { - info!("framebuffer: init end\n{:#x?}", fb); - *FRAME_BUFFER.lock() = Some(fb); - } - Err(err) => warn!("framebuffer init failed: {}", err), - } -} diff --git a/kernel/src/arch/mipsel/board/thinpad/mod.rs b/kernel/src/arch/mipsel/board/thinpad/mod.rs index dbfbb84..6c480f4 100644 --- a/kernel/src/arch/mipsel/board/thinpad/mod.rs +++ b/kernel/src/arch/mipsel/board/thinpad/mod.rs @@ -1,6 +1,7 @@ use once::*; pub mod serial; +#[path = "../../../../drivers/gpu/fb.rs"] pub mod fb; #[path = "../../../../drivers/console/mod.rs"] pub mod console; @@ -16,4 +17,20 @@ pub fn init_serial_early() { pub fn init_driver() { // TODO: add possibly more drivers // timer::init(); +} + +pub fn probe_fb_info(width: u32, height: u32, depth: u32) -> Result<(FramebufferInfo, u32), String> { + let fb_info = FramebufferInfo { + xres: 800, + yres: 600, + xres_virtual: 800, + yres_virtual: 600, + xoffset: 0, + yoffset: 0, + depth: 8, + pitch: 800, + bus_addr: 0xa2000000, + screen_size: 800 * 600, + } + Ok((fb_info, 0xa2000000)) } \ No newline at end of file diff --git a/kernel/src/drivers/console/color.rs b/kernel/src/drivers/console/color.rs index 419df50..1936fb8 100644 --- a/kernel/src/drivers/console/color.rs +++ b/kernel/src/drivers/console/color.rs @@ -3,6 +3,9 @@ use crate::util::color::ConsoleColor; pub trait FramebufferColor { + /// pack as 8-bit integer + fn pack8(&self) -> u8; + /// pack as 16-bit integer fn pack16(&self) -> u16; @@ -42,6 +45,12 @@ impl From for RgbColor { } impl FramebufferColor for RgbColor { + #[inline] + fn pack8(&self) -> u8 { + // RGB332 + ((self.0 >> 5) << 5) | ((self.1 >> 5) << 2) | (self.2 >> 6) + } + #[inline] fn pack16(&self) -> u16 { // BGR565 @@ -58,6 +67,11 @@ impl FramebufferColor for RgbColor { } impl FramebufferColor for ConsoleColor { + #[inline] + fn pack8(&self) -> u8 { + RgbColor::from(*self).pack8() + } + #[inline] fn pack16(&self) -> u16 { RgbColor::from(*self).pack16() diff --git a/kernel/src/drivers/console/mod.rs b/kernel/src/drivers/console/mod.rs index b16ae13..29d56be 100644 --- a/kernel/src/drivers/console/mod.rs +++ b/kernel/src/drivers/console/mod.rs @@ -63,6 +63,10 @@ impl ConsoleBuffer { let off_y = row * F::HEIGHT; if let Some(fb) = FRAME_BUFFER.lock().as_mut() { let (mut foreground, mut background) = match fb.color_depth { + ColorDepth8 => ( + ch.attr.foreground.pack8() as u32, + ch.attr.background.pack8() as u32, + ), ColorDepth16 => ( ch.attr.foreground.pack16() as u32, ch.attr.background.pack16() as u32, diff --git a/kernel/src/arch/aarch64/board/raspi3/fb.rs b/kernel/src/drivers/gpu/fb.rs similarity index 78% rename from kernel/src/arch/aarch64/board/raspi3/fb.rs rename to kernel/src/drivers/gpu/fb.rs index ff3b31f..d5f7021 100644 --- a/kernel/src/arch/aarch64/board/raspi3/fb.rs +++ b/kernel/src/drivers/gpu/fb.rs @@ -1,6 +1,5 @@ //! Framebuffer -use super::mailbox; use alloc::string::String; use core::fmt; use lazy_static::lazy_static; @@ -40,6 +39,7 @@ pub struct FramebufferInfo { #[repr(u32)] #[derive(Debug, Clone, Copy)] pub enum ColorDepth { + ColorDepth8 = 8, ColorDepth16 = 16, ColorDepth32 = 32, } @@ -48,6 +48,7 @@ use self::ColorDepth::*; #[repr(C)] union ColorBuffer { base_addr: usize, + buf8: &'static mut [u8], buf16: &'static mut [u16], buf32: &'static mut [u32], } @@ -56,6 +57,9 @@ impl ColorBuffer { fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer { unsafe { match color_depth { + ColorDepth8 => ColorBuffer { + buf8: core::slice::from_raw_parts_mut(base_addr as *mut u8, size), + }, ColorDepth16 => ColorBuffer { buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2), }, @@ -66,6 +70,11 @@ impl ColorBuffer { } } + #[inline] + fn read8(&self, index: u32) -> u8 { + unsafe { self.buf8[index as usize] } + } + #[inline] fn read16(&self, index: u32) -> u16 { unsafe { self.buf16[index as usize] } @@ -76,6 +85,11 @@ impl ColorBuffer { unsafe { self.buf32[index as usize] } } + #[inline] + fn write8(&mut self, index: u32, pixel: u8) { + unsafe { self.buf8[index as usize] = pixel } + } + #[inline] fn write16(&mut self, index: u32, pixel: u16) { unsafe { self.buf16[index as usize] = pixel } @@ -108,49 +122,27 @@ impl Framebuffer { fn new(width: u32, height: u32, depth: u32) -> Result { assert_has_not_been_called!("Framebuffer::new must be called only once"); - let (width, height) = if width == 0 || height == 0 { - mailbox::framebuffer_get_physical_size()? - } else { - (width, height) - }; - let depth = if depth == 0 { - mailbox::framebuffer_get_depth()? - } else { - depth - }; - - let info = mailbox::framebuffer_alloc(width, height, depth)?; - let color_depth = match info.depth { - 16 => ColorDepth16, - 32 => ColorDepth32, - _ => Err(format!("unsupported color depth {}", info.depth))?, - }; - - if info.bus_addr == 0 || info.screen_size == 0 { - Err(format!("mailbox call returned an invalid address/size"))?; - } - if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 { - Err(format!( - "mailbox call returned an invalid pitch value {}", - info.pitch - ))?; + let probed_info = super::probe_fb_info(width, height, depth); + + match probed_info { + Ok((info, addr)) => { + let color_depth = match info.depth { + 8 => ColorDepth8, + 16 => ColorDepth16, + 32 => ColorDepth32, + _ => Err(format!("unsupported color depth {}", info.depth))?, + }; + Ok(Framebuffer { + buf: ColorBuffer::new(color_depth, addr, info.screen_size as usize), + color_depth, + fb_info: info, + }) + }, + Err(e) => { + Err(e)? + }, } - use crate::arch::memory; - let paddr = info.bus_addr & !0xC0000000; - let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb"); - if vaddr == 0 { - Err(format!( - "cannot remap memory range [{:#x?}..{:#x?}]", - paddr, - paddr + info.screen_size - ))?; - } - Ok(Framebuffer { - buf: ColorBuffer::new(color_depth, vaddr, info.screen_size as usize), - color_depth, - fb_info: info, - }) } #[inline] @@ -162,6 +154,7 @@ impl Framebuffer { #[inline] pub fn read(&self, x: u32, y: u32) -> u32 { match self.color_depth { + ColorDepth8 => self.buf.read8(y * self.fb_info.xres + x) as u32, ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32, ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x), } @@ -171,6 +164,7 @@ impl Framebuffer { #[inline] pub fn write(&mut self, x: u32, y: u32, pixel: u32) { match self.color_depth { + ColorDepth8 => self.buf.write8(y * self.fb_info.xres + x, pixel as u8), ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16), ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel), }