refactor(rpi3/emmc): use tock_registers
This commit is contained in:
@@ -10,4 +10,5 @@ pub enum Errno {
|
||||
WouldBlock,
|
||||
AlreadyExists,
|
||||
NotImplemented,
|
||||
TimedOut,
|
||||
}
|
||||
|
||||
@@ -8,29 +8,108 @@ use crate::mem::virt::DeviceMemoryIo;
|
||||
use crate::sync::IrqSafeSpinLock;
|
||||
use crate::util::InitOnce;
|
||||
use error::Errno;
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||
use tock_registers::registers::{ReadOnly, ReadWrite};
|
||||
use tock_registers::{register_bitfields, register_structs};
|
||||
use vfs::BlockDevice;
|
||||
|
||||
use tock_registers::interfaces::{Readable, Writeable};
|
||||
use tock_registers::register_structs;
|
||||
use tock_registers::registers::{ReadOnly, ReadWrite};
|
||||
register_bitfields! {
|
||||
u32,
|
||||
BLKSIZECNT [
|
||||
BLKCNT OFFSET(16) NUMBITS(16) [],
|
||||
BLKSIZE OFFSET(0) NUMBITS(10) [],
|
||||
],
|
||||
CMDTM [
|
||||
CMD_INDEX OFFSET(24) NUMBITS(6) [],
|
||||
CMD_TYPE OFFSET(22) NUMBITS(23) [
|
||||
Normal = 0,
|
||||
Suspend = 1,
|
||||
Resume = 2,
|
||||
Abort = 3,
|
||||
],
|
||||
CMD_ISDATA OFFSET(21) NUMBITS(1) [],
|
||||
CMD_IXCHK_EN OFFSET(20) NUMBITS(1) [],
|
||||
CMD_CRCCHK_EN OFFSET(19) NUMBITS(1) [],
|
||||
CMD_RSPNS_TYPE OFFSET(16) NUMBITS(2) [
|
||||
None = 0,
|
||||
Bits136 = 1,
|
||||
Bits48 = 2,
|
||||
Bits48Busy = 3
|
||||
],
|
||||
TM_MULTI_BLOCK OFFSET(5) NUMBITS(1) [],
|
||||
TM_DAT_DIR OFFSET(4) NUMBITS(1) [
|
||||
HostToCard = 0,
|
||||
CardToHost = 1,
|
||||
],
|
||||
TM_AUDO_CMD_EN OFFSET(2) NUMBITS(2) [
|
||||
None = 0,
|
||||
Cmd12 = 1,
|
||||
Cmd23 = 2
|
||||
],
|
||||
TM_BLKCNT_EN OFFSET(1) NUMBITS(1) [],
|
||||
],
|
||||
STATUS [
|
||||
READ_TRANSFER OFFSET(9) NUMBITS(1) [],
|
||||
WRITE_TRANSFER OFFSET(8) NUMBITS(1) [],
|
||||
MISC_INSERTED OFFSET(16) NUMBITS(1) [],
|
||||
DAT_ACTIVE OFFSET(2) NUMBITS(1) [],
|
||||
DAT_INHIBIT OFFSET(1) NUMBITS(1) [],
|
||||
CMD_INHIBIT OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
INTERRUPT [
|
||||
ACMD_ERR 24,
|
||||
DEND_ERR 22,
|
||||
DCRC_ERR 21,
|
||||
DTO_ERR 20,
|
||||
CBAD_ERR 19,
|
||||
CEND_ERR 18,
|
||||
CCRC_ERR 17,
|
||||
CTO_ERR 16,
|
||||
ERR 15,
|
||||
ENDBOOT 14,
|
||||
BOOTACK 13,
|
||||
RETUNE 12,
|
||||
CARD 8,
|
||||
READ_RDY 5,
|
||||
WRITE_RDY 4,
|
||||
BLOCK_GAP 2,
|
||||
DATA_DONE 1,
|
||||
CMD_DONE 0,
|
||||
],
|
||||
CONTROL1 [
|
||||
SRST_DATA OFFSET(26) NUMBITS(1) [],
|
||||
SRST_CMD OFFSET(25) NUMBITS(1) [],
|
||||
SRST_HC OFFSET(24) NUMBITS(1) [],
|
||||
DATA_TOUNIT OFFSET(16) NUMBITS(4) [],
|
||||
CLK_FREQ8 OFFSET(8) NUMBITS(8) [],
|
||||
CLK_FREQ_MS2 OFFSET(6) NUMBITS(2) [],
|
||||
CLK_GENSEL OFFSET(5) NUMBITS(1) [
|
||||
Divided = 0,
|
||||
Programmable = 1
|
||||
],
|
||||
CLK_EN OFFSET(2) NUMBITS(1) [],
|
||||
CLK_STABLE OFFSET(1) NUMBITS(1) [],
|
||||
CLK_INTLEN OFFSET(0) NUMBITS(1) [],
|
||||
]
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
(0x00 => ARG2: ReadWrite<u32>),
|
||||
(0x04 => BLKSIZECNT: ReadWrite<u32>),
|
||||
(0x04 => BLKSIZECNT: ReadWrite<u32, BLKSIZECNT::Register>),
|
||||
(0x08 => ARG1: ReadWrite<u32>),
|
||||
(0x0C => CMDTM: ReadWrite<u32>),
|
||||
(0x0C => CMDTM: ReadWrite<u32, CMDTM::Register>),
|
||||
(0x10 => RESP0: ReadOnly<u32>),
|
||||
(0x14 => RESP1: ReadOnly<u32>),
|
||||
(0x18 => RESP2: ReadOnly<u32>),
|
||||
(0x1C => RESP3: ReadOnly<u32>),
|
||||
(0x20 => DATA: ReadWrite<u32>),
|
||||
(0x24 => STATUS: ReadOnly<u32>),
|
||||
(0x24 => STATUS: ReadOnly<u32, STATUS::Register>),
|
||||
(0x28 => CONTROL0: ReadWrite<u32>),
|
||||
(0x2C => CONTROL1: ReadWrite<u32>),
|
||||
(0x30 => INTERRUPT: ReadWrite<u32>),
|
||||
(0x34 => IRPT_MASK: ReadWrite<u32>),
|
||||
(0x2C => CONTROL1: ReadWrite<u32, CONTROL1::Register>),
|
||||
(0x30 => INTERRUPT: ReadWrite<u32, INTERRUPT::Register>),
|
||||
(0x34 => IRPT_MASK: ReadWrite<u32, INTERRUPT::Register>),
|
||||
(0x38 => IRPT_EN: ReadWrite<u32>),
|
||||
(0x3C => CONTROL2: ReadWrite<u32>),
|
||||
(0x40 => _res0),
|
||||
@@ -52,7 +131,7 @@ pub struct MassMediaController {
|
||||
base: usize,
|
||||
}
|
||||
|
||||
fn clock_divider(f_base: u32, f_target: u32) -> Result<u32, Errno> {
|
||||
fn clock_divider(f_base: u32, f_target: u32) -> u32 {
|
||||
let mut target_div;
|
||||
let mut div = 0;
|
||||
if f_target <= f_base {
|
||||
@@ -81,16 +160,13 @@ fn clock_divider(f_base: u32, f_target: u32) -> Result<u32, Errno> {
|
||||
div = 31;
|
||||
}
|
||||
if div != 0 {
|
||||
div = 1 << (div - 1)
|
||||
div = 1 << (div - 1);
|
||||
}
|
||||
if div >= 0x400 {
|
||||
div = 0x3FF;
|
||||
}
|
||||
|
||||
let f_sel = div & 0xFF;
|
||||
let upper_bits = (div >> 8) & 0x3;
|
||||
|
||||
Ok((f_sel << 8) | (upper_bits << 6))
|
||||
div
|
||||
}
|
||||
|
||||
impl MmcInner {
|
||||
@@ -105,63 +181,82 @@ impl MmcInner {
|
||||
machine::BCM_MBOX.clock_rate(Bcm283xMailbox::CLOCK_EMMC)
|
||||
}
|
||||
|
||||
// TODO generalize flag setting
|
||||
fn send_cmd_inner(&mut self, cmd: &mut SdCommand) -> Result<SdResponse, Errno> {
|
||||
debugln!("send_cmd {:?}", cmd.number);
|
||||
const TIMEOUT: u64 = 10000;
|
||||
let info = cmd.info_struct();
|
||||
let mut cmdtm = CMDTM::CMD_INDEX.val(cmd.number as u32);
|
||||
|
||||
while self.regs.STATUS.get() & 1 != 0 {
|
||||
cortex_a::asm::nop();
|
||||
}
|
||||
// Wait until CMD lines free up
|
||||
crate::block!(
|
||||
self.regs.STATUS.matches_all(STATUS::CMD_INHIBIT::CLEAR),
|
||||
TIMEOUT
|
||||
);
|
||||
|
||||
let response_type = cmd.response_type();
|
||||
if response_type.is_busy() {
|
||||
if info.response_type.is_busy() {
|
||||
// TODO check if this is an ABORT command
|
||||
|
||||
while self.regs.STATUS.get() & 2 != 0 {
|
||||
cortex_a::asm::nop();
|
||||
}
|
||||
// Wait until DAT lines free up after busy cmd
|
||||
crate::block!(
|
||||
self.regs.STATUS.matches_all(STATUS::DAT_INHIBIT::CLEAR),
|
||||
TIMEOUT
|
||||
);
|
||||
}
|
||||
|
||||
let (block_count, block_size, io_flags) = match &cmd.transfer {
|
||||
let (block_count, block_size) = match &cmd.transfer {
|
||||
SdCommandTransfer::Write(buf, blk_size) => {
|
||||
let sz = *blk_size as usize;
|
||||
assert!(buf.len() % sz == 0);
|
||||
((buf.len() / sz) as u32, *blk_size, (1 << 21))
|
||||
cmdtm += CMDTM::CMD_ISDATA::SET + CMDTM::TM_DAT_DIR::HostToCard;
|
||||
((buf.len() / sz) as u32, *blk_size)
|
||||
}
|
||||
SdCommandTransfer::Read(buf, blk_size) => {
|
||||
let sz = *blk_size as usize;
|
||||
assert!(buf.len() % sz == 0);
|
||||
((buf.len() / sz) as u32, *blk_size, (1 << 21) | (1 << 4))
|
||||
cmdtm += CMDTM::CMD_ISDATA::SET + CMDTM::TM_DAT_DIR::CardToHost;
|
||||
((buf.len() / sz) as u32, *blk_size)
|
||||
}
|
||||
SdCommandTransfer::None => (0, 512, 0),
|
||||
SdCommandTransfer::None => (0, 512),
|
||||
};
|
||||
|
||||
let (size_136, size_flags) = match response_type {
|
||||
SdResponseType::R2 | SdResponseType::R4 => (true, 1 << 16),
|
||||
SdResponseType::R1b | SdResponseType::R5b => (false, 3 << 16),
|
||||
SdResponseType::None => (false, 0),
|
||||
_ => (false, 2 << 16),
|
||||
let size_136 = match info.response_type {
|
||||
SdResponseType::R2 | SdResponseType::R4 => {
|
||||
cmdtm += CMDTM::CMD_RSPNS_TYPE::Bits136;
|
||||
true
|
||||
}
|
||||
SdResponseType::R1b | SdResponseType::R5b => {
|
||||
cmdtm += CMDTM::CMD_RSPNS_TYPE::Bits48Busy;
|
||||
false
|
||||
}
|
||||
SdResponseType::None => false,
|
||||
_ => {
|
||||
cmdtm += CMDTM::CMD_RSPNS_TYPE::Bits48;
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
debugln!("size_flags: {:#x}, io_flags: {:#x}", size_flags, io_flags);
|
||||
self.regs
|
||||
.BLKSIZECNT
|
||||
.set((block_size as u32) | (block_count << 16));
|
||||
self.regs.BLKSIZECNT.write(
|
||||
BLKSIZECNT::BLKCNT.val(block_count) + BLKSIZECNT::BLKSIZE.val(block_size as u32),
|
||||
);
|
||||
self.regs.ARG1.set(cmd.argument);
|
||||
self.regs
|
||||
.CMDTM
|
||||
.set((cmd.number() << 24) | size_flags | io_flags);
|
||||
|
||||
while self.regs.INTERRUPT.get() & 0x8001 == 0 {
|
||||
cortex_a::asm::nop();
|
||||
}
|
||||
self.regs.CMDTM.write(cmdtm);
|
||||
crate::block!(
|
||||
self.regs
|
||||
.INTERRUPT
|
||||
.matches_any(INTERRUPT::ERR::SET + INTERRUPT::CMD_DONE::SET),
|
||||
10000
|
||||
);
|
||||
|
||||
let irq_status = self.regs.INTERRUPT.get();
|
||||
self.regs.INTERRUPT.set(0xFFFF0001);
|
||||
|
||||
if irq_status & 0xFFFF0001 != 1 {
|
||||
if irq_status & 0xFFFF0000 != 0 {
|
||||
warnln!("SD error: irq_status={:#x}", irq_status);
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
if !INTERRUPT::CMD_DONE.is_set(irq_status) {
|
||||
warnln!("SD command did not report properly");
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
let response = if size_136 {
|
||||
SdResponse::Four([
|
||||
@@ -181,14 +276,22 @@ impl MmcInner {
|
||||
SdCommandTransfer::Read(buf, _) => {
|
||||
debugln!("Reading {} data blocks", block_count);
|
||||
for i in 0..block_count {
|
||||
while self.regs.INTERRUPT.get() & (0x8000 | (1 << 5)) == 0 {
|
||||
cortex_a::asm::nop();
|
||||
}
|
||||
crate::block!(
|
||||
self.regs
|
||||
.INTERRUPT
|
||||
.matches_any(INTERRUPT::ERR::SET + INTERRUPT::READ_RDY::SET),
|
||||
10000
|
||||
);
|
||||
let irq_status = self.regs.INTERRUPT.get();
|
||||
self.regs.INTERRUPT.set(0xFFFF0000 | (1 << 5));
|
||||
|
||||
if irq_status & (0xFFFF0000 | (1 << 5)) != (1 << 5) {
|
||||
todo!();
|
||||
if irq_status & 0xFFFF0000 != 0 {
|
||||
warnln!("SD error during data read: irq_status={:#x}", irq_status);
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
if !INTERRUPT::READ_RDY.is_set(irq_status) {
|
||||
warnln!("SD did not respond with data blocks");
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
assert!(block_size % 4 == 0);
|
||||
@@ -211,37 +314,29 @@ impl MmcInner {
|
||||
fn phys_reset(&mut self) -> Result<(), Errno> {
|
||||
self.status.phys_inserted = false;
|
||||
|
||||
let mut tmp = self.regs.CONTROL1.get();
|
||||
tmp |= 1 << 24;
|
||||
// Disable clock
|
||||
tmp &= !(1 << 2);
|
||||
tmp &= !(1 << 0);
|
||||
self.regs.CONTROL1.set(tmp);
|
||||
self.regs
|
||||
.CONTROL1
|
||||
.modify(CONTROL1::SRST_HC::SET + CONTROL1::CLK_EN::CLEAR + CONTROL1::CLK_INTLEN::CLEAR);
|
||||
|
||||
// Wait for SRST_HC to clear
|
||||
crate::block!(
|
||||
self.regs.CONTROL1.matches_all(CONTROL1::SRST_HC::CLEAR),
|
||||
10000
|
||||
);
|
||||
|
||||
//let mut tmp;
|
||||
|
||||
debugln!("Checking for a card");
|
||||
let mut retry = 5;
|
||||
let mut status = 0;
|
||||
|
||||
while retry > 0 {
|
||||
status = self.regs.STATUS.get();
|
||||
if status & 1 << 16 != 0 {
|
||||
break;
|
||||
crate::block!(
|
||||
self.regs.STATUS.matches_all(STATUS::MISC_INSERTED::SET),
|
||||
10000,
|
||||
{
|
||||
warnln!("No card inserted");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for _ in 0..100000 {
|
||||
cortex_a::asm::nop();
|
||||
}
|
||||
|
||||
retry -= 1;
|
||||
}
|
||||
|
||||
if retry == 0 {
|
||||
warnln!("No card inserted");
|
||||
return Ok(());
|
||||
}
|
||||
);
|
||||
|
||||
self.status.phys_inserted = true;
|
||||
debugln!("A card is present: status={:#x}", status);
|
||||
|
||||
self.regs.CONTROL2.set(0);
|
||||
|
||||
@@ -250,23 +345,31 @@ impl MmcInner {
|
||||
f_base = 100000000;
|
||||
}
|
||||
|
||||
let div = clock_divider(f_base, 400000)?;
|
||||
|
||||
let div = clock_divider(f_base, 400000);
|
||||
debugln!("Switching to ID frequency");
|
||||
|
||||
tmp = self.regs.CONTROL1.get();
|
||||
tmp |= div;
|
||||
tmp &= !(0xF << 16);
|
||||
tmp |= 11 << 16;
|
||||
tmp |= 4;
|
||||
tmp |= 1;
|
||||
self.regs.CONTROL1.set(tmp);
|
||||
let div_lsb = div & 0xFF;
|
||||
let div_msb = (div >> 8) & 0x3;
|
||||
self.regs.CONTROL1.modify(
|
||||
CONTROL1::CLK_FREQ8.val(div_lsb)
|
||||
+ CONTROL1::CLK_FREQ_MS2.val(div_msb)
|
||||
+ CONTROL1::DATA_TOUNIT.val(11)
|
||||
+ CONTROL1::CLK_EN::SET
|
||||
+ CONTROL1::CLK_INTLEN::SET,
|
||||
);
|
||||
|
||||
while self.regs.CONTROL1.get() & 1 << 1 == 0 {
|
||||
cortex_a::asm::nop();
|
||||
}
|
||||
crate::block!(
|
||||
self.regs.CONTROL1.matches_all(CONTROL1::CLK_STABLE::SET),
|
||||
100000,
|
||||
{
|
||||
warnln!("Controller clock did not stabilize in time");
|
||||
return Err(Errno::TimedOut);
|
||||
}
|
||||
);
|
||||
|
||||
// Do not forward any IRQs to ARM side
|
||||
self.regs.IRPT_EN.set(0);
|
||||
// Ack and unmask all interrupts to the controller
|
||||
self.regs.INTERRUPT.set(u32::MAX);
|
||||
self.regs.IRPT_MASK.set(u32::MAX);
|
||||
|
||||
@@ -329,17 +432,6 @@ impl SdHostController for MassMediaController {
|
||||
self.inner.get().lock().status.phys_inserted
|
||||
}
|
||||
|
||||
fn set_transfer_block_size(&self, blk: usize) -> Result<(), Errno> {
|
||||
// TODO other block sizes?
|
||||
assert_eq!(blk, 512);
|
||||
let inner = self.inner.get().lock();
|
||||
let mut tmp = inner.regs.BLKSIZECNT.get();
|
||||
tmp &= !0xFFF;
|
||||
tmp |= 0x200;
|
||||
inner.regs.BLKSIZECNT.set(tmp);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_card_address(&self, rca: u16) -> Result<(), Errno> {
|
||||
self.inner.get().lock().status.address = Some(rca);
|
||||
Ok(())
|
||||
|
||||
+78
-55
@@ -1,13 +1,12 @@
|
||||
use crate::dev::Device;
|
||||
use vfs::BlockDevice;
|
||||
use error::Errno;
|
||||
use vfs::BlockDevice;
|
||||
|
||||
pub trait SdHostController: Device + BlockDevice {
|
||||
// Physical layer
|
||||
fn send_cmd(&self, cmd: &mut SdCommand) -> Result<SdResponse, Errno>;
|
||||
fn phys_reset(&self) -> Result<(), Errno>;
|
||||
fn is_phys_inserted(&self) -> bool;
|
||||
fn set_transfer_block_size(&self, blk: usize) -> Result<(), Errno>;
|
||||
|
||||
// Data layer
|
||||
fn set_card_address(&self, rca: u16) -> Result<(), Errno>;
|
||||
@@ -21,22 +20,28 @@ pub trait SdHostController: Device + BlockDevice {
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?;
|
||||
|
||||
if self.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd8,
|
||||
argument: 0x1AA,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?.unwrap_one() != 0x1AA {
|
||||
if self
|
||||
.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd8,
|
||||
argument: 0x1AA,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?
|
||||
.unwrap_one()
|
||||
!= 0x1AA
|
||||
{
|
||||
warnln!("Card did not respond to CMD8");
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
// Set operating conditions
|
||||
for _ in 0..10 {
|
||||
let res = self.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Acmd41,
|
||||
argument: 0x00FF8000,
|
||||
transfer: SdCommandTransfer::None
|
||||
})?.unwrap_one();
|
||||
let res = self
|
||||
.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Acmd41,
|
||||
argument: 0x00FF8000,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?
|
||||
.unwrap_one();
|
||||
|
||||
if res & (1 << 31) != 0 {
|
||||
return Ok(());
|
||||
@@ -68,17 +73,21 @@ pub trait SdHostController: Device + BlockDevice {
|
||||
self.reset_card_probe()?;
|
||||
|
||||
// Perform init sequence
|
||||
let cmd2 = self.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd2,
|
||||
argument: 0,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?.unwrap_four();
|
||||
let cmd2 = self
|
||||
.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd2,
|
||||
argument: 0,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?
|
||||
.unwrap_four();
|
||||
|
||||
let cmd3 = self.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd3,
|
||||
argument: 0,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?.unwrap_one();
|
||||
let cmd3 = self
|
||||
.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd3,
|
||||
argument: 0,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?
|
||||
.unwrap_one();
|
||||
|
||||
let rca = (cmd3 >> 16) as u16;
|
||||
|
||||
@@ -96,11 +105,13 @@ pub trait SdHostController: Device + BlockDevice {
|
||||
warnln!("Card is not ready for data mode");
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
let cmd9 = self.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd9,
|
||||
argument: cmd3 & 0xFFFF0000,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?.unwrap_four();
|
||||
let cmd9 = self
|
||||
.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd9,
|
||||
argument: cmd3 & 0xFFFF0000,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?
|
||||
.unwrap_four();
|
||||
|
||||
debugln!("cmd9 = {:#x?}", cmd9);
|
||||
let csd_structure = (cmd9[3] >> 16) & 0x3;
|
||||
@@ -109,7 +120,7 @@ pub trait SdHostController: Device + BlockDevice {
|
||||
let c_size = ((cmd9[2] & 0x3) << 10) | ((cmd9[1] >> 22) & 0x3FF);
|
||||
let c_size_mult = (cmd9[1] >> 7) & 0x7;
|
||||
((c_size + 1) as u64) << (c_size_mult + 9 /* Block size is 512 */ + 2)
|
||||
},
|
||||
}
|
||||
1 => todo!(),
|
||||
_ => {
|
||||
warnln!("Invalid CSD version: {}", csd_structure);
|
||||
@@ -117,11 +128,13 @@ pub trait SdHostController: Device + BlockDevice {
|
||||
}
|
||||
};
|
||||
|
||||
let cmd7 = self.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd7,
|
||||
argument: cmd3 & 0xFFFF0000,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?.unwrap_one();
|
||||
let cmd7 = self
|
||||
.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Cmd7,
|
||||
argument: cmd3 & 0xFFFF0000,
|
||||
transfer: SdCommandTransfer::None,
|
||||
})?
|
||||
.unwrap_one();
|
||||
|
||||
let status = (cmd7 >> 9) & 0xF;
|
||||
if status != 3 && status != 4 {
|
||||
@@ -140,7 +153,7 @@ pub trait SdHostController: Device + BlockDevice {
|
||||
self.send_cmd(&mut SdCommand {
|
||||
number: SdCommandNumber::Acmd51,
|
||||
argument: 0,
|
||||
transfer: SdCommandTransfer::Read(&mut buf[..8], 8)
|
||||
transfer: SdCommandTransfer::Read(&mut buf[..8], 8),
|
||||
})?;
|
||||
|
||||
let sd_spec = buf[0] & 0xF;
|
||||
@@ -151,14 +164,14 @@ pub trait SdHostController: Device + BlockDevice {
|
||||
2 => {
|
||||
// FIXME check for 3.0/4.0
|
||||
SdCardVersion::Ver20
|
||||
},
|
||||
_ => panic!("Invalid version: {:#x}", sd_spec)
|
||||
}
|
||||
_ => panic!("Invalid version: {:#x}", sd_spec),
|
||||
};
|
||||
|
||||
let card_id = SdCardIdentification {
|
||||
id: cmd2,
|
||||
version,
|
||||
capacity
|
||||
capacity,
|
||||
};
|
||||
|
||||
self.set_card_identification(card_id)?;
|
||||
@@ -254,10 +267,14 @@ pub enum SdCommandNumber {
|
||||
Cmd55 = 55,
|
||||
}
|
||||
|
||||
pub struct SdCommandInfo {
|
||||
pub response_type: SdResponseType,
|
||||
}
|
||||
|
||||
pub enum SdCommandTransfer<'a> {
|
||||
None,
|
||||
Read(&'a mut [u8], u16),
|
||||
Write(&'a [u8], u16)
|
||||
Write(&'a [u8], u16),
|
||||
}
|
||||
|
||||
pub struct SdCommand<'a> {
|
||||
@@ -280,7 +297,7 @@ impl SdResponseType {
|
||||
pub const fn is_busy(self) -> bool {
|
||||
match self {
|
||||
Self::R1b | Self::R5b => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,40 +306,46 @@ impl SdResponse {
|
||||
pub fn unwrap_one(&self) -> u32 {
|
||||
match self {
|
||||
&SdResponse::One(v) => v,
|
||||
_ => panic!("Unexpected response type")
|
||||
_ => panic!("Unexpected response type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_four(&self) -> [u32; 4] {
|
||||
match self {
|
||||
&SdResponse::Four(v) => v,
|
||||
_ => panic!("Unexpected response type")
|
||||
_ => panic!("Unexpected response type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SdCommandInfo {
|
||||
pub const fn new(response_type: SdResponseType) -> Self {
|
||||
Self { response_type }
|
||||
}
|
||||
}
|
||||
|
||||
impl SdCommand<'_> {
|
||||
pub const fn response_type(&self) -> SdResponseType {
|
||||
pub const fn info_struct(&self) -> SdCommandInfo {
|
||||
match self.number {
|
||||
SdCommandNumber::Cmd0 => SdResponseType::None,
|
||||
SdCommandNumber::Cmd2 => SdResponseType::R2,
|
||||
SdCommandNumber::Cmd3 => SdResponseType::R6,
|
||||
SdCommandNumber::Cmd6 => SdResponseType::R1,
|
||||
SdCommandNumber::Cmd7 => SdResponseType::R1b,
|
||||
SdCommandNumber::Cmd8 => SdResponseType::R7,
|
||||
SdCommandNumber::Cmd9 => SdResponseType::R2,
|
||||
SdCommandNumber::Cmd16 => SdResponseType::R1,
|
||||
SdCommandNumber::Cmd17 => SdResponseType::R1,
|
||||
SdCommandNumber::Acmd41 => SdResponseType::R3,
|
||||
SdCommandNumber::Acmd51 => SdResponseType::R1,
|
||||
SdCommandNumber::Cmd55 => SdResponseType::R1,
|
||||
SdCommandNumber::Cmd0 => SdCommandInfo::new(SdResponseType::None),
|
||||
SdCommandNumber::Cmd2 => SdCommandInfo::new(SdResponseType::R2),
|
||||
SdCommandNumber::Cmd3 => SdCommandInfo::new(SdResponseType::R6),
|
||||
SdCommandNumber::Cmd6 => SdCommandInfo::new(SdResponseType::R1),
|
||||
SdCommandNumber::Cmd7 => SdCommandInfo::new(SdResponseType::R1b),
|
||||
SdCommandNumber::Cmd8 => SdCommandInfo::new(SdResponseType::R7),
|
||||
SdCommandNumber::Cmd9 => SdCommandInfo::new(SdResponseType::R2),
|
||||
SdCommandNumber::Cmd16 => SdCommandInfo::new(SdResponseType::R1),
|
||||
SdCommandNumber::Cmd17 => SdCommandInfo::new(SdResponseType::R1),
|
||||
SdCommandNumber::Acmd41 => SdCommandInfo::new(SdResponseType::R3),
|
||||
SdCommandNumber::Acmd51 => SdCommandInfo::new(SdResponseType::R1),
|
||||
SdCommandNumber::Cmd55 => SdCommandInfo::new(SdResponseType::R1),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn is_acmd(&self) -> bool {
|
||||
match self.number {
|
||||
SdCommandNumber::Acmd41 | SdCommandNumber::Acmd51 => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,3 +52,24 @@ impl<T> InitOnce<T> {
|
||||
|
||||
unsafe impl<T> Sync for InitOnce<T> {}
|
||||
|
||||
///
|
||||
#[macro_export]
|
||||
macro_rules! block {
|
||||
($cond:expr, $timeout:expr, $failure:expr) => {{
|
||||
use $crate::dev::timer::TimestampSource;
|
||||
let __deadline = $crate::arch::machine::local_timer().timestamp().unwrap()
|
||||
+ core::time::Duration::from_micros($timeout);
|
||||
loop {
|
||||
if $cond {
|
||||
break;
|
||||
}
|
||||
if $crate::arch::machine::local_timer().timestamp().unwrap() > __deadline {
|
||||
$failure
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
($cond:expr, $timeout:expr) => {
|
||||
crate::block!($cond, $timeout, return Err(error::Errno::TimedOut))
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user