Tom Rini
2024-04-15 07:38:51 -06:00
20 changed files with 179 additions and 134 deletions

View File

@@ -20,11 +20,19 @@ config MMC_WRITE
config MMC_PWRSEQ config MMC_PWRSEQ
bool "HW reset support for eMMC" bool "HW reset support for eMMC"
depends on PWRSEQ depends on PWRSEQ && DM_GPIO
help help
Ths select Hardware reset support aka pwrseq-emmc for eMMC This select Hardware reset support aka pwrseq-emmc for eMMC
devices. devices.
config SPL_MMC_PWRSEQ
bool "HW reset support for eMMC in SPL"
depends on SPL_PWRSEQ && SPL_DM_GPIO
default y if MMC_PWRSEQ
help
This select Hardware reset support aka pwrseq-emmc for eMMC
devices in SPL.
config MMC_BROKEN_CD config MMC_BROKEN_CD
bool "Poll for broken card detection case" bool "Poll for broken card detection case"
help help
@@ -79,11 +87,12 @@ config MMC_SPI_CRC_ON
config ARM_PL180_MMCI config ARM_PL180_MMCI
bool "ARM AMBA Multimedia Card Interface and compatible support" bool "ARM AMBA Multimedia Card Interface and compatible support"
depends on DM_MMC
help help
This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
Interface (PL180, PL181 and compatible) support. Interface (PL180, PL181 and compatible) support.
If you have an ARM(R) platform with a Multimedia Card slot, If you have an ARM(R) platform with a Multimedia Card slot,
say Y or M here. say Y here.
config MMC_QUIRKS config MMC_QUIRKS
bool "Enable quirks" bool "Enable quirks"
@@ -599,7 +608,7 @@ config MMC_SDHCI_IPROC
This selects the iProc SD/MMC controller. This selects the iProc SD/MMC controller.
If you have a Broadcom IPROC platform with SD or MMC devices, If you have a Broadcom IPROC platform with SD or MMC devices,
say Y or M here. say Y here.
If unsure, say N. If unsure, say N.
@@ -610,7 +619,7 @@ config MMC_SDHCI_F_SDH30
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
Needed by some Fujitsu/Socionext SoC for MMC / SD / SDIO support. Needed by some Fujitsu/Socionext SoC for MMC / SD / SDIO support.
If you have a controller with this interface, say Y or M here. If you have a controller with this interface, say Y here.
If unsure, say N. If unsure, say N.
config MMC_SDHCI_KONA config MMC_SDHCI_KONA
@@ -804,7 +813,7 @@ config STM32_SDMMC2
help help
This selects support for the SD/MMC controller on STM32H7 SoCs. This selects support for the SD/MMC controller on STM32H7 SoCs.
If you have a board based on such a SoC and with a SD/MMC slot, If you have a board based on such a SoC and with a SD/MMC slot,
say Y or M here. say Y here.
config FTSDC010 config FTSDC010
bool "Ftsdc010 SD/MMC controller Support" bool "Ftsdc010 SD/MMC controller Support"
@@ -824,7 +833,7 @@ config MMC_MTK
depends on OF_CONTROL depends on OF_CONTROL
help help
This selects the MediaTek(R) Secure digital and Multimedia card Interface. This selects the MediaTek(R) Secure digital and Multimedia card Interface.
If you have a machine with a integrated SD/MMC card reader, say Y or M here. If you have a machine with a integrated SD/MMC card reader, say Y here.
This is needed if support for any SD/SDIO/MMC devices is required. This is needed if support for any SD/SDIO/MMC devices is required.
If unsure, say N. If unsure, say N.

View File

@@ -11,7 +11,7 @@ obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += mmc_bootdev.o
endif endif
obj-$(CONFIG_$(SPL_TPL_)MMC_WRITE) += mmc_write.o obj-$(CONFIG_$(SPL_TPL_)MMC_WRITE) += mmc_write.o
obj-$(CONFIG_MMC_PWRSEQ) += mmc-pwrseq.o obj-$(CONFIG_$(SPL_)MMC_PWRSEQ) += mmc-pwrseq.o
obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o
ifndef CONFIG_$(SPL_)BLK ifndef CONFIG_$(SPL_)BLK

View File

