Skip to content

Commit

Permalink
sdmmc: some clean up before pull request
Browse files Browse the repository at this point in the history
Signed-off-by: Cheng <[email protected]>
  • Loading branch information
Cheng-Li1 committed Oct 22, 2024
1 parent 4c40e85 commit aec5d6b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 102 deletions.
26 changes: 17 additions & 9 deletions drivers/blk/sdmmc/sdmmc_hal/meson/meson_gx_mmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ use sel4_microkit::debug_println;

const SDIO_BASE: u64 = 0xffe05000; // Base address from DTS

macro_rules! div_round_up {
($n:expr, $d:expr) => {
(($n + $d - 1) / $d)
};
}

// Constants translated from the C version
// Clock related constant
const SD_EMMC_CLKSRC_24M: u32 = 24000000; // 24 MHz
const SD_EMMC_CLKSRC_DIV2: u32 = 1000000000; // 1 GHz

const CLK_MAX_DIV: u32 = 63;
const CLK_SRC_24M: u32 = 0 << 6;
const CLK_SRC_DIV2: u32 = 1 << 6;
Expand All @@ -21,12 +26,6 @@ const CLK_TX_PHASE_000: u32 = 0 << 10;
const CLK_TX_PHASE_180: u32 = 2 << 10;
const CLK_ALWAYS_ON: u32 = 1 << 24;

macro_rules! div_round_up {
($n:expr, $d:expr) => {
(($n + $d - 1) / $d)
};
}

