Loading drivers/mmc/host/sdhci.c +32 −0 Original line number Diff line number Diff line Loading @@ -235,6 +235,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) { unsigned long timeout; retry_reset: sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); if (mask & SDHCI_RESET_ALL) { Loading @@ -260,12 +261,43 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) if (timeout == 0) { pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND) && host->ops->reset_workaround) { if (!host->reset_wa_applied) { /* * apply the workaround and issue * reset again. */ host->ops->reset_workaround(host, 1); host->reset_wa_applied = 1; host->reset_wa_cnt++; goto retry_reset; } else { pr_err("%s: Reset 0x%x failed with workaround\n", mmc_hostname(host->mmc), (int)mask); /* clear the workaround */ host->ops->reset_workaround(host, 0); host->reset_wa_applied = 0; } } sdhci_dumpregs(host); return; } timeout--; mdelay(1); } if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND) && host->ops->reset_workaround && host->reset_wa_applied) { pr_info("%s: Reset 0x%x successful with workaround\n", mmc_hostname(host->mmc), (int)mask); /* clear the workaround */ host->ops->reset_workaround(host, 0); host->reset_wa_applied = 0; } } EXPORT_SYMBOL_GPL(sdhci_reset); Loading drivers/mmc/host/sdhci.h +1 −0 Original line number Diff line number Diff line Loading @@ -331,6 +331,7 @@ struct sdhci_ops { void (*enhanced_strobe_mask)(struct sdhci_host *host, bool set); void (*detect)(struct sdhci_host *host, bool detected); int (*notify_load)(struct sdhci_host *host, enum mmc_load state); void (*reset_workaround)(struct sdhci_host *host, u32 enable); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS Loading include/linux/mmc/sdhci.h +5 −1 Original line number Diff line number Diff line Loading @@ -167,7 +167,6 @@ struct sdhci_host { * calculated based on the base clock. */ #define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1<<16) /* * Some SDHC controllers are unable to handle data-end bit error in * 1-bit mode of SDIO. Loading @@ -184,6 +183,8 @@ struct sdhci_host { #define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<19) /* Capability register bit-63 indicates HS400 support */ #define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<20) /* Use reset workaround in case sdhci reset timeouts */ #define SDHCI_QUIRK2_USE_RESET_WORKAROUND (1<<21) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ Loading Loading @@ -295,6 +296,9 @@ struct sdhci_host { u32 auto_cmd_err_sts; struct ratelimit_state dbg_dump_rs; struct cmdq_host *cq_host; int reset_wa_applied; /* reset workaround status */ ktime_t reset_wa_t; /* time when the reset workaround is applied */ int reset_wa_cnt; /* total number of times workaround is used */ unsigned long private[0] ____cacheline_aligned; }; Loading Loading
drivers/mmc/host/sdhci.c +32 −0 Original line number Diff line number Diff line Loading @@ -235,6 +235,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) { unsigned long timeout; retry_reset: sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); if (mask & SDHCI_RESET_ALL) { Loading @@ -260,12 +261,43 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) if (timeout == 0) { pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND) && host->ops->reset_workaround) { if (!host->reset_wa_applied) { /* * apply the workaround and issue * reset again. */ host->ops->reset_workaround(host, 1); host->reset_wa_applied = 1; host->reset_wa_cnt++; goto retry_reset; } else { pr_err("%s: Reset 0x%x failed with workaround\n", mmc_hostname(host->mmc), (int)mask); /* clear the workaround */ host->ops->reset_workaround(host, 0); host->reset_wa_applied = 0; } } sdhci_dumpregs(host); return; } timeout--; mdelay(1); } if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND) && host->ops->reset_workaround && host->reset_wa_applied) { pr_info("%s: Reset 0x%x successful with workaround\n", mmc_hostname(host->mmc), (int)mask); /* clear the workaround */ host->ops->reset_workaround(host, 0); host->reset_wa_applied = 0; } } EXPORT_SYMBOL_GPL(sdhci_reset); Loading
drivers/mmc/host/sdhci.h +1 −0 Original line number Diff line number Diff line Loading @@ -331,6 +331,7 @@ struct sdhci_ops { void (*enhanced_strobe_mask)(struct sdhci_host *host, bool set); void (*detect)(struct sdhci_host *host, bool detected); int (*notify_load)(struct sdhci_host *host, enum mmc_load state); void (*reset_workaround)(struct sdhci_host *host, u32 enable); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS Loading
include/linux/mmc/sdhci.h +5 −1 Original line number Diff line number Diff line Loading @@ -167,7 +167,6 @@ struct sdhci_host { * calculated based on the base clock. */ #define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1<<16) /* * Some SDHC controllers are unable to handle data-end bit error in * 1-bit mode of SDIO. Loading @@ -184,6 +183,8 @@ struct sdhci_host { #define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<19) /* Capability register bit-63 indicates HS400 support */ #define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<20) /* Use reset workaround in case sdhci reset timeouts */ #define SDHCI_QUIRK2_USE_RESET_WORKAROUND (1<<21) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ Loading Loading @@ -295,6 +296,9 @@ struct sdhci_host { u32 auto_cmd_err_sts; struct ratelimit_state dbg_dump_rs; struct cmdq_host *cq_host; int reset_wa_applied; /* reset workaround status */ ktime_t reset_wa_t; /* time when the reset workaround is applied */ int reset_wa_cnt; /* total number of times workaround is used */ unsigned long private[0] ____cacheline_aligned; }; Loading