Commit 0d81b5fa authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v5.16-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC fixes from Ulf Hansson:
 "MMC core:
   - Disable card detect during shutdown

  MMC host:
   - mmci: Fixup tuning support for stm32_sdmmc
   - meson-mx-sdhc: Fix support for multi-block SDIO commands
   - sdhci-tegra: Fix support for eMMC HS400ES mode"

* tag 'mmc-v5.16-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: mmci: stm32: clear DLYB_CR after sending tuning command
  mmc: meson-mx-sdhc: Set MANUAL_STOP for multi-block SDIO commands
  mmc: core: Disable card detect during shutdown
  mmc: sdhci-tegra: Fix switch to HS400ES mode
parents c8cc50a9 ff31ee0a
...@@ -2264,7 +2264,7 @@ void mmc_start_host(struct mmc_host *host) ...@@ -2264,7 +2264,7 @@ void mmc_start_host(struct mmc_host *host)
_mmc_detect_change(host, 0, false); _mmc_detect_change(host, 0, false);
} }
void mmc_stop_host(struct mmc_host *host) void __mmc_stop_host(struct mmc_host *host)
{ {
if (host->slot.cd_irq >= 0) { if (host->slot.cd_irq >= 0) {
mmc_gpio_set_cd_wake(host, false); mmc_gpio_set_cd_wake(host, false);
...@@ -2273,6 +2273,11 @@ void mmc_stop_host(struct mmc_host *host) ...@@ -2273,6 +2273,11 @@ void mmc_stop_host(struct mmc_host *host)
host->rescan_disable = 1; host->rescan_disable = 1;
cancel_delayed_work_sync(&host->detect); cancel_delayed_work_sync(&host->detect);
}
void mmc_stop_host(struct mmc_host *host)
{
__mmc_stop_host(host);
/* clear pm flags now and let card drivers set them as needed */ /* clear pm flags now and let card drivers set them as needed */
host->pm_flags = 0; host->pm_flags = 0;
......
...@@ -70,6 +70,7 @@ static inline void mmc_delay(unsigned int ms) ...@@ -70,6 +70,7 @@ static inline void mmc_delay(unsigned int ms)
void mmc_rescan(struct work_struct *work); void mmc_rescan(struct work_struct *work);
void mmc_start_host(struct mmc_host *host); void mmc_start_host(struct mmc_host *host);
void __mmc_stop_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host);
void _mmc_detect_change(struct mmc_host *host, unsigned long delay, void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
......
...@@ -80,9 +80,18 @@ static void mmc_host_classdev_release(struct device *dev) ...@@ -80,9 +80,18 @@ static void mmc_host_classdev_release(struct device *dev)
kfree(host); kfree(host);
} }
static int mmc_host_classdev_shutdown(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
__mmc_stop_host(host);
return 0;
}
static struct class mmc_host_class = { static struct class mmc_host_class = {
.name = "mmc_host", .name = "mmc_host",
.dev_release = mmc_host_classdev_release, .dev_release = mmc_host_classdev_release,
.shutdown_pre = mmc_host_classdev_shutdown,
.pm = MMC_HOST_CLASS_DEV_PM_OPS, .pm = MMC_HOST_CLASS_DEV_PM_OPS,
}; };
......
...@@ -135,6 +135,7 @@ static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc, ...@@ -135,6 +135,7 @@ static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc,
struct mmc_command *cmd) struct mmc_command *cmd)
{ {
struct meson_mx_sdhc_host *host = mmc_priv(mmc); struct meson_mx_sdhc_host *host = mmc_priv(mmc);
bool manual_stop = false;
u32 ictl, send; u32 ictl, send;
int pack_len; int pack_len;
...@@ -172,12 +173,27 @@ static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc, ...@@ -172,12 +173,27 @@ static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc,
else else
/* software flush: */ /* software flush: */
ictl |= MESON_SDHC_ICTL_DATA_XFER_OK; ictl |= MESON_SDHC_ICTL_DATA_XFER_OK;
/*
* Mimic the logic from the vendor driver where (only)
* SD_IO_RW_EXTENDED commands with more than one block set the
* MESON_SDHC_MISC_MANUAL_STOP bit. This fixes the firmware
* download in the brcmfmac driver for a BCM43362/1 card.
* Without this sdio_memcpy_toio() (with a size of 219557
* bytes) times out if MESON_SDHC_MISC_MANUAL_STOP is not set.
*/
manual_stop = cmd->data->blocks > 1 &&
cmd->opcode == SD_IO_RW_EXTENDED;
} else { } else {
pack_len = 0; pack_len = 0;
ictl |= MESON_SDHC_ICTL_RESP_OK; ictl |= MESON_SDHC_ICTL_RESP_OK;
} }
regmap_update_bits(host->regmap, MESON_SDHC_MISC,
MESON_SDHC_MISC_MANUAL_STOP,
manual_stop ? MESON_SDHC_MISC_MANUAL_STOP : 0);
if (cmd->opcode == MMC_STOP_TRANSMISSION) if (cmd->opcode == MMC_STOP_TRANSMISSION)
send |= MESON_SDHC_SEND_DATA_STOP; send |= MESON_SDHC_SEND_DATA_STOP;
......
...@@ -441,6 +441,8 @@ static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) ...@@ -441,6 +441,8 @@ static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode)
return -EINVAL; return -EINVAL;
} }
writel_relaxed(0, dlyb->base + DLYB_CR);
phase = end_of_len - max_len / 2; phase = end_of_len - max_len / 2;
sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false);
......
...@@ -356,23 +356,6 @@ static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) ...@@ -356,23 +356,6 @@ static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
} }
} }
static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
struct sdhci_host *host = mmc_priv(mmc);
u32 val;
val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
if (ios->enhanced_strobe)
val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
else
val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
}
static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
...@@ -793,6 +776,32 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -793,6 +776,32 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
} }
} }
static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
struct sdhci_host *host = mmc_priv(mmc);
u32 val;
val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
if (ios->enhanced_strobe) {
val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
/*
* When CMD13 is sent from mmc_select_hs400es() after
* switching to HS400ES mode, the bus is operating at
* either MMC_HIGH_26_MAX_DTR or MMC_HIGH_52_MAX_DTR.
* To meet Tegra SDHCI requirement at HS400ES mode, force SDHCI
* interface clock to MMC_HS200_MAX_DTR (200 MHz) so that host
* controller CAR clock and the interface clock are rate matched.
*/
tegra_sdhci_set_clock(host, MMC_HS200_MAX_DTR);
} else {
val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
}
sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
}
static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment