// SPDX-License-Identifier: MIT OR Apache-2.0 // // Copyright (c) 2018-2022 Andre Richter //! BSP driver support. use super::memory::map::mmio; use crate::{bsp::device_driver, console, driver as generic_driver}; use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- static PL011_UART: device_driver::PL011Uart = unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- /// This must be called only after successful init of the UART driver. fn post_init_uart() -> Result<(), &'static str> { console::register_console(&PL011_UART); Ok(()) } /// This must be called only after successful init of the GPIO driver. fn post_init_gpio() -> Result<(), &'static str> { GPIO.map_pl011_uart(); Ok(()) } fn driver_uart() -> Result<(), &'static str> { let uart_descriptor = generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); generic_driver::driver_manager().register_driver(uart_descriptor); Ok(()) } fn driver_gpio() -> Result<(), &'static str> { let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); generic_driver::driver_manager().register_driver(gpio_descriptor); Ok(()) } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- /// Initialize the driver subsystem. /// /// # Safety /// /// See child function calls. pub unsafe fn init() -> Result<(), &'static str> { static INIT_DONE: AtomicBool = AtomicBool::new(false); if INIT_DONE.load(Ordering::Relaxed) { return Err("Init already done"); } driver_uart()?; driver_gpio()?; INIT_DONE.store(true, Ordering::Relaxed); Ok(()) } /// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps /// than on real hardware due to QEMU's abstractions. #[cfg(feature = "test_build")] pub fn qemu_bring_up_console() { console::register_console(&PL011_UART); }