mmc_disk: add SDHC support.

The main differences:
- The initialization sequence requires an additional command (this was
  already done)
- The layout of the CSD register and the way to compute the device
  geometry from it changes
- The read and write commands parameter is a sector number instead of a
  byte position

Change-Id: Ie729e333c9748f36b37acd70c970adfd425cf0b6
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3512
Reviewed-by: Alex von Gluck IV <kallisti5@unixzen.com>
This commit is contained in:
Adrien Destugues 2020-12-15 21:22:37 +01:00 committed by waddlesplash
parent e21a1abec4
commit d1fee57dee
7 changed files with 59 additions and 19 deletions

View File

@ -76,7 +76,7 @@ typedef struct mmc_bus_interface {
uint32_t argument, uint32_t* result);
// Execute a command with no I/O phase
status_t (*do_io)(void* controller, uint8_t command,
IOOperation* operation);
IOOperation* operation, bool offsetAsSectors);
// Execute a command that involves a data transfer.
} mmc_bus_interface;
@ -92,7 +92,7 @@ typedef struct mmc_device_interface {
uint32_t argument, uint32_t* result);
// Execute a command with no I/O phase
status_t (*do_io)(device_node* controller, uint16_t rca,
uint8_t command, IOOperation* operation);
uint8_t command, IOOperation* operation, bool offsetAsSectors);
// Execute a command that involves a data transfer.
} mmc_device_interface;

View File

@ -86,12 +86,13 @@ MMCBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
status_t
MMCBus::DoIO(uint16_t rca, uint8_t command, IOOperation* operation)
MMCBus::DoIO(uint16_t rca, uint8_t command, IOOperation* operation,
bool offsetAsSectors)
{
status_t status = _ActivateDevice(rca);
if (status != B_OK)
return status;
return fController->do_io(fCookie, command, operation);
return fController->do_io(fCookie, command, operation, offsetAsSectors);
}

View File

@ -44,7 +44,8 @@ public:
status_t ExecuteCommand(uint8_t command,
uint32_t argument, uint32_t* response);
status_t DoIO(uint16_t rca, uint8_t command,
IOOperation* operation);
IOOperation* operation,
bool offsetAsSectors);
void AcquireBus() { acquire_sem(fLockSemaphore); }
void ReleaseBus() { release_sem(fLockSemaphore); }

View File