@@ -390,7 +390,7 @@ static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
for (itap = 0; itap < ITAP_MAX; itap++) { for (itap = 0; itap < ITAP_MAX; itap++) {
am654_sdhci_write_itapdly(plat, itap); am654_sdhci_write_itapdly(plat, itap);
cur_val = !mmc_send_tuning(mmc, opcode, NULL); cur_val = !mmc_send_tuning(mmc, opcode);
if (cur_val && !prev_val) if (cur_val && !prev_val)
pass_window = itap; pass_window = itap;

View File

@@ -18,6 +18,7 @@
#include <malloc.h> #include <malloc.h>
#include <mmc.h> #include <mmc.h>
#include <dm/device_compat.h> #include <dm/device_compat.h>
#include <dm.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm-generic/gpio.h> #include <asm-generic/gpio.h>
@@ -25,8 +26,6 @@
#include "arm_pl180_mmci.h" #include "arm_pl180_mmci.h"
#include <linux/delay.h> #include <linux/delay.h>
#ifdef CONFIG_DM_MMC
#include <dm.h>
#define MMC_CLOCK_MAX 48000000 #define MMC_CLOCK_MAX 48000000
#define MMC_CLOCK_MIN 400000 #define MMC_CLOCK_MIN 400000
@@ -34,7 +33,6 @@ struct arm_pl180_mmc_plat {
struct mmc_config cfg; struct mmc_config cfg;
struct mmc mmc; struct mmc mmc;
}; };
#endif
static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
{ {
@@ -358,65 +356,6 @@ static int host_set_ios(struct mmc *dev)
return 0; return 0;
} }
#ifndef CONFIG_DM_MMC
/* MMC uses open drain drivers in the enumeration phase */
static int mmc_host_reset(struct mmc *dev)
{
struct pl180_mmc_host *host = dev->priv;
writel(host->pwr_init, &host->base->power);
return 0;
}
static const struct mmc_ops arm_pl180_mmci_ops = {
.send_cmd = host_request,
.set_ios = host_set_ios,
.init = mmc_host_reset,
};
/*
* mmc_host_init - initialize the mmc controller.
* Set initial clock and power for mmc slot.
* Initialize mmc struct and register with mmc framework.
*/
int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc)
{
u32 sdi_u32;
writel(host->pwr_init, &host->base->power);
writel(host->clkdiv_init, &host->base->clock);
udelay(CLK_CHANGE_DELAY);
/* Disable mmc interrupts */
sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
writel(sdi_u32, &host->base->mask0);
host->cfg.name = host->name;
host->cfg.ops = &arm_pl180_mmci_ops;
/* TODO remove the duplicates */
host->cfg.host_caps = host->caps;
host->cfg.voltages = host->voltages;
host->cfg.f_min = host->clock_min;
host->cfg.f_max = host->clock_max;
if (host->b_max != 0)
host->cfg.b_max = host->b_max;
else
host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
*mmc = mmc_create(&host->cfg, host);
if (!*mmc)
return -1;
debug("registered mmc interface number is:%d\n",
(*mmc)->block_dev.devnum);
return 0;
}
#endif
#ifdef CONFIG_DM_MMC
static void arm_pl180_mmc_init(struct pl180_mmc_host *host) static void arm_pl180_mmc_init(struct pl180_mmc_host *host)
{ {
u32 sdi_u32; u32 sdi_u32;
@@ -477,7 +416,7 @@ static int arm_pl180_mmc_probe(struct udevice *dev)
host->version2 = true; host->version2 = true;
break; break;
default: default:
host->version2 = true; host->version2 = false; /* ARM variant */
} }
gpio_request_by_name(dev, "cd-gpios", 0, &host->cd_gpio, GPIOD_IS_IN); gpio_request_by_name(dev, "cd-gpios", 0, &host->cd_gpio, GPIOD_IS_IN);
@@ -561,4 +500,3 @@ U_BOOT_DRIVER(arm_pl180_mmc) = {
.priv_auto = sizeof(struct pl180_mmc_host), .priv_auto = sizeof(struct pl180_mmc_host),
.plat_auto = sizeof(struct arm_pl180_mmc_plat), .plat_auto = sizeof(struct arm_pl180_mmc_plat),
}; };
#endif

View File

