diff options
Diffstat (limited to 'drivers/mmc/host')
44 files changed, 1508 insertions, 626 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d5ae22fbb..2c1af1056 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -122,6 +122,7 @@ config MMC_SDHCI_OF_ARASAN tristate "SDHCI OF support for the Arasan SDHCI controllers" depends on MMC_SDHCI_PLTFM depends on OF + depends on COMMON_CLK help This selects the Arasan Secure Digital Host Controller Interface (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC. @@ -296,17 +297,6 @@ config MMC_SDHCI_BCM_KONA If you have a controller with this interface, say Y or M here. -config MMC_SDHCI_BCM2835 - tristate "SDHCI platform support for the BCM2835 SD/MMC Controller" - depends on ARCH_BCM2835 - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the BCM2835 SD/MMC controller. If you have a BCM2835 - platform with SD or MMC devices, say Y or M here. - - If unsure, say N. - config MMC_SDHCI_F_SDH30 tristate "SDHCI support for Fujitsu Semiconductor F_SDH30" depends on MMC_SDHCI_PLTFM @@ -792,3 +782,13 @@ config MMC_SDHCI_MICROCHIP_PIC32 If you have a controller with this interface, say Y or M here. If unsure, say N. +config MMC_SDHCI_BRCMSTB + tristate "Broadcom SDIO/SD/MMC support" + depends on ARCH_BRCMSTB || BMIPS_GENERIC + depends on MMC_SDHCI_PLTFM + default y + help + This selects support for the SDIO/SD/MMC Host Controller on + Broadcom STB SoCs. + + If unsure, say Y. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index af918d261..e2bdaaf43 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -71,11 +71,11 @@ obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o -obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o +obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o ifeq ($(CONFIG_CB710_DEBUG),y) CFLAGS-cb710-mmc += -DDEBUG diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 7e3a3247b..da0ef1765 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -157,7 +157,7 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) * HOLD register should be bypassed in case there is no phase shift * applied on CMD/DATA that is sent to the card. */ - if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel)) + if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->cur_slot) set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags); } diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index 63c2e2ed1..8e9d886bf 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -32,6 +32,12 @@ struct k3_priv { struct regmap *reg; }; +static unsigned long dw_mci_hi6220_caps[] = { + MMC_CAP_CMD23, + MMC_CAP_CMD23, + 0 +}; + static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios) { int ret; @@ -126,6 +132,7 @@ static void dw_mci_hi6220_set_ios(struct dw_mci *host, struct mmc_ios *ios) } static const struct dw_mci_drv_data hi6220_data = { + .caps = dw_mci_hi6220_caps, .switch_voltage = dw_mci_hi6220_switch_voltage, .set_ios = dw_mci_hi6220_set_ios, .parse_dt = dw_mci_hi6220_parse_dt, diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 358b0dc85..25eae359a 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -285,9 +285,6 @@ static int dw_mci_rockchip_init(struct dw_mci *host) /* It is slot 8 on Rockchip SoCs */ host->sdio_id0 = 8; - /* It needs this quirk on all Rockchip SoCs */ - host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO; - if (of_device_is_compatible(host->dev->of_node, "rockchip,rk3288-dw-mshc")) host->bus_hz /= RK3288_CLKGEN_DIV; @@ -297,10 +294,10 @@ static int dw_mci_rockchip_init(struct dw_mci *host) /* Common capabilities of RK3288 SoC */ static unsigned long dw_mci_rk3288_dwmmc_caps[4] = { - MMC_CAP_ERASE | MMC_CAP_CMD23, - MMC_CAP_ERASE | MMC_CAP_CMD23, - MMC_CAP_ERASE | MMC_CAP_CMD23, - MMC_CAP_ERASE | MMC_CAP_CMD23, + MMC_CAP_CMD23, + MMC_CAP_CMD23, + MMC_CAP_CMD23, + MMC_CAP_CMD23, }; static const struct dw_mci_drv_data rk2928_drv_data = { diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 2cc6123b1..767af2026 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -44,11 +44,11 @@ /* Common flag combinations */ #define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \ SDMMC_INT_HTO | SDMMC_INT_SBE | \ - SDMMC_INT_EBE) + SDMMC_INT_EBE | SDMMC_INT_HLE) #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ - SDMMC_INT_RESP_ERR) + SDMMC_INT_RESP_ERR | SDMMC_INT_HLE) #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ - DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE) + DW_MCI_CMD_ERROR_FLAGS) #define DW_MCI_SEND_STATUS 1 #define DW_MCI_RECV_STATUS 2 #define DW_MCI_DMA_THRESHOLD 16 @@ -92,7 +92,7 @@ struct idmac_desc { __le32 des1; /* Buffer sizes */ #define IDMAC_SET_BUFFER1_SIZE(d, s) \ - ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) + ((d)->des1 = ((d)->des1 & cpu_to_le32(0x03ffe000)) | (cpu_to_le32((s) & 0x1fff))) __le32 des2; /* buffer 1 physical address */ @@ -105,6 +105,7 @@ struct idmac_desc { static bool dw_mci_reset(struct dw_mci *host); static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); static int dw_mci_card_busy(struct mmc_host *mmc); +static int dw_mci_get_cd(struct mmc_host *mmc); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -898,23 +899,35 @@ done: mci_writel(host, FIFOTH, fifoth_val); } -static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) +static void dw_mci_ctrl_thld(struct dw_mci *host, struct mmc_data *data) { unsigned int blksz = data->blksz; u32 blksz_depth, fifo_depth; u16 thld_size; - - WARN_ON(!(data->flags & MMC_DATA_READ)); + u8 enable; /* * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is * in the FIFO region, so we really shouldn't access it). */ - if (host->verid < DW_MMC_240A) + if (host->verid < DW_MMC_240A || + (host->verid < DW_MMC_280A && data->flags & MMC_DATA_WRITE)) + return; + + /* + * Card write Threshold is introduced since 2.80a + * It's used when HS400 mode is enabled. + */ + if (data->flags & MMC_DATA_WRITE && + !(host->timing != MMC_TIMING_MMC_HS400)) return; + if (data->flags & MMC_DATA_WRITE) + enable = SDMMC_CARD_WR_THR_EN; + else + enable = SDMMC_CARD_RD_THR_EN; + if (host->timing != MMC_TIMING_MMC_HS200 && - host->timing != MMC_TIMING_MMC_HS400 && host->timing != MMC_TIMING_UHS_SDR104) goto disable; @@ -930,11 +943,11 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) * Currently just choose blksz. */ thld_size = blksz; - mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1)); + mci_writel(host, CDTHRCTL, SDMMC_SET_THLD(thld_size, enable)); return; disable: - mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0)); + mci_writel(host, CDTHRCTL, 0); } static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) @@ -1005,12 +1018,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) host->sg = NULL; host->data = data; - if (data->flags & MMC_DATA_READ) { + if (data->flags & MMC_DATA_READ) host->dir_status = DW_MCI_RECV_STATUS; - dw_mci_ctrl_rd_thld(host, data); - } else { + else host->dir_status = DW_MCI_SEND_STATUS; - } + + dw_mci_ctrl_thld(host, data); if (dw_mci_submit_data_dma(host, data)) { if (host->data->flags & MMC_DATA_READ) @@ -1099,7 +1112,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; - if ((clock << div) != slot->__clk_old || force_clkinit) + if (clock != slot->__clk_old || force_clkinit) dev_info(&slot->mmc->class_dev, "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", slot->id, host->bus_hz, clock, @@ -1128,8 +1141,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) /* inform CIU */ mci_send_cmd(slot, sdmmc_cmd_bits, 0); - /* keep the clock with reflecting clock dividor */ - slot->__clk_old = clock << div; + /* keep the last clock value that was requested from core */ + slot->__clk_old = clock; } host->current_speed = clock; @@ -1253,15 +1266,15 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) * atomic, otherwise the card could be removed in between and the * request wouldn't fail until another card was inserted. */ - spin_lock_bh(&host->lock); - if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { - spin_unlock_bh(&host->lock); + if (!dw_mci_get_cd(mmc)) { mrq->cmd->error = -ENOMEDIUM; mmc_request_done(mmc, mrq); return; } + spin_lock_bh(&host->lock); + dw_mci_queue_request(host, slot, mrq); spin_unlock_bh(&host->lock); @@ -1451,8 +1464,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc) int gpio_cd = mmc_gpio_get_cd(mmc); /* Use platform get_cd function, else try onboard card detect */ - if ((mmc->caps & MMC_CAP_NEEDS_POLL) || - (mmc->caps & MMC_CAP_NONREMOVABLE)) + if ((mmc->caps & MMC_CAP_NEEDS_POLL) || !mmc_card_is_removable(mmc)) present = 1; else if (gpio_cd >= 0) present = gpio_cd; @@ -1761,6 +1773,33 @@ static void dw_mci_tasklet_func(unsigned long priv) } if (cmd->data && err) { + /* + * During UHS tuning sequence, sending the stop + * command after the response CRC error would + * throw the system into a confused state + * causing all future tuning phases to report + * failure. + * + * In such case controller will move into a data + * transfer state after a response error or + * response CRC error. Let's let that finish + * before trying to send a stop, so we'll go to + * STATE_SENDING_DATA. + * + * Although letting the data transfer take place + * will waste a bit of time (we already know + * the command was bad), it can't cause any + * errors since it's possible it would have + * taken place anyway if this tasklet got + * delayed. Allowing the transfer to take place + * avoids races and keeps things simple. + */ + if ((err != -ETIMEDOUT) && + (cmd->opcode == MMC_SEND_TUNING_BLOCK)) { + state = STATE_SENDING_DATA; + continue; + } + dw_mci_stop_dma(host); send_stop_abort(host, data); state = STATE_SENDING_STOP; @@ -1801,8 +1840,7 @@ static void dw_mci_tasklet_func(unsigned long priv) * If all data-related interrupts don't come * within the given time in reading data state. */ - if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) && - (host->dir_status == DW_MCI_RECV_STATUS)) + if (host->dir_status == DW_MCI_RECV_STATUS) dw_mci_set_drto(host); break; } @@ -1844,8 +1882,7 @@ static void dw_mci_tasklet_func(unsigned long priv) * interrupt doesn't come within the given time. * in reading data state. */ - if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) && - (host->dir_status == DW_MCI_RECV_STATUS)) + if (host->dir_status == DW_MCI_RECV_STATUS) dw_mci_set_drto(host); break; } @@ -2411,8 +2448,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) } if (pending & SDMMC_INT_DATA_OVER) { - if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO) - del_timer(&host->dto_timer); + del_timer(&host->dto_timer); mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); if (!host->data_status) @@ -2474,7 +2510,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); - host->dma_ops->complete((void *)host); + if (!test_bit(EVENT_DATA_ERROR, &host->pending_events)) + host->dma_ops->complete((void *)host); } } else { pending = mci_readl(host, IDSTS); @@ -2482,7 +2519,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); - host->dma_ops->complete((void *)host); + if (!test_bit(EVENT_DATA_ERROR, &host->pending_events)) + host->dma_ops->complete((void *)host); } } @@ -2570,6 +2608,12 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (host->pdata->caps) mmc->caps = host->pdata->caps; + /* + * Support MMC_CAP_ERASE by default. + * It needs to use trim/discard/erase commands. + */ + mmc->caps |= MMC_CAP_ERASE; + if (host->pdata->pm_caps) mmc->pm_caps = host->pdata->pm_caps; @@ -2616,10 +2660,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) mmc->max_seg_size = mmc->max_req_size; } - if (dw_mci_get_cd(mmc)) - set_bit(DW_MMC_CARD_PRESENT, &slot->flags); - else - clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); + dw_mci_get_cd(mmc); ret = mmc_add_host(mmc); if (ret) @@ -3006,11 +3047,8 @@ int dw_mci_probe(struct dw_mci *host) setup_timer(&host->cmd11_timer, dw_mci_cmd11_timer, (unsigned long)host); - host->quirks = host->pdata->quirks; - - if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO) - setup_timer(&host->dto_timer, - dw_mci_dto_timer, (unsigned long)host); + setup_timer(&host->dto_timer, + dw_mci_dto_timer, (unsigned long)host); spin_lock_init(&host->lock); spin_lock_init(&host->irq_lock); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 1e8d8380f..e8cd2dec3 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -15,6 +15,7 @@ #define _DW_MMC_H_ #define DW_MMC_240A 0x240a +#define DW_MMC_280A 0x280a #define SDMMC_CTRL 0x000 #define SDMMC_PWREN 0x004 @@ -175,7 +176,10 @@ /* Version ID register define */ #define SDMMC_GET_VERID(x) ((x) & 0xFFFF) /* Card read threshold */ -#define SDMMC_SET_RD_THLD(v, x) (((v) & 0xFFF) << 16 | (x)) +#define SDMMC_SET_THLD(v, x) (((v) & 0xFFF) << 16 | (x)) +#define SDMMC_CARD_WR_THR_EN BIT(2) +#define SDMMC_CARD_RD_THR_EN BIT(0) +/* UHS-1 register defines */ #define SDMMC_UHS_18V BIT(0) /* All ctrl reset bits */ #define SDMMC_CTRL_ALL_RESET_FLAGS \ @@ -245,9 +249,8 @@ extern int dw_mci_resume(struct dw_mci *host); * @queue_node: List node for placing this node in the @queue list of * &struct dw_mci. * @clock: Clock rate configured by set_ios(). Protected by host->lock. - * @__clk_old: The last updated clock with reflecting clock divider. - * Keeping track of this helps us to avoid spamming the console - * with CONFIG_MMC_CLKGATE. + * @__clk_old: The last clock value that was requested from core. + * Keeping track of this helps us to avoid spamming the console. * @flags: Random state bits associated with the slot. * @id: Number of this slot. * @sdio_id: Number of this slot in the SDIO interrupt registers. diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 03ddf0ecf..684087db1 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1068,8 +1068,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev) jz4740_mmc_clock_disable(host); setup_timer(&host->timeout_timer, jz4740_mmc_timeout, (unsigned long)host); - /* It is not important when it times out, it just needs to timeout. */ - set_timer_slack(&host->timeout_timer, HZ); host->use_dma = true; if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 5642f71f8..84e9afcb5 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -287,6 +287,11 @@ struct msdc_save_para { u32 emmc50_cfg0; }; +struct msdc_tune_para { + u32 iocon; + u32 pad_tune; +}; + struct msdc_delay_phase { u8 maxlen; u8 start; @@ -326,7 +331,10 @@ struct msdc_host { unsigned char timing; bool vqmmc_enabled; u32 hs400_ds_delay; + bool hs400_mode; /* current eMMC will run at hs400 mode */ struct msdc_save_para save_para; /* used when gate HCLK */ + struct msdc_tune_para def_tune_para; /* default tune setting */ + struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ }; static void sdr_set_bits(void __iomem *reg, u32 bs) @@ -582,6 +590,18 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); sdr_set_bits(host->base + MSDC_INTEN, flags); + /* + * mmc_select_hs400() will drop to 50Mhz and High speed mode, + * tune result of hs200/200Mhz is not suitable for 50Mhz + */ + if (host->sclk <= 52000000) { + writel(host->def_tune_para.iocon, host->base + MSDC_IOCON); + writel(host->def_tune_para.pad_tune, host->base + MSDC_PAD_TUNE); + } else { + writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON); + writel(host->saved_tune_para.pad_tune, host->base + MSDC_PAD_TUNE); + } + dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing); } @@ -781,7 +801,13 @@ static bool msdc_cmd_done(struct msdc_host *host, int events, } if (!sbc_error && !(events & MSDC_INT_CMDRDY)) { - msdc_reset_hw(host); + if (cmd->opcode != MMC_SEND_TUNING_BLOCK && + cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) + /* + * should not clear fifo/interrupt as the tune data + * may have alreay come. + */ + msdc_reset_hw(host); if (events & MSDC_INT_RSPCRCERR) { cmd->error = -EILSEQ; host->error |= REQ_CMD_EIO; @@ -865,7 +891,11 @@ static void msdc_start_command(struct msdc_host *host, static void msdc_cmd_next(struct msdc_host *host, struct mmc_request *mrq, struct mmc_command *cmd) { - if (cmd->error || (mrq->sbc && mrq->sbc->error)) + if ((cmd->error && + !(cmd->error == -EILSEQ && + (cmd->opcode == MMC_SEND_TUNING_BLOCK || + cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))) || + (mrq->sbc && mrq->sbc->error)) msdc_request_done(host, mrq); else if (cmd == mrq->sbc) msdc_start_command(host, mrq, mrq->cmd); @@ -1158,6 +1188,8 @@ static void msdc_init_hw(struct msdc_host *host) /* Configure to default data timeout */ sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); + host->def_tune_para.iocon = readl(host->base + MSDC_IOCON); + host->def_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE); dev_dbg(host->dev, "init hardware done!"); } @@ -1296,7 +1328,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); u32 rise_delay = 0, fall_delay = 0; - struct msdc_delay_phase final_rise_delay, final_fall_delay; + struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; u8 final_delay, final_maxlen; int cmd_err; int i; @@ -1309,6 +1341,11 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) if (!cmd_err) rise_delay |= (1 << i); } + final_rise_delay = get_best_delay(host, rise_delay); + /* if rising edge has enough margin, then do not scan falling edge */ + if (final_rise_delay.maxlen >= 10 || + (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) + goto skip_fall; sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); for (i = 0; i < PAD_DELAY_MAX; i++) { @@ -1318,10 +1355,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) if (!cmd_err) fall_delay |= (1 << i); } - - final_rise_delay = get_best_delay(host, rise_delay); final_fall_delay = get_best_delay(host, fall_delay); +skip_fall: final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); if (final_maxlen == final_rise_delay.maxlen) { sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); @@ -1342,7 +1378,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); u32 rise_delay = 0, fall_delay = 0; - struct msdc_delay_phase final_rise_delay, final_fall_delay; + struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; u8 final_delay, final_maxlen; int i, ret; @@ -1355,6 +1391,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) if (!ret) rise_delay |= (1 << i); } + final_rise_delay = get_best_delay(host, rise_delay); + /* if rising edge has enough margin, then do not scan falling edge */ + if (final_rise_delay.maxlen >= 10 || + (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) + goto skip_fall; sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); @@ -1365,14 +1406,10 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) if (!ret) fall_delay |= (1 << i); } - - final_rise_delay = get_best_delay(host, rise_delay); final_fall_delay = get_best_delay(host, fall_delay); +skip_fall: final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); - /* Rising edge is more stable, prefer to use it */ - if (final_rise_delay.maxlen >= 10) - final_maxlen = final_rise_delay.maxlen; if (final_maxlen == final_rise_delay.maxlen) { sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); @@ -1402,16 +1439,21 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode) dev_err(host->dev, "Tune response fail!\n"); return ret; } - ret = msdc_tune_data(mmc, opcode); - if (ret == -EIO) - dev_err(host->dev, "Tune data fail!\n"); + if (host->hs400_mode == false) { + ret = msdc_tune_data(mmc, opcode); + if (ret == -EIO) + dev_err(host->dev, "Tune data fail!\n"); + } + host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON); + host->saved_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE); return ret; } static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) { struct msdc_host *host = mmc_priv(mmc); + host->hs400_mode = true; writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE); return 0; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 3d1ea5e0e..fb3ca8296 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1065,7 +1065,7 @@ static int mxcmci_probe(struct platform_device *pdev) if (pdata) dat3_card_detect = pdata->dat3_card_detect; - else if (!(mmc->caps & MMC_CAP_NONREMOVABLE) + else if (mmc_card_is_removable(mmc) && !of_property_read_bool(pdev->dev.of_node, "cd-gpios")) dat3_card_detect = true; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index f23d65eb0..be3c49fa7 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1016,14 +1016,16 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) /* Only reconfigure if we have a different burst size */ if (*bp != burst) { - struct dma_slave_config cfg; - - cfg.src_addr = host->phys_base + OMAP_MMC_REG(host, DATA); - cfg.dst_addr = host->phys_base + OMAP_MMC_REG(host, DATA); - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - cfg.src_maxburst = burst; - cfg.dst_maxburst = burst; + struct dma_slave_config cfg = { + .src_addr = host->phys_base + + OMAP_MMC_REG(host, DATA), + .dst_addr = host->phys_base + + OMAP_MMC_REG(host, DATA), + .src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, + .src_maxburst = burst, + .dst_maxburst = burst, + }; if (dmaengine_slave_config(c, &cfg)) goto use_pio; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 24ebc9a8d..5f2f24a73 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1409,11 +1409,18 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host, struct mmc_request *req) { - struct dma_slave_config cfg; struct dma_async_tx_descriptor *tx; int ret = 0, i; struct mmc_data *data = req->data; struct dma_chan *chan; + struct dma_slave_config cfg = { + .src_addr = host->mapbase + OMAP_HSMMC_DATA, + .dst_addr = host->mapbase + OMAP_HSMMC_DATA, + .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .src_maxburst = data->blksz / 4, + .dst_maxburst = data->blksz / 4, + }; /* Sanity check: all the SG entries must be aligned by block size. */ for (i = 0; i < data->sg_len; i++) { @@ -1433,13 +1440,6 @@ static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host, chan = omap_hsmmc_get_dma_chan(host, data); - cfg.src_addr = host->mapbase + OMAP_HSMMC_DATA; - cfg.dst_addr = host->mapbase + OMAP_HSMMC_DATA; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.src_maxburst = data->blksz / 4; - cfg.dst_maxburst = data->blksz / 4; - ret = dmaengine_slave_config(chan, &cfg); if (ret) return ret; diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 93137483e..396c9b7e4 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -38,7 +38,6 @@ struct realtek_pci_sdmmc { struct rtsx_pcr *pcr; struct mmc_host *mmc; struct mmc_request *mrq; - struct workqueue_struct *workq; #define SDMMC_WORKQ_NAME "rtsx_pci_sdmmc_workq" struct work_struct work; @@ -244,7 +243,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, stat_idx = sd_status_index(rsp_type); if (rsp_type == SD_RSP_TYPE_R1b) - timeout = 3000; + timeout = cmd->busy_timeout ? cmd->busy_timeout : 3000; if (cmd->opcode == SD_SWITCH_VOLTAGE) { err = rtsx_pci_write_register(pcr, SD_BUS_STAT, @@ -885,7 +884,7 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) if (sd_rw_cmd(mrq->cmd) || sdio_extblock_cmd(mrq->cmd, data)) host->using_cookie = sd_pre_dma_transfer(host, data, false); - queue_work(host->workq, &host->work); + schedule_work(&host->work); } static int sd_set_bus_width(struct realtek_pci_sdmmc *host, @@ -1360,7 +1359,7 @@ static void realtek_init_host(struct realtek_pci_sdmmc *host) mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | - MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; + MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_ERASE; mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE; mmc->max_current_330 = 400; mmc->max_current_180 = 800; @@ -1404,11 +1403,6 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) return -ENOMEM; host = mmc_priv(mmc); - host->workq = create_singlethread_workqueue(SDMMC_WORKQ_NAME); - if (!host->workq) { - mmc_free_host(mmc); - return -ENOMEM; - } host->pcr = pcr; host->mmc = mmc; host->pdev = pdev; @@ -1462,9 +1456,7 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) mmc_remove_host(mmc); host->eject = true; - flush_workqueue(host->workq); - destroy_workqueue(host->workq); - host->workq = NULL; + flush_work(&host->work); mmc_free_host(mmc); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 39814f3dc..c531deef3 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1365,7 +1365,7 @@ static struct s3c24xx_mci_pdata s3cmci_def_pdata = { .no_detect = 1, }; -#ifdef CONFIG_CPU_FREQ +#ifdef CONFIG_ARM_S3C24XX_CPUFREQ static int s3cmci_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h index cc2e46cb5..30c2c0dd1 100644 --- a/drivers/mmc/host/s3cmci.h +++ b/drivers/mmc/host/s3cmci.h @@ -74,7 +74,7 @@ struct s3cmci_host { struct dentry *debug_regs; #endif -#ifdef CONFIG_CPU_FREQ +#ifdef CONFIG_ARM_S3C24XX_CPUFREQ struct notifier_block freq_transition; #endif }; diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 458ffb763..8fe0756c8 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -43,6 +43,7 @@ #ifdef CONFIG_X86 #include <asm/cpu_device_id.h> +#include <asm/intel-family.h> #include <asm/iosf_mbi.h> #endif @@ -126,7 +127,7 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { static bool sdhci_acpi_byt(void) { static const struct x86_cpu_id byt[] = { - { X86_VENDOR_INTEL, 6, 0x37 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, {} }; @@ -531,11 +532,6 @@ static int sdhci_acpi_resume(struct device *dev) return sdhci_resume_host(c->host); } -#else - -#define sdhci_acpi_suspend NULL -#define sdhci_acpi_resume NULL - #endif #ifdef CONFIG_PM @@ -559,8 +555,7 @@ static int sdhci_acpi_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops sdhci_acpi_pm_ops = { - .suspend = sdhci_acpi_suspend, - .resume = sdhci_acpi_resume, + SET_SYSTEM_SLEEP_PM_OPS(sdhci_acpi_suspend, sdhci_acpi_resume) SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend, sdhci_acpi_runtime_resume, NULL) }; diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index 00a8a40a3..e5c634bdf 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -264,12 +264,12 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) } dev_dbg(dev, "non-removable=%c\n", - (host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N'); + mmc_card_is_removable(host->mmc) ? 'N' : 'Y'); dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n", (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N', (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N'); - if (host->mmc->caps & MMC_CAP_NONREMOVABLE) + if (!mmc_card_is_removable(host->mmc)) host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; dev_dbg(dev, "is_8bit=%c\n", @@ -288,7 +288,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) } /* if device is eMMC, emulate card insert right here */ - if (host->mmc->caps & MMC_CAP_NONREMOVABLE) { + if (!mmc_card_is_removable(host->mmc)) { ret = sdhci_bcm_kona_sd_card_emulate(host, 1); if (ret) { dev_err(dev, @@ -326,7 +326,7 @@ err_pltfm_free: static struct platform_driver sdhci_bcm_kona_driver = { .driver = { .name = "sdhci-kona", - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_pltfm_pmops, .of_match_table = sdhci_bcm_kona_of_match, }, .probe = sdhci_bcm_kona_probe, diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c new file mode 100644 index 000000000..cce10fe3e --- /dev/null +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -0,0 +1,143 @@ +/* + * sdhci-brcmstb.c Support for SDHCI on Broadcom BRCMSTB SoC's + * + * Copyright (C) 2015 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/io.h> +#include <linux/mmc/host.h> +#include <linux/module.h> +#include <linux/of.h> + +#include "sdhci-pltfm.h" + +#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); + int res; + + res = sdhci_suspend_host(host); + if (res) + return res; + clk_disable_unprepare(pltfm_host->clk); + return res; +} + +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); + int err; + + err = clk_prepare_enable(pltfm_host->clk); + if (err) + return err; + return sdhci_resume_host(host); +} + +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(sdhci_brcmstb_pmops, sdhci_brcmstb_suspend, + sdhci_brcmstb_resume); + +static const struct sdhci_ops sdhci_brcmstb_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static struct sdhci_pltfm_data sdhci_brcmstb_pdata = { + .ops = &sdhci_brcmstb_ops, +}; + +static int sdhci_brcmstb_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct clk *clk; + int res; + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Clock not found in Device Tree\n"); + clk = NULL; + } + res = clk_prepare_enable(clk); + if (res) + return res; + + host = sdhci_pltfm_init(pdev, &sdhci_brcmstb_pdata, 0); + if (IS_ERR(host)) { + res = PTR_ERR(host); + goto err_clk; + } + + /* Enable MMC_CAP2_HC_ERASE_SZ for better max discard calculations */ + host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ; + + sdhci_get_of_property(pdev); + mmc_of_parse(host->mmc); + + /* + * Supply the existing CAPS, but clear the UHS modes. This + * will allow these modes to be specified by device tree + * properties through mmc_of_parse(). + */ + host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); + host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); + host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 | + SDHCI_SUPPORT_DDR50); + host->quirks |= SDHCI_QUIRK_MISSING_CAPS | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + + res = sdhci_add_host(host); + if (res) + goto err; + + pltfm_host = sdhci_priv(host); + pltfm_host->clk = clk; + return res; + +err: + sdhci_pltfm_free(pdev); +err_clk: + clk_disable_unprepare(clk); + return res; +} + +static const struct of_device_id sdhci_brcm_of_match[] = { + { .compatible = "brcm,bcm7425-sdhci" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match); + +static struct platform_driver sdhci_brcmstb_driver = { + .driver = { + .name = "sdhci-brcmstb", + .owner = THIS_MODULE, + .pm = &sdhci_brcmstb_pmops, + .of_match_table = of_match_ptr(sdhci_brcm_of_match), + }, + .probe = sdhci_brcmstb_probe, + .remove = sdhci_pltfm_unregister, +}; + +module_platform_driver(sdhci_brcmstb_driver); + +MODULE_DESCRIPTION("SDHCI driver for Broadcom BRCMSTB SoCs"); +MODULE_AUTHOR("Broadcom"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index 59f2923f8..bd286db7f 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -101,7 +101,7 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev) static struct platform_driver sdhci_cns3xxx_driver = { .driver = { .name = "sdhci-cns3xxx", - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_cns3xxx_probe, .remove = sdhci_pltfm_unregister, diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 407c21f15..de9f9603d 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -117,7 +117,7 @@ MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table); static struct platform_driver sdhci_dove_driver = { .driver = { .name = "sdhci-dove", - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_pltfm_pmops, .of_match_table = sdhci_dove_of_match_table, }, .probe = sdhci_dove_probe, diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 9d3ae1f4b..99e0b334f 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -39,11 +39,13 @@ #define ESDHC_VENDOR_SPEC_VSELECT (1 << 1) #define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8) #define ESDHC_WTMK_LVL 0x44 +#define ESDHC_WTMK_DEFAULT_VAL 0x10401040 #define ESDHC_MIX_CTRL 0x48 #define ESDHC_MIX_CTRL_DDREN (1 << 3) #define ESDHC_MIX_CTRL_AC23EN (1 << 7) #define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22) #define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23) +#define ESDHC_MIX_CTRL_AUTO_TUNE_EN (1 << 24) #define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25) #define ESDHC_MIX_CTRL_HS400_EN (1 << 26) /* Bits 3 and 6 are not SDHCI standard definitions */ @@ -75,7 +77,8 @@ #define ESDHC_TUNING_CTRL 0xcc #define ESDHC_STD_TUNING_EN (1 << 24) /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ -#define ESDHC_TUNING_START_TAP 0x1 +#define ESDHC_TUNING_START_TAP_DEFAULT 0x1 +#define ESDHC_TUNING_START_TAP_MASK 0xff #define ESDHC_TUNING_STEP_MASK 0x00070000 #define ESDHC_TUNING_STEP_SHIFT 16 @@ -299,7 +302,8 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) /* imx6q/dl does not have cap_1 register, fake one */ val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 - | SDHCI_USE_SDR50_TUNING; + | SDHCI_USE_SDR50_TUNING + | (SDHCI_TUNING_MODE_3 << SDHCI_RETUNING_MODE_SHIFT); if (imx_data->socdata->flags & ESDHC_FLAG_HS400) val |= SDHCI_SUPPORT_HS400; @@ -469,32 +473,29 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); - if (val & SDHCI_CTRL_TUNED_CLK) + if (val & SDHCI_CTRL_TUNED_CLK) { new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; - else + new_val |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; + } else { new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; + new_val &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN; + } writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR); u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); - u32 tuning_ctrl; if (val & SDHCI_CTRL_TUNED_CLK) { v |= ESDHC_MIX_CTRL_SMPCLK_SEL; } else { v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; + m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN; } if (val & SDHCI_CTRL_EXEC_TUNING) { v |= ESDHC_MIX_CTRL_EXE_TUNE; m |= ESDHC_MIX_CTRL_FBCLK_SEL; - tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL); - tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP; - if (imx_data->boarddata.tuning_step) { - tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK; - tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT; - } - writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL); + m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; } else { v &= ~ESDHC_MIX_CTRL_EXE_TUNE; } @@ -751,6 +752,7 @@ static void esdhc_post_tuning(struct sdhci_host *host) reg = readl(host->ioaddr + ESDHC_MIX_CTRL); reg &= ~ESDHC_MIX_CTRL_EXE_TUNE; + reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; writel(reg, host->ioaddr + ESDHC_MIX_CTRL); } @@ -838,6 +840,11 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host) u32 v; if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) { + /* disable clock before enabling strobe dll */ + writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & + ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, + host->ioaddr + ESDHC_VENDOR_SPEC); + /* force a reset on strobe dll */ writel(ESDHC_STROBE_DLL_CTRL_RESET, host->ioaddr + ESDHC_STROBE_DLL_CTRL); @@ -899,6 +906,8 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN; writel(m, host->ioaddr + ESDHC_MIX_CTRL); imx_data->is_ddr = 1; + /* update clock after enable DDR for strobe DLL lock */ + host->ops->set_clock(host, host->clock); esdhc_set_strobe_dll(host); break; } @@ -957,6 +966,62 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { .ops = &sdhci_esdhc_ops, }; +static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); + int tmp; + + if (esdhc_is_usdhc(imx_data)) { + /* + * The imx6q ROM code will change the default watermark + * level setting to something insane. Change it back here. + */ + writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL); + + /* + * ROM code will change the bit burst_length_enable setting + * to zero if this usdhc is choosed to boot system. Change + * it back here, otherwise it will impact the performance a + * lot. This bit is used to enable/disable the burst length + * for the external AHB2AXI bridge, it's usefully especially + * for INCR transfer because without burst length indicator, + * the AHB2AXI bridge does not know the burst length in + * advance. And without burst length indicator, AHB INCR + * transfer can only be converted to singles on the AXI side. + */ + writel(readl(host->ioaddr + SDHCI_HOST_CONTROL) + | ESDHC_BURST_LEN_EN_INCR, + host->ioaddr + SDHCI_HOST_CONTROL); + /* + * errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL + * TO1.1, it's harmless for MX6SL + */ + writel(readl(host->ioaddr + 0x6c) | BIT(7), + host->ioaddr + 0x6c); + + /* disable DLL_CTRL delay line settings */ + writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); + + if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { + tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); + tmp |= ESDHC_STD_TUNING_EN | + ESDHC_TUNING_START_TAP_DEFAULT; + if (imx_data->boarddata.tuning_start_tap) { + tmp &= ~ESDHC_TUNING_START_TAP_MASK; + tmp |= imx_data->boarddata.tuning_start_tap; + } + + if (imx_data->boarddata.tuning_step) { + tmp &= ~ESDHC_TUNING_STEP_MASK; + tmp |= imx_data->boarddata.tuning_step + << ESDHC_TUNING_STEP_SHIFT; + } + writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); + } + } +} + #ifdef CONFIG_OF static int sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, @@ -975,6 +1040,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, boarddata->wp_type = ESDHC_WP_GPIO; of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step); + of_property_read_u32(np, "fsl,tuning-start-tap", + &boarddata->tuning_start_tap); if (of_find_property(np, "no-1-8-v", NULL)) boarddata->support_vsel = false; @@ -1147,58 +1214,27 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) 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; - if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207) /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK | SDHCI_QUIRK_BROKEN_ADMA; - /* - * The imx6q ROM code will change the default watermark level setting - * to something insane. Change it back here. - */ if (esdhc_is_usdhc(imx_data)) { - writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL); - host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; host->mmc->caps |= MMC_CAP_1_8V_DDR; - - /* - * ROM code will change the bit burst_length_enable setting - * to zero if this usdhc is choosed to boot system. Change - * it back here, otherwise it will impact the performance a - * lot. This bit is used to enable/disable the burst length - * for the external AHB2AXI bridge, it's usefully especially - * for INCR transfer because without burst length indicator, - * the AHB2AXI bridge does not know the burst length in - * advance. And without burst length indicator, AHB INCR - * transfer can only be converted to singles on the AXI side. - */ - writel(readl(host->ioaddr + SDHCI_HOST_CONTROL) - | ESDHC_BURST_LEN_EN_INCR, - host->ioaddr + SDHCI_HOST_CONTROL); - if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; - /* - * errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL - * TO1.1, it's harmless for MX6SL - */ - writel(readl(host->ioaddr + 0x6c) | BIT(7), - host->ioaddr + 0x6c); + /* clear tuning bits in case ROM has set it already */ + writel(0x0, host->ioaddr + ESDHC_MIX_CTRL); + writel(0x0, host->ioaddr + SDHCI_ACMD12_ERR); + writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); } if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) sdhci_esdhc_ops.platform_execute_tuning = esdhc_executing_tuning; - if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) - writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) | - ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP, - host->ioaddr + ESDHC_TUNING_CTRL); - if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; @@ -1212,6 +1248,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (err) goto disable_clk; + sdhci_esdhc_imx_hwinit(host); + err = sdhci_add_host(host); if (err) goto disable_clk; @@ -1255,6 +1293,25 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int sdhci_esdhc_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + + return sdhci_suspend_host(host); +} + +static int sdhci_esdhc_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + + /* re-initialize hw state in case it's lost in low power mode */ + sdhci_esdhc_imx_hwinit(host); + + return sdhci_resume_host(host); +} +#endif + #ifdef CONFIG_PM static int sdhci_esdhc_runtime_suspend(struct device *dev) { @@ -1291,7 +1348,7 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops sdhci_esdhc_pmops = { - SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume) + SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume) SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend, sdhci_esdhc_runtime_resume, NULL) }; diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 1110f73b0..726246665 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -164,8 +164,17 @@ static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = { static const struct sdhci_iproc_data iproc_data = { .pdata = &sdhci_iproc_pltfm_data, - .caps = 0x05E90000, - .caps1 = 0x00000064, + .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT) + & SDHCI_MAX_BLOCK_MASK) | + SDHCI_CAN_VDD_330 | + SDHCI_CAN_VDD_180 | + SDHCI_CAN_DO_SUSPEND | + SDHCI_CAN_DO_HISPD | + SDHCI_CAN_DO_ADMA2 | + SDHCI_CAN_DO_SDMA, + .caps1 = SDHCI_DRIVER_TYPE_C | + SDHCI_DRIVER_TYPE_D | + SDHCI_SUPPORT_DDR50, .mmc_caps = MMC_CAP_1_8V_DDR, }; @@ -251,7 +260,7 @@ static struct platform_driver sdhci_iproc_driver = { .driver = { .name = "sdhci-iproc", .of_match_table = sdhci_iproc_of_match, - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_iproc_probe, .remove = sdhci_pltfm_unregister, diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 0653fe730..8ef44a2a2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -32,6 +32,21 @@ #define CORE_POWER 0x0 #define CORE_SW_RST BIT(7) +#define CORE_PWRCTL_STATUS 0xdc +#define CORE_PWRCTL_MASK 0xe0 +#define CORE_PWRCTL_CLEAR 0xe4 +#define CORE_PWRCTL_CTL 0xe8 +#define CORE_PWRCTL_BUS_OFF BIT(0) +#define CORE_PWRCTL_BUS_ON BIT(1) +#define CORE_PWRCTL_IO_LOW BIT(2) +#define CORE_PWRCTL_IO_HIGH BIT(3) +#define CORE_PWRCTL_BUS_SUCCESS BIT(0) +#define CORE_PWRCTL_IO_SUCCESS BIT(2) +#define REQ_BUS_OFF BIT(0) +#define REQ_BUS_ON BIT(1) +#define REQ_IO_LOW BIT(2) +#define REQ_IO_HIGH BIT(3) +#define INT_MASK 0xf #define MAX_PHASES 16 #define CORE_DLL_LOCK BIT(7) #define CORE_DLL_EN BIT(16) @@ -56,6 +71,7 @@ struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ + int pwr_irq; /* power irq */ struct clk *clk; /* main SD/MMC bus clock */ struct clk *pclk; /* SDHC peripheral bus clock */ struct clk *bus_clk; /* SDHC bus voter clock */ @@ -410,6 +426,85 @@ retry: return rc; } +static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, + unsigned int uhs) +{ + struct mmc_host *mmc = host->mmc; + u16 ctrl_2; + + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + switch (uhs) { + case MMC_TIMING_UHS_SDR12: + ctrl_2 |= SDHCI_CTRL_UHS_SDR12; + break; + case MMC_TIMING_UHS_SDR25: + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + break; + case MMC_TIMING_UHS_SDR50: + ctrl_2 |= SDHCI_CTRL_UHS_SDR50; + break; + case MMC_TIMING_MMC_HS200: + case MMC_TIMING_UHS_SDR104: + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + break; + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + break; + } + + /* + * When clock frequency is less than 100MHz, the feedback clock must be + * provided and DLL must not be used so that tuning can be skipped. To + * provide feedback clock, the mode selection can be any value less + * than 3'b011 in bits [2:0] of HOST CONTROL2 register. + */ + if (host->clock <= 100000000 && + (uhs == MMC_TIMING_MMC_HS400 || + uhs == MMC_TIMING_MMC_HS200 || + uhs == MMC_TIMING_UHS_SDR104)) + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + + dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n", + mmc_hostname(host->mmc), host->clock, uhs, ctrl_2); + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +} + +static void sdhci_msm_voltage_switch(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + u32 irq_status, irq_ack = 0; + + irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); + irq_status &= INT_MASK; + + writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR); + + if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF)) + irq_ack |= CORE_PWRCTL_BUS_SUCCESS; + if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH)) + irq_ack |= CORE_PWRCTL_IO_SUCCESS; + + /* + * The driver has to acknowledge the interrupt, switch voltages and + * report back if it succeded or not to this register. The voltage + * switches are handled by the sdhci core, so just report success. + */ + writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); +} + +static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) +{ + struct sdhci_host *host = (struct sdhci_host *)data; + + sdhci_msm_voltage_switch(host); + + return IRQ_HANDLED; +} + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, @@ -422,11 +517,13 @@ static const struct sdhci_ops sdhci_msm_ops = { .reset = sdhci_reset, .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, - .set_uhs_signaling = sdhci_set_uhs_signaling, + .set_uhs_signaling = sdhci_msm_set_uhs_signaling, + .voltage_switch = sdhci_msm_voltage_switch, }; static const struct sdhci_pltfm_data sdhci_msm_pdata = { .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_NO_CARD_NO_RESET | SDHCI_QUIRK_SINGLE_POWER_WRITE, .ops = &sdhci_msm_ops, }; @@ -473,7 +570,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->pclk = devm_clk_get(&pdev->dev, "iface"); if (IS_ERR(msm_host->pclk)) { ret = PTR_ERR(msm_host->pclk); - dev_err(&pdev->dev, "Perpheral clk setup failed (%d)\n", ret); + dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret); goto bus_clk_disable; } @@ -545,6 +642,22 @@ static int sdhci_msm_probe(struct platform_device *pdev) CORE_VENDOR_SPEC_CAPABILITIES0); } + /* Setup IRQ for handling power/voltage tasks with PMIC */ + msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq"); + if (msm_host->pwr_irq < 0) { + dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n", + msm_host->pwr_irq); + goto clk_disable; + } + + ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL, + sdhci_msm_pwr_irq, IRQF_ONESHOT, + dev_name(&pdev->dev), host); + if (ret) { + dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret); + goto clk_disable; + } + ret = sdhci_add_host(host); if (ret) goto clk_disable; diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index b6f4c1d41..e0f193f7e 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -19,27 +19,136 @@ * your option) any later version. */ +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/phy/phy.h> +#include <linux/regmap.h> #include "sdhci-pltfm.h" #define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c +#define SDHCI_ARASAN_VENDOR_REGISTER 0x78 +#define VENDOR_ENHANCED_STROBE BIT(0) #define CLK_CTRL_TIMEOUT_SHIFT 16 #define CLK_CTRL_TIMEOUT_MASK (0xf << CLK_CTRL_TIMEOUT_SHIFT) #define CLK_CTRL_TIMEOUT_MIN_EXP 13 +/* + * On some SoCs the syscon area has a feature where the upper 16-bits of + * each 32-bit register act as a write mask for the lower 16-bits. This allows + * atomic updates of the register without locking. This macro is used on SoCs + * that have that feature. + */ +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + +/** + * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map + * + * @reg: Offset within the syscon of the register containing this field + * @width: Number of bits for this field + * @shift: Bit offset within @reg of this field (or -1 if not avail) + */ +struct sdhci_arasan_soc_ctl_field { + u32 reg; + u16 width; + s16 shift; +}; + +/** + * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers + * + * It's up to the licensee of the Arsan IP block to make these available + * somewhere if needed. Presumably these will be scattered somewhere that's + * accessible via the syscon API. + * + * @baseclkfreq: Where to find corecfg_baseclkfreq + * @hiword_update: If true, use HIWORD_UPDATE to access the syscon + */ +struct sdhci_arasan_soc_ctl_map { + struct sdhci_arasan_soc_ctl_field baseclkfreq; + bool hiword_update; +}; + /** * struct sdhci_arasan_data - * @clk_ahb: Pointer to the AHB clock - * @phy: Pointer to the generic phy + * @host: Pointer to the main SDHCI host structure. + * @clk_ahb: Pointer to the AHB clock + * @phy: Pointer to the generic phy + * @sdcardclk_hw: Struct for the clock we might provide to a PHY. + * @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw. + * @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers. + * @soc_ctl_map: Map to get offsets into soc_ctl registers. */ struct sdhci_arasan_data { + struct sdhci_host *host; struct clk *clk_ahb; struct phy *phy; + + struct clk_hw sdcardclk_hw; + struct clk *sdcardclk; + + struct regmap *soc_ctl_base; + const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; +}; + +static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = { + .baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 }, + .hiword_update = true, }; +/** + * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers + * + * This function allows writing to fields in sdhci_arasan_soc_ctl_map. + * Note that if a field is specified as not available (shift < 0) then + * this function will silently return an error code. It will be noisy + * and print errors for any other (unexpected) errors. + * + * @host: The sdhci_host + * @fld: The field to write to + * @val: The value to write + */ +static int sdhci_arasan_syscon_write(struct sdhci_host *host, + const struct sdhci_arasan_soc_ctl_field *fld, + u32 val) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base; + u32 reg = fld->reg; + u16 width = fld->width; + s16 shift = fld->shift; + int ret; + + /* + * Silently return errors for shift < 0 so caller doesn't have + * to check for fields which are optional. For fields that + * are required then caller needs to do something special + * anyway. + */ + if (shift < 0) + return -EINVAL; + + if (sdhci_arasan->soc_ctl_map->hiword_update) + ret = regmap_write(soc_ctl_base, reg, + HIWORD_UPDATE(val, GENMASK(width, 0), + shift)); + else + ret = regmap_update_bits(soc_ctl_base, reg, + GENMASK(shift + width, shift), + val << shift); + + /* Yell about (unexpected) regmap errors */ + if (ret) + pr_warn("%s: Regmap write fail: %d\n", + mmc_hostname(host->mmc), ret); + + return ret; +} + static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) { u32 div; @@ -79,6 +188,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) } } +static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + u32 vendor; + struct sdhci_host *host = mmc_priv(mmc); + + vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER); + if (ios->enhanced_strobe) + vendor |= VENDOR_ENHANCED_STROBE; + else + vendor &= ~VENDOR_ENHANCED_STROBE; + + writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER); +} + static struct sdhci_ops sdhci_arasan_ops = { .set_clock = sdhci_arasan_set_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock, @@ -172,9 +296,168 @@ static int sdhci_arasan_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, sdhci_arasan_resume); +static const struct of_device_id sdhci_arasan_of_match[] = { + /* SoC-specific compatible strings w/ soc_ctl_map */ + { + .compatible = "rockchip,rk3399-sdhci-5.1", + .data = &rk3399_soc_ctl_map, + }, + + /* Generic compatible below here */ + { .compatible = "arasan,sdhci-8.9a" }, + { .compatible = "arasan,sdhci-5.1" }, + { .compatible = "arasan,sdhci-4.9a" }, + + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); + +/** + * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate + * + * Return the current actual rate of the SD card clock. This can be used + * to communicate with out PHY. + * + * @hw: Pointer to the hardware clock structure. + * @parent_rate The parent rate (should be rate of clk_xin). + * Returns the card clock rate. + */ +static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + +{ + struct sdhci_arasan_data *sdhci_arasan = + container_of(hw, struct sdhci_arasan_data, sdcardclk_hw); + struct sdhci_host *host = sdhci_arasan->host; + + return host->mmc->actual_clock; +} + +static const struct clk_ops arasan_sdcardclk_ops = { + .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, +}; + +/** + * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq + * + * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin. This + * function can be used to make that happen. + * + * NOTES: + * - Many existing devices don't seem to do this and work fine. To keep + * compatibility for old hardware where the device tree doesn't provide a + * register map, this function is a noop if a soc_ctl_map hasn't been provided + * for this platform. + * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider + * to achieve lower clock rates. That means that this function is called once + * at probe time and never called again. + * + * @host: The sdhci_host + */ +static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = + sdhci_arasan->soc_ctl_map; + u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000); + + /* Having a map is optional */ + if (!soc_ctl_map) + return; + + /* If we have a map, we expect to have a syscon */ + if (!sdhci_arasan->soc_ctl_base) { + pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", + mmc_hostname(host->mmc)); + return; + } + + sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz); +} + +/** + * sdhci_arasan_register_sdclk - Register the sdclk for a PHY to use + * + * Some PHY devices need to know what the actual card clock is. In order for + * them to find out, we'll provide a clock through the common clock framework + * for them to query. + * + * Note: without seriously re-architecting SDHCI's clock code and testing on + * all platforms, there's no way to create a totally beautiful clock here + * with all clock ops implemented. Instead, we'll just create a clock that can + * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock + * framework that we're doing things behind its back. This should be sufficient + * to create nice clean device tree bindings and later (if needed) we can try + * re-architecting SDHCI if we see some benefit to it. + * + * @sdhci_arasan: Our private data structure. + * @clk_xin: Pointer to the functional clock + * @dev: Pointer to our struct device. + * Returns 0 on success and error value on error + */ +static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, + struct clk *clk_xin, + struct device *dev) +{ + struct device_node *np = dev->of_node; + struct clk_init_data sdcardclk_init; + const char *parent_clk_name; + int ret; + + /* Providing a clock to the PHY is optional; no error if missing */ + if (!of_find_property(np, "#clock-cells", NULL)) + return 0; + + ret = of_property_read_string_index(np, "clock-output-names", 0, + &sdcardclk_init.name); + if (ret) { + dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); + return ret; + } + + parent_clk_name = __clk_get_name(clk_xin); + sdcardclk_init.parent_names = &parent_clk_name; + sdcardclk_init.num_parents = 1; + sdcardclk_init.flags = CLK_GET_RATE_NOCACHE; + sdcardclk_init.ops = &arasan_sdcardclk_ops; + + sdhci_arasan->sdcardclk_hw.init = &sdcardclk_init; + sdhci_arasan->sdcardclk = + devm_clk_register(dev, &sdhci_arasan->sdcardclk_hw); + sdhci_arasan->sdcardclk_hw.init = NULL; + + ret = of_clk_add_provider(np, of_clk_src_simple_get, + sdhci_arasan->sdcardclk); + if (ret) + dev_err(dev, "Failed to add clock provider\n"); + + return ret; +} + +/** + * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk() + * + * Should be called any time we're exiting and sdhci_arasan_register_sdclk() + * returned success. + * + * @dev: Pointer to our struct device. + */ +static void sdhci_arasan_unregister_sdclk(struct device *dev) +{ + struct device_node *np = dev->of_node; + + if (!of_find_property(np, "#clock-cells", NULL)) + return; + + of_clk_del_provider(dev->of_node); +} + static int sdhci_arasan_probe(struct platform_device *pdev) { int ret; + const struct of_device_id *match; + struct device_node *node; struct clk *clk_xin; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; @@ -187,6 +470,24 @@ static int sdhci_arasan_probe(struct platform_device *pdev) pltfm_host = sdhci_priv(host); sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + sdhci_arasan->host = host; + + match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node); + sdhci_arasan->soc_ctl_map = match->data; + + node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0); + if (node) { + sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node); + of_node_put(node); + + if (IS_ERR(sdhci_arasan->soc_ctl_base)) { + ret = PTR_ERR(sdhci_arasan->soc_ctl_base); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Can't get syscon: %d\n", + ret); + goto err_pltfm_free; + } + } sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); if (IS_ERR(sdhci_arasan->clk_ahb)) { @@ -217,10 +518,16 @@ static int sdhci_arasan_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); pltfm_host->clk = clk_xin; + sdhci_arasan_update_baseclkfreq(host); + + ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev); + if (ret) + goto clk_disable_all; + ret = mmc_of_parse(host->mmc); if (ret) { dev_err(&pdev->dev, "parsing dt failed (%u)\n", ret); - goto clk_disable_all; + goto unreg_clk; } sdhci_arasan->phy = ERR_PTR(-ENODEV); @@ -231,13 +538,13 @@ static int sdhci_arasan_probe(struct platform_device *pdev) if (IS_ERR(sdhci_arasan->phy)) { ret = PTR_ERR(sdhci_arasan->phy); dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n"); - goto clk_disable_all; + goto unreg_clk; } ret = phy_init(sdhci_arasan->phy); if (ret < 0) { dev_err(&pdev->dev, "phy_init err.\n"); - goto clk_disable_all; + goto unreg_clk; } ret = phy_power_on(sdhci_arasan->phy); @@ -245,6 +552,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev) dev_err(&pdev->dev, "phy_power_on err.\n"); goto err_phy_power; } + + host->mmc_host_ops.hs400_enhanced_strobe = + sdhci_arasan_hs400_enhanced_strobe; } ret = sdhci_add_host(host); @@ -259,6 +569,8 @@ err_add_host: err_phy_power: if (!IS_ERR(sdhci_arasan->phy)) phy_exit(sdhci_arasan->phy); +unreg_clk: + sdhci_arasan_unregister_sdclk(&pdev->dev); clk_disable_all: clk_disable_unprepare(clk_xin); clk_dis_ahb: @@ -281,6 +593,8 @@ static int sdhci_arasan_remove(struct platform_device *pdev) phy_exit(sdhci_arasan->phy); } + sdhci_arasan_unregister_sdclk(&pdev->dev); + ret = sdhci_pltfm_unregister(pdev); clk_disable_unprepare(clk_ahb); @@ -288,14 +602,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev) return ret; } -static const struct of_device_id sdhci_arasan_of_match[] = { - { .compatible = "arasan,sdhci-8.9a" }, - { .compatible = "arasan,sdhci-5.1" }, - { .compatible = "arasan,sdhci-4.9a" }, - { } -}; -MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); - static struct platform_driver sdhci_arasan_driver = { .driver = { .name = "sdhci-arasan", diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index d4cef713d..a9b7fc06c 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -288,7 +288,7 @@ static int sdhci_at91_probe(struct platform_device *pdev) * Disable SDHCI_QUIRK_BROKEN_CARD_DETECTION to be sure nobody tries * to enable polling via device tree with broken-cd property. */ - if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && + if (mmc_card_is_removable(host->mmc) && mmc_gpio_get_cd(host->mmc) < 0) { host->mmc->caps |= MMC_CAP_NEEDS_POLL; host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 3f34d354f..239be2fde 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -481,7 +481,7 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static u32 esdhc_proctl; static int esdhc_of_suspend(struct device *dev) { @@ -504,16 +504,12 @@ static int esdhc_of_resume(struct device *dev) } return ret; } - -static const struct dev_pm_ops esdhc_pmops = { - .suspend = esdhc_of_suspend, - .resume = esdhc_of_resume, -}; -#define ESDHC_PMOPS (&esdhc_pmops) -#else -#define ESDHC_PMOPS NULL #endif +static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops, + esdhc_of_suspend, + esdhc_of_resume); + static const struct sdhci_ops sdhci_esdhc_be_ops = { .read_l = esdhc_be_readl, .read_w = esdhc_be_readw, @@ -657,7 +653,7 @@ static struct platform_driver sdhci_esdhc_driver = { .driver = { .name = "sdhci-esdhc", .of_match_table = sdhci_esdhc_of_match, - .pm = ESDHC_PMOPS, + .pm = &esdhc_of_dev_pm_ops, }, .probe = sdhci_esdhc_probe, .remove = sdhci_pltfm_unregister, diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 4079a96ad..ac00c5efb 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -85,7 +85,7 @@ static struct platform_driver sdhci_hlwd_driver = { .driver = { .name = "sdhci-hlwd", .of_match_table = sdhci_hlwd_of_match, - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_hlwd_probe, .remove = sdhci_pltfm_unregister, diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index a4dbf7421..897cfd24c 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -419,13 +419,13 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { }; /* Define Host controllers for Intel Merrifield platform */ -#define INTEL_MRFL_EMMC_0 0 -#define INTEL_MRFL_EMMC_1 1 +#define INTEL_MRFLD_EMMC_0 0 +#define INTEL_MRFLD_EMMC_1 1 -static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot) +static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot) { - if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_0) && - (PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_1)) + if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFLD_EMMC_0) && + (PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFLD_EMMC_1)) /* SD support is not ready yet */ return -ENODEV; @@ -435,12 +435,12 @@ static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot) return 0; } -static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = { +static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 | SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .allow_runtime_pm = true, - .probe_slot = intel_mrfl_mmc_probe_slot, + .probe_slot = intel_mrfld_mmc_probe_slot, }; /* O2Micro extra registers */ @@ -1104,10 +1104,10 @@ static const struct pci_device_id pci_ids[] = { { .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MRFL_MMC, + .device = PCI_DEVICE_ID_INTEL_MRFLD_MMC, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrfl_mmc, + .driver_data = (kernel_ulong_t)&sdhci_intel_mrfld_mmc, }, { @@ -1413,8 +1413,7 @@ static const struct sdhci_ops sdhci_pci_ops = { * * \*****************************************************************************/ -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP static int sdhci_pci_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -1496,7 +1495,9 @@ static int sdhci_pci_resume(struct device *dev) return 0; } +#endif +#ifdef CONFIG_PM static int sdhci_pci_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -1562,17 +1563,10 @@ static int sdhci_pci_runtime_resume(struct device *dev) return 0; } - -#else /* CONFIG_PM */ - -#define sdhci_pci_suspend NULL -#define sdhci_pci_resume NULL - -#endif /* CONFIG_PM */ +#endif static const struct dev_pm_ops sdhci_pci_pm_ops = { - .suspend = sdhci_pci_suspend, - .resume = sdhci_pci_resume, + SET_SYSTEM_SLEEP_PM_OPS(sdhci_pci_suspend, sdhci_pci_resume) SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend, sdhci_pci_runtime_resume, NULL) }; @@ -1760,11 +1754,12 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) static void sdhci_pci_runtime_pm_allow(struct device *dev) { - pm_runtime_put_noidle(dev); - pm_runtime_allow(dev); + pm_suspend_ignore_children(dev, 1); pm_runtime_set_autosuspend_delay(dev, 50); pm_runtime_use_autosuspend(dev); - pm_suspend_ignore_children(dev, 1); + pm_runtime_allow(dev); + /* Stay active until mmc core scans for a card */ + pm_runtime_put_noidle(dev); } static void sdhci_pci_runtime_pm_forbid(struct device *dev) @@ -1810,15 +1805,13 @@ static int sdhci_pci_probe(struct pci_dev *pdev, return -ENODEV; } - ret = pci_enable_device(pdev); + ret = pcim_enable_device(pdev); if (ret) return ret; - chip = kzalloc(sizeof(struct sdhci_pci_chip), GFP_KERNEL); - if (!chip) { - ret = -ENOMEM; - goto err; - } + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; chip->pdev = pdev; chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data; @@ -1834,7 +1827,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev, if (chip->fixes && chip->fixes->probe) { ret = chip->fixes->probe(chip); if (ret) - goto free; + return ret; } slots = chip->num_slots; /* Quirk may have changed this */ @@ -1844,8 +1837,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev, if (IS_ERR(slot)) { for (i--; i >= 0; i--) sdhci_pci_remove_slot(chip->slots[i]); - ret = PTR_ERR(slot); - goto free; + return PTR_ERR(slot); } chip->slots[i] = slot; @@ -1855,35 +1847,18 @@ static int sdhci_pci_probe(struct pci_dev *pdev, sdhci_pci_runtime_pm_allow(&pdev->dev); return 0; - -free: - pci_set_drvdata(pdev, NULL); - kfree(chip); - -err: - pci_disable_device(pdev); - return ret; } static void sdhci_pci_remove(struct pci_dev *pdev) { int i; - struct sdhci_pci_chip *chip; + struct sdhci_pci_chip *chip = pci_get_drvdata(pdev); - chip = pci_get_drvdata(pdev); - - if (chip) { - if (chip->allow_runtime_pm) - sdhci_pci_runtime_pm_forbid(&pdev->dev); - - for (i = 0; i < chip->num_slots; i++) - sdhci_pci_remove_slot(chip->slots[i]); - - pci_set_drvdata(pdev, NULL); - kfree(chip); - } + if (chip->allow_runtime_pm) + sdhci_pci_runtime_pm_forbid(&pdev->dev); - pci_disable_device(pdev); + for (i = 0; i < chip->num_slots; i++) + sdhci_pci_remove_slot(chip->slots[i]); } static struct pci_driver sdhci_driver = { diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 89e715168..7e0788712 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -14,7 +14,7 @@ #define PCI_DEVICE_ID_INTEL_BSW_EMMC 0x2294 #define PCI_DEVICE_ID_INTEL_BSW_SDIO 0x2295 #define PCI_DEVICE_ID_INTEL_BSW_SD 0x2296 -#define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190 +#define PCI_DEVICE_ID_INTEL_MRFLD_MMC 0x1190 #define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9 #define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa #define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 64f287a03..1d17dcfc3 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -215,29 +215,26 @@ int sdhci_pltfm_unregister(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister); -#ifdef CONFIG_PM -int sdhci_pltfm_suspend(struct device *dev) +#ifdef CONFIG_PM_SLEEP +static int sdhci_pltfm_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); return sdhci_suspend_host(host); } -EXPORT_SYMBOL_GPL(sdhci_pltfm_suspend); -int sdhci_pltfm_resume(struct device *dev) +static int sdhci_pltfm_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); return sdhci_resume_host(host); } -EXPORT_SYMBOL_GPL(sdhci_pltfm_resume); +#endif const struct dev_pm_ops sdhci_pltfm_pmops = { - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, + SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume) }; EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops); -#endif /* CONFIG_PM */ static int __init sdhci_pltfm_drv_init(void) { diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index d38053bf9..3280f2077 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -109,13 +109,6 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host) return (void *)host->private; } -#ifdef CONFIG_PM -extern int sdhci_pltfm_suspend(struct device *dev); -extern int sdhci_pltfm_resume(struct device *dev); extern const struct dev_pm_ops sdhci_pltfm_pmops; -#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops) -#else -#define SDHCI_PLTFM_PMOPS NULL -#endif #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 1d8dd3540..347eae2d7 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -252,7 +252,7 @@ static struct platform_driver sdhci_pxav2_driver = { .driver = { .name = "sdhci-pxav2", .of_match_table = of_match_ptr(sdhci_pxav2_of_match), - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_pxav2_probe, .remove = sdhci_pxav2_remove, diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 30132500a..dd1938d34 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -583,24 +583,17 @@ static int sdhci_pxav3_runtime_resume(struct device *dev) } #endif -#ifdef CONFIG_PM static const struct dev_pm_ops sdhci_pxav3_pmops = { SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume) SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend, sdhci_pxav3_runtime_resume, NULL) }; -#define SDHCI_PXAV3_PMOPS (&sdhci_pxav3_pmops) - -#else -#define SDHCI_PXAV3_PMOPS NULL -#endif - static struct platform_driver sdhci_pxav3_driver = { .driver = { .name = "sdhci-pxav3", .of_match_table = of_match_ptr(sdhci_pxav3_of_match), - .pm = SDHCI_PXAV3_PMOPS, + .pm = &sdhci_pxav3_pmops, }, .probe = sdhci_pxav3_probe, .remove = sdhci_pxav3_remove, diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 70c724bc6..784c5a848 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -714,19 +714,12 @@ static int sdhci_s3c_runtime_resume(struct device *dev) } #endif -#ifdef CONFIG_PM static const struct dev_pm_ops sdhci_s3c_pmops = { SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume) SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume, NULL) }; -#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) - -#else -#define SDHCI_S3C_PMOPS NULL -#endif - #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { .no_divider = true, @@ -765,7 +758,7 @@ static struct platform_driver sdhci_s3c_driver = { .driver = { .name = "s3c-sdhci", .of_match_table = of_match_ptr(sdhci_s3c_dt_match), - .pm = SDHCI_S3C_PMOPS, + .pm = &sdhci_s3c_pmops, }, }; diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index 34866f668..5d068639d 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -260,9 +260,9 @@ static int sdhci_sirf_resume(struct device *dev) return sdhci_resume_host(host); } +#endif static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume); -#endif static const struct of_device_id sdhci_sirf_of_match[] = { { .compatible = "sirf,prima2-sdhc" }, @@ -274,9 +274,7 @@ static struct platform_driver sdhci_sirf_driver = { .driver = { .name = "sdhci-sirf", .of_match_table = sdhci_sirf_of_match, -#ifdef CONFIG_PM_SLEEP .pm = &sdhci_sirf_pm_ops, -#endif }, .probe = sdhci_sirf_probe, .remove = sdhci_pltfm_unregister, diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index b7eaecfdd..ed92ce729 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -184,7 +184,7 @@ static void st_mmcss_cconfig(struct device_node *np, struct sdhci_host *host) writel_relaxed(cconf2, host->ioaddr + ST_MMC_CCONFIG_REG_2); - if (mhost->caps & MMC_CAP_NONREMOVABLE) + if (!mmc_card_is_removable(mhost)) cconf3 |= ST_MMC_CCONFIG_EMMC_SLOT_TYPE; else /* CARD _D ET_CTRL */ diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index bcc0de47f..1e93dc4e3 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -148,28 +148,37 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) return; misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); - /* Erratum: Enable SDHCI spec v3.00 support */ - if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) - misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; - /* Advertise UHS modes as supported by host */ - if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) - misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; - else - misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50; - if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) - misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; - else - misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50; - if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) - misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; - else - misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104; - sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); - clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); + + misc_ctrl &= ~(SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 | + SDHCI_MISC_CTRL_ENABLE_SDR50 | + SDHCI_MISC_CTRL_ENABLE_DDR50 | + SDHCI_MISC_CTRL_ENABLE_SDR104); + clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE; - if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) - clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; + + /* + * If the board does not define a regulator for the SDHCI + * IO voltage, then don't advertise support for UHS modes + * even if the device supports it because the IO voltage + * cannot be configured. + */ + if (!IS_ERR(host->mmc->supply.vqmmc)) { + /* Erratum: Enable SDHCI spec v3.00 support */ + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; + /* Advertise UHS modes as supported by host */ + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; + if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; + if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) + clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; + } + + sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) @@ -474,7 +483,7 @@ static struct platform_driver sdhci_tegra_driver = { .driver = { .name = "sdhci-tegra", .of_match_table = sdhci_tegra_dt_match, - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_tegra_probe, .remove = sdhci_pltfm_unregister, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0e3d7c056..cd65d474a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -45,65 +45,62 @@ static unsigned int debug_quirks2; static void sdhci_finish_data(struct sdhci_host *); -static void sdhci_finish_command(struct sdhci_host *); -static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); -static int sdhci_get_cd(struct mmc_host *mmc); static void sdhci_dumpregs(struct sdhci_host *host) { - pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", - mmc_hostname(host->mmc)); - - pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", - sdhci_readl(host, SDHCI_DMA_ADDRESS), - sdhci_readw(host, SDHCI_HOST_VERSION)); - pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", - sdhci_readw(host, SDHCI_BLOCK_SIZE), - sdhci_readw(host, SDHCI_BLOCK_COUNT)); - pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", - sdhci_readl(host, SDHCI_ARGUMENT), - sdhci_readw(host, SDHCI_TRANSFER_MODE)); - pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", - sdhci_readl(host, SDHCI_PRESENT_STATE), - sdhci_readb(host, SDHCI_HOST_CONTROL)); - pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", - sdhci_readb(host, SDHCI_POWER_CONTROL), - sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); - pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", - sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), - sdhci_readw(host, SDHCI_CLOCK_CONTROL)); - pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", - sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), - sdhci_readl(host, SDHCI_INT_STATUS)); - pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", - sdhci_readl(host, SDHCI_INT_ENABLE), - sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); - pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", - sdhci_readw(host, SDHCI_ACMD12_ERR), - sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); - pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", - sdhci_readl(host, SDHCI_CAPABILITIES), - sdhci_readl(host, SDHCI_CAPABILITIES_1)); - pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", - sdhci_readw(host, SDHCI_COMMAND), - sdhci_readl(host, SDHCI_MAX_CURRENT)); - pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n", - sdhci_readw(host, SDHCI_HOST_CONTROL2)); + pr_err(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", + mmc_hostname(host->mmc)); + + pr_err(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + sdhci_readl(host, SDHCI_DMA_ADDRESS), + sdhci_readw(host, SDHCI_HOST_VERSION)); + pr_err(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + sdhci_readw(host, SDHCI_BLOCK_SIZE), + sdhci_readw(host, SDHCI_BLOCK_COUNT)); + pr_err(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + sdhci_readl(host, SDHCI_ARGUMENT), + sdhci_readw(host, SDHCI_TRANSFER_MODE)); + pr_err(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + sdhci_readl(host, SDHCI_PRESENT_STATE), + sdhci_readb(host, SDHCI_HOST_CONTROL)); + pr_err(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", + sdhci_readb(host, SDHCI_POWER_CONTROL), + sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); + pr_err(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", + sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), + sdhci_readw(host, SDHCI_CLOCK_CONTROL)); + pr_err(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", + sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), + sdhci_readl(host, SDHCI_INT_STATUS)); + pr_err(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + sdhci_readl(host, SDHCI_INT_ENABLE), + sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); + pr_err(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", + sdhci_readw(host, SDHCI_ACMD12_ERR), + sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); + pr_err(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", + sdhci_readl(host, SDHCI_CAPABILITIES), + sdhci_readl(host, SDHCI_CAPABILITIES_1)); + pr_err(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", + sdhci_readw(host, SDHCI_COMMAND), + sdhci_readl(host, SDHCI_MAX_CURRENT)); + pr_err(DRIVER_NAME ": Host ctl2: 0x%08x\n", + sdhci_readw(host, SDHCI_HOST_CONTROL2)); if (host->flags & SDHCI_USE_ADMA) { if (host->flags & SDHCI_USE_64_BIT_DMA) - pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n", - readl(host->ioaddr + SDHCI_ADMA_ERROR), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n", + readl(host->ioaddr + SDHCI_ADMA_ERROR), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); else - pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", - readl(host->ioaddr + SDHCI_ADMA_ERROR), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", + readl(host->ioaddr + SDHCI_ADMA_ERROR), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); } - pr_debug(DRIVER_NAME ": ===========================================\n"); + pr_err(DRIVER_NAME ": ===========================================\n"); } /*****************************************************************************\ @@ -112,12 +109,17 @@ static void sdhci_dumpregs(struct sdhci_host *host) * * \*****************************************************************************/ +static inline bool sdhci_data_line_cmd(struct mmc_command *cmd) +{ + return cmd->data || cmd->flags & MMC_RSP_BUSY; +} + static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) { u32 present; if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || - (host->mmc->caps & MMC_CAP_NONREMOVABLE)) + !mmc_card_is_removable(host->mmc)) return; if (enable) { @@ -193,7 +195,9 @@ EXPORT_SYMBOL_GPL(sdhci_reset); static void sdhci_do_reset(struct sdhci_host *host, u8 mask) { if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { - if (!sdhci_get_cd(host->mmc)) + struct mmc_host *mmc = host->mmc; + + if (!mmc->ops->get_cd(mmc)) return; } @@ -210,10 +214,10 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask) } } -static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); - static void sdhci_init(struct sdhci_host *host, int soft) { + struct mmc_host *mmc = host->mmc; + if (soft) sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); else @@ -225,13 +229,17 @@ static void sdhci_init(struct sdhci_host *host, int soft) SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; + if (host->tuning_mode == SDHCI_TUNING_MODE_2 || + host->tuning_mode == SDHCI_TUNING_MODE_3) + host->ier |= SDHCI_INT_RETUNE; + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); if (soft) { /* force clock reconfiguration */ host->clock = 0; - sdhci_set_ios(host->mmc, &host->mmc->ios); + mmc->ops->set_ios(mmc, &mmc->ios); } } @@ -429,8 +437,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host) { u32 mask; - BUG_ON(!host->data); - if (host->blocks == 0) return; @@ -747,14 +753,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) u8 ctrl; struct mmc_data *data = cmd->data; - WARN_ON(host->data); - - if (data || (cmd->flags & MMC_RSP_BUSY)) + if (sdhci_data_line_cmd(cmd)) sdhci_set_timeout(host, cmd); if (!data) return; + WARN_ON(host->data); + /* Sanity checks */ BUG_ON(data->blksz * data->blocks > 524288); BUG_ON(data->blksz > host->mmc->max_blk_size); @@ -879,6 +885,12 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); } +static inline bool sdhci_auto_cmd12(struct sdhci_host *host, + struct mmc_request *mrq) +{ + return !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12); +} + static void sdhci_set_transfer_mode(struct sdhci_host *host, struct mmc_command *cmd) { @@ -909,12 +921,12 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, * If we are sending CMD23, CMD12 never gets sent * on successful completion (so no Auto-CMD12). */ - if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) && + if (sdhci_auto_cmd12(host, cmd->mrq) && (cmd->opcode != SD_IO_RW_EXTENDED)) mode |= SDHCI_TRNS_AUTO_CMD12; - else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { + else if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { mode |= SDHCI_TRNS_AUTO_CMD23; - sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2); + sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2); } } @@ -926,14 +938,63 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); } -static void sdhci_finish_data(struct sdhci_host *host) +static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq) +{ + return (!(host->flags & SDHCI_DEVICE_DEAD) && + ((mrq->cmd && mrq->cmd->error) || + (mrq->sbc && mrq->sbc->error) || + (mrq->data && ((mrq->data->error && !mrq->data->stop) || + (mrq->data->stop && mrq->data->stop->error))) || + (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))); +} + +static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) +{ + int i; + + for (i = 0; i < SDHCI_MAX_MRQS; i++) { + if (host->mrqs_done[i] == mrq) { + WARN_ON(1); + return; + } + } + + for (i = 0; i < SDHCI_MAX_MRQS; i++) { + if (!host->mrqs_done[i]) { + host->mrqs_done[i] = mrq; + break; + } + } + + WARN_ON(i >= SDHCI_MAX_MRQS); + + tasklet_schedule(&host->finish_tasklet); +} + +static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) { - struct mmc_data *data; + if (host->cmd && host->cmd->mrq == mrq) + host->cmd = NULL; + + if (host->data_cmd && host->data_cmd->mrq == mrq) + host->data_cmd = NULL; + + if (host->data && host->data->mrq == mrq) + host->data = NULL; - BUG_ON(!host->data); + if (sdhci_needs_reset(host, mrq)) + host->pending_reset = true; + + __sdhci_finish_mrq(host, mrq); +} + +static void sdhci_finish_data(struct sdhci_host *host) +{ + struct mmc_command *data_cmd = host->data_cmd; + struct mmc_data *data = host->data; - data = host->data; host->data = NULL; + host->data_cmd = NULL; if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) == (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) @@ -958,20 +1019,41 @@ static void sdhci_finish_data(struct sdhci_host *host) */ if (data->stop && (data->error || - !host->mrq->sbc)) { + !data->mrq->sbc)) { /* * The controller needs a reset of internal state machines * upon error conditions. */ if (data->error) { - sdhci_do_reset(host, SDHCI_RESET_CMD); + if (!host->cmd || host->cmd == data_cmd) + sdhci_do_reset(host, SDHCI_RESET_CMD); sdhci_do_reset(host, SDHCI_RESET_DATA); } + /* Avoid triggering warning in sdhci_send_command() */ + host->cmd = NULL; sdhci_send_command(host, data->stop); - } else - tasklet_schedule(&host->finish_tasklet); + } else { + sdhci_finish_mrq(host, data->mrq); + } +} + +static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, + unsigned long timeout) +{ + if (sdhci_data_line_cmd(mrq->cmd)) + mod_timer(&host->data_timer, timeout); + else + mod_timer(&host->timer, timeout); +} + +static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) +{ + if (sdhci_data_line_cmd(mrq->cmd)) + del_timer(&host->data_timer); + else + del_timer(&host->timer); } void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) @@ -989,12 +1071,12 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) timeout = 10; mask = SDHCI_CMD_INHIBIT; - if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) + if (sdhci_data_line_cmd(cmd)) mask |= SDHCI_DATA_INHIBIT; /* We shouldn't wait for data inihibit for stop commands, even though they might use busy signaling */ - if (host->mrq->data && (cmd == host->mrq->data->stop)) + if (cmd->mrq->data && (cmd == cmd->mrq->data->stop)) mask &= ~SDHCI_DATA_INHIBIT; while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { @@ -1003,7 +1085,7 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mmc_hostname(host->mmc)); sdhci_dumpregs(host); cmd->error = -EIO; - tasklet_schedule(&host->finish_tasklet); + sdhci_finish_mrq(host, cmd->mrq); return; } timeout--; @@ -1015,10 +1097,13 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; else timeout += 10 * HZ; - mod_timer(&host->timer, timeout); + sdhci_mod_timer(host, cmd->mrq, timeout); host->cmd = cmd; - host->busy_handle = 0; + if (sdhci_data_line_cmd(cmd)) { + WARN_ON(host->data_cmd); + host->data_cmd = cmd; + } sdhci_prepare_data(host, cmd); @@ -1030,7 +1115,7 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) pr_err("%s: Unsupported response type!\n", mmc_hostname(host->mmc)); cmd->error = -EINVAL; - tasklet_schedule(&host->finish_tasklet); + sdhci_finish_mrq(host, cmd->mrq); return; } @@ -1059,40 +1144,58 @@ EXPORT_SYMBOL_GPL(sdhci_send_command); static void sdhci_finish_command(struct sdhci_host *host) { + struct mmc_command *cmd = host->cmd; int i; - BUG_ON(host->cmd == NULL); + host->cmd = NULL; - if (host->cmd->flags & MMC_RSP_PRESENT) { - if (host->cmd->flags & MMC_RSP_136) { + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) { /* CRC is stripped so we need to do some shifting. */ for (i = 0;i < 4;i++) { - host->cmd->resp[i] = sdhci_readl(host, + cmd->resp[i] = sdhci_readl(host, SDHCI_RESPONSE + (3-i)*4) << 8; if (i != 3) - host->cmd->resp[i] |= + cmd->resp[i] |= sdhci_readb(host, SDHCI_RESPONSE + (3-i)*4-1); } } else { - host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE); + cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE); + } + } + + /* + * The host can send and interrupt when the busy state has + * ended, allowing us to wait without wasting CPU cycles. + * The busy signal uses DAT0 so this is similar to waiting + * for data to complete. + * + * Note: The 1.0 specification is a bit ambiguous about this + * feature so there might be some problems with older + * controllers. + */ + if (cmd->flags & MMC_RSP_BUSY) { + if (cmd->data) { + DBG("Cannot wait for busy signal when also doing a data transfer"); + } else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && + cmd == host->data_cmd) { + /* Command complete before busy is ended */ + return; } } /* Finished CMD23, now send actual command. */ - if (host->cmd == host->mrq->sbc) { - host->cmd = NULL; - sdhci_send_command(host, host->mrq->cmd); + if (cmd == cmd->mrq->sbc) { + sdhci_send_command(host, cmd->mrq->cmd); } else { /* Processed actual command. */ if (host->data && host->data_early) sdhci_finish_data(host); - if (!host->cmd->data) - tasklet_schedule(&host->finish_tasklet); - - host->cmd = NULL; + if (!cmd->data) + sdhci_finish_mrq(host, cmd->mrq); } } @@ -1373,26 +1476,22 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_lock_irqsave(&host->lock, flags); - WARN_ON(host->mrq != NULL); - sdhci_led_activate(host); /* * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED * requests if Auto-CMD12 is enabled. */ - if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) { + if (sdhci_auto_cmd12(host, mrq)) { if (mrq->stop) { mrq->data->stop = NULL; mrq->stop = NULL; } } - host->mrq = mrq; - if (!present || host->flags & SDHCI_DEVICE_DEAD) { - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); + mrq->cmd->error = -ENOMEDIUM; + sdhci_finish_mrq(host, mrq); } else { if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) sdhci_send_command(host, mrq->sbc); @@ -1617,7 +1716,7 @@ static int sdhci_get_cd(struct mmc_host *mmc) return 0; /* If nonremovable, assume that the card is always present. */ - if (host->mmc->caps & MMC_CAP_NONREMOVABLE) + if (!mmc_card_is_removable(host->mmc)) return 1; /* @@ -1733,13 +1832,14 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, switch (ios->signal_voltage) { case MMC_SIGNAL_VOLTAGE_330: + if (!(host->flags & SDHCI_SIGNALING_330)) + return -EINVAL; /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ ctrl &= ~SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000, - 3600000); + ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", mmc_hostname(mmc)); @@ -1759,9 +1859,10 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return -EAGAIN; case MMC_SIGNAL_VOLTAGE_180: + if (!(host->flags & SDHCI_SIGNALING_180)) + return -EINVAL; if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_set_voltage(mmc->supply.vqmmc, - 1700000, 1950000); + ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", mmc_hostname(mmc)); @@ -1790,9 +1891,10 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return -EAGAIN; case MMC_SIGNAL_VOLTAGE_120: + if (!(host->flags & SDHCI_SIGNALING_120)) + return -EINVAL; if (!IS_ERR(mmc->supply.vqmmc)) { - ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000, - 1300000); + ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { pr_warn("%s: Switching to 1.2V signalling voltage failed\n", mmc_hostname(mmc)); @@ -1811,10 +1913,10 @@ static int sdhci_card_busy(struct mmc_host *mmc) struct sdhci_host *host = mmc_priv(mmc); u32 present_state; - /* Check whether DAT[3:0] is 0000 */ + /* Check whether DAT[0] is 0 */ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); - return !(present_state & SDHCI_DATA_LVL_MASK); + return !(present_state & SDHCI_DATA_0_LVL_MASK); } static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) @@ -1909,7 +2011,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) /* * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number - * of loops reaches 40 times or a timeout of 150ms occurs. + * of loops reaches 40 times. */ do { struct mmc_command cmd = {0}; @@ -1920,13 +2022,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.retries = 0; cmd.data = NULL; + cmd.mrq = &mrq; cmd.error = 0; if (tuning_loop_counter-- == 0) break; mrq.cmd = &cmd; - host->mrq = &mrq; /* * In response to CMD19, the card sends 64 bytes of tuning @@ -1956,7 +2058,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_send_command(host, &cmd); host->cmd = NULL; - host->mrq = NULL; + sdhci_del_timer(host, &mrq); spin_unlock_irqrestore(&host->lock, flags); /* Wait for Buffer Read Ready interrupt */ @@ -2086,6 +2188,24 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED); } +static inline bool sdhci_has_requests(struct sdhci_host *host) +{ + return host->cmd || host->data_cmd; +} + +static void sdhci_error_out_mrqs(struct sdhci_host *host, int err) +{ + if (host->data_cmd) { + host->data_cmd->error = err; + sdhci_finish_mrq(host, host->data_cmd->mrq); + } + + if (host->cmd) { + host->cmd->error = err; + sdhci_finish_mrq(host, host->cmd->mrq); + } +} + static void sdhci_card_event(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); @@ -2096,12 +2216,12 @@ static void sdhci_card_event(struct mmc_host *mmc) if (host->ops->card_event) host->ops->card_event(host); - present = sdhci_get_cd(host->mmc); + present = mmc->ops->get_cd(mmc); spin_lock_irqsave(&host->lock, flags); - /* Check host->mrq first in case we are runtime suspended */ - if (host->mrq && !present) { + /* Check sdhci_has_requests() first in case we are runtime suspended */ + if (sdhci_has_requests(host) && !present) { pr_err("%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); pr_err("%s: Resetting controller.\n", @@ -2110,8 +2230,7 @@ static void sdhci_card_event(struct mmc_host *mmc) sdhci_do_reset(host, SDHCI_RESET_CMD); sdhci_do_reset(host, SDHCI_RESET_DATA); - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); + sdhci_error_out_mrqs(host, -ENOMEDIUM); } spin_unlock_irqrestore(&host->lock, flags); @@ -2140,28 +2259,28 @@ static const struct mmc_host_ops sdhci_ops = { * * \*****************************************************************************/ -static void sdhci_tasklet_finish(unsigned long param) +static bool sdhci_request_done(struct sdhci_host *host) { - struct sdhci_host *host; unsigned long flags; struct mmc_request *mrq; - - host = (struct sdhci_host*)param; + int i; spin_lock_irqsave(&host->lock, flags); - /* - * If this tasklet gets rescheduled while running, it will - * be run again afterwards but without any active request. - */ - if (!host->mrq) { - spin_unlock_irqrestore(&host->lock, flags); - return; + for (i = 0; i < SDHCI_MAX_MRQS; i++) { + mrq = host->mrqs_done[i]; + if (mrq) { + host->mrqs_done[i] = NULL; + break; + } } - del_timer(&host->timer); + if (!mrq) { + spin_unlock_irqrestore(&host->lock, flags); + return true; + } - mrq = host->mrq; + sdhci_del_timer(host, mrq); /* * Always unmap the data buffers if they were mapped by @@ -2183,13 +2302,7 @@ static void sdhci_tasklet_finish(unsigned long param) * The controller needs a reset of internal state machines * upon error conditions. */ - if (!(host->flags & SDHCI_DEVICE_DEAD) && - ((mrq->cmd && mrq->cmd->error) || - (mrq->sbc && mrq->sbc->error) || - (mrq->data && ((mrq->data->error && !mrq->data->stop) || - (mrq->data->stop && mrq->data->stop->error))) || - (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { - + if (sdhci_needs_reset(host, mrq)) { /* Some controllers need this kick or reset won't work here */ if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) /* This is to force an update */ @@ -2197,20 +2310,31 @@ static void sdhci_tasklet_finish(unsigned long param) /* Spec says we should do both at the same time, but Ricoh controllers do not like that. */ - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); - } + if (!host->cmd) + sdhci_do_reset(host, SDHCI_RESET_CMD); + if (!host->data_cmd) + sdhci_do_reset(host, SDHCI_RESET_DATA); - host->mrq = NULL; - host->cmd = NULL; - host->data = NULL; + host->pending_reset = false; + } - sdhci_led_deactivate(host); + if (!sdhci_has_requests(host)) + sdhci_led_deactivate(host); mmiowb(); spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); + + return false; +} + +static void sdhci_tasklet_finish(unsigned long param) +{ + struct sdhci_host *host = (struct sdhci_host *)param; + + while (!sdhci_request_done(host)) + ; } static void sdhci_timeout_timer(unsigned long data) @@ -2222,7 +2346,30 @@ static void sdhci_timeout_timer(unsigned long data) spin_lock_irqsave(&host->lock, flags); - if (host->mrq) { + if (host->cmd && !sdhci_data_line_cmd(host->cmd)) { + pr_err("%s: Timeout waiting for hardware cmd interrupt.\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + + host->cmd->error = -ETIMEDOUT; + sdhci_finish_mrq(host, host->cmd->mrq); + } + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void sdhci_timeout_data_timer(unsigned long data) +{ + struct sdhci_host *host; + unsigned long flags; + + host = (struct sdhci_host *)data; + + spin_lock_irqsave(&host->lock, flags); + + if (host->data || host->data_cmd || + (host->cmd && sdhci_data_line_cmd(host->cmd))) { pr_err("%s: Timeout waiting for hardware interrupt.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); @@ -2230,13 +2377,12 @@ static void sdhci_timeout_timer(unsigned long data) if (host->data) { host->data->error = -ETIMEDOUT; sdhci_finish_data(host); + } else if (host->data_cmd) { + host->data_cmd->error = -ETIMEDOUT; + sdhci_finish_mrq(host, host->data_cmd->mrq); } else { - if (host->cmd) - host->cmd->error = -ETIMEDOUT; - else - host->mrq->cmd->error = -ETIMEDOUT; - - tasklet_schedule(&host->finish_tasklet); + host->cmd->error = -ETIMEDOUT; + sdhci_finish_mrq(host, host->cmd->mrq); } } @@ -2252,9 +2398,14 @@ static void sdhci_timeout_timer(unsigned long data) static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) { - BUG_ON(intmask == 0); - if (!host->cmd) { + /* + * SDHCI recovers from errors by resetting the cmd and data + * circuits. Until that is done, there very well might be more + * interrupts, so ignore them in that case. + */ + if (host->pending_reset) + return; pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); @@ -2285,37 +2436,14 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) return; } - tasklet_schedule(&host->finish_tasklet); + sdhci_finish_mrq(host, host->cmd->mrq); return; } - /* - * The host can send and interrupt when the busy state has - * ended, allowing us to wait without wasting CPU cycles. - * Unfortunately this is overloaded on the "data complete" - * interrupt, so we need to take some care when handling - * it. - * - * Note: The 1.0 specification is a bit ambiguous about this - * feature so there might be some problems with older - * controllers. - */ - if (host->cmd->flags & MMC_RSP_BUSY) { - if (host->cmd->data) - DBG("Cannot wait for busy signal when also doing a data transfer"); - else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) - && !host->busy_handle) { - /* Mark that command complete before busy is ended */ - host->busy_handle = 1; - return; - } - - /* The controller does not support the end-of-busy IRQ, - * fall through and take the SDHCI_INT_RESPONSE */ - } else if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && - host->cmd->opcode == MMC_STOP_TRANSMISSION && !host->data) { + if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && + !(host->cmd->flags & MMC_RSP_BUSY) && !host->data && + host->cmd->opcode == MMC_STOP_TRANSMISSION) *mask &= ~SDHCI_INT_DATA_END; - } if (intmask & SDHCI_INT_RESPONSE) sdhci_finish_command(host); @@ -2357,7 +2485,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host) { } static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { u32 command; - BUG_ON(intmask == 0); /* CMD19 generates _only_ Buffer Read Ready interrupt */ if (intmask & SDHCI_INT_DATA_AVAIL) { @@ -2371,15 +2498,20 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } if (!host->data) { + struct mmc_command *data_cmd = host->data_cmd; + + if (data_cmd) + host->data_cmd = NULL; + /* * The "data complete" interrupt is also used to * indicate that a busy state has ended. See comment * above in sdhci_cmd_irq(). */ - if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) { + if (data_cmd && (data_cmd->flags & MMC_RSP_BUSY)) { if (intmask & SDHCI_INT_DATA_TIMEOUT) { - host->cmd->error = -ETIMEDOUT; - tasklet_schedule(&host->finish_tasklet); + data_cmd->error = -ETIMEDOUT; + sdhci_finish_mrq(host, data_cmd->mrq); return; } if (intmask & SDHCI_INT_DATA_END) { @@ -2388,14 +2520,22 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) * before the command completed, so make * sure we do things in the proper order. */ - if (host->busy_handle) - sdhci_finish_command(host); - else - host->busy_handle = 1; + if (host->cmd == data_cmd) + return; + + sdhci_finish_mrq(host, data_cmd->mrq); return; } } + /* + * SDHCI recovers from errors by resetting the cmd and data + * circuits. Until that is done, there very well might be more + * interrupts, so ignore them in that case. + */ + if (host->pending_reset) + return; + pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); @@ -2453,7 +2593,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } if (intmask & SDHCI_INT_DATA_END) { - if (host->cmd) { + if (host->cmd == host->data_cmd) { /* * Data managed to finish before the * command completed. Make sure we do @@ -2537,6 +2677,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) pr_err("%s: Card is consuming too much power!\n", mmc_hostname(host->mmc)); + if (intmask & SDHCI_INT_RETUNE) + mmc_retune_needed(host->mmc); + if (intmask & SDHCI_INT_CARD_INT) { sdhci_enable_sdio_irq_nolock(host, false); host->thread_isr |= SDHCI_INT_CARD_INT; @@ -2546,7 +2689,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER | - SDHCI_INT_CARD_INT); + SDHCI_INT_RETUNE | SDHCI_INT_CARD_INT); if (intmask) { unexpected |= intmask; @@ -2582,8 +2725,10 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) spin_unlock_irqrestore(&host->lock, flags); if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { - sdhci_card_event(host->mmc); - mmc_detect_change(host->mmc, msecs_to_jiffies(200)); + struct mmc_host *mmc = host->mmc; + + mmc->ops->card_event(mmc); + mmc_detect_change(mmc, msecs_to_jiffies(200)); } if (isr & SDHCI_INT_CARD_INT) { @@ -2605,18 +2750,31 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) \*****************************************************************************/ #ifdef CONFIG_PM +/* + * To enable wakeup events, the corresponding events have to be enabled in + * the Interrupt Status Enable register too. See 'Table 1-6: Wakeup Signal + * Table' in the SD Host Controller Standard Specification. + * It is useless to restore SDHCI_INT_ENABLE state in + * sdhci_disable_irq_wakeups() since it will be set by + * sdhci_enable_card_detection() or sdhci_init(). + */ void sdhci_enable_irq_wakeups(struct sdhci_host *host) { u8 val; u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE | SDHCI_WAKE_ON_INT; + u32 irq_val = SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | + SDHCI_INT_CARD_INT; val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); val |= mask ; /* Avoid fake wake up */ - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) + if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) { val &= ~(SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE); + irq_val &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); + } sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL); + sdhci_writel(host, irq_val, SDHCI_INT_ENABLE); } EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); @@ -2636,7 +2794,8 @@ int sdhci_suspend_host(struct sdhci_host *host) sdhci_disable_card_detection(host); mmc_retune_timer_stop(host->mmc); - mmc_retune_needed(host->mmc); + if (host->tuning_mode != SDHCI_TUNING_MODE_3) + mmc_retune_needed(host->mmc); if (!device_may_wakeup(mmc_dev(host->mmc))) { host->ier = 0; @@ -2654,6 +2813,7 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host); int sdhci_resume_host(struct sdhci_host *host) { + struct mmc_host *mmc = host->mmc; int ret = 0; if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { @@ -2667,7 +2827,7 @@ int sdhci_resume_host(struct sdhci_host *host) sdhci_init(host, 0); host->pwr = 0; host->clock = 0; - sdhci_set_ios(host->mmc, &host->mmc->ios); + mmc->ops->set_ios(mmc, &mmc->ios); } else { sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); mmiowb(); @@ -2696,7 +2856,8 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) unsigned long flags; mmc_retune_timer_stop(host->mmc); - mmc_retune_needed(host->mmc); + if (host->tuning_mode != SDHCI_TUNING_MODE_3) + mmc_retune_needed(host->mmc); spin_lock_irqsave(&host->lock, flags); host->ier &= SDHCI_INT_CARD_INT; @@ -2716,6 +2877,7 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host); int sdhci_runtime_resume_host(struct sdhci_host *host) { + struct mmc_host *mmc = host->mmc; unsigned long flags; int host_flags = host->flags; @@ -2729,8 +2891,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) /* Force clock and power re-program */ host->pwr = 0; host->clock = 0; - sdhci_start_signal_voltage_switch(host->mmc, &host->mmc->ios); - sdhci_set_ios(host->mmc, &host->mmc->ios); + mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios); + mmc->ops->set_ios(mmc, &mmc->ios); if ((host_flags & SDHCI_PV_ENABLED) && !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { @@ -2781,6 +2943,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, host->mmc_host_ops = sdhci_ops; mmc->ops = &host->mmc_host_ops; + host->flags = SDHCI_SIGNALING_330; + return host; } @@ -2816,10 +2980,41 @@ static int sdhci_set_dma_mask(struct sdhci_host *host) return ret; } -int sdhci_add_host(struct sdhci_host *host) +void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1) +{ + u16 v; + + if (host->read_caps) + return; + + host->read_caps = true; + + if (debug_quirks) + host->quirks = debug_quirks; + + if (debug_quirks2) + host->quirks2 = debug_quirks2; + + sdhci_do_reset(host, SDHCI_RESET_ALL); + + v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION); + host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; + + if (host->quirks & SDHCI_QUIRK_MISSING_CAPS) + return; + + host->caps = caps ? *caps : sdhci_readl(host, SDHCI_CAPABILITIES); + + if (host->version < SDHCI_SPEC_300) + return; + + host->caps1 = caps1 ? *caps1 : sdhci_readl(host, SDHCI_CAPABILITIES_1); +} +EXPORT_SYMBOL_GPL(__sdhci_read_caps); + +int sdhci_setup_host(struct sdhci_host *host) { struct mmc_host *mmc; - u32 caps[2] = {0, 0}; u32 max_current_caps; unsigned int ocr_avail; unsigned int override_timeout_clk; @@ -2832,34 +3027,28 @@ int sdhci_add_host(struct sdhci_host *host) mmc = host->mmc; - if (debug_quirks) - host->quirks = debug_quirks; - if (debug_quirks2) - host->quirks2 = debug_quirks2; + /* + * If there are external regulators, get them. Note this must be done + * early before resetting the host and reading the capabilities so that + * the host can take the appropriate action if regulators are not + * available. + */ + ret = mmc_regulator_get_supply(mmc); + if (ret == -EPROBE_DEFER) + return ret; - override_timeout_clk = host->timeout_clk; + sdhci_read_caps(host); - sdhci_do_reset(host, SDHCI_RESET_ALL); + override_timeout_clk = host->timeout_clk; - host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - host->version = (host->version & SDHCI_SPEC_VER_MASK) - >> SDHCI_SPEC_VER_SHIFT; if (host->version > SDHCI_SPEC_300) { pr_err("%s: Unknown controller version (%d). You may experience problems.\n", mmc_hostname(mmc), host->version); } - caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : - sdhci_readl(host, SDHCI_CAPABILITIES); - - if (host->version >= SDHCI_SPEC_300) - caps[1] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? - host->caps1 : - sdhci_readl(host, SDHCI_CAPABILITIES_1); - if (host->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_SDMA; - else if (!(caps[0] & SDHCI_CAN_DO_SDMA)) + else if (!(host->caps & SDHCI_CAN_DO_SDMA)) DBG("Controller doesn't have SDMA capability\n"); else host->flags |= SDHCI_USE_SDMA; @@ -2871,7 +3060,7 @@ int sdhci_add_host(struct sdhci_host *host) } if ((host->version >= SDHCI_SPEC_200) && - (caps[0] & SDHCI_CAN_DO_ADMA2)) + (host->caps & SDHCI_CAN_DO_ADMA2)) host->flags |= SDHCI_USE_ADMA; if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) && @@ -2887,7 +3076,7 @@ int sdhci_add_host(struct sdhci_host *host) * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to * implement. */ - if (caps[0] & SDHCI_CAN_64BIT) + if (host->caps & SDHCI_CAN_64BIT) host->flags |= SDHCI_USE_64_BIT_DMA; if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { @@ -2963,10 +3152,10 @@ int sdhci_add_host(struct sdhci_host *host) } if (host->version >= SDHCI_SPEC_300) - host->max_clk = (caps[0] & SDHCI_CLOCK_V3_BASE_MASK) + host->max_clk = (host->caps & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; else - host->max_clk = (caps[0] & SDHCI_CLOCK_BASE_MASK) + host->max_clk = (host->caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; host->max_clk *= 1000000; @@ -2985,7 +3174,7 @@ int sdhci_add_host(struct sdhci_host *host) * In case of Host Controller v3.00, find out whether clock * multiplier is supported. */ - host->clk_mul = (caps[1] & SDHCI_CLOCK_MUL_MASK) >> + host->clk_mul = (host->caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; /* @@ -3017,7 +3206,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->f_max = max_clk; if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { - host->timeout_clk = (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> + host->timeout_clk = (host->caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; if (host->timeout_clk == 0) { if (host->ops->get_timeout_clock) { @@ -3031,7 +3220,7 @@ int sdhci_add_host(struct sdhci_host *host) } } - if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT) + if (host->caps & SDHCI_TIMEOUT_CLK_UNIT) host->timeout_clk *= 1000; if (override_timeout_clk) @@ -3072,27 +3261,22 @@ int sdhci_add_host(struct sdhci_host *host) if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23) mmc->caps &= ~MMC_CAP_CMD23; - if (caps[0] & SDHCI_CAN_DO_HISPD) + if (host->caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && - !(mmc->caps & MMC_CAP_NONREMOVABLE) && + mmc_card_is_removable(mmc) && mmc_gpio_get_cd(host->mmc) < 0) mmc->caps |= MMC_CAP_NEEDS_POLL; - /* If there are external regulators, get them */ - ret = mmc_regulator_get_supply(mmc); - if (ret == -EPROBE_DEFER) - goto undma; - /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { ret = regulator_enable(mmc->supply.vqmmc); if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000, 1950000)) - caps[1] &= ~(SDHCI_SUPPORT_SDR104 | - SDHCI_SUPPORT_SDR50 | - SDHCI_SUPPORT_DDR50); + host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | + SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50); if (ret) { pr_warn("%s: Failed to enable vqmmc regulator: %d\n", mmc_hostname(mmc), ret); @@ -3100,28 +3284,30 @@ int sdhci_add_host(struct sdhci_host *host) } } - if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) - caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | - SDHCI_SUPPORT_DDR50); + if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) { + host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50); + } /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ - if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | - SDHCI_SUPPORT_DDR50)) + if (host->caps1 & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50)) mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; /* SDR104 supports also implies SDR50 support */ - if (caps[1] & SDHCI_SUPPORT_SDR104) { + if (host->caps1 & SDHCI_SUPPORT_SDR104) { mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50; /* SD3.0: SDR104 is supported so (for eMMC) the caps2 * field can be promoted to support HS200. */ if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) mmc->caps2 |= MMC_CAP2_HS200; - } else if (caps[1] & SDHCI_SUPPORT_SDR50) + } else if (host->caps1 & SDHCI_SUPPORT_SDR50) { mmc->caps |= MMC_CAP_UHS_SDR50; + } if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 && - (caps[1] & SDHCI_SUPPORT_HS400)) + (host->caps1 & SDHCI_SUPPORT_HS400)) mmc->caps2 |= MMC_CAP2_HS400; if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) && @@ -3130,25 +3316,25 @@ int sdhci_add_host(struct sdhci_host *host) 1300000))) mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V; - if ((caps[1] & SDHCI_SUPPORT_DDR50) && - !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) + if ((host->caps1 & SDHCI_SUPPORT_DDR50) && + !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) mmc->caps |= MMC_CAP_UHS_DDR50; /* Does the host need tuning for SDR50? */ - if (caps[1] & SDHCI_USE_SDR50_TUNING) + if (host->caps1 & SDHCI_USE_SDR50_TUNING) host->flags |= SDHCI_SDR50_NEEDS_TUNING; /* Driver Type(s) (A, C, D) supported by the host */ - if (caps[1] & SDHCI_DRIVER_TYPE_A) + if (host->caps1 & SDHCI_DRIVER_TYPE_A) mmc->caps |= MMC_CAP_DRIVER_TYPE_A; - if (caps[1] & SDHCI_DRIVER_TYPE_C) + if (host->caps1 & SDHCI_DRIVER_TYPE_C) mmc->caps |= MMC_CAP_DRIVER_TYPE_C; - if (caps[1] & SDHCI_DRIVER_TYPE_D) + if (host->caps1 & SDHCI_DRIVER_TYPE_D) mmc->caps |= MMC_CAP_DRIVER_TYPE_D; /* Initial value for re-tuning timer count */ - host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >> - SDHCI_RETUNING_TIMER_COUNT_SHIFT; + host->tuning_count = (host->caps1 & SDHCI_RETUNING_TIMER_COUNT_MASK) >> + SDHCI_RETUNING_TIMER_COUNT_SHIFT; /* * In case Re-tuning Timer is not disabled, the actual value of @@ -3158,7 +3344,7 @@ int sdhci_add_host(struct sdhci_host *host) host->tuning_count = 1 << (host->tuning_count - 1); /* Re-tuning mode supported by the Host Controller */ - host->tuning_mode = (caps[1] & SDHCI_RETUNING_MODE_MASK) >> + host->tuning_mode = (host->caps1 & SDHCI_RETUNING_MODE_MASK) >> SDHCI_RETUNING_MODE_SHIFT; ocr_avail = 0; @@ -3187,7 +3373,7 @@ int sdhci_add_host(struct sdhci_host *host) } } - if (caps[0] & SDHCI_CAN_VDD_330) { + if (host->caps & SDHCI_CAN_VDD_330) { ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; mmc->max_current_330 = ((max_current_caps & @@ -3195,7 +3381,7 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_MAX_CURRENT_330_SHIFT) * SDHCI_MAX_CURRENT_MULTIPLIER; } - if (caps[0] & SDHCI_CAN_VDD_300) { + if (host->caps & SDHCI_CAN_VDD_300) { ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31; mmc->max_current_300 = ((max_current_caps & @@ -3203,7 +3389,7 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_MAX_CURRENT_300_SHIFT) * SDHCI_MAX_CURRENT_MULTIPLIER; } - if (caps[0] & SDHCI_CAN_VDD_180) { + if (host->caps & SDHCI_CAN_VDD_180) { ocr_avail |= MMC_VDD_165_195; mmc->max_current_180 = ((max_current_caps & @@ -3240,6 +3426,15 @@ int sdhci_add_host(struct sdhci_host *host) goto unreg; } + if ((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR)) || + (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) + host->flags |= SDHCI_SIGNALING_180; + + if (mmc->caps2 & MMC_CAP2_HSX00_1_2V) + host->flags |= SDHCI_SIGNALING_120; + spin_lock_init(&host->lock); /* @@ -3281,7 +3476,7 @@ int sdhci_add_host(struct sdhci_host *host) if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) { mmc->max_blk_size = 2; } else { - mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >> + mmc->max_blk_size = (host->caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; if (mmc->max_blk_size >= 3) { pr_warn("%s: Invalid maximum block size, assuming 512 bytes\n", @@ -3297,6 +3492,28 @@ int sdhci_add_host(struct sdhci_host *host) */ mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535; + return 0; + +unreg: + if (!IS_ERR(mmc->supply.vqmmc)) + regulator_disable(mmc->supply.vqmmc); +undma: + if (host->align_buffer) + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, host->align_buffer, + host->align_addr); + host->adma_table = NULL; + host->align_buffer = NULL; + + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_setup_host); + +int __sdhci_add_host(struct sdhci_host *host) +{ + struct mmc_host *mmc = host->mmc; + int ret; + /* * Init tasklets. */ @@ -3304,6 +3521,8 @@ int sdhci_add_host(struct sdhci_host *host) sdhci_tasklet_finish, (unsigned long)host); setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); + setup_timer(&host->data_timer, sdhci_timeout_data_timer, + (unsigned long)host); init_waitqueue_head(&host->buf_ready_int); @@ -3353,10 +3572,10 @@ unirq: free_irq(host->irq, host); untasklet: tasklet_kill(&host->finish_tasklet); -unreg: + if (!IS_ERR(mmc->supply.vqmmc)) regulator_disable(mmc->supply.vqmmc); -undma: + if (host->align_buffer) dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + host->adma_table_sz, host->align_buffer, @@ -3366,7 +3585,18 @@ undma: return ret; } +EXPORT_SYMBOL_GPL(__sdhci_add_host); + +int sdhci_add_host(struct sdhci_host *host) +{ + int ret; + ret = sdhci_setup_host(host); + if (ret) + return ret; + + return __sdhci_add_host(host); +} EXPORT_SYMBOL_GPL(sdhci_add_host); void sdhci_remove_host(struct sdhci_host *host, int dead) @@ -3379,12 +3609,10 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) host->flags |= SDHCI_DEVICE_DEAD; - if (host->mrq) { + if (sdhci_has_requests(host)) { pr_err("%s: Controller removed during " " transfer!\n", mmc_hostname(mmc)); - - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); + sdhci_error_out_mrqs(host, -ENOMEDIUM); } spin_unlock_irqrestore(&host->lock, flags); @@ -3404,6 +3632,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) free_irq(host->irq, host); del_timer_sync(&host->timer); + del_timer_sync(&host->data_timer); tasklet_kill(&host->finish_tasklet); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 609f87ca5..0411c9f36 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -128,6 +128,7 @@ #define SDHCI_INT_CARD_INSERT 0x00000040 #define SDHCI_INT_CARD_REMOVE 0x00000080 #define SDHCI_INT_CARD_INT 0x00000100 +#define SDHCI_INT_RETUNE 0x00001000 #define SDHCI_INT_ERROR 0x00008000 #define SDHCI_INT_TIMEOUT 0x00010000 #define SDHCI_INT_CRC 0x00020000 @@ -186,6 +187,7 @@ #define SDHCI_CAN_DO_ADMA1 0x00100000 #define SDHCI_CAN_DO_HISPD 0x00200000 #define SDHCI_CAN_DO_SDMA 0x00400000 +#define SDHCI_CAN_DO_SUSPEND 0x00800000 #define SDHCI_CAN_VDD_330 0x01000000 #define SDHCI_CAN_VDD_300 0x02000000 #define SDHCI_CAN_VDD_180 0x04000000 @@ -314,6 +316,9 @@ struct sdhci_adma2_64_desc { */ #define SDHCI_MAX_SEGS 128 +/* Allow for a a command request and a data request at the same time */ +#define SDHCI_MAX_MRQS 2 + enum sdhci_cookie { COOKIE_UNMAPPED, COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ @@ -447,6 +452,9 @@ struct sdhci_host { #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ #define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ #define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ +#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */ +#define SDHCI_SIGNALING_180 (1<<15) /* Host is capable of 1.8V signaling */ +#define SDHCI_SIGNALING_120 (1<<16) /* Host is capable of 1.2V signaling */ unsigned int version; /* SDHCI spec. version */ @@ -460,12 +468,13 @@ struct sdhci_host { bool runtime_suspended; /* Host is runtime suspended */ bool bus_on; /* Bus power prevents runtime suspend */ bool preset_enabled; /* Preset is enabled */ + bool pending_reset; /* Cmd/data reset is pending */ - struct mmc_request *mrq; /* Current request */ + struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */ struct mmc_command *cmd; /* Current command */ + struct mmc_command *data_cmd; /* Current data command */ struct mmc_data *data; /* Current data request */ unsigned int data_early:1; /* Data finished before cmd */ - unsigned int busy_handle:1; /* Handling the order of Busy-end */ struct sg_mapping_iter sg_miter; /* SG state for PIO */ unsigned int blocks; /* remaining PIO blocks */ @@ -486,9 +495,11 @@ struct sdhci_host { struct tasklet_struct finish_tasklet; /* Tasklet structures */ struct timer_list timer; /* Timer for timeouts */ + struct timer_list data_timer; /* Timer for data timeouts */ - u32 caps; /* Alternative CAPABILITY_0 */ - u32 caps1; /* Alternative CAPABILITY_1 */ + u32 caps; /* CAPABILITY_0 */ + u32 caps1; /* CAPABILITY_1 */ + bool read_caps; /* Capability flags have been read */ unsigned int ocr_avail_sdio; /* OCR bit masks */ unsigned int ocr_avail_sd; @@ -508,6 +519,8 @@ struct sdhci_host { unsigned int tuning_count; /* Timer count for re-tuning */ unsigned int tuning_mode; /* Re-tuning mode supported by host */ #define SDHCI_TUNING_MODE_1 0 +#define SDHCI_TUNING_MODE_2 1 +#define SDHCI_TUNING_MODE_3 2 unsigned long private[0] ____cacheline_aligned; }; @@ -645,11 +658,20 @@ static inline void *sdhci_priv(struct sdhci_host *host) } extern void sdhci_card_detect(struct sdhci_host *host); +extern void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, + u32 *caps1); +extern int sdhci_setup_host(struct sdhci_host *host); +extern int __sdhci_add_host(struct sdhci_host *host); extern int sdhci_add_host(struct sdhci_host *host); extern void sdhci_remove_host(struct sdhci_host *host, int dead); extern void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); +static inline void sdhci_read_caps(struct sdhci_host *host) +{ + __sdhci_read_caps(host, NULL, NULL, NULL); +} + static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host) { return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED); diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index 983b8b32e..111b66f54 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -222,7 +222,7 @@ static struct platform_driver sdhci_f_sdh30_driver = { .driver = { .name = "f_sdh30", .of_match_table = f_sdh30_dt_ids, - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_f_sdh30_probe, .remove = sdhci_f_sdh30_remove, diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index dd64b8663..900778421 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -574,7 +574,7 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); - for (timeout = 10000000; timeout; timeout--) { + for (timeout = 10000; timeout; timeout--) { if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) & STS1_CMDSEQ)) break; @@ -819,10 +819,12 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, tmp |= CMD_SET_RTYP_NO; break; case MMC_RSP_R1: - case MMC_RSP_R1B: case MMC_RSP_R3: tmp |= CMD_SET_RTYP_6B; break; + case MMC_RSP_R1B: + tmp |= CMD_SET_RBSY | CMD_SET_RTYP_6B; + break; case MMC_RSP_R2: tmp |= CMD_SET_RTYP_17B; break; @@ -830,17 +832,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, dev_err(dev, "Unsupported response type.\n"); break; } - switch (opc) { - /* RBSY */ - case MMC_SLEEP_AWAKE: - case MMC_SWITCH: - case MMC_STOP_TRANSMISSION: - case MMC_SET_WRITE_PROT: - case MMC_CLR_WRITE_PROT: - case MMC_ERASE: - tmp |= CMD_SET_RBSY; - break; - } + /* WDAT / DATW */ if (data) { tmp |= CMD_SET_WDAT; @@ -925,23 +917,13 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, { struct mmc_command *cmd = mrq->cmd; u32 opc = cmd->opcode; - u32 mask; + u32 mask = 0; unsigned long flags; - switch (opc) { - /* response busy check */ - case MMC_SLEEP_AWAKE: - case MMC_SWITCH: - case MMC_STOP_TRANSMISSION: - case MMC_SET_WRITE_PROT: - case MMC_CLR_WRITE_PROT: - case MMC_ERASE: + if (cmd->flags & MMC_RSP_BUSY) mask = MASK_START_CMD | MASK_MRBSYE; - break; - default: + else mask = MASK_START_CMD | MASK_MCRSPE; - break; - } if (host->ccs_enable) mask |= MASK_MCCSTO; @@ -1009,22 +991,6 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) host->state = STATE_REQUEST; spin_unlock_irqrestore(&host->lock, flags); - switch (mrq->cmd->opcode) { - /* MMCIF does not support SD/SDIO command */ - case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */ - case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ - if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR) - break; - case MMC_APP_CMD: - case SD_IO_RW_DIRECT: - host->state = STATE_IDLE; - mrq->cmd->error = -ETIMEDOUT; - mmc_request_done(mmc, mrq); - return; - default: - break; - } - host->mrq = mrq; sh_mmcif_start_cmd(host, mrq); @@ -1488,6 +1454,9 @@ static int sh_mmcif_probe(struct platform_device *pdev) sh_mmcif_init_ocr(host); mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY; + mmc->caps2 |= MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; + mmc->max_busy_timeout = 10000; + if (pd && pd->caps) mmc->caps |= pd->caps; mmc->max_segs = 32; diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index f750f9494..c3b651bf8 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -39,6 +39,12 @@ #define EXT_ACC 0xe4 +#define SDHI_VER_GEN2_SDR50 0x490c +/* very old datasheets said 0x490c for SDR104, too. They are wrong! */ +#define SDHI_VER_GEN2_SDR104 0xcb0d +#define SDHI_VER_GEN3_SD 0xcc10 +#define SDHI_VER_GEN3_SDMMC 0xcd10 + #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) struct sh_mobile_sdhi_of_data { @@ -109,14 +115,14 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) * sh_mobile_sdhi_of_data :: dma_buswidth */ switch (sd_ctrl_read16(host, CTL_VERSION)) { - case 0x490C: + case SDHI_VER_GEN2_SDR50: val = (width == 32) ? 0x0001 : 0x0000; break; - case 0xCB0D: + case SDHI_VER_GEN2_SDR104: val = (width == 32) ? 0x0000 : 0x0001; break; - case 0xCC10: /* Gen3, SD only */ - case 0xCD10: /* Gen3, SD + MMC */ + case SDHI_VER_GEN3_SD: + case SDHI_VER_GEN3_SDMMC: if (width == 64) val = 0x0000; else if (width == 32) diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 1aac2ad8e..7f63ec05b 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -259,7 +259,7 @@ static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host, int addr, u32 val) { - writew(val, host->ctl + (addr << host->bus_shift)); + writew(val & 0xffff, host->ctl + (addr << host->bus_shift)); writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); } diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index f44e2ab7a..92467efc4 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -1086,7 +1086,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || mmc->caps & MMC_CAP_NEEDS_POLL || - mmc->caps & MMC_CAP_NONREMOVABLE || + !mmc_card_is_removable(mmc) || mmc->slot.cd_irq >= 0); if (tmio_mmc_clk_enable(_host) < 0) { |