@ -104,7 +104,7 @@ mmc_bus_execute_command(device_node* node, uint8_t command, uint32_t argument,
static status_t
mmc_bus_do_io(device_node* node, uint16_t rca, uint8_t command,
IOOperation* operation)
IOOperation* operation, bool offsetAsSectors)
{
driver_module_info* mmc;
void* cookie;
@ -119,7 +119,7 @@ mmc_bus_do_io(device_node* node, uint16_t rca, uint8_t command,
bus->AcquireBus();
status_t result = B_OK;
result = bus->DoIO(rca, command, operation);
result = bus->DoIO(rca, command, operation, offsetAsSectors);
bus->ReleaseBus();
return result;

View File

@ -52,7 +52,8 @@ class SdhciBus {
status_t InitCheck();
void Reset();
void SetClock(int kilohertz);
status_t DoIO(uint8_t command, IOOperation* operation);
status_t DoIO(uint8_t command, IOOperation* operation,
bool offsetAsSectors);
private:
bool PowerOn();
@ -340,7 +341,7 @@ SdhciBus::SetClock(int kilohertz)
status_t
SdhciBus::DoIO(uint8_t command, IOOperation* operation)
SdhciBus::DoIO(uint8_t command, IOOperation* operation, bool offsetAsSectors)
{
bool isWrite = operation->IsWrite();
@ -385,8 +386,6 @@ SdhciBus::DoIO(uint8_t command, IOOperation* operation)
while (length > 0) {
size_t toCopy = std::min((generic_size_t)length,
vecs->length - vecOffset);
TRACE("Loop %ld bytes from position %ld to %p\n", toCopy, offset,
vecs->base + vecOffset);
// If the current vec is empty, we can move to the next
if (toCopy == 0) {
@ -413,7 +412,8 @@ SdhciBus::DoIO(uint8_t command, IOOperation* operation)
| TransferMode::kBlockCountEnable | TransferMode::kDmaEnable;
uint32_t response;
result = ExecuteCommand(command, offset, &response);
result = ExecuteCommand(command,
offset / (offsetAsSectors ? kBlockSize : 1), &response);
if (result != B_OK)
break;
@ -817,12 +817,13 @@ execute_command(void* controller, uint8_t command, uint32_t argument,
static status_t
do_io(void* controller, uint8_t command, IOOperation* operation)
do_io(void* controller, uint8_t command, IOOperation* operation,
bool offsetAsSectors)
{
CALLED();
SdhciBus* bus = (SdhciBus*)controller;
return bus->DoIO(command, operation);
return bus->DoIO(command, operation, offsetAsSectors);
}

View File

@ -43,15 +43,29 @@ static device_manager_info* sDeviceManager;
struct mmc_disk_csd {
// The content of this register is described in Physical Layer Simplified
// Specification Version 8.00, section 5.3
uint64 bits[2];
uint8 structure_version() { return bits[1] >> 60; }
uint8 structure_version() { return bits[1] >> 54; }
uint8 read_bl_len() { return (bits[1] >> 8) & 0xF; }
uint16 c_size()
uint32 c_size()
{
return ((bits[0] >> 54) & 0x3FF) | ((bits[1] & 0x3) << 10);
if (structure_version() == 0)
return ((bits[0] >> 54) & 0x3FF) | ((bits[1] & 0x3) << 10);
if (structure_version() == 1)
return (bits[0] >> 40) & 0x3FFFFF;
return ((bits[0] >> 40) & 0xFFFFFF) | ((bits[1] & 0xF) << 24);
}
uint8 c_size_mult()
{
if (structure_version() == 0)
return (bits[0] >> 39) & 0x7;
// In later versions this field is not present in the structure and a
// fixed value is used.
return 8;
}
uint8 c_size_mult() { return (bits[0] >> 39) & 0x7; }
};
@ -115,7 +129,8 @@ mmc_disk_execute_iorequest(void* data, IOOperation* operation)
command = SD_WRITE_MULTIPLE_BLOCKS;
else
command = SD_READ_MULTIPLE_BLOCKS;
error = info->mmc->do_io(info->parent, info->rca, command, operation);
error = info->mmc->do_io(info->parent, info->rca, command, operation,
(info->flags & kIoCommandOffsetAsSectors) != 0);
if (error != B_OK) {
info->scheduler->OperationCompleted(operation, error, 0);
@ -185,6 +200,21 @@ mmc_disk_init_driver(device_node* node, void** cookie)
return B_BAD_DATA;
}
uint8_t deviceType;
if (sDeviceManager->get_attr_uint8(info->parent, kMmcTypeAttribute,
&deviceType, true) != B_OK) {
ERROR("Could not get device type\n");
free(info);
return B_BAD_DATA;
}
// SD and MMC cards use byte offsets for IO commands, later ones (SDHC,
// SDXC, ...) use sectors.
if (deviceType == CARD_TYPE_SD || deviceType == CARD_TYPE_MMC)
info->flags = 0;
else
info->flags = kIoCommandOffsetAsSectors;
static const uint32 kBlockSize = 512; // FIXME get it from the CSD
status_t error;

View File

@ -20,12 +20,19 @@
#include "IOSchedulerSimple.h"
enum MMCDiskFlags {
kIoCommandOffsetAsSectors = 1,
// IO commands use sector offsets instead of byte offsets
};
// This is the device info structure, allocated once per device
typedef struct {
device_node* node;
device_node* parent;
mmc_device_interface* mmc;
uint16_t rca;
uint32_t flags;
device_geometry geometry;