MMC core:

- Fix host controller programming for eMMC fixed driver type
 
 MMC host:
  - dw_mmc-rockchip: Add missing private data for very old controllers
  - litex_mmc: Fix clock management
  - renesas_sdhi: Add OF entry for RZ/G2H SoC
  - sdhci: Manage signal voltage switch during system resume for some hosts
  - sdhci-of-dwcmshc: Fix reset, clk and SDIO support for Eswin EIC7700
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmof3pUQHHVsZmhAa2Vy
 bmVsLm9yZwAKCRD+JoQlc1iMKTM9D/40JpQ+GAHqNJSEHxnomty8kmgvOL91jBjA
 jwbIjU40sY2VQq7Q8e7zM46MQJZTU6I2extKLwEYqEaGXHaznNDnNfd2IzL7be7Y
 +isRKpOw0hx9+dOInMRyv8Zz/Qypz6cuGWkuc8Ac2fYEpcBOvs5afK9EvkHDBMwZ
 VlG5f71AzgUsU6DSMI6HdB+GN6rsXuaQKTQ414QkTSnTdrwdCn+c0nAXXVBztU00
 twK+GAw+KSPpmnoy04gaDHFkEvxNor1ylFazrAp3W6PR0cHoXUwldDaU/V0cplLG
 NRKXl/heQJAnTbM8aTG+a7ALHrh0FEfbuLwn6uSL2cbWy5PkiYY++K5DbJs6YmDu
 MpQbNqCjyznWv7CGeFwbxVvFz/Dcb8zobvfcTUiSUT8zTIPRpoZKOWrhy0w7DO70
 LiWrzUF5ImKDEK5g0GCzOGpcoYc8tPabf6PBUVndVYn+31JMIh0Gksog+vWidAqS
 Z+OGRiCxTqj9PWCelki3Qr8YdcXYmF/vw042aTvSClFaaJB4yXMFn4ObFoNdLg4k
 HTbfMI7MIw082q2dWlnnBDRQ0HfZZhwFiwG0HzYzVlCN8xdXGNbXsDTWLVaXclk2
 RItWpBNMClCE1XhhzPPeYjObetagQTnUnhBEFwSGZJM/keAg2166X6R22JykH+sv
 kNPbaX/Psg==
 =pg25
 -----END PGP SIGNATURE-----

Merge tag 'mmc-v7.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC fixes from Ulf Hansson:
 "MMC core:
   - Fix host controller programming for eMMC fixed driver type

  MMC host:
   - dw_mmc-rockchip: Add missing private data for very old controllers
   - litex_mmc: Fix clock management
   - renesas_sdhi: Add OF entry for RZ/G2H SoC
   - sdhci: Manage signal voltage switch during system resume for some hosts
   - sdhci-of-dwcmshc: Fix reset, clk and SDIO support for Eswin EIC7700"

* tag 'mmc-v7.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: sdhci: add signal voltage switch in sdhci_resume_host
  mmc: dw_mmc-rockchip: Add missing private data for very old controllers
  mmc: litex_mmc: Set mandatory idle clocks before CMD0
  mmc: litex_mmc: Use DIV_ROUND_UP for more accurate clock calculation
  mmc: renesas_sdhi: Add OF entry for RZ/G2H SoC
  mmc: sdhci-of-dwcmshc: Fix reset, clk, and SDIO support for Eswin EIC7700
  mmc: core: Fix host controller programming for fixed driver type
This commit is contained in:
Linus Torvalds 2026-06-03 09:09:24 -07:00
commit 9154c4af78
6 changed files with 61 additions and 26 deletions

View file

@ -1371,7 +1371,9 @@ static void mmc_select_driver_type(struct mmc_card *card)
card->drive_strength = drive_strength;
if (drv_type)
if (fixed_drv_type >= 0 && drive_strength)
mmc_set_driver_type(card->host, drive_strength);
else if (drv_type)
mmc_set_driver_type(card->host, drv_type);
}

View file

@ -441,6 +441,22 @@ static int dw_mci_common_parse_dt(struct dw_mci *host)
return 0;
}
static int dw_mci_rk2928_parse_dt(struct dw_mci *host)
{
struct dw_mci_rockchip_priv_data *priv;
int err;
err = dw_mci_common_parse_dt(host);
if (err)
return err;
priv = host->priv;
priv->internal_phase = false;
return 0;
}
static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
{
struct dw_mci_rockchip_priv_data *priv;
@ -514,6 +530,7 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
static const struct dw_mci_drv_data rk2928_drv_data = {
.init = dw_mci_rockchip_init,
.parse_dt = dw_mci_rk2928_parse_dt,
};
static const struct dw_mci_drv_data rk3288_drv_data = {

View file

@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/litex.h>
#include <linux/math.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@ -68,6 +69,9 @@
#define SD_SLEEP_US 5
#define SD_TIMEOUT_US 20000
#define SD_INIT_DELAY_US 1000
#define SD_INIT_CLK_HZ 400000
#define SDIRQ_CARD_DETECT 1
#define SDIRQ_SD_TO_MEM_DONE 2
#define SDIRQ_MEM_TO_SD_DONE 4
@ -436,11 +440,10 @@ static void litex_mmc_setclk(struct litex_mmc_host *host, unsigned int freq)
struct device *dev = mmc_dev(host->mmc);
u32 div;
div = freq ? host->ref_clk / freq : 256U;
div = roundup_pow_of_two(div);
div = freq ? DIV_ROUND_UP(host->ref_clk, freq) : 256U;
div = clamp(div, 2U, 256U);
dev_dbg(dev, "sd_clk_freq=%d: set to %d via div=%d\n",
freq, host->ref_clk / div, div);
freq, host->ref_clk / ((div + 1) & ~1U), div);
litex_write16(host->sdphy + LITEX_PHY_CLOCKERDIV, div);
host->sd_clk = freq;
}
@ -449,6 +452,17 @@ static void litex_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct litex_mmc_host *host = mmc_priv(mmc);
/*
* The SD specification requires at least 74 idle clocks before CMD0.
* These dummy cycles is generated by writing LITEX_PHY_INITIALIZE.
*/
if (ios->chip_select == MMC_CS_HIGH) {
litex_mmc_setclk(host, SD_INIT_CLK_HZ);
litex_write8(host->sdphy + LITEX_PHY_INITIALIZE, 1);
fsleep(SD_INIT_DELAY_US);
return;
}
/*
* NOTE: Ignore any ios->bus_width updates; they occur right after
* the mmc core sends its own acmd6 bus-width change notification,

View file

@ -279,6 +279,7 @@ static const struct renesas_sdhi_of_data_with_quirks of_rza2_compatible = {
static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
{ .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a774e1", .data = &of_r8a7795_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_r8a7795_compatible, },
{ .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, },
{ .compatible = "renesas,sdhi-r8a77965", .data = &of_r8a77965_compatible, },

View file

@ -277,6 +277,7 @@
#define PHY_DELAY_CODE_MAX 0x7f
#define PHY_DELAY_CODE_EMMC 0x17
#define PHY_DELAY_CODE_SD 0x55
#define PHY_DELAY_CODE_SDIO 0x29
struct rk35xx_priv {
struct reset_control *reset;
@ -1433,10 +1434,7 @@ static void sdhci_eic7700_set_clock(struct sdhci_host *host, unsigned int clock)
clk_set_rate(pltfm_host->clk, clock);
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
dwcmshc_enable_card_clk(host);
sdhci_enable_clk(host, clk);
}
static void sdhci_eic7700_config_phy_delay(struct sdhci_host *host, int delay)
@ -1497,7 +1495,7 @@ static void sdhci_eic7700_config_phy(struct sdhci_host *host)
static void sdhci_eic7700_reset(struct sdhci_host *host, u8 mask)
{
sdhci_reset(host, mask);
dwcmshc_reset(host, mask);
/* after reset all, the phy's config will be clear */
if (mask == SDHCI_RESET_ALL)
@ -1594,18 +1592,17 @@ static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 opcode)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO;
u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
int phase_code = -1;
int code_range = -1;
bool is_sd = false;
int code_min = -1;
int code_max = -1;
int cmd_error = 0;
bool is_emmc;
int ret = 0;
int i = 0;
if ((host->mmc->caps2 & sd_caps) == sd_caps)
is_sd = true;
is_emmc = (host->mmc->caps2 & emmc_caps) == emmc_caps;
for (i = 0; i <= MAX_PHASE_CODE; i++) {
/* Centered Phase code */
@ -1614,8 +1611,8 @@ static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 opcode)
host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
if (ret) {
/* SD specific range tracking */
if (is_sd && code_min != -1 && code_max != -1) {
/* SD/SDIO specific range tracking */
if (!is_emmc && code_min != -1 && code_max != -1) {
if (code_max - code_min > code_range) {
code_range = code_max - code_min;
phase_code = (code_min + code_max) / 2;
@ -1626,17 +1623,17 @@ static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 opcode)
code_max = -1;
}
/* EMMC breaks after first valid range */
if (!is_sd && code_min != -1 && code_max != -1)
if (is_emmc && code_min != -1 && code_max != -1)
break;
} else {
/* Track valid phase code range */
if (code_min == -1) {
code_min = i;
if (!is_sd)
if (is_emmc)
continue;
}
code_max = i;
if (is_sd && i == MAX_PHASE_CODE) {
if (!is_emmc && i == MAX_PHASE_CODE) {
if (code_max - code_min > code_range) {
code_range = code_max - code_min;
phase_code = (code_min + code_max) / 2;
@ -1646,19 +1643,19 @@ static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 opcode)
}
/* Handle tuning failure case */
if ((is_sd && phase_code == -1) ||
(!is_sd && code_min == -1 && code_max == -1)) {
if ((!is_emmc && phase_code == -1) ||
(is_emmc && code_min == -1 && code_max == -1)) {
pr_err("%s: phase code tuning failed!\n", mmc_hostname(host->mmc));
sdhci_writew(host, 0, priv->vendor_specific_area1 + DWCMSHC_AT_STAT);
return -EIO;
}
if (!is_sd)
if (is_emmc)
phase_code = (code_min + code_max) / 2;
sdhci_writew(host, phase_code, priv->vendor_specific_area1 + DWCMSHC_AT_STAT);
/* SD specific final verification */
if (is_sd) {
/* SD/SDIO specific final verification */
if (!is_emmc) {
ret = mmc_send_tuning(host->mmc, opcode, &cmd_error);
host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
if (ret) {
@ -1756,9 +1753,9 @@ static void sdhci_eic7700_set_uhs_signaling(struct sdhci_host *host, unsigned in
static void sdhci_eic7700_set_uhs_wrapper(struct sdhci_host *host, unsigned int timing)
{
u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO;
u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
if ((host->mmc->caps2 & sd_caps) == sd_caps)
if ((host->mmc->caps2 & emmc_caps) != emmc_caps)
sdhci_set_uhs_signaling(host, timing);
else
sdhci_eic7700_set_uhs_signaling(host, timing);
@ -1767,6 +1764,7 @@ static void sdhci_eic7700_set_uhs_wrapper(struct sdhci_host *host, unsigned int
static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
{
u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO;
unsigned int val, hsp_int_status, hsp_pwr_ctrl;
static const char * const clk_ids[] = {"axi"};
struct of_phandle_args args;
@ -1821,8 +1819,10 @@ static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcm
if ((host->mmc->caps2 & emmc_caps) == emmc_caps)
dwc_priv->delay_line = PHY_DELAY_CODE_EMMC;
else
else if ((host->mmc->caps2 & sd_caps) == sd_caps)
dwc_priv->delay_line = PHY_DELAY_CODE_SD;
else
dwc_priv->delay_line = PHY_DELAY_CODE_SDIO;
if (!of_property_read_u32(dev->of_node, "eswin,drive-impedance-ohms", &val))
priv->drive_impedance = eic7700_convert_drive_impedance_ohm(dev, val);

View file

@ -3836,6 +3836,7 @@ int sdhci_resume_host(struct sdhci_host *host)
host->pwr = 0;
host->clock = 0;
host->reinit_uhs = true;
mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
mmc->ops->set_ios(mmc, &mmc->ios);
} else {
sdhci_init(host, (mmc->pm_flags & MMC_PM_KEEP_POWER));