use aligned::{A4, Aligned};
use embedded_hal_async::delay::DelayNs;
pub use crate::common::*;
use crate::{
Addressable, BlockCommand, BlockDevice, BlockReadCommand, BusAdapter, BusWidth, Command,
ControlCommand, INIT_FREQ, MmcBus, MmcError, R1, R1b, R3, common,
};
use core::{convert::TryInto, fmt, marker::PhantomData, str};
pub struct Cmd1 {
pub ocr: u32,
}
impl Command for Cmd1 {
const INDEX: u8 = 1;
type Resp<'a> = R3;
fn arg(&self) -> u32 {
self.ocr
}
}
impl ControlCommand for Cmd1 {}
pub struct Cmd3 {
pub address: u16,
}
impl Command for Cmd3 {
const INDEX: u8 = 3;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
(self.address as u32) << 16
}
}
impl ControlCommand for Cmd3 {}
pub fn assign_relative_address(address: u16) -> Cmd3 {
Cmd3 { address }
}
pub fn send_op_cond(ocr: u32) -> Cmd1 {
Cmd1 { ocr }
}
pub struct Cmd5 {
pub sleep: bool,
pub rca: u16,
}
impl Command for Cmd5 {
const INDEX: u8 = 5;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
((self.sleep as u32) << 15) | ((self.rca as u32) << 16)
}
}
impl ControlCommand for Cmd5 {}
pub struct Cmd6 {
pub access: u8, pub index: u8, pub value: u8, pub cmd_set: u8, }
impl Command for Cmd6 {
const INDEX: u8 = 6;
type Resp<'a> = R1b; fn arg(&self) -> u32 {
((self.access as u32) << 24)
| ((self.index as u32) << 16)
| ((self.value as u32) << 8)
| (self.cmd_set as u32)
}
}
impl ControlCommand for Cmd6 {}
pub enum AccessMode {
SetBits = 0b01,
ClearBits = 0b10,
WriteByte = 0b11,
}
pub fn modify_ext_csd(access_mode: AccessMode, index: u8, value: u8) -> Cmd6 {
Cmd6 {
access: access_mode as u8,
index,
value,
cmd_set: 0,
}
}
pub struct Cmd8<'a> {
pub buf: &'a mut Aligned<A4, [u8; 512]>,
}
impl<'a> Command for Cmd8<'a> {
const INDEX: u8 = 8;
type Resp<'b>
= R1
where
Self: 'b;
fn arg(&self) -> u32 {
0
}
}
impl<'a> BlockCommand for Cmd8<'a> {
fn block_size(&self) -> u16 {
512
}
fn block_count(&self) -> u32 {
1
}
}
impl<'a> BlockReadCommand for Cmd8<'a> {
fn buf(&mut self) -> &mut Aligned<A4, [u8]> {
&mut *self.buf
}
}
pub fn send_ext_csd(ext_csd: &mut ExtCSD) -> Cmd8<'_> {
Cmd8 {
buf: &mut ext_csd.inner,
}
}
pub struct Cmd35 {
pub addr: u32,
}
impl Command for Cmd35 {
const INDEX: u8 = 35;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
self.addr
}
}
impl ControlCommand for Cmd35 {}
pub struct Cmd36 {
pub addr: u32,
}
impl Command for Cmd36 {
const INDEX: u8 = 36;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
self.addr
}
}
impl ControlCommand for Cmd36 {}
pub struct Cmd39 {
pub addr: u8,
pub data: u8,
}
impl Command for Cmd39 {
const INDEX: u8 = 39;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
((self.addr as u32) << 8) | (self.data as u32)
}
}
impl ControlCommand for Cmd39 {}
pub struct Cmd40;
impl Command for Cmd40 {
const INDEX: u8 = 40;
type Resp<'a> = R1;
fn arg(&self) -> u32 {
0
}
}
impl ControlCommand for Cmd40 {}
#[derive(Clone, Copy, Default, Debug)]
pub struct EMMC;
impl OCR<EMMC> {
pub fn is_dual_voltage_card(&self) -> bool {
self.0 & 0x0000_0080 != 0
}
pub fn access_mode(&self) -> u8 {
(self.0 & 0x6000_0000 >> 29) as u8
}
}
impl fmt::Debug for OCR<EMMC> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OCR: Operation Conditions Register")
.field(
"Dual Voltage",
&if self.is_dual_voltage_card() {
"yes"
} else {
"no"
},
)
.field(
"Access mode",
&match self.access_mode() {
0b00 => "byte",
0b10 => "sector",
_ => "unknown",
},
)
.field("Busy", &self.is_busy())
.finish()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DeviceType {
RemovableDevice = 0b00,
BGA = 0b01,
POP = 0b10,
Unknown = 0b11,
}
impl CID<EMMC> {
pub fn device_type(&self) -> DeviceType {
match self.bytes[1] & 0x3 {
0b00 => DeviceType::RemovableDevice,
0b01 => DeviceType::BGA,
0b10 => DeviceType::POP,
_ => DeviceType::POP,
}
}
pub fn oem_application_id(&self) -> u8 {
self.bytes[2]
}
pub fn product_name(&self) -> &str {
str::from_utf8(&self.bytes[3..9]).unwrap_or(&"<ERR>")
}
pub fn product_revision(&self) -> (u8, u8) {
let major = (self.bytes[9] & 0xF0) >> 4;
let minor = self.bytes[9] & 0x0F;
(major, minor)
}
pub fn serial(&self) -> u32 {
(self.inner() >> 16) as u32
}
pub fn manufacturing_date(&self) -> (u8, u8) {
let month = (self.inner() >> 12) as u8 & 0xF;
let year = (self.inner() >> 8) as u8 & 0xF;
(month, year)
}
}
impl fmt::Debug for CID<EMMC> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CID: Card Identification")
.field("Manufacturer ID", &self.manufacturer_id())
.field("Device Type", &self.device_type())
.field("OEM ID", &self.oem_application_id())
.field("Product Name", &self.product_name())
.field("Product Revision", &self.product_revision())
.field("Product Serial Number", &self.serial())
.field("Manufacturing Date", &self.manufacturing_date())
.finish()
}
}
impl CSD<EMMC> {
pub fn erase_size_blocks(&self) -> u32 {
let erase_grp_size = (self.0 >> 42) & 0x1F;
let erase_grp_mult = (self.0 >> 37) & 0x1F;
(erase_grp_size as u32 + 1) + (erase_grp_mult as u32 + 1)
}
}
impl fmt::Debug for CSD<EMMC> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CSD: Card Specific Data")
.field("Transfer Rate", &self.transfer_rate())
.field("Read I (@min VDD)", &self.read_current_minimum_vdd())
.field("Write I (@min VDD)", &self.write_current_minimum_vdd())
.field("Read I (@max VDD)", &self.read_current_maximum_vdd())
.field("Write I (@max VDD)", &self.write_current_maximum_vdd())
.field("Erase Size (Blocks)", &self.erase_size_blocks())
.finish()
}
}
impl CardStatus<EMMC> {
pub fn switch_error(&self) -> bool {
self.0 & 0x80 != 0
}
pub fn exception_event(&self) -> bool {
self.0 & 0x40 != 0
}
}
impl fmt::Debug for CardStatus<EMMC> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Card Status")
.field("Out of range error", &self.out_of_range())
.field("Address error", &self.address_error())
.field("Block len error", &self.block_len_error())
.field("Erase seq error", &self.erase_seq_error())
.field("Erase param error", &self.erase_param())
.field("Write protect error", &self.wp_violation())
.field("Card locked", &self.card_is_locked())
.field("Password lock unlock error", &self.lock_unlock_failed())
.field(
"Crc check for the previous command failed",
&self.com_crc_error(),
)
.field("Illegal command", &self.illegal_command())
.field("Card internal ecc failed", &self.card_ecc_failed())
.field("Internal card controller error", &self.cc_error())
.field("General Error", &self.error())
.field("Csd error", &self.csd_overwrite())
.field("Write protect error", &self.wp_erase_skip())
.field("Erase sequence cleared", &self.erase_reset())
.field("Card state", &self.state())
.field("Buffer empty", &self.ready_for_data())
.field("Switch error", &self.switch_error())
.field("Exception event", &self.exception_event())
.field("Card expects app cmd", &self.app_cmd())
.finish()
}
}
#[derive(Clone, Copy)]
pub struct ExtCSD {
pub inner: Aligned<A4, [u8; 512]>,
}
impl Default for ExtCSD {
fn default() -> Self {
Self::new()
}
}
impl ExtCSD {
#[inline]
pub const fn new() -> Self {
Self {
inner: Aligned([0u8; 512]),
}
}
fn inner_word(&self, i: usize) -> u32 {
u32::from_le_bytes(self.inner[i * 4..i * 4 + 4].try_into().unwrap())
}
pub fn boot_info(&self) -> u8 {
(self.inner_word(57) >> 24) as u8
}
pub fn sleep_awake_timeout(&self) -> u8 {
(self.inner_word(54) >> 16) as u8
}
pub fn sleep_notification_time(&self) -> u8 {
(self.inner_word(54) >> 24) as u8
}
pub fn sector_count(&self) -> u32 {
self.inner_word(53)
}
pub fn driver_strength(&self) -> u8 {
(self.inner_word(49) >> 16) as u8
}
pub fn card_type(&self) -> u8 {
(self.inner_word(49) >> 24) as u8
}
pub fn csd_structure_version(&self) -> u8 {
(self.inner_word(48) >> 8) as u8
}
pub fn extended_csd_revision(&self) -> u8 {
(self.inner_word(48) >> 24) as u8
}
pub fn data_sector_size(&self) -> u8 {
(self.inner_word(15) >> 16) as u8
}
pub fn secure_removal_type(&self) -> u8 {
(self.inner_word(4) >> 24) as u8
}
}
impl fmt::Debug for ExtCSD {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Extended CSD")
.field("Boot Info", &self.boot_info())
.field("Sleep/Awake Timeout", &self.sleep_awake_timeout())
.field("Sleep Notification Time", &self.sleep_notification_time())
.field("Sector Count", &self.sector_count())
.field("Driver Strength", &self.driver_strength())
.field("Card Type", &self.card_type())
.field("CSD Structure Version", &self.csd_structure_version())
.field("Extended CSD Revision", &self.extended_csd_revision())
.field("Sector Size", &self.data_sector_size())
.field("Secure removal type", &self.secure_removal_type())
.finish()
}
}
impl From<u16> for RCA<EMMC> {
fn from(address: u16) -> Self {
Self((address as u32) << 16, PhantomData)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Emmc {
pub capacity: CardCapacity,
pub ocr: OCR<EMMC>,
pub cid: CID<EMMC>,
pub csd: CSD<EMMC>,
pub ext_csd: ExtCSD,
}
impl Addressable for Emmc {
type Ext = EMMC;
fn get_capacity(&self) -> CardCapacity {
self.capacity
}
fn size(&self) -> u64 {
u64::from(self.ext_csd.sector_count()) * 512
}
fn supports_cmd23(&self) -> bool {
true }
}
impl<B: MmcBus, D: DelayNs, const BLOCK_SIZE: usize> BlockDevice<Emmc, B, D, BLOCK_SIZE> {
pub async fn new_emmc(bus: B, freq: u32, delay: D) -> Result<Self, MmcError> {
let mut s = Self::new_uninit_emmc(bus, delay);
s.acquire(freq).await?;
Ok(s)
}
pub fn new_uninit_emmc(bus: B, delay: D) -> Self {
Self {
info: Emmc::default(),
bus: BusAdapter { bus, delay, rca: 0 },
}
}
pub async fn reacquire(&mut self, freq: u32) -> Result<(), MmcError> {
self.acquire(freq).await
}
async fn acquire(&mut self, freq: u32) -> Result<(), MmcError> {
let freq = freq.clamp(0, self.bus.bus.supports_frequency());
let bus_width = self.bus.bus.supports_bus_width();
self.bus.bus.init_idle(INIT_FREQ).await?;
self.bus.send_command(common::idle(), false).await?;
let mut i = 0;
let ocr = loop {
let high_voltage = 0b0 << 7;
let access_mode = 0b10 << 29;
let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15;
let ocr: OCR<EMMC> = self
.bus
.send_command(send_op_cond(op_cond), false)
.await?
.into();
if !ocr.is_busy() {
break ocr;
} else if i > 750 {
return Err(MmcError::Timeout);
}
self.bus.delay.delay_ms(1).await;
i += 1;
};
self.info.capacity = if ocr.access_mode() == 0b10 {
CardCapacity::HighCapacity
} else {
CardCapacity::StandardCapacity
};
self.info.ocr = ocr;
self.info.cid = self
.bus
.send_command(common::all_send_cid(), false)
.await?
.into();
self.bus.rca = 1u16.into();
self.bus
.send_command(assign_relative_address(self.bus.rca), false)
.await?;
self.info.csd = self
.bus
.send_command(common::send_csd(self.bus.rca), false)
.await?
.into();
self.bus.select_card(Some(self.bus.rca)).await?;
let widbus = match bus_width {
BusWidth::W1 => 0,
BusWidth::W4 => 1,
BusWidth::W8 => 2,
};
self.bus
.send_command(modify_ext_csd(AccessMode::WriteByte, 183, widbus), false)
.await?;
self.bus.bus.set_bus(bus_width, freq).await?;
self.bus
.read_blocks(send_ext_csd(&mut self.info.ext_csd), false)
.await?;
Ok(())
}
}