diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-10-05 20:00:19 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-10-05 20:00:19 +0300 |
commit | c3f13bbfc2f0240743a4d03a8a890d03730f5a6d (patch) | |
tree | 6fcfe8f5aacd3da999ecbdab0df3a50f12370e93 | |
parent | ebcfaeeceaf1d60de48f0b3c17b057d54ef790e9 (diff) | |
parent | 178422c27badb8eee5edfae3f6cc3048cc140364 (diff) | |
download | linux-c3f13bbfc2f0240743a4d03a8a890d03730f5a6d.tar.xz |
Merge tag 'mmc-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
- dt-bindings: Increase maximum supported frequency to 384MHz
- dw_mmc-rockchip: Add support for the rk3128 variant
- meson-gx: Add support for SDIO interrupts
- mtk-sd: Add support for MT6795 Helio X10 variant
- sdhci: Improve the code by centralizing the CMD/DATA reset handling
- sdhci-msm:
- Add support for the sdm670 variant
- Add support for the sm6115 variant
- sdhci-omap: Make Vignesh replace Kishon as the maintainer
- sdhci-pci-o2micro: Disable fragile support for DDR50 in favor of
SDR50
- sdhci-sprd: Fix clock divider limitation
* tag 'mmc-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (31 commits)
mmc: sdhci: Centralize CMD and DATA reset handling
mmc: sdhci: Get rid of SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS
mmc: sdhci: Remove misleading comment about resets
mmc: sdhci: Separate out sdhci_reset_for_all()
MAINTAINERS: Add Vignesh as maintainer of TI SDHCI OMAP DRIVER
mmc: sdhci-msm: add compatible string check for sdm670
dt-bindings: mmc: sdhci-msm: add sdm670 compatible
mmc: wmt-sdmmc: Fix an error handling path in wmt_mci_probe()
mmc: rtsx_usb_sdmmc: Remove the unneeded result variable
mmc: sdhci-of-aspeed: Add dependency on ARCH_ASPEED
mmc: mtk-sd: Add support for MT6795 Helio X10
mmc: mtk-sd: Reorder of_device_id and platform data by name
mmc: sdhci-sprd: Fix the limitation of div
dt-bindings: mmc: sdhci-msm: Add pinctrl-1 property
dt-bindings: mmc: rockchip: add rockchip,rk3128-dw-mshc
dt-bindings: mmc: renesas,sdhi: Add iommus property
mmc: sdhci_am654: Remove the unneeded result variable
mmc: meson-gx: add SDIO interrupt support
mmc: meson-gx: adjust and re-use constant IRQ_EN_MASK
mmc: jz4740_mmc: Fix error check for dma_map_sg
...
28 files changed, 255 insertions, 136 deletions
diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml index 4207fed62dfe..8b1a0fdcb5e3 100644 --- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml @@ -8,7 +8,6 @@ title: Cadence SD/SDIO/eMMC Host Controller (SD4HC) maintainers: - Masahiro Yamada <yamada.masahiro@socionext.com> - - Piotr Sroka <piotrs@cadence.com> allOf: - $ref: mmc-controller.yaml diff --git a/Documentation/devicetree/bindings/mmc/mmc-controller.yaml b/Documentation/devicetree/bindings/mmc/mmc-controller.yaml index ff5ce89e5111..802e3ca8be4d 100644 --- a/Documentation/devicetree/bindings/mmc/mmc-controller.yaml +++ b/Documentation/devicetree/bindings/mmc/mmc-controller.yaml @@ -88,11 +88,18 @@ properties: default: 1 max-frequency: - description: - Maximum operating frequency of the bus. + description: | + Maximum operating frequency of the bus: + - for eMMC, the maximum supported frequency is 200MHz, + - for SD/SDIO cards the SDR104 mode has a max supported + frequency of 208MHz, + - some mmc host controllers do support a max frequency upto + 384MHz. + So, lets keep the maximum supported value here. + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 400000 - maximum: 200000000 + maximum: 384000000 disable-wp: $ref: /schemas/types.yaml#/definitions/flag diff --git a/Documentation/devicetree/bindings/mmc/mmc-spi-slot.yaml b/Documentation/devicetree/bindings/mmc/mmc-spi-slot.yaml index c45b91099325..c0662ce9946d 100644 --- a/Documentation/devicetree/bindings/mmc/mmc-spi-slot.yaml +++ b/Documentation/devicetree/bindings/mmc/mmc-spi-slot.yaml @@ -23,8 +23,6 @@ properties: reg: maxItems: 1 - spi-max-frequency: true - interrupts: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml index 083d1ec2f661..d8e1e2e9adf2 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml @@ -20,6 +20,7 @@ properties: - mediatek,mt2701-mmc - mediatek,mt2712-mmc - mediatek,mt6779-mmc + - mediatek,mt6795-mmc - mediatek,mt7620-mmc - mediatek,mt7622-mmc - mediatek,mt8135-mmc diff --git a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml index 14945ebc31d2..0424b06cb655 100644 --- a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml +++ b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml @@ -89,6 +89,9 @@ properties: - tx - rx + iommus: + maxItems: 1 + power-domains: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml index 8d888b435817..ccf0e3e93efa 100644 --- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml +++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml @@ -32,6 +32,7 @@ properties: - rockchip,px30-dw-mshc - rockchip,rk1808-dw-mshc - rockchip,rk3036-dw-mshc + - rockchip,rk3128-dw-mshc - rockchip,rk3228-dw-mshc - rockchip,rk3308-dw-mshc - rockchip,rk3328-dw-mshc diff --git a/Documentation/devicetree/bindings/mmc/sdhci-am654.yaml b/Documentation/devicetree/bindings/mmc/sdhci-am654.yaml index 0ab07759b472..ea9121fb188d 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-am654.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-am654.yaml @@ -51,6 +51,9 @@ properties: sdhci-caps-mask: true + dma-coherent: + type: boolean + # PHY output tap delays: # Used to delay the data valid window and align it to the sampling clock. # Binding needs to be provided for each supported speed mode otherwise the diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index fc0e81c2066c..a96f143479c7 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -38,9 +38,11 @@ properties: - qcom,sc7180-sdhci - qcom,sc7280-sdhci - qcom,sdm630-sdhci + - qcom,sdm670-sdhci - qcom,sdm845-sdhci - qcom,sdx55-sdhci - qcom,sdx65-sdhci + - qcom,sm6115-sdhci - qcom,sm6125-sdhci - qcom,sm6350-sdhci - qcom,sm8150-sdhci @@ -96,6 +98,10 @@ properties: description: Should specify pin control groups used for this controller. + pinctrl-1: + description: + Should specify sleep pin control groups used for this controller. + resets: maxItems: 1 diff --git a/MAINTAINERS b/MAINTAINERS index 8656ab794786..b2a88ff1596c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7536,7 +7536,7 @@ M: Adrian Hunter <adrian.hunter@intel.com> M: Ritesh Harjani <riteshh@codeaurora.org> M: Asutosh Das <asutoshd@codeaurora.org> L: linux-mmc@vger.kernel.org -S: Maintained +S: Supported F: drivers/mmc/host/cqhci* EMULEX 10Gbps iSCSI - OneConnect DRIVER @@ -18316,7 +18316,7 @@ F: drivers/mmc/host/sdhci-brcmstb* SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER M: Adrian Hunter <adrian.hunter@intel.com> L: linux-mmc@vger.kernel.org -S: Maintained +S: Supported F: drivers/mmc/host/sdhci* SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER @@ -18339,7 +18339,7 @@ S: Maintained F: drivers/mmc/host/sdhci-spear.c SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) TI OMAP DRIVER -M: Kishon Vijay Abraham I <kishon@ti.com> +M: Vignesh Raghavendra <vigneshr@ti.com> L: linux-mmc@vger.kernel.org S: Maintained F: drivers/mmc/host/sdhci-omap.c diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 0fd91f749b3a..b89dca1f15e9 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -565,7 +565,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); - INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work); + INIT_WORK(&host->sdio_irq_work, sdio_irq_work); timer_setup(&host->retune_timer, mmc_retune_timer, 0); /* diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 0b682a31cd3e..f64b9ac76a5c 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1043,7 +1043,7 @@ static int mmc_sdio_suspend(struct mmc_host *host) /* Prevent processing of SDIO IRQs in suspended state. */ mmc_card_set_suspended(host->card); - cancel_delayed_work_sync(&host->sdio_irq_work); + cancel_work_sync(&host->sdio_irq_work); mmc_claim_host(host); @@ -1103,7 +1103,7 @@ static int mmc_sdio_resume(struct mmc_host *host) if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) wake_up_process(host->sdio_irq_thread); else if (host->caps & MMC_CAP_SDIO_IRQ) - queue_delayed_work(system_wq, &host->sdio_irq_work, 0); + schedule_work(&host->sdio_irq_work); } out: diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 4b1f7c966ec8..2b24bdf38296 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -124,7 +124,7 @@ static void sdio_run_irqs(struct mmc_host *host) void sdio_irq_work(struct work_struct *work) { struct mmc_host *host = - container_of(work, struct mmc_host, sdio_irq_work.work); + container_of(work, struct mmc_host, sdio_irq_work); sdio_run_irqs(host); } @@ -132,7 +132,7 @@ void sdio_irq_work(struct work_struct *work) void sdio_signal_irq(struct mmc_host *host) { host->sdio_irq_pending = true; - queue_delayed_work(system_wq, &host->sdio_irq_work, 0); + schedule_work(&host->sdio_irq_work); } EXPORT_SYMBOL_GPL(sdio_signal_irq); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index e63608834411..f324daadaf70 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -157,6 +157,7 @@ config MMC_SDHCI_OF_ARASAN config MMC_SDHCI_OF_ASPEED tristate "SDHCI OF support for the ASPEED SDHCI controller" + depends on ARCH_ASPEED || COMPILE_TEST depends on MMC_SDHCI_PLTFM depends on OF && OF_ADDRESS select MMC_SDHCI_IO_ACCESSORS diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index a9a0837153d8..c88b039dc9fb 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -1097,8 +1097,9 @@ out5: if (host->platdata && host->platdata->cd_setup && !(mmc->caps & MMC_CAP_NEEDS_POLL)) host->platdata->cd_setup(mmc, 0); -out_clk: + clk_disable_unprepare(host->clk); +out_clk: clk_put(host->clk); out_irq: free_irq(host->irq, host); diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index b1d563b2ed1b..dc2db9c185ea 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -298,7 +298,7 @@ static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host, { struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data); enum dma_data_direction dir = mmc_get_dma_dir(data); - int sg_count; + unsigned int sg_count; if (data->host_cookie == COOKIE_PREMAPPED) return data->sg_count; @@ -308,7 +308,7 @@ static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host, data->sg_len, dir); - if (sg_count <= 0) { + if (!sg_count) { dev_err(mmc_dev(host->mmc), "Failed to map scatterlist for DMA operation\n"); return -EINVAL; diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index fc462995cf94..df05e60bed9a 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -41,14 +41,17 @@ #define CLK_V2_TX_DELAY_MASK GENMASK(19, 16) #define CLK_V2_RX_DELAY_MASK GENMASK(23, 20) #define CLK_V2_ALWAYS_ON BIT(24) +#define CLK_V2_IRQ_SDIO_SLEEP BIT(25) #define CLK_V3_TX_DELAY_MASK GENMASK(21, 16) #define CLK_V3_RX_DELAY_MASK GENMASK(27, 22) #define CLK_V3_ALWAYS_ON BIT(28) +#define CLK_V3_IRQ_SDIO_SLEEP BIT(29) #define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask) #define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask) #define CLK_ALWAYS_ON(h) (h->data->always_on) +#define CLK_IRQ_SDIO_SLEEP(h) (h->data->irq_sdio_sleep) #define SD_EMMC_DELAY 0x4 #define SD_EMMC_ADJUST 0x8 @@ -101,8 +104,7 @@ #define IRQ_RESP_STATUS BIT(14) #define IRQ_SDIO BIT(15) #define IRQ_EN_MASK \ - (IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN | IRQ_RESP_STATUS |\ - IRQ_SDIO) + (IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN) #define SD_EMMC_CMD_CFG 0x50 #define SD_EMMC_CMD_ARG 0x54 @@ -136,6 +138,7 @@ struct meson_mmc_data { unsigned int rx_delay_mask; unsigned int always_on; unsigned int adjust; + unsigned int irq_sdio_sleep; }; struct sd_emmc_desc { @@ -175,6 +178,7 @@ struct meson_host { bool vqmmc_enabled; bool needs_pre_post_req; + spinlock_t lock; }; #define CMD_CFG_LENGTH_MASK GENMASK(8, 0) @@ -431,6 +435,7 @@ static int meson_mmc_clk_init(struct meson_host *host) clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180); clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_0); clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0); + clk_reg |= CLK_IRQ_SDIO_SLEEP(host); writel(clk_reg, host->regs + SD_EMMC_CLOCK); /* get the mux parents */ @@ -929,33 +934,54 @@ static void meson_mmc_read_resp(struct mmc_host *mmc, struct mmc_command *cmd) } } +static void __meson_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct meson_host *host = mmc_priv(mmc); + u32 reg_irqen = IRQ_EN_MASK; + + if (enable) + reg_irqen |= IRQ_SDIO; + writel(reg_irqen, host->regs + SD_EMMC_IRQ_EN); +} + static irqreturn_t meson_mmc_irq(int irq, void *dev_id) { struct meson_host *host = dev_id; struct mmc_command *cmd; - struct mmc_data *data; - u32 irq_en, status, raw_status; + u32 status, raw_status; irqreturn_t ret = IRQ_NONE; - irq_en = readl(host->regs + SD_EMMC_IRQ_EN); raw_status = readl(host->regs + SD_EMMC_STATUS); - status = raw_status & irq_en; + status = raw_status & (IRQ_EN_MASK | IRQ_SDIO); if (!status) { dev_dbg(host->dev, - "Unexpected IRQ! irq_en 0x%08x - status 0x%08x\n", - irq_en, raw_status); + "Unexpected IRQ! irq_en 0x%08lx - status 0x%08x\n", + IRQ_EN_MASK | IRQ_SDIO, raw_status); return IRQ_NONE; } - if (WARN_ON(!host) || WARN_ON(!host->cmd)) + if (WARN_ON(!host)) return IRQ_NONE; /* ack all raised interrupts */ writel(status, host->regs + SD_EMMC_STATUS); cmd = host->cmd; - data = cmd->data; + + if (status & IRQ_SDIO) { + spin_lock(&host->lock); + __meson_mmc_enable_sdio_irq(host->mmc, 0); + sdio_signal_irq(host->mmc); + spin_unlock(&host->lock); + status &= ~IRQ_SDIO; + if (!status) + return IRQ_HANDLED; + } + + if (WARN_ON(!cmd)) + return IRQ_NONE; + cmd->error = 0; if (status & IRQ_CRC_ERR) { dev_dbg(host->dev, "CRC Error - status 0x%08x\n", status); @@ -973,12 +999,9 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) meson_mmc_read_resp(host->mmc, cmd); - if (status & IRQ_SDIO) { - dev_dbg(host->dev, "IRQ: SDIO TODO.\n"); - ret = IRQ_HANDLED; - } - if (status & (IRQ_END_OF_CHAIN | IRQ_RESP_STATUS)) { + struct mmc_data *data = cmd->data; + if (data && !cmd->error) data->bytes_xfered = data->blksz * data->blocks; if (meson_mmc_bounce_buf_read(data) || @@ -1121,6 +1144,21 @@ static int meson_mmc_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) return -EINVAL; } +static void meson_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct meson_host *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + __meson_mmc_enable_sdio_irq(mmc, enable); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void meson_mmc_ack_sdio_irq(struct mmc_host *mmc) +{ + meson_mmc_enable_sdio_irq(mmc, 1); +} + static const struct mmc_host_ops meson_mmc_ops = { .request = meson_mmc_request, .set_ios = meson_mmc_set_ios, @@ -1130,6 +1168,8 @@ static const struct mmc_host_ops meson_mmc_ops = { .execute_tuning = meson_mmc_resampling_tuning, .card_busy = meson_mmc_card_busy, .start_signal_voltage_switch = meson_mmc_voltage_switch, + .enable_sdio_irq = meson_mmc_enable_sdio_irq, + .ack_sdio_irq = meson_mmc_ack_sdio_irq, }; static int meson_mmc_probe(struct platform_device *pdev) @@ -1226,10 +1266,8 @@ static int meson_mmc_probe(struct platform_device *pdev) /* clear, ack and enable interrupts */ writel(0, host->regs + SD_EMMC_IRQ_EN); - writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN, - host->regs + SD_EMMC_STATUS); - writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN, - host->regs + SD_EMMC_IRQ_EN); + writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS); + writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN); ret = request_threaded_irq(host->irq, meson_mmc_irq, meson_mmc_irq_thread, IRQF_ONESHOT, @@ -1237,7 +1275,13 @@ static int meson_mmc_probe(struct platform_device *pdev) if (ret) goto err_init_clk; + spin_lock_init(&host->lock); + mmc->caps |= MMC_CAP_CMD23; + + if (mmc->caps & MMC_CAP_SDIO_IRQ) + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + if (host->dram_access_quirk) { /* Limit segments to 1 due to low available sram memory */ mmc->max_segs = 1; @@ -1328,6 +1372,7 @@ static const struct meson_mmc_data meson_gx_data = { .rx_delay_mask = CLK_V2_RX_DELAY_MASK, .always_on = CLK_V2_ALWAYS_ON, .adjust = SD_EMMC_ADJUST, + .irq_sdio_sleep = CLK_V2_IRQ_SDIO_SLEEP, }; static const struct meson_mmc_data meson_axg_data = { @@ -1335,6 +1380,7 @@ static const struct meson_mmc_data meson_axg_data = { .rx_delay_mask = CLK_V3_RX_DELAY_MASK, .always_on = CLK_V3_ALWAYS_ON, .adjust = SD_EMMC_V3_ADJUST, + .irq_sdio_sleep = CLK_V3_IRQ_SDIO_SLEEP, }; static const struct of_device_id meson_mmc_of_match[] = { diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c index e92e63cb5641..da85c2f2acb8 100644 --- a/drivers/mmc/host/meson-mx-sdhc-mmc.c +++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c @@ -381,14 +381,14 @@ static void meson_mx_sdhc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static int meson_mx_sdhc_map_dma(struct mmc_host *mmc, struct mmc_request *mrq) { struct mmc_data *data = mrq->data; - int dma_len; + unsigned int dma_len; if (!data) return 0; dma_len = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, mmc_get_dma_dir(data)); - if (dma_len <= 0) { + if (!dma_len) { dev_err(mmc_dev(mmc), "dma_map_sg failed\n"); return -ENOMEM; } diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 69d78604d1fc..df941438aef5 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -474,33 +474,20 @@ struct msdc_host { struct cqhci_host *cq_host; }; -static const struct mtk_mmc_compatible mt8135_compat = { - .clk_div_bits = 8, +static const struct mtk_mmc_compatible mt2701_compat = { + .clk_div_bits = 12, .recheck_sdio_irq = true, .hs400_tune = false, - .pad_tune_reg = MSDC_PAD_TUNE, - .async_fifo = false, - .data_tune = false, - .busy_check = false, - .stop_clk_fix = false, - .enhance_rx = false, - .support_64g = false, -}; - -static const struct mtk_mmc_compatible mt8173_compat = { - .clk_div_bits = 8, - .recheck_sdio_irq = true, - .hs400_tune = true, - .pad_tune_reg = MSDC_PAD_TUNE, - .async_fifo = false, - .data_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, .busy_check = false, .stop_clk_fix = false, .enhance_rx = false, .support_64g = false, }; -static const struct mtk_mmc_compatible mt8183_compat = { +static const struct mtk_mmc_compatible mt2712_compat = { .clk_div_bits = 12, .recheck_sdio_irq = false, .hs400_tune = false, @@ -513,30 +500,43 @@ static const struct mtk_mmc_compatible mt8183_compat = { .support_64g = true, }; -static const struct mtk_mmc_compatible mt2701_compat = { +static const struct mtk_mmc_compatible mt6779_compat = { .clk_div_bits = 12, - .recheck_sdio_irq = true, + .recheck_sdio_irq = false, .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 mtk_mmc_compatible mt6795_compat = { + .clk_div_bits = 8, + .recheck_sdio_irq = false, + .hs400_tune = true, + .pad_tune_reg = MSDC_PAD_TUNE, + .async_fifo = false, + .data_tune = false, .busy_check = false, .stop_clk_fix = false, .enhance_rx = false, .support_64g = false, }; -static const struct mtk_mmc_compatible mt2712_compat = { - .clk_div_bits = 12, - .recheck_sdio_irq = false, +static const struct mtk_mmc_compatible mt7620_compat = { + .clk_div_bits = 8, + .recheck_sdio_irq = true, .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, + .pad_tune_reg = MSDC_PAD_TUNE, + .async_fifo = false, + .data_tune = false, + .busy_check = false, + .stop_clk_fix = false, + .enhance_rx = false, + .use_internal_cd = true, }; static const struct mtk_mmc_compatible mt7622_compat = { @@ -552,31 +552,33 @@ static const struct mtk_mmc_compatible mt7622_compat = { .support_64g = false, }; -static const struct mtk_mmc_compatible mt8516_compat = { - .clk_div_bits = 12, +static const struct mtk_mmc_compatible mt8135_compat = { + .clk_div_bits = 8, .recheck_sdio_irq = true, .hs400_tune = false, - .pad_tune_reg = MSDC_PAD_TUNE0, - .async_fifo = true, - .data_tune = true, - .busy_check = true, - .stop_clk_fix = true, + .pad_tune_reg = MSDC_PAD_TUNE, + .async_fifo = false, + .data_tune = false, + .busy_check = false, + .stop_clk_fix = false, + .enhance_rx = false, + .support_64g = false, }; -static const struct mtk_mmc_compatible mt7620_compat = { +static const struct mtk_mmc_compatible mt8173_compat = { .clk_div_bits = 8, .recheck_sdio_irq = true, - .hs400_tune = false, + .hs400_tune = true, .pad_tune_reg = MSDC_PAD_TUNE, .async_fifo = false, .data_tune = false, .busy_check = false, .stop_clk_fix = false, .enhance_rx = false, - .use_internal_cd = true, + .support_64g = false, }; -static const struct mtk_mmc_compatible mt6779_compat = { +static const struct mtk_mmc_compatible mt8183_compat = { .clk_div_bits = 12, .recheck_sdio_irq = false, .hs400_tune = false, @@ -589,16 +591,29 @@ static const struct mtk_mmc_compatible mt6779_compat = { .support_64g = true, }; +static const struct mtk_mmc_compatible mt8516_compat = { + .clk_div_bits = 12, + .recheck_sdio_irq = true, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, + .busy_check = true, + .stop_clk_fix = true, +}; + static const struct of_device_id msdc_of_ids[] = { - { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, - { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, - { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat}, { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, + { .compatible = "mediatek,mt6779-mmc", .data = &mt6779_compat}, + { .compatible = "mediatek,mt6795-mmc", .data = &mt6795_compat}, + { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, + { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, + { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, + { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_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); diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 5fe4528e296e..5798aee06653 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1042,7 +1042,6 @@ static int sd_set_timing(struct rtsx_usb_sdmmc *host, unsigned char timing, bool *ddr_mode) { struct rtsx_ucr *ucr = host->ucr; - int err; *ddr_mode = false; @@ -1097,9 +1096,7 @@ static int sd_set_timing(struct rtsx_usb_sdmmc *host, break; } - err = rtsx_usb_send_cmd(ucr, MODE_C, 100); - - return err; + return rtsx_usb_send_cmd(ucr, MODE_C, 100); } static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index dc2991422a87..3a091a387ecb 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2441,6 +2441,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = { */ {.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var}, {.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var}, + {.compatible = "qcom,sdm670-sdhci", .data = &sdm845_sdhci_var}, {.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var}, {.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var}, {}, diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 622b7de96c7f..169b84761041 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -297,6 +297,27 @@ static const struct sdhci_pci_fixes sdhci_ricoh_mmc = { SDHCI_QUIRK_MISSING_CAPS }; +static void ene_714_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_set_ios(mmc, ios); + + /* + * Some (ENE) controllers misbehave on some ios operations, + * signalling timeout and CRC errors even on CMD0. Resetting + * it on each ios seems to solve the problem. + */ + if (!(host->flags & SDHCI_DEVICE_DEAD)) + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); +} + +static int ene_714_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc_host_ops.set_ios = ene_714_set_ios; + return 0; +} + static const struct sdhci_pci_fixes sdhci_ene_712 = { .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_BROKEN_DMA, @@ -304,8 +325,8 @@ static const struct sdhci_pci_fixes sdhci_ene_712 = { static const struct sdhci_pci_fixes sdhci_ene_714 = { .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | - SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS | SDHCI_QUIRK_BROKEN_DMA, + .probe_slot = ene_714_probe_slot, }; static const struct sdhci_pci_fixes sdhci_cafe = { diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index 0d4d343dbb77..ad457cd9cbaa 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -317,11 +317,12 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) u32 reg_val; /* - * This handler only implements the eMMC tuning that is specific to + * This handler implements the hardware tuning that is specific to * this controller. Fall back to the standard method for other TIMING. */ if ((host->timing != MMC_TIMING_MMC_HS200) && - (host->timing != MMC_TIMING_UHS_SDR104)) + (host->timing != MMC_TIMING_UHS_SDR104) && + (host->timing != MMC_TIMING_UHS_SDR50)) return sdhci_execute_tuning(mmc, opcode); if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) && @@ -631,6 +632,8 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) if (reg & 0x1) host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; + host->quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50; + sdhci_pci_o2_enable_msi(chip, host); if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) { diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index f33e9349e4e6..46c55ab4884c 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -205,14 +205,14 @@ static inline u32 sdhci_sprd_calc_div(u32 base_clk, u32 clk) if ((base_clk / div) > (clk * 2)) div++; - if (div > SDHCI_SPRD_CLK_MAX_DIV) - div = SDHCI_SPRD_CLK_MAX_DIV; - if (div % 2) div = (div + 1) / 2; else div = div / 2; + if (div > SDHCI_SPRD_CLK_MAX_DIV) + div = SDHCI_SPRD_CLK_MAX_DIV; + return div; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 251172890af7..fef03de85b99 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -233,28 +233,62 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) } EXPORT_SYMBOL_GPL(sdhci_reset); -static void sdhci_do_reset(struct sdhci_host *host, u8 mask) +static bool sdhci_do_reset(struct sdhci_host *host, u8 mask) { if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { struct mmc_host *mmc = host->mmc; if (!mmc->ops->get_cd(mmc)) - return; + return false; } host->ops->reset(host, mask); - if (mask & SDHCI_RESET_ALL) { + return true; +} + +static void sdhci_reset_for_all(struct sdhci_host *host) +{ + if (sdhci_do_reset(host, SDHCI_RESET_ALL)) { if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) host->ops->enable_dma(host); } - /* Resetting the controller clears many */ host->preset_enabled = false; } } +enum sdhci_reset_reason { + SDHCI_RESET_FOR_INIT, + SDHCI_RESET_FOR_REQUEST_ERROR, + SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY, + SDHCI_RESET_FOR_TUNING_ABORT, + SDHCI_RESET_FOR_CARD_REMOVED, + SDHCI_RESET_FOR_CQE_RECOVERY, +}; + +static void sdhci_reset_for_reason(struct sdhci_host *host, enum sdhci_reset_reason reason) +{ + switch (reason) { + case SDHCI_RESET_FOR_INIT: + sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + break; + case SDHCI_RESET_FOR_REQUEST_ERROR: + case SDHCI_RESET_FOR_TUNING_ABORT: + case SDHCI_RESET_FOR_CARD_REMOVED: + case SDHCI_RESET_FOR_CQE_RECOVERY: + sdhci_do_reset(host, SDHCI_RESET_CMD); + sdhci_do_reset(host, SDHCI_RESET_DATA); + break; + case SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY: + sdhci_do_reset(host, SDHCI_RESET_DATA); + break; + } +} + +#define sdhci_reset_for(h, r) sdhci_reset_for_reason((h), SDHCI_RESET_FOR_##r) + static void sdhci_set_default_irqs(struct sdhci_host *host) { host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | @@ -323,9 +357,9 @@ static void sdhci_init(struct sdhci_host *host, int soft) unsigned long flags; if (soft) - sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + sdhci_reset_for(host, INIT); else - sdhci_do_reset(host, SDHCI_RESET_ALL); + sdhci_reset_for_all(host); if (host->v4_mode) sdhci_do_enable_v4_mode(host); @@ -1538,8 +1572,9 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout) */ if (data->error) { if (!host->cmd || host->cmd == data_cmd) - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); + sdhci_reset_for(host, REQUEST_ERROR); + else + sdhci_reset_for(host, REQUEST_ERROR_DATA_ONLY); } if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) == @@ -2403,14 +2438,6 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->ops->set_clock(host, host->clock); } else sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - - /* - * Some (ENE) controllers go apeshit on some ios operation, - * signalling timeout and CRC errors even on CMD0. Resetting - * it on each ios seems to solve the problem. - */ - if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) - sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); } EXPORT_SYMBOL_GPL(sdhci_set_ios); @@ -2718,8 +2745,7 @@ void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode) { sdhci_reset_tuning(host); - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); + sdhci_reset_for(host, TUNING_ABORT); sdhci_end_tuning(host); @@ -2987,8 +3013,7 @@ static void sdhci_card_event(struct mmc_host *mmc) pr_err("%s: Resetting controller.\n", mmc_hostname(mmc)); - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); + sdhci_reset_for(host, CARD_REMOVED); sdhci_error_out_mrqs(host, -ENOMEDIUM); } @@ -3059,12 +3084,7 @@ static bool sdhci_request_done(struct sdhci_host *host) /* This is to force an update */ host->ops->set_clock(host, host->clock); - /* - * 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); + sdhci_reset_for(host, REQUEST_ERROR); host->pending_reset = false; } @@ -3905,10 +3925,8 @@ void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery) host->cqe_on = false; - if (recovery) { - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); - } + if (recovery) + sdhci_reset_for(host, CQE_RECOVERY); pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n", mmc_hostname(mmc), host->ier, @@ -4066,7 +4084,7 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver, if (debug_quirks2) host->quirks2 = debug_quirks2; - sdhci_do_reset(host, SDHCI_RESET_ALL); + sdhci_reset_for_all(host); if (host->v4_mode) sdhci_do_enable_v4_mode(host); @@ -4807,7 +4825,7 @@ int __sdhci_add_host(struct sdhci_host *host) unled: sdhci_led_unregister(host); unirq: - sdhci_do_reset(host, SDHCI_RESET_ALL); + sdhci_reset_for_all(host); sdhci_writel(host, 0, SDHCI_INT_ENABLE); sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); free_irq(host->irq, host); @@ -4865,7 +4883,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) sdhci_led_unregister(host); if (!dead) - sdhci_do_reset(host, SDHCI_RESET_ALL); + sdhci_reset_for_all(host); sdhci_writel(host, 0, SDHCI_INT_ENABLE); sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 95a08f09df30..d750c464bd1e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -379,8 +379,6 @@ struct sdhci_host { #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) /* Controller doesn't like clearing the power reg before a change */ #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) -/* Controller has flaky internal state so reset it on each ios change */ -#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) /* Controller has an unusable DMA engine */ #define SDHCI_QUIRK_BROKEN_DMA (1<<5) /* Controller has an unusable ADMA engine */ diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index e7ced1496a07..8f1023480e12 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -554,7 +554,6 @@ static const struct cqhci_host_ops sdhci_am654_cqhci_ops = { static int sdhci_am654_cqe_add_host(struct sdhci_host *host) { struct cqhci_host *cq_host; - int ret; cq_host = devm_kzalloc(mmc_dev(host->mmc), sizeof(struct cqhci_host), GFP_KERNEL); @@ -568,9 +567,7 @@ static int sdhci_am654_cqe_add_host(struct sdhci_host *host) host->mmc->caps2 |= MMC_CAP2_CQE; - ret = cqhci_init(cq_host, host->mmc, 1); - - return ret; + return cqhci_init(cq_host, host->mmc, 1); } static int sdhci_am654_get_otap_delay(struct sdhci_host *host, diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 163ac9df8cca..9b5c503e3a3f 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -846,7 +846,7 @@ static int wmt_mci_probe(struct platform_device *pdev) if (IS_ERR(priv->clk_sdmmc)) { dev_err(&pdev->dev, "Error getting clock\n"); ret = PTR_ERR(priv->clk_sdmmc); - goto fail5; + goto fail5_and_a_half; } ret = clk_prepare_enable(priv->clk_sdmmc); @@ -863,6 +863,9 @@ static int wmt_mci_probe(struct platform_device *pdev) return 0; fail6: clk_put(priv->clk_sdmmc); +fail5_and_a_half: + dma_free_coherent(&pdev->dev, mmc->max_blk_count * 16, + priv->dma_desc_buffer, priv->dma_desc_device_addr); fail5: free_irq(dma_irq, priv); fail4: diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index eb8bc5b9b0b7..8fdd3cf971a3 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -476,7 +476,7 @@ struct mmc_host { unsigned int sdio_irqs; struct task_struct *sdio_irq_thread; - struct delayed_work sdio_irq_work; + struct work_struct sdio_irq_work; bool sdio_irq_pending; atomic_t sdio_irq_thread_abort; |