feat: mach_orangepi3 feature parity with mach_qemu
This commit is contained in:
parent
e21d7fdd59
commit
ea7eb300f7
@ -1,10 +1,10 @@
|
|||||||
//! aarch64 common boot logic
|
//! aarch64 common boot logic
|
||||||
|
|
||||||
use crate::arch::aarch64::asm::{CPACR_EL1};
|
use crate::arch::{aarch64::asm::CPACR_EL1, machine};
|
||||||
use cortex_a::registers::{VBAR_EL1, SCTLR_EL1};
|
use crate::dev::{Device, serial::SerialDevice, timer::TimestampSource};
|
||||||
use tock_registers::interfaces::{Writeable, ReadWriteable};
|
|
||||||
|
|
||||||
use cortex_a::asm::barrier::{self, dsb, isb};
|
use cortex_a::asm::barrier::{self, dsb, isb};
|
||||||
|
use cortex_a::registers::{SCTLR_EL1, VBAR_EL1};
|
||||||
|
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn __aa64_bsp_main() {
|
fn __aa64_bsp_main() {
|
||||||
@ -21,44 +21,25 @@ fn __aa64_bsp_main() {
|
|||||||
dsb(barrier::SY);
|
dsb(barrier::SY);
|
||||||
isb(barrier::SY);
|
isb(barrier::SY);
|
||||||
|
|
||||||
SCTLR_EL1.modify(SCTLR_EL1::I::SET +
|
SCTLR_EL1
|
||||||
SCTLR_EL1::SA::SET +
|
.modify(SCTLR_EL1::I::SET + SCTLR_EL1::SA::SET + SCTLR_EL1::C::SET + SCTLR_EL1::A::SET);
|
||||||
SCTLR_EL1::C::SET +
|
|
||||||
SCTLR_EL1::A::SET);
|
|
||||||
|
|
||||||
dsb(barrier::SY);
|
dsb(barrier::SY);
|
||||||
isb(barrier::SY);
|
isb(barrier::SY);
|
||||||
}
|
}
|
||||||
|
|
||||||
debugln!("Test");
|
machine::init_board().unwrap();
|
||||||
|
|
||||||
let mut el: u64;
|
|
||||||
let mut sctlr_el1: u64;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mrs {}, currentel", out(reg) el);
|
machine::local_timer().lock().enable().unwrap();
|
||||||
asm!("mrs {}, sctlr_el1", out(reg) sctlr_el1);
|
|
||||||
}
|
}
|
||||||
el >>= 2;
|
|
||||||
el &= 0x3;
|
|
||||||
|
|
||||||
debugln!("Current EL = {}", el);
|
let base = machine::local_timer().lock().timestamp().unwrap();
|
||||||
debugln!("SCTLR_EL1 = {:#x}", sctlr_el1);
|
|
||||||
|
|
||||||
//use crate::arch::machine;
|
|
||||||
//use crate::dev::{serial::SerialDevice, timer::TimestampSource, Device};
|
|
||||||
|
|
||||||
//unsafe {
|
|
||||||
//machine::console().lock().enable().unwrap();
|
|
||||||
//machine::local_timer().lock().enable().unwrap();
|
|
||||||
//}
|
|
||||||
|
|
||||||
//let base = machine::local_timer().lock().timestamp().unwrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
cortex_a::asm::wfe();
|
let count = machine::local_timer().lock().timestamp().unwrap();
|
||||||
//let count = machine::local_timer().lock().timestamp().unwrap();
|
let ch = machine::console().lock().recv(true).unwrap();
|
||||||
//let ch = machine::console().lock().recv(true).unwrap();
|
debugln!("[{:?}] {:#04x} = '{}'!", count - base, ch, ch as char);
|
||||||
//debugln!("[{:?}] {:#04x} = '{}'!", count - base, ch, ch as char);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
// vi:ft=a64asm.asm:
|
// vi:ft=a64asm.asm:
|
||||||
|
|
||||||
.set UART0_BASE, 0x05000000
|
.set SCTLR_EL2_RES1, 0x30C50830
|
||||||
|
|
||||||
.set SPSR_EL2_EL1h, 0x5
|
.set SPSR_EL2_EL1h, 0x5
|
||||||
.set HCR_EL2_RW, 1 << 31
|
.set SPSR_EL2_MASK_DAIF, 0xF << 6
|
||||||
.set HCR_EL2_HCD, 1 << 29
|
.set HCR_EL2_RW, 1 << 31
|
||||||
|
.set HCR_EL2_HCD, 1 << 29
|
||||||
|
|
||||||
|
.set CNTHCTL_EL2_EL1PCEN, 1 << 1
|
||||||
|
.set CNTHCTL_EL2_EL1PCTEN, 1 << 0
|
||||||
|
|
||||||
.macro ADR_REL reg, sym
|
.macro ADR_REL reg, sym
|
||||||
adrp \reg, \sym
|
adrp \reg, \sym
|
||||||
add \reg, \reg, #:lo12:\sym
|
add \reg, \reg, #:lo12:\sym
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro MOV_L reg, value
|
||||||
|
mov \reg, #((\value) & 0xFFFF)
|
||||||
|
movk \reg, #((\value) >> 16), lsl #16
|
||||||
|
.endm
|
||||||
|
|
||||||
.section .text._entry
|
.section .text._entry
|
||||||
.global _entry
|
.global _entry
|
||||||
_entry:
|
_entry:
|
||||||
@ -19,16 +28,27 @@ _entry:
|
|||||||
lsr x0, x0, #2
|
lsr x0, x0, #2
|
||||||
cmp x0, #2
|
cmp x0, #2
|
||||||
bne 1f
|
bne 1f
|
||||||
|
|
||||||
// Exit EL2
|
// Exit EL2
|
||||||
// TODO cnthtctl_el2 setup
|
mrs x0, cnthctl_el2
|
||||||
|
orr x0, x0, #(CNTHCTL_EL2_EL1PCTEN | CNTHCTL_EL2_EL1PCEN)
|
||||||
|
msr cnthctl_el2, x0
|
||||||
|
msr cntvoff_el2, xzr
|
||||||
|
|
||||||
|
MOV_L x0, SCTLR_EL2_RES1
|
||||||
|
msr sctlr_el2, x0
|
||||||
|
|
||||||
|
mov x0, #HCR_EL2_RW
|
||||||
|
msr hcr_el2, x0
|
||||||
|
|
||||||
|
mov x0, #SPSR_EL2_EL1h
|
||||||
|
orr x0, x0, #SPSR_EL2_MASK_DAIF
|
||||||
|
msr spsr_el2, x0
|
||||||
|
|
||||||
ADR_REL x0, 1f
|
ADR_REL x0, 1f
|
||||||
msr elr_el2, x0
|
msr elr_el2, x0
|
||||||
mov x0, #SPSR_EL2_EL1h
|
|
||||||
msr spsr_el2, x0
|
|
||||||
mov x0, #(HCR_EL2_RW | HCR_EL2_HCD)
|
|
||||||
msr hcr_el2, x0
|
|
||||||
|
|
||||||
|
isb
|
||||||
eret
|
eret
|
||||||
1:
|
1:
|
||||||
dsb sy
|
dsb sy
|
||||||
@ -37,7 +57,9 @@ _entry:
|
|||||||
ADR_REL x0, bsp_stack_top
|
ADR_REL x0, bsp_stack_top
|
||||||
mov sp, x0
|
mov sp, x0
|
||||||
|
|
||||||
b __aa64_bsp_main
|
mov lr, xzr
|
||||||
|
bl __aa64_bsp_main
|
||||||
|
b .
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
.p2align 12
|
.p2align 12
|
||||||
|
111
kernel/src/arch/aarch64/mach_orangepi3/gpio.rs
Normal file
111
kernel/src/arch/aarch64/mach_orangepi3/gpio.rs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
use crate::arch::MemoryIo;
|
||||||
|
use crate::dev::{
|
||||||
|
gpio::{GpioDevice, PinConfig, PinMode, PullMode},
|
||||||
|
Device,
|
||||||
|
};
|
||||||
|
use error::Errno;
|
||||||
|
use tock_registers::interfaces::{Readable, Writeable};
|
||||||
|
use tock_registers::register_structs;
|
||||||
|
use tock_registers::registers::ReadWrite;
|
||||||
|
|
||||||
|
pub const PH0_UART0_TX: u32 = 2;
|
||||||
|
pub const PH1_UART0_RX: u32 = 2;
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
Regs {
|
||||||
|
(0x00 => CFG: [ReadWrite<u32>; 4]),
|
||||||
|
(0x10 => DAT: ReadWrite<u32>),
|
||||||
|
(0x14 => DRV: [ReadWrite<u32>; 2]),
|
||||||
|
(0x1C => PUL: [ReadWrite<u32>; 2]),
|
||||||
|
(0x24 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct Gpio {
|
||||||
|
regs: MemoryIo<Regs>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Gpio {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"Allwinner H6 GPIO Controller"
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enable(&mut self) -> Result<(), Errno> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpioDevice for Gpio {
|
||||||
|
unsafe fn set_pin_config(&mut self, pin: u32, cfg: &PinConfig) -> Result<(), Errno> {
|
||||||
|
let pull = match cfg.pull {
|
||||||
|
PullMode::None => 0,
|
||||||
|
PullMode::Up => 1,
|
||||||
|
PullMode::Down => 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
match cfg.mode {
|
||||||
|
PinMode::Disable => self.set_pin_cfg_inner(pin, 7),
|
||||||
|
PinMode::Input => {
|
||||||
|
self.set_pin_cfg_inner(pin, 0);
|
||||||
|
self.set_pin_pul_inner(pin, pull);
|
||||||
|
}
|
||||||
|
PinMode::Output => {
|
||||||
|
self.set_pin_cfg_inner(pin, 1); // TODO is it the same for all pins?
|
||||||
|
self.set_pin_pul_inner(pin, pull);
|
||||||
|
}
|
||||||
|
PinMode::InputInterrupt => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
PinMode::Alt => {
|
||||||
|
assert!(cfg.func > 1 && cfg.func < 7);
|
||||||
|
self.set_pin_cfg_inner(pin, cfg.func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_pin_config(&mut self, _pin: u32) -> Result<PinConfig, Errno> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_pin(&mut self, pin: u32) {
|
||||||
|
self.regs.DAT.set(self.regs.DAT.get() | (1 << pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_pin(&mut self, pin: u32) {
|
||||||
|
self.regs.DAT.set(self.regs.DAT.get() & !(1 << pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_pin(&mut self, pin: u32) {
|
||||||
|
self.regs.DAT.set(self.regs.DAT.get() ^ (1 << pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_pin(&mut self, pin: u32) -> Result<bool, Errno> {
|
||||||
|
Ok(self.regs.DAT.get() & (1 << pin) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gpio {
|
||||||
|
#[inline]
|
||||||
|
fn set_pin_cfg_inner(&mut self, pin: u32, cfg: u32) {
|
||||||
|
let reg = pin >> 3;
|
||||||
|
let shift = (pin & 0x7) * 4;
|
||||||
|
let tmp = self.regs.CFG[reg as usize].get() & !(0xF << shift);
|
||||||
|
self.regs.CFG[reg as usize].set(tmp | ((cfg & 0x7) << shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_pin_pul_inner(&mut self, pin: u32, pul: u32) {
|
||||||
|
let reg = pin >> 4;
|
||||||
|
let shift = (pin & 0xF) * 2;
|
||||||
|
let tmp = self.regs.PUL[reg as usize].get() & !(0x3 << shift);
|
||||||
|
self.regs.PUL[reg as usize].set(tmp | ((pul & 0x3) << shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const unsafe fn new(base: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
regs: MemoryIo::new(base),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,51 +1,35 @@
|
|||||||
//! QEMU virt machine
|
//! Xunlong Orange Pi 3, with Allwinner H6 SoC
|
||||||
|
|
||||||
use crate::arch::aarch64::timer::GenericTimer;
|
use crate::arch::aarch64::timer::GenericTimer;
|
||||||
use crate::dev::{Device, serial::SerialDevice};
|
use crate::dev::{
|
||||||
use crate::dev::timer::TimestampSource;
|
gpio::{GpioDevice, PinConfig},
|
||||||
|
serial::SerialDevice,
|
||||||
|
timer::TimestampSource,
|
||||||
|
Device,
|
||||||
|
};
|
||||||
use crate::sync::Spin;
|
use crate::sync::Spin;
|
||||||
use error::Errno;
|
use error::Errno;
|
||||||
|
|
||||||
fn delay(mut p: usize) {
|
mod gpio;
|
||||||
while p != 0 {
|
mod uart;
|
||||||
cortex_a::asm::nop();
|
|
||||||
p -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Uart {
|
use gpio::Gpio;
|
||||||
base: usize
|
use uart::Uart;
|
||||||
}
|
|
||||||
|
|
||||||
impl Device for Uart {
|
#[allow(missing_docs)]
|
||||||
fn name() -> &'static str {
|
pub fn init_board() -> Result<(), Errno> {
|
||||||
"Allwinner H6 UART"
|
unsafe {
|
||||||
}
|
let mut gpioh = GPIOH.lock();
|
||||||
|
gpioh.set_pin_config(0, &PinConfig::alt(gpio::PH0_UART0_TX))?;
|
||||||
|
gpioh.set_pin_config(1, &PinConfig::alt(gpio::PH1_UART0_RX))?;
|
||||||
|
|
||||||
unsafe fn enable(&mut self) -> Result<(), Errno> {
|
UART0.lock().enable()?;
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SerialDevice for Uart {
|
|
||||||
fn send(&mut self, byte: u8) -> Result<(), Errno> {
|
|
||||||
unsafe {
|
|
||||||
if byte == b'\n' {
|
|
||||||
core::ptr::write_volatile(self.base as *mut u32, 13u32);
|
|
||||||
delay(10000);
|
|
||||||
}
|
|
||||||
core::ptr::write_volatile(self.base as *mut u32, byte as u32);
|
|
||||||
delay(10000);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recv(&mut self, blocking: bool) -> Result<u8, Errno> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const UART0_BASE: usize = 0x05000000;
|
const UART0_BASE: usize = 0x05000000;
|
||||||
|
const PIO_BASE: usize = 0x0300B000;
|
||||||
|
|
||||||
/// Returns primary console for this machine
|
/// Returns primary console for this machine
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -53,10 +37,14 @@ pub fn console() -> &'static Spin<impl SerialDevice> {
|
|||||||
&UART0
|
&UART0
|
||||||
}
|
}
|
||||||
|
|
||||||
///// Returns the timer used as CPU-local periodic IRQ source
|
/// Returns the timer used as CPU-local periodic IRQ source
|
||||||
//#[inline]
|
#[inline]
|
||||||
//pub fn local_timer() -> &'static Spin<impl TimestampSource> {
|
pub fn local_timer() -> &'static Spin<impl TimestampSource> {
|
||||||
// &LOCAL_TIMER
|
&LOCAL_TIMER
|
||||||
//}
|
}
|
||||||
|
|
||||||
static UART0: Spin<Uart> = Spin::new(Uart { base: UART0_BASE });
|
static UART0: Spin<Uart> = Spin::new(unsafe { Uart::new(UART0_BASE) });
|
||||||
|
static LOCAL_TIMER: Spin<GenericTimer> = Spin::new(GenericTimer {});
|
||||||
|
#[allow(dead_code)]
|
||||||
|
static GPIOD: Spin<Gpio> = Spin::new(unsafe { Gpio::new(PIO_BASE + 0x24 * 3) });
|
||||||
|
static GPIOH: Spin<Gpio> = Spin::new(unsafe { Gpio::new(PIO_BASE + 0x24 * 7) });
|
||||||
|
106
kernel/src/arch/aarch64/mach_orangepi3/uart.rs
Normal file
106
kernel/src/arch/aarch64/mach_orangepi3/uart.rs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
use crate::arch::MemoryIo;
|
||||||
|
use crate::dev::{serial::SerialDevice, Device};
|
||||||
|
use error::Errno;
|
||||||
|
use tock_registers::registers::{Aliased, ReadOnly, ReadWrite};
|
||||||
|
use tock_registers::interfaces::{Readable, Writeable};
|
||||||
|
use tock_registers::{register_bitfields, register_structs};
|
||||||
|
|
||||||
|
register_bitfields! [
|
||||||
|
u32,
|
||||||
|
IER [
|
||||||
|
PTIME OFFSET(7) NUMBITS(1) [],
|
||||||
|
RS485_INT_EN OFFSET(4) NUMBITS(1) [],
|
||||||
|
EDSSI OFFSET(3) NUMBITS(1) [],
|
||||||
|
ELSI OFFSET(2) NUMBITS(1) [],
|
||||||
|
ETBEI OFFSET(1) NUMBITS(1) [],
|
||||||
|
ERBFI OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
IIR [
|
||||||
|
FEFLAG OFFSET(6) NUMBITS(2) [
|
||||||
|
Enable = 3,
|
||||||
|
Disable = 0
|
||||||
|
],
|
||||||
|
IID OFFSET(0) NUMBITS(4) [
|
||||||
|
ModemStatus = 0,
|
||||||
|
NoInterrupt = 1,
|
||||||
|
ThrEmpty = 2,
|
||||||
|
Rs485Interrupt = 3,
|
||||||
|
ReceivedDataAvailable = 4,
|
||||||
|
ReceiverLineStatus = 6,
|
||||||
|
BusyDetect = 7,
|
||||||
|
CharacterTimeout = 12
|
||||||
|
]
|
||||||
|
],
|
||||||
|
LSR [
|
||||||
|
FIFOERR OFFSET(7) NUMBITS(1) [],
|
||||||
|
TEMT OFFSET(6) NUMBITS(1) [],
|
||||||
|
THRE OFFSET(5) NUMBITS(1) [],
|
||||||
|
BI OFFSET(4) NUMBITS(1) [],
|
||||||
|
FE OFFSET(3) NUMBITS(1) [],
|
||||||
|
PE OFFSET(2) NUMBITS(1) [],
|
||||||
|
OE OFFSET(1) NUMBITS(1) [],
|
||||||
|
DR OFFSET(0) NUMBITS(1) []
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
Regs {
|
||||||
|
(0x0000 => DR_DLL: Aliased<u32>),
|
||||||
|
(0x0004 => IER_DLH: ReadWrite<u32, IER::Register>),
|
||||||
|
(0x0008 => IIR_FCR: Aliased<u32, IIR::Register, ()>),
|
||||||
|
(0x000C => LCR: ReadWrite<u32>),
|
||||||
|
(0x0010 => MCR: ReadWrite<u32>),
|
||||||
|
(0x0014 => LSR: ReadOnly<u32, LSR::Register>),
|
||||||
|
(0x0018 => MSR: ReadOnly<u32>),
|
||||||
|
(0x001C => SCH: ReadWrite<u32>),
|
||||||
|
(0x0020 => _res0),
|
||||||
|
(0x007C => USR: ReadOnly<u32>),
|
||||||
|
(0x0080 => TFL: ReadWrite<u32>),
|
||||||
|
(0x0084 => RFL: ReadWrite<u32>),
|
||||||
|
(0x0088 => HSK: ReadWrite<u32>),
|
||||||
|
(0x008C => _res1),
|
||||||
|
(0x00A4 => HALT: ReadWrite<u32>),
|
||||||
|
(0x00D0 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct Uart {
|
||||||
|
regs: MemoryIo<Regs>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Uart {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"Allwinner H6 UART"
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn enable(&mut self) -> Result<(), Errno> {
|
||||||
|
// TODO
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialDevice for Uart {
|
||||||
|
fn send(&mut self, byte: u8) -> Result<(), Errno> {
|
||||||
|
while !self.regs.LSR.matches_all(LSR::THRE::SET) {
|
||||||
|
cortex_a::asm::nop();
|
||||||
|
}
|
||||||
|
self.regs.DR_DLL.set(byte as u32);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv(&mut self, _blocking: bool) -> Result<u8, Errno> {
|
||||||
|
while !self.regs.LSR.matches_all(LSR::DR::SET) {
|
||||||
|
cortex_a::asm::nop();
|
||||||
|
}
|
||||||
|
Ok(self.regs.DR_DLL.get() as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Uart {
|
||||||
|
pub const unsafe fn new(base: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
regs: MemoryIo::new(base),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,21 @@
|
|||||||
//! QEMU virt machine
|
//! QEMU virt machine
|
||||||
|
|
||||||
use crate::arch::aarch64::timer::GenericTimer;
|
use crate::arch::aarch64::timer::GenericTimer;
|
||||||
use crate::dev::serial::{pl011::Pl011, SerialDevice};
|
use crate::dev::{Device, serial::{pl011::Pl011, SerialDevice}};
|
||||||
use crate::dev::timer::TimestampSource;
|
use crate::dev::timer::TimestampSource;
|
||||||
use crate::sync::Spin;
|
use crate::sync::Spin;
|
||||||
|
use error::Errno;
|
||||||
|
|
||||||
const UART0_BASE: usize = 0x09000000;
|
const UART0_BASE: usize = 0x09000000;
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub fn init_board() -> Result<(), Errno> {
|
||||||
|
unsafe {
|
||||||
|
UART0.lock().enable()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns primary console for this machine
|
/// Returns primary console for this machine
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn console() -> &'static Spin<impl SerialDevice> {
|
pub fn console() -> &'static Spin<impl SerialDevice> {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.section .text
|
.section .text
|
||||||
.global aa64_el1_vectors
|
.global aa64_el1_vectors
|
||||||
.p2align 8
|
.p2align 12
|
||||||
aa64_el1_vectors:
|
aa64_el1_vectors:
|
||||||
.el1_sp_el0_sync:
|
.el1_sp_el0_sync:
|
||||||
b .
|
b .
|
||||||
|
@ -15,6 +15,9 @@ impl<T: SerialDevice> fmt::Write for SerialOutput<T> {
|
|||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
let mut lock = self.inner.lock();
|
let mut lock = self.inner.lock();
|
||||||
for &byte in s.as_bytes() {
|
for &byte in s.as_bytes() {
|
||||||
|
if byte == b'\n' {
|
||||||
|
lock.send(b'\r').ok();
|
||||||
|
}
|
||||||
// TODO check for errors
|
// TODO check for errors
|
||||||
lock.send(byte).ok();
|
lock.send(byte).ok();
|
||||||
}
|
}
|
||||||
|
76
kernel/src/dev/gpio.rs
Normal file
76
kernel/src/dev/gpio.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
//! GPIO and pin control interfaces
|
||||||
|
|
||||||
|
use crate::dev::Device;
|
||||||
|
use error::Errno;
|
||||||
|
|
||||||
|
/// Pin function mode
|
||||||
|
pub enum PinMode {
|
||||||
|
/// Do not use pin
|
||||||
|
Disable = 0,
|
||||||
|
/// Use pin as a GPIO input
|
||||||
|
Input,
|
||||||
|
/// Use pin as a GPIO output
|
||||||
|
Output,
|
||||||
|
/// Use pin as an external interrupt trigger source
|
||||||
|
InputInterrupt,
|
||||||
|
/// Use pin for peripheral functionality
|
||||||
|
Alt,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Input/output pin pull mode
|
||||||
|
pub enum PullMode {
|
||||||
|
/// No pull
|
||||||
|
None,
|
||||||
|
/// Pull up
|
||||||
|
Up,
|
||||||
|
/// Pull down
|
||||||
|
Down,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pin configuration for [GpioDevice::set_pin_config]
|
||||||
|
pub struct PinConfig {
|
||||||
|
/// Pin function
|
||||||
|
pub mode: PinMode,
|
||||||
|
/// Pin pull mode, only used for Input/Output pins
|
||||||
|
pub pull: PullMode,
|
||||||
|
/// Alternate pin function, only used when mode == [PinMode::Alt]
|
||||||
|
pub func: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO separate traits for "single port controller" and "global gpio controller"
|
||||||
|
/// Generic GPIO controller interface
|
||||||
|
pub trait GpioDevice: Device {
|
||||||
|
/// Initializes configuration for given pin
|
||||||
|
unsafe fn set_pin_config(&mut self, pin: u32, cfg: &PinConfig) -> Result<(), Errno>;
|
||||||
|
/// Returns current configuration of given pin
|
||||||
|
unsafe fn get_pin_config(&mut self, pin: u32) -> Result<PinConfig, Errno>;
|
||||||
|
|
||||||
|
/// Sets `pin` to HIGH state
|
||||||
|
fn set_pin(&mut self, pin: u32);
|
||||||
|
/// Sets `pin` to LOW state
|
||||||
|
fn clear_pin(&mut self, pin: u32);
|
||||||
|
/// Toggles `pin`'s HIGH/LOW state
|
||||||
|
fn toggle_pin(&mut self, pin: u32);
|
||||||
|
/// Returns `true` if input `pin` is in HIGH state
|
||||||
|
fn read_pin(&mut self, pin: u32) -> Result<bool, Errno>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PinConfig {
|
||||||
|
/// Alternative (peripheral) pin configuration
|
||||||
|
pub const fn alt(func: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
mode: PinMode::Alt,
|
||||||
|
pull: PullMode::None,
|
||||||
|
func
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pull-down output
|
||||||
|
pub const fn out_pull_down() -> Self {
|
||||||
|
Self {
|
||||||
|
mode: PinMode::Output,
|
||||||
|
pull: PullMode::Down,
|
||||||
|
func: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ use error::Errno;
|
|||||||
// Device classes
|
// Device classes
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
pub mod gpio;
|
||||||
|
|
||||||
/// Generic device trait
|
/// Generic device trait
|
||||||
pub trait Device {
|
pub trait Device {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user