diff options
Diffstat (limited to 'crates/imxrt1170evk/src/lib.rs')
| -rw-r--r-- | crates/imxrt1170evk/src/lib.rs | 329 |
1 files changed, 271 insertions, 58 deletions
diff --git a/crates/imxrt1170evk/src/lib.rs b/crates/imxrt1170evk/src/lib.rs index b626843..1b2aad7 100644 --- a/crates/imxrt1170evk/src/lib.rs +++ b/crates/imxrt1170evk/src/lib.rs @@ -2,14 +2,25 @@ #![feature(rustc_private)] extern crate fusible; +use core::net::Ipv4Addr; +use core::num::NonZeroU8; use core::pin::Pin; -use imxrt_ral as ral; use imxrt_rt as _; use imxrt1170evk_fcb as _; use rust_threadx_cortex_m as _; +use rust_threadx_imxrt::*; use rust_threadx_stdio_semihosting as _; +use drivers::{enet, gpio}; + +use imxrt1170::interrupt; + +use fusible::netx_duo::{ + ip::{Ip, IpContext}, + packet::{PacketPool, PacketPoolContext, StaticPacketStorage, packet_storage_size}, +}; + #[doc(hidden)] #[unsafe(no_mangle)] pub unsafe extern "C" fn _tx_initialize_low_level() { @@ -35,83 +46,285 @@ pub unsafe extern "C" fn _tx_initialize_low_level() { SYST.enable_interrupt(); SYST.enable_counter(); } +} - unsafe { - use ral::ccm; +use fusible::thread::{StaticStack, Thread, ThreadContext}; +static STACK: StaticStack<512> = StaticStack::new(); +static THREAD: ThreadContext = Thread::context(); - let ccm = ccm::CCM::instance(); - let clock_root = &ccm.CLOCK_ROOT[8]; - ral::modify_reg!(ccm::clockroot, clock_root, CLOCK_ROOT_CONTROL, MUX: 1, DIV: 240 - 1); - } +#[unsafe(no_mangle)] +#[doc(hidden)] +pub extern "C" fn __rust_threadx_app_define() { + configure_clocks(); + configure_pins(); unsafe { - use ral::iomuxc; - let iomuxc = iomuxc::IOMUXC::instance(); + cortex_m::peripheral::NVIC::unmask(interrupt::ENET); - ral::write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD_GPIO_AD_04, MUX_MODE: 5, SION: 0); + let gpio3 = GPIO3.create(const { imxrt1170::instances::gpio3() }); + let gpio6 = GPIO6.create(const { imxrt1170::instances::gpio6() }); - ral::write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD_GPIO_AD_04, PUE: 0); - } + let led = gpio3.make_output(gpio::IO::IO03); + let phy_rst = gpio6.make_output(gpio::IO::IO12); - unsafe { - use ral::gpio; - let gpio3 = gpio::GPIO3::instance(); + let enet = ENET.create( + imxrt1170::instances::enet(), + ENET_TX_RING.as_slice(), + ENET_RX_RING.as_slice(), + rust_threadx_net_phys::ksz8081::Ksz8081::new(), + phy_rst, + BUS_FREQUENCY_HZ, + ); + + let pool = PacketPool::create( + Pin::static_ref(&PACKET_POOL), + PACKET_STORAGE.0.take().unwrap(), + 1536 / 12, + &Default::default(), + ) + .unwrap(); - const GPIO3_OUTPUTS: u32 = led::MASK; + let ip = Ip::create( + Pin::static_ref(&IP), + Ipv4Addr::new(192, 168, 5, 1), + 0xffff_ff00, + pool, + enet, + IP_THREAD_STACK.take().unwrap(), + &Default::default(), + ) + .unwrap(); - ral::write_reg!(gpio, gpio3, GDIR, GPIO3_OUTPUTS); + ip.set_physical_address(0x0011, 0x22334456); + ip.enable_arp(); + ip.enable_udp(); + ip.enable_icmp(); + + Thread::create( + Pin::static_ref(&THREAD), + STACK.take().unwrap(), + &Default::default(), + move || loop { + fusible::thread::sleep(25); + led.toggle(); + }, + ) + .unwrap(); } } -/// Controls the LED. -pub mod led { - use crate::ral::gpio; +#[unsafe(no_mangle)] +#[doc(hidden)] +pub extern "C" fn __rust_threadx_ip() -> Option<&'static Ip> { + Pin::static_ref(&IP).try_created() +} - pub(crate) const MASK: u32 = 1 << 3; +fn configure_clocks() { + use imxrt1170::{ccm, gpc_cpu_mode_ctrl as gpc_cpu, pmu}; - /// Turn on the LED. - #[inline] - pub fn set() { - unsafe { crate::ral::write_reg!(gpio, gpio::GPIO3, DR_SET, MASK) }; - } + let ccm = unsafe { imxrt1170::instances::ccm() }; + let pmu = unsafe { imxrt1170::instances::pmu() }; + let gpc_cpu = unsafe { imxrt1170::instances::gpc_cpu_mode_ctrl0() }; + let pll = unsafe { imxrt1170::instances::pll() }; - /// Turn off the LED. - #[inline] - pub fn clear() { - unsafe { crate::ral::write_reg!(gpio, gpio::GPIO3, DR_CLEAR, MASK) }; - } + // Switch the core to something stable before we + // start changing upstream sources. + ccm::set_clock_root( + ccm, + ccm::ClockRoot::M7, + const { ccm::mux(ccm::ClockRoot::M7, ccm::ClockSource::Xtal) }, + NO_DIVIDER, + ); + ccm::set_clock_root( + ccm, + ccm::ClockRoot::Bus, + const { ccm::mux(ccm::ClockRoot::Bus, ccm::ClockSource::Xtal) }, + NO_DIVIDER, + ); + ccm::set_clock_root( + ccm, + ccm::ClockRoot::BusLpsr, + const { ccm::mux(ccm::ClockRoot::BusLpsr, ccm::ClockSource::Xtal) }, + NO_DIVIDER, + ); + ccm::set_clock_root( + ccm, + ccm::ClockRoot::M7Systick, + const { ccm::mux(ccm::ClockRoot::M7Systick, ccm::ClockSource::Xtal) }, + const { NonZeroU8::new(240).unwrap() }, + ); + + pmu::enable_pll_reference_voltage(pmu, true); + pmu::set_phy_ldo_setpoints(pmu, u16::MAX); + pmu::enable_phy_ldo_setpoints(pmu); + pmu::enable_pll_reference_setpoints(pmu); - /// Toggle the LED. - /// - /// This is achieved in hardware, without reading the current state - /// of the LED. It's usually more efficient. - #[inline] - pub fn toggle() { - unsafe { crate::ral::write_reg!(gpio, gpio::GPIO3, DR_TOGGLE, MASK) }; + for clock_source in { + use ccm::ClockSource::*; + [ + Pll1, Pll1Clk, Pll1Div2, Pll1Div5, ArmPll, ArmPllClk, // + Pll2, Pll2Clk, Pll2Pfd0, Pll2Pfd1, Pll2Pfd2, Pll2Pfd3, // + Pll3, Pll3Clk, Pll3Div2, Pll3Pfd0, Pll3Pfd1, Pll3Pfd2, Pll3Pfd3, // + ] + } { + ccm::set_source_setpoints(ccm, clock_source, u16::MAX, 0); + ccm::enable_source_setpoints(ccm, clock_source).unwrap(); } - /// Drive the LED on or off. - #[inline] - pub fn drive(value: bool) { - if value { set() } else { clear() } + ccm::pll::enable_sys_pll1_setpoints(pll); + ccm::pll::enable_arm_pll_setpoints(pll, ARM_PLL_POST_DIV, ARM_PLL_DIV_SELECT); + ccm::pll::enable_sys_pll2_setpoints(pll); + ccm::pll::enable_sys_pll3_setpoints(pll); + + gpc_cpu::request_setpoint_transition(gpc_cpu, 1).unwrap(); + + ccm::pll::set_pll3_pfd_fracs( + pll, + [ + SYS_PLL3_PFD0_DIV, + SYS_PLL3_PFD1_DIV, + SYS_PLL3_PFD2_DIV, + SYS_PLL3_PFD3_DIV, + ], + ); + ccm::pll::update_pll3_pfd_fracs(pll, [true, true, true, true]); + + ccm::set_clock_root( + ccm, + ccm::ClockRoot::M7, + const { ccm::mux(ccm::ClockRoot::M7, ccm::ClockSource::ArmPll) }, + M7_DIVIDER, + ); + + ccm::set_clock_root( + ccm, + ccm::ClockRoot::Bus, + const { ccm::mux(ccm::ClockRoot::Bus, ccm::ClockSource::Pll1Div5) }, + BUS_DIVIDER, + ); + + ccm::set_clock_root( + ccm, + ccm::ClockRoot::Enet, + const { ccm::mux(ccm::ClockRoot::Enet, ccm::ClockSource::Pll1Div2) }, + const { NonZeroU8::new((SYS_PLL1_DIV2_FREQUENCY_HZ / ENET_FREQUENCY_HZ) as u8).unwrap() }, + ); +} + +const NO_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap(); +const M7_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap(); +const BUS_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap(); +const FLEXSPI1_DIVIDER: NonZeroU8 = NonZeroU8::new(2).unwrap(); + +pub const XTAL_FREQUENCY_HZ: u32 = 24_000_000; +pub const BUS_FREQUENCY_HZ: u32 = SYS_PLL1_DIV5_FREQUENCY_HZ / BUS_DIVIDER.get() as u32; +pub const ENET_FREQUENCY_HZ: u32 = 50_000_000; +pub const SYS_PLL1_FREQUENCY_HZ: u32 = 1_000_000_000; +pub const SYS_PLL1_DIV2_FREQUENCY_HZ: u32 = SYS_PLL1_FREQUENCY_HZ / 2; +pub const SYS_PLL1_DIV5_FREQUENCY_HZ: u32 = SYS_PLL1_FREQUENCY_HZ / 5; +pub const M7_FREQUENCY_HZ: u32 = ARM_PLL_FREQUENCY_HZ / M7_DIVIDER.get() as u32; +pub const SYS_PLL2_FREQUENCY_HZ: u32 = 528_000_000; +pub const SYS_PLL3_FREQUENCY_HZ: u32 = 480_000_000; +pub const FLEXSPI1_FREQUENCY_HZ: u32 = + SYS_PLL3_FREQUENCY_HZ / SYS_PLL3_PFD0_DIV.get() as u32 / FLEXSPI1_DIVIDER.get() as u32 * 18; + +const ARM_PLL_DIV_SELECT: imxrt1170::ccm::pll::ArmPllDivSelect = + imxrt1170::ccm::pll::ArmPllDivSelect::new(200).unwrap(); +const ARM_PLL_POST_DIV: imxrt1170::ccm::pll::ArmPllPostDiv = + imxrt1170::ccm::pll::ArmPllPostDiv::Div4; +const ARM_PLL_FREQUENCY_HZ: u32 = + imxrt1170::ccm::pll::arm_pll_frequency(ARM_PLL_POST_DIV, ARM_PLL_DIV_SELECT); +const SYS_PLL3_PFD0_DIV: imxrt1170::ccm::pll::PfdFrac = + imxrt1170::ccm::pll::PfdFrac::new(33).unwrap(); +const SYS_PLL3_PFD1_DIV: imxrt1170::ccm::pll::PfdFrac = + imxrt1170::ccm::pll::PfdFrac::new(27).unwrap(); +const SYS_PLL3_PFD2_DIV: imxrt1170::ccm::pll::PfdFrac = + imxrt1170::ccm::pll::PfdFrac::new(21).unwrap(); +const SYS_PLL3_PFD3_DIV: imxrt1170::ccm::pll::PfdFrac = + imxrt1170::ccm::pll::PfdFrac::new(17).unwrap(); + +fn configure_pins() { + use imxrt1170::{ + iomuxc::{self, select_input}, + iomuxc_gpr, iomuxc_lpsr, + }; + + let iomuxc = unsafe { imxrt1170::instances::iomuxc() }; + let iomuxc_gpr = unsafe { imxrt1170::instances::iomuxc_gpr() }; + let iomuxc_lpsr = unsafe { imxrt1170::instances::iomuxc_lpsr() }; + + // ENET_REF_CLK driven as output. + modify_reg!(iomuxc_gpr, iomuxc_gpr, GPR[4], |gpr| gpr | (1 << 1)); + // ERR050396 handling. + modify_reg!(iomuxc_gpr, iomuxc_gpr, GPR[28], |gpr| gpr + | (1 << 5) + | (1 << 7)); + + // LED. + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[4], MUX_MODE: 5); + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[4], PUE: 0); + + // ENET PHY_RST. + write_reg!(iomuxc_lpsr, iomuxc_lpsr, SW_MUX_CTL_PAD[12], MUX_MODE: 5); + + // ENET RMII. + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[32], MUX_MODE: 3, SION: 0); // MDC + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[33], MUX_MODE: 3, SION: 0); // MDIO + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[2], MUX_MODE: 1, SION: 0); // TX_DATA0 + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[3], MUX_MODE: 1, SION: 0); // TX_DATA1 + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[4], MUX_MODE: 1, SION: 0); // TX_EN + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[5], MUX_MODE: 2, SION: 1); // REF_CLK + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[6], MUX_MODE: 1, SION: 1); // RX_DATA0 + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[7], MUX_MODE: 1, SION: 1); // RX_DATA1 + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[8], MUX_MODE: 1, SION: 0); // RX_EN + write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[9], MUX_MODE: 1, SION: 0); // RX_ER + + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[32], PUE: 1, PUS: PULL_UP, ODE: 0); // MDC + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[33], PUE: 1, PUS: PULL_UP, ODE: 1); // MDIO + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[2], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_DATA0 + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[3], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_DATA1 + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[4], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_EN + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[5], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // REF_CLK + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[6], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_DATA0 + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[7], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_DATA1 + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[8], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_EN + write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[9], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_ER + + for select_input in [ + select_input::ENET_IPG_CLK_RMII, + select_input::ENET_MAC0_MDIO, + select_input::ENET_MAC0_RXDATA_0, + select_input::ENET_MAC0_RXDATA_1, + select_input::ENET_MAC0_RXEN, + select_input::ENET_MAC0_RXERR, + ] { + write_reg!(iomuxc, iomuxc, SELECT_INPUT[select_input], 1); } } -use fusible::thread::{StaticStack, Thread, ThreadContext}; -static STACK: StaticStack<512> = StaticStack::new(); -static THREAD: ThreadContext = Thread::context(); +type Enet = drivers::enet::Enet<rust_threadx_net_phys::ksz8081::Ksz8081>; -#[unsafe(no_mangle)] -#[doc(hidden)] -pub extern "C" fn __rust_threadx_app_define() { - Thread::create( - Pin::static_ref(&THREAD), - STACK.take().unwrap(), - &Default::default(), - || loop { - fusible::thread::sleep(25); - led::toggle(); - }, - ) - .unwrap(); +static ENET: enet::EnetContext = enet::EnetContext::new(); +static ENET_TX_RING: enet::TxRing<16> = enet::TxRing::ZEROED; +static ENET_RX_RING: enet::RxRing<16> = enet::RxRing::ZEROED; +static IP: IpContext<Enet> = Ip::context(); + +#[repr(align(64))] +pub struct AlignedPacketStorage(StaticPacketStorage<{ packet_storage_size(8 * 12, 1536 / 12) }>); + +static PACKET_POOL: PacketPoolContext = PacketPool::context(); +static PACKET_STORAGE: AlignedPacketStorage = AlignedPacketStorage(StaticPacketStorage::new()); +static IP_THREAD_STACK: StaticStack<4096> = StaticStack::new(); + +static GPIO3: gpio::GpioContext = gpio::GpioContext::new(); +static GPIO6: gpio::GpioContext = gpio::GpioContext::new(); + +#[imxrt_rt::interrupt] +fn ENET() { + unsafe { + ENET.on_interrupt( + const { imxrt1170::instances::enet() }, + Pin::static_ref(&IP).assume_created(), + ) + } } |
