The branch main has been updated by wma:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=b8f94506f2d4b0ae811f27c244896d044d8780bf

commit b8f94506f2d4b0ae811f27c244896d044d8780bf
Author:     Artur Rojek <[email protected]>
AuthorDate: 2021-11-05 09:14:25 +0000
Commit:     Wojciech Macek <[email protected]>
CommitDate: 2021-11-05 09:18:57 +0000

    sdhci: Provide devmethod for software reset
    
    Some sdhci controllers require custom software reset logic. Accommodate
    this need by introducing a new SDHCI_RESET devmethod. Move the existing
    reset logic into sdhci_generic_reset and use it as a default for the
    aforementioned method.
    
    Obtained from: Semihalf
    Sponsored by: Alstom Group
    Differeential revision: https://reviews.freebsd.org/D32704
---
 sys/dev/sdhci/sdhci.c    | 157 ++++++++++++++++++++++++-----------------------
 sys/dev/sdhci/sdhci.h    |   1 +
 sys/dev/sdhci/sdhci_if.m |   6 ++
 3 files changed, 87 insertions(+), 77 deletions(-)

diff --git a/sys/dev/sdhci/sdhci.c b/sys/dev/sdhci/sdhci.c
index 4a59a73a7e26..22618ca0a822 100644
--- a/sys/dev/sdhci/sdhci.c
+++ b/sys/dev/sdhci/sdhci.c
@@ -106,7 +106,6 @@ static void sdhci_init(struct sdhci_slot *slot);
 static void sdhci_read_block_pio(struct sdhci_slot *slot);
 static void sdhci_req_done(struct sdhci_slot *slot);
 static void sdhci_req_wakeup(struct mmc_request *req);
-static void sdhci_reset(struct sdhci_slot *slot, uint8_t mask);
 static void sdhci_retune(void *arg);
 static void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock);
 static void sdhci_set_power(struct sdhci_slot *slot, u_char power);
@@ -370,66 +369,6 @@ sdhci_syctl_dumpcaps(SYSCTL_HANDLER_ARGS)
        return (0);
 }
 
