Loading Documentation/devicetree/bindings/mmc/sdhci-omap.txt +7 −0 Original line number Diff line number Diff line Loading @@ -4,7 +4,14 @@ Refer to mmc.txt for standard MMC bindings. Required properties: - compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers Should be "ti,k2g-sdhci" for K2G - ti,hwmods: Must be "mmc<n>", <n> is controller instance starting 1 (Not required for K2G). - pinctrl-names: Should be subset of "default", "hs", "sdr12", "sdr25", "sdr50", "ddr50-rev11", "sdr104-rev11", "ddr50", "sdr104", "ddr_1_8v-rev11", "ddr_1_8v" or "ddr_3_3v", "hs200_1_8v-rev11", "hs200_1_8v", - pinctrl-<n> : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt Example: mmc1: mmc@4809c000 { Loading drivers/mmc/host/sdhci-omap.c +81 −11 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/pinctrl/consumer.h> #include <linux/sys_soc.h> #include "sdhci-pltfm.h" Loading @@ -35,6 +36,7 @@ #define CON_DDR BIT(19) #define CON_CLKEXTFREE BIT(16) #define CON_PADEN BIT(15) #define CON_CTPL BIT(11) #define CON_INIT BIT(1) #define CON_OD BIT(0) Loading Loading @@ -100,6 +102,7 @@ struct sdhci_omap_data { }; struct sdhci_omap_host { char *version; void __iomem *base; struct device *dev; struct regulator *pbias; Loading Loading @@ -224,6 +227,23 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host, } } static void sdhci_omap_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sdhci_host *host = mmc_priv(mmc); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); u32 reg; reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); if (enable) reg |= (CON_CTPL | CON_CLKEXTFREE); else reg &= ~(CON_CTPL | CON_CLKEXTFREE); sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); sdhci_enable_sdio_irq(mmc, enable); } static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host, int count) { Loading Loading @@ -713,10 +733,15 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = { SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_RSP_136_HAS_CRC, SDHCI_QUIRK2_RSP_136_HAS_CRC | SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, .ops = &sdhci_omap_ops, }; static const struct sdhci_omap_data k2g_data = { .offset = 0x200, }; static const struct sdhci_omap_data dra7_data = { .offset = 0x200, .flags = SDHCI_OMAP_REQUIRE_IODELAY, Loading @@ -724,6 +749,7 @@ static const struct sdhci_omap_data dra7_data = { static const struct of_device_id omap_sdhci_match[] = { { .compatible = "ti,dra7-sdhci", .data = &dra7_data }, { .compatible = "ti,k2g-sdhci", .data = &k2g_data }, {}, }; MODULE_DEVICE_TABLE(of, omap_sdhci_match); Loading @@ -733,12 +759,21 @@ static struct pinctrl_state u32 *caps, u32 capmask) { struct device *dev = omap_host->dev; char *version = omap_host->version; struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV); char str[20]; if (!(*caps & capmask)) goto ret; if (version) { snprintf(str, 20, "%s-%s", mode, version); pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, str); } if (IS_ERR(pinctrl_state)) pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode); if (IS_ERR(pinctrl_state)) { dev_err(dev, "no pinctrl state for %s mode", mode); *caps &= ~capmask; Loading Loading @@ -807,8 +842,15 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps, MMC_CAP_1_8V_DDR); if (!IS_ERR(state)) { pinctrl_state[MMC_TIMING_MMC_DDR52] = state; } else { state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_3_3v", caps, MMC_CAP_3_3V_DDR); if (!IS_ERR(state)) pinctrl_state[MMC_TIMING_MMC_DDR52] = state; } state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, MMC_CAP_SD_HIGHSPEED); Loading @@ -830,6 +872,16 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host return 0; } static const struct soc_device_attribute sdhci_omap_soc_devices[] = { { .machine = "DRA7[45]*", .revision = "ES1.[01]", }, { /* sentinel */ } }; static int sdhci_omap_probe(struct platform_device *pdev) { int ret; Loading @@ -841,6 +893,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) struct mmc_host *mmc; const struct of_device_id *match; struct sdhci_omap_data *data; const struct soc_device_attribute *soc; match = of_match_device(omap_sdhci_match, dev); if (!match) Loading Loading @@ -871,10 +924,22 @@ static int sdhci_omap_probe(struct platform_device *pdev) host->ioaddr += offset; mmc = host->mmc; sdhci_get_of_property(pdev); ret = mmc_of_parse(mmc); if (ret) goto err_pltfm_free; soc = soc_device_match(sdhci_omap_soc_devices); if (soc) { omap_host->version = "rev11"; if (!strcmp(dev_name(dev), "4809c000.mmc")) mmc->f_max = 96000000; if (!strcmp(dev_name(dev), "480b4000.mmc")) mmc->f_max = 48000000; if (!strcmp(dev_name(dev), "480ad000.mmc")) mmc->f_max = 48000000; } pltfm_host->clk = devm_clk_get(dev, "fck"); if (IS_ERR(pltfm_host->clk)) { ret = PTR_ERR(pltfm_host->clk); Loading Loading @@ -916,26 +981,31 @@ static int sdhci_omap_probe(struct platform_device *pdev) goto err_put_sync; } ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); if (ret) goto err_put_sync; host->mmc_host_ops.get_ro = mmc_gpio_get_ro; host->mmc_host_ops.start_signal_voltage_switch = sdhci_omap_start_signal_voltage_switch; host->mmc_host_ops.set_ios = sdhci_omap_set_ios; host->mmc_host_ops.card_busy = sdhci_omap_card_busy; host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning; host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq; sdhci_read_caps(host); host->caps |= SDHCI_CAN_DO_ADMA2; ret = sdhci_add_host(host); ret = sdhci_setup_host(host); if (ret) goto err_put_sync; ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); if (ret) goto err_cleanup_host; ret = __sdhci_add_host(host); if (ret) goto err_cleanup_host; return 0; err_cleanup_host: sdhci_cleanup_host(host); err_put_sync: pm_runtime_put_sync(dev); Loading drivers/mmc/host/sdhci.c +119 −29 Original line number Diff line number Diff line Loading @@ -709,29 +709,16 @@ static u32 sdhci_sdma_address(struct sdhci_host *host) return sg_dma_address(host->data->sg); } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) static unsigned int sdhci_target_timeout(struct sdhci_host *host, struct mmc_command *cmd, struct mmc_data *data) { u8 count; struct mmc_data *data = cmd->data; unsigned target_timeout, current_timeout; /* * If the host controller provides us with an incorrect timeout * value, just skip the check and use 0xE. The hardware may take * longer to time out, but that's much better than having a too-short * timeout value. */ if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return 0xE; /* Unspecified timeout, assume max */ if (!data && !cmd->busy_timeout) return 0xE; unsigned int target_timeout; /* timeout in us */ if (!data) if (!data) { target_timeout = cmd->busy_timeout * 1000; else { } else { target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000); if (host->clock && data->timeout_clks) { unsigned long long val; Loading @@ -748,6 +735,67 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } } return target_timeout; } static void sdhci_calc_sw_timeout(struct sdhci_host *host, struct mmc_command *cmd) { struct mmc_data *data = cmd->data; struct mmc_host *mmc = host->mmc; struct mmc_ios *ios = &mmc->ios; unsigned char bus_width = 1 << ios->bus_width; unsigned int blksz; unsigned int freq; u64 target_timeout; u64 transfer_time; target_timeout = sdhci_target_timeout(host, cmd, data); target_timeout *= NSEC_PER_USEC; if (data) { blksz = data->blksz; freq = host->mmc->actual_clock ? : host->clock; transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width); do_div(transfer_time, freq); /* multiply by '2' to account for any unknowns */ transfer_time = transfer_time * 2; /* calculate timeout for the entire data */ host->data_timeout = data->blocks * target_timeout + transfer_time; } else { host->data_timeout = target_timeout; } if (host->data_timeout) host->data_timeout += MMC_CMD_TRANSFER_TIME; } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, bool *too_big) { u8 count; struct mmc_data *data = cmd->data; unsigned target_timeout, current_timeout; *too_big = true; /* * If the host controller provides us with an incorrect timeout * value, just skip the check and use 0xE. The hardware may take * longer to time out, but that's much better than having a too-short * timeout value. */ if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return 0xE; /* Unspecified timeout, assume max */ if (!data && !cmd->busy_timeout) return 0xE; /* timeout in us */ target_timeout = sdhci_target_timeout(host, cmd, data); /* * Figure out needed cycles. * We do this in steps in order to fit inside a 32 bit int. Loading @@ -768,9 +816,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT)) DBG("Too large timeout 0x%x requested for CMD%d!\n", count, cmd->opcode); count = 0xE; } else { *too_big = false; } return count; Loading @@ -790,6 +841,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable) { if (enable) host->ier |= SDHCI_INT_DATA_TIMEOUT; else host->ier &= ~SDHCI_INT_DATA_TIMEOUT; sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) { u8 count; Loading @@ -797,7 +858,18 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) if (host->ops->set_timeout) { host->ops->set_timeout(host, cmd); } else { count = sdhci_calc_timeout(host, cmd); bool too_big = false; count = sdhci_calc_timeout(host, cmd, &too_big); if (too_big && host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) { sdhci_calc_sw_timeout(host, cmd); sdhci_set_data_timeout_irq(host, false); } else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) { sdhci_set_data_timeout_irq(host, true); } sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL); } } Loading @@ -807,6 +879,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) u8 ctrl; struct mmc_data *data = cmd->data; host->data_timeout = 0; if (sdhci_data_line_cmd(cmd)) sdhci_set_timeout(host, cmd); Loading Loading @@ -1160,13 +1234,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mdelay(1); } timeout = jiffies; if (!cmd->data && cmd->busy_timeout > 9000) timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; else timeout += 10 * HZ; sdhci_mod_timer(host, cmd->mrq, timeout); host->cmd = cmd; if (sdhci_data_line_cmd(cmd)) { WARN_ON(host->data_cmd); Loading Loading @@ -1206,6 +1273,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) flags |= SDHCI_CMD_DATA; timeout = jiffies; if (host->data_timeout) timeout += nsecs_to_jiffies(host->data_timeout); else if (!cmd->data && cmd->busy_timeout > 9000) timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; else timeout += 10 * HZ; sdhci_mod_timer(host, cmd->mrq, timeout); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } EXPORT_SYMBOL_GPL(sdhci_send_command); Loading Loading @@ -3616,6 +3692,10 @@ int sdhci_setup_host(struct sdhci_host *host) mmc->max_busy_timeout /= host->timeout_clk; } if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT && !host->ops->get_max_timeout_count) mmc->max_busy_timeout = 0; mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; Loading Loading @@ -3672,6 +3752,16 @@ int sdhci_setup_host(struct sdhci_host *host) if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) { host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); /* * The SDHCI controller in a SoC might support HS200/HS400 * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property), * but if the board is modeled such that the IO lines are not * connected to 1.8v then HS200/HS400 cannot be supported. * Disable HS200/HS400 if the board does not have 1.8v connected * to the IO lines. (Applicable for other modes in 1.8v) */ mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES); mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS); } /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ Loading drivers/mmc/host/sdhci.h +15 −0 Original line number Diff line number Diff line Loading @@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc { /* Allow for a a command request and a data request at the same time */ #define SDHCI_MAX_MRQS 2 /* * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms. * However since the start time of the command, the time between * command and response, and the time between response and start of data is * not known, set the command transfer time to 10ms. */ #define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */ enum sdhci_cookie { COOKIE_UNMAPPED, COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ Loading Loading @@ -437,6 +445,11 @@ struct sdhci_host { #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) /* Controller has CRC in 136 bit Command Response */ #define SDHCI_QUIRK2_RSP_136_HAS_CRC (1<<16) /* * Disable HW timeout if the requested timeout is more than the maximum * obtainable timeout. */ #define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ Loading Loading @@ -550,6 +563,8 @@ struct sdhci_host { /* Host SDMA buffer boundary. */ u32 sdma_boundary; u64 data_timeout; unsigned long private[0] ____cacheline_aligned; }; Loading include/linux/mmc/host.h +4 −0 Original line number Diff line number Diff line Loading @@ -320,6 +320,9 @@ struct mmc_host { #define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */ #define MMC_CAP_UHS_SDR104 (1 << 19) /* Host supports UHS SDR104 mode */ #define MMC_CAP_UHS_DDR50 (1 << 20) /* Host supports UHS DDR50 mode */ #define MMC_CAP_UHS (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | \ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | \ MMC_CAP_UHS_DDR50) /* (1 << 21) is free for reuse */ #define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */ #define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */ Loading @@ -345,6 +348,7 @@ struct mmc_host { #define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */ #define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \ MMC_CAP2_HS400_1_2V) #define MMC_CAP2_HSX00_1_8V (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V) #define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V) #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17) #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18) /* No physical write protect pin, assume that card is always read-write */ Loading Loading
Documentation/devicetree/bindings/mmc/sdhci-omap.txt +7 −0 Original line number Diff line number Diff line Loading @@ -4,7 +4,14 @@ Refer to mmc.txt for standard MMC bindings. Required properties: - compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers Should be "ti,k2g-sdhci" for K2G - ti,hwmods: Must be "mmc<n>", <n> is controller instance starting 1 (Not required for K2G). - pinctrl-names: Should be subset of "default", "hs", "sdr12", "sdr25", "sdr50", "ddr50-rev11", "sdr104-rev11", "ddr50", "sdr104", "ddr_1_8v-rev11", "ddr_1_8v" or "ddr_3_3v", "hs200_1_8v-rev11", "hs200_1_8v", - pinctrl-<n> : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt Example: mmc1: mmc@4809c000 { Loading
drivers/mmc/host/sdhci-omap.c +81 −11 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/pinctrl/consumer.h> #include <linux/sys_soc.h> #include "sdhci-pltfm.h" Loading @@ -35,6 +36,7 @@ #define CON_DDR BIT(19) #define CON_CLKEXTFREE BIT(16) #define CON_PADEN BIT(15) #define CON_CTPL BIT(11) #define CON_INIT BIT(1) #define CON_OD BIT(0) Loading Loading @@ -100,6 +102,7 @@ struct sdhci_omap_data { }; struct sdhci_omap_host { char *version; void __iomem *base; struct device *dev; struct regulator *pbias; Loading Loading @@ -224,6 +227,23 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host, } } static void sdhci_omap_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sdhci_host *host = mmc_priv(mmc); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); u32 reg; reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); if (enable) reg |= (CON_CTPL | CON_CLKEXTFREE); else reg &= ~(CON_CTPL | CON_CLKEXTFREE); sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); sdhci_enable_sdio_irq(mmc, enable); } static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host, int count) { Loading Loading @@ -713,10 +733,15 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = { SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_RSP_136_HAS_CRC, SDHCI_QUIRK2_RSP_136_HAS_CRC | SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, .ops = &sdhci_omap_ops, }; static const struct sdhci_omap_data k2g_data = { .offset = 0x200, }; static const struct sdhci_omap_data dra7_data = { .offset = 0x200, .flags = SDHCI_OMAP_REQUIRE_IODELAY, Loading @@ -724,6 +749,7 @@ static const struct sdhci_omap_data dra7_data = { static const struct of_device_id omap_sdhci_match[] = { { .compatible = "ti,dra7-sdhci", .data = &dra7_data }, { .compatible = "ti,k2g-sdhci", .data = &k2g_data }, {}, }; MODULE_DEVICE_TABLE(of, omap_sdhci_match); Loading @@ -733,12 +759,21 @@ static struct pinctrl_state u32 *caps, u32 capmask) { struct device *dev = omap_host->dev; char *version = omap_host->version; struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV); char str[20]; if (!(*caps & capmask)) goto ret; if (version) { snprintf(str, 20, "%s-%s", mode, version); pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, str); } if (IS_ERR(pinctrl_state)) pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode); if (IS_ERR(pinctrl_state)) { dev_err(dev, "no pinctrl state for %s mode", mode); *caps &= ~capmask; Loading Loading @@ -807,8 +842,15 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps, MMC_CAP_1_8V_DDR); if (!IS_ERR(state)) { pinctrl_state[MMC_TIMING_MMC_DDR52] = state; } else { state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_3_3v", caps, MMC_CAP_3_3V_DDR); if (!IS_ERR(state)) pinctrl_state[MMC_TIMING_MMC_DDR52] = state; } state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, MMC_CAP_SD_HIGHSPEED); Loading @@ -830,6 +872,16 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host return 0; } static const struct soc_device_attribute sdhci_omap_soc_devices[] = { { .machine = "DRA7[45]*", .revision = "ES1.[01]", }, { /* sentinel */ } }; static int sdhci_omap_probe(struct platform_device *pdev) { int ret; Loading @@ -841,6 +893,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) struct mmc_host *mmc; const struct of_device_id *match; struct sdhci_omap_data *data; const struct soc_device_attribute *soc; match = of_match_device(omap_sdhci_match, dev); if (!match) Loading Loading @@ -871,10 +924,22 @@ static int sdhci_omap_probe(struct platform_device *pdev) host->ioaddr += offset; mmc = host->mmc; sdhci_get_of_property(pdev); ret = mmc_of_parse(mmc); if (ret) goto err_pltfm_free; soc = soc_device_match(sdhci_omap_soc_devices); if (soc) { omap_host->version = "rev11"; if (!strcmp(dev_name(dev), "4809c000.mmc")) mmc->f_max = 96000000; if (!strcmp(dev_name(dev), "480b4000.mmc")) mmc->f_max = 48000000; if (!strcmp(dev_name(dev), "480ad000.mmc")) mmc->f_max = 48000000; } pltfm_host->clk = devm_clk_get(dev, "fck"); if (IS_ERR(pltfm_host->clk)) { ret = PTR_ERR(pltfm_host->clk); Loading Loading @@ -916,26 +981,31 @@ static int sdhci_omap_probe(struct platform_device *pdev) goto err_put_sync; } ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); if (ret) goto err_put_sync; host->mmc_host_ops.get_ro = mmc_gpio_get_ro; host->mmc_host_ops.start_signal_voltage_switch = sdhci_omap_start_signal_voltage_switch; host->mmc_host_ops.set_ios = sdhci_omap_set_ios; host->mmc_host_ops.card_busy = sdhci_omap_card_busy; host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning; host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq; sdhci_read_caps(host); host->caps |= SDHCI_CAN_DO_ADMA2; ret = sdhci_add_host(host); ret = sdhci_setup_host(host); if (ret) goto err_put_sync; ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); if (ret) goto err_cleanup_host; ret = __sdhci_add_host(host); if (ret) goto err_cleanup_host; return 0; err_cleanup_host: sdhci_cleanup_host(host); err_put_sync: pm_runtime_put_sync(dev); Loading
drivers/mmc/host/sdhci.c +119 −29 Original line number Diff line number Diff line Loading @@ -709,29 +709,16 @@ static u32 sdhci_sdma_address(struct sdhci_host *host) return sg_dma_address(host->data->sg); } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) static unsigned int sdhci_target_timeout(struct sdhci_host *host, struct mmc_command *cmd, struct mmc_data *data) { u8 count; struct mmc_data *data = cmd->data; unsigned target_timeout, current_timeout; /* * If the host controller provides us with an incorrect timeout * value, just skip the check and use 0xE. The hardware may take * longer to time out, but that's much better than having a too-short * timeout value. */ if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return 0xE; /* Unspecified timeout, assume max */ if (!data && !cmd->busy_timeout) return 0xE; unsigned int target_timeout; /* timeout in us */ if (!data) if (!data) { target_timeout = cmd->busy_timeout * 1000; else { } else { target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000); if (host->clock && data->timeout_clks) { unsigned long long val; Loading @@ -748,6 +735,67 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } } return target_timeout; } static void sdhci_calc_sw_timeout(struct sdhci_host *host, struct mmc_command *cmd) { struct mmc_data *data = cmd->data; struct mmc_host *mmc = host->mmc; struct mmc_ios *ios = &mmc->ios; unsigned char bus_width = 1 << ios->bus_width; unsigned int blksz; unsigned int freq; u64 target_timeout; u64 transfer_time; target_timeout = sdhci_target_timeout(host, cmd, data); target_timeout *= NSEC_PER_USEC; if (data) { blksz = data->blksz; freq = host->mmc->actual_clock ? : host->clock; transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width); do_div(transfer_time, freq); /* multiply by '2' to account for any unknowns */ transfer_time = transfer_time * 2; /* calculate timeout for the entire data */ host->data_timeout = data->blocks * target_timeout + transfer_time; } else { host->data_timeout = target_timeout; } if (host->data_timeout) host->data_timeout += MMC_CMD_TRANSFER_TIME; } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, bool *too_big) { u8 count; struct mmc_data *data = cmd->data; unsigned target_timeout, current_timeout; *too_big = true; /* * If the host controller provides us with an incorrect timeout * value, just skip the check and use 0xE. The hardware may take * longer to time out, but that's much better than having a too-short * timeout value. */ if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return 0xE; /* Unspecified timeout, assume max */ if (!data && !cmd->busy_timeout) return 0xE; /* timeout in us */ target_timeout = sdhci_target_timeout(host, cmd, data); /* * Figure out needed cycles. * We do this in steps in order to fit inside a 32 bit int. Loading @@ -768,9 +816,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT)) DBG("Too large timeout 0x%x requested for CMD%d!\n", count, cmd->opcode); count = 0xE; } else { *too_big = false; } return count; Loading @@ -790,6 +841,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable) { if (enable) host->ier |= SDHCI_INT_DATA_TIMEOUT; else host->ier &= ~SDHCI_INT_DATA_TIMEOUT; sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) { u8 count; Loading @@ -797,7 +858,18 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) if (host->ops->set_timeout) { host->ops->set_timeout(host, cmd); } else { count = sdhci_calc_timeout(host, cmd); bool too_big = false; count = sdhci_calc_timeout(host, cmd, &too_big); if (too_big && host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) { sdhci_calc_sw_timeout(host, cmd); sdhci_set_data_timeout_irq(host, false); } else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) { sdhci_set_data_timeout_irq(host, true); } sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL); } } Loading @@ -807,6 +879,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) u8 ctrl; struct mmc_data *data = cmd->data; host->data_timeout = 0; if (sdhci_data_line_cmd(cmd)) sdhci_set_timeout(host, cmd); Loading Loading @@ -1160,13 +1234,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mdelay(1); } timeout = jiffies; if (!cmd->data && cmd->busy_timeout > 9000) timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; else timeout += 10 * HZ; sdhci_mod_timer(host, cmd->mrq, timeout); host->cmd = cmd; if (sdhci_data_line_cmd(cmd)) { WARN_ON(host->data_cmd); Loading Loading @@ -1206,6 +1273,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) flags |= SDHCI_CMD_DATA; timeout = jiffies; if (host->data_timeout) timeout += nsecs_to_jiffies(host->data_timeout); else if (!cmd->data && cmd->busy_timeout > 9000) timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; else timeout += 10 * HZ; sdhci_mod_timer(host, cmd->mrq, timeout); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } EXPORT_SYMBOL_GPL(sdhci_send_command); Loading Loading @@ -3616,6 +3692,10 @@ int sdhci_setup_host(struct sdhci_host *host) mmc->max_busy_timeout /= host->timeout_clk; } if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT && !host->ops->get_max_timeout_count) mmc->max_busy_timeout = 0; mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; Loading Loading @@ -3672,6 +3752,16 @@ int sdhci_setup_host(struct sdhci_host *host) if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) { host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); /* * The SDHCI controller in a SoC might support HS200/HS400 * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property), * but if the board is modeled such that the IO lines are not * connected to 1.8v then HS200/HS400 cannot be supported. * Disable HS200/HS400 if the board does not have 1.8v connected * to the IO lines. (Applicable for other modes in 1.8v) */ mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES); mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS); } /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ Loading
drivers/mmc/host/sdhci.h +15 −0 Original line number Diff line number Diff line Loading @@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc { /* Allow for a a command request and a data request at the same time */ #define SDHCI_MAX_MRQS 2 /* * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms. * However since the start time of the command, the time between * command and response, and the time between response and start of data is * not known, set the command transfer time to 10ms. */ #define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */ enum sdhci_cookie { COOKIE_UNMAPPED, COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ Loading Loading @@ -437,6 +445,11 @@ struct sdhci_host { #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) /* Controller has CRC in 136 bit Command Response */ #define SDHCI_QUIRK2_RSP_136_HAS_CRC (1<<16) /* * Disable HW timeout if the requested timeout is more than the maximum * obtainable timeout. */ #define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ Loading Loading @@ -550,6 +563,8 @@ struct sdhci_host { /* Host SDMA buffer boundary. */ u32 sdma_boundary; u64 data_timeout; unsigned long private[0] ____cacheline_aligned; }; Loading
include/linux/mmc/host.h +4 −0 Original line number Diff line number Diff line Loading @@ -320,6 +320,9 @@ struct mmc_host { #define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */ #define MMC_CAP_UHS_SDR104 (1 << 19) /* Host supports UHS SDR104 mode */ #define MMC_CAP_UHS_DDR50 (1 << 20) /* Host supports UHS DDR50 mode */ #define MMC_CAP_UHS (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | \ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | \ MMC_CAP_UHS_DDR50) /* (1 << 21) is free for reuse */ #define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */ #define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */ Loading @@ -345,6 +348,7 @@ struct mmc_host { #define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */ #define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \ MMC_CAP2_HS400_1_2V) #define MMC_CAP2_HSX00_1_8V (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V) #define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V) #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17) #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18) /* No physical write protect pin, assume that card is always read-write */ Loading