Skip to content

Commit

Permalink
fix(imx8mn): bug fixes for usdhc impl
Browse files Browse the repository at this point in the history
  • Loading branch information
nihalpasham committed Mar 28, 2023
1 parent e461fe1 commit 79d8f13
Show file tree
Hide file tree
Showing 16 changed files with 3,009 additions and 286 deletions.
16 changes: 11 additions & 5 deletions boards/bootloaders/imx8mn/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
use core::arch::global_asm;

use crate::kernel_init;
use crate::{clocks, exception, mux::iomux::uart2_mux_mmio_set, start_system_counter};
use crate::{
clocks, exception,
mux::{uart2grp::uart2_mux_mmio_set, usdhc2grp::usdhc2_mux_mmio_set},
start_system_counter,
};

// Assembly counterpart to this file.
global_asm!(include_str!("entry.S"));
Expand All @@ -16,13 +20,15 @@ global_asm!(include_str!("entry.S"));
pub unsafe extern "C" fn _start_rust() -> ! {
// set the vector base address for register handlers
exception::exception::handling_init();
// initialize uart clock and ungate sys_counter clock
clocks::ccm::init_uart_clk(1);
clocks::ccm::enable_sctr();
// enable Uart and uSDHC clock and ungate sys_counter clock
clocks::uartclks::enable_uart_clk(1);
clocks::usdhcclks::enable_usdhc_clk(2);
clocks::scntrclk::enable_sctr();
// start the system counter, this allows us to access ARM's architectural counter - CNTPCT_EL0
start_system_counter();
// set the mux state for UART2 peripheral.
// set mux state for UART2 and uSDHC2 peripherals.
uart2_mux_mmio_set();
usdhc2_mux_mmio_set();
// jump to next init stage.
kernel_init()
}
9 changes: 8 additions & 1 deletion boards/bootloaders/imx8mn/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ mod boot;

