Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SysCtrl uDMA UART for ASIC #63

Merged
merged 16 commits into from
Aug 25, 2024
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