-static void
-sdhci_reset(struct sdhci_slot *slot, uint8_t mask)
-{
-       int timeout;
-       uint32_t clock;
-
-       if (slot->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-               if (!SDHCI_GET_CARD_PRESENT(slot->bus, slot))
-                       return;
-       }
-
-       /* Some controllers need this kick or reset won't work. */
-       if ((mask & SDHCI_RESET_ALL) == 0 &&
-           (slot->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)) {
-               /* This is to force an update */
-               clock = slot->clock;
-               slot->clock = 0;
-               sdhci_set_clock(slot, clock);
-       }
-
-       if (mask & SDHCI_RESET_ALL) {
-               slot->clock = 0;
-               slot->power = 0;
-       }
-
-       WR1(slot, SDHCI_SOFTWARE_RESET, mask);
-
-       if (slot->quirks & SDHCI_QUIRK_WAITFOR_RESET_ASSERTED) {
-               /*
-                * Resets on TI OMAPs and AM335x are incompatible with SDHCI
-                * specification.  The reset bit has internal propagation delay,
-                * so a fast read after write returns 0 even if reset process is
-                * in progress.  The workaround is to poll for 1 before polling
-                * for 0.  In the worst case, if we miss seeing it asserted the
-                * time we spent waiting is enough to ensure the reset finishes.
-                */
-               timeout = 10000;
-               while ((RD1(slot, SDHCI_SOFTWARE_RESET) & mask) != mask) {
-                       if (timeout <= 0)
-                               break;
-                       timeout--;
-                       DELAY(1);
-               }
-       }
-
-       /* Wait max 100 ms */
-       timeout = 10000;
-       /* Controller clears the bits when it's done */
-       while (RD1(slot, SDHCI_SOFTWARE_RESET) & mask) {
-               if (timeout <= 0) {
-                       slot_printf(slot, "Reset 0x%x never completed.\n",
-                           mask);
-                       sdhci_dumpregs(slot);
-                       return;
-               }
-               timeout--;
-               DELAY(10);
-       }
-}
-
 static uint32_t
 sdhci_tuning_intmask(const struct sdhci_slot *slot)
 {
@@ -449,7 +388,7 @@ static void
 sdhci_init(struct sdhci_slot *slot)
 {
 
-       sdhci_reset(slot, SDHCI_RESET_ALL);
+       SDHCI_RESET(slot->bus, slot, SDHCI_RESET_ALL);
 
        /* Enable interrupts. */
        slot->intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
@@ -1256,7 +1195,7 @@ sdhci_cleanup_slot(struct sdhci_slot *slot)
                device_delete_child(slot->bus, d);
 
        SDHCI_LOCK(slot);
-       sdhci_reset(slot, SDHCI_RESET_ALL);
+       SDHCI_RESET(slot->bus, slot, SDHCI_RESET_ALL);
        SDHCI_UNLOCK(slot);
        if (slot->opt & SDHCI_HAVE_DMA)
                sdhci_dma_free(slot);
@@ -1283,7 +1222,7 @@ sdhci_generic_suspend(struct sdhci_slot *slot)
        callout_drain(&slot->retune_callout);
        SDHCI_LOCK(slot);
        slot->opt &= ~SDHCI_TUNING_ENABLED;
-       sdhci_reset(slot, SDHCI_RESET_ALL);
+       SDHCI_RESET(slot->bus, slot, SDHCI_RESET_ALL);
        SDHCI_UNLOCK(slot);
 
        return (0);
@@ -1300,6 +1239,67 @@ sdhci_generic_resume(struct sdhci_slot *slot)
        return (0);
 }
 
+void
+sdhci_generic_reset(device_t brdev __unused, struct sdhci_slot *slot,
+    uint8_t mask)
+{
+       int timeout;
+       uint32_t clock;
+
+       if (slot->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+               if (!SDHCI_GET_CARD_PRESENT(slot->bus, slot))
+                       return;
+       }
+
+       /* Some controllers need this kick or reset won't work. */
+       if ((mask & SDHCI_RESET_ALL) == 0 &&
+           (slot->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)) {
+               /* This is to force an update */
+               clock = slot->clock;
+               slot->clock = 0;
+               sdhci_set_clock(slot, clock);
+       }
+
+       if (mask & SDHCI_RESET_ALL) {
+               slot->clock = 0;
+               slot->power = 0;
+       }
+
+       WR1(slot, SDHCI_SOFTWARE_RESET, mask);
+
+       if (slot->quirks & SDHCI_QUIRK_WAITFOR_RESET_ASSERTED) {
+               /*
+                * Resets on TI OMAPs and AM335x are incompatible with SDHCI
+                * specification.  The reset bit has internal propagation delay,
+                * so a fast read after write returns 0 even if reset process is
+                * in progress.  The workaround is to poll for 1 before polling
+                * for 0.  In the worst case, if we miss seeing it asserted the
+                * time we spent waiting is enough to ensure the reset finishes.
+                */
+               timeout = 10000;
+               while ((RD1(slot, SDHCI_SOFTWARE_RESET) & mask) != mask) {
+                       if (timeout <= 0)
+                               break;
+                       timeout--;
+                       DELAY(1);
+               }
+       }
+
+       /* Wait max 100 ms */
+       timeout = 10000;
+       /* Controller clears the bits when it's done */
+       while (RD1(slot, SDHCI_SOFTWARE_RESET) & mask) {
+               if (timeout <= 0) {
+                       slot_printf(slot, "Reset 0x%x never completed.\n",
+                           mask);
+                       sdhci_dumpregs(slot);
+                       return;
+               }
+               timeout--;
+               DELAY(10);
+       }
+}
+
 uint32_t
 sdhci_generic_min_freq(device_t brdev __unused, struct sdhci_slot *slot)
 {
@@ -1391,7 +1391,8 @@ sdhci_generic_update_ios(device_t brdev, device_t reqdev)
        SDHCI_SET_UHS_TIMING(brdev, slot);
        /* Some controllers like reset after bus changes. */
        if (slot->quirks & SDHCI_QUIRK_RESET_ON_IOS)
-               sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+               SDHCI_RESET(slot->bus, slot,
+                   SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
        SDHCI_UNLOCK(slot);
        return (0);
@@ -1634,7 +1635,7 @@ sdhci_exec_tuning(struct sdhci_slot *slot, bool reset)
        slot_printf(slot, "Tuning failed, using fixed sampling clock\n");
        WR2(slot, SDHCI_HOST_CONTROL2, hostctrl2 & ~(SDHCI_CTRL2_EXEC_TUNING |
            SDHCI_CTRL2_SAMPLING_CLOCK));
-       sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+       SDHCI_RESET(slot->bus, slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
        return (EIO);
 }
 
@@ -1703,7 +1704,8 @@ sdhci_timeout(void *arg)
        if (slot->curcmd != NULL) {
                slot_printf(slot, "Controller timeout\n");
                sdhci_dumpregs(slot);
-               sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+               SDHCI_RESET(slot->bus, slot,
+                   SDHCI_RESET_CMD | SDHCI_RESET_DATA);
                slot->curcmd->error = MMC_ERR_TIMEOUT;
                sdhci_req_done(slot);
        } else {
@@ -1881,8 +1883,8 @@ sdhci_finish_command(struct sdhci_slot *slot)
        if (slot->curcmd->error) {
                if (slot->curcmd->error == MMC_ERR_BADCRC)
                        slot->retune_req |= SDHCI_RETUNE_REQ_RESET;
-               sdhci_reset(slot, SDHCI_RESET_CMD);
-               sdhci_reset(slot, SDHCI_RESET_DATA);
+               SDHCI_RESET(slot->bus, slot, SDHCI_RESET_CMD);
+               SDHCI_RESET(slot->bus, slot, SDHCI_RESET_DATA);
                sdhci_start(slot);
                return;
        }
@@ -2041,8 +2043,8 @@ sdhci_finish_data(struct sdhci_slot *slot)
        if (slot->curcmd->error) {
                if (slot->curcmd->error == MMC_ERR_BADCRC)
                        slot->retune_req |= SDHCI_RETUNE_REQ_RESET;
-               sdhci_reset(slot, SDHCI_RESET_CMD);
-               sdhci_reset(slot, SDHCI_RESET_DATA);
+               SDHCI_RESET(slot->bus, slot, SDHCI_RESET_CMD);
+               SDHCI_RESET(slot->bus, slot, SDHCI_RESET_DATA);
                sdhci_start(slot);
                return;
        }
@@ -2084,8 +2086,8 @@ sdhci_start(struct sdhci_slot *slot)
                slot_printf(slot, "result: %d\n", mmcio->cmd.error);
        if (mmcio->cmd.error == 0 &&
            (slot->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
-               sdhci_reset(slot, SDHCI_RESET_CMD);
-               sdhci_reset(slot, SDHCI_RESET_DATA);
+               SDHCI_RESET(slot->bus, slot, SDHCI_RESET_CMD);
+               SDHCI_RESET(slot->bus, slot, SDHCI_RESET_DATA);
        }
 
        sdhci_req_done(slot);
@@ -2117,8 +2119,8 @@ sdhci_start(struct sdhci_slot *slot)
            ((slot->curcmd == req->stop &&
             (slot->quirks & SDHCI_QUIRK_BROKEN_AUTO_STOP)) ||
             (slot->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
-               sdhci_reset(slot, SDHCI_RESET_CMD);
-               sdhci_reset(slot, SDHCI_RESET_DATA);
+               SDHCI_RESET(slot->bus, slot, SDHCI_RESET_CMD);
+               SDHCI_RESET(slot->bus, slot, SDHCI_RESET_DATA);
        }
 
        sdhci_req_done(slot);
@@ -2343,7 +2345,7 @@ sdhci_acmd_irq(struct sdhci_slot *slot, uint16_t acmd_err)
                return;
        }
        slot_printf(slot, "Got AutoCMD12 error 0x%04x\n", acmd_err);
-       sdhci_reset(slot, SDHCI_RESET_CMD);
+       SDHCI_RESET(slot->bus, slot, SDHCI_RESET_CMD);
 }
 
 void
@@ -2849,7 +2851,8 @@ sdhci_cam_update_ios(struct sdhci_slot *slot)
        WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl);
        /* Some controllers like reset after bus changes. */
        if(slot->quirks & SDHCI_QUIRK_RESET_ON_IOS)
-               sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+               SDHCI_RESET(slot->bus, slot,
+                   SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
        SDHCI_UNLOCK(slot);
        return (0);
diff --git a/sys/dev/sdhci/sdhci.h b/sys/dev/sdhci/sdhci.h
index 9d68a14b28a2..4feb272bb359 100644
--- a/sys/dev/sdhci/sdhci.h
+++ b/sys/dev/sdhci/sdhci.h
@@ -431,6 +431,7 @@ void sdhci_finish_data(struct sdhci_slot *slot);
 int sdhci_cleanup_slot(struct sdhci_slot *slot);
 int sdhci_generic_suspend(struct sdhci_slot *slot);
 int sdhci_generic_resume(struct sdhci_slot *slot);
+void sdhci_generic_reset(device_t brdev, struct sdhci_slot *slot, uint8_t 
mask);
 int sdhci_generic_update_ios(device_t brdev, device_t reqdev);
 int sdhci_generic_tune(device_t brdev, device_t reqdev, bool hs400);
 int sdhci_generic_switch_vccq(device_t brdev, device_t reqdev);
diff --git a/sys/dev/sdhci/sdhci_if.m b/sys/dev/sdhci/sdhci_if.m
index 93c97a155fb1..c888f35bdaf0 100644
--- a/sys/dev/sdhci/sdhci_if.m
+++ b/sys/dev/sdhci/sdhci_if.m
@@ -164,3 +164,9 @@ METHOD void set_uhs_timing {
        device_t                brdev;
        struct sdhci_slot       *slot;
 } DEFAULT null_set_uhs_timing;
+
+METHOD void reset {
+       device_t                brdev;
+       struct sdhci_slot       *slot;
+       uint8_t                 mask;
+} DEFAULT sdhci_generic_reset;

Reply via email to