diff --git a/boards/bootloaders/imx8mn/debug.md b/boards/bootloaders/imx8mn/debug.md index c3933d6e..c50f7e1e 100644 --- a/boards/bootloaders/imx8mn/debug.md +++ b/boards/bootloaders/imx8mn/debug.md @@ -8,29 +8,46 @@ Port /dev/tty.usbserial-1101, 11:47:54 Press Meta-Z for help on special keys -[ 0.000249] imx8mn-rs version 0.1.0 -[ 0.003708] Booting on: i.MX 8M Nano EVK -[ 0.007704] Current privilege level: EL3 -[ 0.011687] Exception handling state: -[ 0.015486] Debug: Masked -[ 0.018770] SError: Unmasked -[ 0.022237] IRQ: Masked -[ 0.025530] FIQ: Masked -[ 0.028797] Drivers loaded: -[ 0.031522] 1. i.MX8M Uart2 -[ 0.034975] Chars written: 382 -[ 0.038089] uSDHC2 has support for 1.8v, 3.0v, 3.3v ... -[ 0.043339] Sd host circuit reset in 4us -[ 0.047362] Sd clock stablized in 38us -[ 0.051125] Prescaler = 64, Divisor = 16, Freq Set = 390625 -[ 0.057011] Sd: sending command, CMD_NAME: "GO_IDLE_STATE", CMD_CODE: 0x00000000, CMD_ARG: 0x00000000 -[ 0.069780] Sd: sending command, CMD_NAME: "SEND_IF_COND", CMD_CODE: 0x081a0000, CMD_ARG: 0x000001aa -[ 0.084405] Error: we got a response for the last cmd but it contains errors, decode contents of interrupt status register for details - VendSpec: 0x20007879, SysCtrl: 0x008f20ff, ProtCtrl: 0x08800020, PresentStatus: 0xf0058088, intStatus: 0x000c8001, Resp0: 0x00000000, Resp1: 0x00000000, -Resp2: 0x00000000, Resp3: 0x00000000, CC_bit set in 4084us +[ 0.000005] imx8mn-rs version 0.1.0 +[ 0.003584] Booting on: i.MX 8M Nano EVK +[ 0.007607] Current privilege level: EL3 +[ 0.011545] Exception handling state: +[ 0.015345] Debug: Masked +[ 0.018591] SError: Unmasked +[ 0.022112] IRQ: Masked +[ 0.025395] FIQ: Masked +[ 0.028603] Drivers loaded: +[ 0.031523] 1. i.MX8M Uart2 +[ 0.034965] Chars written: 382 +[ 0.037976] uSDHC2 supports 1.8v, 3.0v, 3.3v ... +[ 0.042765] Sd clock stablized in 38us +[ 0.046555] Prescaler = 64, Divisor = 16, Freq = 390625 Hz +[ 0.052420] Sd: sending command, CMD_NAME: "GO_IDLE_STATE", CMD_CODE: 0x00000000, CMD_ARG: 0x00000000 +[ 0.065373] Sd: sending command, CMD_NAME: "SEND_IF_COND", CMD_CODE: 0x081a0000, CMD_ARG: 0x000001aa +[ 0.076527] Sd: sending command, CMD_NAME: "APP_CMD", CMD_CODE: 0x371a0000, CMD_ARG: 0x00000000 +[ 0.087369] Sd: sending command, CMD_NAME: "APP_SEND_OP_COND", CMD_CODE: 0x29020000, CMD_ARG: 0x50ff8000 +[ 0.499191] Sd: sending command, CMD_NAME: "APP_CMD", CMD_CODE: 0x371a0000, CMD_ARG: 0x00000000 +[ 0.509984] Sd: sending command, CMD_NAME: "APP_SEND_OP_COND", CMD_CODE: 0x29020000, CMD_ARG: 0x50ff8000 +[ 0.521794] Sd: sending command, CMD_NAME: "ALL_SEND_CID", CMD_CODE: 0x02090000, CMD_ARG: 0x00000000 +[ 0.533471] Sd: sending command, CMD_NAME: "SEND_REL_ADDR", CMD_CODE: 0x03020000, CMD_ARG: 0x00000000 +[ 0.544576] Sd: sending command, CMD_NAME: "SEND_CSD", CMD_CODE: 0x09010000, CMD_ARG: 0x00010000 +[ 0.555735] CSD Contents : 00 40 0e 00 32 5b 59 00 003b 83 7f 80 0a 40 00 +[ 0.562789] cemmc_structure=1, spec_vers=0, taac=0x0E, nsac=0x00, tran_speed=0x32,ccc=0x05B5, read_bl_len=0x09, read_bl_partial=0b, write_blk_misalign=0b,read_blk_misalign=0b, dsr_imp=0b, sector_size =0x7F, erase_blk_en=1b +[ 0.583485] CSD 2.0: ver2_c_size = 0x3BFF, card capacity: 7987527680 bytes or 7.99GiB +[ 0.591571] wp_grp_size=0x0000000b, wp_grp_enable=0b, default_ecc=00b, r2w_factor=010b, write_bl_len=0x09, write_bl_partial=0b, file_format_grp=0, copy=0b, perm_write_protect=0b, tmp_write_protect=0b, file_format=0b ecc=00b +[ 0.612260] Sd clock stablized in 0us +[ 0.616093] Prescaler = 1, Divisor = 8, Freq = 50000000 Hz +[ 0.621697] Sd: sending command, CMD_NAME: "CARD_SELECT", CMD_CODE: 0x07030000, CMD_ARG: 0x00010000 +[ 0.632286] Sd: sending command, CMD_NAME: "APP_CMD_RCA", CMD_CODE: 0x37020000, CMD_ARG: 0x00010000 +[ 0.642606] Sd: sending command, CMD_NAME: "SEND_SCR", CMD_CODE: 0x333a0000, CMD_ARG: 0x00000000 +[ 0.653013] SCR bus width: WIDTH_1_4 +[ 0.656649] Sd: sending command, CMD_NAME: "APP_CMD_RCA", CMD_CODE: 0x37020000, CMD_ARG: 0x00010000 +[ 0.667078] Sd: sending command, CMD_NAME: "SET_BUS_WIDTH", CMD_CODE: 0x06020000, CMD_ARG: 0x00010002 +[ 0.677648] Sd Bus width set to 4 +[ 0.680970] Sd: sending command, CMD_NAME: "SET_BLOCKLEN", CMD_CODE: 0x10000000, CMD_ARG: 0x00000200 +[ 0.691651] Sd Card: Type 2 HC, 7617Mb, mfr_id: 150, 'DE:SD', r2.0, mfr_date: 1/2021, serial: 0x424f0218, RCA: 0x0001 +[ 0.703020] uSDHC driver initialized +[ 0.706679] -[ 0.118136] SdError: Send interface condition command (CMD8) returned an error -[ 0.125688] failed to initialize -[ 0.128972] -[ 0.130618] ... wait forever +[ 0.708156] ... wait forever ``` \ No newline at end of file diff --git a/boards/bootloaders/imx8mn/src/boot.rs b/boards/bootloaders/imx8mn/src/boot.rs index 5e6c0a6d..5a6fee0a 100644 --- a/boards/bootloaders/imx8mn/src/boot.rs +++ b/boards/bootloaders/imx8mn/src/boot.rs @@ -6,7 +6,7 @@ use crate::kernel_init; use crate::{ clocks, exception, memory, mux::{uart2grp::uart2_mux_mmio_set, usdhc2grp::usdhc2_mux_mmio_set}, - start_system_counter, sys_clocks_init, + start_system_counter, }; // Assembly counterpart to this file. @@ -26,8 +26,6 @@ pub unsafe extern "C" fn _start_rust() -> ! { clocks::scntrclk::enable_sctr(); // start the system counter, this allows us to access ARM's architectural counter - CNTPCT_EL0 start_system_counter(); - // initialize system clocks - sys_clocks_init(); // enable Uart and uSDHC clock clocks::uartclks::enable_uart_clk(1); clocks::usdhcclks::enable_usdhc_clk(2); diff --git a/boards/bootloaders/imx8mn/src/main.rs b/boards/bootloaders/imx8mn/src/main.rs index 670c914e..16436988 100644 --- a/boards/bootloaders/imx8mn/src/main.rs +++ b/boards/bootloaders/imx8mn/src/main.rs @@ -12,7 +12,7 @@ use rustBoot_hal::nxp::imx8mn::bsp::{ clocks, drivers::{ common::interface::DriverManager, - driver_manager::{driver_manager, start_system_counter, sys_clocks_init}, + driver_manager::{driver_manager, start_system_counter}, }, global, mux, }; @@ -66,7 +66,7 @@ fn kernel_main() -> ! { // init uSDHC match SDHC2.init_usdhc() { - SdResult::SdOk => info!("uSDHC driver initialized"), + SdResult::SdOk => info!("uSDHC driver initialized..."), _ => info!("failed to initialize"), } diff --git a/boards/hal/src/nxp/imx8mn/bsp/clocks/analog.rs b/boards/hal/src/nxp/imx8mn/bsp/clocks/analog.rs index 72685ef3..1b3530da 100644 --- a/boards/hal/src/nxp/imx8mn/bsp/clocks/analog.rs +++ b/boards/hal/src/nxp/imx8mn/bsp/clocks/analog.rs @@ -1,3 +1,5 @@ +//! PLL configuration - TODO - implementation not ready yet + use tock_registers::interfaces::ReadWriteable; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -351,6 +353,7 @@ impl CCMAnalog { + SYS_PLL2_GEN_CTRL::PLL_DIV20_CLKE::SET, ) } + /// TODO: implementation not complete. Still needs to be tested pub fn pll_configure(&self, pll: PllClocks, freq: u32) { let pll_clke_masks = INTPLL_CLKE_MASK; // Bypass clock and set lock to pll output lock @@ -434,7 +437,7 @@ impl CCMAnalog { _ => {} } } - + /// TODO: implementation not complete. Still needs to be tested /// Configure system Plls and set clock-gates, root-clocks for GIC, DRAM, NAND, WDG etc. pub fn clock_init(&self) { self.set_pll1_outputs(); diff --git a/boards/hal/src/nxp/imx8mn/bsp/drivers/gpio.rs b/boards/hal/src/nxp/imx8mn/bsp/drivers/gpio.rs index 6c6c6d01..9dd02100 100644 --- a/boards/hal/src/nxp/imx8mn/bsp/drivers/gpio.rs +++ b/boards/hal/src/nxp/imx8mn/bsp/drivers/gpio.rs @@ -184,14 +184,13 @@ impl GpioInner { /// Set GPIO pin fn set_gpio_pin(&mut self, pin: u8, val: bool) { - // Set pin-direction to output - self.registers - .GPIO_GDIR - .modify(GPIO_GDIR::PIN_DIR.val(1 << pin)); - // set or clear DR bit for corresponding pin match val { true => { + // Set pin-direction to output + self.registers + .GPIO_GDIR + .modify(GPIO_GDIR::PIN_DIR.val(1 << pin)); self.registers.GPIO_DR.modify(GPIO_DR::DR.val(1 << pin)); } false => { @@ -224,17 +223,17 @@ impl Gpio { inner: NullLock::new(GpioInner::new(mmio_start_addr)), } } - /// Sets the supplied Gpio pin's state to output + /// Sets the supplied Gpio pin's direction and state to output pub fn set_pin(&self, pin: u8) { - self.inner.lock(|gpio | gpio.set_gpio_pin(pin, true)); + self.inner.lock(|gpio| gpio.set_gpio_pin(pin, true)); } /// Clears the supplied Gpio pin's output-mode status pub fn clear_pin(&self, pin: u8) { - self.inner.lock(|gpio | gpio.set_gpio_pin(pin, false)); + self.inner.lock(|gpio| gpio.set_gpio_pin(pin, false)); } /// Reads the the supplied Gpio pin's state. pub fn read_pin(&self, pin: u8) -> u8 { - let res = self.inner.lock(|gpio | gpio.get_gpio_pin(pin)); + let res = self.inner.lock(|gpio| gpio.get_gpio_pin(pin)); res } } @@ -247,4 +246,3 @@ impl super::common::interface::DeviceDriver for Gpio { "i.MX 8M Nano Gpio" } } - diff --git a/boards/hal/src/nxp/imx8mn/bsp/drivers/usdhc.rs b/boards/hal/src/nxp/imx8mn/bsp/drivers/usdhc.rs index d69813f9..82280d28 100644 --- a/boards/hal/src/nxp/imx8mn/bsp/drivers/usdhc.rs +++ b/boards/hal/src/nxp/imx8mn/bsp/drivers/usdhc.rs @@ -8,6 +8,7 @@ use super::common::MMIODerefWrapper; use crate::nxp::imx8mn::arch::cpu_core; use crate::nxp::imx8mn::bsp::drivers::usdhc::INT_STATUS::DEBE; +use crate::nxp::imx8mn::bsp::global::GPIO2; use crate::{info, print, warn}; use core::fmt::Debug; use tock_registers::{ @@ -561,12 +562,18 @@ register_bitfields! { /// /// 0b - No reset /// 1b - Reset - RSTC OFFSET(25) NUMBITS(1) [], + RSTC OFFSET(25) NUMBITS(1) [ + NoReset = 0, + Reset = 1, + ], /// Software reset for data line /// /// Only part of the data circuit is reset. DMA circuit is also reset. After this field is set, the software waits for /// self-clear. - RSTD OFFSET(26) NUMBITS(1) [], + RSTD OFFSET(26) NUMBITS(1) [ + NoReset = 0, + Reset = 1, + ], /// Initialization active /// /// When this field is set, 80 SD-clocks are sent to the card. After the 80 clocks are sent, this field is self @@ -1183,7 +1190,7 @@ mod uSDHC_constants { SD CARD FREQUENCIES --------------------------------------------------------------------------*/ pub const FREQ_SETUP : usize = 400_000; // 400 Khz - pub const FREQ_NORMAL : usize = 24_000_000; // 24 Mhz + pub const FREQ_NORMAL : usize = 50_000_000; // 50 Mhz pub const BASE_CLOCK : usize = 400_000_000; // 400 Mhz @@ -1341,8 +1348,7 @@ impl SdCardCommands { cmd.write( CMD_XFR_TYP::CMDINX.val(0x02) + CMD_XFR_TYP::RSPTYP::CMD_136BIT_RESP - + CMD_XFR_TYP::CCCEN::SET - + CMD_XFR_TYP::CICEN::SET, + + CMD_XFR_TYP::CCCEN::SET, // + CMD_XFR_TYP::CICEN::SET, ); cmd }, @@ -1724,7 +1730,9 @@ impl SdCardCommands { cmd.write( CMD_XFR_TYP::CMDINX.val(0x33) + CMD_XFR_TYP::RSPTYP::CMD_48BIT_RESP - + CMD_XFR_TYP::DPSEL.val(1), + + CMD_XFR_TYP::DPSEL.val(1) + + CMD_XFR_TYP::CCCEN::SET + + CMD_XFR_TYP::CICEN::SET, ); cmd }, @@ -1935,7 +1943,7 @@ impl UsdhController { div += 1; info!( - "Prescaler = {:?}, Divisor = {:?}, Freq Set = {:?}", + "Prescaler = {:?}, Divisor = {:?}, Freq = {:?} Hz", pre_div, div, (BASE_CLOCK as u32 / (div * pre_div)) @@ -1944,59 +1952,32 @@ impl UsdhController { return SdResult::SdOk; } - /// Reset SD Host Controller + /// Reset SD Host Controller. + /// + /// Note: this method does not perform a hardware or a software reset. Apparently, it works without this + /// - **hardware reset OR power-cycle**: we toggle the `IPP_RST_N` bit(23) of SYS_CTRL as per the SD standard (i.e. 1ms high and + /// then 1ms low) + /// - **software reset**: the reference manual says we must reset the uSDHC peripheral by setting the `RSTA` + /// bit (24) of SYS_CTRL register /// + /// but after weeks of debugging, I realized (maybe) this board does not need to be reset. In fact, if you try to reset + /// the card/controller with either a hardware or software reset, we run into sd-communication errors - strange. + /// + /// Helpful hint: Performing any of type (above mentioned) of resets results in the data and command line signals being pulled low + /// I confirmed this via the PRES_STAT register DLSL and CLSL bits. + /// /// Returns: /// - SdErrorReset - A fatal error occurred resetting the Sd card /// - SdOk - Sd card reset correctly fn reset_card(&self) -> SdResult { - // start with a time difference of zero - let mut td = 0; - let mut start_time = 0; - - // Reset the complete host controller - self.registers.SYS_CTRL.modify(SYS_CTRL::RSTA::Reset); - - // Wait for reset done - while (self.registers.SYS_CTRL.is_set(SYS_CTRL::RSTA)) && (td < 10) { - // set start time - if (start_time == 0) { - start_time = timer_get_tick_count(); - } else { - td = tick_difference(start_time, timer_get_tick_count()); - } - } - if (td >= 10) { - // Timeout waiting for reset flag - info!("Sd Error: failed to reset.\n"); - // Return reset Sd card error - return SdResult::SdErrorReset; - } - info!("Sd host circuit reset in {:?}us", td); - // self.registers.SYS_CTRL.modify(SYS_CTRL::RESERVED0::SET); - + // Start without a hardware or software reset. See above self.registers.MMCBOOT.set(0); self.registers.MIXCTRL.set(0); self.registers.CLK_TUNE_CTRL_STS.set(0); - - self.registers.VEND_SPEC.write( - VEND_SPEC::RSRV1::SET - + VEND_SPEC::CKEN::SET - + VEND_SPEC::PEREN::SET - + VEND_SPEC::HCKEN::SET - + VEND_SPEC::IPGEN::SET - + VEND_SPEC::AC12_WR_CHKBUSY_EN::SET - + VEND_SPEC::EXT_DMA_EN::SET, - ); - /* Default setup, 3.3V IO */ - // self.registers.VEND_SPEC.modify(VEND_SPEC::VSELECT::CLEAR); - /* Disable DLL_CTRL delay line */ + // Disable DLL_CTRL delay line self.registers.DLL_CTRL.set(0); - self.registers - .VEND_SPEC - .modify(VEND_SPEC::PEREN::SET + VEND_SPEC::IPGEN::SET); - /* Set clock to setup frequency */ + // Set clock to setup frequency // i.e. set to low frequency clock (400Khz) let mut resp = self.set_clock(FREQ_SETUP as u32); timer_wait_micro(100); @@ -2015,6 +1996,7 @@ impl UsdhController { CCSEN::SET + TCSEN::SET + DINTSEN::SET + + BRRSENN::SET + CINTSEN::SET + CTOESEN::SET + CCESEN::SET @@ -2024,11 +2006,6 @@ impl UsdhController { + DCESEN::SET + DEBESEN::SET, ); - - // Clear read/write ready status - self.registers - .INT_STATUS_EN - .modify(INT_STATUS_EN::BRRSENN::CLEAR + INT_STATUS_EN::BWRSEN::CLEAR); // Set INITA field to send 80 SD-clocks to the card. After the 80 clocks are sent, this field is self // cleared self.registers.SYS_CTRL.modify(SYS_CTRL::INITA::SET); @@ -2037,12 +2014,9 @@ impl UsdhController { } // Set PROCTL reg to the default self.registers.PROT_CTRL.modify( - PROT_CTRL::EMODE::LittleEndianMode + PROT_CTRL::DTW::OneBitWide, // + PROT_CTRL::D3CD::CLEAR - // + PROT_CTRL::DTW::FourBitWide, + PROT_CTRL::DTW::OneBitWide, // PROT_CTRL::EMODE::LittleEndianMode + PROT_CTRL::D3CD::CLEAR + // + PROT_CTRL::DTW::FourBitWide, ); - // self.registers.VEND_SPEC.modify(VEND_SPEC::FRC_SDCLK_ON::SET); - // self.registers.SYS_CTRL.modify(SYS_CTRL::RESERVED0.val(0x8)); - // self.registers.SYS_CTRL.modify(SYS_CTRL::IPP_RST_N::SET); // set timeout to maximum value self.registers.SYS_CTRL.modify(SYS_CTRL::DTOCV.val(0xf)); @@ -2050,10 +2024,8 @@ impl UsdhController { self.registers .WTMK_LVL .modify(WTMK_LVL::RD_WML.val(0x10) + WTMK_LVL::WR_WML.val(0x10)); - // set tuning ctrl - // self.registers.TUNINIG_CTRL.set(TUNINIG_CTRL_INIT); - - /* Reset our card structure entries */ + + // Reset our card structure entries unsafe { SD_CARD.rca = 0; // Zero rca SD_CARD.ocr.set(0); // Zero ocr @@ -2061,6 +2033,7 @@ impl UsdhController { SD_CARD.status = 0; // Zero status SD_CARD.sd_card_type = SdCardType::TypeUnknown; // Set card type unknown } + // Send GO_IDLE_STATE to card resp = self.send_command(SdCardCommands::GoIdleState); @@ -2069,7 +2042,7 @@ impl UsdhController { return resp; } - /// Wait for command completion, this method loops polling for the condition (for up to 1 second). + /// Wait for command completion, this method loops polling for the condition (for up to 10 milli seconds). /// /// Returns: /// - SdTimeout - Operation timed out @@ -2112,7 +2085,7 @@ impl UsdhController { } else if (int_status & int_error_status.get()) != 0 { info!( "Error: we got a response for the last cmd but it contains errors, \ - decode contents of interrupt status register for details \ + decode contents of interrupt status register for details\n \ VendSpec: 0x{:08x}, SysCtrl: 0x{:08x}, ProtCtrl: 0x{:08x}, \ PresentStatus: 0x{:08x}, intStatus: 0x{:08x}, Resp0: 0x{:08x}, Resp1: 0x{:08x}, Resp2: 0x{:08x}, \ Resp3: 0x{:08x}, CC_bit set in {}us\n", @@ -2277,6 +2250,27 @@ impl UsdhController { } return SdResult::SdOk; } + // SEND_SCR command + 0x33 => unsafe { + let mut scr_lo = 0; + let mut scr_hi = 0; + for (idx, word) in (0..2u8).enumerate() { + while !self.registers.INT_STATUS.is_set(INT_STATUS::BRR) {} + // clear BRR with w1c - write 1 to clear + self.registers.INT_STATUS.modify(INT_STATUS::BRR::SET); + // for non-DMA read transfers, the uSDHC module implements an internal buffer to + // transfer data efficiently. + match idx { + 0 => scr_lo = self.registers.DATA_BUFF_ACC_PORT.get(), + 1 => scr_hi = self.registers.DATA_BUFF_ACC_PORT.get(), + _ => { + unreachable!() + } + } + } + SD_CARD.scr.set(scr_lo as u64 | ((scr_hi as u64) << 32)); + return SdResult::SdOk; + }, _ => { unsafe { SD_CARD.status = resp0; @@ -2588,7 +2582,7 @@ impl UsdhController { // In other words- issuing `APP_SEND_OP_COND`, will trigger an APP_CMD prior to sending out APP_SEND_OP_COND. // We must ensure a 100us delay between the 2 commands. let mut resp = self.send_command_a(SdCardCommands::AppSendOpCond, arg); - if resp != SdResult::SdTimeout { + if resp != SdResult::SdOk && resp != SdResult::SdTimeout { // #[cfg(feature = "log")] info!("{:?}: ACMD41 returned non-timeout error \n", resp); @@ -2598,7 +2592,7 @@ impl UsdhController { while unsafe { SD_CARD.ocr.read(OCR::card_power_up_busy) == 0 } && retries != 0 { timer_wait_micro(400000); resp = self.send_command_a(SdCardCommands::AppSendOpCond, arg); - if resp != SdResult::SdTimeout { + if resp != SdResult::SdOk && resp != SdResult::SdTimeout { // #[cfg(feature = "log")] info!("{:?}: ACMD41 returned non-timeout error \n", resp); @@ -2624,73 +2618,23 @@ impl UsdhController { } /// Read card's SCR. APP_CMD sent automatically if required. + /// + /// TODO: Find out why we get a timeout error when we send SetBlocklen (CMD 16) before issuing the SCR. fn sd_read_scr(&self) -> SdResult { - // SEND_SCR command is like a READ_SINGLE but for a block of 8 bytes. - // Ensure that any data operation has completed before reading the block. - if self.wait_for_cmd_data() != SdResult::SdOk { - return SdResult::SdTimeout; - } - - self.registers.MIXCTRL.modify(MIXCTRL::BCEN::SET); - // Set BLKSIZECNT to 1 block of 8 bytes, send SEND_SCR command - self.registers.BLK_ATT.modify(BLK_ATT::BLKCNT.val(1)); + // Send set block length command + // let resp = self.send_command_a(SdCardCommands::SetBlocklen, 8); + // if resp != SdResult::SdOk { + // return self.debug_response(resp); + // } + // enable MIXCTRL bitfield to transfer data from the SD card to uSDHC + self.registers.MIXCTRL.modify(MIXCTRL::DTDSEL::SET); + // Set BLKSIZE to 1 block of 8 bytes, send SEND_SCR command self.registers.BLK_ATT.modify(BLK_ATT::BLKSIZE.val(8)); let resp = self.send_command(SdCardCommands::SendScr); if resp != SdResult::SdOk { return self.debug_response(resp); } - - // Allow maximum of 100ms for the read operation. - let mut num_read = 0u32; - let mut count = 100000u32; - let mut scr_lo = 0u32; - let mut scr_hi = 0u32; - while (num_read < 2) { - if self - .registers - .PRES_STATE - .matches_all(PRES_STATE::RTA.val(1)) - { - if num_read == 0 { - unsafe { - scr_lo = self.registers.DATA_BUFF_ACC_PORT.get(); - } - } else { - unsafe { - scr_hi = self.registers.DATA_BUFF_ACC_PORT.get(); - } - } - num_read += 1; - info!("in num_read match-arm"); - } else { - timer_wait_micro(1); - count -= 1; - if count == 0 { - break; - } - } - } - // If SCR not fully read, the operation timed out. - if (num_read != 2) { - // #[cfg(feature = "log")] - { - info!( - "Sd Error: SEND_SCR ERR: 0x{:x}, 0x{:x}, 0x{:?}\n", - self.registers.PRES_STATE.get(), - self.registers.INT_STATUS.get(), - self.registers.CMD_RSP0.get() - ); - info!( - "Sd Read Timeout: Reading SCR, only read : {:?} words\n", - num_read - ); - } - - return SdResult::SdTimeout; - } - - unsafe { SD_CARD.scr.set(scr_lo as u64 | ((scr_hi as u64) << 32)) }; return SdResult::SdOk; } @@ -2710,7 +2654,7 @@ impl UsdhController { Some(HOST_CTRL_CAP::VS18::Value::Supported), Some(HOST_CTRL_CAP::VS30::Value::Supported), Some(HOST_CTRL_CAP::VS33::Value::Supported), - ) => info!("uSDHC2 has support for 1.8v, 3.0v, 3.3v ..."), + ) => info!("uSDHC2 supports 1.8v, 3.0v, 3.3v ..."), _ => unimplemented!(), }; SdResult::SdOk @@ -2731,7 +2675,6 @@ impl UsdhController { if (resp != SdResult::SdOk) { return resp; } - // Send SEND_IF_COND,0x000001AA (CMD8) voltage range 0x1 check pattern 0xAA // If voltage range and check pattern don't match, look for older card. resp = self.send_command_a(SdCardCommands::SendIfCond, 0x000001AA); @@ -2757,50 +2700,29 @@ impl UsdhController { SdResult::SdBusy => return resp, // No response to SEND_IF_COND, treat as an old card. _ => { - info!( - "{:?}: Send interface condition command (CMD8) returned an error \n", - resp - ); - return SdResult::SdError; + // info!( + // "{:?}: Send interface condition command (CMD8) returned an error \n", + // resp + // ); + // return SdResult::SdError; // If there appears to be a command in progress, reset the card. - // resp = self.reset_card(); - // if self.registers.PRES_STATE.is_set(PRES_STATE::CIHB) && (resp != SdResult::SdOk) - // { - // return resp; - // } - - // // wait(50); - // // Resolve voltage. - // resp = self.app_send_op_cond(ACMD41_ARG_SC as u32); - // if (resp != SdResult::SdOk) { - // return self.debug_response(resp); - // } - - // unsafe { - // SD_CARD.sd_card_type = SdCardType::Type1; - // } - } - }; + resp = self.reset_card(); + if self.registers.PRES_STATE.is_set(PRES_STATE::CIHB) && (resp != SdResult::SdOk) { + return resp; + } - // // Send SEND_OP_COND (CMD1) - // while true { - // resp = self.send_command_a(SdCardCommands::SendOpCond, 0x40ff8080); - // if (resp != SdResult::SdOk) { - // return self.debug_response(resp); - // } - // /* Wait for uSDHC to power up */ - // if (self.registers.CMD_RSP0.get() & (1 << 31)) != 0 { - // break; - // } else { - // timer_wait_micro(1000); - // } - // } + // wait(50); + // Resolve voltage. + resp = self.app_send_op_cond(ACMD41_ARG_SC as u32); + if (resp != SdResult::SdOk) { + return self.debug_response(resp); + } - // // Send SEND_STATUS (CMD 0xd) - // resp = self.send_command(SdCardCommands::SendStatus); - // if (resp != SdResult::SdOk) { - // return self.debug_response(resp); - // } + unsafe { + SD_CARD.sd_card_type = SdCardType::Type1; + } + } + }; // Send ALL_SEND_CID (CMD2) resp = self.send_command(SdCardCommands::AllSendCid); @@ -2850,7 +2772,7 @@ impl UsdhController { .read_as_enum::(SCR::BUS_WIDTH) } { Some(v) => { - info!("SCR BUS_WIDTH: {:?}", v) + info!("SCR bus width: {:?}", v) } None => { info!("Unsupported bus width, we'll default to using a `1-bit` bus") diff --git a/boards/hal/src/nxp/imx8mn/bsp/mux/usdhc2grp.rs b/boards/hal/src/nxp/imx8mn/bsp/mux/usdhc2grp.rs index 19a1c775..8589847d 100644 --- a/boards/hal/src/nxp/imx8mn/bsp/mux/usdhc2grp.rs +++ b/boards/hal/src/nxp/imx8mn/bsp/mux/usdhc2grp.rs @@ -1,6 +1,6 @@ //! Pin Mux settings for uSDHC2 -use super::super::global::{GPIO2, GPIO1}; +use super::super::global::{GPIO1, GPIO2}; use super::super::memory_map::map::mmio::IOMUXC_START; use super::iomuxc::*; @@ -10,68 +10,6 @@ enum PadSelect { Usdhc2Vselect, Sdma1ExtEvent1, } - -/// GPIO regs associated with uSDHC2 -struct Usdhc2GpioRegs { - iomuxc_sw_mux_ctl_pad_gpio1_io15: u32, - iomuxc_sw_pad_ctl_pad_gpio1_io15: u32, -} - -impl Default for Usdhc2GpioRegs { - /// Defaults taken from 8.2.4 IOMUXC Memory Map/Register Definition of - /// the i.MX 8M Nano Applications Processor Reference Manual, Rev. 2, 07/2022 - /// - /// Note: the device tree for i.MX 8M Nano-EVK contains these offsets as well. Look for a - /// a usdhc2gpiogrp `pincfg` within the pin-controller node (i.e. pinctrl@30330000) - fn default() -> Self { - Usdhc2GpioRegs { - iomuxc_sw_mux_ctl_pad_gpio1_io15: (IOMUXC_START + 0x64) as u32, - iomuxc_sw_pad_ctl_pad_gpio1_io15: (IOMUXC_START + 0x2cc) as u32, - } - } -} - -impl Usdhc2GpioRegs { - fn set_usdhc2_gpio_mux_cfg(&self, mux_val: MuxMode, sion_val: Sion) { - // #Safety - // - // Only valid register writes (vals) are used via rust pattern-matching. - match (mux_val, sion_val) { - (MuxMode::Alt0, Sion::Disabled) => unsafe { - // write to Pad Mux Registers - ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_gpio1_io15 as *mut u32, 0x0); - }, - _ => unimplemented!(), - } - GPIO1.set_pin(15); - - // write to Pad Control Registers - unsafe { - ::core::ptr::write_volatile( - self.iomuxc_sw_pad_ctl_pad_gpio1_io15 as *mut u32, - self.get_pad_ctrl_val( - Dse::DseX2, - Fsel::Slow, - Ode::Disabled, - Pue::PullUp, - Hys::Enabled, - Pe::Enabled, - ), - ); - } - GPIO1.clear_pin(15); - - } - - fn get_pad_ctrl_val(&self, dse: Dse, fsel: Fsel, ode: Ode, pue: Pue, hys: Hys, pe: Pe) -> u32 { - match (dse, fsel, ode, pue, hys, pe) { - (Dse::DseX2, Fsel::Slow, Ode::Disabled, Pue::PullUp, Hys::Enabled, Pe::Enabled) => { - 0x1c4 - } - _ => unimplemented!(), - } - } -} /// Pin Muxing Registers for uSDHC2. struct Usdhc2MuxRegs { // Pad Mux Registers @@ -133,42 +71,48 @@ impl Default for Usdhc2MuxRegs { impl Usdhc2MuxRegs { fn set_usdhc2_mux_cfg(&self, mux_val: MuxMode, sion_val: Sion, input_selector: u32) { - // set sd2-reset pin to alternate mux-mode i.e. gpio 19 - unsafe { - ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_reset_b as *mut u32, 0x5); - GPIO2.set_pin(19); - } // #Safety // // Only valid register writes (vals) are used via rust pattern-matching. match (mux_val, sion_val) { (MuxMode::Alt0, Sion::Disabled) => unsafe { // write to Pad Mux Registers - // ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_cd_b as *mut u32, 0x0); + ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_cd_b as *mut u32, 0x0); ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_clk as *mut u32, 0x0); ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_cmd as *mut u32, 0x0); ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_data0 as *mut u32, 0x0); ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_data1 as *mut u32, 0x0); ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_data2 as *mut u32, 0x0); ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_data3 as *mut u32, 0x0); - // ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_wp as *mut u32, 0x0); + // set sd2-reset pin to alt0 mux-mode i.e. usdhc_reset_b. + // according to 6.4 of the physical layer specification. For a hardware reset, + // we need at least 1ms of low voltage, then at least 1ms of high voltage (ignoring power ramp-up delays.) + // And this is before we send the 74 clock cycles i.e. before we set the initialize active bit (27) in SYS_CTRL + + // note: we use `IPP_RST_N` bit (23) of the SYS_CTRL register to toggle the reset pin with a 1ms delay. + ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_reset_b as *mut u32, 0x0); + ::core::ptr::write_volatile(self.iomuxc_sw_mux_ctl_pad_sd2_wp as *mut u32, 0x0); + ::core::ptr::write_volatile( + self.iomuxc_sw_mux_ctl_pad_usdhc2_vselect as *mut u32, + input_selector, + ); }, _ => unimplemented!(), } // write to Pad Control Registers unsafe { - // ::core::ptr::write_volatile( - // self.iomuxc_sw_pad_ctl_pad_sd2_cd_b as *mut u32, - // self.get_pad_ctrl_val( - // Dse::DseX1, - // Fsel::Slow, - // Ode::Disabled, - // Pue::PullDown, - // Hys::Enabled, - // Pe::Enabled, - // ), - // ); + ::core::ptr::write_volatile( + self.iomuxc_sw_pad_ctl_pad_sd2_cd_b as *mut u32, + self.get_pad_ctrl_val( + Dse::DseX1, + Fsel::Fast, + Ode::Disabled, + Pue::PullDown, + Hys::Enabled, + Pe::Enabled, + ), + ); ::core::ptr::write_volatile( self.iomuxc_sw_pad_ctl_pad_sd2_clk as *mut u32, self.get_pad_ctrl_val( @@ -246,20 +190,16 @@ impl Usdhc2MuxRegs { Pe::Disabled, ), ); - // ::core::ptr::write_volatile( - // self.iomuxc_sw_pad_ctl_pad_sd2_wp as *mut u32, - // self.get_pad_ctrl_val( - // Dse::DseX1, - // Fsel::Fast, - // Ode::Disabled, - // Pue::PullDown, - // Hys::Enabled, - // Pe::Enabled, - // ), - // ); ::core::ptr::write_volatile( - self.iomuxc_sw_mux_ctl_pad_usdhc2_vselect as *mut u32, - input_selector, + self.iomuxc_sw_pad_ctl_pad_sd2_wp as *mut u32, + self.get_pad_ctrl_val( + Dse::DseX1, + Fsel::Fast, + Ode::Disabled, + Pue::PullDown, + Hys::Enabled, + Pe::Enabled, + ), ); ::core::ptr::write_volatile( self.iomuxc_sw_pad_ctl_pad_usdhc2_vselect as *mut u32, @@ -272,7 +212,6 @@ impl Usdhc2MuxRegs { Pe::Enabled, ), ); - GPIO2.clear_pin(19) // clear - gpio2 pin 19 data register. } } @@ -281,14 +220,20 @@ impl Usdhc2MuxRegs { (Dse::DseX1, Fsel::Fast, Ode::Disabled, Pue::PullUp, Hys::Enabled, Pe::Enabled) => { 0x1d0 } + (Dse::DseX6, Fsel::Fast, Ode::Disabled, Pue::PullUp, Hys::Enabled, Pe::Enabled) => { + 0x1d6 + } (Dse::DseX1, Fsel::Fast, Ode::Disabled, Pue::PullDown, Hys::Enabled, Pe::Enabled) => { 0x190 } + (Dse::DseX6, Fsel::Fast, Ode::Disabled, Pue::PullDown, Hys::Enabled, Pe::Enabled) => { + 0x196 + } (Dse::DseX1, Fsel::Slow, Ode::Disabled, Pue::PullUp, Hys::Disabled, Pe::Disabled) => { 0x41 } - (Dse::DseX1, Fsel::Slow, Ode::Disabled, Pue::PullUp, Hys::Enabled, Pe::Disabled) => { - 0xc1 + (Dse::DseX6, Fsel::Fast, Ode::Disabled, Pue::PullUp, Hys::Enabled, Pe::Disabled) => { + 0xd6 } _ => unimplemented!(), } @@ -304,10 +249,6 @@ impl Usdhc2MuxRegs { /// Set mux-config for the uSDHC2 peripheral. pub fn usdhc2_mux_mmio_set() { - // set uSDHC2 gpio mux and pincfg - let usdhc_gpio_regs = Usdhc2GpioRegs::default(); - usdhc_gpio_regs.set_usdhc2_gpio_mux_cfg(MuxMode::Alt0, Sion::Disabled); - // set uSDHC2 mux and pincfg let usdhc_regs = Usdhc2MuxRegs::default(); let input_selector = usdhc_regs.get_pad_sel_val(PadSelect::Usdhc2Vselect); usdhc_regs.set_usdhc2_mux_cfg(MuxMode::Alt0, Sion::Disabled, input_selector);