replaced the old demo-board GPIOM5/GPIOH2 pins with SGPIOM outputs 8/9 for pulse helper. and split it into explicit assert/release operations so monitor setup happens while the BMC is held in reset.
diff --git a/target/ast10x0/board/src/lib.rs b/target/ast10x0/board/src/lib.rs index 78c5ab8..064ddb2 100644 --- a/target/ast10x0/board/src/lib.rs +++ b/target/ast10x0/board/src/lib.rs
@@ -21,7 +21,8 @@ pub use monitor::Ast1060Monitor; pub use spim_wiring::{ apply_spim_external_mux, apply_spim_pinctrl, apply_spim_wiring, apply_spim_wiring_with_log, - presets, spim_external_mux_state, SpimWiring, SpimWiringError, + enable_flash_power, presets, set_bmc_resets, spim_external_mux_state, SpimWiring, + SpimWiringError, }; pub use ast10x0_peripherals::i2c::{I2cConfig, I2cError}; @@ -134,7 +135,7 @@ /// This is a placeholder; production code should use a proper timer or delay provider. /// Spins for approximately `micros` microseconds. #[inline] -pub(crate) fn delay_us(micros: u32) { +pub fn delay_us(micros: u32) { // Very rough approximation: ~16 cycles per microsecond on Cortex-M4 @ ~50MHz // This is calibration-free but inaccurate; improve for production. for _ in 0..(micros * 16) {
diff --git a/target/ast10x0/board/src/spim_wiring.rs b/target/ast10x0/board/src/spim_wiring.rs index f540d52..1aa4fb1 100644 --- a/target/ast10x0/board/src/spim_wiring.rs +++ b/target/ast10x0/board/src/spim_wiring.rs
@@ -12,8 +12,8 @@ use ast10x0_peripherals::scu::{ pinctrl::{ - PINCTRL_SPIM1_DEFAULT, PINCTRL_SPIM2_DEFAULT, PINCTRL_SPIM3_DEFAULT, - PINCTRL_SPIM4_DEFAULT, + PINCTRL_GPIOL2, PINCTRL_GPIOL3, PINCTRL_SPIM1_DEFAULT, PINCTRL_SPIM2_DEFAULT, + PINCTRL_SPIM3_DEFAULT, PINCTRL_SPIM4_DEFAULT, }, ScuError, ScuExtMuxSelect, ScuRegisters, SpiMonitorInstance, SpiMonitorPassthrough, SpiMonitorSource, @@ -202,6 +202,82 @@ } } +/// Enable the flash-power outputs required by older AST1060 demo boards. +#[must_use] +pub fn enable_flash_power(scu: &ScuRegisters) -> bool { + scu.apply_pinctrl_group(PINCTRL_GPIOL2); + scu.apply_pinctrl_group(PINCTRL_GPIOL3); + + const FLASH_POWER_MASK: u32 = (1 << 26) | (1 << 27); + let gpio = unsafe { &*device::Gpio::ptr() }; + gpio.gpio070().modify(|r, w| unsafe { + w.bits(r.bits() | FLASH_POWER_MASK) + }); + gpio.gpio074().modify(|r, w| unsafe { + w.bits(r.bits() | FLASH_POWER_MASK) + }); + crate::delay_us(1_000); + + gpio.gpio0c8().read().bits() & FLASH_POWER_MASK == FLASH_POWER_MASK +} + +/// Assert or release the active-low BMC reset outputs. +/// +/// The prot board routes BMC_SRST to SGPIOM output 8 and BMC_EXTRST to +/// SGPIOM output 9. On assertion EXTRST is driven low first; on release SRST +/// is driven high first. +#[must_use] +pub fn set_bmc_resets(asserted: bool) -> bool { + const BMC_SRST_MASK: u32 = 1 << 8; + const BMC_EXTRST_MASK: u32 = 1 << 9; + + let scu = unsafe { &*device::Scu::ptr() }; + scu.scu41c().modify(|_, w| { + w.enbl_sgpiomaster_ckfn_pin() + .set_bit() + .enbl_sgpiomaster_ldfn_pin() + .set_bit() + .enbl_sgpiomaster_dofn_pin() + .set_bit() + .enbl_sgpiomaster_difn_pin() + .set_bit() + }); + + let sgpio = unsafe { &*device::Sgpiom::ptr() }; + sgpio.gpio554().modify(|_, w| unsafe { + w.enbl_of_serial_gpio() + .set_bit() + .numbers_of_serial_gpiopins() + .bits(16) + .serial_gpioclk_division() + .bits(24) + }); + + let output_high = !asserted; + let first_mask = if asserted { + BMC_EXTRST_MASK + } else { + BMC_SRST_MASK + }; + let second_mask = if asserted { + BMC_SRST_MASK + } else { + BMC_EXTRST_MASK + }; + + for mask in [first_mask, second_mask] { + let latch = sgpio.gpio570().read().bits(); + sgpio + .gpio500() + .write(|w| unsafe { w.bits(update_bit(latch, mask, output_high)) }); + crate::delay_us(10_000); + } + + let latch = sgpio.gpio570().read().bits(); + let reset_mask = BMC_SRST_MASK | BMC_EXTRST_MASK; + (latch & reset_mask == reset_mask) == output_high +} + #[derive(Clone, Copy)] enum ExternalMuxGpioGroup { Abcd,
diff --git a/target/ast10x0/peripherals/scu/pinctrl.rs b/target/ast10x0/peripherals/scu/pinctrl.rs index 9d90f54..2b5f872 100644 --- a/target/ast10x0/peripherals/scu/pinctrl.rs +++ b/target/ast10x0/peripherals/scu/pinctrl.rs
@@ -538,8 +538,14 @@ } // GPIO +pub const PINCTRL_GPIOH2: &[PinctrlPin] = &[ + CLR_PIN_SCU414_26, + CLR_PIN_SCU4B4_26, + CLR_PIN_SCU694_26, +]; pub const PINCTRL_GPIOL2: &[PinctrlPin] = &[CLR_PIN_SCU418_26]; pub const PINCTRL_GPIOL3: &[PinctrlPin] = &[CLR_PIN_SCU418_27]; +pub const PINCTRL_GPIOM5: &[PinctrlPin] = &[CLR_PIN_SCU41C_5]; /// I2C1 pin group: SCL2/SDA2 mux selection on SCU414[30:31]. ///
diff --git a/target/ast10x0/peripherals/smc/controller.rs b/target/ast10x0/peripherals/smc/controller.rs index eaf74de..bef0003 100644 --- a/target/ast10x0/peripherals/smc/controller.rs +++ b/target/ast10x0/peripherals/smc/controller.rs
@@ -618,8 +618,7 @@ let reg = self.regs.read_cs_ctrl(cs); self.regs .write_cs_ctrl(cs, (reg & !SPI_CTRL_FREQ_MASK) | encoded_div); - let val = self.normal_read_ctrl(cs) & ((!SPI_CTRL_FREQ_MASK) | encoded_div); - self.set_normal_read_ctrl(cs, val); + self.normal_read_ctrl[cs_idx] = self.regs.read_cs_ctrl(cs); Ok(()) }
diff --git a/target/ast10x0/tests/smc/read/BUILD.bazel b/target/ast10x0/tests/smc/read/BUILD.bazel index 3caf693..d437777 100644 --- a/target/ast10x0/tests/smc/read/BUILD.bazel +++ b/target/ast10x0/tests/smc/read/BUILD.bazel
@@ -63,8 +63,8 @@ ":codegen", ":linker_script", "//target/ast10x0:entry", + "//target/ast10x0/board:ast10x0_board", "//target/ast10x0/peripherals", - "@ast1060_pac", "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", "@pigweed//pw_kernel/kernel", "@pigweed//pw_kernel/subsys/console:console_backend",
diff --git a/target/ast10x0/tests/smc/read/target_spi2.rs b/target/ast10x0/tests/smc/read/target_spi2.rs index 43759a1..7901877 100644 --- a/target/ast10x0/tests/smc/read/target_spi2.rs +++ b/target/ast10x0/tests/smc/read/target_spi2.rs
@@ -5,12 +5,11 @@ #![no_std] #![no_main] -use ast1060_pac as device; +use ast10x0_board::{apply_spim_external_mux, enable_flash_power}; #[allow(unused_imports)] use ast10x0_peripherals::scu::{ pinctrl::{ - PINCTRL_GPIOL2, PINCTRL_GPIOL3, PINCTRL_SPI2_QUAD, PINCTRL_SPIM3_DEFAULT, - PINCTRL_SPIM4_DEFAULT, + PINCTRL_SPI2_QUAD, PINCTRL_SPIM3_DEFAULT, PINCTRL_SPIM4_DEFAULT, }, ScuExtMuxSelect, ScuRegisters, SpiMonitorInstance, SpiMonitorPassthrough, SpiMonitorSource, }; @@ -35,91 +34,17 @@ }; pub struct Target {} -/* -SCU418 = 0x7E6E_2418, clear bits 26, 27 -GPIO070 = 0x7E78_0070, set bits 26, 27 -GPIO074 = 0x7E78_0074, set bits 26, 27 -*/ -fn gpio_flash_power() { - const GPIOL2_L3_MASK: u32 = (1 << 26) | (1 << 27); - - // SAFETY: Board initialization has exclusive access to the PAC singleton. - let gpio = unsafe { &*device::Gpio::ptr() }; - gpio.gpio070() - .modify(|r, w| unsafe { w.bits(r.bits() | GPIOL2_L3_MASK) }); - gpio.gpio074() - .modify(|r, w| unsafe { w.bits(r.bits() | GPIOL2_L3_MASK) }); - - for _ in 0..1_000_000 { - core::hint::spin_loop(); - } -} - -#[allow(dead_code)] -fn configure_spi2_external_mux(select_mux1: bool) { - const GPIO_E8: u32 = 1 << 8; - const SGPIOM_A_D_2: u32 = 1 << 2; - - // SAFETY: Board initialization has exclusive access to the PAC singletons. - let gpio = unsafe { &*device::Gpio::ptr() }; - let sgpio = unsafe { &*device::Sgpiom::ptr() }; - let _scu_unlocked = unsafe { ScuRegisters::new_global_unlocked() }; - let scu = unsafe { &*device::Scu::ptr() }; - - scu.scu41c().modify(|_, w| { - w.enbl_sgpiomaster_ckfn_pin() - .set_bit() - .enbl_sgpiomaster_ldfn_pin() - .set_bit() - .enbl_sgpiomaster_dofn_pin() - .set_bit() - .enbl_sgpiomaster_difn_pin() - .set_bit() - }); - sgpio.gpio554().modify(|_, w| unsafe { - w.enbl_of_serial_gpio() - .set_bit() - .numbers_of_serial_gpiopins() - .bits(16) - .serial_gpioclk_division() - .bits(24) - }); - - gpio.gpio020().modify(|r, w| unsafe { - let bits = if select_mux1 { - r.bits() | GPIO_E8 - } else { - r.bits() & !GPIO_E8 - }; - w.bits(bits) - }); - gpio.gpio024() - .modify(|r, w| unsafe { w.bits(r.bits() | GPIO_E8) }); - - let sgpio_latch = sgpio.gpio570().read().bits(); - let sgpio_data = if select_mux1 { - sgpio_latch | SGPIOM_A_D_2 - } else { - sgpio_latch & !SGPIOM_A_D_2 - }; - sgpio.gpio500().write(|w| unsafe { w.bits(sgpio_data) }); - - // Match the overlay's ext-mux-sel-delay-us = <1000>. - for _ in 0..100_000 { - core::hint::spin_loop(); - } -} fn config_spi2_master_controller() -> Result<(), SmcError> { let scu = unsafe { ScuRegisters::new_global_unlocked() }; scu.apply_pinctrl_group(PINCTRL_SPIM3_DEFAULT); scu.apply_pinctrl_group(PINCTRL_SPIM4_DEFAULT); scu.apply_pinctrl_group(PINCTRL_SPI2_QUAD); - scu.apply_pinctrl_group(PINCTRL_GPIOL2); - scu.apply_pinctrl_group(PINCTRL_GPIOL3); - gpio_flash_power(); - //configure spi2 external mux through gpio pins - configure_spi2_external_mux(true); + if !enable_flash_power(&scu) { + pw_log::info!("GPIOL2/GPIOL3 flash power readback failed"); + return Err(SmcError::HardwareError); + } + apply_spim_external_mux(SpiMonitorInstance::Spim2, ScuExtMuxSelect::Mux1); // Configure the mux for the SPI master controller path. scu.set_spim_internal_master_route(SpiMonitorInstance::Spim2, SpiMonitorSource::Spi2);
diff --git a/target/ast10x0/tests/spimonitor/setup_all_spim.rs b/target/ast10x0/tests/spimonitor/setup_all_spim.rs index a041959..820dac6 100644 --- a/target/ast10x0/tests/spimonitor/setup_all_spim.rs +++ b/target/ast10x0/tests/spimonitor/setup_all_spim.rs
@@ -11,6 +11,7 @@ #[path = "test_common.rs"] mod test_common; +use ast10x0_board::{delay_us, enable_flash_power, set_bmc_resets}; use ast10x0_peripherals::scu::{ScuRegisters, SpiMonitorInstance}; use ast10x0_peripherals::spimonitor::{ MonitorPolicy, PrivilegeDirection, PrivilegeOp, SpiMonitorController, @@ -60,6 +61,9 @@ 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x3b, 0x3c, 0x70, 0xbb, 0xbc, 0x50, 0xeb, 0xec, 0xc2, ]; +const SPIM4_ALLOW_COMMANDS: [u8; 15] = [ + 0x01, 0x06, 0x04, 0x20, 0x21, 0xb7, 0xe9, 0x32, 0x34, 0xd8, 0xdc, 0x02, 0x12, 0x50, 0xc2, +]; fn log_buffer(log: &'static LogRam) -> &'static mut [u32] { // SAFETY: The caller assigns each static buffer to exactly one monitor. @@ -79,9 +83,38 @@ policy } +fn spim4_test_policy() -> MonitorPolicy { + let mut policy = MonitorPolicy::empty(); + policy.allow_commands[..SPIM4_ALLOW_COMMANDS.len()] + .copy_from_slice(&SPIM4_ALLOW_COMMANDS); + policy.allow_command_count = SPIM4_ALLOW_COMMANDS.len(); + let _ = policy.add_region( + 0, + WRITE_PROTECTED_LENGTH, + PrivilegeDirection::Write, + PrivilegeOp::Disable, + ); + policy +} + fn setup_all_spim() -> Result<(), test_common::TestError> { let scu = unsafe { ScuRegisters::new_global_unlocked() }; let policy = production_policy(); + let spim4_policy = spim4_test_policy(); + + pw_log::info!("=== GPIO flash power ==="); + if !enable_flash_power(&scu) { + pw_log::info!("FAIL: GPIOL2/GPIOL3 flash power readback"); + return Err(test_common::TestError::Check); + } + pw_log::info!("PASS: GPIOL2 and GPIOL3 set high"); + + pw_log::info!("=== Hold BMC in reset ==="); + if !set_bmc_resets(true) { + pw_log::info!("FAIL: SGPIOM BMC reset outputs did not assert"); + return Err(test_common::TestError::Check); + } + pw_log::info!("PASS: SGPIOM outputs 8 and 9 asserted low"); pw_log::info!("=== SPIM1 ==="); test_common::configure_wiring::<Spim1Config>(&scu)?; @@ -111,15 +144,31 @@ let _spim3 = test_common::lock_monitor(spim3)?; pw_log::info!("=== SPIM4 ==="); + pw_log::info!("SPIM4 test policy blocks all read commands"); test_common::configure_wiring::<Spim4Config>(&scu)?; let spim4 = test_common::initialize_monitor_with_policy::<Spim4Config>( log_buffer(&SPIM4_LOG), - &policy, + &spim4_policy, )?; test_common::dump_policy(&spim4, WRITE_PROTECTED_LENGTH)?; let _spim4 = test_common::lock_monitor(spim4)?; pw_log::info!("All SPIM1-4 monitors are configured and locked"); + pw_log::info!( + "SCU0F0 after SPIM setup: 0x{:08x}", + scu.route_control_raw() as u32 + ); + + pw_log::info!("Waiting 60 ms for flash routing to settle"); + delay_us(60_000); + + pw_log::info!("=== Release BMC reset ==="); + if !set_bmc_resets(false) { + pw_log::info!("FAIL: SGPIOM BMC reset outputs did not release"); + return Err(test_common::TestError::Check); + } + pw_log::info!("PASS: SGPIOM outputs 8 and 9 released high"); + pw_log::info!("Firmware will remain active until the user stops or resets it"); Ok(()) }
diff --git a/target/ast10x0/tests/spimonitor/test_common.rs b/target/ast10x0/tests/spimonitor/test_common.rs index d252f89..837930f 100644 --- a/target/ast10x0/tests/spimonitor/test_common.rs +++ b/target/ast10x0/tests/spimonitor/test_common.rs
@@ -90,17 +90,14 @@ scu.set_spim_miso_multi_func(C::INSTANCE, true); scu.set_spim_filter(C::INSTANCE, true); - apply_spim_external_mux(C::INSTANCE, ScuExtMuxSelect::Mux0); - test_check!( - spim_external_mux_state(C::INSTANCE) == Some(ScuExtMuxSelect::Mux0), - "FAIL: external mux 0 GPIO readback" - ); + // This board provides ext-mux-sel-gpios. Match the Zephyr driver by + // driving those GPIOs only; SCU0F0[15:12] is used only when no external + // mux GPIOs are described. apply_spim_external_mux(C::INSTANCE, ScuExtMuxSelect::Mux1); test_check!( spim_external_mux_state(C::INSTANCE) == Some(ScuExtMuxSelect::Mux1), "FAIL: external mux 1 GPIO readback" ); - scu.set_spim_ext_mux(C::INSTANCE, ScuExtMuxSelect::Mux1); test_check!( scu.route_control_raw() & 0x0f == 0,