Extract common framebuffer driver from aarch64

Signed-off-by: Harry Chen <i@harrychen.xyz>
master
Harry Chen 6 years ago
parent 0acb65ff74
commit 8bc00324c8

@ -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(); let dtb = std::env::var("DTB").unwrap();
if !Path::new(&dtb).is_file() { if !Path::new(&dtb).is_file() {

@ -2,13 +2,18 @@
use bcm2837::atags::Atags; use bcm2837::atags::Atags;
use once::*; use once::*;
use alloc::string::String;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb; pub mod fb;
pub mod irq; pub mod irq;
pub mod mailbox; pub mod mailbox;
pub mod serial; pub mod serial;
pub mod timer; pub mod timer;
use fb::FramebufferInfo;
pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE; pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE;
pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000; pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000;
@ -41,3 +46,43 @@ pub fn probe_memory() -> Option<(usize, usize)> {
} }
None 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))
}

@ -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<Framebuffer, String> {
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::<usize>();
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::<usize>();
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<Option<Framebuffer>> = 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),
}
}

@ -1,6 +1,7 @@
use once::*; use once::*;
pub mod serial; pub mod serial;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb; pub mod fb;
#[path = "../../../../drivers/console/mod.rs"] #[path = "../../../../drivers/console/mod.rs"]
pub mod console; pub mod console;
@ -17,3 +18,19 @@ pub fn init_driver() {
// TODO: add possibly more drivers // TODO: add possibly more drivers
// timer::init(); // 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))
}

@ -3,6 +3,9 @@
use crate::util::color::ConsoleColor; use crate::util::color::ConsoleColor;
pub trait FramebufferColor { pub trait FramebufferColor {
/// pack as 8-bit integer
fn pack8(&self) -> u8;
/// pack as 16-bit integer /// pack as 16-bit integer
fn pack16(&self) -> u16; fn pack16(&self) -> u16;
@ -42,6 +45,12 @@ impl From<ConsoleColor> for RgbColor {
} }
impl FramebufferColor for RgbColor { impl FramebufferColor for RgbColor {
#[inline]
fn pack8(&self) -> u8 {
// RGB332
((self.0 >> 5) << 5) | ((self.1 >> 5) << 2) | (self.2 >> 6)
}
#[inline] #[inline]
fn pack16(&self) -> u16 { fn pack16(&self) -> u16 {
// BGR565 // BGR565
@ -58,6 +67,11 @@ impl FramebufferColor for RgbColor {
} }
impl FramebufferColor for ConsoleColor { impl FramebufferColor for ConsoleColor {
#[inline]
fn pack8(&self) -> u8 {
RgbColor::from(*self).pack8()
}
#[inline] #[inline]
fn pack16(&self) -> u16 { fn pack16(&self) -> u16 {
RgbColor::from(*self).pack16() RgbColor::from(*self).pack16()

@ -63,6 +63,10 @@ impl<F: Font> ConsoleBuffer<F> {
let off_y = row * F::HEIGHT; let off_y = row * F::HEIGHT;
if let Some(fb) = FRAME_BUFFER.lock().as_mut() { if let Some(fb) = FRAME_BUFFER.lock().as_mut() {
let (mut foreground, mut background) = match fb.color_depth { let (mut foreground, mut background) = match fb.color_depth {
ColorDepth8 => (
ch.attr.foreground.pack8() as u32,
ch.attr.background.pack8() as u32,
),
ColorDepth16 => ( ColorDepth16 => (
ch.attr.foreground.pack16() as u32, ch.attr.foreground.pack16() as u32,
ch.attr.background.pack16() as u32, ch.attr.background.pack16() as u32,

@ -1,6 +1,5 @@
//! Framebuffer //! Framebuffer
use super::mailbox;
use alloc::string::String; use alloc::string::String;
use core::fmt; use core::fmt;
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -40,6 +39,7 @@ pub struct FramebufferInfo {
#[repr(u32)] #[repr(u32)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum ColorDepth { pub enum ColorDepth {
ColorDepth8 = 8,
ColorDepth16 = 16, ColorDepth16 = 16,
ColorDepth32 = 32, ColorDepth32 = 32,
} }
@ -48,6 +48,7 @@ use self::ColorDepth::*;
#[repr(C)] #[repr(C)]
union ColorBuffer { union ColorBuffer {
base_addr: usize, base_addr: usize,
buf8: &'static mut [u8],
buf16: &'static mut [u16], buf16: &'static mut [u16],
buf32: &'static mut [u32], buf32: &'static mut [u32],
} }
@ -56,6 +57,9 @@ impl ColorBuffer {
fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer { fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer {
unsafe { unsafe {
match color_depth { match color_depth {
ColorDepth8 => ColorBuffer {
buf8: core::slice::from_raw_parts_mut(base_addr as *mut u8, size),
},
ColorDepth16 => ColorBuffer { ColorDepth16 => ColorBuffer {
buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2), 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] #[inline]
fn read16(&self, index: u32) -> u16 { fn read16(&self, index: u32) -> u16 {
unsafe { self.buf16[index as usize] } unsafe { self.buf16[index as usize] }
@ -76,6 +85,11 @@ impl ColorBuffer {
unsafe { self.buf32[index as usize] } unsafe { self.buf32[index as usize] }
} }
#[inline]
fn write8(&mut self, index: u32, pixel: u8) {
unsafe { self.buf8[index as usize] = pixel }
}
#[inline] #[inline]
fn write16(&mut self, index: u32, pixel: u16) { fn write16(&mut self, index: u32, pixel: u16) {
unsafe { self.buf16[index as usize] = pixel } unsafe { self.buf16[index as usize] = pixel }
@ -108,49 +122,27 @@ impl Framebuffer {
fn new(width: u32, height: u32, depth: u32) -> Result<Framebuffer, String> { fn new(width: u32, height: u32, depth: u32) -> Result<Framebuffer, String> {
assert_has_not_been_called!("Framebuffer::new must be called only once"); assert_has_not_been_called!("Framebuffer::new must be called only once");
let (width, height) = if width == 0 || height == 0 { let probed_info = super::probe_fb_info(width, height, depth);
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)?; match probed_info {
Ok((info, addr)) => {
let color_depth = match info.depth { let color_depth = match info.depth {
8 => ColorDepth8,
16 => ColorDepth16, 16 => ColorDepth16,
32 => ColorDepth32, 32 => ColorDepth32,
_ => Err(format!("unsupported color depth {}", info.depth))?, _ => 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 { Ok(Framebuffer {
buf: ColorBuffer::new(color_depth, vaddr, info.screen_size as usize), buf: ColorBuffer::new(color_depth, addr, info.screen_size as usize),
color_depth, color_depth,
fb_info: info, fb_info: info,
}) })
},
Err(e) => {
Err(e)?
},
}
} }
#[inline] #[inline]
@ -162,6 +154,7 @@ impl Framebuffer {
#[inline] #[inline]
pub fn read(&self, x: u32, y: u32) -> u32 { pub fn read(&self, x: u32, y: u32) -> u32 {
match self.color_depth { 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, ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32,
ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x), ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x),
} }
@ -171,6 +164,7 @@ impl Framebuffer {
#[inline] #[inline]
pub fn write(&mut self, x: u32, y: u32, pixel: u32) { pub fn write(&mut self, x: u32, y: u32, pixel: u32) {
match self.color_depth { 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), ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16),
ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel), ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel),
} }
Loading…
Cancel
Save