From nobody Fri Nov 05 09:19:18 2021 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 3FAE3184C04F; Fri, 5 Nov 2021 09:19:19 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Hlw1g10S8z4kCM; Fri, 5 Nov 2021 09:19:19 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 02B04150CF; Fri, 5 Nov 2021 09:19:19 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1A59JIHV078224; Fri, 5 Nov 2021 09:19:18 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1A59JIGD078223; Fri, 5 Nov 2021 09:19:18 GMT (envelope-from git) Date: Fri, 5 Nov 2021 09:19:18 GMT Message-Id: <202111050919.1A59JIGD078223@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Wojciech Macek Subject: git: b8f94506f2d4 - main - sdhci: Provide devmethod for software reset List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: wma X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: b8f94506f2d4b0ae811f27c244896d044d8780bf Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by wma: URL: https://cgit.FreeBSD.org/src/commit/?id=b8f94506f2d4b0ae811f27c244896d044d8780bf commit b8f94506f2d4b0ae811f27c244896d044d8780bf Author: Artur Rojek AuthorDate: 2021-11-05 09:14:25 +0000 Commit: Wojciech Macek 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;