[haiku-commits] Change in haiku[master]: sd/mmc: enable 4-bit data transfers

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 14 Jan 2021 17:51:02 +0000

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

Other related posts:

  • » [haiku-commits] Change in haiku[master]: sd/mmc: enable 4-bit data transfers - Gerrit