From 2faa68bdc9b0c3394979890d187be58f35d0df7f Mon Sep 17 00:00:00 2001 From: pca Date: Mon, 4 May 2020 17:05:16 +0800 Subject: [PATCH 01/34] basic code for initialization, not tested yet --- experiments/src/main.rs | 230 +-------------------------------- libboard_zynq/src/sdio/mod.rs | 206 ++++++++++++++++++++++++++++- libboard_zynq/src/sdio/regs.rs | 46 +++---- 3 files changed, 229 insertions(+), 253 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 67adb77..842b365 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -12,14 +12,6 @@ use libcortex_a9::{mutex::Mutex, sync_channel::{self, sync_channel}}; use libboard_zynq::{ print, println, self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, - smoltcp::{ - self, - wire::{EthernetAddress, IpAddress, IpCidr}, - iface::{NeighborCache, EthernetInterfaceBuilder, Routes}, - time::Instant, - socket::SocketSet, - socket::{TcpSocket, TcpSocketBuffer}, - }, time::Milliseconds, }; use libsupport_zynq::{ @@ -61,224 +53,16 @@ pub fn main_core0() { let clocks = zynq::clocks::Clocks::get(); println!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x()); - let mut flash = zynq::flash::Flash::new(200_000_000).linear_addressing_mode(); - let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) }; - for i in 0..=1 { - print!("Flash {}:", i); - for b in &flash_ram[(i * 16 * 1024 * 1024)..][..128] { - print!(" {:02X}", *b); - } - println!(""); - } - let mut flash = flash.stop(); - let timer = libboard_zynq::timer::GlobalTimer::start(); - let mut ddr = zynq::ddr::DdrRam::new(); - #[cfg(not(feature = "target_zc706"))] - ddr.memtest(); - ram::init_alloc_ddr(&mut ddr); - - for i in 0..=1 { - let mut flash_io = flash.manual_mode(i); - // println!("rdcr={:02X}", flash_io.rdcr()); - print!("Flash {} ID:", i); - for b in flash_io.rdid() { - print!(" {:02X}", b); - } - println!(""); - print!("Flash {} I/O:", i); - for o in 0..8 { - const CHUNK: u32 = 8; - for b in flash_io.read(CHUNK * o, CHUNK as usize) { - print!(" {:02X}", b); - } - } - println!(""); - - flash_io.dump("Read cr1", 0x35); - flash_io.dump("Read Autoboot", 0x14); - flash_io.dump("Read Bank", 0x16); - flash_io.dump("DLP Bank", 0x16); - flash_io.dump("Read ESig", 0xAB); - flash_io.dump("OTP Read", 0x4B); - flash_io.dump("DYB Read", 0xE0); - flash_io.dump("PPB Read", 0xE2); - flash_io.dump("ASP Read", 0x2B); - flash_io.dump("Password Read", 0xE7); - - flash_io.write_enabled(|flash_io| { - flash_io.erase(0); - }); - flash_io.write_enabled(|flash_io| { - flash_io.program(0, [0x23054223; (0x100 >> 2)].iter().cloned()); - }); - - flash = flash_io.stop(); + let mut sd = libboard_zynq::sdio::SDIO::sdio0(400_000); + loop { + println!("Wait for SD card inertion!"); + sd.wait_insert(); + println!("SD card inserted"); + sd.wait_remove(); + println!("SD card removed!"); } - - let (mut tx, mut rx) = sync_channel::sync_channel(0); - task::spawn(async move { - println!("outer task"); - while let Some(item) = *rx.async_recv().await { - println!("received {}", item); - } - }); - task::spawn(async { - for i in 1..=3 { - println!("outer task2: {}", i); - task::r#yield().await; - } - }); - task::block_on(async { - task::spawn(async { - println!("inner task"); - }); - - for i in 1..=10 { - println!("yield {}", i); - task::r#yield().await; - tx.async_send(Some(i)).await; - } - tx.async_send(None).await; - }); - - let core1_stack = unsafe { &mut STACK_CORE1[..] }; - println!("{} bytes stack for core1", core1_stack.len()); - let core1 = boot::Core1::start(core1_stack); - - let (mut core1_req, rx) = sync_channel(10); - *CORE1_REQ.lock() = Some(rx); - let (tx, mut core1_res) = sync_channel(10); - *CORE1_RES.lock() = Some(tx); - task::block_on(async { - for i in 0..10 { - core1_req.async_send(i).await; - let j = core1_res.async_recv().await; - println!("{} -> {}", i, j); - } - }); - core1.disable(); - - libcortex_a9::asm::dsb(); - print!("Core1 stack [{:08X}..{:08X}]:", &core1.stack[0] as *const _ as u32, &core1.stack[core1.stack.len() - 1] as *const _ as u32); - for w in core1.stack { - print!(" {:08X}", w); - } - println!("."); - - let eth = zynq::eth::Eth::default(HWADDR.clone()); - println!("Eth on"); - - const RX_LEN: usize = 8; - let mut rx_descs = (0..RX_LEN) - .map(|_| zynq::eth::rx::DescEntry::zeroed()) - .collect::>(); - let mut rx_buffers = vec![zynq::eth::Buffer::new(); RX_LEN]; - // Number of transmission buffers (minimum is two because with - // one, duplicate packet transmission occurs) - const TX_LEN: usize = 8; - let mut tx_descs = (0..TX_LEN) - .map(|_| zynq::eth::tx::DescEntry::zeroed()) - .collect::>(); - let mut tx_buffers = vec![zynq::eth::Buffer::new(); TX_LEN]; - let eth = eth.start_rx(&mut rx_descs, &mut rx_buffers); - // let mut eth = eth.start_tx(&mut tx_descs, &mut tx_buffers); - let mut eth = eth.start_tx( - // HACK - unsafe { transmute(tx_descs.as_mut_slice()) }, - unsafe { transmute(tx_buffers.as_mut_slice()) }, - ); - // loop { - // match eth.recv_next() { - // Ok(None) => {}, - // Ok(Some(pkt)) => println!("received {} bytes", pkt.len()), - // Err(e) => println!("e: {:?}", e), - // } - // } - - println!("iface..."); - let ethernet_addr = EthernetAddress(HWADDR); - // IP stack - let local_addr = IpAddress::v4(192, 168, 1, 51); - let mut ip_addrs = [IpCidr::new(local_addr, 24)]; - let mut routes_storage = vec![None; 4]; - let routes = Routes::new(/*BTreeMap::new()*/ &mut routes_storage[..]); - let mut neighbor_storage = vec![None; 256]; - let neighbor_cache = NeighborCache::new(&mut neighbor_storage[..]); - let mut iface = EthernetInterfaceBuilder::new(&mut eth) - .ethernet_addr(ethernet_addr) - .ip_addrs(&mut ip_addrs[..]) - .routes(routes) - .neighbor_cache(neighbor_cache) - .finalize(); - - // TODO: compare with ps7_init - - Sockets::init(32); - /// `chargen` - const TCP_PORT: u16 = 19; - async fn handle_connection(stream: TcpStream) -> smoltcp::Result<()> { - stream.send("Enter your name: ".bytes()).await?; - let name = stream.recv(|buf| { - for (i, b) in buf.iter().enumerate() { - if *b == '\n' as u8 { - return match core::str::from_utf8(&buf[0..i]) { - Ok(name) => - Poll::Ready((i + 1, Some(name.to_owned()))), - Err(_) => - Poll::Ready((i + 1, None)) - }; - } - } - if buf.len() > 100 { - // Too much input, consume all - Poll::Ready((buf.len(), None)) - } else { - Poll::Pending - } - }).await?; - match name { - Some(name) => - stream.send(format!("Hello {}!\n", name).bytes()).await?, - None => - stream.send("I had trouble reading your name.\n".bytes()).await?, - } - stream.flush().await; - Ok(()) - } - - let mut counter = alloc::rc::Rc::new(core::cell::RefCell::new(0)); - task::spawn(async move { - while let stream = TcpStream::accept(TCP_PORT, 2048, 2408).await.unwrap() { - let counter = counter.clone(); - task::spawn(async move { - *counter.borrow_mut() += 1; - println!("Serving {} connections", *counter.borrow()); - handle_connection(stream) - .await - .map_err(|e| println!("Connection: {:?}", e)); - *counter.borrow_mut() -= 1; - println!("Now serving {} connections", *counter.borrow()); - }); - } - }); - - let mut countdown = timer.countdown(); - task::spawn(async move { - loop { - delay(&mut countdown, Milliseconds(1000)).await; - - let timestamp = timer.get_us(); - let seconds = timestamp / 1_000_000; - let micros = timestamp % 1_000_000; - println!("time: {:6}.{:06}s", seconds, micros); - } - }); - - Sockets::run(&mut iface, || { - Instant::from_millis(timer.get_time().0 as i64) - }) } static CORE1_REQ: Mutex>> = Mutex::new(None); diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 77e8519..f168a28 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -1 +1,205 @@ -mod regs; \ No newline at end of file +mod regs; +use super::slcr; +use libregister::*; + +struct TransferMode { + dma_en: bool, + block_cnt_en: bool, + dat_dir_sel: bool, +} + +pub struct SDIO { + regs: &'static mut regs::RegisterBlock, + input_clk_hz: u32, + transfer_mode: TransferMode, +} + +impl SDIO { + #[cfg(feature = "target_cora_z7_10")] + pub fn sdio0(input_clk_hz: u32) -> Self { + // initialization according to ps7_init.c + slcr::RegisterBlock::unlocked(|slcr| { + slcr.mio_pin_40.write( + slcr::MioPin40::zeroed() + .l3_sel(0b100) + .io_type(slcr::IoBufferType::Lvcmos18) + .pullup(true), + ); + slcr.mio_pin_41.write( + slcr::MioPin41::zeroed() + .l3_sel(0b100) + .io_type(slcr::IoBufferType::Lvcmos18) + .pullup(true), + ); + slcr.mio_pin_42.write( + slcr::MioPin42::zeroed() + .l3_sel(0b100) + .io_type(slcr::IoBufferType::Lvcmos18) + .pullup(true), + ); + slcr.mio_pin_43.write( + slcr::MioPin43::zeroed() + .l3_sel(0b100) + .io_type(slcr::IoBufferType::Lvcmos18) + .pullup(true), + ); + slcr.mio_pin_44.write( + slcr::MioPin44::zeroed() + .l3_sel(0b100) + .io_type(slcr::IoBufferType::Lvcmos18) + .pullup(true), + ); + slcr.mio_pin_45.write( + slcr::MioPin45::zeroed() + .l3_sel(0b100) + .io_type(slcr::IoBufferType::Lvcmos18) + .pullup(true), + ); + slcr.mio_pin_47.write( + slcr::MioPin47::zeroed() + .io_type(slcr::IoBufferType::Lvcmos18) + .pullup(true), + ); + unsafe { + slcr.sdio_clk_ctrl.write(0x00001401); + } + }); + let mut self_ = SDIO { + regs: regs::RegisterBlock::sdio0(), + input_clk_hz, + transfer_mode: TransferMode { + dma_en: false, + block_cnt_en: true, + dat_dir_sel: true, + }, + }; + + self_.init(); + self_ + } + + /// initialization based on XSdPs_CfgInitialize function in xsdps.c + fn init(&mut self) { + // poweroff + self.regs + .control + .modify(|_, w| w.bus_voltage(regs::BusVoltage::V0)); + + if self.regs.misc_reg.read().spec_ver() == regs::SpecificationVersion::V3 { + // The documentation said the field can only be V1 or V2, + // so the code is written for V1 and V2. V3 requires special handling + // which is currently not implemented. + // I hope that this would never trigger but it is safer to put a check here. + panic!("The code written is for V1 and V2"); + } + // TODO: delay to poweroff card + + // reset all + self.regs + .clock_control + .modify(|_, w| w.software_reset_all(true)); + while self.regs.clock_control.read().software_reset_all() {} + + // set power to 3.3V + self.regs + .control + .modify(|_, w| w.bus_voltage(regs::BusVoltage::V33).bus_power(true)); + // set clock frequency + self.change_clk_freq(400_000); + // select voltage + let capabilities = self.regs.capabilities.read(); + let voltage = if capabilities.voltage_3_3() { + regs::BusVoltage::V33 + } else if capabilities.voltage_3_0() { + regs::BusVoltage::V30 + } else if capabilities.voltage_1_8() { + regs::BusVoltage::V18 + } else { + regs::BusVoltage::V0 + }; + self.regs.control.modify(|_, w| w.bus_voltage(voltage)); + + // enable all interrupt status except card interrupt + self.regs.interrupt_status_en.write( + regs::InterruptStatusEn::zeroed() + .adma_error_status_en(true) + .auto_cmd12_error_status_en(true) + .block_gap_evt_status_en(true) + .boot_ack_rcv_en(true) + .boot_terminate_interrupt_en(true) + .buffer_read_ready_status_en(true) + .buffer_write_ready_status_en(true) + .card_insertion_status_en(true) + .card_interrupt_status_en(false) + .card_removal_status_en(true) + .ceata_error_status_en(true) + .cmd_complete_status_en(true) + .cmd_crc_error_status_en(true) + .cmd_end_bit_error_status_en(true) + .cmd_index_error_status_en(true) + .cmd_timeout_error_status_en(true) + .current_limit_error_status_en(true) + .data_crc_error_status_en(true) + .data_end_bit_error_status_en(true) + .data_timeout_error_status_en(true) + .dma_interrupt_status_en(true) + .target_response_error_status_en(true) + .transfer_complete_status_en(true), + ); + + // disable all interrupt signals + self.regs + .interrupt_signal_en + .write(regs::InterruptSignalEn::zeroed()); + + + // set block size to 512 by default + self.regs.block_size_block_count.modify(|_, w| w.transfer_block_size(512)); + } + + /// Change clock frequency to the value less than or equal to the given value. + /// From XSdPs_Change_ClkFreq in xsdps_options.c. SPEC_V3 related code is removed as + /// our board would only be V1 or V2. + fn change_clk_freq(&mut self, freq: u32) { + self.regs + .clock_control + .modify(|_, w| w.sd_clk_en(false).internal_clk_en(false)); + + const XSDPS_CC_MAX_DIV_CNT: u32 = 256; + // calculate clock divisor + let mut div_cnt: u32 = 0x1; + let mut divisor = 0; + while div_cnt <= XSDPS_CC_MAX_DIV_CNT { + if (self.input_clk_hz / div_cnt) <= freq { + divisor = div_cnt / 2; + break; + } + div_cnt <<= 1; + } + if div_cnt > XSDPS_CC_MAX_DIV_CNT { + panic!("No valid divisor!"); + } + // enable internal clock + self.regs + .clock_control + .modify(|_, w| w.sdclk_freq_divisor(divisor as u8).internal_clk_en(true)); + while !self.regs.clock_control.read().internal_clk_stable() {} + + // enable SD clock + self.regs.clock_control.modify(|_, w| w.sd_clk_en(true)); + } + + pub fn wait_insert(&mut self) { + // poll for status register + while !self.regs.interrupt_status.read().card_insertion() {} + // clear status register (WTC) + self.regs.interrupt_status.modify(|_, w| w.card_insertion()); + } + + pub fn wait_remove(&mut self) { + // poll for status regsiter + while !self.regs.interrupt_status.read().card_removal() {} + // clear status register (WTC) + self.regs.interrupt_status.modify(|_, w| w.card_removal()); + } +} diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index 4538ca3..54d5904 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -14,7 +14,7 @@ pub struct RegisterBlock { /// Host. power, block gap, wakeup control pub control: Control, /// Clock and timeout control, and software reset register. - pub timing_control: TimingControl, + pub clock_control: ClockControl, pub interrupt_status: InterruptStatus, pub interrupt_status_en: InterruptStatusEn, pub interrupt_signal_en: InterruptSignalEn, @@ -57,6 +57,8 @@ pub enum BusVoltage { V30 = 0b110, /// 1.8V, typ. V18 = 0b101, + /// No power, + V0 = 0b000 } #[allow(unused)] @@ -68,21 +70,6 @@ pub enum DmaSelect { ADMA3 = 0b11, } -#[allow(unused)] -#[repr(u8)] -/// SDCLK Frequency divisor, d(number) means baseclock divided by (number). -pub enum SdclkFreqDivisor { - D256 = 0x80, - D128 = 0x40, - D64 = 0x20, - D32 = 0x10, - D16 = 0x08, - D8 = 0x04, - D4 = 0x02, - D2 = 0x01, - D1 = 0x00, -} - #[allow(unused)] #[repr(u8)] pub enum AdmaErrorState { @@ -93,13 +80,15 @@ pub enum AdmaErrorState { #[allow(unused)] #[repr(u8)] +#[derive(PartialEq)] pub enum SpecificationVersion { V1 = 0, V2 = 1, + V3 = 2, } -register_at!(RegisterBlock, 0xE0100000, sd0); -register_at!(RegisterBlock, 0xE0101000, sd1); +register_at!(RegisterBlock, 0xE0100000, sdio0); +register_at!(RegisterBlock, 0xE0101000, sdio1); register!(block_size_block_count, BlockSizeBlockCount, RW, u32); register_bits!( @@ -328,27 +317,27 @@ register_bit!( 0 ); -register!(timing_control, TimingControl, RW, u32); +register!(clock_control, ClockControl, RW, u32); register_bit!( - timing_control, + clock_control, /// Software reset for DAT line. software_reset_dat, 26 ); register_bit!( - timing_control, + clock_control, /// Software reset for CMD line. software_reset_cmd, 25 ); register_bit!( - timing_control, + clock_control, /// Software reset for ALL. software_reset_all, 24 ); register_bits!( - timing_control, + clock_control, /// Determines the interval by which DAT line time-outs are detected. /// Interval = TMCLK * 2^(13 + val) /// Note: 0b1111 is reserved. @@ -357,27 +346,26 @@ register_bits!( 16, 19 ); -register_bits_typed!( - timing_control, +register_bits!( + clock_control, /// Selects the frequency divisor, thus the clock frequency for SDCLK. /// Choose the smallest possible divisor which results in a clock frequency /// that is less than or equal to the target frequency. sdclk_freq_divisor, u8, - SdclkFreqDivisor, 8, 15 ); -register_bit!(timing_control, sd_clk_en, 2); +register_bit!(clock_control, sd_clk_en, 2); register_bit!( - timing_control, + clock_control, /// 1 when SD clock is stable. /// Note that this field is read-only. internal_clk_stable, 1, RO ); -register_bit!(timing_control, internal_clk_en, 0); +register_bit!(clock_control, internal_clk_en, 0); register!(interrupt_status, InterruptStatus, RW, u32, 1 << 15 | 1 << 8); register_bit!(interrupt_status, ceata_error, 29, WTC); -- 2.42.0 From 6f15df943d904f2b3904e6298a039106a32d0336 Mon Sep 17 00:00:00 2001 From: pca Date: Mon, 4 May 2020 17:06:26 +0800 Subject: [PATCH 02/34] ignore personal scripts --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ea8c4bf..703e0a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +.scripts \ No newline at end of file -- 2.42.0 From 7f5f80489484a418ba1f0032e89e04a3ab64f819 Mon Sep 17 00:00:00 2001 From: pca Date: Mon, 4 May 2020 17:13:15 +0800 Subject: [PATCH 03/34] minimize warnings --- experiments/src/main.rs | 17 ++++------------- libboard_zynq/src/sdio/regs.rs | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 78152cc..3990c35 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -3,21 +3,14 @@ extern crate alloc; -use core::{mem::transmute, task::Poll}; -use alloc::{borrow::ToOwned, collections::BTreeMap, format}; use log::info; use libregister::RegisterR; -use libcortex_a9::{mutex::Mutex, sync_channel::{self, sync_channel}}; +use libcortex_a9::{mutex::Mutex, sync_channel::{self}}; use libboard_zynq::{ - print, println, - self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, - time::Milliseconds, + println, + self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll}, }; -use libsupport_zynq::{ - ram, alloc::{vec, vec::Vec}, - boot, -}; -use libasync::{delay, smoltcp::{Sockets, TcpStream}, task}; +use libsupport_zynq; mod ps7_init; @@ -48,8 +41,6 @@ pub fn main_core0() { let clocks = zynq::clocks::Clocks::get(); info!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x()); - let timer = libboard_zynq::timer::GlobalTimer::start(); - let mut sd = libboard_zynq::sdio::SDIO::sdio0(400_000); loop { println!("Wait for SD card inertion!"); diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index 54d5904..c54a636 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -1,4 +1,4 @@ -use volatile_register::{RO, RW, WO}; +use volatile_register::{RO, RW}; use libregister::{register, register_at, register_bit, register_bits, register_bits_typed}; -- 2.42.0 From a41caf9cf5556a15d02e36f3a256383864202a9d Mon Sep 17 00:00:00 2001 From: pca Date: Wed, 6 May 2020 11:04:15 +0800 Subject: [PATCH 04/34] writing command transmission --- libboard_zynq/src/sdio/cmd.rs | 38 ++++++++++++++++ libboard_zynq/src/sdio/mod.rs | 82 +++++++++++++++++++++++------------ 2 files changed, 92 insertions(+), 28 deletions(-) create mode 100644 libboard_zynq/src/sdio/cmd.rs diff --git a/libboard_zynq/src/sdio/cmd.rs b/libboard_zynq/src/sdio/cmd.rs new file mode 100644 index 0000000..85b1559 --- /dev/null +++ b/libboard_zynq/src/sdio/cmd.rs @@ -0,0 +1,38 @@ +const XSDPS_APP_CMD_PREFIX: u32 = 0x8000; + +#[allow(unused)] +#[repr(u32)] +pub enum SdCmd { + CMD0 = 0x0000, + CMD1 = 0x0100, + CMD2 = 0x0200, + CMD3 = 0x0300, + CMD4 = 0x0400, + CMD5 = 0x0500, + CMD6 = 0x0600, + ACMD6 = XSDPS_APP_CMD_PREFIX + 0x0600, + CMD7 = 0x0700, + CMD8 = 0x0800, + CMD9 = 0x0900, + CMD10 = 0x0A00, + CMD11 = 0x0B00, + CMD12 = 0x0C00, + ACMD13 = XSDPS_APP_CMD_PREFIX + 0x0D00, + CMD16 = 0x1000, + CMD17 = 0x1100, + CMD18 = 0x1200, + CMD19 = 0x1300, + CMD21 = 0x1500, + CMD23 = 0x1700, + ACMD23 = XSDPS_APP_CMD_PREFIX + 0x1700, + CMD24 = 0x1800, + CMD25 = 0x1900, + CMD41 = 0x2900, + ACMD41 = XSDPS_APP_CMD_PREFIX + 0x2900, + ACMD42 = XSDPS_APP_CMD_PREFIX + 0x2A00, + ACMD51 = XSDPS_APP_CMD_PREFIX + 0x3300, + CMD52 = 0x3400, + CMD55 = 0x3700, + CMD58 = 0x3A00, +} + diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index f168a28..9253ebc 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -1,3 +1,4 @@ +mod cmd; mod regs; use super::slcr; use libregister::*; @@ -120,41 +121,19 @@ impl SDIO { self.regs.control.modify(|_, w| w.bus_voltage(voltage)); // enable all interrupt status except card interrupt - self.regs.interrupt_status_en.write( - regs::InterruptStatusEn::zeroed() - .adma_error_status_en(true) - .auto_cmd12_error_status_en(true) - .block_gap_evt_status_en(true) - .boot_ack_rcv_en(true) - .boot_terminate_interrupt_en(true) - .buffer_read_ready_status_en(true) - .buffer_write_ready_status_en(true) - .card_insertion_status_en(true) - .card_interrupt_status_en(false) - .card_removal_status_en(true) - .ceata_error_status_en(true) - .cmd_complete_status_en(true) - .cmd_crc_error_status_en(true) - .cmd_end_bit_error_status_en(true) - .cmd_index_error_status_en(true) - .cmd_timeout_error_status_en(true) - .current_limit_error_status_en(true) - .data_crc_error_status_en(true) - .data_end_bit_error_status_en(true) - .data_timeout_error_status_en(true) - .dma_interrupt_status_en(true) - .target_response_error_status_en(true) - .transfer_complete_status_en(true), - ); + self.regs + .interrupt_status_en + .write(SDIO::enable_all_interrupt_status().card_interrupt_status_en(false)); // disable all interrupt signals self.regs .interrupt_signal_en .write(regs::InterruptSignalEn::zeroed()); - // set block size to 512 by default - self.regs.block_size_block_count.modify(|_, w| w.transfer_block_size(512)); + self.regs + .block_size_block_count + .modify(|_, w| w.transfer_block_size(512)); } /// Change clock frequency to the value less than or equal to the given value. @@ -189,6 +168,53 @@ impl SDIO { self.regs.clock_control.modify(|_, w| w.sd_clk_en(true)); } + /// Send SD command. + /// Return: Transfer success. + fn cmd_transfer(&mut self, cmd: cmd::SdCmd, arg: u32, block_cnt: u16) -> bool { + let state = self.regs.present_state.read(); + if state.command_inhibit_cmd() { + return false; + } + self.regs + .block_size_block_count + .modify(|_, w| w.blocks_count(block_cnt)); + self.regs + .clock_control + .modify(|_, w| w.timeout_counter_value(0xE)); + unsafe { + self.regs.argument.write(arg); + } + self.regs.interrupt_status_en(SDIO::enable_all_interrupt_status()); + return true; + } + + fn enable_all_interrupt_status() -> regs::interrupt_status_en::Write { + regs::InterruptStatusEn::zeroed() + .adma_error_status_en(true) + .auto_cmd12_error_status_en(true) + .block_gap_evt_status_en(true) + .boot_ack_rcv_en(true) + .boot_terminate_interrupt_en(true) + .buffer_read_ready_status_en(true) + .buffer_write_ready_status_en(true) + .card_insertion_status_en(true) + .card_interrupt_status_en(true) + .card_removal_status_en(true) + .ceata_error_status_en(true) + .cmd_complete_status_en(true) + .cmd_crc_error_status_en(true) + .cmd_end_bit_error_status_en(true) + .cmd_index_error_status_en(true) + .cmd_timeout_error_status_en(true) + .current_limit_error_status_en(true) + .data_crc_error_status_en(true) + .data_end_bit_error_status_en(true) + .data_timeout_error_status_en(true) + .dma_interrupt_status_en(true) + .target_response_error_status_en(true) + .transfer_complete_status_en(true) + } + pub fn wait_insert(&mut self) { // poll for status register while !self.regs.interrupt_status.read().card_insertion() {} -- 2.42.0 From ddb7294e0525aaa0b129ca6ce15b6b0c8180d655 Mon Sep 17 00:00:00 2001 From: pca Date: Wed, 6 May 2020 13:58:04 +0800 Subject: [PATCH 05/34] added command transfer --- libboard_zynq/src/sdio/cmd.rs | 100 ++++++++++++++++++++++++++++++--- libboard_zynq/src/sdio/mod.rs | 100 ++++++++++++++++++++++----------- libboard_zynq/src/sdio/regs.rs | 4 +- 3 files changed, 161 insertions(+), 43 deletions(-) diff --git a/libboard_zynq/src/sdio/cmd.rs b/libboard_zynq/src/sdio/cmd.rs index 85b1559..7ee15df 100644 --- a/libboard_zynq/src/sdio/cmd.rs +++ b/libboard_zynq/src/sdio/cmd.rs @@ -1,7 +1,10 @@ -const XSDPS_APP_CMD_PREFIX: u32 = 0x8000; +use super::regs; + +const APP_CMD_PREFIX: u32 = 0x8000; #[allow(unused)] #[repr(u32)] +#[derive(Copy, Clone, PartialEq)] pub enum SdCmd { CMD0 = 0x0000, CMD1 = 0x0100, @@ -10,29 +13,112 @@ pub enum SdCmd { CMD4 = 0x0400, CMD5 = 0x0500, CMD6 = 0x0600, - ACMD6 = XSDPS_APP_CMD_PREFIX + 0x0600, + ACMD6 = APP_CMD_PREFIX + 0x0600, CMD7 = 0x0700, CMD8 = 0x0800, CMD9 = 0x0900, CMD10 = 0x0A00, CMD11 = 0x0B00, CMD12 = 0x0C00, - ACMD13 = XSDPS_APP_CMD_PREFIX + 0x0D00, + ACMD13 = APP_CMD_PREFIX + 0x0D00, CMD16 = 0x1000, CMD17 = 0x1100, CMD18 = 0x1200, CMD19 = 0x1300, CMD21 = 0x1500, CMD23 = 0x1700, - ACMD23 = XSDPS_APP_CMD_PREFIX + 0x1700, + ACMD23 = APP_CMD_PREFIX + 0x1700, CMD24 = 0x1800, CMD25 = 0x1900, CMD41 = 0x2900, - ACMD41 = XSDPS_APP_CMD_PREFIX + 0x2900, - ACMD42 = XSDPS_APP_CMD_PREFIX + 0x2A00, - ACMD51 = XSDPS_APP_CMD_PREFIX + 0x3300, + ACMD41 = APP_CMD_PREFIX + 0x2900, + ACMD42 = APP_CMD_PREFIX + 0x2A00, + ACMD51 = APP_CMD_PREFIX + 0x3300, CMD52 = 0x3400, CMD55 = 0x3700, CMD58 = 0x3A00, } +pub fn require_dat(cmd: SdCmd, is_sd_card: bool) -> bool { + use SdCmd::*; + match cmd { + CMD6 => is_sd_card, + CMD8 => !is_sd_card, + ACMD13 | CMD17 | CMD18 | CMD19 | CMD21 | CMD23 | ACMD23 | CMD24 | CMD25 | ACMD51 => true, + _ => false, + } +} + +type CmdReg = regs::transfer_mode_command::Write; + +fn resp_r1(w: CmdReg) -> CmdReg { + w.response_type_select(regs::ResponseTypeSelect::Length48) + .crc_check_en(true) + .index_check_en(true) +} + +fn resp_r1b(w: CmdReg) -> CmdReg { + w.response_type_select(regs::ResponseTypeSelect::Legnth48Check) + .crc_check_en(true) + .index_check_en(true) +} + +fn resp_r2(w: CmdReg) -> CmdReg { + w.response_type_select(regs::ResponseTypeSelect::Length136) + .crc_check_en(true) +} + +fn resp_r3(w: CmdReg) -> CmdReg { + w.response_type_select(regs::ResponseTypeSelect::Length48) +} + +fn resp_r6(w: CmdReg) -> CmdReg { + w.response_type_select(regs::ResponseTypeSelect::Legnth48Check) + .crc_check_en(true) + .index_check_en(true) +} + +pub fn set_cmd_reg(cmd: SdCmd, is_sd_card: bool, w: CmdReg) -> CmdReg { + use SdCmd::*; + let w = w.command_index(cmd as u8); + match cmd { + CMD1 => resp_r3(w), + CMD2 => resp_r2(w), + CMD3 => { + if is_sd_card { + resp_r6(w) + } else { + resp_r1(w) + } + } + CMD5 => resp_r1b(w), + CMD6 => { + if is_sd_card { + resp_r1(w).data_present_select(true) + } else { + resp_r1b(w) + } + } + ACMD6 => resp_r1(w), + CMD7 => resp_r1(w), + CMD8 => { + if is_sd_card { + resp_r1(w) + } else { + resp_r1(w).data_present_select(true) + } + } + CMD9 => resp_r2(w), + CMD10 | CMD11 | CMD12 => resp_r1(w), + ACMD13 => resp_r1(w).data_present_select(true), + CMD16 => resp_r1(w), + CMD17 | CMD18 | CMD19 | CMD21 | CMD23 | ACMD23 | CMD24 | CMD25 => { + resp_r1(w).data_present_select(true) + } + ACMD41 => resp_r3(w), + ACMD42 => resp_r1(w), + ACMD51 => resp_r1(w).data_present_select(true), + CMD52 | CMD55 => resp_r1(w), + _ => w, + } +} diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 9253ebc..ddf809d 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -9,10 +9,21 @@ struct TransferMode { dat_dir_sel: bool, } +#[derive(PartialEq)] +enum CardType { + CardNone, + CardSd, + CardMmc, + CardSdio, + CardSdcombo, + ChipEmmc, +} + pub struct SDIO { regs: &'static mut regs::RegisterBlock, input_clk_hz: u32, transfer_mode: TransferMode, + card_type: CardType, } impl SDIO { @@ -73,6 +84,7 @@ impl SDIO { block_cnt_en: true, dat_dir_sel: true, }, + card_type: CardType::CardNone, }; self_.init(); @@ -121,9 +133,10 @@ impl SDIO { self.regs.control.modify(|_, w| w.bus_voltage(voltage)); // enable all interrupt status except card interrupt - self.regs - .interrupt_status_en - .write(SDIO::enable_all_interrupt_status().card_interrupt_status_en(false)); + self.regs.interrupt_status_en.write( + (regs::interrupt_status_en::Write { inner: 0xFFFFFFFF }) + .card_interrupt_status_en(false), + ); // disable all interrupt signals self.regs @@ -169,11 +182,11 @@ impl SDIO { } /// Send SD command. - /// Return: Transfer success. - fn cmd_transfer(&mut self, cmd: cmd::SdCmd, arg: u32, block_cnt: u16) -> bool { + /// Return: Ok if success, Err(msg) if failed. Err type may change later. + fn cmd_transfer(&mut self, cmd: cmd::SdCmd, arg: u32, block_cnt: u16) -> Result<(), &str> { let state = self.regs.present_state.read(); if state.command_inhibit_cmd() { - return false; + return Err("Command Inhibited"); } self.regs .block_size_block_count @@ -184,35 +197,54 @@ impl SDIO { unsafe { self.regs.argument.write(arg); } - self.regs.interrupt_status_en(SDIO::enable_all_interrupt_status()); - return true; - } + self.regs + .interrupt_status_en + .write(regs::interrupt_status_en::Write { inner: 0xFFFFFFFF }); - fn enable_all_interrupt_status() -> regs::interrupt_status_en::Write { - regs::InterruptStatusEn::zeroed() - .adma_error_status_en(true) - .auto_cmd12_error_status_en(true) - .block_gap_evt_status_en(true) - .boot_ack_rcv_en(true) - .boot_terminate_interrupt_en(true) - .buffer_read_ready_status_en(true) - .buffer_write_ready_status_en(true) - .card_insertion_status_en(true) - .card_interrupt_status_en(true) - .card_removal_status_en(true) - .ceata_error_status_en(true) - .cmd_complete_status_en(true) - .cmd_crc_error_status_en(true) - .cmd_end_bit_error_status_en(true) - .cmd_index_error_status_en(true) - .cmd_timeout_error_status_en(true) - .current_limit_error_status_en(true) - .data_crc_error_status_en(true) - .data_end_bit_error_status_en(true) - .data_timeout_error_status_en(true) - .dma_interrupt_status_en(true) - .target_response_error_status_en(true) - .transfer_complete_status_en(true) + let is_sd_card = self.card_type == CardType::CardSd; + // Check DAT Line + if cmd != cmd::SdCmd::CMD21 && cmd != cmd::SdCmd::CMD19 { + if self.regs.present_state.read().command_inhibit_dat() + && cmd::require_dat(cmd, is_sd_card) + { + return Err("Requires DAT line, but it is inhibited."); + } + } + + // Set the command registers. + self.regs + .transfer_mode_command + .modify(|_, w| cmd::set_cmd_reg(cmd, is_sd_card, w)); + + // polling for response + loop { + let status = self.regs.interrupt_status.read(); + if cmd == cmd::SdCmd::CMD21 || cmd == cmd::SdCmd::CMD19 { + if status.buffer_read_ready() { + self.regs + .interrupt_status + .modify(|_, w| w.buffer_read_ready()); + break; + } + } + if status.error_interrupt() { + let error_msg = if status.inner & 0xFFFE0000 == 0 { + "Command Timeout" + } else { + "Unknown Error" + }; + self.regs + .interrupt_status + .write(regs::interrupt_status::Write { inner: 0xF3FF0000 }); + return Err(error_msg); + } + if status.command_complete() { + break; + } + } + + self.regs.interrupt_status.modify(|_, w| w.command_complete()); + return Ok(()); } pub fn wait_insert(&mut self) { diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index c54a636..1a65328 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -131,8 +131,8 @@ register_bits_typed!( command_type, u8, CommandType, - 24, - 29 + 22, + 23 ); register_bit!( transfer_mode_command, -- 2.42.0 From ed8231147cf856cabf53811fd781535f148bd69b Mon Sep 17 00:00:00 2001 From: pca Date: Wed, 6 May 2020 14:19:39 +0800 Subject: [PATCH 06/34] modified interface --- libboard_zynq/src/sdio/mod.rs | 38 ++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index ddf809d..0a1838e 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -19,6 +19,14 @@ enum CardType { ChipEmmc, } +pub enum CmdTransferStatus { + Ok, + CmdInhibited, + DatLineInhibited, + CmdTimeout, + Other(regs::interrupt_status::Read), +} + pub struct SDIO { regs: &'static mut regs::RegisterBlock, input_clk_hz: u32, @@ -152,7 +160,7 @@ impl SDIO { /// Change clock frequency to the value less than or equal to the given value. /// From XSdPs_Change_ClkFreq in xsdps_options.c. SPEC_V3 related code is removed as /// our board would only be V1 or V2. - fn change_clk_freq(&mut self, freq: u32) { + pub fn change_clk_freq(&mut self, freq: u32) { self.regs .clock_control .modify(|_, w| w.sd_clk_en(false).internal_clk_en(false)); @@ -182,11 +190,16 @@ impl SDIO { } /// Send SD command. - /// Return: Ok if success, Err(msg) if failed. Err type may change later. - fn cmd_transfer(&mut self, cmd: cmd::SdCmd, arg: u32, block_cnt: u16) -> Result<(), &str> { + /// Return: Ok if success, Err(status) if failed + pub fn cmd_transfer( + &mut self, + cmd: cmd::SdCmd, + arg: u32, + block_cnt: u16, + ) -> Result<(), CmdTransferStatus> { let state = self.regs.present_state.read(); if state.command_inhibit_cmd() { - return Err("Command Inhibited"); + return Err(CmdTransferStatus::CmdInhibited); } self.regs .block_size_block_count @@ -207,7 +220,7 @@ impl SDIO { if self.regs.present_state.read().command_inhibit_dat() && cmd::require_dat(cmd, is_sd_card) { - return Err("Requires DAT line, but it is inhibited."); + return Err(CmdTransferStatus::DatLineInhibited); } } @@ -228,25 +241,30 @@ impl SDIO { } } if status.error_interrupt() { - let error_msg = if status.inner & 0xFFFE0000 == 0 { - "Command Timeout" + let err_status = if status.inner & 0xFFFE0000 == 0 { + CmdTransferStatus::CmdTimeout } else { - "Unknown Error" + CmdTransferStatus::Other(regs::interrupt_status::Read { + inner: status.inner, + }) }; self.regs .interrupt_status .write(regs::interrupt_status::Write { inner: 0xF3FF0000 }); - return Err(error_msg); + return Err(err_status); } if status.command_complete() { break; } } - self.regs.interrupt_status.modify(|_, w| w.command_complete()); + self.regs + .interrupt_status + .modify(|_, w| w.command_complete()); return Ok(()); } + pub fn wait_insert(&mut self) { // poll for status register while !self.regs.interrupt_status.read().card_insertion() {} -- 2.42.0 From 5082715465cd6d7e5d4034b9171b3382659668f8 Mon Sep 17 00:00:00 2001 From: pca Date: Wed, 6 May 2020 16:09:45 +0800 Subject: [PATCH 07/34] sd card initialize --- libboard_zynq/src/sdio/cmd.rs | 8 ++ libboard_zynq/src/sdio/mod.rs | 203 +++++++++++++++++++++++++++++++-- libboard_zynq/src/sdio/regs.rs | 1 + 3 files changed, 203 insertions(+), 9 deletions(-) diff --git a/libboard_zynq/src/sdio/cmd.rs b/libboard_zynq/src/sdio/cmd.rs index 7ee15df..4dda61a 100644 --- a/libboard_zynq/src/sdio/cmd.rs +++ b/libboard_zynq/src/sdio/cmd.rs @@ -1,6 +1,14 @@ use super::regs; const APP_CMD_PREFIX: u32 = 0x8000; +#[allow(unused)] +pub mod args { + pub const CMD8_VOL_PATTERN: u32 = 0x1AA; + pub const RESPOCR_READY: u32 = 0x80000000; + pub const ACMD41_HCS: u32 = 0x40000000; + pub const ACMD41_3V3: u32 = 0x00300000; + pub const OCR_S18: u32 = 1 << 24; +} #[allow(unused)] #[repr(u32)] diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 0a1838e..1957e87 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -1,6 +1,8 @@ mod cmd; mod regs; use super::slcr; +use super::time::Milliseconds; +use embedded_hal::timer::CountDown; use libregister::*; struct TransferMode { @@ -19,19 +21,44 @@ enum CardType { ChipEmmc, } -pub enum CmdTransferStatus { - Ok, +pub enum CmdTransferError { CmdInhibited, DatLineInhibited, CmdTimeout, Other(regs::interrupt_status::Read), } +pub enum CardInitializationError { + AlreadyInitialized, + NoCardInserted, + InitializationFailed(Option), +} + +impl From for CardInitializationError { + fn from(error: CmdTransferError) -> Self { + CardInitializationError::InitializationFailed(Some(error)) + } +} + +enum CardVersion { + None, + SdVer1, + SdVer2, +} + pub struct SDIO { regs: &'static mut regs::RegisterBlock, input_clk_hz: u32, transfer_mode: TransferMode, card_type: CardType, + card_detect_en: bool, + card_version: CardVersion, + hcs: bool, + switch_1v8: bool, + count_down: super::timer::global::CountDown, + card_id: [u32; 4], + rel_card_addr: u32, + sector_cnt: u32, } impl SDIO { @@ -93,6 +120,14 @@ impl SDIO { dat_dir_sel: true, }, card_type: CardType::CardNone, + card_detect_en: true, + card_version: CardVersion::None, + hcs: false, + switch_1v8: false, + count_down: super::timer::GlobalTimer::start().countdown(), + card_id: [0, 0, 0, 0], + rel_card_addr: 0, + sector_cnt: 0, }; self_.init(); @@ -113,7 +148,9 @@ impl SDIO { // I hope that this would never trigger but it is safer to put a check here. panic!("The code written is for V1 and V2"); } - // TODO: delay to poweroff card + // delay to poweroff card + self.count_down.start(Milliseconds(1)); + while let Err(_) = self.count_down.wait() {} // reset all self.regs @@ -196,10 +233,10 @@ impl SDIO { cmd: cmd::SdCmd, arg: u32, block_cnt: u16, - ) -> Result<(), CmdTransferStatus> { + ) -> Result<(), CmdTransferError> { let state = self.regs.present_state.read(); if state.command_inhibit_cmd() { - return Err(CmdTransferStatus::CmdInhibited); + return Err(CmdTransferError::CmdInhibited); } self.regs .block_size_block_count @@ -220,7 +257,7 @@ impl SDIO { if self.regs.present_state.read().command_inhibit_dat() && cmd::require_dat(cmd, is_sd_card) { - return Err(CmdTransferStatus::DatLineInhibited); + return Err(CmdTransferError::DatLineInhibited); } } @@ -242,9 +279,9 @@ impl SDIO { } if status.error_interrupt() { let err_status = if status.inner & 0xFFFE0000 == 0 { - CmdTransferStatus::CmdTimeout + CmdTransferError::CmdTimeout } else { - CmdTransferStatus::Other(regs::interrupt_status::Read { + CmdTransferError::Other(regs::interrupt_status::Read { inner: status.inner, }) }; @@ -261,9 +298,157 @@ impl SDIO { self.regs .interrupt_status .modify(|_, w| w.command_complete()); - return Ok(()); + Ok(()) } + pub fn sd_card_initialize(&mut self) -> Result<(), CardInitializationError> { + use cmd::{args::*, SdCmd::*}; + if self.card_detect_en { + if !self.regs.present_state.read().card_inserted() { + return Err(CardInitializationError::NoCardInserted); + } + } + + self.cmd_transfer(CMD0, 0, 0)?; + match self.cmd_transfer(CMD8, CMD8_VOL_PATTERN, 0) { + Err(CmdTransferError::CmdTimeout) => { + // reset + self.regs + .clock_control + .modify(|_, w| w.software_reset_cmd(true)); + // wait until reset is completed + while self.regs.clock_control.read().software_reset_cmd() {} + } + // for other error, return initialization failed + Err(e) => return Err(CardInitializationError::from(e)), + _ => (), + } + + self.card_version = if self.regs.responses[0].read() != CMD8_VOL_PATTERN { + CardVersion::SdVer1 + } else { + CardVersion::SdVer2 + }; + + // send ACMD41 while card is still busy with power up + loop { + self.cmd_transfer(CMD55, 0, 0)?; + self.cmd_transfer(ACMD41, ACMD41_HCS | ACMD41_3V3 | (0x1FF << 15), 0)?; + + if (self.regs.responses[0].read() & RESPOCR_READY) != 0 { + break; + } + } + + let response = self.regs.responses[0].read(); + // update HCS support flag + self.hcs = (response & ACMD41_HCS) != 0; + if (response & OCR_S18) != 0 { + self.switch_1v8 = true; + self.switch_voltage()?; + } + + self.cmd_transfer(CMD2, 0, 0)?; + for i in 0..=3 { + self.card_id[i] = self.regs.responses[i].read(); + } + + self.rel_card_addr = 0; + while self.rel_card_addr == 0 { + self.cmd_transfer(CMD3, 0, 0)?; + self.rel_card_addr = self.regs.responses[0].read() & 0xFFFF0000; + } + + self.cmd_transfer(CMD9, self.rel_card_addr, 0)?; + + let mut csd: [u32; 4] = [0, 0, 0, 0]; + for i in 0..=3 { + csd[i] = self.regs.responses[i].read(); + } + + const CSD_STRUCT_MSK: u32 = 0x00C00000; + const C_SIZE_MULT_MASK: u32 = 0x00000380; + const C_SIZE_LOWER_MASK: u32 = 0xFFC00000; + const C_SIZE_UPPER_MASK: u32 = 0x00000003; + const READ_BLK_LEN_MASK: u32 = 0x00000F00; + const CSD_V2_C_SIZE_MASK: u32 = 0x3FFFFF00; + const XSDPS_BLK_SIZE_512_MASK: u32 = 0x200; + if ((csd[3] & CSD_STRUCT_MSK) >> 22) == 0 { + let blk_len = 1 << ((csd[2] & READ_BLK_LEN_MASK) >> 8); + let mult = 1 << (((csd[1] & C_SIZE_MULT_MASK) >> 7) + 2); + let mut device_size = (csd[1] & C_SIZE_LOWER_MASK) >> 22; + device_size |= (csd[2] & C_SIZE_UPPER_MASK) << 10; + device_size = (device_size + 1) * mult; + device_size = device_size * blk_len; + self.sector_cnt = device_size / XSDPS_BLK_SIZE_512_MASK; + } else if ((csd[3] & CSD_STRUCT_MSK) >> 22) == 1 { + self.sector_cnt = (((csd[1] & CSD_V2_C_SIZE_MASK) >> 8) + 1) * 1024; + } else { + return Err(CardInitializationError::InitializationFailed(None)); + } + Ok(()) + } + + /// Switch voltage from 3.3V to 1.8V + fn switch_voltage(&mut self) -> Result<(), CmdTransferError> { + use cmd::SdCmd::*; + // send switch voltage command + self.cmd_transfer(CMD11, 0, 0)?; + // wait for the lines to go low + let mut state = self.regs.present_state.read(); + while state.cmd_line_level() + || state.dat0_level() + || state.dat1_level() + || state.dat2_level() + || state.dat3_level() + { + state = self.regs.present_state.read(); + } + // stop the clock + self.regs + .clock_control + .modify(|_, w| w.sd_clk_en(false).internal_clk_en(false)); + // enabling 1.8v in controller + self.regs + .control + .modify(|_, w| w.bus_voltage(regs::BusVoltage::V18)); + + // wait minimum 5ms + self.count_down.start(Milliseconds(5)); + while let Err(_) = self.count_down.wait() {} + + if self.regs.control.read().bus_voltage() != regs::BusVoltage::V18 { + // I should not wrap the error of this function into another type later. + // actually this is not correct. + return Err(CmdTransferError::CmdTimeout); + } + + // wait for internal clock to stabilize + self.regs + .clock_control + .modify(|_, w| w.internal_clk_en(true)); + while !self.regs.clock_control.read().internal_clk_stable() {} + + // enable SD clock + self.regs.clock_control.modify(|_, w| w.sd_clk_en(true)); + + // wait for 1ms + self.count_down.start(Milliseconds(1)); + while let Err(_) = self.count_down.wait() {} + + // wait for CMD and DATA line to go high + state = self.regs.present_state.read(); + while !state.cmd_line_level() + || !state.dat0_level() + || !state.dat1_level() + || !state.dat2_level() + || !state.dat3_level() + { + state = self.regs.present_state.read(); + } + + Ok(()) + } pub fn wait_insert(&mut self) { // poll for status register diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index 1a65328..e6453ee 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -50,6 +50,7 @@ pub enum ResponseTypeSelect { #[allow(unused)] #[repr(u8)] +#[derive(PartialEq)] pub enum BusVoltage { /// 3.3V V33 = 0b111, -- 2.42.0 From 011084cd8783c3e081c2dabd6d9a28fdc484dad3 Mon Sep 17 00:00:00 2001 From: pca Date: Wed, 6 May 2020 16:31:47 +0800 Subject: [PATCH 08/34] identify card --- libboard_zynq/src/sdio/cmd.rs | 1 + libboard_zynq/src/sdio/mod.rs | 35 +++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/libboard_zynq/src/sdio/cmd.rs b/libboard_zynq/src/sdio/cmd.rs index 4dda61a..04ed9a2 100644 --- a/libboard_zynq/src/sdio/cmd.rs +++ b/libboard_zynq/src/sdio/cmd.rs @@ -7,6 +7,7 @@ pub mod args { pub const RESPOCR_READY: u32 = 0x80000000; pub const ACMD41_HCS: u32 = 0x40000000; pub const ACMD41_3V3: u32 = 0x00300000; + pub const CMD1_HIGH_VOL: u32 = 0x00FF8000; pub const OCR_S18: u32 = 1 << 24; } diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 1957e87..13dfdda 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -134,6 +134,12 @@ impl SDIO { self_ } + fn delay(&mut self, ms: u64) { + self.count_down.start(Milliseconds(ms)); + // wait for the countdown to complete + while let Err(_) = self.count_down.wait() {} + } + /// initialization based on XSdPs_CfgInitialize function in xsdps.c fn init(&mut self) { // poweroff @@ -149,8 +155,7 @@ impl SDIO { panic!("The code written is for V1 and V2"); } // delay to poweroff card - self.count_down.start(Milliseconds(1)); - while let Err(_) = self.count_down.wait() {} + self.delay(1); // reset all self.regs @@ -414,8 +419,7 @@ impl SDIO { .modify(|_, w| w.bus_voltage(regs::BusVoltage::V18)); // wait minimum 5ms - self.count_down.start(Milliseconds(5)); - while let Err(_) = self.count_down.wait() {} + self.delay(5); if self.regs.control.read().bus_voltage() != regs::BusVoltage::V18 { // I should not wrap the error of this function into another type later. @@ -433,8 +437,7 @@ impl SDIO { self.regs.clock_control.modify(|_, w| w.sd_clk_en(true)); // wait for 1ms - self.count_down.start(Milliseconds(1)); - while let Err(_) = self.count_down.wait() {} + self.delay(1); // wait for CMD and DATA line to go high state = self.regs.present_state.read(); @@ -450,6 +453,26 @@ impl SDIO { Ok(()) } + pub fn identify_card(&mut self) -> Result<(), CmdTransferError> { + use cmd::{args::*, SdCmd::*}; + // actually the delay for this one is unclear in the xilinx code. + self.delay(10); + self.cmd_transfer(CMD0, 0, 0)?; + + self.card_type = match self.cmd_transfer(CMD1, ACMD41_HCS | CMD1_HIGH_VOL, 0) { + Ok(()) => CardType::CardMmc, + Err(_) => CardType::CardSd, + }; + // clear all status + self.regs + .interrupt_status + .write(regs::interrupt_status::Write { inner: 0xF3FFFFFF }); + self.regs.clock_control.modify(|_, w| w.software_reset_cmd(true)); + // wait for reset completion + while self.regs.clock_control.read().software_reset_cmd() {} + Ok(()) + } + pub fn wait_insert(&mut self) { // poll for status register while !self.regs.interrupt_status.read().card_insertion() {} -- 2.42.0 From c4c2fa3621e9337afa5a91c3ba28fd0de3cbb629 Mon Sep 17 00:00:00 2001 From: pca Date: Wed, 6 May 2020 17:07:48 +0800 Subject: [PATCH 09/34] simple test for sd card identification --- experiments/src/main.rs | 9 ++++++--- libboard_zynq/src/sdio/mod.rs | 29 ++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 3990c35..e613c5a 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -42,12 +42,15 @@ pub fn main_core0() { info!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x()); let mut sd = libboard_zynq::sdio::SDIO::sdio0(400_000); + println!("Wait for SD card inertion!"); + sd.wait_insert(); + sd.identify_card().unwrap(); + println!("{:?}", sd.card_type); loop { - println!("Wait for SD card inertion!"); - sd.wait_insert(); - println!("SD card inserted"); sd.wait_remove(); println!("SD card removed!"); + sd.wait_insert(); + println!("SD card inserted"); } } diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 13dfdda..97af4c5 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -4,6 +4,7 @@ use super::slcr; use super::time::Milliseconds; use embedded_hal::timer::CountDown; use libregister::*; +use core::fmt; struct TransferMode { dma_en: bool, @@ -11,16 +12,17 @@ struct TransferMode { dat_dir_sel: bool, } -#[derive(PartialEq)] -enum CardType { +#[derive(PartialEq, Debug)] +pub enum CardType { CardNone, CardSd, CardMmc, - CardSdio, - CardSdcombo, - ChipEmmc, + // CardSdio, + // CardSdcombo, + // ChipEmmc, } +#[derive(Debug)] pub enum CmdTransferError { CmdInhibited, DatLineInhibited, @@ -28,15 +30,24 @@ pub enum CmdTransferError { Other(regs::interrupt_status::Read), } +impl fmt::Debug for regs::interrupt_status::Read { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_fmt(format_args!("status: {}", self.inner)) + } +} + + +#[derive(Debug)] pub enum CardInitializationError { AlreadyInitialized, NoCardInserted, - InitializationFailed(Option), + InitializationFailedOther, + InitializationFailedCmd(CmdTransferError), } impl From for CardInitializationError { fn from(error: CmdTransferError) -> Self { - CardInitializationError::InitializationFailed(Some(error)) + CardInitializationError::InitializationFailedCmd(error) } } @@ -50,7 +61,7 @@ pub struct SDIO { regs: &'static mut regs::RegisterBlock, input_clk_hz: u32, transfer_mode: TransferMode, - card_type: CardType, + pub card_type: CardType, card_detect_en: bool, card_version: CardVersion, hcs: bool, @@ -389,7 +400,7 @@ impl SDIO { } else if ((csd[3] & CSD_STRUCT_MSK) >> 22) == 1 { self.sector_cnt = (((csd[1] & CSD_V2_C_SIZE_MASK) >> 8) + 1) * 1024; } else { - return Err(CardInitializationError::InitializationFailed(None)); + return Err(CardInitializationError::InitializationFailedOther); } Ok(()) } -- 2.42.0 From a3e33da99f3b4d1de2f7dcbebd5164c505b5239d Mon Sep 17 00:00:00 2001 From: pca Date: Sun, 10 May 2020 17:29:57 +0800 Subject: [PATCH 10/34] added two simple commands --- libboard_zynq/src/sdio/mod.rs | 20 +++++++++++++------- libboard_zynq/src/sdio/regs.rs | 6 ++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 97af4c5..bf1743a 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -30,13 +30,6 @@ pub enum CmdTransferError { Other(regs::interrupt_status::Read), } -impl fmt::Debug for regs::interrupt_status::Read { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_fmt(format_args!("status: {}", self.inner)) - } -} - - #[derive(Debug)] pub enum CardInitializationError { AlreadyInitialized, @@ -405,6 +398,19 @@ impl SDIO { Ok(()) } + /// Selects card and sets default block size + fn select_card(&mut self) -> Result<(), CmdTransferError> { + use cmd::SdCmd::*; + self.cmd_transfer(CMD7, self.rel_card_addr, 0) + } + + /// API to send pullup command to card before using DAT line 3(using 4-bit bus) + fn pull_up(&mut self) -> Result<(), CmdTransferError> { + use cmd::SdCmd::*; + self.cmd_transfer(CMD55, self.rel_card_addr, 0)?; + self.cmd_transfer(ACMD42, 0, 0) + } + /// Switch voltage from 3.3V to 1.8V fn switch_voltage(&mut self) -> Result<(), CmdTransferError> { use cmd::SdCmd::*; diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index e6453ee..a0e6600 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -534,3 +534,9 @@ register_bits!( 0, 7 ); + +impl fmt::Debug for regs::interrupt_status::Read { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_fmt(format_args!("status: {}", self.inner)) + } +} -- 2.42.0 From a65b780b722960b0688f6c6c887e7a78af42f099 Mon Sep 17 00:00:00 2001 From: pca Date: Sun, 10 May 2020 19:18:49 +0800 Subject: [PATCH 11/34] refactored --- experiments/src/main.rs | 9 +- libboard_zynq/src/sdio/mod.rs | 285 +++++++----------------------- libboard_zynq/src/sdio/regs.rs | 4 +- libboard_zynq/src/sdio/sd_card.rs | 133 ++++++++++++++ 4 files changed, 206 insertions(+), 225 deletions(-) create mode 100644 libboard_zynq/src/sdio/sd_card.rs diff --git a/experiments/src/main.rs b/experiments/src/main.rs index e613c5a..e64315a 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -43,13 +43,12 @@ pub fn main_core0() { let mut sd = libboard_zynq::sdio::SDIO::sdio0(400_000); println!("Wait for SD card inertion!"); - sd.wait_insert(); - sd.identify_card().unwrap(); - println!("{:?}", sd.card_type); + while !sd.is_card_inserted() {} + println!("{:?}", sd.identify_card().unwrap()); loop { - sd.wait_remove(); + while sd.is_card_inserted() {} println!("SD card removed!"); - sd.wait_insert(); + while !sd.is_card_inserted() {} println!("SD card inserted"); } } diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index bf1743a..f0eab37 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -1,25 +1,19 @@ +pub mod sd_card; + mod cmd; mod regs; use super::slcr; use super::time::Milliseconds; use embedded_hal::timer::CountDown; -use libregister::*; -use core::fmt; +use libregister::{RegisterR, RegisterRW, RegisterW}; +use nb; -struct TransferMode { - dma_en: bool, - block_cnt_en: bool, - dat_dir_sel: bool, -} - -#[derive(PartialEq, Debug)] -pub enum CardType { - CardNone, - CardSd, - CardMmc, - // CardSdio, - // CardSdcombo, - // ChipEmmc, +/// Basic SDIO Struct with common low-level functions. +pub struct SDIO { + pub regs: &'static mut regs::RegisterBlock, + count_down: super::timer::global::CountDown, + input_clk_hz: u32, + card_type: CardType, } #[derive(Debug)] @@ -30,43 +24,16 @@ pub enum CmdTransferError { Other(regs::interrupt_status::Read), } -#[derive(Debug)] -pub enum CardInitializationError { - AlreadyInitialized, - NoCardInserted, - InitializationFailedOther, - InitializationFailedCmd(CmdTransferError), -} - -impl From for CardInitializationError { - fn from(error: CmdTransferError) -> Self { - CardInitializationError::InitializationFailedCmd(error) - } -} - -enum CardVersion { - None, - SdVer1, - SdVer2, -} - -pub struct SDIO { - regs: &'static mut regs::RegisterBlock, - input_clk_hz: u32, - transfer_mode: TransferMode, - pub card_type: CardType, - card_detect_en: bool, - card_version: CardVersion, - hcs: bool, - switch_1v8: bool, - count_down: super::timer::global::CountDown, - card_id: [u32; 4], - rel_card_addr: u32, - sector_cnt: u32, +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum CardType { + CardNone, + CardSd, + CardMmc, } impl SDIO { #[cfg(feature = "target_cora_z7_10")] + /// Initialize SDIO0 for Cora Z7 10 pub fn sdio0(input_clk_hz: u32) -> Self { // initialization according to ps7_init.c slcr::RegisterBlock::unlocked(|slcr| { @@ -117,34 +84,48 @@ impl SDIO { }); let mut self_ = SDIO { regs: regs::RegisterBlock::sdio0(), - input_clk_hz, - transfer_mode: TransferMode { - dma_en: false, - block_cnt_en: true, - dat_dir_sel: true, - }, - card_type: CardType::CardNone, - card_detect_en: true, - card_version: CardVersion::None, - hcs: false, - switch_1v8: false, count_down: super::timer::GlobalTimer::start().countdown(), - card_id: [0, 0, 0, 0], - rel_card_addr: 0, - sector_cnt: 0, + input_clk_hz, + card_type: CardType::CardNone }; self_.init(); self_ } - fn delay(&mut self, ms: u64) { - self.count_down.start(Milliseconds(ms)); - // wait for the countdown to complete - while let Err(_) = self.count_down.wait() {} + /// Change clock frequency to the value less than or equal to the given value. + /// From XSdPs_Change_ClkFreq in xsdps_options.c. SPEC_V3 related code is removed as + /// our board would only be V1 or V2. + fn change_clk_freq(&mut self, freq: u32) { + self.regs + .clock_control + .modify(|_, w| w.sd_clk_en(false).internal_clk_en(false)); + + const XSDPS_CC_MAX_DIV_CNT: u32 = 256; + // calculate clock divisor + let mut div_cnt: u32 = 0x1; + let mut divisor = 0; + while div_cnt <= XSDPS_CC_MAX_DIV_CNT { + if (self.input_clk_hz / div_cnt) <= freq { + divisor = div_cnt / 2; + break; + } + div_cnt <<= 1; + } + if div_cnt > XSDPS_CC_MAX_DIV_CNT { + panic!("No valid divisor!"); + } + // enable internal clock + self.regs + .clock_control + .modify(|_, w| w.sdclk_freq_divisor(divisor as u8).internal_clk_en(true)); + while !self.regs.clock_control.read().internal_clk_stable() {} + + // enable SD clock + self.regs.clock_control.modify(|_, w| w.sd_clk_en(true)); } - /// initialization based on XSdPs_CfgInitialize function in xsdps.c + /// Initialization based on XSdPs_CfgInitialize function in xsdps.c fn init(&mut self) { // poweroff self.regs @@ -203,41 +184,15 @@ impl SDIO { .modify(|_, w| w.transfer_block_size(512)); } - /// Change clock frequency to the value less than or equal to the given value. - /// From XSdPs_Change_ClkFreq in xsdps_options.c. SPEC_V3 related code is removed as - /// our board would only be V1 or V2. - pub fn change_clk_freq(&mut self, freq: u32) { - self.regs - .clock_control - .modify(|_, w| w.sd_clk_en(false).internal_clk_en(false)); - - const XSDPS_CC_MAX_DIV_CNT: u32 = 256; - // calculate clock divisor - let mut div_cnt: u32 = 0x1; - let mut divisor = 0; - while div_cnt <= XSDPS_CC_MAX_DIV_CNT { - if (self.input_clk_hz / div_cnt) <= freq { - divisor = div_cnt / 2; - break; - } - div_cnt <<= 1; - } - if div_cnt > XSDPS_CC_MAX_DIV_CNT { - panic!("No valid divisor!"); - } - // enable internal clock - self.regs - .clock_control - .modify(|_, w| w.sdclk_freq_divisor(divisor as u8).internal_clk_en(true)); - while !self.regs.clock_control.read().internal_clk_stable() {} - - // enable SD clock - self.regs.clock_control.modify(|_, w| w.sd_clk_en(true)); + /// Delay for SDIO operations, simple wrapper for nb. + fn delay(&mut self, ms: u64) { + self.count_down.start(Milliseconds(ms)); + nb::block!(self.count_down.wait()).unwrap(); } /// Send SD command. - /// Return: Ok if success, Err(status) if failed - pub fn cmd_transfer( + /// Return: Ok if success, Err(status) if failed. + fn cmd_transfer( &mut self, cmd: cmd::SdCmd, arg: u32, @@ -310,108 +265,12 @@ impl SDIO { Ok(()) } - pub fn sd_card_initialize(&mut self) -> Result<(), CardInitializationError> { - use cmd::{args::*, SdCmd::*}; - if self.card_detect_en { - if !self.regs.present_state.read().card_inserted() { - return Err(CardInitializationError::NoCardInserted); - } - } - - self.cmd_transfer(CMD0, 0, 0)?; - match self.cmd_transfer(CMD8, CMD8_VOL_PATTERN, 0) { - Err(CmdTransferError::CmdTimeout) => { - // reset - self.regs - .clock_control - .modify(|_, w| w.software_reset_cmd(true)); - // wait until reset is completed - while self.regs.clock_control.read().software_reset_cmd() {} - } - // for other error, return initialization failed - Err(e) => return Err(CardInitializationError::from(e)), - _ => (), - } - - self.card_version = if self.regs.responses[0].read() != CMD8_VOL_PATTERN { - CardVersion::SdVer1 - } else { - CardVersion::SdVer2 - }; - - // send ACMD41 while card is still busy with power up - loop { - self.cmd_transfer(CMD55, 0, 0)?; - self.cmd_transfer(ACMD41, ACMD41_HCS | ACMD41_3V3 | (0x1FF << 15), 0)?; - - if (self.regs.responses[0].read() & RESPOCR_READY) != 0 { - break; - } - } - - let response = self.regs.responses[0].read(); - // update HCS support flag - self.hcs = (response & ACMD41_HCS) != 0; - if (response & OCR_S18) != 0 { - self.switch_1v8 = true; - self.switch_voltage()?; - } - - self.cmd_transfer(CMD2, 0, 0)?; - for i in 0..=3 { - self.card_id[i] = self.regs.responses[i].read(); - } - - self.rel_card_addr = 0; - while self.rel_card_addr == 0 { - self.cmd_transfer(CMD3, 0, 0)?; - self.rel_card_addr = self.regs.responses[0].read() & 0xFFFF0000; - } - - self.cmd_transfer(CMD9, self.rel_card_addr, 0)?; - - let mut csd: [u32; 4] = [0, 0, 0, 0]; - for i in 0..=3 { - csd[i] = self.regs.responses[i].read(); - } - - const CSD_STRUCT_MSK: u32 = 0x00C00000; - const C_SIZE_MULT_MASK: u32 = 0x00000380; - const C_SIZE_LOWER_MASK: u32 = 0xFFC00000; - const C_SIZE_UPPER_MASK: u32 = 0x00000003; - const READ_BLK_LEN_MASK: u32 = 0x00000F00; - const CSD_V2_C_SIZE_MASK: u32 = 0x3FFFFF00; - const XSDPS_BLK_SIZE_512_MASK: u32 = 0x200; - if ((csd[3] & CSD_STRUCT_MSK) >> 22) == 0 { - let blk_len = 1 << ((csd[2] & READ_BLK_LEN_MASK) >> 8); - let mult = 1 << (((csd[1] & C_SIZE_MULT_MASK) >> 7) + 2); - let mut device_size = (csd[1] & C_SIZE_LOWER_MASK) >> 22; - device_size |= (csd[2] & C_SIZE_UPPER_MASK) << 10; - device_size = (device_size + 1) * mult; - device_size = device_size * blk_len; - self.sector_cnt = device_size / XSDPS_BLK_SIZE_512_MASK; - } else if ((csd[3] & CSD_STRUCT_MSK) >> 22) == 1 { - self.sector_cnt = (((csd[1] & CSD_V2_C_SIZE_MASK) >> 8) + 1) * 1024; - } else { - return Err(CardInitializationError::InitializationFailedOther); - } - Ok(()) + /// Check if card is inserted. + pub fn is_card_inserted(&self) -> bool { + self.regs.present_state.read().card_inserted() } - /// Selects card and sets default block size - fn select_card(&mut self) -> Result<(), CmdTransferError> { - use cmd::SdCmd::*; - self.cmd_transfer(CMD7, self.rel_card_addr, 0) - } - - /// API to send pullup command to card before using DAT line 3(using 4-bit bus) - fn pull_up(&mut self) -> Result<(), CmdTransferError> { - use cmd::SdCmd::*; - self.cmd_transfer(CMD55, self.rel_card_addr, 0)?; - self.cmd_transfer(ACMD42, 0, 0) - } - - /// Switch voltage from 3.3V to 1.8V + /// Switch voltage from 3.3V to 1.8V. fn switch_voltage(&mut self) -> Result<(), CmdTransferError> { use cmd::SdCmd::*; // send switch voltage command @@ -470,7 +329,9 @@ impl SDIO { Ok(()) } - pub fn identify_card(&mut self) -> Result<(), CmdTransferError> { + /// Detect inserted card type, and set the corresponding field. + /// Return Ok(CardType) on success, Err(CmdTransferError) when failed to identify. + pub fn identify_card(&mut self) -> Result { use cmd::{args::*, SdCmd::*}; // actually the delay for this one is unclear in the xilinx code. self.delay(10); @@ -484,23 +345,11 @@ impl SDIO { self.regs .interrupt_status .write(regs::interrupt_status::Write { inner: 0xF3FFFFFF }); - self.regs.clock_control.modify(|_, w| w.software_reset_cmd(true)); + self.regs + .clock_control + .modify(|_, w| w.software_reset_cmd(true)); // wait for reset completion while self.regs.clock_control.read().software_reset_cmd() {} - Ok(()) + Ok(self.card_type) } - - pub fn wait_insert(&mut self) { - // poll for status register - while !self.regs.interrupt_status.read().card_insertion() {} - // clear status register (WTC) - self.regs.interrupt_status.modify(|_, w| w.card_insertion()); - } - - pub fn wait_remove(&mut self) { - // poll for status regsiter - while !self.regs.interrupt_status.read().card_removal() {} - // clear status register (WTC) - self.regs.interrupt_status.modify(|_, w| w.card_removal()); - } -} +} \ No newline at end of file diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index a0e6600..7984b66 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -1,5 +1,5 @@ use volatile_register::{RO, RW}; - +use core::fmt; use libregister::{register, register_at, register_bit, register_bits, register_bits_typed}; #[repr(C)] @@ -535,7 +535,7 @@ register_bits!( 7 ); -impl fmt::Debug for regs::interrupt_status::Read { +impl fmt::Debug for interrupt_status::Read { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_fmt(format_args!("status: {}", self.inner)) } diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs new file mode 100644 index 0000000..957e102 --- /dev/null +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -0,0 +1,133 @@ +use super::cmd; +use super::{SDIO, CmdTransferError}; +use libregister::{RegisterR, RegisterRW}; + +#[derive(Debug)] +pub enum CardInitializationError { + AlreadyInitialized, + NoCardInserted, + InitializationFailedOther, + InitializationFailedCmd(CmdTransferError), +} + +impl From for CardInitializationError { + fn from(error: CmdTransferError) -> Self { + CardInitializationError::InitializationFailedCmd(error) + } +} + +enum CardVersion { + SdVer1, + SdVer2, +} + +pub struct SdCard { + sdio: SDIO, + card_version: CardVersion, + hcs: bool, + card_id: [u32; 4], + rel_card_addr: u32, + sector_cnt: u32, + switch_1v8: bool, +} + +impl SdCard { + pub fn sd_card_initialize(&mut self) -> Result<(), CardInitializationError> { + use cmd::{args::*, SdCmd::*}; + if !self.sdio.is_card_inserted() { + return Err(CardInitializationError::NoCardInserted); + } + + self.sdio.cmd_transfer(CMD0, 0, 0)?; + match self.sdio.cmd_transfer(CMD8, CMD8_VOL_PATTERN, 0) { + Err(CmdTransferError::CmdTimeout) => { + // reset + self.sdio.regs + .clock_control + .modify(|_, w| w.software_reset_cmd(true)); + // wait until reset is completed + while self.sdio.regs.clock_control.read().software_reset_cmd() {} + } + // for other error, return initialization failed + Err(e) => return Err(CardInitializationError::from(e)), + _ => (), + } + + self.card_version = if self.sdio.regs.responses[0].read() != CMD8_VOL_PATTERN { + CardVersion::SdVer1 + } else { + CardVersion::SdVer2 + }; + + // send ACMD41 while card is still busy with power up + loop { + self.sdio.cmd_transfer(CMD55, 0, 0)?; + self.sdio.cmd_transfer(ACMD41, ACMD41_HCS | ACMD41_3V3 | (0x1FF << 15), 0)?; + + if (self.sdio.regs.responses[0].read() & RESPOCR_READY) != 0 { + break; + } + } + + let response = self.sdio.regs.responses[0].read(); + // update HCS support flag + self.hcs = (response & ACMD41_HCS) != 0; + if (response & OCR_S18) != 0 { + self.switch_1v8 = true; + self.sdio.switch_voltage()?; + } + + self.sdio.cmd_transfer(CMD2, 0, 0)?; + for i in 0..=3 { + self.card_id[i] = self.sdio.regs.responses[i].read(); + } + + self.rel_card_addr = 0; + while self.rel_card_addr == 0 { + self.sdio.cmd_transfer(CMD3, 0, 0)?; + self.rel_card_addr = self.sdio.regs.responses[0].read() & 0xFFFF0000; + } + + self.sdio.cmd_transfer(CMD9, self.rel_card_addr, 0)?; + + let mut csd: [u32; 4] = [0, 0, 0, 0]; + for i in 0..=3 { + csd[i] = self.sdio.regs.responses[i].read(); + } + + const CSD_STRUCT_MSK: u32 = 0x00C00000; + const C_SIZE_MULT_MASK: u32 = 0x00000380; + const C_SIZE_LOWER_MASK: u32 = 0xFFC00000; + const C_SIZE_UPPER_MASK: u32 = 0x00000003; + const READ_BLK_LEN_MASK: u32 = 0x00000F00; + const CSD_V2_C_SIZE_MASK: u32 = 0x3FFFFF00; + const XSDPS_BLK_SIZE_512_MASK: u32 = 0x200; + if ((csd[3] & CSD_STRUCT_MSK) >> 22) == 0 { + let blk_len = 1 << ((csd[2] & READ_BLK_LEN_MASK) >> 8); + let mult = 1 << (((csd[1] & C_SIZE_MULT_MASK) >> 7) + 2); + let mut device_size = (csd[1] & C_SIZE_LOWER_MASK) >> 22; + device_size |= (csd[2] & C_SIZE_UPPER_MASK) << 10; + device_size = (device_size + 1) * mult; + device_size = device_size * blk_len; + self.sector_cnt = device_size / XSDPS_BLK_SIZE_512_MASK; + } else if ((csd[3] & CSD_STRUCT_MSK) >> 22) == 1 { + self.sector_cnt = (((csd[1] & CSD_V2_C_SIZE_MASK) >> 8) + 1) * 1024; + } else { + return Err(CardInitializationError::InitializationFailedOther); + } + Ok(()) + } + + /// Selects card and sets default block size + fn select_card(&mut self) -> Result<(), CmdTransferError> { + use cmd::SdCmd::*; + self.sdio.cmd_transfer(CMD7, self.rel_card_addr, 0) + } + + /// API to send pullup command to card before using DAT line 3(using 4-bit bus) + fn pull_up(&mut self) -> Result<(), CmdTransferError> { + use cmd::SdCmd::*; + self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; + self.sdio.cmd_transfer(ACMD42, 0, 0) + } +} \ No newline at end of file -- 2.42.0 From a290e1e3398597d82256afed70cabf453bc4f8a4 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 11 May 2020 17:04:47 +0800 Subject: [PATCH 12/34] Debugging clock issue --- experiments/src/main.rs | 11 +++++- libboard_zynq/src/sdio/cmd.rs | 2 +- libboard_zynq/src/sdio/mod.rs | 16 +++++--- libboard_zynq/src/sdio/sd_card.rs | 62 ++++++++++++++++++++++++------- libboard_zynq/src/slcr.rs | 41 +++++++++++++++++++- 5 files changed, 110 insertions(+), 22 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index e64315a..daf8999 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -9,6 +9,7 @@ use libcortex_a9::{mutex::Mutex, sync_channel::{self}}; use libboard_zynq::{ println, self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll}, + sdio::sd_card::SdCard }; use libsupport_zynq; @@ -41,10 +42,16 @@ pub fn main_core0() { let clocks = zynq::clocks::Clocks::get(); info!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x()); - let mut sd = libboard_zynq::sdio::SDIO::sdio0(400_000); + let mut sd = libboard_zynq::sdio::SDIO::sdio0(50000000); println!("Wait for SD card inertion!"); while !sd.is_card_inserted() {} - println!("{:?}", sd.identify_card().unwrap()); + // let result = SdCard::from_sdio(sd); + // match &result { + // Ok(_) => (), + // Err(a) => println!("{:?}", a), + // }; + // let sd_card = result.unwrap(); + // sd = sd_card.to_sdio(); loop { while sd.is_card_inserted() {} println!("SD card removed!"); diff --git a/libboard_zynq/src/sdio/cmd.rs b/libboard_zynq/src/sdio/cmd.rs index 04ed9a2..d527822 100644 --- a/libboard_zynq/src/sdio/cmd.rs +++ b/libboard_zynq/src/sdio/cmd.rs @@ -13,7 +13,7 @@ pub mod args { #[allow(unused)] #[repr(u32)] -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum SdCmd { CMD0 = 0x0000, CMD1 = 0x0100, diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index f0eab37..79670d4 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -6,6 +6,7 @@ use super::slcr; use super::time::Milliseconds; use embedded_hal::timer::CountDown; use libregister::{RegisterR, RegisterRW, RegisterW}; +use super::println; use nb; /// Basic SDIO Struct with common low-level functions. @@ -41,7 +42,6 @@ impl SDIO { slcr::MioPin40::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .pullup(true), ); slcr.mio_pin_41.write( slcr::MioPin41::zeroed() @@ -78,8 +78,11 @@ impl SDIO { .io_type(slcr::IoBufferType::Lvcmos18) .pullup(true), ); + slcr.sdio_rst_ctrl.reset_sdio0(); + slcr.aper_clk_ctrl.enable_sdio0(); unsafe { - slcr.sdio_clk_ctrl.write(0x00001401); + let value = slcr.sdio_clk_ctrl.read(); + slcr.sdio_clk_ctrl.write((value & 0x00003F33) | 0x00001401); } }); let mut self_ = SDIO { @@ -190,7 +193,7 @@ impl SDIO { nb::block!(self.count_down.wait()).unwrap(); } - /// Send SD command. + /// Send SD command. This function would block until response is ready. /// Return: Ok if success, Err(status) if failed. fn cmd_transfer( &mut self, @@ -198,6 +201,7 @@ impl SDIO { arg: u32, block_cnt: u16, ) -> Result<(), CmdTransferError> { + println!("Send {:?}", cmd); let state = self.regs.present_state.read(); if state.command_inhibit_cmd() { return Err(CmdTransferError::CmdInhibited); @@ -249,6 +253,7 @@ impl SDIO { inner: status.inner, }) }; + // reset all error status self.regs .interrupt_status .write(regs::interrupt_status::Write { inner: 0xF3FF0000 }); @@ -258,7 +263,8 @@ impl SDIO { break; } } - + // wait for command complete + while !self.regs.interrupt_status.read().command_complete() {} self.regs .interrupt_status .modify(|_, w| w.command_complete()); @@ -352,4 +358,4 @@ impl SDIO { while self.regs.clock_control.read().software_reset_cmd() {} Ok(self.card_type) } -} \ No newline at end of file +} diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 957e102..5505950 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -1,6 +1,7 @@ use super::cmd; -use super::{SDIO, CmdTransferError}; +use super::{SDIO, CmdTransferError, CardType}; use libregister::{RegisterR, RegisterRW}; +use super::super::println; #[derive(Debug)] pub enum CardInitializationError { @@ -32,12 +33,13 @@ pub struct SdCard { } impl SdCard { - pub fn sd_card_initialize(&mut self) -> Result<(), CardInitializationError> { + fn sd_card_initialize(&mut self) -> Result<(), CardInitializationError> { use cmd::{args::*, SdCmd::*}; if !self.sdio.is_card_inserted() { return Err(CardInitializationError::NoCardInserted); } + // CMD0 self.sdio.cmd_transfer(CMD0, 0, 0)?; match self.sdio.cmd_transfer(CMD8, CMD8_VOL_PATTERN, 0) { Err(CmdTransferError::CmdTimeout) => { @@ -61,7 +63,7 @@ impl SdCard { // send ACMD41 while card is still busy with power up loop { - self.sdio.cmd_transfer(CMD55, 0, 0)?; + // self.sdio.cmd_transfer(CMD55, 0, 0)?; self.sdio.cmd_transfer(ACMD41, ACMD41_HCS | ACMD41_3V3 | (0x1FF << 15), 0)?; if (self.sdio.regs.responses[0].read() & RESPOCR_READY) != 0 { @@ -115,19 +117,53 @@ impl SdCard { } else { return Err(CardInitializationError::InitializationFailedOther); } + + // CMD7: select card + self.sdio.cmd_transfer(CMD7, self.rel_card_addr, 0)?; + // ACMD6: set bus width + self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; + self.sdio.cmd_transfer(ACMD6, 2, 0)?; + Ok(()) } - /// Selects card and sets default block size - fn select_card(&mut self) -> Result<(), CmdTransferError> { - use cmd::SdCmd::*; - self.sdio.cmd_transfer(CMD7, self.rel_card_addr, 0) + pub fn from_sdio(mut sdio: SDIO) -> Result { + match sdio.identify_card()? { + CardType::CardSd => (), + _ => return Err(CardInitializationError::NoCardInserted), + }; + let mut _self = SdCard { + sdio, + card_version: CardVersion::SdVer1, + hcs: false, + card_id: [0, 0, 0, 0], + rel_card_addr: 0, + sector_cnt: 0, + switch_1v8: false + }; + _self.sd_card_initialize()?; + Ok(_self) } - /// API to send pullup command to card before using DAT line 3(using 4-bit bus) - fn pull_up(&mut self) -> Result<(), CmdTransferError> { - use cmd::SdCmd::*; - self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; - self.sdio.cmd_transfer(ACMD42, 0, 0) + pub fn to_sdio(self) -> SDIO { + self.sdio } -} \ No newline at end of file + + pub fn read_block(&mut self, block: u16, buffer: &mut [u32]) -> Result<(), CmdTransferError>{ + use cmd::SdCmd::*; + self.sdio.cmd_transfer(CMD17, 0, block)?; + + for i in 0..(block as usize) { + // wait for buffer read ready + while !self.sdio.regs.interrupt_status.read().buffer_read_ready() {} + // clear interrupt status + self.sdio.regs.interrupt_status.modify(|_, w| w.buffer_read_ready()); + buffer[i] = self.sdio.regs.buffer.read(); + println!("Read {}", buffer[i]); + } + // wait for transfer complete interrupt + while !self.sdio.regs.interrupt_status.read().transfer_complete() {} + self.sdio.regs.interrupt_status.modify(|_, w| w.transfer_complete()); + Ok(()) + } +} diff --git a/libboard_zynq/src/slcr.rs b/libboard_zynq/src/slcr.rs index 98c0a95..3b99786 100644 --- a/libboard_zynq/src/slcr.rs +++ b/libboard_zynq/src/slcr.rs @@ -127,7 +127,7 @@ pub struct RegisterBlock { pub dmac_rst_ctrl: RW, pub usb_rst_ctrl: RW, pub gem_rst_ctrl: RW, - pub sdio_rst_ctrl: RW, + pub sdio_rst_ctrl: SdioRstCtrl, pub spi_rst_ctrl: RW, pub can_rst_ctrl: RW, pub i2c_rst_ctrl: RW, @@ -391,6 +391,8 @@ register_bit!(clk_621_true, clk_621_true, 0); register!(aper_clk_ctrl, AperClkCtrl, RW, u32); register_bit!(aper_clk_ctrl, uart1_cpu_1xclkact, 21); register_bit!(aper_clk_ctrl, uart0_cpu_1xclkact, 20); +register_bit!(aper_clk_ctrl, sdio1_cpu_1xclkact, 11); +register_bit!(aper_clk_ctrl, sdio0_cpu_1xclkact, 10); impl AperClkCtrl { pub fn enable_uart0(&mut self) { self.modify(|_, w| w.uart0_cpu_1xclkact(true)); @@ -399,6 +401,14 @@ impl AperClkCtrl { pub fn enable_uart1(&mut self) { self.modify(|_, w| w.uart1_cpu_1xclkact(true)); } + + pub fn enable_sdio0(&mut self) { + self.modify(|_, w| w.sdio0_cpu_1xclkact(true)); + } + + pub fn enable_sdio1(&mut self) { + self.modify(|_, w| w.sdio1_cpu_1xclkact(true)); + } } register!(rclk_ctrl, RclkCtrl, RW, u32); @@ -453,6 +463,35 @@ impl UartClkCtrl { } } +register!(sdio_rst_ctrl, SdioRstCtrl, RW, u32); +register_bit!(sdio_rst_ctrl, sdio1_ref_rst, 5); +register_bit!(sdio_rst_ctrl, sdio0_ref_rst, 4); +register_bit!(sdio_rst_ctrl, sdio1_cpu1x_rst, 1); +register_bit!(sdio_rst_ctrl, sdio0_cpu1x_rst, 0); +register_at!(SdioRstCtrl, 0xF8000218, new); +impl SdioRstCtrl { + pub fn reset_sdio0(&mut self) { + self.modify(|_, w| + w.sdio0_ref_rst(true) + .sdio0_cpu1x_rst(true) + ); + self.modify(|_, w| + w.sdio0_ref_rst(false) + .sdio0_cpu1x_rst(false) + ); + } + pub fn reset_sdio1(&mut self) { + self.modify(|_, w| + w.sdio1_ref_rst(true) + .sdio1_cpu1x_rst(true) + ); + self.modify(|_, w| + w.sdio1_ref_rst(false) + .sdio1_cpu1x_rst(false) + ); + } +} + register!(uart_rst_ctrl, UartRstCtrl, RW, u32); register_bit!(uart_rst_ctrl, uart0_ref_rst, 3); register_bit!(uart_rst_ctrl, uart1_ref_rst, 2); -- 2.42.0 From 3678df5e630522ecb492593b74b04ea6cb71c174 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 15 May 2020 14:02:57 +0800 Subject: [PATCH 13/34] Debugging clock line issue. --- experiments/src/main.rs | 2 +- libboard_zynq/src/clocks/mod.rs | 14 ++++++++ libboard_zynq/src/sdio/mod.rs | 62 ++++++++++++++++++++++++++------- libboard_zynq/src/sdio/regs.rs | 8 ++++- libboard_zynq/src/slcr.rs | 21 +++++++++-- 5 files changed, 90 insertions(+), 17 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index daf8999..29ed633 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -42,7 +42,7 @@ pub fn main_core0() { let clocks = zynq::clocks::Clocks::get(); info!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x()); - let mut sd = libboard_zynq::sdio::SDIO::sdio0(50000000); + let mut sd = libboard_zynq::sdio::SDIO::sdio0(); println!("Wait for SD card inertion!"); while !sd.is_card_inserted() {} // let result = SdCard::from_sdio(sd); diff --git a/libboard_zynq/src/clocks/mod.rs b/libboard_zynq/src/clocks/mod.rs index fef755a..925768c 100644 --- a/libboard_zynq/src/clocks/mod.rs +++ b/libboard_zynq/src/clocks/mod.rs @@ -104,4 +104,18 @@ impl Clocks { }; pll / u32::from(uart_clk_ctrl.divisor()) } + + pub fn sdio_ref_clk(&self) -> u32 { + let regs = slcr::RegisterBlock::new(); + let sdio_clk_ctrl = regs.sdio_clk_ctrl.read(); + let pll = match sdio_clk_ctrl.srcsel() { + slcr::PllSource::ArmPll => + self.arm, + slcr::PllSource::DdrPll => + self.ddr, + slcr::PllSource::IoPll => + self.io, + }; + pll / u32::from(sdio_clk_ctrl.divisor()) + } } diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 79670d4..5ef2c2b 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -4,11 +4,17 @@ mod cmd; mod regs; use super::slcr; use super::time::Milliseconds; +use super::clocks::Clocks; use embedded_hal::timer::CountDown; use libregister::{RegisterR, RegisterRW, RegisterW}; use super::println; use nb; +macro_rules! print_field_addr { + ($self: expr, $name: ident) => + (println!("Addr {:p}: {}", &$self.$name, stringify!($name));) +} + /// Basic SDIO Struct with common low-level functions. pub struct SDIO { pub regs: &'static mut regs::RegisterBlock, @@ -35,9 +41,18 @@ pub enum CardType { impl SDIO { #[cfg(feature = "target_cora_z7_10")] /// Initialize SDIO0 for Cora Z7 10 - pub fn sdio0(input_clk_hz: u32) -> Self { + pub fn sdio0() -> Self { // initialization according to ps7_init.c slcr::RegisterBlock::unlocked(|slcr| { + print_field_addr!(slcr, mio_pin_40); + print_field_addr!(slcr, mio_pin_41); + print_field_addr!(slcr, mio_pin_42); + print_field_addr!(slcr, mio_pin_43); + print_field_addr!(slcr, mio_pin_44); + print_field_addr!(slcr, mio_pin_45); + print_field_addr!(slcr, mio_pin_47); + print_field_addr!(slcr, sdio_clk_ctrl); + print_field_addr!(slcr, sdio_rst_ctrl); slcr.mio_pin_40.write( slcr::MioPin40::zeroed() .l3_sel(0b100) @@ -47,51 +62,43 @@ impl SDIO { slcr::MioPin41::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .pullup(true), ); slcr.mio_pin_42.write( slcr::MioPin42::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .pullup(true), ); slcr.mio_pin_43.write( slcr::MioPin43::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .pullup(true), ); slcr.mio_pin_44.write( slcr::MioPin44::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .pullup(true), ); slcr.mio_pin_45.write( slcr::MioPin45::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .pullup(true), ); slcr.mio_pin_47.write( slcr::MioPin47::zeroed() .io_type(slcr::IoBufferType::Lvcmos18) - .pullup(true), ); slcr.sdio_rst_ctrl.reset_sdio0(); slcr.aper_clk_ctrl.enable_sdio0(); - unsafe { - let value = slcr.sdio_clk_ctrl.read(); - slcr.sdio_clk_ctrl.write((value & 0x00003F33) | 0x00001401); - } + slcr.sdio_clk_ctrl.enable_sdio0(); }); + let clocks = Clocks::get(); + println!("Ref Clk: {}", clocks.sdio_ref_clk()); let mut self_ = SDIO { regs: regs::RegisterBlock::sdio0(), count_down: super::timer::GlobalTimer::start().countdown(), - input_clk_hz, + input_clk_hz: clocks.sdio_ref_clk(), card_type: CardType::CardNone }; - self_.init(); self_ } @@ -115,6 +122,7 @@ impl SDIO { } div_cnt <<= 1; } + println!("{}", div_cnt); if div_cnt > XSDPS_CC_MAX_DIV_CNT { panic!("No valid divisor!"); } @@ -128,8 +136,35 @@ impl SDIO { self.regs.clock_control.modify(|_, w| w.sd_clk_en(true)); } + + fn print_registers(&self) { + print_field_addr!(self.regs, sdma_system_address); + print_field_addr!(self.regs, block_size_block_count); + print_field_addr!(self.regs, argument); + print_field_addr!(self.regs, transfer_mode_command); + print_field_addr!(self.regs, responses); + print_field_addr!(self.regs, buffer); + print_field_addr!(self.regs, present_state); + print_field_addr!(self.regs, control); + print_field_addr!(self.regs, clock_control); + print_field_addr!(self.regs, interrupt_status); + print_field_addr!(self.regs, interrupt_status_en); + print_field_addr!(self.regs, interrupt_signal_en); + print_field_addr!(self.regs, auto_cmd12_error_status); + print_field_addr!(self.regs, capabilities); + print_field_addr!(self.regs, max_current_capabilities); + print_field_addr!(self.regs, force_event); + print_field_addr!(self.regs, adma_error_status); + print_field_addr!(self.regs, adma_system_address); + print_field_addr!(self.regs, boot_data_timeout_counter); + print_field_addr!(self.regs, debug_selection); + print_field_addr!(self.regs, spi_interrupt_support); + print_field_addr!(self.regs, misc_reg); + } + /// Initialization based on XSdPs_CfgInitialize function in xsdps.c fn init(&mut self) { + self.print_registers(); // poweroff self.regs .control @@ -168,6 +203,7 @@ impl SDIO { } else { regs::BusVoltage::V0 }; + println!("{:?}", voltage); self.regs.control.modify(|_, w| w.bus_voltage(voltage)); // enable all interrupt status except card interrupt diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index 7984b66..f30bd21 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -2,6 +2,7 @@ use volatile_register::{RO, RW}; use core::fmt; use libregister::{register, register_at, register_bit, register_bits, register_bits_typed}; +#[allow(unused)] #[repr(C)] pub struct RegisterBlock { pub sdma_system_address: RW, @@ -20,13 +21,18 @@ pub struct RegisterBlock { pub interrupt_signal_en: InterruptSignalEn, pub auto_cmd12_error_status: AutoCmd12ErrorStatus, pub capabilities: Capabilities, + pub unused0: RO, pub max_current_capabilities: MaxCurrentCapabilities, + pub unused1: RO, pub force_event: ForceEvent, pub adma_error_status: AdmaErrorStatus, pub adma_system_address: RW, + pub unused2: RO, pub boot_data_timeout_counter: RW, pub debug_selection: DebugSelection, + pub unused3: [RO; 34], pub spi_interrupt_support: SpiInterruptSupport, + pub unused4: [RO; 2], pub misc_reg: MiscReg, } @@ -50,7 +56,7 @@ pub enum ResponseTypeSelect { #[allow(unused)] #[repr(u8)] -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum BusVoltage { /// 3.3V V33 = 0b111, diff --git a/libboard_zynq/src/slcr.rs b/libboard_zynq/src/slcr.rs index 3b99786..b2fa276 100644 --- a/libboard_zynq/src/slcr.rs +++ b/libboard_zynq/src/slcr.rs @@ -94,7 +94,7 @@ pub struct RegisterBlock { pub gem1_clk_ctrl: GemClkCtrl, pub smc_clk_ctrl: RW, pub lqspi_clk_ctrl: LqspiClkCtrl, - pub sdio_clk_ctrl: RW, + pub sdio_clk_ctrl: SdioClkCtrl, pub uart_clk_ctrl: UartClkCtrl, pub spi_clk_ctrl: RW, pub can_clk_ctrl: RW, @@ -433,6 +433,24 @@ register_bit!(gem_clk_ctrl, /// SMC reference clock control clkact, 0); +register!(sdio_clk_ctrl, SdioClkCtrl, RW, u32); +register_bit!(sdio_clk_ctrl, clkact0, 0); +register_bit!(sdio_clk_ctrl, clkact1, 1); +register_bits!(sdio_clk_ctrl, divisor, u8, 8, 13); +register_bits_typed!(sdio_clk_ctrl, srcsel, u8, PllSource, 4, 5); +impl SdioClkCtrl { + pub fn enable_sdio0(&mut self) { + self.modify(|_, w| { + w.divisor(0x1E).srcsel(PllSource::IoPll).clkact0(true) + }) + } + pub fn enable_sdio1(&mut self) { + self.modify(|_, w| { + w.divisor(0x1E).srcsel(PllSource::IoPll).clkact1(true) + }) + } +} + register!(uart_clk_ctrl, UartClkCtrl, RW, u32); register_bit!(uart_clk_ctrl, clkact0, 0); register_bit!(uart_clk_ctrl, clkact1, 1); @@ -468,7 +486,6 @@ register_bit!(sdio_rst_ctrl, sdio1_ref_rst, 5); register_bit!(sdio_rst_ctrl, sdio0_ref_rst, 4); register_bit!(sdio_rst_ctrl, sdio1_cpu1x_rst, 1); register_bit!(sdio_rst_ctrl, sdio0_cpu1x_rst, 0); -register_at!(SdioRstCtrl, 0xF8000218, new); impl SdioRstCtrl { pub fn reset_sdio0(&mut self) { self.modify(|_, w| -- 2.42.0 From e1c3d7c5ea18111d051dab1268cbc6f5c15ffbca Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 15 May 2020 15:03:16 +0800 Subject: [PATCH 14/34] Changed println to debug and info. Setup IO PLL. --- experiments/src/main.rs | 13 +++++++++---- libboard_zynq/src/sdio/mod.rs | 12 ++++++------ libboard_zynq/src/sdio/sd_card.rs | 4 ++-- libboard_zynq/src/slcr.rs | 4 ++-- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 29ed633..b1ff36d 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -8,7 +8,7 @@ use libregister::RegisterR; use libcortex_a9::{mutex::Mutex, sync_channel::{self}}; use libboard_zynq::{ println, - self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll}, + self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, sdio::sd_card::SdCard }; use libsupport_zynq; @@ -38,12 +38,17 @@ pub fn main_core0() { IoPll::setup(1_000_000_000); libboard_zynq::stdio::drop_uart(); } + #[cfg(feature = "target_cora_z7_10")] + { + IoPll::setup(1_000_000_000); + libboard_zynq::stdio::drop_uart(); + } info!("PLLs set up"); let clocks = zynq::clocks::Clocks::get(); info!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x()); let mut sd = libboard_zynq::sdio::SDIO::sdio0(); - println!("Wait for SD card inertion!"); + info!("Wait for SD card inertion!"); while !sd.is_card_inserted() {} // let result = SdCard::from_sdio(sd); // match &result { @@ -54,9 +59,9 @@ pub fn main_core0() { // sd = sd_card.to_sdio(); loop { while sd.is_card_inserted() {} - println!("SD card removed!"); + info!("SD card removed!"); while !sd.is_card_inserted() {} - println!("SD card inserted"); + info!("SD card inserted"); } } diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 5ef2c2b..59e8394 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -7,12 +7,12 @@ use super::time::Milliseconds; use super::clocks::Clocks; use embedded_hal::timer::CountDown; use libregister::{RegisterR, RegisterRW, RegisterW}; -use super::println; +use log::debug; use nb; macro_rules! print_field_addr { ($self: expr, $name: ident) => - (println!("Addr {:p}: {}", &$self.$name, stringify!($name));) + (debug!("Addr {:p}: {}", &$self.$name, stringify!($name));) } /// Basic SDIO Struct with common low-level functions. @@ -92,7 +92,7 @@ impl SDIO { slcr.sdio_clk_ctrl.enable_sdio0(); }); let clocks = Clocks::get(); - println!("Ref Clk: {}", clocks.sdio_ref_clk()); + debug!("Ref Clk: {}", clocks.sdio_ref_clk()); let mut self_ = SDIO { regs: regs::RegisterBlock::sdio0(), count_down: super::timer::GlobalTimer::start().countdown(), @@ -122,7 +122,7 @@ impl SDIO { } div_cnt <<= 1; } - println!("{}", div_cnt); + debug!("{}", div_cnt); if div_cnt > XSDPS_CC_MAX_DIV_CNT { panic!("No valid divisor!"); } @@ -203,7 +203,7 @@ impl SDIO { } else { regs::BusVoltage::V0 }; - println!("{:?}", voltage); + debug!("{:?}", voltage); self.regs.control.modify(|_, w| w.bus_voltage(voltage)); // enable all interrupt status except card interrupt @@ -237,7 +237,7 @@ impl SDIO { arg: u32, block_cnt: u16, ) -> Result<(), CmdTransferError> { - println!("Send {:?}", cmd); + debug!("Send {:?}", cmd); let state = self.regs.present_state.read(); if state.command_inhibit_cmd() { return Err(CmdTransferError::CmdInhibited); diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 5505950..164d543 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -1,7 +1,7 @@ use super::cmd; use super::{SDIO, CmdTransferError, CardType}; use libregister::{RegisterR, RegisterRW}; -use super::super::println; +use log::debug; #[derive(Debug)] pub enum CardInitializationError { @@ -159,7 +159,7 @@ impl SdCard { // clear interrupt status self.sdio.regs.interrupt_status.modify(|_, w| w.buffer_read_ready()); buffer[i] = self.sdio.regs.buffer.read(); - println!("Read {}", buffer[i]); + debug!("Read {}", buffer[i]); } // wait for transfer complete interrupt while !self.sdio.regs.interrupt_status.read().transfer_complete() {} diff --git a/libboard_zynq/src/slcr.rs b/libboard_zynq/src/slcr.rs index b2fa276..8204926 100644 --- a/libboard_zynq/src/slcr.rs +++ b/libboard_zynq/src/slcr.rs @@ -441,12 +441,12 @@ register_bits_typed!(sdio_clk_ctrl, srcsel, u8, PllSource, 4, 5); impl SdioClkCtrl { pub fn enable_sdio0(&mut self) { self.modify(|_, w| { - w.divisor(0x1E).srcsel(PllSource::IoPll).clkact0(true) + w.divisor(0x14).srcsel(PllSource::IoPll).clkact0(true) }) } pub fn enable_sdio1(&mut self) { self.modify(|_, w| { - w.divisor(0x1E).srcsel(PllSource::IoPll).clkact1(true) + w.divisor(0x14).srcsel(PllSource::IoPll).clkact1(true) }) } } -- 2.42.0 From d194fd93f66015b619637ae3aa7a22072355b376 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Sat, 16 May 2020 17:19:02 +0800 Subject: [PATCH 15/34] Modified configurations, removed print addr. --- libboard_zynq/src/sdio/mod.rs | 43 ++++++----------------------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 59e8394..aea3a07 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -44,48 +44,46 @@ impl SDIO { pub fn sdio0() -> Self { // initialization according to ps7_init.c slcr::RegisterBlock::unlocked(|slcr| { - print_field_addr!(slcr, mio_pin_40); - print_field_addr!(slcr, mio_pin_41); - print_field_addr!(slcr, mio_pin_42); - print_field_addr!(slcr, mio_pin_43); - print_field_addr!(slcr, mio_pin_44); - print_field_addr!(slcr, mio_pin_45); - print_field_addr!(slcr, mio_pin_47); - print_field_addr!(slcr, sdio_clk_ctrl); - print_field_addr!(slcr, sdio_rst_ctrl); slcr.mio_pin_40.write( slcr::MioPin40::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) + .speed(true) ); slcr.mio_pin_41.write( slcr::MioPin41::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) + .speed(true) ); slcr.mio_pin_42.write( slcr::MioPin42::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) + .speed(true) ); slcr.mio_pin_43.write( slcr::MioPin43::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) + .speed(true) ); slcr.mio_pin_44.write( slcr::MioPin44::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) + .speed(true) ); slcr.mio_pin_45.write( slcr::MioPin45::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) + .speed(true) ); slcr.mio_pin_47.write( slcr::MioPin47::zeroed() .io_type(slcr::IoBufferType::Lvcmos18) + .speed(true) ); slcr.sdio_rst_ctrl.reset_sdio0(); slcr.aper_clk_ctrl.enable_sdio0(); @@ -136,35 +134,8 @@ impl SDIO { self.regs.clock_control.modify(|_, w| w.sd_clk_en(true)); } - - fn print_registers(&self) { - print_field_addr!(self.regs, sdma_system_address); - print_field_addr!(self.regs, block_size_block_count); - print_field_addr!(self.regs, argument); - print_field_addr!(self.regs, transfer_mode_command); - print_field_addr!(self.regs, responses); - print_field_addr!(self.regs, buffer); - print_field_addr!(self.regs, present_state); - print_field_addr!(self.regs, control); - print_field_addr!(self.regs, clock_control); - print_field_addr!(self.regs, interrupt_status); - print_field_addr!(self.regs, interrupt_status_en); - print_field_addr!(self.regs, interrupt_signal_en); - print_field_addr!(self.regs, auto_cmd12_error_status); - print_field_addr!(self.regs, capabilities); - print_field_addr!(self.regs, max_current_capabilities); - print_field_addr!(self.regs, force_event); - print_field_addr!(self.regs, adma_error_status); - print_field_addr!(self.regs, adma_system_address); - print_field_addr!(self.regs, boot_data_timeout_counter); - print_field_addr!(self.regs, debug_selection); - print_field_addr!(self.regs, spi_interrupt_support); - print_field_addr!(self.regs, misc_reg); - } - /// Initialization based on XSdPs_CfgInitialize function in xsdps.c fn init(&mut self) { - self.print_registers(); // poweroff self.regs .control -- 2.42.0 From 7262dea0a515d0be6a99c1d3761900bb22675b1e Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 18 May 2020 17:01:32 +0800 Subject: [PATCH 16/34] command transfer working --- experiments/src/main.rs | 18 ++++---- libboard_zynq/src/sdio/cmd.rs | 69 ++++++++++++++++--------------- libboard_zynq/src/sdio/mod.rs | 11 ++--- libboard_zynq/src/sdio/sd_card.rs | 2 +- 4 files changed, 51 insertions(+), 49 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index b1ff36d..34e9828 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -47,16 +47,16 @@ pub fn main_core0() { let clocks = zynq::clocks::Clocks::get(); info!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x()); - let mut sd = libboard_zynq::sdio::SDIO::sdio0(); + let mut sd = libboard_zynq::sdio::SDIO::sdio0(false); info!("Wait for SD card inertion!"); - while !sd.is_card_inserted() {} - // let result = SdCard::from_sdio(sd); - // match &result { - // Ok(_) => (), - // Err(a) => println!("{:?}", a), - // }; - // let sd_card = result.unwrap(); - // sd = sd_card.to_sdio(); + // while !sd.is_card_inserted() {} + let result = SdCard::from_sdio(sd); + match &result { + Ok(_) => (), + Err(a) => println!("{:?}", a), + }; + let sd_card = result.unwrap(); + sd = sd_card.to_sdio(); loop { while sd.is_card_inserted() {} info!("SD card removed!"); diff --git a/libboard_zynq/src/sdio/cmd.rs b/libboard_zynq/src/sdio/cmd.rs index d527822..5809c60 100644 --- a/libboard_zynq/src/sdio/cmd.rs +++ b/libboard_zynq/src/sdio/cmd.rs @@ -1,6 +1,7 @@ use super::regs; +use log::debug; -const APP_CMD_PREFIX: u32 = 0x8000; +const APP_CMD_PREFIX: u8 = 0x80; #[allow(unused)] pub mod args { pub const CMD8_VOL_PATTERN: u32 = 0x1AA; @@ -12,40 +13,40 @@ pub mod args { } #[allow(unused)] -#[repr(u32)] +#[repr(u8)] #[derive(Copy, Clone, PartialEq, Debug)] pub enum SdCmd { - CMD0 = 0x0000, - CMD1 = 0x0100, - CMD2 = 0x0200, - CMD3 = 0x0300, - CMD4 = 0x0400, - CMD5 = 0x0500, - CMD6 = 0x0600, - ACMD6 = APP_CMD_PREFIX + 0x0600, - CMD7 = 0x0700, - CMD8 = 0x0800, - CMD9 = 0x0900, - CMD10 = 0x0A00, - CMD11 = 0x0B00, - CMD12 = 0x0C00, - ACMD13 = APP_CMD_PREFIX + 0x0D00, - CMD16 = 0x1000, - CMD17 = 0x1100, - CMD18 = 0x1200, - CMD19 = 0x1300, - CMD21 = 0x1500, - CMD23 = 0x1700, - ACMD23 = APP_CMD_PREFIX + 0x1700, - CMD24 = 0x1800, - CMD25 = 0x1900, - CMD41 = 0x2900, - ACMD41 = APP_CMD_PREFIX + 0x2900, - ACMD42 = APP_CMD_PREFIX + 0x2A00, - ACMD51 = APP_CMD_PREFIX + 0x3300, - CMD52 = 0x3400, - CMD55 = 0x3700, - CMD58 = 0x3A00, + CMD0 = 0x00, + CMD1 = 0x01, + CMD2 = 0x02, + CMD3 = 0x03, + CMD4 = 0x04, + CMD5 = 0x05, + CMD6 = 0x06, + ACMD6 = APP_CMD_PREFIX + 0x06, + CMD7 = 0x07, + CMD8 = 0x08, + CMD9 = 0x09, + CMD10 = 0x0A, + CMD11 = 0x0B, + CMD12 = 0x0C, + ACMD13 = APP_CMD_PREFIX + 0x0D, + CMD16 = 0x10, + CMD17 = 0x11, + CMD18 = 0x12, + CMD19 = 0x13, + CMD21 = 0x15, + CMD23 = 0x17, + ACMD23 = APP_CMD_PREFIX + 0x17, + CMD24 = 0x18, + CMD25 = 0x19, + CMD41 = 0x29, + ACMD41 = APP_CMD_PREFIX + 0x29, + ACMD42 = APP_CMD_PREFIX + 0x2A, + ACMD51 = APP_CMD_PREFIX + 0x33, + CMD52 = 0x34, + CMD55 = 0x37, + CMD58 = 0x3A, } pub fn require_dat(cmd: SdCmd, is_sd_card: bool) -> bool { @@ -89,7 +90,7 @@ fn resp_r6(w: CmdReg) -> CmdReg { pub fn set_cmd_reg(cmd: SdCmd, is_sd_card: bool, w: CmdReg) -> CmdReg { use SdCmd::*; - let w = w.command_index(cmd as u8); + let w = w.command_index(cmd as u8 & 0x3F); match cmd { CMD1 => resp_r3(w), CMD2 => resp_r2(w), diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index aea3a07..524baf9 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -21,6 +21,7 @@ pub struct SDIO { count_down: super::timer::global::CountDown, input_clk_hz: u32, card_type: CardType, + card_detect: bool, } #[derive(Debug)] @@ -41,7 +42,7 @@ pub enum CardType { impl SDIO { #[cfg(feature = "target_cora_z7_10")] /// Initialize SDIO0 for Cora Z7 10 - pub fn sdio0() -> Self { + pub fn sdio0(card_detect: bool) -> Self { // initialization according to ps7_init.c slcr::RegisterBlock::unlocked(|slcr| { slcr.mio_pin_40.write( @@ -95,7 +96,8 @@ impl SDIO { regs: regs::RegisterBlock::sdio0(), count_down: super::timer::GlobalTimer::start().countdown(), input_clk_hz: clocks.sdio_ref_clk(), - card_type: CardType::CardNone + card_type: CardType::CardNone, + card_detect }; self_.init(); self_ @@ -208,7 +210,6 @@ impl SDIO { arg: u32, block_cnt: u16, ) -> Result<(), CmdTransferError> { - debug!("Send {:?}", cmd); let state = self.regs.present_state.read(); if state.command_inhibit_cmd() { return Err(CmdTransferError::CmdInhibited); @@ -239,7 +240,7 @@ impl SDIO { // Set the command registers. self.regs .transfer_mode_command - .modify(|_, w| cmd::set_cmd_reg(cmd, is_sd_card, w)); + .write(cmd::set_cmd_reg(cmd, is_sd_card, regs::TransferModeCommand::zeroed())); // polling for response loop { @@ -280,7 +281,7 @@ impl SDIO { /// Check if card is inserted. pub fn is_card_inserted(&self) -> bool { - self.regs.present_state.read().card_inserted() + !self.card_detect || self.regs.present_state.read().card_inserted() } /// Switch voltage from 3.3V to 1.8V. diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 164d543..071ad37 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -63,7 +63,7 @@ impl SdCard { // send ACMD41 while card is still busy with power up loop { - // self.sdio.cmd_transfer(CMD55, 0, 0)?; + self.sdio.cmd_transfer(CMD55, 0, 0)?; self.sdio.cmd_transfer(ACMD41, ACMD41_HCS | ACMD41_3V3 | (0x1FF << 15), 0)?; if (self.sdio.regs.responses[0].read() & RESPOCR_READY) != 0 { -- 2.42.0 From a5f457f6d8d039da9b82cf500ba5ea28d6be0683 Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 18 May 2020 17:23:40 +0800 Subject: [PATCH 17/34] debugging read block --- experiments/src/main.rs | 6 ++++-- libboard_zynq/src/sdio/sd_card.rs | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 34e9828..49a85fd 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -52,10 +52,12 @@ pub fn main_core0() { // while !sd.is_card_inserted() {} let result = SdCard::from_sdio(sd); match &result { - Ok(_) => (), + Ok(_) => println!("OK!"), Err(a) => println!("{:?}", a), }; - let sd_card = result.unwrap(); + let mut sd_card = result.unwrap(); + sd_card.read_block().unwrap(); + info!("End"); sd = sd_card.to_sdio(); loop { while sd.is_card_inserted() {} diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 071ad37..dbb9f15 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -149,17 +149,19 @@ impl SdCard { self.sdio } - pub fn read_block(&mut self, block: u16, buffer: &mut [u32]) -> Result<(), CmdTransferError>{ + pub fn read_block(&mut self) -> Result<(), CmdTransferError>{ use cmd::SdCmd::*; - self.sdio.cmd_transfer(CMD17, 0, block)?; + self.sdio.regs.block_size_block_count.modify(|_, w| w.transfer_block_size(512)); + self.sdio.cmd_transfer(CMD17, 0, 1)?; - for i in 0..(block as usize) { + for i in 0..512 { + debug!("Waiting for buffer"); // wait for buffer read ready while !self.sdio.regs.interrupt_status.read().buffer_read_ready() {} // clear interrupt status self.sdio.regs.interrupt_status.modify(|_, w| w.buffer_read_ready()); - buffer[i] = self.sdio.regs.buffer.read(); - debug!("Read {}", buffer[i]); + let result = self.sdio.regs.buffer.read(); + debug!("Read {}", result); } // wait for transfer complete interrupt while !self.sdio.regs.interrupt_status.read().transfer_complete() {} -- 2.42.0 From 6a78d3f445157e16c37dbe97e63c3060b4728ecd Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 20 May 2020 14:11:02 +0800 Subject: [PATCH 18/34] block read write --- .script/run.sh | 2 + experiments/src/main.rs | 34 +++++-- libboard_zynq/src/sdio/mod.rs | 98 +++++++++++++------ libboard_zynq/src/sdio/sd_card.rs | 151 ++++++++++++++++++++++++++---- 4 files changed, 234 insertions(+), 51 deletions(-) create mode 100755 .script/run.sh diff --git a/.script/run.sh b/.script/run.sh new file mode 100755 index 0000000..714816d --- /dev/null +++ b/.script/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +cd experiments && cargo xbuild --release --no-default-features --features=target_cora_z7_10 && cd ../openocd && openocd -f cora-z7-10.cfg -c 'load_image ../target/armv7-none-eabihf/release/experiments; resume 0; exit' diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 49a85fd..e0e1bf3 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -3,15 +3,20 @@ extern crate alloc; -use log::info; -use libregister::RegisterR; -use libcortex_a9::{mutex::Mutex, sync_channel::{self}}; use libboard_zynq::{ + self as zynq, + clocks::source::{ArmPll, ClockSource, IoPll}, + clocks::Clocks, println, - self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, - sdio::sd_card::SdCard + sdio::sd_card::SdCard, }; +use libcortex_a9::{ + mutex::Mutex, + sync_channel::{self}, +}; +use libregister::RegisterR; use libsupport_zynq; +use log::info; mod ps7_init; @@ -23,7 +28,13 @@ pub fn main_core0() { libboard_zynq::logger::init().unwrap(); log::set_max_level(log::LevelFilter::Trace); - info!("Boot mode: {:?}", zynq::slcr::RegisterBlock::new().boot_mode.read().boot_mode_pins()); + info!( + "Boot mode: {:?}", + zynq::slcr::RegisterBlock::new() + .boot_mode + .read() + .boot_mode_pins() + ); #[cfg(feature = "target_zc706")] const CPU_FREQ: u32 = 800_000_000; @@ -45,7 +56,13 @@ pub fn main_core0() { } info!("PLLs set up"); let clocks = zynq::clocks::Clocks::get(); - info!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x()); + info!( + "CPU Clocks: {}/{}/{}/{}", + clocks.cpu_6x4x(), + clocks.cpu_3x2x(), + clocks.cpu_2x(), + clocks.cpu_1x() + ); let mut sd = libboard_zynq::sdio::SDIO::sdio0(false); info!("Wait for SD card inertion!"); @@ -56,7 +73,8 @@ pub fn main_core0() { Err(a) => println!("{:?}", a), }; let mut sd_card = result.unwrap(); - sd_card.read_block().unwrap(); + let mut buffer: [u32; 512 / 4] = [0; 512 / 4]; + sd_card.read_block(0, 1, &mut buffer).unwrap(); info!("End"); sd = sd_card.to_sdio(); loop { diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 524baf9..d80a11c 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -2,17 +2,18 @@ pub mod sd_card; mod cmd; mod regs; +use super::clocks::Clocks; use super::slcr; use super::time::Milliseconds; -use super::clocks::Clocks; use embedded_hal::timer::CountDown; use libregister::{RegisterR, RegisterRW, RegisterW}; use log::debug; use nb; macro_rules! print_field_addr { - ($self: expr, $name: ident) => - (debug!("Addr {:p}: {}", &$self.$name, stringify!($name));) + ($self: expr, $name: ident) => { + debug!("Addr {:p}: {}", &$self.$name, stringify!($name)); + }; } /// Basic SDIO Struct with common low-level functions. @@ -49,42 +50,42 @@ impl SDIO { slcr::MioPin40::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .speed(true) + .speed(true), ); slcr.mio_pin_41.write( slcr::MioPin41::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .speed(true) + .speed(true), ); slcr.mio_pin_42.write( slcr::MioPin42::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .speed(true) + .speed(true), ); slcr.mio_pin_43.write( slcr::MioPin43::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .speed(true) + .speed(true), ); slcr.mio_pin_44.write( slcr::MioPin44::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .speed(true) + .speed(true), ); slcr.mio_pin_45.write( slcr::MioPin45::zeroed() .l3_sel(0b100) .io_type(slcr::IoBufferType::Lvcmos18) - .speed(true) + .speed(true), ); slcr.mio_pin_47.write( slcr::MioPin47::zeroed() .io_type(slcr::IoBufferType::Lvcmos18) - .speed(true) + .speed(true), ); slcr.sdio_rst_ctrl.reset_sdio0(); slcr.aper_clk_ctrl.enable_sdio0(); @@ -97,7 +98,7 @@ impl SDIO { count_down: super::timer::GlobalTimer::start().countdown(), input_clk_hz: clocks.sdio_ref_clk(), card_type: CardType::CardNone, - card_detect + card_detect, }; self_.init(); self_ @@ -202,13 +203,27 @@ impl SDIO { nb::block!(self.count_down.wait()).unwrap(); } - /// Send SD command. This function would block until response is ready. + /// Send SD command. Basically `cmd_transfer_with_mode` with mode + /// `regs::TransferModeCommand::zeroed()`. /// Return: Ok if success, Err(status) if failed. fn cmd_transfer( &mut self, cmd: cmd::SdCmd, arg: u32, block_cnt: u16, + ) -> Result<(), CmdTransferError> { + self.cmd_transfer_with_mode(cmd, arg, block_cnt, regs::TransferModeCommand::zeroed()) + } + + /// Send SD Command with additional transfer mode. + /// This function would block until response is ready. + /// Return: Ok if success, Err(status) if failed. + fn cmd_transfer_with_mode( + &mut self, + cmd: cmd::SdCmd, + arg: u32, + block_cnt: u16, + transfer_mode: regs::transfer_mode_command::Write, ) -> Result<(), CmdTransferError> { let state = self.regs.present_state.read(); if state.command_inhibit_cmd() { @@ -240,7 +255,7 @@ impl SDIO { // Set the command registers. self.regs .transfer_mode_command - .write(cmd::set_cmd_reg(cmd, is_sd_card, regs::TransferModeCommand::zeroed())); + .write(cmd::set_cmd_reg(cmd, is_sd_card, transfer_mode)); // polling for response loop { @@ -252,20 +267,7 @@ impl SDIO { .modify(|_, w| w.buffer_read_ready()); break; } - } - if status.error_interrupt() { - let err_status = if status.inner & 0xFFFE0000 == 0 { - CmdTransferError::CmdTimeout - } else { - CmdTransferError::Other(regs::interrupt_status::Read { - inner: status.inner, - }) - }; - // reset all error status - self.regs - .interrupt_status - .write(regs::interrupt_status::Write { inner: 0xF3FF0000 }); - return Err(err_status); + self.check_error()?; } if status.command_complete() { break; @@ -366,4 +368,46 @@ impl SDIO { while self.regs.clock_control.read().software_reset_cmd() {} Ok(self.card_type) } + + /// Modify transfer block size. + fn set_block_size(&mut self, block_size: u16) -> Result<(), CmdTransferError> { + use cmd::SdCmd::*; + let state = self.regs.present_state.read(); + if state.command_inhibit_cmd() + || state.command_inhibit_dat() + || state.write_transfer_active() + || state.read_transfer_active() + { + return Err(CmdTransferError::CmdInhibited); + } + + // send block write command + self.cmd_transfer(CMD16, block_size as u32, 0)?; + // set block size + self.regs + .block_size_block_count + .modify(|_, w| w.transfer_block_size(block_size)); + Ok(()) + } + + /// Check if error occured, and reset the error status. + /// Return Err(CmdTransferError) if error occured, Ok(()) otherwise. + fn check_error(&mut self) -> Result<(), CmdTransferError> { + let status = self.regs.interrupt_status.read(); + if status.error_interrupt() { + let err_status = if status.inner & 0xFFFE0000 == 0 { + CmdTransferError::CmdTimeout + } else { + CmdTransferError::Other(regs::interrupt_status::Read { + inner: status.inner, + }) + }; + // reset all error status + self.regs + .interrupt_status + .write(regs::interrupt_status::Write { inner: 0xF3FF0000 }); + return Err(err_status); + } + Ok(()) + } } diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index dbb9f15..197867e 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -1,6 +1,7 @@ use super::cmd; -use super::{SDIO, CmdTransferError, CardType}; -use libregister::{RegisterR, RegisterRW}; +use super::{CardType, CmdTransferError, SDIO}; +use libcortex_a9::cache; +use libregister::{RegisterR, RegisterRW, RegisterW}; use log::debug; #[derive(Debug)] @@ -44,7 +45,8 @@ impl SdCard { match self.sdio.cmd_transfer(CMD8, CMD8_VOL_PATTERN, 0) { Err(CmdTransferError::CmdTimeout) => { // reset - self.sdio.regs + self.sdio + .regs .clock_control .modify(|_, w| w.software_reset_cmd(true)); // wait until reset is completed @@ -64,7 +66,8 @@ impl SdCard { // send ACMD41 while card is still busy with power up loop { self.sdio.cmd_transfer(CMD55, 0, 0)?; - self.sdio.cmd_transfer(ACMD41, ACMD41_HCS | ACMD41_3V3 | (0x1FF << 15), 0)?; + self.sdio + .cmd_transfer(ACMD41, ACMD41_HCS | ACMD41_3V3 | (0x1FF << 15), 0)?; if (self.sdio.regs.responses[0].read() & RESPOCR_READY) != 0 { break; @@ -139,7 +142,7 @@ impl SdCard { card_id: [0, 0, 0, 0], rel_card_addr: 0, sector_cnt: 0, - switch_1v8: false + switch_1v8: false, }; _self.sd_card_initialize()?; Ok(_self) @@ -149,23 +152,139 @@ impl SdCard { self.sdio } - pub fn read_block(&mut self) -> Result<(), CmdTransferError>{ - use cmd::SdCmd::*; - self.sdio.regs.block_size_block_count.modify(|_, w| w.transfer_block_size(512)); - self.sdio.cmd_transfer(CMD17, 0, 1)?; + pub fn read_block( + &mut self, + address: u32, + block_cnt: u16, + buffer: &mut [u32], + ) -> Result<(), CmdTransferError> { + assert!(buffer.len() >= (block_cnt as usize) * (512 / 4)); + // set block size if not set already + if self + .sdio + .regs + .block_size_block_count + .read() + .transfer_block_size() + != 512 + { + self.sdio.set_block_size(512)?; + } + // invalidate D cache, required for ZC706, not sure for Cora Z7 10 + cache::dcc_slice(buffer); - for i in 0..512 { - debug!("Waiting for buffer"); + let (cmd, mode) = if block_cnt == 1 { + ( + cmd::SdCmd::CMD17, + super::regs::TransferModeCommand::zeroed() + .block_count_en(true) + .direction_select(true), + ) + } else { + ( + cmd::SdCmd::CMD18, + super::regs::TransferModeCommand::zeroed() + .auto_cmd12_en(true) + .block_count_en(true) + .direction_select(true) + .multi_block_en(true), + ) + }; + self.sdio + .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; + + debug!("Waiting for read"); + for i in 0..(512 / 4) * block_cnt { // wait for buffer read ready - while !self.sdio.regs.interrupt_status.read().buffer_read_ready() {} - // clear interrupt status - self.sdio.regs.interrupt_status.modify(|_, w| w.buffer_read_ready()); + while !self.sdio.regs.interrupt_status.read().buffer_read_ready() { + self.sdio.check_error()?; + } let result = self.sdio.regs.buffer.read(); + buffer[i as usize] = result; debug!("Read {}", result); + // clear buffer read + self.sdio + .regs + .interrupt_status + .modify(|_, w| w.buffer_read_ready()); } // wait for transfer complete interrupt - while !self.sdio.regs.interrupt_status.read().transfer_complete() {} - self.sdio.regs.interrupt_status.modify(|_, w| w.transfer_complete()); + while !self.sdio.regs.interrupt_status.read().transfer_complete() { + // just to see if I calculate the buffer size wrongly + assert!(!self.sdio.regs.interrupt_status.read().buffer_read_ready()); + } + self.sdio + .regs + .interrupt_status + .modify(|_, w| w.transfer_complete()); + + cache::dcc_slice(buffer); + Ok(()) + } + + pub fn write_block( + &mut self, + address: u32, + block_cnt: u16, + buffer: &mut [u32], + ) -> Result<(), CmdTransferError> { + assert!(buffer.len() >= (block_cnt as usize) * (512 / 4)); + // set block size if not set already + if self + .sdio + .regs + .block_size_block_count + .read() + .transfer_block_size() + != 512 + { + self.sdio.set_block_size(512)?; + } + // invalidate D cache, required for ZC706, not sure for Cora Z7 10 + cache::dcc_slice(buffer); + + let (cmd, mode) = if block_cnt == 1 { + ( + cmd::SdCmd::CMD24, + super::regs::TransferModeCommand::zeroed().block_count_en(true), + ) + } else { + ( + cmd::SdCmd::CMD25, + super::regs::TransferModeCommand::zeroed() + .auto_cmd12_en(true) + .block_count_en(true) + .multi_block_en(true), + ) + }; + self.sdio + .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; + debug!("Waiting for write"); + for i in 0..(512 / 4) * block_cnt { + // wait for buffer write ready + while !self.sdio.regs.interrupt_status.read().buffer_write_ready() { + self.sdio.check_error()?; + } + unsafe { + self.sdio.regs.buffer.write(buffer[i as usize]); + } + // clear buffer write + self.sdio + .regs + .interrupt_status + .modify(|_, w| w.buffer_write_ready()); + } + // wait for transfer complete interrupt + while !self.sdio.regs.interrupt_status.read().transfer_complete() { + // just to see if I calculate the buffer size wrongly + assert!(!self.sdio.regs.interrupt_status.read().buffer_write_ready()); + } + self.sdio + .regs + .interrupt_status + .modify(|_, w| w.transfer_complete()); + + cache::dcc_slice(buffer); Ok(()) } } -- 2.42.0 From ed2ac1ff009fbeb45e0993fc2d201e7f937bf73c Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 20 May 2020 14:33:20 +0800 Subject: [PATCH 19/34] modified check error --- .script/run.sh | 2 +- libboard_zynq/src/sdio/mod.rs | 9 ++++++--- libboard_zynq/src/sdio/sd_card.rs | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.script/run.sh b/.script/run.sh index 714816d..3e5d29d 100755 --- a/.script/run.sh +++ b/.script/run.sh @@ -1,2 +1,2 @@ #!/usr/bin/env sh -cd experiments && cargo xbuild --release --no-default-features --features=target_cora_z7_10 && cd ../openocd && openocd -f cora-z7-10.cfg -c 'load_image ../target/armv7-none-eabihf/release/experiments; resume 0; exit' +cd experiments && cargo xbuild --release --no-default-features --features=target_cora_z7_10 && cd ../openocd && openocd -f cora-z7-10.cfg -c 'reset; load_image ../target/armv7-none-eabihf/release/experiments; resume 0; exit' diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index d80a11c..0e56f08 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -225,6 +225,7 @@ impl SDIO { block_cnt: u16, transfer_mode: regs::transfer_mode_command::Write, ) -> Result<(), CmdTransferError> { + debug!("Send Cmd {:?}", cmd); let state = self.regs.present_state.read(); if state.command_inhibit_cmd() { return Err(CmdTransferError::CmdInhibited); @@ -267,7 +268,7 @@ impl SDIO { .modify(|_, w| w.buffer_read_ready()); break; } - self.check_error()?; + self.check_error(&status)?; } if status.command_complete() { break; @@ -392,8 +393,10 @@ impl SDIO { /// Check if error occured, and reset the error status. /// Return Err(CmdTransferError) if error occured, Ok(()) otherwise. - fn check_error(&mut self) -> Result<(), CmdTransferError> { - let status = self.regs.interrupt_status.read(); + fn check_error( + &mut self, + status: ®s::interrupt_status::Read, + ) -> Result<(), CmdTransferError> { if status.error_interrupt() { let err_status = if status.inner & 0xFFFE0000 == 0 { CmdTransferError::CmdTimeout diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 197867e..37517f9 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -196,8 +196,12 @@ impl SdCard { debug!("Waiting for read"); for i in 0..(512 / 4) * block_cnt { // wait for buffer read ready - while !self.sdio.regs.interrupt_status.read().buffer_read_ready() { - self.sdio.check_error()?; + loop { + let status = self.sdio.regs.interrupt_status.read(); + if status.buffer_read_ready() { + break; + } + self.sdio.check_error(&status)?; } let result = self.sdio.regs.buffer.read(); buffer[i as usize] = result; @@ -262,8 +266,12 @@ impl SdCard { debug!("Waiting for write"); for i in 0..(512 / 4) * block_cnt { // wait for buffer write ready - while !self.sdio.regs.interrupt_status.read().buffer_write_ready() { - self.sdio.check_error()?; + loop { + let status = self.sdio.regs.interrupt_status.read(); + if status.buffer_write_ready() { + break; + } + self.sdio.check_error(&status)?; } unsafe { self.sdio.regs.buffer.write(buffer[i as usize]); -- 2.42.0 From bd3cb7a889b564eaf0b0182d576b0a5e5428df7e Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 20 May 2020 14:46:48 +0800 Subject: [PATCH 20/34] removed .script --- .script/run.sh | 2 -- 1 file changed, 2 deletions(-) delete mode 100755 .script/run.sh diff --git a/.script/run.sh b/.script/run.sh deleted file mode 100755 index 3e5d29d..0000000 --- a/.script/run.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env sh -cd experiments && cargo xbuild --release --no-default-features --features=target_cora_z7_10 && cd ../openocd && openocd -f cora-z7-10.cfg -c 'reset; load_image ../target/armv7-none-eabihf/release/experiments; resume 0; exit' -- 2.42.0 From e5672e295c56c3ca1fe290b19d460b97e5d61b6a Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 21 May 2020 13:58:59 +0800 Subject: [PATCH 21/34] Fixed wrong error check --- libboard_zynq/src/sdio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 0e56f08..27ae50a 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -268,11 +268,11 @@ impl SDIO { .modify(|_, w| w.buffer_read_ready()); break; } - self.check_error(&status)?; } if status.command_complete() { break; } + self.check_error(&status)?; } // wait for command complete while !self.regs.interrupt_status.read().command_complete() {} -- 2.42.0 From 1e170918875d009f90081599104bb6e5c98586d6 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 21 May 2020 16:46:58 +0800 Subject: [PATCH 22/34] Read/Write not yet working. --- experiments/src/main.rs | 2 +- libboard_zynq/src/sdio/mod.rs | 1 - libboard_zynq/src/sdio/regs.rs | 2 +- libboard_zynq/src/sdio/sd_card.rs | 6 ++++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index e0e1bf3..2273cb0 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -74,7 +74,7 @@ pub fn main_core0() { }; let mut sd_card = result.unwrap(); let mut buffer: [u32; 512 / 4] = [0; 512 / 4]; - sd_card.read_block(0, 1, &mut buffer).unwrap(); + sd_card.read_block(1, 1, &mut buffer).unwrap(); info!("End"); sd = sd_card.to_sdio(); loop { diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 27ae50a..9829175 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -123,7 +123,6 @@ impl SDIO { } div_cnt <<= 1; } - debug!("{}", div_cnt); if div_cnt > XSDPS_CC_MAX_DIV_CNT { panic!("No valid divisor!"); } diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index f30bd21..5af14a2 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -543,6 +543,6 @@ register_bits!( impl fmt::Debug for interrupt_status::Read { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_fmt(format_args!("status: {}", self.inner)) + fmt.write_fmt(format_args!("status: {:0X}", self.inner)) } } diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 37517f9..4e731aa 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -98,6 +98,7 @@ impl SdCard { let mut csd: [u32; 4] = [0, 0, 0, 0]; for i in 0..=3 { csd[i] = self.sdio.regs.responses[i].read(); + debug!("CSD[{}] = {:0X}", i, csd[i]); } const CSD_STRUCT_MSK: u32 = 0x00C00000; @@ -127,6 +128,11 @@ impl SdCard { self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; self.sdio.cmd_transfer(ACMD6, 2, 0)?; + // pull up + self.sdio.set_block_size(512)?; + self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; + self.sdio.cmd_transfer(ACMD42, 0, 0)?; + Ok(()) } -- 2.42.0 From 974d4be30fe62dcb79de1cf470f58936a9beadbc Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 3 Jun 2020 14:37:44 +0800 Subject: [PATCH 23/34] testing ADMA2 --- experiments/src/main.rs | 15 +++- libboard_zynq/src/sdio/adma.rs | 109 ++++++++++++++++++++++++++++++ libboard_zynq/src/sdio/mod.rs | 5 +- libboard_zynq/src/sdio/regs.rs | 4 +- libboard_zynq/src/sdio/sd_card.rs | 69 +++++++------------ 5 files changed, 150 insertions(+), 52 deletions(-) create mode 100644 libboard_zynq/src/sdio/adma.rs diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 2273cb0..1c63208 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -12,7 +12,7 @@ use libboard_zynq::{ }; use libcortex_a9::{ mutex::Mutex, - sync_channel::{self}, + sync_channel::self, }; use libregister::RegisterR; use libsupport_zynq; @@ -20,6 +20,12 @@ use log::info; mod ps7_init; +#[repr(align(8))] +struct SdBuffer { + padding: u8, + buffer: [u32; 512/4] +} + #[no_mangle] pub fn main_core0() { // zynq::clocks::CpuClocks::enable_io(1_250_000_000); @@ -73,8 +79,11 @@ pub fn main_core0() { Err(a) => println!("{:?}", a), }; let mut sd_card = result.unwrap(); - let mut buffer: [u32; 512 / 4] = [0; 512 / 4]; - sd_card.read_block(1, 1, &mut buffer).unwrap(); + let mut buffer = [1; 512 / 4]; + sd_card.write_block(1, 1, &mut buffer).unwrap(); + // for i in 0..buffer.len() { + // info!("buffer[{}] = {}", i, buffer[i]); + // } info!("End"); sd = sd_card.to_sdio(); loop { diff --git a/libboard_zynq/src/sdio/adma.rs b/libboard_zynq/src/sdio/adma.rs new file mode 100644 index 0000000..7f7a930 --- /dev/null +++ b/libboard_zynq/src/sdio/adma.rs @@ -0,0 +1,109 @@ +/// ADMA library +use super::SDIO; +use libcortex_a9::cache; +use libregister::{RegisterR, RegisterW, RegisterRW}; +use log::debug; + +#[repr(C, packed)] +#[derive(Clone, Copy)] +pub struct Adma2Desc32 { + attribute: u16, + length: u16, + address: u32, +} + +// Default::default() cannot be used as it is not a constant function... +static mut ADMA2_DESCR32_TABLE: [Adma2Desc32; 32] = [ + Adma2Desc32 { + attribute: 0, + length: 0, + address: 0, + }; 32]; + +#[allow(unused)] +const DESC_MAX_LENGTH: u32 = 65536; +#[allow(unused)] +const DESC_TRANS: u16 = 0x2 << 4; +#[allow(unused)] +const DESC_INT: u16 = 0x1 << 2; +#[allow(unused)] +const DESC_END: u16 = 0x1 << 1; +#[allow(unused)] +const DESC_VALID: u16 = 0x1 << 0; + +impl Adma2Desc32 { + pub fn set_attribute(&mut self, attribute: u16) { + unsafe { + core::ptr::write_volatile(&mut self.attribute as *mut u16, attribute); + } + } + + pub fn get_attribute(&mut self) -> u16 { + unsafe { + core::ptr::read_volatile(&mut self.attribute as *mut u16) + } + } + + pub fn set_length(&mut self, length: u16) { + unsafe { + core::ptr::write_volatile(&mut self.length as *mut u16, length); + } + } + + pub fn get_length(&mut self) -> u16 { + unsafe { + core::ptr::read_volatile(&mut self.length as *mut u16) + } + } + + pub fn set_address(&mut self, address: u32) { + unsafe { + core::ptr::write_volatile(&mut self.address as *mut u32, address); + } + } + + pub fn get_address(&mut self) -> u32{ + unsafe { + core::ptr::read_volatile(&mut self.address as *mut u32) + } + } +} + +pub fn setup_adma2_descr32(sdio: &mut SDIO, blk_cnt: u32, buffer: &mut [u32]) { + let mut descr_table = unsafe { &mut ADMA2_DESCR32_TABLE }; + let blk_size = sdio.regs.block_size_block_count.read().transfer_block_size() as u32; + + let total_desc_lines = if blk_size * blk_cnt < DESC_MAX_LENGTH { + 1 + } else { + blk_size * blk_cnt / DESC_MAX_LENGTH + + if (blk_size * blk_cnt) % DESC_MAX_LENGTH == 0 { + 0 + } else { + 1 + } + } as usize; + + let ptr = buffer.as_ptr() as u32; + debug!("Buffer address: {:0X}", ptr); + debug!("Table address: {:0X}", descr_table.as_ptr() as u64); + for desc_num in 0..total_desc_lines { + descr_table[desc_num].set_address(ptr + (desc_num as u32) * DESC_MAX_LENGTH); + descr_table[desc_num].set_attribute(DESC_TRANS | DESC_VALID); + // 0 is the max length (65536) + descr_table[desc_num].set_length(0); + } + descr_table[total_desc_lines - 1].set_attribute(DESC_TRANS | DESC_VALID | DESC_END); + descr_table[total_desc_lines - 1].set_length((blk_cnt * blk_size + -((total_desc_lines as u32) - 1) * DESC_MAX_LENGTH) as u16); + debug!("Desc line address: {:0X}", descr_table[total_desc_lines - 1].get_address()); + unsafe { + let memory = core::mem::transmute::<&mut Adma2Desc32, *mut u64>(&mut descr_table[0]); + debug!("Desc line content: {:0X}", core::ptr::read_volatile(memory)); + } + unsafe { + sdio.regs.adma_system_address.write(descr_table.as_ptr() as u32); + } + cache::dcc_slice(descr_table); +} + diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 9829175..f6cc728 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -2,6 +2,7 @@ pub mod sd_card; mod cmd; mod regs; +mod adma; use super::clocks::Clocks; use super::slcr; use super::time::Milliseconds; @@ -18,7 +19,7 @@ macro_rules! print_field_addr { /// Basic SDIO Struct with common low-level functions. pub struct SDIO { - pub regs: &'static mut regs::RegisterBlock, + regs: &'static mut regs::RegisterBlock, count_down: super::timer::global::CountDown, input_clk_hz: u32, card_type: CardType, @@ -179,6 +180,8 @@ impl SDIO { debug!("{:?}", voltage); self.regs.control.modify(|_, w| w.bus_voltage(voltage)); + self.regs.control.modify(|_, w| w.dma_select(regs::DmaSelect::ADMA2_32)); + // enable all interrupt status except card interrupt self.regs.interrupt_status_en.write( (regs::interrupt_status_en::Write { inner: 0xFFFFFFFF }) diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index 5af14a2..ee963ec 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -73,8 +73,8 @@ pub enum BusVoltage { pub enum DmaSelect { SDMA = 0b00, ADMA1 = 0b01, - ADMA2 = 0b10, - ADMA3 = 0b11, + ADMA2_32 = 0b10, + ADMA2_64 = 0b11, } #[allow(unused)] diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 4e731aa..db3c8fc 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -1,5 +1,4 @@ -use super::cmd; -use super::{CardType, CmdTransferError, SDIO}; +use super::{cmd, CardType, CmdTransferError, SDIO, adma::setup_adma2_descr32}; use libcortex_a9::cache; use libregister::{RegisterR, RegisterRW, RegisterW}; use log::debug; @@ -176,6 +175,8 @@ impl SdCard { { self.sdio.set_block_size(512)?; } + + setup_adma2_descr32(&mut self.sdio, block_cnt as u32, buffer); // invalidate D cache, required for ZC706, not sure for Cora Z7 10 cache::dcc_slice(buffer); @@ -184,7 +185,8 @@ impl SdCard { cmd::SdCmd::CMD17, super::regs::TransferModeCommand::zeroed() .block_count_en(true) - .direction_select(true), + .direction_select(true) + .dma_en(true), ) } else { ( @@ -193,35 +195,20 @@ impl SdCard { .auto_cmd12_en(true) .block_count_en(true) .direction_select(true) - .multi_block_en(true), + .multi_block_en(true) + .dma_en(true), ) }; self.sdio .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; debug!("Waiting for read"); - for i in 0..(512 / 4) * block_cnt { - // wait for buffer read ready - loop { - let status = self.sdio.regs.interrupt_status.read(); - if status.buffer_read_ready() { - break; - } - self.sdio.check_error(&status)?; - } - let result = self.sdio.regs.buffer.read(); - buffer[i as usize] = result; - debug!("Read {}", result); - // clear buffer read - self.sdio - .regs - .interrupt_status - .modify(|_, w| w.buffer_read_ready()); - } // wait for transfer complete interrupt - while !self.sdio.regs.interrupt_status.read().transfer_complete() { - // just to see if I calculate the buffer size wrongly - assert!(!self.sdio.regs.interrupt_status.read().buffer_read_ready()); + let mut status = self.sdio.regs.interrupt_status.read(); + self.sdio.check_error(&status)?; + while !status.transfer_complete() { + status = self.sdio.regs.interrupt_status.read(); + self.sdio.check_error(&status)?; } self.sdio .regs @@ -229,6 +216,9 @@ impl SdCard { .modify(|_, w| w.transfer_complete()); cache::dcc_slice(buffer); + debug!("ADMA Error Status: {:0X}", self.sdio.regs.adma_error_status.read().inner); + debug!("ADMA System Address: {:0X}", self.sdio.regs.adma_system_address.read()); + debug!("SDIO Status: {:0X}", self.sdio.regs.interrupt_status.read().inner); Ok(()) } @@ -250,6 +240,8 @@ impl SdCard { { self.sdio.set_block_size(512)?; } + + setup_adma2_descr32(&mut self.sdio, block_cnt as u32, buffer); // invalidate D cache, required for ZC706, not sure for Cora Z7 10 cache::dcc_slice(buffer); @@ -264,35 +256,20 @@ impl SdCard { super::regs::TransferModeCommand::zeroed() .auto_cmd12_en(true) .block_count_en(true) - .multi_block_en(true), + .multi_block_en(true) + .dma_en(true), ) }; + assert!(!self.sdio.regs.interrupt_status.read().transfer_complete()); self.sdio .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; debug!("Waiting for write"); - for i in 0..(512 / 4) * block_cnt { - // wait for buffer write ready - loop { - let status = self.sdio.regs.interrupt_status.read(); - if status.buffer_write_ready() { - break; - } - self.sdio.check_error(&status)?; - } - unsafe { - self.sdio.regs.buffer.write(buffer[i as usize]); - } - // clear buffer write - self.sdio - .regs - .interrupt_status - .modify(|_, w| w.buffer_write_ready()); - } // wait for transfer complete interrupt while !self.sdio.regs.interrupt_status.read().transfer_complete() { - // just to see if I calculate the buffer size wrongly - assert!(!self.sdio.regs.interrupt_status.read().buffer_write_ready()); + let status = self.sdio.regs.interrupt_status.read(); + self.sdio.check_error(&status)?; } + debug!("ADMA Error Status: {:?}", self.sdio.regs.adma_error_status.read().inner); self.sdio .regs .interrupt_status -- 2.42.0 From 42fcce74d242c8dd6213b7843504be3810ebaecb Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 3 Jun 2020 14:43:09 +0800 Subject: [PATCH 24/34] testing weird behavior... --- experiments/src/main.rs | 2 +- libboard_zynq/src/sdio/sd_card.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 1c63208..7b17671 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -80,7 +80,7 @@ pub fn main_core0() { }; let mut sd_card = result.unwrap(); let mut buffer = [1; 512 / 4]; - sd_card.write_block(1, 1, &mut buffer).unwrap(); + sd_card.read_block(1, 1, &mut buffer).unwrap(); // for i in 0..buffer.len() { // info!("buffer[{}] = {}", i, buffer[i]); // } diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index db3c8fc..c3fc7f5 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -199,6 +199,7 @@ impl SdCard { .dma_en(true), ) }; + assert!(!self.sdio.regs.interrupt_status.read().transfer_complete()); self.sdio .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; @@ -248,7 +249,7 @@ impl SdCard { let (cmd, mode) = if block_cnt == 1 { ( cmd::SdCmd::CMD24, - super::regs::TransferModeCommand::zeroed().block_count_en(true), + super::regs::TransferModeCommand::zeroed().block_count_en(true).dma_en(true), ) } else { ( -- 2.42.0 From 8bd88f55a0595f76239308a5295d03b597cade63 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 3 Jun 2020 16:33:53 +0800 Subject: [PATCH 25/34] Added logs, fixed transfer complete problem. Still CRC error. --- experiments/src/main.rs | 2 +- libboard_zynq/src/sdio/mod.rs | 9 ++++++++- libboard_zynq/src/sdio/sd_card.rs | 25 +++++++++++++++---------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 7b17671..335ad0b 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -79,7 +79,7 @@ pub fn main_core0() { Err(a) => println!("{:?}", a), }; let mut sd_card = result.unwrap(); - let mut buffer = [1; 512 / 4]; + let mut buffer = [5; 512 / 4]; sd_card.read_block(1, 1, &mut buffer).unwrap(); // for i in 0..buffer.len() { // info!("buffer[{}] = {}", i, buffer[i]); diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index f6cc728..7b22ef5 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -109,6 +109,7 @@ impl SDIO { /// From XSdPs_Change_ClkFreq in xsdps_options.c. SPEC_V3 related code is removed as /// our board would only be V1 or V2. fn change_clk_freq(&mut self, freq: u32) { + debug!("Change clock frequency to {}", freq); self.regs .clock_control .modify(|_, w| w.sd_clk_en(false).internal_clk_en(false)); @@ -155,12 +156,14 @@ impl SDIO { self.delay(1); // reset all + debug!("Reset SDIO!"); self.regs .clock_control .modify(|_, w| w.software_reset_all(true)); while self.regs.clock_control.read().software_reset_all() {} // set power to 3.3V + debug!("Set power to 3.3V"); self.regs .control .modify(|_, w| w.bus_voltage(regs::BusVoltage::V33).bus_power(true)); @@ -177,17 +180,20 @@ impl SDIO { } else { regs::BusVoltage::V0 }; - debug!("{:?}", voltage); + debug!("Set voltage to {:?}", voltage); self.regs.control.modify(|_, w| w.bus_voltage(voltage)); + debug!("Select DMA2 32Bit"); self.regs.control.modify(|_, w| w.dma_select(regs::DmaSelect::ADMA2_32)); // enable all interrupt status except card interrupt + debug!("Enable interrupt status."); self.regs.interrupt_status_en.write( (regs::interrupt_status_en::Write { inner: 0xFFFFFFFF }) .card_interrupt_status_en(false), ); + debug!("Debug interrupt signals."); // disable all interrupt signals self.regs .interrupt_signal_en @@ -384,6 +390,7 @@ impl SDIO { return Err(CmdTransferError::CmdInhibited); } + debug!("Set block size to {}", block_size); // send block write command self.cmd_transfer(CMD16, block_size as u32, 0)?; // set block size diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index c3fc7f5..b3a52e8 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -38,7 +38,6 @@ impl SdCard { if !self.sdio.is_card_inserted() { return Err(CardInitializationError::NoCardInserted); } - // CMD0 self.sdio.cmd_transfer(CMD0, 0, 0)?; match self.sdio.cmd_transfer(CMD8, CMD8_VOL_PATTERN, 0) { @@ -93,6 +92,7 @@ impl SdCard { } self.sdio.cmd_transfer(CMD9, self.rel_card_addr, 0)?; + self.sdio.regs.interrupt_status.modify(|_, w| w.transfer_complete()); let mut csd: [u32; 4] = [0, 0, 0, 0]; for i in 0..=3 { @@ -121,6 +121,7 @@ impl SdCard { return Err(CardInitializationError::InitializationFailedOther); } + // CMD7: select card self.sdio.cmd_transfer(CMD7, self.rel_card_addr, 0)?; // ACMD6: set bus width @@ -129,8 +130,8 @@ impl SdCard { // pull up self.sdio.set_block_size(512)?; - self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; - self.sdio.cmd_transfer(ACMD42, 0, 0)?; + // self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; + // self.sdio.cmd_transfer(ACMD42, 0, 0)?; Ok(()) } @@ -176,8 +177,10 @@ impl SdCard { self.sdio.set_block_size(512)?; } + debug!("Set up ADMA descriptor table"); setup_adma2_descr32(&mut self.sdio, block_cnt as u32, buffer); // invalidate D cache, required for ZC706, not sure for Cora Z7 10 + debug!("Invalidate D cache for buffer"); cache::dcc_slice(buffer); let (cmd, mode) = if block_cnt == 1 { @@ -199,11 +202,11 @@ impl SdCard { .dma_en(true), ) }; - assert!(!self.sdio.regs.interrupt_status.read().transfer_complete()); + self.sdio .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; - debug!("Waiting for read"); + debug!("Waiting for read. (Transfer complete = 1)"); // wait for transfer complete interrupt let mut status = self.sdio.regs.interrupt_status.read(); self.sdio.check_error(&status)?; @@ -211,14 +214,14 @@ impl SdCard { status = self.sdio.regs.interrupt_status.read(); self.sdio.check_error(&status)?; } + debug!("Reset transfer complete."); self.sdio .regs .interrupt_status .modify(|_, w| w.transfer_complete()); + debug!("Flush buffer D cache"); cache::dcc_slice(buffer); - debug!("ADMA Error Status: {:0X}", self.sdio.regs.adma_error_status.read().inner); - debug!("ADMA System Address: {:0X}", self.sdio.regs.adma_system_address.read()); debug!("SDIO Status: {:0X}", self.sdio.regs.interrupt_status.read().inner); Ok(()) } @@ -242,8 +245,10 @@ impl SdCard { self.sdio.set_block_size(512)?; } + debug!("Set up ADMA descriptor table"); setup_adma2_descr32(&mut self.sdio, block_cnt as u32, buffer); // invalidate D cache, required for ZC706, not sure for Cora Z7 10 + debug!("Invalidate D cache for buffer"); cache::dcc_slice(buffer); let (cmd, mode) = if block_cnt == 1 { @@ -261,21 +266,21 @@ impl SdCard { .dma_en(true), ) }; - assert!(!self.sdio.regs.interrupt_status.read().transfer_complete()); self.sdio .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; - debug!("Waiting for write"); + debug!("Waiting for write. (Transfer complete = 1)"); // wait for transfer complete interrupt while !self.sdio.regs.interrupt_status.read().transfer_complete() { let status = self.sdio.regs.interrupt_status.read(); self.sdio.check_error(&status)?; } - debug!("ADMA Error Status: {:?}", self.sdio.regs.adma_error_status.read().inner); + debug!("Reset transfer complete."); self.sdio .regs .interrupt_status .modify(|_, w| w.transfer_complete()); + debug!("Flush buffer D cache"); cache::dcc_slice(buffer); Ok(()) } -- 2.42.0 From d662076834168c87a86e40d3e2452db44c49422b Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 4 Jun 2020 09:37:30 +0800 Subject: [PATCH 26/34] Formatting --- libboard_zynq/src/sdio/adma.rs | 52 ++++++++++++++++--------------- libboard_zynq/src/sdio/mod.rs | 6 ++-- libboard_zynq/src/sdio/regs.rs | 4 +-- libboard_zynq/src/sdio/sd_card.rs | 17 +++++++--- 4 files changed, 45 insertions(+), 34 deletions(-) diff --git a/libboard_zynq/src/sdio/adma.rs b/libboard_zynq/src/sdio/adma.rs index 7f7a930..693af30 100644 --- a/libboard_zynq/src/sdio/adma.rs +++ b/libboard_zynq/src/sdio/adma.rs @@ -1,7 +1,7 @@ /// ADMA library use super::SDIO; use libcortex_a9::cache; -use libregister::{RegisterR, RegisterW, RegisterRW}; +use libregister::{RegisterR, RegisterRW, RegisterW}; use log::debug; #[repr(C, packed)] @@ -13,12 +13,11 @@ pub struct Adma2Desc32 { } // Default::default() cannot be used as it is not a constant function... -static mut ADMA2_DESCR32_TABLE: [Adma2Desc32; 32] = [ - Adma2Desc32 { - attribute: 0, - length: 0, - address: 0, - }; 32]; +static mut ADMA2_DESCR32_TABLE: [Adma2Desc32; 32] = [Adma2Desc32 { + attribute: 0, + length: 0, + address: 0, +}; 32]; #[allow(unused)] const DESC_MAX_LENGTH: u32 = 65536; @@ -39,9 +38,7 @@ impl Adma2Desc32 { } pub fn get_attribute(&mut self) -> u16 { - unsafe { - core::ptr::read_volatile(&mut self.attribute as *mut u16) - } + unsafe { core::ptr::read_volatile(&mut self.attribute as *mut u16) } } pub fn set_length(&mut self, length: u16) { @@ -51,9 +48,7 @@ impl Adma2Desc32 { } pub fn get_length(&mut self) -> u16 { - unsafe { - core::ptr::read_volatile(&mut self.length as *mut u16) - } + unsafe { core::ptr::read_volatile(&mut self.length as *mut u16) } } pub fn set_address(&mut self, address: u32) { @@ -62,22 +57,24 @@ impl Adma2Desc32 { } } - pub fn get_address(&mut self) -> u32{ - unsafe { - core::ptr::read_volatile(&mut self.address as *mut u32) - } + pub fn get_address(&mut self) -> u32 { + unsafe { core::ptr::read_volatile(&mut self.address as *mut u32) } } } pub fn setup_adma2_descr32(sdio: &mut SDIO, blk_cnt: u32, buffer: &mut [u32]) { let mut descr_table = unsafe { &mut ADMA2_DESCR32_TABLE }; - let blk_size = sdio.regs.block_size_block_count.read().transfer_block_size() as u32; + let blk_size = sdio + .regs + .block_size_block_count + .read() + .transfer_block_size() as u32; let total_desc_lines = if blk_size * blk_cnt < DESC_MAX_LENGTH { 1 } else { - blk_size * blk_cnt / DESC_MAX_LENGTH + - if (blk_size * blk_cnt) % DESC_MAX_LENGTH == 0 { + blk_size * blk_cnt / DESC_MAX_LENGTH + + if (blk_size * blk_cnt) % DESC_MAX_LENGTH == 0 { 0 } else { 1 @@ -94,16 +91,21 @@ pub fn setup_adma2_descr32(sdio: &mut SDIO, blk_cnt: u32, buffer: &mut [u32]) { descr_table[desc_num].set_length(0); } descr_table[total_desc_lines - 1].set_attribute(DESC_TRANS | DESC_VALID | DESC_END); - descr_table[total_desc_lines - 1].set_length((blk_cnt * blk_size - -((total_desc_lines as u32) - 1) * DESC_MAX_LENGTH) as u16); - debug!("Desc line address: {:0X}", descr_table[total_desc_lines - 1].get_address()); + descr_table[total_desc_lines - 1].set_length( + (blk_cnt * blk_size - ((total_desc_lines as u32) - 1) * DESC_MAX_LENGTH) as u16, + ); + debug!( + "Desc line address: {:0X}", + descr_table[total_desc_lines - 1].get_address() + ); unsafe { let memory = core::mem::transmute::<&mut Adma2Desc32, *mut u64>(&mut descr_table[0]); debug!("Desc line content: {:0X}", core::ptr::read_volatile(memory)); } unsafe { - sdio.regs.adma_system_address.write(descr_table.as_ptr() as u32); + sdio.regs + .adma_system_address + .write(descr_table.as_ptr() as u32); } cache::dcc_slice(descr_table); } - diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 7b22ef5..77e16dd 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -1,8 +1,8 @@ pub mod sd_card; +mod adma; mod cmd; mod regs; -mod adma; use super::clocks::Clocks; use super::slcr; use super::time::Milliseconds; @@ -184,7 +184,9 @@ impl SDIO { self.regs.control.modify(|_, w| w.bus_voltage(voltage)); debug!("Select DMA2 32Bit"); - self.regs.control.modify(|_, w| w.dma_select(regs::DmaSelect::ADMA2_32)); + self.regs + .control + .modify(|_, w| w.dma_select(regs::DmaSelect::ADMA2_32)); // enable all interrupt status except card interrupt debug!("Enable interrupt status."); diff --git a/libboard_zynq/src/sdio/regs.rs b/libboard_zynq/src/sdio/regs.rs index ee963ec..208fba4 100644 --- a/libboard_zynq/src/sdio/regs.rs +++ b/libboard_zynq/src/sdio/regs.rs @@ -1,6 +1,6 @@ -use volatile_register::{RO, RW}; use core::fmt; use libregister::{register, register_at, register_bit, register_bits, register_bits_typed}; +use volatile_register::{RO, RW}; #[allow(unused)] #[repr(C)] @@ -65,7 +65,7 @@ pub enum BusVoltage { /// 1.8V, typ. V18 = 0b101, /// No power, - V0 = 0b000 + V0 = 0b000, } #[allow(unused)] diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index b3a52e8..6d1a29d 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -1,4 +1,4 @@ -use super::{cmd, CardType, CmdTransferError, SDIO, adma::setup_adma2_descr32}; +use super::{adma::setup_adma2_descr32, cmd, CardType, CmdTransferError, SDIO}; use libcortex_a9::cache; use libregister::{RegisterR, RegisterRW, RegisterW}; use log::debug; @@ -92,7 +92,10 @@ impl SdCard { } self.sdio.cmd_transfer(CMD9, self.rel_card_addr, 0)?; - self.sdio.regs.interrupt_status.modify(|_, w| w.transfer_complete()); + self.sdio + .regs + .interrupt_status + .modify(|_, w| w.transfer_complete()); let mut csd: [u32; 4] = [0, 0, 0, 0]; for i in 0..=3 { @@ -121,7 +124,6 @@ impl SdCard { return Err(CardInitializationError::InitializationFailedOther); } - // CMD7: select card self.sdio.cmd_transfer(CMD7, self.rel_card_addr, 0)?; // ACMD6: set bus width @@ -222,7 +224,10 @@ impl SdCard { debug!("Flush buffer D cache"); cache::dcc_slice(buffer); - debug!("SDIO Status: {:0X}", self.sdio.regs.interrupt_status.read().inner); + debug!( + "SDIO Status: {:0X}", + self.sdio.regs.interrupt_status.read().inner + ); Ok(()) } @@ -254,7 +259,9 @@ impl SdCard { let (cmd, mode) = if block_cnt == 1 { ( cmd::SdCmd::CMD24, - super::regs::TransferModeCommand::zeroed().block_count_en(true).dma_en(true), + super::regs::TransferModeCommand::zeroed() + .block_count_en(true) + .dma_en(true), ) } else { ( -- 2.42.0 From 84a59a94d3fe875a599073329e2866e20f366c39 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 4 Jun 2020 11:31:02 +0800 Subject: [PATCH 27/34] Fixed warnings --- experiments/src/main.rs | 8 +------- libboard_zynq/src/sdio/adma.rs | 5 +++-- libboard_zynq/src/sdio/cmd.rs | 1 - libboard_zynq/src/sdio/mod.rs | 6 ------ 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 335ad0b..70f7781 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -20,12 +20,6 @@ use log::info; mod ps7_init; -#[repr(align(8))] -struct SdBuffer { - padding: u8, - buffer: [u32; 512/4] -} - #[no_mangle] pub fn main_core0() { // zynq::clocks::CpuClocks::enable_io(1_250_000_000); @@ -80,7 +74,7 @@ pub fn main_core0() { }; let mut sd_card = result.unwrap(); let mut buffer = [5; 512 / 4]; - sd_card.read_block(1, 1, &mut buffer).unwrap(); + sd_card.read_block(0x1000, 1, &mut buffer).unwrap(); // for i in 0..buffer.len() { // info!("buffer[{}] = {}", i, buffer[i]); // } diff --git a/libboard_zynq/src/sdio/adma.rs b/libboard_zynq/src/sdio/adma.rs index 693af30..959ab42 100644 --- a/libboard_zynq/src/sdio/adma.rs +++ b/libboard_zynq/src/sdio/adma.rs @@ -1,7 +1,7 @@ /// ADMA library use super::SDIO; use libcortex_a9::cache; -use libregister::{RegisterR, RegisterRW, RegisterW}; +use libregister::RegisterR; use log::debug; #[repr(C, packed)] @@ -30,6 +30,7 @@ const DESC_END: u16 = 0x1 << 1; #[allow(unused)] const DESC_VALID: u16 = 0x1 << 0; +#[allow(unused)] impl Adma2Desc32 { pub fn set_attribute(&mut self, attribute: u16) { unsafe { @@ -63,7 +64,7 @@ impl Adma2Desc32 { } pub fn setup_adma2_descr32(sdio: &mut SDIO, blk_cnt: u32, buffer: &mut [u32]) { - let mut descr_table = unsafe { &mut ADMA2_DESCR32_TABLE }; + let descr_table = unsafe { &mut ADMA2_DESCR32_TABLE }; let blk_size = sdio .regs .block_size_block_count diff --git a/libboard_zynq/src/sdio/cmd.rs b/libboard_zynq/src/sdio/cmd.rs index 5809c60..8bf9921 100644 --- a/libboard_zynq/src/sdio/cmd.rs +++ b/libboard_zynq/src/sdio/cmd.rs @@ -1,5 +1,4 @@ use super::regs; -use log::debug; const APP_CMD_PREFIX: u8 = 0x80; #[allow(unused)] diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 77e16dd..0351dd1 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -11,12 +11,6 @@ use libregister::{RegisterR, RegisterRW, RegisterW}; use log::debug; use nb; -macro_rules! print_field_addr { - ($self: expr, $name: ident) => { - debug!("Addr {:p}: {}", &$self.$name, stringify!($name)); - }; -} - /// Basic SDIO Struct with common low-level functions. pub struct SDIO { regs: &'static mut regs::RegisterBlock, -- 2.42.0 From 4881fe6e29c8037b110ef49d29fe2edfb7d6872d Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 4 Jun 2020 14:51:52 +0800 Subject: [PATCH 28/34] Fixed data crc error due to incorrect buswidth. --- experiments/src/main.rs | 6 +- libboard_zynq/src/sdio/mod.rs | 2 +- libboard_zynq/src/sdio/sd_card.rs | 116 ++++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 33 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 70f7781..2665536 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -75,9 +75,9 @@ pub fn main_core0() { let mut sd_card = result.unwrap(); let mut buffer = [5; 512 / 4]; sd_card.read_block(0x1000, 1, &mut buffer).unwrap(); - // for i in 0..buffer.len() { - // info!("buffer[{}] = {}", i, buffer[i]); - // } + for i in 0..buffer.len() { + info!("buffer[{}] = {}", i, buffer[i]); + } info!("End"); sd = sd_card.to_sdio(); loop { diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 0351dd1..77c368d 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -137,7 +137,7 @@ impl SDIO { // poweroff self.regs .control - .modify(|_, w| w.bus_voltage(regs::BusVoltage::V0)); + .modify(|_, w| w.bus_voltage(regs::BusVoltage::V0).bus_power(false)); if self.regs.misc_reg.read().spec_ver() == regs::SpecificationVersion::V3 { // The documentation said the field can only be V1 or V2, diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 6d1a29d..e592509 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -17,6 +17,7 @@ impl From for CardInitializationError { } } +#[derive(Debug)] enum CardVersion { SdVer1, SdVer2, @@ -30,6 +31,16 @@ pub struct SdCard { rel_card_addr: u32, sector_cnt: u32, switch_1v8: bool, + width_4_bit: bool, +} + +const BLK_SIZE_MASK: u16 = 0x00000FFF; + +impl core::fmt::Display for SdCard { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "SdCard: \n card version: {:?}\n hcs: {}\n card id: {:?}\n rel card addr: {}\n sector count: {}", + self.card_version, self.hcs, self.card_id, self.rel_card_addr, self.sector_cnt) + } } impl SdCard { @@ -126,14 +137,21 @@ impl SdCard { // CMD7: select card self.sdio.cmd_transfer(CMD7, self.rel_card_addr, 0)?; - // ACMD6: set bus width - self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; - self.sdio.cmd_transfer(ACMD6, 2, 0)?; // pull up + self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; + self.sdio.cmd_transfer(ACMD42, 0, 0)?; + + let mut scr: [u32; 8] = [0; 8]; + self.get_bus_width(&mut scr)?; + debug!("{:?}", scr); + if scr[1] & 0x4 != 0 { + // 4bit support + debug!("4 bit support"); + self.change_bus_width()?; + } + self.sdio.set_block_size(512)?; - // self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; - // self.sdio.cmd_transfer(ACMD42, 0, 0)?; Ok(()) } @@ -151,6 +169,7 @@ impl SdCard { rel_card_addr: 0, sector_cnt: 0, switch_1v8: false, + width_4_bit: false, }; _self.sd_card_initialize()?; Ok(_self) @@ -208,20 +227,7 @@ impl SdCard { self.sdio .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; - debug!("Waiting for read. (Transfer complete = 1)"); - // wait for transfer complete interrupt - let mut status = self.sdio.regs.interrupt_status.read(); - self.sdio.check_error(&status)?; - while !status.transfer_complete() { - status = self.sdio.regs.interrupt_status.read(); - self.sdio.check_error(&status)?; - } - debug!("Reset transfer complete."); - self.sdio - .regs - .interrupt_status - .modify(|_, w| w.transfer_complete()); - + self.wait_transfer_complete()?; debug!("Flush buffer D cache"); cache::dcc_slice(buffer); debug!( @@ -275,20 +281,72 @@ impl SdCard { }; self.sdio .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; - debug!("Waiting for write. (Transfer complete = 1)"); // wait for transfer complete interrupt - while !self.sdio.regs.interrupt_status.read().transfer_complete() { - let status = self.sdio.regs.interrupt_status.read(); - self.sdio.check_error(&status)?; - } - debug!("Reset transfer complete."); - self.sdio - .regs - .interrupt_status - .modify(|_, w| w.transfer_complete()); + self.wait_transfer_complete()?; debug!("Flush buffer D cache"); cache::dcc_slice(buffer); Ok(()) } + + fn get_bus_width(&mut self, buf: &mut [u32]) -> Result<(), CmdTransferError> { + use cmd::SdCmd::*; + debug!("Getting bus width"); + for i in 0..8 { + buf[i] = 0; + } + // send block write command + self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; + + let blk_cnt: u16 = 1; + let blk_size: u16 = 8 & BLK_SIZE_MASK; + self.sdio + .regs + .block_size_block_count + .modify(|_, w| w.transfer_block_size(blk_size)); + + setup_adma2_descr32(&mut self.sdio, blk_cnt as u32, buf); + cache::dcc_slice(buf); + self.sdio.cmd_transfer_with_mode( + ACMD51, + 0, + blk_cnt, + super::regs::TransferModeCommand::zeroed() + .dma_en(true) + .direction_select(true), + )?; + + self.wait_transfer_complete()?; + cache::dcc_slice(buf); + Ok(()) + } + + fn change_bus_width(&mut self) -> Result<(), CmdTransferError> { + use cmd::SdCmd::*; + debug!("Changing bus speed"); + self.sdio.cmd_transfer(CMD55, self.rel_card_addr, 0)?; + self.width_4_bit = true; + self.sdio.cmd_transfer(ACMD6, 0x2, 0)?; + self.sdio.delay(1); + self.sdio + .regs + .control + .modify(|_, w| w.data_width_select(true)); + Ok(()) + } + + fn wait_transfer_complete(&mut self) -> Result<(), CmdTransferError> { + debug!("Wait for transfer complete"); + let mut status = self.sdio.regs.interrupt_status.read(); + while !status.transfer_complete() { + self.sdio.check_error(&status)?; + status = self.sdio.regs.interrupt_status.read(); + } + debug!("Clearing transfer complete"); + self.sdio + .regs + .interrupt_status + .modify(|_, w| w.transfer_complete()); + Ok(()) + } } -- 2.42.0 From eec13e4bcf4fd4cc8eed88385690fcfe820fd4fd Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 4 Jun 2020 15:25:11 +0800 Subject: [PATCH 29/34] Invalidate cache correctly. --- libboard_zynq/src/sdio/adma.rs | 2 +- libboard_zynq/src/sdio/sd_card.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libboard_zynq/src/sdio/adma.rs b/libboard_zynq/src/sdio/adma.rs index 959ab42..134021b 100644 --- a/libboard_zynq/src/sdio/adma.rs +++ b/libboard_zynq/src/sdio/adma.rs @@ -108,5 +108,5 @@ pub fn setup_adma2_descr32(sdio: &mut SDIO, blk_cnt: u32, buffer: &mut [u32]) { .adma_system_address .write(descr_table.as_ptr() as u32); } - cache::dcc_slice(descr_table); + cache::dcci_slice(descr_table); } diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index e592509..41ef0ef 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -202,7 +202,7 @@ impl SdCard { setup_adma2_descr32(&mut self.sdio, block_cnt as u32, buffer); // invalidate D cache, required for ZC706, not sure for Cora Z7 10 debug!("Invalidate D cache for buffer"); - cache::dcc_slice(buffer); + cache::dcci_slice(buffer); let (cmd, mode) = if block_cnt == 1 { ( @@ -229,7 +229,7 @@ impl SdCard { self.wait_transfer_complete()?; debug!("Flush buffer D cache"); - cache::dcc_slice(buffer); + cache::dcci_slice(buffer); debug!( "SDIO Status: {:0X}", self.sdio.regs.interrupt_status.read().inner @@ -260,7 +260,7 @@ impl SdCard { setup_adma2_descr32(&mut self.sdio, block_cnt as u32, buffer); // invalidate D cache, required for ZC706, not sure for Cora Z7 10 debug!("Invalidate D cache for buffer"); - cache::dcc_slice(buffer); + cache::dcci_slice(buffer); let (cmd, mode) = if block_cnt == 1 { ( @@ -285,7 +285,7 @@ impl SdCard { self.wait_transfer_complete()?; debug!("Flush buffer D cache"); - cache::dcc_slice(buffer); + cache::dcci_slice(buffer); Ok(()) } @@ -306,7 +306,7 @@ impl SdCard { .modify(|_, w| w.transfer_block_size(blk_size)); setup_adma2_descr32(&mut self.sdio, blk_cnt as u32, buf); - cache::dcc_slice(buf); + cache::dcci_slice(buf); self.sdio.cmd_transfer_with_mode( ACMD51, 0, @@ -317,7 +317,7 @@ impl SdCard { )?; self.wait_transfer_complete()?; - cache::dcc_slice(buf); + cache::dcci_slice(buf); Ok(()) } -- 2.42.0 From 1f29034e25902d624573c1aa78944d99f12dbd14 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 4 Jun 2020 15:30:12 +0800 Subject: [PATCH 30/34] now supports read and write --- experiments/src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 2665536..71cf5b7 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -74,7 +74,11 @@ pub fn main_core0() { }; let mut sd_card = result.unwrap(); let mut buffer = [5; 512 / 4]; - sd_card.read_block(0x1000, 1, &mut buffer).unwrap(); + sd_card.write_block(0x0, 1, &mut buffer).unwrap(); + for i in 0..512/4 { + buffer[i] = 123; + } + sd_card.read_block(0x0, 1, &mut buffer).unwrap(); for i in 0..buffer.len() { info!("buffer[{}] = {}", i, buffer[i]); } -- 2.42.0 From 9dbdf5d95de5a89faab81cc67b24c26033945c24 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 4 Jun 2020 16:22:49 +0800 Subject: [PATCH 31/34] Added some documentation to public functions --- experiments/src/main.rs | 24 +++++++++++++++--------- libboard_zynq/src/sdio/adma.rs | 11 ----------- libboard_zynq/src/sdio/mod.rs | 13 ++++--------- libboard_zynq/src/sdio/sd_card.rs | 16 ++++++---------- 4 files changed, 25 insertions(+), 39 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 71cf5b7..7c41924 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -64,21 +64,27 @@ pub fn main_core0() { clocks.cpu_1x() ); - let mut sd = libboard_zynq::sdio::SDIO::sdio0(false); + let mut sd = libboard_zynq::sdio::SDIO::sdio0(true); info!("Wait for SD card inertion!"); - // while !sd.is_card_inserted() {} + while !sd.is_card_inserted() {} + // debouncing by waiting... + sd.delay(100); let result = SdCard::from_sdio(sd); match &result { - Ok(_) => println!("OK!"), - Err(a) => println!("{:?}", a), + Ok(_) => info!("OK!"), + Err(a) => info!("{:?}", a), }; + const SIZE: usize = 512/2; let mut sd_card = result.unwrap(); - let mut buffer = [5; 512 / 4]; - sd_card.write_block(0x0, 1, &mut buffer).unwrap(); - for i in 0..512/4 { - buffer[i] = 123; + let mut buffer: [u32; SIZE] = [0; SIZE]; + for i in 0..buffer.len() { + buffer[i] = (i % 16) as u32; } - sd_card.read_block(0x0, 1, &mut buffer).unwrap(); + sd_card.write_block(0x0, 2, &mut buffer).unwrap(); + for i in 0..buffer.len() { + buffer[i] = 0; + } + sd_card.read_block(0x1, 2, &mut buffer).unwrap(); for i in 0..buffer.len() { info!("buffer[{}] = {}", i, buffer[i]); } diff --git a/libboard_zynq/src/sdio/adma.rs b/libboard_zynq/src/sdio/adma.rs index 134021b..3d6f4a3 100644 --- a/libboard_zynq/src/sdio/adma.rs +++ b/libboard_zynq/src/sdio/adma.rs @@ -2,7 +2,6 @@ use super::SDIO; use libcortex_a9::cache; use libregister::RegisterR; -use log::debug; #[repr(C, packed)] #[derive(Clone, Copy)] @@ -83,8 +82,6 @@ pub fn setup_adma2_descr32(sdio: &mut SDIO, blk_cnt: u32, buffer: &mut [u32]) { } as usize; let ptr = buffer.as_ptr() as u32; - debug!("Buffer address: {:0X}", ptr); - debug!("Table address: {:0X}", descr_table.as_ptr() as u64); for desc_num in 0..total_desc_lines { descr_table[desc_num].set_address(ptr + (desc_num as u32) * DESC_MAX_LENGTH); descr_table[desc_num].set_attribute(DESC_TRANS | DESC_VALID); @@ -95,14 +92,6 @@ pub fn setup_adma2_descr32(sdio: &mut SDIO, blk_cnt: u32, buffer: &mut [u32]) { descr_table[total_desc_lines - 1].set_length( (blk_cnt * blk_size - ((total_desc_lines as u32) - 1) * DESC_MAX_LENGTH) as u16, ); - debug!( - "Desc line address: {:0X}", - descr_table[total_desc_lines - 1].get_address() - ); - unsafe { - let memory = core::mem::transmute::<&mut Adma2Desc32, *mut u64>(&mut descr_table[0]); - debug!("Desc line content: {:0X}", core::ptr::read_volatile(memory)); - } unsafe { sdio.regs .adma_system_address diff --git a/libboard_zynq/src/sdio/mod.rs b/libboard_zynq/src/sdio/mod.rs index 77c368d..4e4f9a3 100644 --- a/libboard_zynq/src/sdio/mod.rs +++ b/libboard_zynq/src/sdio/mod.rs @@ -36,8 +36,9 @@ pub enum CardType { } impl SDIO { - #[cfg(feature = "target_cora_z7_10")] - /// Initialize SDIO0 for Cora Z7 10 + /// Initialize SDIO0 + /// card_detect means if we would use the card detect pin, + /// false to disable card detection (assume there is card inserted) pub fn sdio0(card_detect: bool) -> Self { // initialization according to ps7_init.c slcr::RegisterBlock::unlocked(|slcr| { @@ -87,7 +88,6 @@ impl SDIO { slcr.sdio_clk_ctrl.enable_sdio0(); }); let clocks = Clocks::get(); - debug!("Ref Clk: {}", clocks.sdio_ref_clk()); let mut self_ = SDIO { regs: regs::RegisterBlock::sdio0(), count_down: super::timer::GlobalTimer::start().countdown(), @@ -157,7 +157,6 @@ impl SDIO { while self.regs.clock_control.read().software_reset_all() {} // set power to 3.3V - debug!("Set power to 3.3V"); self.regs .control .modify(|_, w| w.bus_voltage(regs::BusVoltage::V33).bus_power(true)); @@ -174,22 +173,18 @@ impl SDIO { } else { regs::BusVoltage::V0 }; - debug!("Set voltage to {:?}", voltage); self.regs.control.modify(|_, w| w.bus_voltage(voltage)); - debug!("Select DMA2 32Bit"); self.regs .control .modify(|_, w| w.dma_select(regs::DmaSelect::ADMA2_32)); // enable all interrupt status except card interrupt - debug!("Enable interrupt status."); self.regs.interrupt_status_en.write( (regs::interrupt_status_en::Write { inner: 0xFFFFFFFF }) .card_interrupt_status_en(false), ); - debug!("Debug interrupt signals."); // disable all interrupt signals self.regs .interrupt_signal_en @@ -202,7 +197,7 @@ impl SDIO { } /// Delay for SDIO operations, simple wrapper for nb. - fn delay(&mut self, ms: u64) { + pub fn delay(&mut self, ms: u64) { self.count_down.start(Milliseconds(ms)); nb::block!(self.count_down.wait()).unwrap(); } diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 41ef0ef..938cd2c 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -156,6 +156,7 @@ impl SdCard { Ok(()) } + /// Convert SDIO into SdCard struct, error if no card inserted or it is not an SD card. pub fn from_sdio(mut sdio: SDIO) -> Result { match sdio.identify_card()? { CardType::CardSd => (), @@ -175,10 +176,13 @@ impl SdCard { Ok(_self) } + /// Convert SdCard struct back to SDIO struct. pub fn to_sdio(self) -> SDIO { self.sdio } + /// read blocks starting from an address. Each block has length 512 byte. + /// Note that the address is block address, i.e. 0 for 0~512, 1 for 512~1024, etc. pub fn read_block( &mut self, address: u32, @@ -198,10 +202,8 @@ impl SdCard { self.sdio.set_block_size(512)?; } - debug!("Set up ADMA descriptor table"); setup_adma2_descr32(&mut self.sdio, block_cnt as u32, buffer); // invalidate D cache, required for ZC706, not sure for Cora Z7 10 - debug!("Invalidate D cache for buffer"); cache::dcci_slice(buffer); let (cmd, mode) = if block_cnt == 1 { @@ -228,15 +230,12 @@ impl SdCard { .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; self.wait_transfer_complete()?; - debug!("Flush buffer D cache"); cache::dcci_slice(buffer); - debug!( - "SDIO Status: {:0X}", - self.sdio.regs.interrupt_status.read().inner - ); Ok(()) } + /// write blocks starting from an address. Each block has length 512 byte. + /// Note that the address is block address, i.e. 0 for 0~512, 1 for 512~1024, etc. pub fn write_block( &mut self, address: u32, @@ -256,10 +255,8 @@ impl SdCard { self.sdio.set_block_size(512)?; } - debug!("Set up ADMA descriptor table"); setup_adma2_descr32(&mut self.sdio, block_cnt as u32, buffer); // invalidate D cache, required for ZC706, not sure for Cora Z7 10 - debug!("Invalidate D cache for buffer"); cache::dcci_slice(buffer); let (cmd, mode) = if block_cnt == 1 { @@ -284,7 +281,6 @@ impl SdCard { // wait for transfer complete interrupt self.wait_transfer_complete()?; - debug!("Flush buffer D cache"); cache::dcci_slice(buffer); Ok(()) } -- 2.42.0 From 3e99c840253b220a552822a12485e3dfa9333253 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 4 Jun 2020 16:48:13 +0800 Subject: [PATCH 32/34] Added back other features to main --- experiments/src/main.rs | 168 ++++++++++++++++++++++++++++++++-------- 1 file changed, 134 insertions(+), 34 deletions(-) diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 0011771..905156d 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -3,28 +3,37 @@ extern crate alloc; -use core::{mem::transmute, task::Poll}; use alloc::{borrow::ToOwned, collections::BTreeMap, format}; -use log::info; -use libregister::RegisterR; -use libcortex_a9::{mutex::Mutex, sync_channel::{self, sync_channel}}; +use core::{mem::transmute, task::Poll}; +use libasync::{ + delay, + smoltcp::{Sockets, TcpStream}, + task, +}; use libboard_zynq::{ + self as zynq, + clocks::source::{ArmPll, ClockSource, IoPll}, + clocks::Clocks, print, println, - self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, + sdio::{self, sd_card::SdCard}, smoltcp::{ self, - wire::{EthernetAddress, IpAddress, IpCidr}, - iface::{NeighborCache, EthernetInterfaceBuilder, Routes}, + iface::{EthernetInterfaceBuilder, NeighborCache, Routes}, time::Instant, + wire::{EthernetAddress, IpAddress, IpCidr}, }, time::Milliseconds, - sdio::{self, sd_card::SdCard} }; +use libcortex_a9::{ + mutex::Mutex, + sync_channel::{self, sync_channel}, +}; +use libregister::RegisterR; use libsupport_zynq::{ - ram, alloc::{vec, vec::Vec}, - boot, + alloc::{vec, vec::Vec}, + boot, ram, }; -use libasync::{delay, smoltcp::{Sockets, TcpStream}, task}; +use log::info; mod ps7_init; @@ -82,7 +91,7 @@ pub fn main_core0() { Ok(_) => info!("OK!"), Err(a) => info!("{:?}", a), }; - const SIZE: usize = 512/2; + const SIZE: usize = 512 / 2; let mut sd_card = result.unwrap(); let mut buffer: [u32; SIZE] = [0; SIZE]; for i in 0..buffer.len() { @@ -97,8 +106,65 @@ pub fn main_core0() { info!("buffer[{}] = {}", i, buffer[i]); } info!("End"); - sd = sd_card.to_sdio(); } + + let mut flash = zynq::flash::Flash::new(200_000_000).linear_addressing_mode(); + let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) }; + for i in 0..=1 { + print!("Flash {}:", i); + for b in &flash_ram[(i * 16 * 1024 * 1024)..][..128] { + print!(" {:02X}", *b); + } + println!(""); + } + let mut flash = flash.stop(); + + let timer = libboard_zynq::timer::GlobalTimer::start(); + + let mut ddr = zynq::ddr::DdrRam::new(); + #[cfg(not(feature = "target_zc706"))] + ddr.memtest(); + ram::init_alloc_ddr(&mut ddr); + #[cfg(dev)] + for i in 0..=1 { + let mut flash_io = flash.manual_mode(i); + // println!("rdcr={:02X}", flash_io.rdcr()); + print!("Flash {} ID:", i); + for b in flash_io.rdid() { + print!(" {:02X}", b); + } + println!(""); + print!("Flash {} I/O:", i); + for o in 0..8 { + const CHUNK: u32 = 8; + for b in flash_io.read(CHUNK * o, CHUNK as usize) { + print!(" {:02X}", b); + } + } + println!(""); + + flash_io.dump("Read cr1", 0x35); + flash_io.dump("Read Autoboot", 0x14); + flash_io.dump("Read Bank", 0x16); + flash_io.dump("DLP Bank", 0x16); + flash_io.dump("Read ESig", 0xAB); + flash_io.dump("OTP Read", 0x4B); + flash_io.dump("DYB Read", 0xE0); + flash_io.dump("PPB Read", 0xE2); + flash_io.dump("ASP Read", 0x2B); + flash_io.dump("Password Read", 0xE7); + + flash_io.write_enabled(|flash_io| { + flash_io.erase(0); + }); + flash_io.write_enabled(|flash_io| { + flash_io.program(0, [0x23054223; 0x100 >> 2].iter().cloned()); + }); + + flash = flash_io.stop(); + } + + let core1 = boot::Core1::start(false); let (mut core1_req, rx) = sync_channel(10); @@ -158,33 +224,67 @@ pub fn main_core0() { const TCP_PORT: u16 = 19; async fn handle_connection(stream: TcpStream) -> smoltcp::Result<()> { stream.send("Enter your name: ".bytes()).await?; - let name = stream.recv(|buf| { - for (i, b) in buf.iter().enumerate() { - if *b == '\n' as u8 { - return match core::str::from_utf8(&buf[0..i]) { - Ok(name) => - Poll::Ready((i + 1, Some(name.to_owned()))), - Err(_) => - Poll::Ready((i + 1, None)) - }; + let name = stream + .recv(|buf| { + for (i, b) in buf.iter().enumerate() { + if *b == '\n' as u8 { + return match core::str::from_utf8(&buf[0..i]) { + Ok(name) => Poll::Ready((i + 1, Some(name.to_owned()))), + Err(_) => Poll::Ready((i + 1, None)), + }; + } } - } - if buf.len() > 100 { - // Too much input, consume all - Poll::Ready((buf.len(), None)) - } else { - Poll::Pending - } - }).await?; + if buf.len() > 100 { + // Too much input, consume all + Poll::Ready((buf.len(), None)) + } else { + Poll::Pending + } + }) + .await?; match name { - Some(name) => - stream.send(format!("Hello {}!\n", name).bytes()).await?, - None => - stream.send("I had trouble reading your name.\n".bytes()).await?, + Some(name) => stream.send(format!("Hello {}!\n", name).bytes()).await?, + None => { + stream + .send("I had trouble reading your name.\n".bytes()) + .await? + } } let _ = stream.flush().await; Ok(()) } + + let counter = alloc::rc::Rc::new(core::cell::RefCell::new(0)); + task::spawn(async move { + while let Ok(stream) = TcpStream::accept(TCP_PORT, 2048, 2408).await { + let counter = counter.clone(); + task::spawn(async move { + *counter.borrow_mut() += 1; + println!("Serving {} connections", *counter.borrow()); + handle_connection(stream) + .await + .unwrap_or_else(|e| println!("Connection: {:?}", e)); + *counter.borrow_mut() -= 1; + println!("Now serving {} connections", *counter.borrow()); + }); + } + }); + + let mut countdown = timer.countdown(); + task::spawn(async move { + loop { + delay(&mut countdown, Milliseconds(1000)).await; + + let timestamp = timer.get_us(); + let seconds = timestamp / 1_000_000; + let micros = timestamp % 1_000_000; + info!("time: {:6}.{:06}s", seconds, micros); + } + }); + + Sockets::run(&mut iface, || { + Instant::from_millis(timer.get_time().0 as i64) + }) } static CORE1_REQ: Mutex>> = Mutex::new(None); -- 2.42.0 From 8233ea1c29df6557d3100a7fd700747960065c77 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 4 Jun 2020 17:27:09 +0800 Subject: [PATCH 33/34] faster clock --- libboard_zynq/src/sdio/sd_card.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 938cd2c..74eadc7 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -135,6 +135,7 @@ impl SdCard { return Err(CardInitializationError::InitializationFailedOther); } + self.sdio.change_clk_freq(25_000_000); // CMD7: select card self.sdio.cmd_transfer(CMD7, self.rel_card_addr, 0)?; -- 2.42.0 From f83c543899fb22ab0512d990acfd5614a86b344c Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 5 Jun 2020 10:12:52 +0800 Subject: [PATCH 34/34] Changed tuple into 2 statements for readability. --- libboard_zynq/src/sdio/sd_card.rs | 65 ++++++++++++++++--------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/libboard_zynq/src/sdio/sd_card.rs b/libboard_zynq/src/sdio/sd_card.rs index 74eadc7..26824f9 100644 --- a/libboard_zynq/src/sdio/sd_card.rs +++ b/libboard_zynq/src/sdio/sd_card.rs @@ -207,24 +207,24 @@ impl SdCard { // invalidate D cache, required for ZC706, not sure for Cora Z7 10 cache::dcci_slice(buffer); - let (cmd, mode) = if block_cnt == 1 { - ( - cmd::SdCmd::CMD17, - super::regs::TransferModeCommand::zeroed() - .block_count_en(true) - .direction_select(true) - .dma_en(true), - ) + let cmd = if block_cnt == 1 { + cmd::SdCmd::CMD17 } else { - ( - cmd::SdCmd::CMD18, - super::regs::TransferModeCommand::zeroed() - .auto_cmd12_en(true) - .block_count_en(true) - .direction_select(true) - .multi_block_en(true) - .dma_en(true), - ) + cmd::SdCmd::CMD18 + }; + + let mode = if block_cnt == 1 { + super::regs::TransferModeCommand::zeroed() + .block_count_en(true) + .direction_select(true) + .dma_en(true) + } else { + super::regs::TransferModeCommand::zeroed() + .auto_cmd12_en(true) + .block_count_en(true) + .direction_select(true) + .multi_block_en(true) + .dma_en(true) }; self.sdio @@ -260,23 +260,24 @@ impl SdCard { // invalidate D cache, required for ZC706, not sure for Cora Z7 10 cache::dcci_slice(buffer); - let (cmd, mode) = if block_cnt == 1 { - ( - cmd::SdCmd::CMD24, - super::regs::TransferModeCommand::zeroed() - .block_count_en(true) - .dma_en(true), - ) + let cmd = if block_cnt == 1 { + cmd::SdCmd::CMD24 } else { - ( - cmd::SdCmd::CMD25, - super::regs::TransferModeCommand::zeroed() - .auto_cmd12_en(true) - .block_count_en(true) - .multi_block_en(true) - .dma_en(true), - ) + cmd::SdCmd::CMD25 }; + + let mode = if block_cnt == 1 { + super::regs::TransferModeCommand::zeroed() + .block_count_en(true) + .dma_en(true) + } else { + super::regs::TransferModeCommand::zeroed() + .auto_cmd12_en(true) + .block_count_en(true) + .multi_block_en(true) + .dma_en(true) + }; + self.sdio .cmd_transfer_with_mode(cmd, address, block_cnt, mode)?; // wait for transfer complete interrupt -- 2.42.0