@@ -42,7 +42,7 @@ static int cv1800b_execute_tuning(struct mmc *mmc, u8 opcode)
for (tap = 0; tap < TUNE_MAX_PHCODE; tap++) { for (tap = 0; tap < TUNE_MAX_PHCODE; tap++) {
cv1800b_set_tap_delay(host, tap); cv1800b_set_tap_delay(host, tap);
if (mmc_send_tuning(host->mmc, opcode, NULL)) { if (mmc_send_tuning(host->mmc, opcode)) {
current_size = 0; current_size = 0;
} else { } else {
current_size++; current_size++;

View File

@@ -262,8 +262,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) {
if (get_timer(start) > timeout) { if (get_timer(start) > timeout) {
debug("%s: Timeout on data busy\n", __func__); debug("%s: Timeout on data busy, continue anyway\n", __func__);
return -ETIMEDOUT; break;
} }
} }

View File

@@ -1123,7 +1123,7 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
esdhc_write32(&regs->irqstaten, IRQSTATEN_BRR); esdhc_write32(&regs->irqstaten, IRQSTATEN_BRR);
for (i = 0; i < MAX_TUNING_LOOP; i++) { for (i = 0; i < MAX_TUNING_LOOP; i++) {
mmc_send_tuning(mmc, opcode, NULL); mmc_send_tuning(mmc, opcode);
mdelay(1); mdelay(1);
val = esdhc_read32(&regs->autoc12err); val = esdhc_read32(&regs->autoc12err);

View File

@@ -882,7 +882,7 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
esdhc_write32(&regs->mixctrl, val); esdhc_write32(&regs->mixctrl, val);
/* We are using STD tuning, no need to check return value */ /* We are using STD tuning, no need to check return value */
mmc_send_tuning(mmc, opcode, NULL); mmc_send_tuning(mmc, opcode);
ctrl = esdhc_read32(&regs->autoc12err); ctrl = esdhc_read32(&regs->autoc12err);
if ((!(ctrl & MIX_CTRL_EXE_TUNE)) && if ((!(ctrl & MIX_CTRL_EXE_TUNE)) &&

View File

@@ -5,15 +5,24 @@
*/ */
#include <common.h> #include <common.h>
#include <clk.h>
#include <dm.h> #include <dm.h>
#include <dwmmc.h> #include <dwmmc.h>
#include <errno.h> #include <errno.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <malloc.h> #include <malloc.h>
#include <reset.h>
#include <asm/global_data.h> #include <asm/global_data.h>
#include <dm/device_compat.h>
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
enum hi6220_dwmmc_clk_type {
HI6220_DWMMC_CLK_BIU,
HI6220_DWMMC_CLK_CIU,
HI6220_DWMMC_CLK_CNT,
};
struct hi6220_dwmmc_plat { struct hi6220_dwmmc_plat {
struct mmc_config cfg; struct mmc_config cfg;
struct mmc mmc; struct mmc mmc;
@@ -21,18 +30,43 @@ struct hi6220_dwmmc_plat {
struct hi6220_dwmmc_priv_data { struct hi6220_dwmmc_priv_data {
struct dwmci_host host; struct dwmci_host host;
struct clk *clks[HI6220_DWMMC_CLK_CNT];
struct reset_ctl_bulk rsts;
}; };
struct hisi_mmc_data { struct hisi_mmc_data {
unsigned int clock; unsigned int clock;
bool use_fifo; bool use_fifo;
u32 fifoth_val;
}; };
static int hi6220_dwmmc_of_to_plat(struct udevice *dev) static int hi6220_dwmmc_of_to_plat(struct udevice *dev)
{ {
struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev);
struct dwmci_host *host = &priv->host; struct dwmci_host *host = &priv->host;
int ret;
if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) {
priv->clks[HI6220_DWMMC_CLK_BIU] = devm_clk_get(dev, "biu");
if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_BIU])) {
ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_BIU]);
dev_err(dev, "Failed to get BIU clock(ret = %d).\n", ret);
return log_msg_ret("clk", ret);
}
priv->clks[HI6220_DWMMC_CLK_CIU] = devm_clk_get(dev, "ciu");
if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_CIU])) {
ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_CIU]);
dev_err(dev, "Failed to get CIU clock(ret = %d).\n", ret);
return log_msg_ret("clk", ret);
}
ret = reset_get_bulk(dev, &priv->rsts);
if (ret) {
dev_err(dev, "Failed to get resets(ret = %d)", ret);
return log_msg_ret("rst", ret);
}
}
host->name = dev->name; host->name = dev->name;
host->ioaddr = dev_read_addr_ptr(dev); host->ioaddr = dev_read_addr_ptr(dev);
host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
@@ -56,16 +90,43 @@ static int hi6220_dwmmc_probe(struct udevice *dev)
struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev);
struct dwmci_host *host = &priv->host; struct dwmci_host *host = &priv->host;
struct hisi_mmc_data *mmc_data; struct hisi_mmc_data *mmc_data;
int ret;
mmc_data = (struct hisi_mmc_data *)dev_get_driver_data(dev); mmc_data = (struct hisi_mmc_data *)dev_get_driver_data(dev);
/* Use default bus speed due to absence of clk driver */
host->bus_hz = mmc_data->clock; host->bus_hz = mmc_data->clock;
if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) {
ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_BIU]);
if (ret) {
dev_err(dev, "Failed to enable biu clock(ret = %d).\n", ret);
return log_msg_ret("clk", ret);
}
ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_CIU]);
if (ret) {
dev_err(dev, "Failed to enable ciu clock(ret = %d).\n", ret);
return log_msg_ret("clk", ret);
}
ret = reset_deassert_bulk(&priv->rsts);
if (ret) {
dev_err(dev, "Failed to deassert resets(ret = %d).\n", ret);
return log_msg_ret("rst", ret);
}
host->bus_hz = clk_get_rate(priv->clks[HI6220_DWMMC_CLK_CIU]);
if (host->bus_hz <= 0) {
dev_err(dev, "Failed to get ciu clock rate(ret = %d).\n", ret);
return log_msg_ret("clk", ret);
}
}
dev_dbg(dev, "bus clock rate: %d.\n", host->bus_hz);
dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 400000); dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 400000);
host->mmc = &plat->mmc; host->mmc = &plat->mmc;
host->fifo_mode = mmc_data->use_fifo; host->fifo_mode = mmc_data->use_fifo;
host->fifoth_val = mmc_data->fifoth_val;
host->mmc->priv = &priv->host; host->mmc->priv = &priv->host;
upriv->mmc = host->mmc; upriv->mmc = host->mmc;
host->mmc->dev = dev; host->mmc->dev = dev;
@@ -95,13 +156,20 @@ static const struct hisi_mmc_data hi6220_mmc_data = {
.use_fifo = false, .use_fifo = false,
}; };
static const struct hisi_mmc_data hi3798mv2x_mmc_data = {
.clock = 50000000,
.use_fifo = false,
// FIFO depth is 256
.fifoth_val = MSIZE(4) | RX_WMARK(0x7f) | TX_WMARK(0x80),
};
static const struct udevice_id hi6220_dwmmc_ids[] = { static const struct udevice_id hi6220_dwmmc_ids[] = {
{ .compatible = "hisilicon,hi6220-dw-mshc", { .compatible = "hisilicon,hi6220-dw-mshc",
.data = (ulong)&hi6220_mmc_data }, .data = (ulong)&hi6220_mmc_data },
{ .compatible = "hisilicon,hi3798cv200-dw-mshc", { .compatible = "hisilicon,hi3798cv200-dw-mshc",
.data = (ulong)&hi6220_mmc_data }, .data = (ulong)&hi6220_mmc_data },
{ .compatible = "hisilicon,hi3798mv200-dw-mshc", { .compatible = "hisilicon,hi3798mv200-dw-mshc",
.data = (ulong)&hi6220_mmc_data }, .data = (ulong)&hi3798mv2x_mmc_data },
{ .compatible = "hisilicon,hi3660-dw-mshc", { .compatible = "hisilicon,hi3660-dw-mshc",
.data = (ulong)&hi3660_mmc_data }, .data = (ulong)&hi3660_mmc_data },
{ } { }

View File

@@ -288,7 +288,7 @@ static int meson_mmc_probe(struct udevice *dev)
mmc_set_clock(mmc, cfg->f_min, MMC_CLK_ENABLE); mmc_set_clock(mmc, cfg->f_min, MMC_CLK_ENABLE);
#ifdef CONFIG_MMC_PWRSEQ #if CONFIG_IS_ENABLED(MMC_PWRSEQ)
/* Enable power if needed */ /* Enable power if needed */
ret = mmc_pwrseq_get_power(dev, cfg); ret = mmc_pwrseq_get_power(dev, cfg);
if (!ret) { if (!ret) {

View File

@@ -124,7 +124,13 @@ static int dm_mmc_execute_tuning(struct udevice *dev, uint opcode)
int mmc_execute_tuning(struct mmc *mmc, uint opcode) int mmc_execute_tuning(struct mmc *mmc, uint opcode)
{ {
return dm_mmc_execute_tuning(mmc->dev, opcode); int ret;
mmc->tuning = true;
ret = dm_mmc_execute_tuning(mmc->dev, opcode);
mmc->tuning = false;
return ret;
} }
#endif #endif
@@ -494,9 +500,6 @@ static int mmc_blk_probe(struct udevice *dev)
if (ret) { if (ret) {
debug("Probing %s failed (err=%d)\n", dev->name, ret); debug("Probing %s failed (err=%d)\n", dev->name, ret);
if (CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) ||
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) ||
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT))
mmc_deinit(mmc); mmc_deinit(mmc);
return ret; return ret;
@@ -505,9 +508,6 @@ static int mmc_blk_probe(struct udevice *dev)
return 0; return 0;
} }
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
static int mmc_blk_remove(struct udevice *dev) static int mmc_blk_remove(struct udevice *dev)
{ {
struct udevice *mmc_dev = dev_get_parent(dev); struct udevice *mmc_dev = dev_get_parent(dev);
@@ -516,7 +516,6 @@ static int mmc_blk_remove(struct udevice *dev)
return mmc_deinit(mmc); return mmc_deinit(mmc);
} }
#endif
static const struct blk_ops mmc_blk_ops = { static const struct blk_ops mmc_blk_ops = {
.read = mmc_bread, .read = mmc_bread,
@@ -532,12 +531,8 @@ U_BOOT_DRIVER(mmc_blk) = {
.id = UCLASS_BLK, .id = UCLASS_BLK,
.ops = &mmc_blk_ops, .ops = &mmc_blk_ops,
.probe = mmc_blk_probe, .probe = mmc_blk_probe,
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
.remove = mmc_blk_remove, .remove = mmc_blk_remove,
.flags = DM_FLAG_OS_PREPARE, .flags = DM_FLAG_OS_PREPARE,
#endif
}; };
#endif /* CONFIG_BLK */ #endif /* CONFIG_BLK */

View File

@@ -360,7 +360,7 @@ static const u8 tuning_blk_pattern_8bit[] = {
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
}; };
int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error) int mmc_send_tuning(struct mmc *mmc, u32 opcode)
{ {
struct mmc_cmd cmd; struct mmc_cmd cmd;
struct mmc_data data; struct mmc_data data;
@@ -1570,13 +1570,20 @@ static int sd_read_ssr(struct mmc *mmc)
return 0; return 0;
} }
#endif #endif
/* frequency bases */ /*
/* divided by 10 to be nice to platforms without floating point */ * TRAN_SPEED bits 0:2 encode the frequency unit:
* 0 = 100KHz, 1 = 1MHz, 2 = 10MHz, 3 = 100MHz, values 4 - 7 are reserved.
* The values in fbase[] are divided by 10 to avoid floats in multiplier[].
*/
static const int fbase[] = { static const int fbase[] = {
10000, 10000,
100000, 100000,
1000000, 1000000,
10000000, 10000000,
0, /* reserved */
0, /* reserved */
0, /* reserved */
0, /* reserved */
}; };
/* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice
@@ -2027,9 +2034,9 @@ static int mmc_select_hs400(struct mmc *mmc)
mmc_set_clock(mmc, mmc->tran_speed, false); mmc_set_clock(mmc, mmc->tran_speed, false);
/* execute tuning if needed */ /* execute tuning if needed */
mmc->hs400_tuning = 1; mmc->hs400_tuning = true;
err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200); err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
mmc->hs400_tuning = 0; mmc->hs400_tuning = false;
if (err) { if (err) {
debug("tuning failed\n"); debug("tuning failed\n");
return err; return err;
@@ -2250,6 +2257,16 @@ error:
return -ENOTSUPP; return -ENOTSUPP;
} }
#else
static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
{
return 0;
};
static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
{
return 0;
};
#endif #endif
#if CONFIG_IS_ENABLED(MMC_TINY) #if CONFIG_IS_ENABLED(MMC_TINY)
@@ -2560,6 +2577,8 @@ static int mmc_startup(struct mmc *mmc)
mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
mmc->legacy_speed = freq * mult; mmc->legacy_speed = freq * mult;
if (!mmc->legacy_speed)
log_debug("TRAN_SPEED: reserved value");
mmc_select_mode(mmc, MMC_LEGACY); mmc_select_mode(mmc, MMC_LEGACY);
mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
@@ -3010,13 +3029,15 @@ int mmc_init(struct mmc *mmc)
return err; return err;
} }
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
int mmc_deinit(struct mmc *mmc) int mmc_deinit(struct mmc *mmc)
{ {
u32 caps_filtered; u32 caps_filtered;
if (!CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) &&
!CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) &&
!CONFIG_IS_ENABLED(MMC_HS400_SUPPORT))
return 0;
if (!mmc->has_init) if (!mmc->has_init)
return 0; return 0;
@@ -3034,7 +3055,6 @@ int mmc_deinit(struct mmc *mmc)
return mmc_select_mode_and_width(mmc, caps_filtered); return mmc_select_mode_and_width(mmc, caps_filtered);
} }
} }
#endif
int mmc_set_dsr(struct mmc *mmc, u16 val) int mmc_set_dsr(struct mmc *mmc, u16 val)
{ {

View File

@@ -1131,7 +1131,7 @@ static int hs400_tune_response(struct udevice *dev, u32 opcode)
i << PAD_CMD_TUNE_RX_DLY3_S); i << PAD_CMD_TUNE_RX_DLY3_S);
for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
mmc_send_tuning(mmc, opcode, &cmd_err); cmd_err = mmc_send_tuning(mmc, opcode);
if (!cmd_err) { if (!cmd_err) {
cmd_delay |= (1 << i); cmd_delay |= (1 << i);
} else { } else {
@@ -1181,7 +1181,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode)
i << MSDC_PAD_TUNE_CMDRDLY_S); i << MSDC_PAD_TUNE_CMDRDLY_S);
for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
mmc_send_tuning(mmc, opcode, &cmd_err); cmd_err = mmc_send_tuning(mmc, opcode);
if (!cmd_err) { if (!cmd_err) {
rise_delay |= (1 << i); rise_delay |= (1 << i);
} else { } else {
@@ -1203,7 +1203,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode)
i << MSDC_PAD_TUNE_CMDRDLY_S); i << MSDC_PAD_TUNE_CMDRDLY_S);
for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
mmc_send_tuning(mmc, opcode, &cmd_err); cmd_err = mmc_send_tuning(mmc, opcode);
if (!cmd_err) { if (!cmd_err) {
fall_delay |= (1 << i); fall_delay |= (1 << i);
} else { } else {
@@ -1238,7 +1238,7 @@ skip_fall:
clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M, clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M,
i << MSDC_PAD_TUNE_CMDRRDLY_S); i << MSDC_PAD_TUNE_CMDRRDLY_S);
mmc_send_tuning(mmc, opcode, &cmd_err); cmd_err = mmc_send_tuning(mmc, opcode);
if (!cmd_err) if (!cmd_err)
internal_delay |= (1 << i); internal_delay |= (1 << i);
} }
@@ -1264,7 +1264,6 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode)
struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0, }; struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0, };
u8 final_delay, final_maxlen; u8 final_delay, final_maxlen;
void __iomem *tune_reg = &host->base->pad_tune; void __iomem *tune_reg = &host->base->pad_tune;
int cmd_err;
int i, ret; int i, ret;
if (host->dev_comp->pad_tune0) if (host->dev_comp->pad_tune0)
@@ -1277,10 +1276,10 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode)
clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M, clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M,
i << MSDC_PAD_TUNE_DATRRDLY_S); i << MSDC_PAD_TUNE_DATRRDLY_S);
ret = mmc_send_tuning(mmc, opcode, &cmd_err); ret = mmc_send_tuning(mmc, opcode);
if (!ret) { if (!ret) {
rise_delay |= (1 << i); rise_delay |= (1 << i);
} else if (cmd_err) { } else {
/* in this case, retune response is needed */ /* in this case, retune response is needed */
ret = msdc_tune_response(dev, opcode); ret = msdc_tune_response(dev, opcode);
if (ret) if (ret)
@@ -1300,10 +1299,10 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode)
clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M, clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M,
i << MSDC_PAD_TUNE_DATRRDLY_S); i << MSDC_PAD_TUNE_DATRRDLY_S);
ret = mmc_send_tuning(mmc, opcode, &cmd_err); ret = mmc_send_tuning(mmc, opcode);
if (!ret) { if (!ret) {
fall_delay |= (1 << i); fall_delay |= (1 << i);
} else if (cmd_err) { } else {
/* in this case, retune response is needed */ /* in this case, retune response is needed */
ret = msdc_tune_response(dev, opcode); ret = msdc_tune_response(dev, opcode);
if (ret) if (ret)
@@ -1362,7 +1361,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode)
for (i = 0; i < PAD_DELAY_MAX; i++) { for (i = 0; i < PAD_DELAY_MAX; i++) {
msdc_set_cmd_delay(host, i); msdc_set_cmd_delay(host, i);
msdc_set_data_delay(host, i); msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL); ret = mmc_send_tuning(mmc, opcode);
if (!ret) if (!ret)
rise_delay |= (1 << i); rise_delay |= (1 << i);
} }
@@ -1378,7 +1377,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode)
for (i = 0; i < PAD_DELAY_MAX; i++) { for (i = 0; i < PAD_DELAY_MAX; i++) {
msdc_set_cmd_delay(host, i); msdc_set_cmd_delay(host, i);
msdc_set_data_delay(host, i); msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL); ret = mmc_send_tuning(mmc, opcode);
if (!ret) if (!ret)
fall_delay |= (1 << i); fall_delay |= (1 << i);
} }

