aboutsummaryrefslogtreecommitdiff
path: root/crates/imxrt1170evk/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/imxrt1170evk/src/lib.rs')
-rw-r--r--crates/imxrt1170evk/src/lib.rs329
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(),
+ )
+ }
}