// CMD_CFG constants
const CMD_CFG_CMD_INDEX_SHIFT: u32 = 24;
const CMD_CFG_RESP_128: u32 = 1 << 21;
Expand Down Expand Up @@ -167,7 +166,7 @@ impl MesonSdmmcRegisters {
/// * `mmc_clock` - The desired clock frequency in Hz.
/// * `is_sm1_soc` - A boolean indicating whether the SoC is an SM1 variant.
/// * For odorid C4, this is_sm1_soc is true
pub fn meson_mmc_config_clock(&mut self) {
fn meson_mmc_config_clock(&mut self, frequency: u32) {
// #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
let mut meson_mmc_clk:u32 = 0;

Expand All @@ -177,7 +176,7 @@ impl MesonSdmmcRegisters {
let clk: u32;
let clk_src: u32;
// 400 khz for init the card
let clock_freq: u32 = 400000;
let clock_freq: u32 = frequency;
if clock_freq > 16000000 {
clk = SD_EMMC_CLKSRC_DIV2;
clk_src = CLK_SRC_DIV2;
Expand All @@ -194,6 +193,7 @@ impl MesonSdmmcRegisters {
* Other SoCs use CLK_CO_PHASE_180 by default.
* It needs to find what is a proper value about each SoCs.
* Since we are using Odroid C4, we set phase to 270
* TODO: Config it as what Linux driver are doing
*/
meson_mmc_clk |= CLK_CO_PHASE_270;
meson_mmc_clk |= CLK_TX_PHASE_000;
Expand All @@ -204,6 +204,14 @@ impl MesonSdmmcRegisters {
unsafe { ptr::write_volatile(&mut self.clock, meson_mmc_clk); }
}

// Incomplete placeholder function, need regulator system to configure voltage
pub fn meson_set_ios(&mut self) {
/*
* This function should be able to adjust the voltage, frequency and number of data lanes in use
*
*/
}

// This function can be seen as a Rust version of meson_mmc_setup_cmd function in uboot
fn meson_mmc_set_up_cmd_cfg_and_cfg(&mut self, cmd: &SdmmcCmd, data: Option<&MmcData>) {
let mut meson_mmc_cmd: u32 = 0u32;
Expand Down
3 changes: 3 additions & 0 deletions drivers/blk/sdmmc/sdmmc_protocol/sdmmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ pub trait SdmmcHardware {
}
}

// Not used right now, but would be useful in the future once we want to execute some command synchronously
fn send_cmd_and_receive_resp<T: SdmmcHardware>(
hardware: &mut T,
cmd: &SdmmcCmd,
Expand Down Expand Up @@ -143,8 +144,10 @@ impl<'a, T: SdmmcHardware> SdmmcProtocol<'a, T> {
}
}

// Funtion that is not completed
pub fn reset_card(&mut self) -> Result<(), SdmmcHalError> {
let all: u32 = InterruptType::Success as u32 | InterruptType::Error as u32 | InterruptType::SDIO as u32;
todo!();
self.hardware.sdmmc_ack_interrupt(&all)
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/blk/sdmmc/sdmmc_protocol/sdmmc/sdmmc_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ pub const SD_CMD_APP_SD_STATUS: u32 = 13;
pub const SD_CMD_ERASE_WR_BLK_START: u32 = 32;
pub const SD_CMD_ERASE_WR_BLK_END: u32 = 33;
pub const SD_CMD_APP_SEND_OP_COND: u32 = 41;
pub const SD_CMD_APP_SEND_SCR: u32 = 51;
pub const SD_CMD_APP_SEND_SCR: u32 = 51;
157 changes: 71 additions & 86 deletions drivers/blk/sdmmc/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
#![no_std] // Don't link the standard library
#![no_std] // Don't link the standard library
#![no_main] // Don't use the default entry point

extern crate alloc;

mod sddf_blk;

use core::{future::Future, pin::Pin, task::{Context, Poll, RawWaker, RawWakerVTable, Waker}};
use core::{
future::Future,
pin::Pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

use alloc::boxed::Box;
use sddf_blk::{blk_dequeue_req_helper, blk_enqueue_resp_helper, blk_queue_empty_req_helper, blk_queue_full_resp_helper, blk_queue_init_helper, BlkOp, BlkRequest, BlkStatus};
use sddf_blk::{
blk_dequeue_req_helper, blk_enqueue_resp_helper, blk_queue_empty_req_helper,
blk_queue_full_resp_helper, blk_queue_init_helper, BlkOp, BlkRequest, BlkStatus,
};
use sdmmc_hal::meson_gx_mmc::MesonSdmmcRegisters;

use sdmmc_protocol::sdmmc::{InterruptType, SdmmcHalError, SdmmcHardware, SdmmcProtocol};
Expand All @@ -20,10 +27,12 @@ const INTERRUPT: sel4_microkit::Channel = sel4_microkit::Channel::new(1);

const SDCARD_SECTOR_SIZE: u32 = 512;
const SDDF_TRANSFER_SIZE: u32 = 4096;
const SDDF_TO_REAL_SECTOR: u32 = SDDF_TRANSFER_SIZE/SDCARD_SECTOR_SIZE;
const SDDF_TO_REAL_SECTOR: u32 = SDDF_TRANSFER_SIZE / SDCARD_SECTOR_SIZE;

const RETRY_CHANCE: u16 = 5;

// Debug function for printing out content in one block
#[allow(dead_code)]
fn print_one_block(ptr: *const u8) {
unsafe {
// Iterate over the 512 bytes and print each one in hexadecimal format
Expand All @@ -45,12 +54,7 @@ unsafe fn noop_clone(_data: *const ()) -> RawWaker {
}

// A VTable that points to the no-op functions
static VTABLE: RawWakerVTable = RawWakerVTable::new(
noop_clone,
noop,
noop,
noop,
);
static VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);

// Function to create a dummy Waker
fn create_dummy_waker() -> Waker {
Expand Down Expand Up @@ -78,7 +82,13 @@ fn init() -> HandlerImpl<'static, MesonSdmmcRegisters> {
}

struct HandlerImpl<'a, T: SdmmcHardware> {
future: Option<Pin<Box<dyn Future<Output = (Result<(), SdmmcHalError>, Option<SdmmcProtocol<'a, T>>)> + 'a>>>,
future: Option<
Pin<
Box<
dyn Future<Output = (Result<(), SdmmcHalError>, Option<SdmmcProtocol<'a, T>>)> + 'a,
>,
>,
>,
sdmmc: Option<SdmmcProtocol<'a, T>>,
request: Option<BlkRequest>,
retry: u16,
Expand All @@ -87,13 +97,15 @@ struct HandlerImpl<'a, T: SdmmcHardware> {
impl<'a, T: SdmmcHardware> Handler for HandlerImpl<'a, T> {
type Error = Infallible;

/// In Rust, it is actually very hard to manage long live future object that must be created
/// by borrowing
fn notified(&mut self, channel: Channel) -> Result<(), Self::Error> {
// debug_println!("SDMMC_DRIVER: MESSAGE FROM CHANNEL: {}", channel.index());

if channel.index() != INTERRUPT.index() && channel.index() != BLK_VIRTUALIZER.index() {
debug_println!("SDMMC_DRIVER: Unknown channel sent me message: {}", channel.index());
debug_println!(
"SDMMC_DRIVER: Unknown channel sent me message: {}",
channel.index()
);
return Ok(());
}

if channel.index() == INTERRUPT.index() {
Expand All @@ -110,32 +122,42 @@ impl<'a, T: SdmmcHardware> Handler for HandlerImpl<'a, T> {
if let Some(future) = &mut self.future {
let waker = create_dummy_waker();
let mut cx = Context::from_waker(&waker);
// TODO: I can get rid of this loop once I configure out how to enable interrupt from Linux kernel driver
// debug_println!("SDMMC_DRIVER: Polling future!");
match future.as_mut().poll(&mut cx) {
Poll::Ready((result, sdmmc)) => {
// debug_println!("SDMMC_DRIVER: Future completed with result");
self.future = None; // Reset the future once done
self.sdmmc = sdmmc;
if result.is_err() {
debug_println!("SDMMC_DRIVER: DISK ERROR ENCOUNTERED, possibly retry!");
debug_println!(
"SDMMC_DRIVER: DISK ERROR ENCOUNTERED, possibly retry!"
);
self.retry -= 1;
}
else {
} else {
// Deduct finished count from count
request.success_count += request.count_to_do;
request.count -= request.count_to_do as u16;
}
if request.count == 0 {
let resp_status = BlkStatus::BlkRespOk;
notify_virt = true;
// Have to divide the SDDF_TO_REAL_SECTOR here, we should really use real sector
unsafe { blk_enqueue_resp_helper(resp_status, request.success_count / SDDF_TO_REAL_SECTOR, request.id); }
unsafe {
blk_enqueue_resp_helper(
resp_status,
request.success_count / SDDF_TO_REAL_SECTOR,
request.id,
);
}
self.request = None;
} else if self.retry == 0 {
let resp_status = BlkStatus::BlkRespSeekError;
notify_virt = true;
unsafe { blk_enqueue_resp_helper(resp_status, request.success_count / SDDF_TO_REAL_SECTOR, request.id); }
unsafe {
blk_enqueue_resp_helper(
resp_status,
request.success_count / SDDF_TO_REAL_SECTOR,
request.id,
);
}
self.request = None;
}
}
Expand All @@ -148,7 +170,9 @@ impl<'a, T: SdmmcHardware> Handler for HandlerImpl<'a, T> {
}
}

while self.request.is_none() && unsafe { blk_queue_empty_req_helper() == 0 && blk_queue_full_resp_helper() == 0 } {
while self.request.is_none()
&& unsafe { blk_queue_empty_req_helper() == 0 && blk_queue_full_resp_helper() == 0 }
{
let mut request: BlkRequest = BlkRequest {
request_code: BlkOp::BlkReqFlush,
io_or_offset: 0,
Expand Down Expand Up @@ -188,7 +212,7 @@ impl<'a, T: SdmmcHardware> Handler for HandlerImpl<'a, T> {
self.retry = RETRY_CHANCE;
self.request = Some(request);
break;
},
}
_ => {
// For other request, enqueue response
notify_virt = true;
Expand All @@ -204,21 +228,35 @@ impl<'a, T: SdmmcHardware> Handler for HandlerImpl<'a, T> {
match request.request_code {
BlkOp::BlkReqRead => {
// TODO: The MAX_BLOCK_PER_TRANSFER is got by hackily get the defines in hardware layer which is wrong, check that to get properly from protocol layer
request.count_to_do = core::cmp::min(request.count as u32, sdmmc_hal::meson_gx_mmc::MAX_BLOCK_PER_TRANSFER);
request.count_to_do = core::cmp::min(
request.count as u32,
sdmmc_hal::meson_gx_mmc::MAX_BLOCK_PER_TRANSFER,
);
if let Some(sdmmc) = self.sdmmc.take() {
self.future = Some(Box::pin(sdmmc.read_block(request.count_to_do as u32, request.block_number as u64 + request.success_count as u64, request.io_or_offset + request.success_count as u64 * SDCARD_SECTOR_SIZE as u64)));
}
else {
self.future = Some(Box::pin(sdmmc.read_block(
request.count_to_do as u32,
request.block_number as u64 + request.success_count as u64,
request.io_or_offset
+ request.success_count as u64 * SDCARD_SECTOR_SIZE as u64,
)));
} else {
panic!("SDMMC_DRIVER: The sdmmc should be here and the future should be empty!!!")
}
}
BlkOp::BlkReqWrite => {
// TODO: The MAX_BLOCK_PER_TRANSFER is got by hackily get the defines in hardware layer which is wrong, check that to get properly from protocol layer
request.count_to_do = core::cmp::min(request.count as u32, sdmmc_hal::meson_gx_mmc::MAX_BLOCK_PER_TRANSFER);
request.count_to_do = core::cmp::min(
request.count as u32,
sdmmc_hal::meson_gx_mmc::MAX_BLOCK_PER_TRANSFER,
);
if let Some(sdmmc) = self.sdmmc.take() {
self.future = Some(Box::pin(sdmmc.write_block(request.count_to_do as u32, request.block_number as u64 + request.success_count as u64, request.io_or_offset + request.success_count as u64 * SDCARD_SECTOR_SIZE as u64)));
}
else {
self.future = Some(Box::pin(sdmmc.write_block(
request.count_to_do as u32,
request.block_number as u64 + request.success_count as u64,
request.io_or_offset
+ request.success_count as u64 * SDCARD_SECTOR_SIZE as u64,
)));
} else {
panic!("SDMMC_DRIVER: The sdmmc should be here and the future should be empty!!!")
}
}
Expand All @@ -227,8 +265,7 @@ impl<'a, T: SdmmcHardware> Handler for HandlerImpl<'a, T> {
}
}
}
}
else {
} else {
// If Request is empty, means there are no future available, so we do not need to poll again
break;
}
Expand All @@ -240,55 +277,3 @@ impl<'a, T: SdmmcHardware> Handler for HandlerImpl<'a, T> {
Ok(())
}
}

/*
// Code block to test block read
{
let test_hal: &mut MesonSdmmcRegisters = MesonSdmmcRegisters::new();
let test: SdmmcProtocol<'static, MesonSdmmcRegisters> = SdmmcProtocol::new(test_hal);
debug_println!("Read and Print out the content in sector 0, sector 1");
let mut future = Box::pin(test.read_block(2, 0, 0x50000000));
let waker = create_dummy_waker();
let mut cx = Context::from_waker(&waker);
let future_ref = &mut future;
// TODO: I can get rid of this loop once I configure out how to enable interrupt from Linux kernel driver
loop {
match future_ref.as_mut().poll(&mut cx) {
Poll::Ready((result, sdmmc)) => {
// debug_println!("SDMMC_DRIVER: Future completed with result");
if result.is_err() {
debug_println!("SDMMC_DRIVER: DISK ERROR ENCOUNTERED, possiblely retry!");
}
else {
debug_println!("Content in sector 0:");
print_one_block(0x50000000 as *const u8);
debug_println!("Content in sector 1:");
print_one_block((0x50000000 + 512) as *const u8);
}
break;
}
Poll::Pending => {
// debug_println!("SDMMC_DRIVER: Future is not ready, polling again...");
}
}
}
}
// Poll on the future once to start it up
let waker = create_dummy_waker();
let mut cx = Context::from_waker(&waker);
if let Some(new_future) = self.future {
let res = new_future.as_mut().poll(&mut cx);
// If the first poll on the future is not pending, why are you even use async then?
match res {
Poll::Pending => {
// The future is pending, this is the desired case
}
Poll::Ready(_) => {
// The future is ready, handle the result here if needed
panic!("Expected Poll::Pending but got Poll::Ready. Why are you even use async if the first poll on the future is not pending?");
}
}
}
*/
14 changes: 8 additions & 6 deletions drivers/blk/sdmmc/src/sddf_blk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ extern "C" {
pub fn blk_queue_empty_req_helper() -> u8;
pub fn blk_queue_full_resp_helper() -> u8;
pub fn blk_enqueue_resp_helper(status: BlkStatus, success: u32, id: u32) -> u8;
pub fn blk_dequeue_req_helper(code: *mut BlkOp,
io_or_offset: *mut u64,
block_number: *mut u32,
count: *mut u16,
id: *mut u32);
pub fn blk_dequeue_req_helper(
code: *mut BlkOp,
io_or_offset: *mut u64,
block_number: *mut u32,
count: *mut u16,
id: *mut u32,
);
}

#[repr(C)]
Expand All @@ -34,4 +36,4 @@ pub struct BlkRequest {
pub success_count: u32,
pub count_to_do: u32,
pub id: u32,
}
}

0 comments on commit aec5d6b

Please sign in to comment.