diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-05 13:23:24 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-05 13:23:24 -0700 |
| commit | 8f7be6291529011a58856bf178f52ed5751c68ac (patch) | |
| tree | ab0e58a5ff58e6c713e7abfa97c815be1bcc44e4 /drivers/mmc | |
| parent | 9aebd3254c184fb6c731548b8347193bf882b6f7 (diff) | |
| parent | 7f4bc2e8687ecea52177aac30fb153cc076f7022 (diff) | |
| download | linux-8f7be6291529011a58856bf178f52ed5751c68ac.tar.gz linux-8f7be6291529011a58856bf178f52ed5751c68ac.tar.bz2 linux-8f7be6291529011a58856bf178f52ed5751c68ac.zip | |
Merge tag 'mmc-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Add a new host cap bit and a corresponding DT property, to support
power cycling of the card by FW at system suspend/resume.
- Fix clock rate setting for SDIO in SDR12/SDR25 speed-mode
- Fix switch to 1/4-bit mode at system suspend/resume for SD-combo
cards
- Convert the mmc-pwrseq DT bindings to the json-schema
- Always allow the card detect uevent to be consumed by userspace
MMC host controllers:
- Convert a few DT bindings to the json-schema
- mtk-sd:
- Add support for command queue through cqhci
- Add support for the MT6779 variant
- renesas_sdhi_internal_dmac:
- Fix dma unmapping in the error path
- sdhci_am654:
- Add support for the AM65x PG2.0 variant
- Extend support for phys/clocks
- sdhci-cadence:
- Drop incorrect HW tuning for SD mode
- sdhci-msm:
- Add support for interconnect bandwidth scaling
- Enable internal voltage control
- Enable low power state for pinctrls
- sdhci-of-at91:
- Ludovic Desroches handovers maintenance to Eugen Hristev
- sdhci-pci-gli:
- Improve clock handling for GL975x
- sdhci-pci-o2micro:
- Add HW tuning for SDR104 mode
- Fix support for O2 host controller Seabird1"
* tag 'mmc-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (66 commits)
mmc: mediatek: make function msdc_cqe_disable() static
MAINTAINERS: mmc: sdhci-of-at91: handover maintenance to Eugen Hristev
dt-bindings: mmc: mediatek: Add document for mt6779
mmc: mediatek: command queue support
mmc: mediatek: refine msdc timeout api
mmc: mediatek: add MT6779 MMC driver support
mmc: sdhci-pci-o2micro: Add HW tuning for SDR104 mode
mmc: sdhci-pci-o2micro: Bug fix for O2 host controller Seabird1
mmc: via-sdmmc: use generic power management
memstick: jmb38x_ms: use generic power management
mmc: sdhci-cadence: do not use hardware tuning for SD mode
mmc: sdhci-pci-gli: Set SDR104's clock to 205MHz and enable SSC for GL975x
mmc: cqhci: Fix a print format for the task descriptor
mmc: sdhci-of-arasan: fix timings allocation code
mmc: sdhci: Fix a potential uninitialized variable
dt-bindings: mmc: renesas,sdhi: convert to YAML
dt-bindings: mmc: convert arasan sdhci bindings to yaml
mmc: sdhci: Fix potential null pointer access while accessing vqmmc
mmc: core: Add MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND
dt-bindings: mmc: Add full-pwr-cycle-in-suspend property
...
Diffstat (limited to 'drivers/mmc')
34 files changed, 968 insertions, 209 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8d2b808e9b58..8ccae6452b9c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1455,12 +1455,12 @@ void mmc_detach_bus(struct mmc_host *host) void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq) { /* - * If the device is configured as wakeup, we prevent a new sleep for - * 5 s to give provision for user space to consume the event. + * Prevent system sleep for 5s to allow user space to consume the + * corresponding uevent. This is especially useful, when CD irq is used + * as a system wakeup, but doesn't hurt in other cases. */ - if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) && - device_can_wakeup(mmc_dev(host))) - pm_wakeup_event(mmc_dev(host), 5000); + if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL)) + __pm_wakeup_event(host->ws, 5000); host->detect_change = 1; mmc_schedule_delayed_work(&host->detect, delay); @@ -2303,7 +2303,6 @@ void mmc_start_host(struct mmc_host *host) { host->f_init = max(min(freqs[0], host->f_max), host->f_min); host->rescan_disable = 0; - host->ios.power_mode = MMC_POWER_UNDEFINED; if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) { mmc_claim_host(host); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index c8768726d925..ce43f7573d80 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -15,6 +15,7 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/pagemap.h> +#include <linux/pm_wakeup.h> #include <linux/export.h> #include <linux/leds.h> #include <linux/slab.h> @@ -36,6 +37,7 @@ static DEFINE_IDA(mmc_host_ida); static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); + wakeup_source_unregister(host->ws); ida_simple_remove(&mmc_host_ida, host->index); kfree(host); } @@ -275,6 +277,8 @@ int mmc_of_parse(struct mmc_host *host) host->caps |= MMC_CAP_SDIO_IRQ; if (device_property_read_bool(dev, "full-pwr-cycle")) host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; + if (device_property_read_bool(dev, "full-pwr-cycle-in-suspend")) + host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND; if (device_property_read_bool(dev, "keep-power-in-suspend")) host->pm_caps |= MMC_PM_KEEP_POWER; if (device_property_read_bool(dev, "wakeup-source") || @@ -400,6 +404,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->index = err; dev_set_name(&host->class_dev, "mmc%d", host->index); + host->ws = wakeup_source_register(NULL, dev_name(&host->class_dev)); host->parent = dev; host->class_dev.parent = dev; @@ -431,6 +436,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->fixed_drv_type = -EINVAL; host->ios.power_delay_ms = 10; + host->ios.power_mode = MMC_POWER_UNDEFINED; return host; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4203303f946a..b3fa193de846 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2038,7 +2038,8 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) goto out; if (mmc_can_poweroff_notify(host->card) && - ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend)) + ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend || + (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND))) err = mmc_poweroff_notify(host->card, notify_type); else if (mmc_can_sleep(host->card)) err = mmc_sleep(host); diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 4b1eb89b401d..6c022ef0f84d 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -203,7 +203,7 @@ static unsigned int mmc_get_max_segments(struct mmc_host *host) /** * mmc_init_request() - initialize the MMC-specific per-request data - * @q: the request queue + * @mq: the request queue * @req: the request * @gfp: memory allocation policy */ diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 472fa2fdcf13..d68e6e513a4f 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -14,7 +14,7 @@ #include "card.h" -static const struct mmc_fixup mmc_blk_fixups[] = { +static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = { #define INAND_CMD38_ARG_EXT_CSD 113 #define INAND_CMD38_ARG_ERASE 0x00 #define INAND_CMD38_ARG_TRIM 0x01 @@ -102,7 +102,7 @@ static const struct mmc_fixup mmc_blk_fixups[] = { END_FIXUP }; -static const struct mmc_fixup mmc_ext_csd_fixups[] = { +static const struct mmc_fixup __maybe_unused mmc_ext_csd_fixups[] = { /* * Certain Hynix eMMC 4.41 cards might get broken when HPI feature * is used so disable the HPI feature for such buggy cards. @@ -120,7 +120,7 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = { }; -static const struct mmc_fixup sdio_fixup_methods[] = { +static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c index 96b1d15045d6..609201a467ef 100644 --- a/drivers/mmc/core/regulator.c +++ b/drivers/mmc/core/regulator.c @@ -159,6 +159,8 @@ static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator, /** * mmc_regulator_set_vqmmc - Set VQMMC as per the ios + * @mmc: the host to regulate + * @ios: io bus settings * * For 3.3V signaling, we try to match VQMMC to VMMC as closely as possible. * That will match the behavior of old boards where VQMMC and VMMC were supplied diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index b65b26f76d71..7b40553d3934 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -176,15 +176,18 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr) if (mmc_host_uhs(card->host)) { if (data & SDIO_UHS_DDR50) card->sw_caps.sd3_bus_mode - |= SD_MODE_UHS_DDR50; + |= SD_MODE_UHS_DDR50 | SD_MODE_UHS_SDR50 + | SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12; if (data & SDIO_UHS_SDR50) card->sw_caps.sd3_bus_mode - |= SD_MODE_UHS_SDR50; + |= SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR25 + | SD_MODE_UHS_SDR12; if (data & SDIO_UHS_SDR104) card->sw_caps.sd3_bus_mode - |= SD_MODE_UHS_SDR104; + |= SD_MODE_UHS_SDR104 | SD_MODE_UHS_SDR50 + | SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12; } ret = mmc_io_rw_direct(card, 0, 0, @@ -303,30 +306,49 @@ static int sdio_disable_wide(struct mmc_card *card) return 0; } +static int sdio_disable_4bit_bus(struct mmc_card *card) +{ + int err; + + if (card->type == MMC_TYPE_SDIO) + goto out; + + if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) + return 0; + + if (!(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) + return 0; + + err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1); + if (err) + return err; + +out: + return sdio_disable_wide(card); +} + static int sdio_enable_4bit_bus(struct mmc_card *card) { int err; + err = sdio_enable_wide(card); + if (err <= 0) + return err; if (card->type == MMC_TYPE_SDIO) - err = sdio_enable_wide(card); - else if ((card->host->caps & MMC_CAP_4_BIT_DATA) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + goto out; + + if (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) { err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); - if (err) + if (err) { + sdio_disable_wide(card); return err; - err = sdio_enable_wide(card); - if (err <= 0) - mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1); - } else - return 0; - - if (err > 0) { - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - err = 0; + } } +out: + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - return err; + return 0; } @@ -518,10 +540,8 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) max_rate = min_not_zero(card->quirk_max_rate, card->sw_caps.uhs_max_dtr); - if (bus_speed) { - mmc_set_timing(card->host, timing); - mmc_set_clock(card->host, max_rate); - } + mmc_set_timing(card->host, timing); + mmc_set_clock(card->host, max_rate); return 0; } @@ -972,7 +992,7 @@ static int mmc_sdio_suspend(struct mmc_host *host) mmc_claim_host(host); if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) - sdio_disable_wide(host->card); + sdio_disable_4bit_bus(host->card); if (!mmc_card_keep_power(host)) { mmc_power_off(host); diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 2ba00acf64e6..79dbf90216b5 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -133,7 +133,7 @@ int sdio_disable_func(struct sdio_func *func) err: pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func)); - return -EIO; + return ret; } EXPORT_SYMBOL_GPL(sdio_disable_func); @@ -709,6 +709,7 @@ EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps); /** * sdio_set_host_pm_flags - set wanted host power management capabilities * @func: SDIO function attached to host + * @flags: Power Management flags to set * * Set a capability bitmask corresponding to wanted host controller * power management features for the upcoming suspend state. diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 3b706af35ec3..9c89a5b780e8 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -1009,6 +1009,7 @@ config MMC_MTK tristate "MediaTek SD/MMC Card Interface support" depends on HAS_DMA select REGULATOR + select MMC_CQHCI help This selects the MediaTek(R) Secure digital and Multimedia card Interface. If you have a machine with a integrated SD/MMC card reader, say Y or M here. diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 5cb692687698..300901415aa2 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -225,12 +225,13 @@ struct atmel_mci_dma { * @lock: Spinlock protecting the queue and associated data. * @regs: Pointer to MMIO registers. * @sg: Scatterlist entry currently being processed by PIO or PDC code. + * @sg_len: Size of the scatterlist * @pio_offset: Offset into the current scatterlist entry. * @buffer: Buffer used if we don't have the r/w proof capability. We * don't have the time to switch pdc buffers so we have to use only * one buffer for the full transaction. * @buf_size: size of the buffer. - * @phys_buf_addr: buffer address needed for pdc. + * @buf_phys_addr: buffer address needed for pdc. * @cur_slot: The slot which is currently using the controller. * @mrq: The request currently being processed on @cur_slot, * or NULL if the controller is idle. @@ -240,6 +241,7 @@ struct atmel_mci_dma { * @data_size: just data->blocks * data->blksz. * @dma: DMA client state. * @data_chan: DMA channel being used for the current data transfer. + * @dma_conf: Configuration for the DMA slave * @cmd_status: Snapshot of SR taken upon completion of the current * command. Only valid when EVENT_CMD_COMPLETE is pending. * @data_status: Snapshot of SR taken upon completion of the current diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c index 75934f3c117e..cfa87dfa73d8 100644 --- a/drivers/mmc/host/cqhci.c +++ b/drivers/mmc/host/cqhci.c @@ -144,7 +144,7 @@ static void cqhci_dumpregs(struct cqhci_host *cq_host) CQHCI_DUMP(": ===========================================\n"); } -/** +/* * The allocated descriptor table for task, link & transfer descritors * looks like: * |----------| @@ -422,7 +422,7 @@ static void cqhci_prep_task_desc(struct mmc_request *mrq, CQHCI_BLK_COUNT(mrq->data->blocks) | CQHCI_BLK_ADDR((u64)mrq->data->blk_addr); - pr_debug("%s: cqhci: tag %d task descriptor 0x016%llx\n", + pr_debug("%s: cqhci: tag %d task descriptor 0x%016llx\n", mmc_hostname(mrq->host), mrq->tag, (unsigned long long)*data); } diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 5e3d95b63676..95adeee07217 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -176,6 +176,7 @@ static int dw_mci_exynos_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP /** * dw_mci_exynos_suspend_noirq - Exynos-specific suspend code + * @dev: Device to suspend (this device) * * This ensures that device will be in runtime active state in * dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume() @@ -188,6 +189,7 @@ static int dw_mci_exynos_suspend_noirq(struct device *dev) /** * dw_mci_exynos_resume_noirq - Exynos-specific resume code + * @dev: Device to resume (this device) * * On exynos5420 there is a silicon errata that will sometimes leave the * WAKEUP_INT bit in the CLKSEL register asserted. This bit is 1 to indicate @@ -472,7 +474,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode) struct dw_mci_exynos_priv_data *priv = host->priv; struct mmc_host *mmc = slot->mmc; u8 start_smpl, smpl, candiates = 0; - s8 found = -1; + s8 found; int ret = 0; start_smpl = dw_mci_exynos_get_clksmpl(host); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index a69d6a0c2e15..b5a41a7ce165 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -267,6 +267,7 @@ static struct variant_data variant_stm32_sdmmc = { .datalength_bits = 25, .datactrl_blocksz = 14, .datactrl_any_blocksz = true, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .stm32_idmabsize_mask = GENMASK(12, 5), .busy_timeout = true, .busy_detect = true, @@ -292,6 +293,7 @@ static struct variant_data variant_stm32_sdmmcv2 = { .datalength_bits = 25, .datactrl_blocksz = 14, .datactrl_any_blocksz = true, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .stm32_idmabsize_mask = GENMASK(16, 5), .dma_lli = true, .busy_timeout = true, diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 39e7fc54c438..4e2583f69a63 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -31,6 +31,8 @@ #include <linux/mmc/sdio.h> #include <linux/mmc/slot-gpio.h> +#include "cqhci.h" + #define MAX_BD_NUM 1024 /*--------------------------------------------------------------------------*/ @@ -152,6 +154,7 @@ #define MSDC_INT_DMA_BDCSERR (0x1 << 17) /* W1C */ #define MSDC_INT_DMA_GPDCSERR (0x1 << 18) /* W1C */ #define MSDC_INT_DMA_PROTECT (0x1 << 19) /* W1C */ +#define MSDC_INT_CMDQ (0x1 << 28) /* W1C */ /* MSDC_INTEN mask */ #define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */ @@ -182,6 +185,7 @@ /* SDC_CFG mask */ #define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */ #define SDC_CFG_INSWKUP (0x1 << 1) /* RW */ +#define SDC_CFG_WRDTOC (0x1fff << 2) /* RW */ #define SDC_CFG_BUSWIDTH (0x3 << 16) /* RW */ #define SDC_CFG_SDIO (0x1 << 19) /* RW */ #define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */ @@ -230,6 +234,7 @@ #define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */ #define MSDC_PATCH_BIT1_CMDTA (0x7 << 3) /* RW */ +#define MSDC_PB1_BUSY_CHECK_SEL (0x1 << 7) /* RW */ #define MSDC_PATCH_BIT1_STOP_DLY (0xf << 8) /* RW */ #define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */ @@ -431,9 +436,11 @@ struct msdc_host { /* cmd response sample selection for HS400 */ bool hs400_mode; /* current eMMC will run at hs400 mode */ bool internal_cd; /* Use internal card-detect logic */ + bool cqhci; /* support eMMC hw cmdq */ 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 */ + struct cqhci_host *cq_host; }; static const struct mtk_mmc_compatible mt8135_compat = { @@ -538,6 +545,18 @@ static const struct mtk_mmc_compatible mt7620_compat = { .use_internal_cd = true, }; +static const struct mtk_mmc_compatible mt6779_compat = { + .clk_div_bits = 12, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, + .busy_check = true, + .stop_clk_fix = true, + .enhance_rx = true, + .support_64g = true, +}; + static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, @@ -547,6 +566,7 @@ static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, { .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat}, { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, + { .compatible = "mediatek,mt6779-mmc", .data = &mt6779_compat}, {} }; MODULE_DEVICE_TABLE(of, msdc_of_ids); @@ -710,21 +730,21 @@ static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq) } } -/* clock control primitives */ -static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) +static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks) { - u32 timeout, clk_ns; + u64 timeout, clk_ns; u32 mode = 0; - host->timeout_ns = ns; - host->timeout_clks = clks; if (host->mmc->actual_clock == 0) { timeout = 0; } else { - clk_ns = 1000000000UL / host->mmc->actual_clock; - timeout = (ns + clk_ns - 1) / clk_ns + clks; + clk_ns = 1000000000ULL; + do_div(clk_ns, host->mmc->actual_clock); + timeout = ns + clk_ns - 1; + do_div(timeout, clk_ns); + timeout += clks; /* in 1048576 sclk cycle unit */ - timeout = (timeout + (0x1 << 20) - 1) >> 20; + timeout = DIV_ROUND_UP(timeout, (0x1 << 20)); if (host->dev_comp->clk_div_bits == 8) sdr_get_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD, &mode); @@ -734,9 +754,30 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) /*DDR mode will double the clk cycles for data timeout */ timeout = mode >= 2 ? timeout * 2 : timeout; timeout = timeout > 1 ? timeout - 1 : 0; - timeout = timeout > 255 ? 255 : timeout; } - sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, timeout); + return timeout; +} + +/* clock control primitives */ +static void msdc_set_timeout(struct msdc_host *host, u64 ns, u64 clks) +{ + u64 timeout; + + host->timeout_ns = ns; + host->timeout_clks = clks; + + timeout = msdc_timeout_cal(host, ns, clks); + sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, + (u32)(timeout > 255 ? 255 : timeout)); +} + +static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks) +{ + u64 timeout; + + timeout = msdc_timeout_cal(host, ns, clks); + sdr_set_field(host->base + SDC_CFG, SDC_CFG_WRDTOC, + (u32)(timeout > 8191 ? 8191 : timeout)); } static void msdc_gate_clock(struct msdc_host *host) @@ -1018,13 +1059,12 @@ static int msdc_auto_cmd_done(struct msdc_host *host, int events, return cmd->error; } -/** +/* * msdc_recheck_sdio_irq - recheck whether the SDIO irq is lost * * Host controller may lost interrupt in some special case. * Add SDIO irq recheck mechanism to make sure all interrupts * can be processed immediately - * */ static void msdc_recheck_sdio_irq(struct msdc_host *host) { @@ -1456,6 +1496,34 @@ static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) pm_runtime_put_noidle(host->dev); } +static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts) +{ + int cmd_err = 0, dat_err = 0; + + if (intsts & MSDC_INT_RSPCRCERR) { + cmd_err = -EILSEQ; + dev_err(host->dev, "%s: CMD CRC ERR", __func__); + } else if (intsts & MSDC_INT_CMDTMO) { + cmd_err = -ETIMEDOUT; + dev_err(host->dev, "%s: CMD TIMEOUT ERR", __func__); + } + + if (intsts & MSDC_INT_DATCRCERR) { + dat_err = -EILSEQ; + dev_err(host->dev, "%s: DATA CRC ERR", __func__); + } else if (intsts & MSDC_INT_DATTMO) { + dat_err = -ETIMEDOUT; + dev_err(host->dev, "%s: DATA TIMEOUT ERR", __func__); + } + + if (cmd_err || dat_err) { + dev_err(host->dev, "cmd_err = %d, dat_err =%d, intsts = 0x%x", + cmd_err, dat_err, intsts); + } + + return cqhci_irq(host->mmc, 0, cmd_err, dat_err); +} + static irqreturn_t msdc_irq(int irq, void *dev_id) { struct msdc_host *host = (struct msdc_host *) dev_id; @@ -1492,6 +1560,14 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ))) break; + if ((host->mmc->caps2 & MMC_CAP2_CQE) && + (events & MSDC_INT_CMDQ)) { + msdc_cmdq_irq(host, events); + /* clear interrupts */ + writel(events, host->base + MSDC_INT); + return IRQ_HANDLED; + } + if (!mrq) { dev_err(host->dev, "%s: MRQ=NULL; events=%08X; event_mask=%08X\n", @@ -2176,6 +2252,36 @@ static int msdc_get_cd(struct mmc_host *mmc) return !val; } +static void msdc_cqe_enable(struct mmc_host *mmc) +{ + struct msdc_host *host = mmc_priv(mmc); + + /* enable cmdq irq */ + writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN); + /* enable busy check */ + sdr_set_bits(host->base + MSDC_PATCH_BIT1, MSDC_PB1_BUSY_CHECK_SEL); + /* default write data / busy timeout 20s */ + msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0); + /* default read data timeout 1s */ + msdc_set_timeout(host, 1000000000ULL, 0); +} + +static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery) +{ + struct msdc_host *host = mmc_priv(mmc); + + /* disable cmdq irq */ + sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INT_CMDQ); + /* disable busy check */ + sdr_clr_bits(host->base + MSDC_PATCH_BIT1, MSDC_PB1_BUSY_CHECK_SEL); + + if (recovery) { + sdr_set_field(host->base + MSDC_DMA_CTRL, + MSDC_DMA_CTRL_STOP, 1); + msdc_reset_hw(host); + } +} + static const struct mmc_host_ops mt_msdc_ops = { .post_req = msdc_post_req, .pre_req = msdc_pre_req, @@ -2192,6 +2298,11 @@ static const struct mmc_host_ops mt_msdc_ops = { .hw_reset = msdc_hw_reset, }; +static const struct cqhci_host_ops msdc_cmdq_ops = { + .enable = msdc_cqe_enable, + .disable = msdc_cqe_disable, +}; + static void msdc_of_property_parse(struct platform_device *pdev, struct msdc_host *host) { @@ -2212,6 +2323,12 @@ static void msdc_of_property_parse(struct platform_device *pdev, host->hs400_cmd_resp_sel_rising = true; else host->hs400_cmd_resp_sel_rising = false; + + if (of_property_read_bool(pdev->dev.of_node, + "supports-cqe")) + host->cqhci = true; + else + host->cqhci = false; } static int msdc_drv_probe(struct platform_device *pdev) @@ -2327,6 +2444,8 @@ static int msdc_drv_probe(struct platform_device *pdev) mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; mmc->caps |= MMC_CAP_CMD23; + if (host->cqhci) + mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; /* MMC core transfer sizes tunable parameters */ mmc->max_segs = MAX_BD_NUM; if (host->dev_comp->support_64g) @@ -2342,6 +2461,26 @@ static int msdc_drv_probe(struct platform_device *pdev) host->dma_mask = DMA_BIT_MASK(32); mmc_dev(mmc)->dma_mask = &host->dma_mask; + if (mmc->caps2 & MMC_CAP2_CQE) { + host->cq_host = devm_kzalloc(host->mmc->parent, + sizeof(*host->cq_host), + GFP_KERNEL); + if (!host->cq_host) { + ret = -ENOMEM; |