View File

@@ -1653,6 +1653,12 @@ static int octeontx_mmc_test_cmd(struct mmc *mmc, u32 opcode, int *statp)
return err; return err;
} }
static int octeontx_mmc_send_tuning(struct mmc *mmc, u32 opcode, int *error)
{
*error = 0;
return mmc_send_tuning(mmc, opcode);
}
static int octeontx_mmc_test_get_ext_csd(struct mmc *mmc, u32 opcode, static int octeontx_mmc_test_get_ext_csd(struct mmc *mmc, u32 opcode,
int *statp) int *statp)
{ {
@@ -2006,7 +2012,7 @@ struct adj adj[] = {
{ "CMD_IN", 48, octeontx_mmc_test_cmd, MMC_CMD_SEND_STATUS, { "CMD_IN", 48, octeontx_mmc_test_cmd, MMC_CMD_SEND_STATUS,
false, false, false, 2, }, false, false, false, 2, },
/* { "CMD_OUT", 32, octeontx_mmc_test_cmd, MMC_CMD_SEND_STATUS, },*/ /* { "CMD_OUT", 32, octeontx_mmc_test_cmd, MMC_CMD_SEND_STATUS, },*/
{ "DATA_IN(HS200)", 16, mmc_send_tuning, { "DATA_IN(HS200)", 16, octeontx_mmc_send_tuning,
MMC_CMD_SEND_TUNING_BLOCK_HS200, false, true, false, 2, }, MMC_CMD_SEND_TUNING_BLOCK_HS200, false, true, false, 2, },
{ "DATA_IN", 16, octeontx_mmc_test_get_ext_csd, 0, false, false, { "DATA_IN", 16, octeontx_mmc_test_get_ext_csd, 0, false, false,
true, 2, }, true, 2, },

View File

@@ -666,7 +666,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode)
while (phase_delay <= MAX_PHASE_DELAY) { while (phase_delay <= MAX_PHASE_DELAY) {
omap_hsmmc_set_dll(mmc, phase_delay); omap_hsmmc_set_dll(mmc, phase_delay);
cur_match = !mmc_send_tuning(mmc, opcode, NULL); cur_match = !mmc_send_tuning(mmc, opcode);
if (cur_match) { if (cur_match) {
if (prev_match) { if (prev_match) {
@@ -731,7 +731,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode)
*/ */
for (i = 3; i <= 10; i++) { for (i = 3; i <= 10; i++) {
omap_hsmmc_set_dll(mmc, phase_delay + i); omap_hsmmc_set_dll(mmc, phase_delay + i);
if (mmc_send_tuning(mmc, opcode, NULL)) { if (mmc_send_tuning(mmc, opcode)) {
if (temperature < 10000) if (temperature < 10000)
phase_delay += i + 6; phase_delay += i + 6;
else if (temperature < 20000) else if (temperature < 20000)
@@ -749,7 +749,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode)
for (i = 2; i >= -10; i--) { for (i = 2; i >= -10; i--) {
omap_hsmmc_set_dll(mmc, phase_delay + i); omap_hsmmc_set_dll(mmc, phase_delay + i);
if (mmc_send_tuning(mmc, opcode, NULL)) { if (mmc_send_tuning(mmc, opcode)) {
if (temperature < 10000) if (temperature < 10000)
phase_delay += i + 12; phase_delay += i + 12;
else if (temperature < 20000) else if (temperature < 20000)

View File

@@ -568,8 +568,8 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode)
struct mmc *mmc = upriv->mmc; struct mmc *mmc = upriv->mmc;
unsigned int tap_num; unsigned int tap_num;
unsigned int taps = 0; unsigned int taps = 0;
int i, ret = 0; int i, ret = 0, sret;
u32 caps; u32 caps, reg;
/* Only supported on Renesas RCar */ /* Only supported on Renesas RCar */
if (!(priv->caps & TMIO_SD_CAP_RCAR_UHS)) if (!(priv->caps & TMIO_SD_CAP_RCAR_UHS))
@@ -605,15 +605,15 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode)
caps = priv->caps; caps = priv->caps;
priv->caps &= ~TMIO_SD_CAP_DMA_INTERNAL; priv->caps &= ~TMIO_SD_CAP_DMA_INTERNAL;
ret = mmc_send_tuning(mmc, opcode, NULL); ret = mmc_send_tuning(mmc, opcode);
priv->caps = caps; priv->caps = caps;
if (ret == 0) if (ret == 0)
taps |= BIT(i); taps |= BIT(i);
ret = renesas_sdhi_compare_scc_data(priv); reg = renesas_sdhi_compare_scc_data(priv);
if (ret == 0) if (reg == 0)
priv->smpcmp |= BIT(i); priv->smpcmp |= BIT(i);
mdelay(1); mdelay(1);
@@ -624,9 +624,9 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode)
* eMMC. * eMMC.
*/ */
if (ret && (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200)) { if (ret && (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200)) {
ret = mmc_send_stop_transmission(mmc, false); sret = mmc_send_stop_transmission(mmc, false);
if (ret < 0) if (sret < 0)
dev_dbg(dev, "Tuning abort fail (%d)\n", ret); dev_dbg(dev, "Tuning abort fail (%d)\n", sret);
} }
} }
@@ -798,8 +798,11 @@ static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct tmio_sd_priv *priv = dev_get_priv(dev); struct tmio_sd_priv *priv = dev_get_priv(dev);
struct mmc *mmc = upriv->mmc;
if (!mmc->tuning)
renesas_sdhi_check_scc_error(dev); renesas_sdhi_check_scc_error(dev);
if (cmd->cmdidx == MMC_CMD_SEND_STATUS) if (cmd->cmdidx == MMC_CMD_SEND_STATUS)

View File

@@ -145,7 +145,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
host->fifo_mode = priv->fifo_mode; host->fifo_mode = priv->fifo_mode;
#ifdef CONFIG_MMC_PWRSEQ #if CONFIG_IS_ENABLED(MMC_PWRSEQ)
/* Enable power if needed */ /* Enable power if needed */
ret = mmc_pwrseq_get_power(dev, &plat->cfg); ret = mmc_pwrseq_get_power(dev, &plat->cfg);
if (!ret) { if (!ret) {

View File

@@ -224,7 +224,7 @@ static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev,
for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) { for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
if (sdhci_cdns_set_tune_val(plat, i) || if (sdhci_cdns_set_tune_val(plat, i) ||
mmc_send_tuning(mmc, opcode, NULL)) { /* bad */ mmc_send_tuning(mmc, opcode)) { /* bad */
cur_streak = 0; cur_streak = 0;
} else { /* good */ } else { /* good */
cur_streak++; cur_streak++;

View File

@@ -299,7 +299,13 @@ static int tmio_sd_dma_wait_for_irq(struct udevice *dev, u32 flag,
struct tmio_sd_priv *priv = dev_get_priv(dev); struct tmio_sd_priv *priv = dev_get_priv(dev);
long wait = 1000000 + 10 * blocks; long wait = 1000000 + 10 * blocks;
while (!(tmio_sd_readl(priv, TMIO_SD_DMA_INFO1) & flag)) { for (;;) {
if (tmio_sd_readl(priv, TMIO_SD_DMA_INFO1) & flag)
break;
if (tmio_sd_readl(priv, TMIO_SD_INFO1) & TMIO_SD_INFO1_CMP)
break;
if (wait-- < 0) { if (wait-- < 0) {
dev_err(dev, "timeout during DMA\n"); dev_err(dev, "timeout during DMA\n");
return -ETIMEDOUT; return -ETIMEDOUT;

View File

@@ -590,7 +590,7 @@ struct mmc_config {
uint f_max; uint f_max;
uint b_max; uint b_max;
unsigned char part_type; unsigned char part_type;
#ifdef CONFIG_MMC_PWRSEQ #if CONFIG_IS_ENABLED(MMC_PWRSEQ)
struct udevice *pwr_dev; struct udevice *pwr_dev;
#endif #endif
}; };
@@ -736,7 +736,8 @@ struct mmc {
* accessing the boot partitions * accessing the boot partitions
*/ */
u32 quirks; u32 quirks;
u8 hs400_tuning; bool tuning:1;
bool hs400_tuning:1;
enum bus_mode user_speed_mode; /* input speed mode from user */ enum bus_mode user_speed_mode; /* input speed mode from user */
}; };
@@ -795,7 +796,7 @@ int mmc_unbind(struct udevice *dev);
int mmc_initialize(struct bd_info *bis); int mmc_initialize(struct bd_info *bis);
int mmc_init_device(int num); int mmc_init_device(int num);
int mmc_init(struct mmc *mmc); int mmc_init(struct mmc *mmc);
int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error); int mmc_send_tuning(struct mmc *mmc, u32 opcode);
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data); int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data);
int mmc_deinit(struct mmc *mmc); int mmc_deinit(struct mmc *mmc);
@@ -808,7 +809,7 @@ int mmc_deinit(struct mmc *mmc);
*/ */
int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg); int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg);
#ifdef CONFIG_MMC_PWRSEQ #if CONFIG_IS_ENABLED(MMC_PWRSEQ)
/** /**
* mmc_pwrseq_get_power() - get a power device from device tree * mmc_pwrseq_get_power() - get a power device from device tree
* *