blob: 5bf0507f2e6140261b03ffe3d50859c4db493fe0 [file]
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0
//! AST10x0 SMC portable smoke test target.
//!
//! Safe to run on both QEMU and silicon. Does not assert on flash content
//! because silicon flash will not be in the erased state.
//!
//! Tests (in order):
//!
//! 1. **Init** — construct FMC controller, run hardware init, assert Ready.
//! 2. **PIO read — success path** — issue a read from offset 0; assert the
//! call succeeds and returns the expected byte count. Flash content is not
//! inspected.
//! 3. **PIO read — bounds rejection** — assert that a read past the configured
//! capacity returns `SmcError::InvalidCapacity` before touching hardware.
//! 4. **DMA disabled rejection** — assert that `dma_read` returns
//! `SmcError::DmaNotEnabled` when `SmcConfig::dma_enabled` is false.
#![no_std]
#![no_main]
#[allow(unused_imports)]
use ast10x0_peripherals::scu::pinctrl::PINCTRL_FMC_QUAD;
use ast10x0_peripherals::scu::ScuRegisters;
use ast10x0_peripherals::smc::{
ChipSelect, FlashConfig, SmcConfig, SmcController, SmcError, SmcTopology, UninitSmc,
};
use console_backend::console_backend_write_all;
use target_common::{declare_target, TargetInterface};
use {console_backend as _, entry as _};
#[path = "../target_debug.rs"]
mod target_debug;
use target_debug::{dump_smc_read, dump_smc_register};
pub struct Target {}
#[allow(dead_code)]
fn run_smc_read_test() -> Result<(), SmcError> {
// --- 1. Init ---
// TODO:: set pinctrl in board/src/lib.rs
let scu = unsafe { ScuRegisters::new_global_unlocked() };
scu.apply_pinctrl_group(PINCTRL_FMC_QUAD);
let config = SmcConfig {
controller_id: SmcController::Fmc,
cs0: Some(FlashConfig {
capacity_mb: 8,
page_size: 256,
sector_size: 4096,
block_size: 65536,
spi_clock_mhz: 50,
}),
cs1: Some(FlashConfig {
capacity_mb: 64,
page_size: 256,
sector_size: 4096,
block_size: 65536,
spi_clock_mhz: 50,
}),
dma_enabled: true,
enable_interrupts: false,
topology: SmcTopology::BootSpi { master_idx: 0 },
};
pw_log::info!("=== AST10x0 smc read test ===");
let controller = unsafe { UninitSmc::new(config)? };
let mut controller = controller.init()?;
let _ = match controller.spi_nor_read_init(ChipSelect::Cs0) {
Ok(v) => v,
Err(e) => {
pw_log::info!("Error:: spi_nor_read_init cs0");
return Err(e);
}
};
let _ = match controller.spi_nor_read_init(ChipSelect::Cs1) {
Ok(v) => v,
Err(e) => {
pw_log::info!("Error:: spi_nor_read_init cs1");
return Err(e);
}
};
pw_log::info!("=== Dump 0x7E62_0000 ===");
dump_smc_register(0x7E62_0000, 16);
dump_smc_register(0x8000_0000, 16);
if !controller.is_ready() || controller.controller_id() != SmcController::Fmc {
return Err(SmcError::HardwareError);
}
// --- 2. MMIO read — success path ---
// Confirm the call succeeds and returns the correct byte count. Flash
// content is not inspected so this is safe on both QEMU and silicon.
// TODO: need to add test CS1
pw_log::info!("=== read test cs0===");
let mut buf = [0u8; 64];
let n = controller.read(ChipSelect::Cs0, 0x400, &mut buf)?;
if n != 64 {
return Err(SmcError::HardwareError);
}
dump_smc_read(&buf, 64);
pw_log::info!("=== read test cs1===");
let n = controller.read(ChipSelect::Cs1, 0x400, &mut buf)?;
if n != 64 {
return Err(SmcError::HardwareError);
}
dump_smc_read(&buf, 64);
pw_log::info!("=== read dma test===");
// --- 4. DMA ---
let tempbuf = unsafe { core::slice::from_raw_parts(0x41500 as *mut u8, 256) };
let _ = match controller.dma_read(ChipSelect::Cs0, 0x400, 0x41500 as usize, 256) {
Err(SmcError::InvalidCapacity) => Ok(()),
Err(other) => Err(other),
Ok(()) => Err(SmcError::HardwareError),
};
loop {
match controller.poll_dma_completion() {
core::task::Poll::Pending => {
// still running
}
core::task::Poll::Ready(result) => {
result?;
pw_log::info!("dma completion is ready");
break;
}
}
}
pw_log::info!("=== dma done= ==");
dump_smc_register(0x7E62_0000, 8);
dump_smc_register(0x7E62_0080, 8);
dump_smc_read(tempbuf, 256);
Ok(())
}
impl TargetInterface for Target {
const NAME: &'static str = "AST10x0 SMC read Test";
fn main() -> ! {
let sentinel = if run_smc_read_test().is_ok() {
b"TEST_RESULT:PASS\n"
} else {
b"TEST_RESULT:FAIL\n"
};
let _ = console_backend_write_all(sentinel);
// Physical-board UART tests stop after the sentinel. Semihosting exit
// faults on silicon when no debugger handles the BKPT request.
#[expect(clippy::empty_loop)]
loop {}
}
}
declare_target!(Target);