From Adrien Destugues <pulkomandy@xxxxxxxxx>:
Adrien Destugues has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/3630 ;)
Change subject: sd/mmc: enable 4-bit data transfers
......................................................................
sd/mmc: enable 4-bit data transfers
It works, but performance is still unexpectedly low (getting about
50kB/s write speed) with almost no CPU load.
---
M headers/private/drivers/mmc.h
M src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp
M src/add-ons/kernel/bus_managers/mmc/mmc_bus.h
M src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp
M src/add-ons/kernel/busses/mmc/sdhci_pci.cpp
M src/add-ons/kernel/busses/mmc/sdhci_pci.h
M src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp
7 files changed, 93 insertions(+), 7 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/30/3630/1
diff --git a/headers/private/drivers/mmc.h b/headers/private/drivers/mmc.h
index 98fd6ab..0bf8320 100644
--- a/headers/private/drivers/mmc.h
+++ b/headers/private/drivers/mmc.h
@@ -81,6 +81,8 @@
// Execute a command that involves a data transfer.
void (*set_scan_semaphore)(void* controller, sem_id sem);
// Pass the semaphore used for device rescan to the bus
controller
+ void (*set_bus_width)(void* controller, int width);
+ // Set the data bus width to 1, 4 or 8 bit mode.
} mmc_bus_interface;
@@ -97,6 +99,8 @@
status_t (*do_io)(device_node* controller, uint16_t rca,
uint8_t command, IOOperation* operation, bool offsetAsSectors);
// Execute a command that involves a data transfer.
+ void (*set_bus_width)(device_node* controller, int width);
+ // Set the data bus width to 1, 4 or 8 bit mode.
} 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 448304a..45124d2 100644
--- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp
+++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp
@@ -106,6 +106,13 @@
}
+void
+MMCBus::SetBusWidth(int width)
+{
+ fController->set_bus_width(fCookie, width);
+}
+
+
status_t
MMCBus::_ActivateDevice(uint16_t rca)
{
@@ -151,6 +158,12 @@
status_t result;
do {
bus->_AcquireScanSemaphore();
+
+ // In case we just got a "card inserted", wait for things to
settle
+ // a bit before continuing (there can be glitches while the
card is
+ // being inserted)
+ snooze(30000);
+
TRACE("Reset the bus...\n");
result = bus->ExecuteCommand(0, SD_GO_IDLE_STATE, 0, NULL);
TRACE("CMD0 result: %s\n", strerror(result));
@@ -158,14 +171,16 @@
// Need to wait at least 8 clock cycles after CMD0 before sending the
next
// command. With the default 400kHz clock that would be 20 microseconds,
- // but apparently we need more.
+ // but we need to wait at least 20ms here, otherwise the next command
times
+ // out
snooze(20000);
while (bus->fStatus != B_SHUTTING_DOWN) {
TRACE("Scanning the bus\n");
- // Use the low speed clock for scanning
+ // Use the low speed clock and 1bit bus width for scanning
bus->SetClock(400);
+ bus->SetBusWidth(1);
// Probe the voltage range
enum {
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 fe42c06..0adc3b9 100644
--- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h
+++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h
@@ -48,6 +48,7 @@
bool
offsetAsSectors);
void SetClock(int frequency);
+ void SetBusWidth(int width);
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 e09d4cc..a1bac8d 100644
--- a/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp
+++ b/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp
@@ -124,6 +124,26 @@
}
+static void
+mmc_bus_set_width(device_node* node, int width)
+{
+ driver_module_info* mmc;
+ void* cookie;
+
+ // FIXME store the parent cookie in the bus cookie or something instead
of
+ // getting/putting the parent each time.
+ device_node* parent = gDeviceManager->get_parent_node(node);
+ gDeviceManager->get_driver(parent, &mmc, &cookie);
+ gDeviceManager->put_node(parent);
+
+ MMCBus* bus = (MMCBus*)cookie;
+
+ bus->AcquireBus();
+ bus->SetBusWidth(width);
+ bus->ReleaseBus();
+}
+
+
static status_t
std_ops(int32 op, ...)
{
@@ -174,7 +194,8 @@
NULL
},
mmc_bus_execute_command,
- mmc_bus_do_io
+ mmc_bus_do_io,
+ mmc_bus_set_width
};
diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp
b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp
index 92d1332..49cc82d 100644
--- a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp
+++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp
@@ -56,6 +56,7 @@
status_t DoIO(uint8_t command,
IOOperation* operation,
bool
offsetAsSectors);
void SetScanSemaphore(sem_id sem);
+ void SetBusWidth(int width);
private:
bool PowerOn();
@@ -389,7 +390,7 @@
off_t offset = operation->Offset();
generic_size_t length = operation->Length();
- TRACE("%s %" B_PRIuSIZE " bytes at %" B_PRIdOFF "\n",
+ TRACE("%s %lld bytes at %" B_PRIdOFF "\n",
isWrite ? "Write" : "Read", length, offset);
// Check that the IO scheduler did its job in following our DMA
restrictions
@@ -489,6 +490,28 @@
}
+void
+SdhciBus::SetBusWidth(int width)
+{
+ uint8_t widthBits;
+ switch(width) {
+ case 1:
+ widthBits = HostControl::kDataTransfer1Bit;
+ break;
+ case 4:
+ widthBits = HostControl::kDataTransfer4Bit;
+ break;
+ case 8:
+ widthBits = HostControl::kDataTransfer8Bit;
+ break;
+ default:
+ panic("Incorrect bitwidth value");
+ return;
+ }
+ fRegisters->host_control.SetDataTransferWidth(widthBits);
+}
+
+
bool
SdhciBus::PowerOn()
{
@@ -962,6 +985,16 @@
}
+static void
+set_bus_width(void* controller, int width)
+{
+ CALLED();
+
+ SdhciBus* bus = (SdhciBus*)controller;
+ return bus->SetBusWidth(width);
+}
+
+
module_dependency module_dependencies[] = {
{ MMC_BUS_MODULE_NAME, (module_info**)&gMMCBusController},
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
@@ -990,7 +1023,8 @@
set_clock,
execute_command,
do_io,
- set_scan_semaphore
+ set_scan_semaphore,
+ set_bus_width
};
diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.h
b/src/add-ons/kernel/busses/mmc/sdhci_pci.h
index ec5d0ad..381e503 100644
--- a/src/add-ons/kernel/busses/mmc/sdhci_pci.h
+++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.h
@@ -224,10 +224,20 @@
value = (value & ~kDmaMask) | dmaMode;
}
+ void SetDataTransferWidth(uint8_t width)
+ {
+ value = (value & ~kDataTransferWidthMask) | width;
+ }
+
static const uint8_t kDmaMask = 3 << 3;
static const uint8_t kSdma = 0 << 3;
static const uint8_t kAdma32 = 2 << 3;
static const uint8_t kAdma64 = 3 << 3;
+
+ static const uint8_t kDataTransferWidthMask = 0x22;
+ static const uint8_t kDataTransfer1Bit = 0;
+ static const uint8_t kDataTransfer4Bit = 2;
+ static const uint8_t kDataTransfer8Bit = 0x20;
private:
volatile uint8_t value;
} __attribute__((packed));
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 c80d7fc..9d2c8d2 100644
--- a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp
+++ b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp
@@ -170,7 +170,6 @@
geometry->read_only = false; // TODO check write protect switch?
geometry->write_once = false;
-#if 0
// This function will be called before all data transfers, so we use
this
// opportunity to switch the card to 4-bit data transfers (instead of
the
// default 1 bit mode)
@@ -180,7 +179,9 @@
info->rca << 16, &cardStatus);
info->mmc->execute_command(info->parent, info->rca, SD_SET_BUS_WIDTH,
k4BitMode, &cardStatus);
-#endif
+
+ // From now on we use 4 bit mode
+ info->mmc->set_bus_width(info->parent, 4);
return B_OK;
}
--
To view, visit https://review.haiku-os.org/c/haiku/+/3630
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: I7da3ee70c8b379c4e6c2250d67f880c78635874f
Gerrit-Change-Number: 3630
Gerrit-PatchSet: 1
Gerrit-Owner: Adrien Destugues <pulkomandy@xxxxxxxxx>
Gerrit-MessageType: newchange