Skip to content

Commit

Permalink
SysCtrl uDMA UART for ASIC (#63)
Browse files Browse the repository at this point in the history
BSP:

* Depend optionally on headsail-pac
* Expose PAC
* Fix GPIO bug
* Add periph_clk_div_set
* Sanitize feature hierarchy
* Add HAL for uDMA UART

SysCtrl tests:

* Update led test notes
* Use debug syms in release builds
* gdb(sysctrl): load program on connect
* Use -Fpanic-apb-uart0
* Use -Fbsp/sysctrl-pac
* Rename apb_uart0
* Add test: original raw led blinker
* Add test: PAC-based uDMA UART
* Add test: uDMA UART HAL
  • Loading branch information
hegza authored Aug 25, 2024
1 parent 035073b commit a74e029
Show file tree
Hide file tree
Showing 17 changed files with 295 additions and 18 deletions.
7 changes: 6 additions & 1 deletion examples/headsail-bsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ alloc = ["dep:good_memory_allocator", "hpc"]
sdram = []
vp = []
asic = []
sysctrl-pac = ["dep:headsail-sysctrl-pac", "sysctrl", "pac"]
hpc-pac = ["dep:headsail-hpc-pac", "hpc", "pac"]

# This is generated by the above options, don't use directly
# These are generated by the above options, don't use directly
rt = ["dep:riscv-rt"]
pac = []

[dependencies]
ufmt = "0.2.0"
Expand All @@ -32,6 +35,8 @@ riscv-peripheral = { version = "0.1.0", optional = true }
riscv-pac = { version = "0.1.1", optional = true }
good_memory_allocator = { version = "0.1.7", optional = true }
bit_field = "0.10.2"
headsail-sysctrl-pac = { git = "https://github.com/soc-hub-fi/headsail-pac", version = "0.1.1", optional = true }
headsail-hpc-pac = { git = "https://github.com/soc-hub-fi/headsail-pac", version = "0.1.1", optional = true }

[[example]]
name = "panic"
Expand Down
5 changes: 3 additions & 2 deletions examples/headsail-bsp/src/apb_uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ impl<const BASE_ADDR: usize> ApbUart<BASE_ADDR> {
pub fn init(soc_freq: u32, baud: u32) -> Self {
#[cfg(feature = "asic")]
{
const PERIPH_CLK_DIV: u32 = 2;
let divisor: u32 = soc_freq / PERIPH_CLK_DIV / (baud << 4);
use crate::mmap::{
UART_DIV_LSB_OFFSET, UART_DIV_MSB_OFFSET, UART_FIFO_CONTROL_OFFSET,
UART_INTERRUPT_ENABLE_OFFSET, UART_LINE_CONTROL_OFFSET, UART_MODEM_CONTROL_OFFSET,
};

const PERIPH_CLK_DIV: u32 = 2;
let divisor: u32 = soc_freq / PERIPH_CLK_DIV / (baud << 4);

// Safety: unknown; we don't know if 8-bit writes will succeed
unsafe {
// Disable all interrupts
Expand Down
5 changes: 5 additions & 0 deletions examples/headsail-bsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ pub mod timer {
pub use crate::timer_unit::*;
}
pub mod tb;
#[cfg(feature = "hpc-pac")]
pub use headsail_hpc_pac as pac;
#[cfg(feature = "sysctrl-pac")]
pub use headsail_sysctrl_pac as pac;

#[cfg(not(feature = "vp"))]
mod apb_timer;
Expand Down Expand Up @@ -75,6 +79,7 @@ pub fn mask_u32(addr: usize, mask: u32) {
unsafe { core::ptr::write_volatile(addr as *mut _, r | mask) }
}

/// Unmasks supplied bits from given register
#[inline(always)]
pub fn unmask_u32(addr: usize, unmask: u32) {
let r = unsafe { core::ptr::read_volatile(addr as *const u32) };
Expand Down
10 changes: 2 additions & 8 deletions examples/headsail-bsp/src/sysctrl/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,19 @@ pub struct Gpio<const IDX: u32, State: GpioState = Uninit> {

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);
unmask_u32(mmap::GPIO_DIR, 1 << IDX);

Gpio { _pd: PhantomData }
}

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

Gpio { _pd: PhantomData }
}
Expand Down
2 changes: 2 additions & 0 deletions examples/headsail-bsp/src/sysctrl/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ 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;

pub(crate) const PERIPH_CLK_DIV: usize = SOC_CONTROL_ADDR + 0xA8;
2 changes: 2 additions & 0 deletions examples/headsail-bsp/src/sysctrl/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Abstractions that only exist on SysCtrl
pub mod gpio;
pub mod soc_ctrl;
#[cfg(feature = "pac")]
pub mod udma;

mod interrupt;
mod mmap;
9 changes: 9 additions & 0 deletions examples/headsail-bsp/src/sysctrl/soc_ctrl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,12 @@ pub fn clk2_set(conf_val: u32) {
pub fn clk3_set(conf_val: u32) {
write_u32(mmap::SS_CLK_CTRL3, conf_val);
}

/// # Parameters
///
/// * `div` - value to set the `div` register to. Divider will be 1 << `div`
/// (unverified).
pub fn periph_clk_div_set(div: u32) {
let valid_bit = 0x400;
write_u32(mmap::PERIPH_CLK_DIV, valid_bit | div)
}
30 changes: 30 additions & 0 deletions examples/headsail-bsp/src/sysctrl/udma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
pub mod uart;

use core::marker::PhantomData;

use crate::pac;
pub use uart::UdmaUart;

/// Type-state trait for uDMA peripherals in different states
pub trait UdmaPeriphState {}

pub struct Enabled;
impl UdmaPeriphState for Enabled {}

pub struct Disabled;
impl UdmaPeriphState for Disabled {}

/// Relocatable driver for uDMA IP
pub struct Udma<'u>(pub &'u pac::sysctrl::Udma);

pub struct UdmaParts<'u> {
pub uart: UdmaUart<'u, Disabled>,
}

impl<'u> Udma<'u> {
pub fn split(self) -> UdmaParts<'u> {
UdmaParts {
uart: UdmaUart::<Disabled>(self.0, PhantomData::default()),
}
}
}
72 changes: 72 additions & 0 deletions examples/headsail-bsp/src/sysctrl/udma/uart.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use core::marker::PhantomData;

use super::{Disabled, Enabled};
use crate::pac;

/// Obtain an instance by calling [Udma::split]
pub struct UdmaUart<'u, UdmaPeriphState>(
pub(crate) &'u pac::sysctrl::Udma,
pub(crate) PhantomData<UdmaPeriphState>,
);

type UartSetupW = pac::sysctrl::udma::uart_setup::W;

impl<'u> UdmaUart<'u, Disabled> {
#[inline]
pub fn enable<F>(self, setup_spec: F) -> UdmaUart<'u, Enabled>
where
F: FnOnce(&mut UartSetupW) -> &mut UartSetupW,
{
let udma = &self.0;

// Turn on the clock gates for UART
udma.ctrl_cfg_cg().modify(|_r, w| w.cg_uart().set_bit());

// Setup UART
udma.uart_setup().write(|w| unsafe { w.bits(0) });
udma.uart_setup().write(setup_spec);

UdmaUart::<Enabled>(self.0, PhantomData::default())
}
}

impl<'u> UdmaUart<'u, Enabled> {
#[inline]
pub fn disable(self) -> UdmaUart<'u, Disabled> {
self.0.ctrl_cfg_cg().modify(|_r, w| w.cg_uart().clear_bit());
UdmaUart::<Disabled>(self.0, PhantomData::default())
}

/// # Safety
///
/// This will not configure the UART in any way.
#[inline]
pub unsafe fn steal(udma: &'static pac::sysctrl::Udma) -> Self {
Self(udma, PhantomData::default())
}

#[inline]
pub fn write(&mut self, buf: &[u8]) {
let udma = &self.0;

// Write buffer location & len
udma.uart_tx_saddr()
.write(|w| unsafe { w.bits(buf.as_ptr() as u32) });
udma.uart_tx_size()
.write(|w| unsafe { w.bits(buf.len() as u32) });

// Dispatch transmission
udma.uart_tx_cfg().write(
|w| w.en().set_bit(), // If we want "continuous mode". In continuous mode, uDMA reloads the address and transmits it again
//.continous().set_bit()
);

// Poll until finished (prevents `buf` leakage)
while udma.uart_tx_saddr().read().bits() != 0 {}
}

#[inline]
pub fn write_str(&mut self, s: &str) {
self.write(s.as_bytes());
}
}
3 changes: 3 additions & 0 deletions examples/sysctrl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[workspace]
members = ["hello-sysctrl"]
resolver = "2"

