diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-04 19:41:09 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-04 19:41:09 -0700 |
| commit | 328141e51e6fc79d21168bfd4e356dddc2ec7491 (patch) | |
| tree | d96dbb769f25332d17269339873617c350c8f799 /drivers/mmc/host | |
| parent | eff0cb3d91c06acbb957be1134a07afa2c4978e3 (diff) | |
| parent | 527f36f5efa45b6a897190cabf982e2d207887da (diff) | |
| download | linux-328141e51e6fc79d21168bfd4e356dddc2ec7491.tar.gz linux-328141e51e6fc79d21168bfd4e356dddc2ec7491.tar.bz2 linux-328141e51e6fc79d21168bfd4e356dddc2ec7491.zip | |
Merge tag 'mmc-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Add support for the asynchronous SDIO wakeup interrupts
- Skip redundant evaluation of eMMC HS400 caps when no-MMC-cap
- Add support to store error stats from host drivers
- Extend debugfs to show error stats from host drivers
- Add single I/O read support in the recovery path for 4k sector cards
MMC host:
- dw_mmc-exynos: Convert corresponding DT bindings to the dtschema
- dw_mmc-rockchip: Add support for the Rockchip RV1126 variant
- mmc_spi: Convert corresponding DT bindings to the dtschema
- mtk-sd: Extend support for interrupts/pinctrls for SDIO low-power mode
- mtk-sd: Add support for SDIO wake irqs
- mtk-sd: Add support for the Mediatek MT8188 variant
- renesas_sdhi: Drop redundant manual tap correction for newer SoCs
- renesas_sdhi: Add support for the R-Car S4-8 and generic Gen4 variants
- sdhci/cqhci: Add support to capture stats from host errors
- sdhci-brcmstb: Add ability to increase max clock rate for SDIO on 72116b0
- sdhci-msm: Add support for the MSM8998 and SM8450 variant
- sdhci-of-at91: Fixup UHS-I mode by rewriting of MC1R
- sdhci-of-dwcmshc: Add support for the Rockchip rk3588 variant
- sdhci-of-dwcmshc: Enable reset support for the Rockchip variants
- sdhci-pci-gli: Improve I/O read/write performance for GL9763E
- sdhci-s3c: Convert corresponding DT bindings to the dtschema
- tmio: Avoid glitches when resetting
MEMSTICK core:
- A couple of minor fixes and cleanups"
* tag 'mmc-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (61 commits)
mmc: mediatek: add support for SDIO eint wakup IRQ
mmc: core: Add support for SDIO wakeup interrupt
dt-bindings: mmc: mtk-sd: extend interrupts and pinctrls properties
dt-bindings: mmc: rockchip-dw-mshc: Document Rockchip RV1126
mmc: renesas_sdhi: newer SoCs don't need manual tap correction
mmc: cavium-thunderx: Add of_node_put() when breaking out of loop
mmc: cavium-octeon: Add of_node_put() when breaking out of loop
mmc: core: quirks: Add of_node_put() when breaking out of loop
mmc: sdhci-brcmstb: use clk_get_rate(base_clk) in PM resume
dt-bindings: mmc: sdhci-msm: Document the SM8450 compatible
mmc: sdhci-msm: drop redundant of_device_id entries
dt-bindings: mmc: sdhci-msm: add MSM8998
mmc: block: Add single read for 4k sector cards
mmc: mxcmmc: Use mmc_card_sdio macro
mmc: core: Use mmc_card_* macro and add a new for the sd_combo type
dt-bindings: mmc: sdhci-msm: constrain reg-names per variants
dt-bindings: mmc: sdhci-msm: fix reg-names entries
dt-bindings: mmc: Add compatible for MediaTek MT8188
dt-bindings: mmc: sdhci-msm: document resets
mmc: sdhci-of-at91: fix set_uhs_signaling rewriting of MC1R
...
Diffstat (limited to 'drivers/mmc/host')
25 files changed, 490 insertions, 140 deletions
diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c index 2c4b2df52adb..12dca91a8ef6 100644 --- a/drivers/mmc/host/cavium-octeon.c +++ b/drivers/mmc/host/cavium-octeon.c @@ -277,6 +277,7 @@ static int octeon_mmc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Error populating slots\n"); octeon_mmc_set_shared_power(host, 0); + of_node_put(cn); goto error; } i++; diff --git a/drivers/mmc/host/cavium-thunderx.c b/drivers/mmc/host/cavium-thunderx.c index 76013bbbcff3..202b1d6da678 100644 --- a/drivers/mmc/host/cavium-thunderx.c +++ b/drivers/mmc/host/cavium-thunderx.c @@ -142,8 +142,10 @@ static int thunder_mmc_probe(struct pci_dev *pdev, continue; ret = cvm_mmc_of_slot_probe(&host->slot_pdev[i]->dev, host); - if (ret) + if (ret) { + of_node_put(child_node); goto error; + } } i++; } diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index b0d30c35c390..b3d7d6d8d654 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -822,8 +822,15 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, pr_debug("%s: cqhci: IRQ status: 0x%08x\n", mmc_hostname(mmc), status); if ((status & (CQHCI_IS_RED | CQHCI_IS_GCE | CQHCI_IS_ICCE)) || - cmd_error || data_error) + cmd_error || data_error) { + if (status & CQHCI_IS_RED) + mmc_debugfs_err_stats_inc(mmc, MMC_ERR_CMDQ_RED); + if (status & CQHCI_IS_GCE) + mmc_debugfs_err_stats_inc(mmc, MMC_ERR_CMDQ_GCE); + if (status & CQHCI_IS_ICCE) + mmc_debugfs_err_stats_inc(mmc, MMC_ERR_CMDQ_ICCE); cqhci_error_irq(mmc, status, cmd_error, data_error); + } if (status & CQHCI_IS_TCC) { /* read TCN and complete the request */ diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index ca5be4445ae0..9f20ac524c8b 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -670,7 +670,9 @@ static int dw_mci_exynos_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - return dw_mci_pltfm_remove(pdev); + dw_mci_pltfm_remove(pdev); + + return 0; } static const struct dev_pm_ops dw_mci_exynos_pmops = { diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c index e9437ef8ef19..6f22fe054087 100644 --- a/drivers/mmc/host/dw_mmc-hi3798cv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -179,7 +179,9 @@ static int dw_mci_hi3798cv200_remove(struct platform_device *pdev) clk_disable_unprepare(priv->drive_clk); clk_disable_unprepare(priv->sample_clk); - return dw_mci_pltfm_remove(pdev); + dw_mci_pltfm_remove(pdev); + + return 0; } static const struct of_device_id dw_mci_hi3798cv200_match[] = { diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index f825487aa739..2a99f15f527f 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -377,7 +377,9 @@ static int dw_mci_rockchip_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - return dw_mci_pltfm_remove(pdev); + dw_mci_pltfm_remove(pdev); + + return 0; } static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = { diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 01159eaf8694..012aa85489d8 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -762,7 +762,7 @@ int mmci_dmae_setup(struct mmci_host *host) /* * If only an RX channel is specified, the driver will - * attempt to use it bidirectionally, however if it is + * attempt to use it bidirectionally, however if it * is specified but cannot be located, DMA will be disabled. */ if (dmae->rx_channel && !dmae->tx_channel) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 9da4489dc345..4ff73d1883de 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2015 MediaTek Inc. + * Copyright (c) 2014-2015, 2022 MediaTek Inc. * Author: Chaotian.Jing <chaotian.jing@mediatek.com> */ @@ -20,6 +20,7 @@ #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/pm_wakeirq.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -440,8 +441,10 @@ struct msdc_host { struct pinctrl *pinctrl; struct pinctrl_state *pins_default; struct pinctrl_state *pins_uhs; + struct pinctrl_state *pins_eint; struct delayed_work req_timeout; int irq; /* host interrupt */ + int eint_irq; /* interrupt from sdio device for waking up system */ struct reset_control *reset; struct clk *src_clk; /* msdc source clock */ @@ -1521,17 +1524,46 @@ static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb) static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) { - unsigned long flags; struct msdc_host *host = mmc_priv(mmc); + unsigned long flags; + int ret; spin_lock_irqsave(&host->lock, flags); __msdc_enable_sdio_irq(host, enb); spin_unlock_irqrestore(&host->lock, flags); - if (enb) - pm_runtime_get_noresume(host->dev); - else - pm_runtime_put_noidle(host->dev); + if (mmc_card_enable_async_irq(mmc->card) && host->pins_eint) { + if (enb) { + /* + * In dev_pm_set_dedicated_wake_irq_reverse(), eint pin will be set to + * GPIO mode. We need to restore it to SDIO DAT1 mode after that. + * Since the current pinstate is pins_uhs, to ensure pinctrl select take + * affect successfully, we change the pinstate to pins_eint firstly. + */ + pinctrl_select_state(host->pinctrl, host->pins_eint); + ret = dev_pm_set_dedicated_wake_irq_reverse(host->dev, host->eint_irq); + + if (ret) { + dev_err(host->dev, "Failed to register SDIO wakeup irq!\n"); + host->pins_eint = NULL; + pm_runtime_get_noresume(host->dev); + } else { + dev_dbg(host->dev, "SDIO eint irq: %d!\n", host->eint_irq); + } + + pinctrl_select_state(host->pinctrl, host->pins_uhs); + } else { + dev_pm_clear_wake_irq(host->dev); + } + } else { + if (enb) { + /* Ensure host->pins_eint is NULL */ + host->pins_eint = NULL; + pm_runtime_get_noresume(host->dev); + } else { + pm_runtime_put_noidle(host->dev); + } + } } static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts) @@ -2319,7 +2351,7 @@ static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card else val = readl(host->base + PAD_DS_TUNE); - dev_info(host->dev, "Fianl PAD_DS_TUNE: 0x%x\n", val); + dev_info(host->dev, "Final PAD_DS_TUNE: 0x%x\n", val); return 0; @@ -2635,6 +2667,20 @@ static int msdc_drv_probe(struct platform_device *pdev) goto host_free; } + /* Support for SDIO eint irq ? */ + if ((mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ) && (mmc->pm_caps & MMC_PM_KEEP_POWER)) { + host->eint_irq = platform_get_irq_byname(pdev, "sdio_wakeup"); + if (host->eint_irq > 0) { + host->pins_eint = pinctrl_lookup_state(host->pinctrl, "state_eint"); + if (IS_ERR(host->pins_eint)) { + dev_err(&pdev->dev, "Cannot find pinctrl eint!\n"); + host->pins_eint = NULL; + } else { + device_init_wakeup(&pdev->dev, true); + } + } + } + msdc_of_property_parse(pdev, host); host->dev = &pdev->dev; @@ -2849,6 +2895,15 @@ static int __maybe_unused msdc_runtime_suspend(struct device *dev) struct msdc_host *host = mmc_priv(mmc); msdc_save_reg(host); + + if (sdio_irq_claimed(mmc)) { + if (host->pins_eint) { + disable_irq(host->irq); + pinctrl_select_state(host->pinctrl, host->pins_eint); + } + + __msdc_enable_sdio_irq(host, 0); + } msdc_gate_clock(host); return 0; } @@ -2864,12 +2919,18 @@ static int __maybe_unused msdc_runtime_resume(struct device *dev) return ret; msdc_restore_reg(host); + + if (sdio_irq_claimed(mmc) && host->pins_eint) { + pinctrl_select_state(host->pinctrl, host->pins_uhs); + enable_irq(host->irq); + } return 0; } static int __maybe_unused msdc_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); + struct msdc_host *host = mmc_priv(mmc); int ret; if (mmc->caps2 & MMC_CAP2_CQE) { @@ -2878,11 +2939,24 @@ static int __maybe_unused msdc_suspend(struct device *dev) return ret; } + /* + * Bump up runtime PM usage counter otherwise dev->power.needs_force_resume will + * not be marked as 1, pm_runtime_force_resume() will go out directly. + */ + if (sdio_irq_claimed(mmc) && host->pins_eint) + pm_runtime_get_noresume(dev); + return pm_runtime_force_suspend(dev); } static int __maybe_unused msdc_resume(struct device *dev) { + struct mmc_host *mmc = dev_get_drvdata(dev); + struct msdc_host *host = mmc_priv(mmc); + + if (sdio_irq_claimed(mmc) && host->pins_eint) + pm_runtime_put_noidle(dev); + return pm_runtime_force_resume(dev); } diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index de04b5afef2e..2cf0413407ea 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -923,7 +923,7 @@ static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) * One way to prevent this is to only allow 1-bit transfers. */ - if (is_imx31_mmc(mxcmci) && card->type == MMC_TYPE_SDIO) + if (is_imx31_mmc(mxcmci) && mmc_card_sdio(card)) host->caps &= ~MMC_CAP_4_BIT_DATA; else host->caps |= MMC_CAP_4_BIT_DATA; @@ -1025,7 +1025,7 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; - host->devtype = (enum mxcmci_type)of_device_get_match_data(&pdev->dev); + host->devtype = (uintptr_t)of_device_get_match_data(&pdev->dev); /* adjust max_segs after devtype detection */ if (!is_mpc512x_mmc(host)) diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 1a1e3e020a8c..c4abfee1ebae 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -43,6 +43,7 @@ struct renesas_sdhi_quirks { bool hs400_4taps; bool fixed_addr_mode; bool dma_one_rx_only; + bool manual_tap_correction; u32 hs400_bad_taps; const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX]; }; diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 4404ca1f98d8..6edbf5c161ab 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -49,9 +49,6 @@ #define HOST_MODE_GEN3_32BIT (HOST_MODE_GEN3_WMODE | HOST_MODE_GEN3_BUSWIDTH) #define HOST_MODE_GEN3_64BIT 0 -#define CTL_SDIF_MODE 0xe6 -#define SDIF_MODE_HS400 BIT(0) - #define SDHI_VER_GEN2_SDR50 0x490c #define SDHI_VER_RZ_A1 0x820b /* very old datasheets said 0x490c for SDR104, too. They are wrong! */ @@ -383,8 +380,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc) sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos_hs400); - /* Gen3 can't do automatic tap correction with HS400, so disable it */ - if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC) + if (priv->quirks && priv->quirks->manual_tap_correction) sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); @@ -562,23 +558,25 @@ static void renesas_sdhi_scc_reset(struct tmio_mmc_host *host, struct renesas_sd } /* only populated for TMIO_MMC_MIN_RCAR2 */ -static void renesas_sdhi_reset(struct tmio_mmc_host *host) +static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve) { struct renesas_sdhi *priv = host_to_priv(host); int ret; u16 val; - if (priv->rstc) { - reset_control_reset(priv->rstc); - /* Unknown why but without polling reset status, it will hang */ - read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100, - false, priv->rstc); - /* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */ - sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); - priv->needs_adjust_hs400 = false; - renesas_sdhi_set_clock(host, host->clk_cache); - } else if (priv->scc_ctl) { - renesas_sdhi_scc_reset(host, priv); + if (!preserve) { + if (priv->rstc) { + reset_control_reset(priv->rstc); + /* Unknown why but without polling reset status, it will hang */ + read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100, + false, priv->rstc); + /* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */ + sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); + priv->needs_adjust_hs400 = false; + renesas_sdhi_set_clock(host, host->clk_cache); + } else if (priv->scc_ctl) { + renesas_sdhi_scc_reset(host, priv); + } } if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) { @@ -719,7 +717,7 @@ static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); /* Change TAP position according to correction status */ - if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC && + if (priv->quirks && priv->quirks->manual_tap_correction && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; /* @@ -938,6 +936,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (IS_ERR(priv->clk_cd)) return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk_cd), "cannot get cd clock"); + priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + if (IS_ERR(priv->rstc)) + return PTR_ERR(priv->rstc); + priv->pinctrl = devm_pinctrl_get(&pdev->dev); if (!IS_ERR(priv->pinctrl)) { priv->pins_default = pinctrl_lookup_state(priv->pinctrl, @@ -1030,10 +1032,6 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (ret) goto efree; - priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(priv->rstc)) - return PTR_ERR(priv->rstc); - ver = sd_ctrl_read16(host, CTL_VERSION); /* GEN2_SDR104 is first known SDHI to use 32bit block count */ if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 3084b15ae2cb..42937596c4c4 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -170,6 +170,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400_one_rx = { static const struct renesas_sdhi_quirks sdhi_quirks_4tap = { .hs400_4taps = true, .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), + .manual_tap_correction = true, }; static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = { @@ -182,25 +183,30 @@ static const struct renesas_sdhi_quirks sdhi_quirks_fixed_addr = { static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps1357 = { .hs400_bad_taps = BIT(1) | BIT(3) | BIT(5) | BIT(7), + .manual_tap_correction = true, }; static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps2367 = { .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), + .manual_tap_correction = true, }; static const struct renesas_sdhi_quirks sdhi_quirks_r8a7796_es13 = { .hs400_4taps = true, .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), .hs400_calib_table = r8a7796_es13_calib_table, + .manual_tap_correction = true, }; static const struct renesas_sdhi_quirks sdhi_quirks_r8a77965 = { .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), .hs400_calib_table = r8a77965_calib_table, + .manual_tap_correction = true, }; static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = { .hs400_calib_table = r8a77990_calib_table, + .manual_tap_correction = true, }; /* @@ -268,6 +274,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, }, { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, + { .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, }, {}, }; MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match); @@ -321,7 +328,7 @@ renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) } /* - * renesas_sdhi_internal_dmac_map() will be called with two difference + * renesas_sdhi_internal_dmac_map() will be called with two different * sg pointers in two mmc_data by .pre_req(), but tmio host can have a single * sg_ptr only. So, renesas_sdhi_internal_dmac_{un}map() should use a sg * pointer in a mmc_data instead of host->sg_ptr. @@ -355,7 +362,7 @@ renesas_sdhi_internal_dmac_map(struct tmio_mmc_host *host, data->host_cookie = cookie; - /* This DMAC cannot handle if buffer is not 128-bytes alignment */ + /* This DMAC needs buffers to be 128-byte aligned */ if (!IS_ALIGNED(sg_dma_address(data->sg), 128)) { renesas_sdhi_internal_dmac_unmap(host, data, cookie); return false; diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index 8eb57de48e0c..aff36a933ebe 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -31,6 +31,8 @@ struct sdhci_brcmstb_priv { void __iomem *cfg_regs; unsigned int flags; + struct clk *base_clk; + u32 base_freq_hz; }; struct brcmstb_match_priv { @@ -250,9 +252,11 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host; const struct of_device_id *match; struct sdhci_brcmstb_priv *priv; + u32 actual_clock_mhz; struct sdhci_host *host; struct resource *iomem; struct clk *clk; + struct clk *base_clk = NULL; int res; match = of_match_node(sdhci_brcm_of_match, pdev->dev.of_node); @@ -330,6 +334,35 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) if (match_priv->flags & BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + /* Change the base clock frequency if the DT property exists */ + if (device_property_read_u32(&pdev->dev, "clock-frequency", + &priv->base_freq_hz) != 0) + goto add_host; + + base_clk = devm_clk_get_optional(&pdev->dev, "sdio_freq"); + if (IS_ERR(base_clk)) { + dev_warn(&pdev->dev, "Clock for \"sdio_freq\" not found\n"); + goto add_host; + } + + res = clk_prepare_enable(base_clk); + if (res) + goto err; + + /* set improved clock rate */ + clk_set_rate(base_clk, priv->base_freq_hz); + actual_clock_mhz = clk_get_rate(base_clk) / 1000000; + + host->caps &= ~SDHCI_CLOCK_V3_BASE_MASK; + host->caps |= (actual_clock_mhz << SDHCI_CLOCK_BASE_SHIFT); + /* Disable presets because they are now incorrect */ + host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; + + dev_dbg(&pdev->dev, "Base Clock Frequency changed to %dMHz\n", + actual_clock_mhz); + priv->base_clk = base_clk; + +add_host: res = sdhci_brcmstb_add_host(host, priv); if (res) goto err; @@ -340,6 +373,7 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) err: sdhci_pltfm_free(pdev); err_clk: + clk_disable_unprepare(base_clk); clk_disable_unprepare(clk); return res; } @@ -351,11 +385,51 @@ static void sdhci_brcmstb_shutdown(struct platform_device *pdev) MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match); +#ifdef CONFIG_PM_SLEEP +static int sdhci_brcmstb_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host); + + clk_disable_unprepare(priv->base_clk); + return sdhci_pltfm_suspend(dev); +} + +static int sdhci_brcmstb_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host); + int ret; + + ret = sdhci_pltfm_resume(dev); + if (!ret && priv->base_freq_hz) { + ret = clk_prepare_enable(priv->base_clk); + /* + * Note: using clk_get_rate() below as clk_get_rate() + * honors CLK_GET_RATE_NOCACHE attribute, but clk_set_rate() + * may do implicit get_rate() calls that do not honor + * CLK_GET_RATE_NOCACHE. + */ + if (!ret && + (clk_get_rate(priv->base_clk) != priv->base_freq_hz)) + ret = clk_set_rate(priv->base_clk, priv->base_freq_hz); + } + + return ret; +} +#endif + +static const struct dev_pm_ops sdhci_brcmstb_pmops = { + SET_SYSTEM_SLEEP_PM_OPS(sdhci_brcmstb_suspend, sdhci_brcmstb_resume) +}; + static struct platform_driver sdhci_brcmstb_driver = { .driver = { .name = "sdhci-brcmstb", .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .pm = &sdhci_pltfm_pmops, + .pm = &sdhci_brcmstb_pmops, .of_match_table = of_match_ptr(sdhci_brcm_of_match), }, .probe = sdhci_brcmstb_probe, diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index e395411fb6fd..dc2991422a87 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2435,33 +2435,12 @@ static const struct sdhci_msm_variant_info sdm845_sdhci_var = { }; static const struct of_device_id sdhci_msm_dt_match[] = { - /* Following two entries are deprecated (kept only for backward compatibility) */ - {.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var}, - {.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var}, - /* Add entries for sdcc versions less than 5.0 here */ - {.compatible = "qcom,apq8084-sdhci", .data = &sdhci_msm_mci_var}, - {.compatible = "qcom,msm8226-sdhci", .data = &sdhci_msm_mci_var}, - {.compatible = "qcom,msm8916-sdhci", .data = &sdhci_msm_mci_var}, - {.compatible = "qcom,msm8953-sdhci", .data = &sdhci_msm_mci_var}, - {.compatible = "qcom,msm8974-sdhci", .data = &sdhci_msm_mci_var}, - {.compatible = "qcom,msm8992-sdhci", .data = &sdhci_msm_mci_var}, - {.compatible = "qcom,msm8994-sdhci", .data = &sdhci_msm_mci_var}, - {.compatible = "qcom,msm8996-sdhci", .data = &sdhci_msm_mci_var}, /* - * Add entries for sdcc version 5.0 here. For SDCC version 5.0.0, - * MCI registers are removed from SDCC interface and some registers - * are moved to HC. + * Do not add new variants to the driver which are compatible with + * generic ones, unless they need customization. */ - {.compatible = "qcom,qcs404-sdhci", .data = &sdhci_msm_v5_var}, - {.compatible = "qcom,sdx55-sdhci", .data = &sdhci_msm_v5_var}, - {.compatible = "qcom,sdx65-sdhci", .data = &sdhci_msm_v5_var}, - {.compatible = "qcom,sdm630-sdhci", .data = &sdhci_msm_v5_var}, - {.compatible = "qcom,sm6125-sdhci", .data = &sdhci_msm_v5_var}, - {.compatible = "qcom,sm6350-sdhci", .data = &sdhci_msm_v5_var}, - {.compatible = "qcom,sm8150-sdhci", .data = &sdhci_msm_v5_var}, - {.compatible = "qcom,sm8250-sdhci", .data = &sdhci_msm_v5_var}, - {.compatible = "qcom,sc7280-sdhci", .data = &sdhci_msm_v5_var}, - /* Add entries where soc specific handling is required, here */ + {.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var}, + {.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var}, {.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var}, {.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var}, {}, diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 757801dfc308..3997cad1f793 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -1733,7 +1733,6 @@ err_pltfm_free: static int sdhci_arasan_remove(struct platform_device *pdev) { - int ret; struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); @@ -1747,11 +1746,11 @@ static int sdhci_arasan_remove(struct platform_device *pdev) sdhci_arasan_unregister_sdclk(&pdev->dev); - ret = sdhci_pltfm_unregister(pdev); + sdhci_pltfm_unregister(pdev); clk_disable_unprepare(clk_ahb); - return ret; + return 0; } static struct platform_driver sdhci_arasan_driver = { diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 10fb4cb2c731..cd0134580a90 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -100,8 +100,13 @@ static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock) static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) { - if (timing == MMC_TIMING_MMC_DDR52) - sdhci_writeb(host, SDMMC_MC1R_DDR, SDMMC_MC1R); + u8 mc1r; + + if (timing == MMC_TIMING_MMC_DDR52) { + mc1r = sdhci_readb(host, SDMMC_MC1R); + mc1r |= SDMMC_MC1R_DDR; + sdhci_writeb(host, mc1r, SDMMC_MC1R); + } sdhci_set_uhs_signaling(host, timing); } diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index bac874ab0b33..4e904850973c 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -15,6 +15,7 @@ #include |