use rustBoot_hal::info;
use rustBoot_hal::nxp::imx8mn::arch::cpu_core::*;
use rustBoot_hal::nxp::imx8mn::bsp::drivers::usdhc::SdResult;
use rustBoot_hal::nxp::imx8mn::bsp::global::SDHC;
use rustBoot_hal::nxp::imx8mn::bsp::{
drivers::{common::interface::DriverManager, driver_manager::{driver_manager, start_system_counter}},
global,
Expand Down Expand Up @@ -57,9 +59,14 @@ fn kernel_main() -> ! {
for (i, driver) in driver_manager().all_device_drivers().iter().enumerate() {
info!(" {}. {}", i + 1, driver.compatible());
}

info!("Chars written: {}", console::console().chars_written());

// init uSDHC
match SDHC.init_usdhc() {
SdResult::SdOk => info!("uSDHC driver initialized"),
_ => info!("failed to initialize"),
};

wait_forever()
}

Expand Down
2 changes: 1 addition & 1 deletion boards/hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ nrf52840 = ["nrf", "nrf52840-hal"]
rpi = []
rpi4 = ["rpi", "tock-registers", "cortex-a", "rustBoot"]
nxp = []
imx8mn = ["nxp", "tock-registers", "cortex-a", "rustBoot"]
imx8mn = ["nxp", "tock-registers", "aarch64-cpu", "rustBoot"]
stm = []
stm32f411 = ["stm", "stm32f4xx-hal/stm32f411"]
stm32f446 = ["stm", "stm32f4xx-hal/stm32f446"]
Expand Down
78 changes: 17 additions & 61 deletions boards/hal/src/nxp/imx8mn/bsp/clocks/ccm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
//! from PLLs and oscillators and creates clocks for on-chip peripherals through a set of
//! multiplexers, dividers and gates.
//!
//! We're using the `target interface`. This programming model is a 2-step process
//! We're using the `target interface` api. This programming model is a 2-step process
//! - enable or disable `gates` corresponding to the desired clock
//! - set (or turn on) target `root` clock

use super::super::memory_map::*;
use crate::info;

/// (CCGR) is a register that controls the clock gating of a specific module or peripheral
const CCM_CCGR_N_SET: u32 = (map::mmio::CCM_START + 0x4004) as u32;
Expand All @@ -18,26 +17,29 @@ const CCM_CCGR_N_CLR: u32 = (map::mmio::CCM_START + 0x4008) as u32;
const CCM_TARGET_ROOT_N_SET: u32 = (map::mmio::CCM_START + 0x8004) as u32;

/// Enable target root clock
const CLK_ROOT_ON: u32 = 1 << 28;
pub const CLK_ROOT_ON: u32 = 1 << 28;
/// Disable target root clock
const CLK_ROOT_OFF: u32 = 0 << 28;
pub const CLK_ROOT_OFF: u32 = 0 << 28;

/// Clock source selection for each clock slice
const fn clk_root_source_sel(n: u32) -> u32 {
pub const fn clk_root_source_sel(n: u32) -> u32 {
(((n) & 0x7) << 24)
}

/// Clock Root Selects
/// The table below details the clock root slices.
///
/// See Table 5-1. Clock Root Table
enum ClkRootIdx {
pub enum ClkRootIdx {
ArmA53ClkRoot = 0,
ArmM7ClkRoot = 1,
Usdhc1ClkRoot = 88,
Usdhc2ClkRoot = 89,
Uart1ClkRoot = 94,
Uart2ClkRoot = 95,
Uart3ClkRoot = 96,
Uart4ClkRoot = 97,
Usdhc3ClkRoot = 121,
Sai7ClkRoot = 134,
ClkRootMax,
}
Expand All @@ -46,14 +48,17 @@ enum ClkRootIdx {
/// given module or peripheral
///
/// See Table 5-9. CCGR Mapping Table
enum CCGRIdx {
pub enum CCGRIdx {
CcgrDvfs = 0,
CcgrCpu = 2,
CcgrSctr = 57,
CcgrUart1 = 73,
CcgrUart2 = 74,
CcgrUart3 = 75,
CcgrUart4 = 76,
CcgrUsdhc1 = 81,
CcgrUsdhc2 = 82,
CcgrUsdhc3 = 94,
}

/// Before a clock root goes to on–chip peripherals, the clock root is distributed through low
Expand All @@ -66,11 +71,12 @@ enum CCGRIdx {
/// - 11 Domain clocks needed all the time
///
/// TODO! - figure out what domains (0-3) actually mean here.
fn clock_enable(idx: CCGRIdx, enabled: bool) {
pub fn clock_enable(idx: CCGRIdx, enabled: bool) {
let ccgr = if enabled {
match idx {
CCGRIdx::CcgrUart2 => CCM_CCGR_N_SET + (0x10 * 74),
CCGRIdx::CcgrSctr => CCM_CCGR_N_SET + (0x10 * 57),
CCGRIdx::CcgrUsdhc2 => CCM_CCGR_N_SET + (0x10 * 82),
_ => {
unimplemented!()
}
Expand All @@ -79,6 +85,7 @@ fn clock_enable(idx: CCGRIdx, enabled: bool) {
match idx {
CCGRIdx::CcgrUart2 => CCM_CCGR_N_CLR + (0x10 * 74),
CCGRIdx::CcgrSctr => CCM_CCGR_N_CLR + (0x10 * 57),
CCGRIdx::CcgrUsdhc2 => CCM_CCGR_N_CLR + (0x10 * 82),
_ => {
unimplemented!()
}
Expand All @@ -102,9 +109,10 @@ fn clock_enable(idx: CCGRIdx, enabled: bool) {
/// fields.
///
/// This function only enables or disables the clock and does not change any other settings.
fn clock_set_target_val(idx: ClkRootIdx, val: u32) {
pub fn clock_set_target_val(idx: ClkRootIdx, val: u32) {
let target_clk = match idx {
ClkRootIdx::Uart2ClkRoot => CCM_TARGET_ROOT_N_SET + (0x80 * 95),
ClkRootIdx::Usdhc2ClkRoot => CCM_TARGET_ROOT_N_SET + (0x80 * 89),
_ => {
unimplemented!()
}
Expand All @@ -115,55 +123,3 @@ fn clock_set_target_val(idx: ClkRootIdx, val: u32) {
// the offsets are set as per i.MX8MN reference manual
unsafe { ::core::ptr::write_volatile(target_clk as *mut u32, val) }
}

/// Initialize UART clocks. The `i.MX8MN` has 4 UARTs in total. Although, a UART interface does not use a clock signal i.e.
/// it is an asynchronous protocol, the i.MX8MN requires the corresponding clock for a UART to be enabled
/// before you can start using the peripheral.
pub fn init_uart_clk(index: u32) {
/*
* set uart clock root
* 24M OSC
*/
match index {
0 => {
clock_enable(CCGRIdx::CcgrUart1, false);
clock_set_target_val(
ClkRootIdx::Uart1ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUart1, true);
}
1 => {
clock_enable(CCGRIdx::CcgrUart2, false);
clock_set_target_val(
ClkRootIdx::Uart2ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUart2, true);
}
2 => {
clock_enable(CCGRIdx::CcgrUart3, false);
clock_set_target_val(
ClkRootIdx::Uart3ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUart3, true);
}
3 => {
clock_enable(CCGRIdx::CcgrUart4, false);
clock_set_target_val(
ClkRootIdx::Uart4ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUart4, true);
}
_ => {
info!("invalid uart index\n");
}
}
}

/// Allow system counter i.e. ungate clock gate for SCTR.
pub fn enable_sctr() {
clock_enable(CCGRIdx::CcgrSctr, true)
}
5 changes: 4 additions & 1 deletion boards/hal/src/nxp/imx8mn/bsp/clocks/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pub mod ccm;
mod ccm;
pub mod uartclks;
pub mod usdhcclks;
pub mod scntrclk;
8 changes: 8 additions & 0 deletions boards/hal/src/nxp/imx8mn/bsp/clocks/scntrclk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//! Enable or Disable system counter

use super::ccm::*;

/// Allow system counter i.e. ungate clock gate for SCTR.
pub fn enable_sctr() {
clock_enable(CCGRIdx::CcgrSctr, true)
}
51 changes: 51 additions & 0 deletions boards/hal/src/nxp/imx8mn/bsp/clocks/uartclks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//! The `i.MX8MN` has 4 UARTs in total. Although, a UART interface does not use a clock signal i.e.
//! it is an asynchronous protocol, the i.MX8MN requires the corresponding clock for a UART to be enabled
//! before you can start using the peripheral.

use super::ccm::*;
use crate::info;

/// Enable UART clocks.
pub fn enable_uart_clk(index: u32) {
/*
* set uart clock root
* 24M OSC
*/
match index {
0 => {
clock_enable(CCGRIdx::CcgrUart1, false);
clock_set_target_val(
ClkRootIdx::Uart1ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUart1, true);
}
1 => {
clock_enable(CCGRIdx::CcgrUart2, false);
clock_set_target_val(
ClkRootIdx::Uart2ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUart2, true);
}
2 => {
clock_enable(CCGRIdx::CcgrUart3, false);
clock_set_target_val(
ClkRootIdx::Uart3ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUart3, true);
}
3 => {
clock_enable(CCGRIdx::CcgrUart4, false);
clock_set_target_val(
ClkRootIdx::Uart4ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUart4, true);
}
_ => {
info!("invalid uart selection \n");
}
}
}
37 changes: 37 additions & 0 deletions boards/hal/src/nxp/imx8mn/bsp/clocks/usdhcclks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! The i.MX8 has 3 uSDHC(s). We use a default 400mhz source clock.

use super::ccm::*;
use crate::info;

/// Enable uSDHC clocks.
pub fn enable_usdhc_clk(index: u32) {
match index {
1 => {
clock_enable(CCGRIdx::CcgrUsdhc1, false);
clock_set_target_val(
ClkRootIdx::Usdhc1ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(1),
);
clock_enable(CCGRIdx::CcgrUsdhc1, true);
}
2 => {
clock_enable(CCGRIdx::CcgrUsdhc2, false);
clock_set_target_val(
ClkRootIdx::Usdhc2ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(0),
);
clock_enable(CCGRIdx::CcgrUsdhc2, true);
}
3 => {
clock_enable(CCGRIdx::CcgrUsdhc3, false);
clock_set_target_val(
ClkRootIdx::Usdhc3ClkRoot,
CLK_ROOT_ON | clk_root_source_sel(1),
);
clock_enable(CCGRIdx::CcgrUsdhc3, true);
}
_ => {
info!("invalid uSDHC selection \n");
}
}
}

0 comments on commit 79d8f13

Please sign in to comment.