[profile.release]
debug = true
3 changes: 2 additions & 1 deletion examples/sysctrl/hello-sysctrl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ asic = ["headsail-bsp/asic"]
[dependencies]
headsail-bsp = { version = "0.1.0", path = "../../headsail-bsp", features = [
"sysctrl-rt",
"sysctrl-pac",
"panic-apb-uart0",
] }
panic-halt = "0.2.0"
3 changes: 2 additions & 1 deletion examples/sysctrl/hello-sysctrl/connect-and-load.gdb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Sysctrl is exposed at to 3333
target remote :3333
backtrace
load
backtrace
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#![no_std]
#![no_main]

use headsail_bsp::{apb_uart::ApbUart0, rt::entry, sysctrl::soc_ctrl};
use panic_halt as _;
use headsail_bsp::{apb_uart::ApbUart, rt::entry, sysctrl::soc_ctrl};

#[entry]
fn main() -> ! {
Expand All @@ -20,7 +19,7 @@ fn main() -> ! {
soc_ctrl::clk3_set(conf_val);

let (soc_freq, baud) = (30_000_000, 9600);
let mut uart = ApbUart0::init(soc_freq, baud);
let mut uart = ApbUart::<0xFFF00000>::init(soc_freq, baud);
uart.write(b"Hello world!");

loop {}
Expand Down
3 changes: 1 addition & 2 deletions examples/sysctrl/hello-sysctrl/examples/led.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
//! | Date | Status | Changes |
//! | :- | :-: | :- |
//! | 2024-08-15 | *Works* | |
//! | 2024-08-15T1530 | Untested | Use HAL |
//! | 2024-08-23 | *Works* | Use HAL |
#![no_std]
#![no_main]

use headsail_bsp::{rt::entry, sysctrl::soc_ctrl};
use hello_sysctrl::NOPS_PER_SEC;
use panic_halt as _;

#[entry]
fn main() -> ! {
Expand Down
53 changes: 53 additions & 0 deletions examples/sysctrl/hello-sysctrl/examples/led_raw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//! Blinks a LED
//!
//! Tested working on ASIC: 2024-08-23
#![no_std]
#![no_main]

use core::ptr;
use headsail_bsp::rt::entry;

// Below addresses are in SysCtrl memory space
const GPIO: usize = 0x1a10_1000;
const GPIO_DIR: usize = GPIO + 0x0;
const GPIO_OUT: usize = GPIO + 0xc;
const SOC_CONTROL: usize = 0x1a10_4000;
const PADMUX0: usize = SOC_CONTROL + 0x10;

// Number of nops SysCtrl is capable of executing at 30 MHz reference clocks
const NOPS_PER_SEC: usize = match () {
#[cfg(debug_assertions)]
// This is an experimentally found value
() => 2_000_000 / 9,
#[cfg(not(debug_assertions))]
// This is just a guess for now (10x debug)
() => 200_000 / 9,
};

#[entry]
fn main() -> ! {
unsafe {
ptr::write_volatile(PADMUX0 as *mut _, 0);
ptr::write_volatile(GPIO_DIR as *mut _, 0);

// Padmux enable GPIO9
ptr::write_volatile(PADMUX0 as *mut _, 0x40000);

// Set GPIO 9 as output
ptr::write_volatile(GPIO_DIR as *mut _, 1 << 9);
}

loop {
unsafe {
// Toggle GPIO
let mut r = ptr::read_volatile(GPIO_OUT as *mut u32);
r ^= 1 << 9;
ptr::write_volatile(GPIO_OUT as *mut u32, r);

// 1 second period
for _ in 0..NOPS_PER_SEC {
core::arch::asm!("nop");
}
}
}
}
38 changes: 38 additions & 0 deletions examples/sysctrl/hello-sysctrl/examples/udma_uart.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! Prints over SysCtrl UART
#![no_std]
#![no_main]

use headsail_bsp::{pac, rt::entry, sysctrl::udma::Udma};

#[entry]
fn main() -> ! {
let sysctrl = unsafe { pac::Sysctrl::steal() };
let udma = Udma(sysctrl.udma());

// Set the bit length, enable TX, set clk_div
let (soc_freq, baud) = (30_000_000, 9600_u32);
let clk_div: u16 = (soc_freq / baud) as u16;
let mut uart = udma.split().uart.enable(|w| {
unsafe {
w
// Use this if using parity bit
.parity_ena()
.bit(false)
.bit_length()
.bits(0b11)
// Stop bit?
.stop_bits()
.bit(false)
.tx_ena()
.bit(true)
.rx_ena()
.bit(true)
.clkdiv()
.bits(clk_div)
}
});

uart.write(b"Hello uDMA UART HAL\r\n");

loop {}
}
Loading

0 comments on commit a74e029

Please sign in to comment.