From d1fee57deec586903e32d05712a78c093323335f Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 15 Dec 2020 21:22:37 +0100 Subject: [PATCH] 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 --- headers/private/drivers/mmc.h | 4 +- .../kernel/bus_managers/mmc/mmc_bus.cpp | 5 ++- src/add-ons/kernel/bus_managers/mmc/mmc_bus.h | 3 +- .../kernel/bus_managers/mmc/mmc_module.cpp | 4 +- src/add-ons/kernel/busses/mmc/sdhci_pci.cpp | 15 +++---- .../kernel/drivers/disk/mmc/mmc_disk.cpp | 40 ++++++++++++++++--- .../kernel/drivers/disk/mmc/mmc_disk.h | 7 ++++ 7 files changed, 59 insertions(+), 19 deletions(-) diff --git a/headers/private/drivers/mmc.h b/headers/private/drivers/mmc.h index 6449b75de3..1fdfbbd0a5 100644 --- a/headers/private/drivers/mmc.h +++ b/headers/private/drivers/mmc.h @@ -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; diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp index 15693363c4..3b34c93daa 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp @@ -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); } diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h index fa8c3f3830..f3809181a8 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h @@ -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); } diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp b/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp index d3186d771f..8434a5dfb9 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp @@ -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; diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp index cf318eb022..6b564dcbc5 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp @@ -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); } diff --git a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp index a04eff7334..6b0511193e 100644 --- a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp @@ -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; diff --git a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.h b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.h index a1efd4a743..8f82daba5f 100644 --- a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.h +++ b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.h @@ -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;