Skip to content

Commit

Permalink
ASIC-specific SysCtrl drivers & examples (#60)
Browse files Browse the repository at this point in the history
BSP:

* Add -Fasic
* Add ASIC specific UART memory map
* impl UART for ASIC (untested)
* Fancy HALs for soc_ctrl, gpio
* Organize SysCtrl HAL & mmaps

Examples:

* LED: refactor for HAL
* SysCtrl: give nops/sec calibration value
* UART: use HAL
* rm unused unsafe
  • Loading branch information
hegza authored Aug 16, 2024
1 parent 6e44724 commit 53e27bc
Show file tree
Hide file tree
Showing 12 changed files with 349 additions and 49 deletions.
1 change: 1 addition & 0 deletions examples/headsail-bsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ sysctrl = []
alloc = ["dep:good_memory_allocator", "hpc"]
sdram = []
vp = []
asic = []

# This is generated by the above options, don't use directly
rt = ["dep:riscv-rt"]
Expand Down
23 changes: 21 additions & 2 deletions examples/headsail-bsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#![no_std]

pub mod sprintln;
#[cfg(feature = "sysctrl")]
pub mod sysctrl;
pub mod uart;
pub mod timer {
/*!
Expand Down Expand Up @@ -38,8 +40,6 @@ pub mod alloc;
#[cfg(feature = "hpc")]
mod hpc;
mod mmap;
#[cfg(feature = "sysctrl")]
mod sysctrl;
#[cfg(feature = "panic-uart")]
mod ufmt_panic;

Expand Down Expand Up @@ -69,6 +69,25 @@ pub fn write_u32(addr: usize, val: u32) {
unsafe { core::ptr::write_volatile(addr as *mut _, val) }
}

#[inline(always)]
pub fn mask_u32(addr: usize, mask: u32) {
let r = unsafe { core::ptr::read_volatile(addr as *const u32) };
unsafe { core::ptr::write_volatile(addr as *mut _, r | mask) }
}

#[inline(always)]
pub fn unmask_u32(addr: usize, unmask: u32) {
let r = unsafe { core::ptr::read_volatile(addr as *const u32) };
unsafe { core::ptr::write_volatile(addr as *mut _, r & !unmask) }
}

#[inline(always)]
pub fn toggle_u32(addr: usize, toggle_bits: u32) {
let mut r = read_u32(addr);
r ^= toggle_bits;
write_u32(addr, r);
}

#[cfg(feature = "alloc")]
pub fn init_alloc() {
unsafe { alloc::init_heap() };
Expand Down
18 changes: 18 additions & 0 deletions examples/headsail-bsp/src/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,26 @@
pub(crate) const UART0_ADDR: usize = 0x1FFF00000;
#[cfg(not(feature = "hpc"))]
pub(crate) const UART0_ADDR: usize = 0xFFF00000;
pub(crate) const UART0_THR: usize = UART0_ADDR;

// NOTE: (20240614 [email protected]) This applies to renode NS16550 uart, but might not apply to headsail ASIC
pub(crate) const UART_DATA_READY_OFFSET: usize = 5;

#[cfg(feature = "asic")]
mod asic_uart {
use super::UART0_ADDR;

pub(crate) const UART0_DIV_LSB: usize = UART0_ADDR + 0;
pub(crate) const UART0_DIV_MSB: usize = UART0_ADDR + 1;
pub(crate) const UART0_INTERRUPT_ENABLE: usize = UART0_ADDR + 1;
pub(crate) const UART0_FIFO_CONTROL: usize = UART0_ADDR + 2;
pub(crate) const UART0_LINE_CONTROL: usize = UART0_ADDR + 3;
pub(crate) const UART0_MODEM_CONTROL: usize = UART0_ADDR + 4;
pub(crate) const UART0_LINE_STATUS: usize = UART0_ADDR + 5;
}
#[cfg(feature = "asic")]
pub(crate) use self::asic_uart::*;

pub(crate) const TIMER0_ADDR: usize = 0x5_0000;
pub(crate) const TIMER1_ADDR: usize = 0x5_0010;
pub(crate) const TIMER2_ADDR: usize = 0x5_0020;
Expand Down
92 changes: 92 additions & 0 deletions examples/headsail-bsp/src/sysctrl/gpio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use core::marker::PhantomData;

use super::{mmap, soc_ctrl};
use crate::{mask_u32, toggle_u32, unmask_u32};

/// Type-state trait for GPIO in different states
pub trait GpioState {}

pub struct Uninit;
impl GpioState for Uninit {}

pub struct Input;
impl GpioState for Input {}

pub struct Output;
impl GpioState for Output {}

/// To obtain an instance:
///
/// 1. Obtain [Pads] with [sysctrl::soc_ctrl::Pads::take]
/// 2. Pick pin: `pads.p9`
/// 3. Convert pin into GPIO [systcrl::soc_ctrl::Pad::into_gpio]
pub struct Gpio<const IDX: u32, State: GpioState = Uninit> {
_pd: PhantomData<State>,
}

pub type Gpio9<S> = Gpio<9, S>;

#[repr(u32)]
enum Dir {
In = 0,
Out = 1,
}

impl<const IDX: u32> Gpio<IDX, Uninit> {
pub(crate) fn new() -> Self {
Self { _pd: PhantomData }
}

pub fn into_input(self) -> Gpio<IDX, Input> {
mask_u32(mmap::GPIO_DIR, Dir::In as u32);

Gpio { _pd: PhantomData }
}

pub fn into_output(self) -> Gpio<IDX, Output> {
mask_u32(mmap::GPIO_DIR, Dir::Out as u32);

Gpio { _pd: PhantomData }
}
}

impl<const IDX: u32> Gpio<IDX, Output> {
pub fn toggle(&mut self) {
toggle_u32(mmap::GPIO_OUT, 1 << IDX);
}

pub fn set_high(&mut self) {
mask_u32(mmap::GPIO_OUT, 1 << IDX);
}

pub fn set_low(&mut self) {
unmask_u32(mmap::GPIO_OUT, 1 << IDX);
}
}

impl<const IDX: u32, S: GpioState> Gpio<IDX, S> {
/// Release pad back to its original function
///
/// Pins can be released in any state. GPIO register configurations will
/// retain their state (until overridden again by HAL methods).
pub fn release(self) -> soc_ctrl::Pad<IDX> {
unmask_u32(
if IDX <= 15 {
mmap::PADMUX0
} else {
mmap::PADMUX1
},
(soc_ctrl::PadFn::Gpio as u32) << (IDX * 2),
);

soc_ctrl::Pad::<IDX> {}
}

/// # Safety
///
/// This will not configure the pin in any way (i.e., for use as GPIO or
/// direction).
pub unsafe fn steal() -> Self {
Self { _pd: PhantomData }
}
}
15 changes: 15 additions & 0 deletions examples/headsail-bsp/src/sysctrl/mmap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// SysCtrl-specific memory maps
pub(crate) const SYSCTRL_ADDR: usize = 0x1a10_0000;

pub(crate) const GPIO_ADDR: usize = SYSCTRL_ADDR + 0x1000;
pub(crate) const GPIO_DIR: usize = GPIO_ADDR + 0x0;
pub(crate) const GPIO_OUT: usize = GPIO_ADDR + 0xc;

pub(crate) const SOC_CONTROL_ADDR: usize = SYSCTRL_ADDR + 0x4000;
pub(crate) const PADMUX0: usize = SOC_CONTROL_ADDR + 0x10;
pub(crate) const PADMUX1: usize = SOC_CONTROL_ADDR + 0x14;

pub(crate) const SS_RESET_EN: usize = SOC_CONTROL_ADDR + 0xb0;
pub(crate) const SS_CLK_CTRL2: usize = SOC_CONTROL_ADDR + 0x9c;
pub(crate) const SS_CLK_CTRL3: usize = SOC_CONTROL_ADDR + 0xb8;
4 changes: 4 additions & 0 deletions examples/headsail-bsp/src/sysctrl/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
//! Abstractions that only exist on SysCtrl
pub mod gpio;
pub mod soc_ctrl;

mod interrupt;
mod mmap;
103 changes: 103 additions & 0 deletions examples/headsail-bsp/src/sysctrl/soc_ctrl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use riscv::interrupt;

use super::{gpio::Gpio, mmap};
use crate::{mask_u32, write_u32};

#[repr(u32)]
pub(crate) enum PadFn {
//Default = 0,
Gpio = 1,
}

/// ~Pin
pub struct Pad<const IDX: u32> {}

pub struct Pads {
pub p0: Pad<0>,
pub p1: Pad<1>,
pub p2: Pad<2>,
pub p3: Pad<3>,
pub p4: Pad<4>,
pub p5: Pad<5>,
pub p6: Pad<6>,
pub p7: Pad<7>,
pub p8: Pad<8>,
pub p9: Pad<9>,
pub p10: Pad<10>,
pub p11: Pad<11>,
pub p12: Pad<12>,
pub p13: Pad<13>,
pub p14: Pad<14>,
pub p15: Pad<15>,
pub p16: Pad<16>,
pub p17: Pad<17>,
pub p18: Pad<18>,
}

/// Set to `true` when `take` or `steal` was called to make `Peripherals` a singleton.
static mut PADS_TAKEN: bool = false;

impl Pads {
#[inline]
pub fn take() -> Option<Self> {
interrupt::free(|| {
if unsafe { PADS_TAKEN } {
None
} else {
Some(unsafe { Self::steal() })
}
})
}

#[inline]
pub unsafe fn steal() -> Self {
Self {
p0: Pad {},
p1: Pad {},
p2: Pad {},
p3: Pad {},
p4: Pad {},
p5: Pad {},
p6: Pad {},
p7: Pad {},
p8: Pad {},
p9: Pad {},
p10: Pad {},
p11: Pad {},
p12: Pad {},
p13: Pad {},
p14: Pad {},
p15: Pad {},
p16: Pad {},
p17: Pad {},
p18: Pad {},
}
}
}

impl<const IDX: u32> Pad<IDX> {
pub fn into_gpio(self) -> Gpio<IDX> {
mask_u32(
if IDX <= 15 {
mmap::PADMUX0
} else {
mmap::PADMUX1
},
(PadFn::Gpio as u32) << (IDX * 2),
);

Gpio::<IDX>::new()
}
}

pub fn ss_enable(ss_bits: u32) {
write_u32(mmap::SS_RESET_EN, ss_bits);
}

pub fn clk2_set(conf_val: u32) {
write_u32(mmap::SS_CLK_CTRL2, conf_val);
}

pub fn clk3_set(conf_val: u32) {
write_u32(mmap::SS_CLK_CTRL3, conf_val);
}
53 changes: 50 additions & 3 deletions examples/headsail-bsp/src/uart.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,53 @@
use crate::{mmap::UART0_ADDR, mmap::UART_DATA_READY_OFFSET, read_u8, write_u8};
use crate::{
mmap::{UART0_ADDR, UART0_THR, UART_DATA_READY_OFFSET},
read_u8, write_u8,
};

#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;

#[cfg(feature = "asic")]
#[inline]
pub fn init_uart(freq: u32, baud: u32) {
use crate::mmap::{
UART0_DIV_LSB, UART0_DIV_MSB, UART0_FIFO_CONTROL, UART0_INTERRUPT_ENABLE,
UART0_LINE_CONTROL, UART0_MODEM_CONTROL,
};
const PERIPH_CLK_DIV: u32 = 2;
let divisor: u32 = freq / PERIPH_CLK_DIV / (baud << 4);

// Safety: unknown; we don't know if 8-bit writes will succeed
unsafe {
// Disable all interrupts
write_u8(UART0_INTERRUPT_ENABLE, 0x00);
// Enable DLAB (set baud rate divisor)
write_u8(UART0_LINE_CONTROL, 0x80);
// Divisor (lo byte)
write_u8(UART0_DIV_LSB, divisor as u8);
// Divisor (hi byte)
write_u8(UART0_DIV_MSB, (divisor >> 8) as u8);
// 8 bits, no parity, one stop bit
write_u8(UART0_LINE_CONTROL, 0x03);
// Enable FIFO, clear them, with 14-byte threshold
write_u8(UART0_FIFO_CONTROL, 0xC7);
// Autoflow mode
write_u8(UART0_MODEM_CONTROL, 0x20);
}
}

/// Dummy definition for VP, as the UART on VP does not require configuration
#[cfg(feature = "vp")]
pub fn init_uart(_freq: u32, _baud: u32) {}

#[cfg(feature = "asic")]
#[inline]
fn is_transmit_empty() -> bool {
// Safety: UART_LINE_STATUS is 4-byte aligned
unsafe { (read_u8(crate::mmap::UART0_LINE_STATUS) & 0x20) != 0 }
}

#[inline]
pub fn uart_write(s: &str) {
for b in s.as_bytes() {
Expand All @@ -14,8 +57,12 @@ pub fn uart_write(s: &str) {

#[inline]
pub fn putc(c: u8) {
// Safety: we don't know if u8 writes work for all target architectures
unsafe { write_u8(UART0_ADDR, c) };
// Wait for hardware to report completion
#[cfg(feature = "asic")]
while !is_transmit_empty() {}

// Safety: UART_THR is 4-byte aligned
unsafe { write_u8(UART0_THR, c) };
}

#[inline]
Expand Down
3 changes: 3 additions & 0 deletions examples/sysctrl/hello-sysctrl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
asic = ["headsail-bsp/asic"]

[dependencies]
headsail-bsp = { version = "0.1.0", path = "../../headsail-bsp", features = [
"sysctrl-rt",
Expand Down
Loading

0 comments on commit 53e27bc

Please sign in to comment.