refactor(rpi3/emmc): use tock_registers

This commit is contained in:
2021-10-27 22:59:08 +03:00
parent 39f2d12e32
commit 0e94785fe2
4 changed files with 292 additions and 155 deletions
+1
View File
@@ -10,4 +10,5 @@ pub enum Errno {
WouldBlock,
AlreadyExists,
NotImplemented,
TimedOut,
}
+192 -100
View File
@@ -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
View File
@@ -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,
}
}
+21
View File
@@ -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))
};
}