Broadcom Linux 4.1-1.1
Change-Id: I4fe10beb0bbd7af8c6332ded1de2b0cabc612082
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b841bb7..461698b 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -65,8 +65,6 @@
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
#define ESDHC_TUNING_START_TAP 0x1
-#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64
-
/* pinctrl state */
#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz"
@@ -160,7 +158,6 @@
MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
} multiblock_status;
- u32 uhs_mode;
u32 is_ddr;
};
@@ -382,7 +379,6 @@
if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
ret |= SDHCI_CTRL_TUNED_CLK;
- ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK);
ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
return ret;
@@ -420,7 +416,7 @@
new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
else
new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
- writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
+ writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
return;
case SDHCI_HOST_CONTROL2:
new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
@@ -429,7 +425,6 @@
else
new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
- imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK;
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
if (val & SDHCI_CTRL_TUNED_CLK)
@@ -600,12 +595,14 @@
u32 temp, val;
if (clock == 0) {
+ host->mmc->actual_clock = 0;
+
if (esdhc_is_usdhc(imx_data)) {
val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
host->ioaddr + ESDHC_VENDOR_SPEC);
}
- goto out;
+ return;
}
if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr)
@@ -645,8 +642,6 @@
}
mdelay(1);
-out:
- host->clock = clock;
}
static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
@@ -668,7 +663,7 @@
return -ENOSYS;
}
-static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
+static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
{
u32 ctrl;
@@ -686,8 +681,6 @@
esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl,
SDHCI_HOST_CONTROL);
-
- return 0;
}
static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
@@ -697,7 +690,6 @@
/* FIXME: delay a bit for card to be ready for next tuning due to errors */
mdelay(1);
- pm_runtime_get_sync(host->mmc->parent);
reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
ESDHC_MIX_CTRL_FBCLK_SEL;
@@ -708,59 +700,6 @@
val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
}
-static void esdhc_request_done(struct mmc_request *mrq)
-{
- complete(&mrq->completion);
-}
-
-static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
-{
- struct mmc_command cmd = {0};
- struct mmc_request mrq = {NULL};
- struct mmc_data data = {0};
- struct scatterlist sg;
- char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN];
-
- cmd.opcode = opcode;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern));
-
- mrq.cmd = &cmd;
- mrq.cmd->mrq = &mrq;
- mrq.data = &data;
- mrq.data->mrq = &mrq;
- mrq.cmd->data = mrq.data;
-
- mrq.done = esdhc_request_done;
- init_completion(&(mrq.completion));
-
- disable_irq(host->irq);
- spin_lock(&host->lock);
- host->mrq = &mrq;
-
- sdhci_send_command(host, mrq.cmd);
-
- spin_unlock(&host->lock);
- enable_irq(host->irq);
-
- wait_for_completion(&mrq.completion);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
-}
-
static void esdhc_post_tuning(struct sdhci_host *host)
{
u32 reg;
@@ -778,7 +717,7 @@
min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min);
- if (!esdhc_send_tuning_cmd(host, opcode))
+ if (!mmc_send_tuning(host->mmc))
break;
min += ESDHC_TUNE_CTRL_STEP;
}
@@ -787,7 +726,7 @@
max = min + ESDHC_TUNE_CTRL_STEP;
while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, max);
- if (esdhc_send_tuning_cmd(host, opcode)) {
+ if (mmc_send_tuning(host->mmc)) {
max -= ESDHC_TUNE_CTRL_STEP;
break;
}
@@ -797,7 +736,7 @@
/* use average delay to get the best timing */
avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg);
- ret = esdhc_send_tuning_cmd(host, opcode);
+ ret = mmc_send_tuning(host->mmc);
esdhc_post_tuning(host);
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
@@ -837,28 +776,21 @@
return pinctrl_select_state(imx_data->pinctrl, pinctrl);
}
-static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
- switch (uhs) {
+ switch (timing) {
case MMC_TIMING_UHS_SDR12:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12;
- break;
case MMC_TIMING_UHS_SDR25:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25;
- break;
case MMC_TIMING_UHS_SDR50:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50;
- break;
case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_MMC_HS200:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104;
break;
case MMC_TIMING_UHS_DDR50:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50;
+ case MMC_TIMING_MMC_DDR52:
writel(readl(host->ioaddr + ESDHC_MIX_CTRL) |
ESDHC_MIX_CTRL_DDREN,
host->ioaddr + ESDHC_MIX_CTRL);
@@ -875,7 +807,33 @@
break;
}
- return esdhc_change_pinstate(host, uhs);
+ esdhc_change_pinstate(host, timing);
+}
+
+static void esdhc_reset(struct sdhci_host *host, u8 mask)
+{
+ sdhci_reset(host, mask);
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+ return esdhc_is_usdhc(imx_data) ? 1 << 28 : 1 << 27;
+}
+
+static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+ /* use maximum timeout counter */
+ sdhci_writeb(host, esdhc_is_usdhc(imx_data) ? 0xF : 0xE,
+ SDHCI_TIMEOUT_CONTROL);
}
static struct sdhci_ops sdhci_esdhc_ops = {
@@ -887,9 +845,12 @@
.set_clock = esdhc_pltfm_set_clock,
.get_max_clock = esdhc_pltfm_get_max_clock,
.get_min_clock = esdhc_pltfm_get_min_clock,
+ .get_max_timeout_count = esdhc_get_max_timeout_count,
.get_ro = esdhc_pltfm_get_ro,
- .platform_bus_width = esdhc_pltfm_bus_width,
+ .set_timeout = esdhc_set_timeout,
+ .set_bus_width = esdhc_pltfm_set_bus_width,
.set_uhs_signaling = esdhc_set_uhs_signaling,
+ .reset = esdhc_reset,
};
static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -903,9 +864,11 @@
#ifdef CONFIG_OF
static int
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
+ struct sdhci_host *host,
struct esdhc_platform_data *boarddata)
{
struct device_node *np = pdev->dev.of_node;
+ int ret;
if (!np)
return -ENODEV;
@@ -939,11 +902,22 @@
if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
boarddata->delay_line = 0;
+ mmc_of_parse_voltage(np, &host->ocr_mask);
+
+ /* call to generic mmc_of_parse to support additional capabilities */
+ ret = mmc_of_parse(host->mmc);
+ if (ret)
+ return ret;
+
+ if (!IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc)))
+ host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+
return 0;
}
#else
static inline int
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
+ struct sdhci_host *host,
struct esdhc_platform_data *boarddata)
{
return -ENODEV;
@@ -959,6 +933,7 @@
struct esdhc_platform_data *boarddata;
int err;
struct pltfm_imx_data *imx_data;
+ bool dt = true;
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 0);
if (IS_ERR(host))
@@ -1008,11 +983,8 @@
imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
PINCTRL_STATE_DEFAULT);
- if (IS_ERR(imx_data->pins_default)) {
- err = PTR_ERR(imx_data->pins_default);
- dev_err(mmc_dev(host->mmc), "could not get default state\n");
- goto disable_clk;
- }
+ if (IS_ERR(imx_data->pins_default))
+ dev_warn(mmc_dev(host->mmc), "could not get default state\n");
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@@ -1041,7 +1013,7 @@
host->ioaddr + ESDHC_TUNING_CTRL);
boarddata = &imx_data->boarddata;
- if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
+ if (sdhci_esdhc_imx_probe_dt(pdev, host, boarddata) < 0) {
if (!host->mmc->parent->platform_data) {
dev_err(mmc_dev(host->mmc), "no board data!\n");
err = -EINVAL;
@@ -1049,10 +1021,10 @@
}
imx_data->boarddata = *((struct esdhc_platform_data *)
host->mmc->parent->platform_data);
+ dt = false;
}
-
/* write_protect */
- if (boarddata->wp_type == ESDHC_WP_GPIO) {
+ if (boarddata->wp_type == ESDHC_WP_GPIO && !dt) {
err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio);
if (err) {
dev_err(mmc_dev(host->mmc),
@@ -1065,6 +1037,8 @@
/* card_detect */
switch (boarddata->cd_type) {
case ESDHC_CD_GPIO:
+ if (dt)
+ break;
err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
if (err) {
dev_err(mmc_dev(host->mmc),
@@ -1100,7 +1074,8 @@
}
/* sdr50 and sdr104 needs work on 1.8v signal voltage */
- if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data)) {
+ if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) &&
+ !IS_ERR(imx_data->pins_default)) {
imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
ESDHC_PINCTRL_STATE_100MHZ);
imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
@@ -1121,10 +1096,10 @@
goto disable_clk;
pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
pm_suspend_ignore_children(&pdev->dev, 1);
+ pm_runtime_enable(&pdev->dev);
return 0;
@@ -1144,23 +1119,22 @@
struct pltfm_imx_data *imx_data = pltfm_host->priv;
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
sdhci_remove_host(host, dead);
- pm_runtime_dont_use_autosuspend(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
- if (!IS_ENABLED(CONFIG_PM_RUNTIME)) {
- clk_disable_unprepare(imx_data->clk_per);
- clk_disable_unprepare(imx_data->clk_ipg);
- clk_disable_unprepare(imx_data->clk_ahb);
- }
+ clk_disable_unprepare(imx_data->clk_per);
+ clk_disable_unprepare(imx_data->clk_ipg);
+ clk_disable_unprepare(imx_data->clk_ahb);
sdhci_pltfm_free(pdev);
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int sdhci_esdhc_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
@@ -1170,8 +1144,10 @@
ret = sdhci_runtime_suspend_host(host);
- clk_disable_unprepare(imx_data->clk_per);
- clk_disable_unprepare(imx_data->clk_ipg);
+ if (!sdhci_sdio_irq_enabled(host)) {
+ clk_disable_unprepare(imx_data->clk_per);
+ clk_disable_unprepare(imx_data->clk_ipg);
+ }
clk_disable_unprepare(imx_data->clk_ahb);
return ret;
@@ -1183,8 +1159,10 @@
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
- clk_prepare_enable(imx_data->clk_per);
- clk_prepare_enable(imx_data->clk_ipg);
+ if (!sdhci_sdio_irq_enabled(host)) {
+ clk_prepare_enable(imx_data->clk_per);
+ clk_prepare_enable(imx_data->clk_ipg);
+ }
clk_prepare_enable(imx_data->clk_ahb);
return sdhci_runtime_resume_host(host);
@@ -1200,7 +1178,6 @@
static struct platform_driver sdhci_esdhc_imx_driver = {
.driver = {
.name = "sdhci-esdhc-imx",
- .owner = THIS_MODULE,
.of_match_table = imx_esdhc_dt_ids,
.pm = &sdhci_esdhc_pmops,
},