From addf49ffdb2816049f8a42de637152bdde34b18b Mon Sep 17 00:00:00 2001 From: equation314 Date: Sat, 27 Oct 2018 02:45:47 +0800 Subject: [PATCH] aarch64: add crate bcm2837, implement GPIO --- crate/bcm2837/Cargo.toml | 7 + crate/bcm2837/src/asm.rs | 10 ++ crate/bcm2837/src/gpio.rs | 159 ++++++++++++++++++++ crate/bcm2837/src/lib.rs | 11 ++ crate/bcm2837/src/mini_uart.rs | 1 + kernel/Cargo.lock | 14 +- kernel/Cargo.toml | 5 +- kernel/src/arch/aarch64/board/raspi3/mod.rs | 4 + kernel/src/arch/aarch64/mod.rs | 9 +- 9 files changed, 212 insertions(+), 8 deletions(-) create mode 100644 crate/bcm2837/Cargo.toml create mode 100644 crate/bcm2837/src/asm.rs create mode 100644 crate/bcm2837/src/gpio.rs create mode 100644 crate/bcm2837/src/lib.rs create mode 100644 crate/bcm2837/src/mini_uart.rs diff --git a/crate/bcm2837/Cargo.toml b/crate/bcm2837/Cargo.toml new file mode 100644 index 0000000..969c995 --- /dev/null +++ b/crate/bcm2837/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "bcm2837" +version = "0.1.0" +authors = ["equation314 "] + +[dependencies] +volatile = "0.2.4" diff --git a/crate/bcm2837/src/asm.rs b/crate/bcm2837/src/asm.rs new file mode 100644 index 0000000..72f4c73 --- /dev/null +++ b/crate/bcm2837/src/asm.rs @@ -0,0 +1,10 @@ +//! utility assembly instructions + +/// delay for some clocks +#[inline] +pub unsafe fn delay(clock: u32) { + #[cfg(target_arch = "aarch64")] + asm!("1: subs x0, x0, #1; bne 1b;" + :: "{x0}"(clock) + :: "volatile"); +} diff --git a/crate/bcm2837/src/gpio.rs b/crate/bcm2837/src/gpio.rs new file mode 100644 index 0000000..aa2f9ef --- /dev/null +++ b/crate/bcm2837/src/gpio.rs @@ -0,0 +1,159 @@ +use super::IO_BASE; +use super::asm::delay; +use core::marker::PhantomData; +use volatile::{ReadOnly, Volatile, WriteOnly}; + +/// The base address of the `GPIO` registers. +const GPIO_BASE: usize = IO_BASE + 0x200000; + +/// An alternative GPIO function. +#[repr(u8)] +pub enum Function { + Input = 0b000, + Output = 0b001, + Alt0 = 0b100, + Alt1 = 0b101, + Alt2 = 0b110, + Alt3 = 0b111, + Alt4 = 0b011, + Alt5 = 0b010, +} + +#[repr(C)] +#[allow(non_snake_case)] +struct Registers { + FSEL: [Volatile; 6], + __reserved0: u32, + SET: [WriteOnly; 2], + __reserved1: u32, + CLR: [WriteOnly; 2], + __reserved2: u32, + LEV: [ReadOnly; 2], + __reserved3: u32, + EDS: [Volatile; 2], + __reserved4: u32, + REN: [Volatile; 2], + __reserved5: u32, + FEN: [Volatile; 2], + __reserved6: u32, + HEN: [Volatile; 2], + __reserved7: u32, + LEN: [Volatile; 2], + __reserved8: u32, + AREN: [Volatile; 2], + __reserved9: u32, + AFEN: [Volatile; 2], + __reserved10: u32, + PUD: Volatile, + PUDCLK: [Volatile; 2], +} + +/// Possible states for a GPIO pin. +pub enum Uninitialized {} +pub enum Input {} +pub enum Output {} +pub enum Alt {} + +/// A GPIO pin in state `State`. +/// +/// The `State` generic always corresponds to an uninstantiatable type that is +/// use solely to mark and track the state of a given GPIO pin. A `Gpio` +/// structure starts in the `Uninitialized` state and must be transitions into +/// one of `Input`, `Output`, or `Alt` via the `into_input`, `into_output`, and +/// `into_alt` methods before it can be used. +pub struct Gpio { + pin: u8, + registers: &'static mut Registers, + _state: PhantomData, +} + +impl Gpio { + /// Transitions `self` to state `S`, consuming `self` and returning a new + /// `Gpio` instance in state `S`. This method should _never_ be exposed to + /// the public! + #[inline(always)] + fn transition(self) -> Gpio { + Gpio { + pin: self.pin, + registers: self.registers, + _state: PhantomData, + } + } + + /// Set the Gpio pull-up/pull-down state for values in `pin_value` + pub fn set_gpio_pd(&mut self, pud_value: u8) { + unsafe { + let index = if self.pin >= 32 { 1 } else { 0 }; + + self.registers.PUD.write(pud_value as u32); + delay(150); + self.registers.PUDCLK[index as usize].write((1 << self.pin) as u32); + delay(150); + self.registers.PUD.write(0); + self.registers.PUDCLK[index as usize].write(0); + } + } +} + +impl Gpio { + /// Returns a new `GPIO` structure for pin number `pin`. + /// + /// # Panics + /// + /// Panics if `pin` > `53`. + pub fn new(pin: u8) -> Gpio { + if pin > 53 { + panic!("Gpio::new(): pin {} exceeds maximum of 53", pin); + } + + Gpio { + registers: unsafe { &mut *(GPIO_BASE as *mut Registers) }, + pin: pin, + _state: PhantomData, + } + } + + /// Enables the alternative function `function` for `self`. Consumes self + /// and returns a `Gpio` structure in the `Alt` state. + pub fn into_alt(self, function: Function) -> Gpio { + self.registers.FSEL[(self.pin / 10) as usize] + .write((function as u32) << (3 * (self.pin % 10))); + self.transition() + } + + /// Sets this pin to be an _output_ pin. Consumes self and returns a `Gpio` + /// structure in the `Output` state. + pub fn into_output(self) -> Gpio { + self.into_alt(Function::Output).transition() + } + + /// Sets this pin to be an _input_ pin. Consumes self and returns a `Gpio` + /// structure in the `Input` state. + pub fn into_input(self) -> Gpio { + self.into_alt(Function::Input).transition() + } +} + +impl Gpio { + /// Sets (turns on) the pin. + pub fn set(&mut self) { + let index = if self.pin >= 32 { 1 } else { 0 }; + self.registers.SET[index as usize].write(1 << (self.pin - index * 32)); + } + + /// Clears (turns off) the pin. + pub fn clear(&mut self) { + let index = if self.pin >= 32 { 1 } else { 0 }; + self.registers.CLR[index as usize].write(1 << (self.pin - index * 32)); + } +} + +impl Gpio { + /// Reads the pin's value. Returns `true` if the level is high and `false` + /// if the level is low. + pub fn level(&mut self) -> bool { + let index = if self.pin >= 32 { 1 } else { 0 }; + let high = 1 << (self.pin - index * 32); + (self.registers.LEV[index as usize].read() & high) == high + } +} diff --git a/crate/bcm2837/src/lib.rs b/crate/bcm2837/src/lib.rs new file mode 100644 index 0000000..b2611e3 --- /dev/null +++ b/crate/bcm2837/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] +#![feature(asm)] + +extern crate volatile; + +mod asm; + +pub mod gpio; +pub mod mini_uart; + +pub const IO_BASE: usize = 0x3F000000; diff --git a/crate/bcm2837/src/mini_uart.rs b/crate/bcm2837/src/mini_uart.rs new file mode 100644 index 0000000..db28245 --- /dev/null +++ b/crate/bcm2837/src/mini_uart.rs @@ -0,0 +1 @@ +use super::IO_BASE; diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index d8de26e..3886b0c 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -7,6 +7,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "bbl" version = "0.1.0" +[[package]] +name = "bcm2837" +version = "0.1.0" +dependencies = [ + "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bit-allocator" version = "0.1.0" @@ -211,6 +218,7 @@ name = "ucore" version = "0.1.0" dependencies = [ "bbl 0.1.0", + "bcm2837 0.1.0", "bit-allocator 0.1.0", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -227,7 +235,7 @@ dependencies = [ "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ucore-memory 0.1.0", "ucore-process 0.1.0", - "volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -265,7 +273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "volatile" -version = "0.1.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -344,7 +352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" "checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" -"checksum volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37c5d76c0f40ba4f8ac10ec4717d4e98ce3e58c5607eea36e9464226fc5e0a95" +"checksum volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "54d4343a2df2d65144a874f95950754ee7b7e8594f6027aae8c7d0f4858a3fe8" "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 7bde15d..fe19377 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -25,7 +25,7 @@ once = "0.3.3" xmas-elf = "0.6" bitflags = "1.0" bit_field = "0.9.0" -volatile = "0.1.0" +volatile = "0.2.4" linked_list_allocator = "0.6" lazy_static = { version = "1.0.0", features = ["spin_no_std"] } bit-allocator = { path = "../crate/bit-allocator" } @@ -43,6 +43,9 @@ uart_16550 = "0.1" riscv = { path = "../crate/riscv" } bbl = { path = "../crate/bbl" } +[target.'cfg(target_arch = "aarch64")'.dependencies] +bcm2837 = { path = "../crate/bcm2837" } + [package.metadata.bootimage] default-target = "x86_64-blog_os.json" output = "target/x86_64-blog_os/bootimage.bin" diff --git a/kernel/src/arch/aarch64/board/raspi3/mod.rs b/kernel/src/arch/aarch64/board/raspi3/mod.rs index db63357..c8cff9f 100644 --- a/kernel/src/arch/aarch64/board/raspi3/mod.rs +++ b/kernel/src/arch/aarch64/board/raspi3/mod.rs @@ -1,5 +1,9 @@ //! Raspberry PI 3 Model B/B+ +extern crate bcm2837; + pub fn init() { // TODO + bcm2837::gpio::Gpio::new(14).set_gpio_pd(0); + bcm2837::gpio::Gpio::new(15).set_gpio_pd(0); } diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 137941c..0f66365 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -11,8 +11,11 @@ pub mod board; /// TODO /// The entry point of kernel -#[no_mangle] // don't mangle the name of this function -pub extern fn rust_main() -> ! { +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn rust_main() -> ! { + // Init board. + board::init(); + println!("Hello ARM64!"); // First init log mod, so that we can print log info. @@ -24,8 +27,6 @@ pub extern fn rust_main() -> ! { // Now heap is available // timer::init(); - // Init board. - board::init(); ::kmain(); }