diff options
author | Geert Uytterhoeven <geert+renesas@glider.be> | 2024-04-23 10:25:16 +0200 |
---|---|---|
committer | Geert Uytterhoeven <geert+renesas@glider.be> | 2024-04-23 10:25:16 +0200 |
commit | a692fb4b65acef7e8a5f701327f0c837fa1bd4f8 (patch) | |
tree | b220b500cf95f89b70a9a4eed9c61a8f4e945972 | |
parent | c92a061e2a94a4d97195ae166c9b92b861f1f02c (diff) | |
parent | bce42d6108c9ff6de1381995dffa762730ce0756 (diff) | |
download | renesas-drivers-a692fb4b65acef7e8a5f701327f0c837fa1bd4f8.tar.gz |
Merge remote-tracking branch 'mmc/next' into renesas-drivers
Notice: this object is not reachable from any branch.
Notice: this object is not reachable from any branch.
26 files changed, 400 insertions, 119 deletions
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml index 82f7ee8702cb28..b9b99957052901 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml @@ -91,6 +91,9 @@ properties: - enum: - fsl,imxrt1170-usdhc - const: fsl,imxrt1050-usdhc + - items: + - const: nxp,s32g3-usdhc + - const: nxp,s32g2-usdhc reg: maxItems: 1 diff --git a/MAINTAINERS b/MAINTAINERS index 22b10889fe640b..fa672ec8514529 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8537,7 +8537,7 @@ F: Documentation/devicetree/bindings/crypto/fsl,sec-v4.0* F: drivers/crypto/caam/ FREESCALE COLDFIRE M5441X MMC DRIVER -M: Angelo Dureghello <angelo.dureghello@timesys.com> +M: Angelo Dureghello <adureghello@baylibre.com> L: linux-mmc@vger.kernel.org S: Maintained F: drivers/mmc/host/sdhci-esdhc-mcf.c diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index d76c799553aaa1..85b7f2bb425982 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1736,7 +1736,6 @@ static struct sdio_driver bt_mrvl_sdio = { .probe = btmrvl_sdio_probe, .remove = btmrvl_sdio_remove, .drv = { - .owner = THIS_MODULE, .coredump = btmrvl_sdio_coredump, .pm = &btmrvl_sdio_pm_ops, } diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index ff4868c83cd81e..8ded9ef8089a2f 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -1519,7 +1519,6 @@ static struct sdio_driver btmtksdio_driver = { .remove = btmtksdio_remove, .id_table = btmtksdio_table, .drv = { - .owner = THIS_MODULE, .pm = BTMTKSDIO_PM_OPS, } }; diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 90c51b12148e8d..367509b5b6466c 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -234,7 +234,7 @@ static ssize_t power_ro_lock_show(struct device *dev, else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) locked = 1; - ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); + ret = sysfs_emit(buf, "%d\n", locked); mmc_blk_put(md); @@ -296,9 +296,9 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, int ret; struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); - ret = snprintf(buf, PAGE_SIZE, "%d\n", - get_disk_ro(dev_to_disk(dev)) ^ - md->read_only); + ret = sysfs_emit(buf, "%d\n", + get_disk_ro(dev_to_disk(dev)) ^ + md->read_only); mmc_blk_put(md); return ret; } diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 1642ea72d22c5c..f10a4dcf1f9512 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -351,11 +351,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) root = debugfs_create_dir(mmc_hostname(host), NULL); host->debugfs_root = root; - debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops); + debugfs_create_file("ios", 0400, root, host, &mmc_ios_fops); debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops); debugfs_create_file("caps2", 0600, root, &host->caps2, &mmc_caps2_fops); - debugfs_create_file_unsafe("clock", S_IRUSR | S_IWUSR, root, host, + debugfs_create_file_unsafe("clock", 0600, root, host, &mmc_clock_fops); debugfs_create_file_unsafe("err_state", 0600, root, host, @@ -388,7 +388,8 @@ void mmc_add_card_debugfs(struct mmc_card *card) root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root); card->debugfs_root = root; - debugfs_create_x32("state", S_IRUSR, root, &card->state); + debugfs_create_x32("state", 0400, root, &card->state); + debugfs_create_x32("quirks", 0400, root, &card->quirks); } void mmc_remove_card_debugfs(struct mmc_card *card) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 8f8781d6c25ed0..48bda70145ee68 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -13,7 +13,6 @@ #include <linux/err.h> #include <linux/idr.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pagemap.h> #include <linux/pm_wakeup.h> #include <linux/export.h> diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 71d885fbc22876..c5fdfe2325f8f4 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -265,16 +265,19 @@ void sdio_unregister_bus(void) } /** - * sdio_register_driver - register a function driver + * __sdio_register_driver - register a function driver * @drv: SDIO function driver + * @owner: owning module/driver */ -int sdio_register_driver(struct sdio_driver *drv) +int __sdio_register_driver(struct sdio_driver *drv, struct module *owner) { drv->drv.name = drv->name; drv->drv.bus = &sdio_bus_type; + drv->drv.owner = owner; + return driver_register(&drv->drv); } -EXPORT_SYMBOL_GPL(sdio_register_driver); +EXPORT_SYMBOL_GPL(__sdio_register_driver); /** * sdio_unregister_driver - unregister a function driver diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index aebc587f77a7dc..bb0d4fb0892ae1 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -233,6 +233,7 @@ config MMC_SDHCI_OF_DWCMSHC depends on MMC_SDHCI_PLTFM depends on OF depends on COMMON_CLK + select MMC_CQHCI help This selects Synopsys DesignWare Cores Mobile Storage Controller support. diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index 41e94cd1410980..c14d7251d0bbe7 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -474,8 +474,8 @@ static int cqhci_dma_map(struct mmc_host *host, struct mmc_request *mrq) return sg_count; } -static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, - bool dma64) +void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, + bool dma64) { __le32 *attr = (__le32 __force *)desc; @@ -495,6 +495,7 @@ static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, dataddr[0] = cpu_to_le32(addr); } } +EXPORT_SYMBOL(cqhci_set_tran_desc); static int cqhci_prep_tran_desc(struct mmc_request *mrq, struct cqhci_host *cq_host, int tag) @@ -522,7 +523,11 @@ static int cqhci_prep_tran_desc(struct mmc_request *mrq, if ((i+1) == sg_count) end = true; - cqhci_set_tran_desc(desc, addr, len, end, dma64); + if (cq_host->ops->set_tran_desc) + cq_host->ops->set_tran_desc(cq_host, &desc, addr, len, end, dma64); + else + cqhci_set_tran_desc(desc, addr, len, end, dma64); + desc += cq_host->trans_desc_len; } diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 1a12e40a02e670..fab9d74445ba72 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -293,6 +293,9 @@ struct cqhci_host_ops { int (*program_key)(struct cqhci_host *cq_host, const union cqhci_crypto_cfg_entry *cfg, int slot); #endif + void (*set_tran_desc)(struct cqhci_host *cq_host, u8 **desc, + dma_addr_t addr, int len, bool end, bool dma64); + }; static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) @@ -318,6 +321,7 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64); struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev); int cqhci_deactivate(struct mmc_host *mmc); +void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, bool dma64); static inline int cqhci_suspend(struct mmc_host *mmc) { return cqhci_deactivate(mmc); diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 8bd938919687b7..d7427894e0bc9f 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1337,7 +1337,7 @@ ioremap_fail: return ret; } -static void __exit davinci_mmcsd_remove(struct platform_device *pdev) +static void davinci_mmcsd_remove(struct platform_device *pdev) { struct mmc_davinci_host *host = platform_get_drvdata(pdev); @@ -1392,7 +1392,7 @@ static struct platform_driver davinci_mmcsd_driver = { .of_match_table = davinci_mmc_dt_ids, }, .probe = davinci_mmcsd_probe, - .remove_new = __exit_p(davinci_mmcsd_remove), + .remove_new = davinci_mmcsd_remove, .id_table = davinci_mmc_devtype, }; diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c index 61923a5183693b..6099756e59b3c9 100644 --- a/drivers/mmc/host/dw_mmc-hi3798cv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -87,7 +87,6 @@ static int dw_mci_hi3798cv200_execute_tuning(struct dw_mci_slot *slot, goto tuning_out; prev_err = err; - err = 0; } tuning_out: diff --git a/drivers/mmc/host/dw_mmc-hi3798mv200.c b/drivers/mmc/host/dw_mmc-hi3798mv200.c index 989ae8dda72289..96af693e3e37ce 100644 --- a/drivers/mmc/host/dw_mmc-hi3798mv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798mv200.c @@ -133,7 +133,6 @@ static int dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci_slot *slot, goto tuning_out; prev_err = err; - err = 0; } tuning_out: diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 1634b1f5d2010b..a94835b8ab9394 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -13,7 +13,6 @@ #include <linux/ioport.h> #include <linux/irq.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm.h> diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 668e0aceeebac9..e113b99a3eab59 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2694,6 +2694,11 @@ static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = true; + spin_unlock_irqrestore(&host->lock, flags); /* Drop the performance vote */ dev_pm_opp_set_rate(dev, 0); @@ -2708,6 +2713,7 @@ static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + unsigned long flags; int ret; ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), @@ -2726,7 +2732,15 @@ static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev) dev_pm_opp_set_rate(dev, msm_host->clk_rate); - return sdhci_msm_ice_resume(msm_host); + ret = sdhci_msm_ice_resume(msm_host); + if (ret) + return ret; + + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = false; + spin_unlock_irqrestore(&host->lock, flags); + + return ret; } static const struct dev_pm_ops sdhci_msm_pm_ops = { diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 1d8f5a76096aeb..c6a20be12712c8 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -21,6 +21,7 @@ #include <linux/sizes.h> #include "sdhci-pltfm.h" +#include "cqhci.h" #define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16) @@ -52,6 +53,9 @@ #define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits [31:24] */ #define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */ +/* DWC IP vendor area 2 pointer */ +#define DWCMSHC_P_VENDOR_AREA2 0xea + /* Sophgo CV18XX specific Registers */ #define CV18XX_SDHCI_MSHC_CTRL 0x00 #define CV18XX_EMMC_FUNC_EN BIT(0) @@ -181,6 +185,10 @@ #define BOUNDARY_OK(addr, len) \ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) +#define DWCMSHC_SDHCI_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ + SDHCI_TRNS_BLK_CNT_EN | \ + SDHCI_TRNS_DMA) + enum dwcmshc_rk_type { DWCMSHC_RK3568, DWCMSHC_RK3588, @@ -196,7 +204,9 @@ struct rk35xx_priv { struct dwcmshc_priv { struct clk *bus_clk; - int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ + int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA1 reg */ + int vendor_specific_area2; /* P_VENDOR_SPECIFIC_AREA2 reg */ + void *priv; /* pointer to SoC private stuff */ u16 delay_line; u16 flags; @@ -455,6 +465,90 @@ static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, sdhci_writel(host, vendor, reg); } +static int dwcmshc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + int err = sdhci_execute_tuning(mmc, opcode); + struct sdhci_host *host = mmc_priv(mmc); + + if (err) + return err; + + /* + * Tuning can leave the IP in an active state (Buffer Read Enable bit + * set) which prevents the entry to low power states (i.e. S0i3). Data + * reset will clear it. + */ + sdhci_reset(host, SDHCI_RESET_DATA); + + return 0; +} + +static u32 dwcmshc_cqe_irq_handler(struct sdhci_host *host, u32 intmask) +{ + int cmd_error = 0; + int data_error = 0; + + if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) + return intmask; + + cqhci_irq(host->mmc, intmask, cmd_error, data_error); + + return 0; +} + +static void dwcmshc_sdhci_cqe_enable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + u8 ctrl; + + sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); + + sdhci_cqe_enable(mmc); + + /* + * The "DesignWare Cores Mobile Storage Host Controller + * DWC_mshc / DWC_mshc_lite Databook" says: + * when Host Version 4 Enable" is 1 in Host Control 2 register, + * SDHCI_CTRL_ADMA32 bit means ADMA2 is selected. + * Selection of 32-bit/64-bit System Addressing: + * either 32-bit or 64-bit system addressing is selected by + * 64-bit Addressing bit in Host Control 2 register. + * + * On the other hand the "DesignWare Cores Mobile Storage Host + * Controller DWC_mshc / DWC_mshc_lite User Guide" says, that we have to + * set DMA_SEL to ADMA2 _only_ mode in the Host Control 2 register. + */ + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + ctrl &= ~SDHCI_CTRL_DMA_MASK; + ctrl |= SDHCI_CTRL_ADMA32; + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +} + +static void dwcmshc_set_tran_desc(struct cqhci_host *cq_host, u8 **desc, + dma_addr_t addr, int len, bool end, bool dma64) +{ + int tmplen, offset; + + if (likely(!len || BOUNDARY_OK(addr, len))) { + cqhci_set_tran_desc(*desc, addr, len, end, dma64); + return; + } + + offset = addr & (SZ_128M - 1); + tmplen = SZ_128M - offset; + cqhci_set_tran_desc(*desc, addr, tmplen, false, dma64); + + addr += tmplen; + len -= tmplen; + *desc += cq_host->trans_desc_len; + cqhci_set_tran_desc(*desc, addr, len, end, dma64); +} + +static void dwcmshc_cqhci_dumpregs(struct mmc_host *mmc) +{ + sdhci_dumpregs(mmc_priv(mmc)); +} + static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -626,6 +720,7 @@ static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) /* perform tuning */ sdhci_start_tuning(host); + host->tuning_loop_count = 128; host->tuning_err = __sdhci_execute_tuning(host, opcode); if (host->tuning_err) { /* disable auto-tuning upon tuning error */ @@ -692,6 +787,7 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = { .get_max_clock = dwcmshc_get_max_clock, .reset = sdhci_reset, .adma_write_desc = dwcmshc_adma_write_desc, + .irq = dwcmshc_cqe_irq_handler, }; static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { @@ -758,6 +854,73 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, }; +static const struct cqhci_host_ops dwcmshc_cqhci_ops = { + .enable = dwcmshc_sdhci_cqe_enable, + .disable = sdhci_cqe_disable, + .dumpregs = dwcmshc_cqhci_dumpregs, + .set_tran_desc = dwcmshc_set_tran_desc, +}; + +static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *pdev) +{ + struct cqhci_host *cq_host; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + bool dma64 = false; + u16 clk; + int err; + + host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; + cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL); + if (!cq_host) { + dev_err(mmc_dev(host->mmc), "Unable to setup CQE: not enough memory\n"); + goto dsbl_cqe_caps; + } + + /* + * For dwcmshc host controller we have to enable internal clock + * before access to some registers from Vendor Specific Area 2. + */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + if (!(clk & SDHCI_CLOCK_INT_EN)) { + dev_err(mmc_dev(host->mmc), "Unable to setup CQE: internal clock enable error\n"); + goto free_cq_host; + } + + cq_host->mmio = host->ioaddr + priv->vendor_specific_area2; + cq_host->ops = &dwcmshc_cqhci_ops; + + /* Enable using of 128-bit task descriptors */ + dma64 = host->flags & SDHCI_USE_64_BIT_DMA; + if (dma64) { + dev_dbg(mmc_dev(host->mmc), "128-bit task descriptors\n"); + cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + } + err = cqhci_init(cq_host, host->mmc, dma64); + if (err) { + dev_err(mmc_dev(host->mmc), "Unable to setup CQE: error %d\n", err); + goto int_clock_disable; + } + + dev_dbg(mmc_dev(host->mmc), "CQE init done\n"); + + return; + +int_clock_disable: + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + +free_cq_host: + devm_kfree(&pdev->dev, cq_host); + +dsbl_cqe_caps: + host->mmc->caps2 &= ~(MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD); +} + static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) { int err; @@ -862,7 +1025,7 @@ static int dwcmshc_probe(struct platform_device *pdev) struct rk35xx_priv *rk_priv = NULL; const struct sdhci_pltfm_data *pltfm_data; int err; - u32 extra; + u32 extra, caps; pltfm_data = device_get_match_data(&pdev->dev); if (!pltfm_data) { @@ -913,6 +1076,7 @@ static int dwcmshc_probe(struct platform_device *pdev) host->mmc_host_ops.request = dwcmshc_request; host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; + host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning; if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) { rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL); @@ -962,6 +1126,10 @@ static int dwcmshc_probe(struct platform_device *pdev) sdhci_enable_v4_mode(host); #endif + caps = sdhci_readl(host, SDHCI_CAPABILITIES); + if (caps & SDHCI_CAN_64BIT_V4) + sdhci_enable_v4_mode(host); + host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; pm_runtime_get_noresume(dev); @@ -972,6 +1140,14 @@ static int dwcmshc_probe(struct platform_device *pdev) if (err) goto err_rpm; + /* Setup Command Queue Engine if enabled */ + if (device_property_read_bool(&pdev->dev, "supports-cqe")) { + priv->vendor_specific_area2 = + sdhci_readw(host, DWCMSHC_P_VENDOR_AREA2); + + dwcmshc_cqhci_init(host, pdev); + } + if (rk_priv) dwcmshc_rk35xx_postinit(host, priv); @@ -1044,6 +1220,12 @@ static int dwcmshc_suspend(struct device *dev) pm_runtime_resume(dev); + if (host->mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_suspend(host->mmc); + if (ret) + return ret; + } + ret = sdhci_suspend_host(host); if (ret) return ret; @@ -1088,6 +1270,12 @@ static int dwcmshc_resume(struct device *dev) if (ret) goto disable_rockchip_clks; + if (host->mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_resume(host->mmc); + if (ret) + goto disable_rockchip_clks; + } + return 0; disable_rockchip_clks: diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 77911a57b12cfc..0f81586a19df38 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -25,12 +25,6 @@ #define GLI_9750_WT_EN_ON 0x1 #define GLI_9750_WT_EN_OFF 0x0 -#define PCI_GLI_9750_PM_CTRL 0xFC -#define PCI_GLI_9750_PM_STATE GENMASK(1, 0) - -#define PCI_GLI_9750_CORRERR_MASK 0x214 -#define PCI_GLI_9750_CORRERR_MASK_REPLAY_TIMER_TIMEOUT BIT(12) - #define SDHCI_GLI_9750_CFG2 0x848 #define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24) #define GLI_9750_CFG2_L1DLY_VALUE 0x1F @@ -152,12 +146,6 @@ #define PCI_GLI_9755_MISC 0x78 #define PCI_GLI_9755_MISC_SSC_OFF BIT(26) -#define PCI_GLI_9755_PM_CTRL 0xFC -#define PCI_GLI_9755_PM_STATE GENMASK(1, 0) - -#define PCI_GLI_9755_CORRERR_MASK 0x214 -#define PCI_GLI_9755_CORRERR_MASK_REPLAY_TIMER_TIMEOUT BIT(12) - #define SDHCI_GLI_9767_GM_BURST_SIZE 0x510 #define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8) @@ -547,6 +535,7 @@ static void gl9750_hw_setting(struct sdhci_host *host) { struct sdhci_pci_slot *slot = sdhci_priv(host); struct pci_dev *pdev; + int aer; u32 value; pdev = slot->chip->pdev; @@ -561,16 +550,16 @@ static void gl9750_hw_setting(struct sdhci_host *host) sdhci_writel(host, value, SDHCI_GLI_9750_CFG2); /* toggle PM state to allow GL9750 to enter ASPM L1.2 */ - pci_read_config_dword(pdev, PCI_GLI_9750_PM_CTRL, &value); - value |= PCI_GLI_9750_PM_STATE; - pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value); - value &= ~PCI_GLI_9750_PM_STATE; - pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value); + pci_set_power_state(pdev, PCI_D3hot); + pci_set_power_state(pdev, PCI_D0); /* mask the replay timer timeout of AER */ - pci_read_config_dword(pdev, PCI_GLI_9750_CORRERR_MASK, &value); - value |= PCI_GLI_9750_CORRERR_MASK_REPLAY_TIMER_TIMEOUT; - pci_write_config_dword(pdev, PCI_GLI_9750_CORRERR_MASK, value); + aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); + if (aer) { + pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value); + value |= PCI_ERR_COR_REP_TIMER; + pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value); + } gl9750_wt_off(host); } @@ -745,6 +734,7 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) static void gl9755_hw_setting(struct sdhci_pci_slot *slot) { struct pci_dev *pdev = slot->chip->pdev; + int aer; u32 value; gl9755_wt_on(pdev); @@ -775,16 +765,16 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot) pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value); /* toggle PM state to allow GL9755 to enter ASPM L1.2 */ - pci_read_config_dword(pdev, PCI_GLI_9755_PM_CTRL, &value); - value |= PCI_GLI_9755_PM_STATE; - pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value); - value &= ~PCI_GLI_9755_PM_STATE; - pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value); + pci_set_power_state(pdev, PCI_D3hot); + pci_set_power_state(pdev, PCI_D0); /* mask the replay timer timeout of AER */ - pci_read_config_dword(pdev, PCI_GLI_9755_CORRERR_MASK, &value); - value |= PCI_GLI_9755_CORRERR_MASK_REPLAY_TIMER_TIMEOUT; - pci_write_config_dword(pdev, PCI_GLI_9755_CORRERR_MASK, value); + aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); + if (aer) { + pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value); + value |= PCI_ERR_COR_REP_TIMER; + pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value); + } gl9755_wt_off(pdev); } diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 0e8a8ac14e5695..6493b0edba34bd 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -17,10 +17,8 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/gpio.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -446,7 +444,7 @@ static int sdhci_s3c_parse_dt(struct device *dev, return 0; } - if (of_get_named_gpio(node, "cd-gpios", 0)) + if (of_property_present(node, "cd-gpios")) return 0; /* assuming internal card detect that will be configured by pinctrl */ diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index bed57a1c64b522..685b1c6489018a 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -13,7 +13,6 @@ #include <linux/mmc/mmc.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index d659c59422e1ea..ba36123e4ccc55 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -141,18 +141,26 @@ static const struct timing_data td[] = { struct sdhci_am654_data { struct regmap *base; - int otap_del_sel[ARRAY_SIZE(td)]; - int itap_del_sel[ARRAY_SIZE(td)]; + u32 otap_del_sel[ARRAY_SIZE(td)]; + u32 itap_del_sel[ARRAY_SIZE(td)]; + u32 itap_del_ena[ARRAY_SIZE(td)]; int clkbuf_sel; int trm_icp; int drv_strength; int strb_sel; u32 flags; u32 quirks; + bool dll_enable; #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) }; +struct window { + u8 start; + u8 end; + u8 length; +}; + struct sdhci_am654_driver_data { const struct sdhci_pltfm_data *pdata; u32 flags; @@ -232,11 +240,13 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock) } static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654, - u32 itapdly) + u32 itapdly, u32 enable) { /* Set ITAPCHGWIN before writing to ITAPDLY */ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 1 << ITAPCHGWIN_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, + enable << ITAPDLYENA_SHIFT); regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK, itapdly << ITAPDLYSEL_SHIFT); regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); @@ -253,8 +263,8 @@ static void sdhci_am654_setup_delay_chain(struct sdhci_am654_data *sdhci_am654, mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val); - sdhci_am654_write_itapdly(sdhci_am654, - sdhci_am654->itap_del_sel[timing]); + sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing], + sdhci_am654->itap_del_ena[timing]); } static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) @@ -263,19 +273,17 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); unsigned char timing = host->mmc->ios.timing; u32 otap_del_sel; - u32 otap_del_ena; u32 mask, val; regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0); sdhci_set_clock(host, clock); - /* Setup DLL Output TAP delay */ + /* Setup Output TAP delay */ otap_del_sel = sdhci_am654->otap_del_sel[timing]; - otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; - val = (otap_del_ena << OTAPDLYENA_SHIFT) | + val = (0x1 << OTAPDLYENA_SHIFT) | (otap_del_sel << OTAPDLYSEL_SHIFT); /* Write to STRBSEL for HS400 speed mode */ @@ -290,10 +298,21 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); - if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) + if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) { sdhci_am654_setup_dll(host, clock); - else + sdhci_am654->dll_enable = true; + + if (timing == MMC_TIMING_MMC_HS400) { + sdhci_am654->itap_del_ena[timing] = 0x1; + sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel[timing - 1]; + } + + sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing], + sdhci_am654->itap_del_ena[timing]); + } else { sdhci_am654_setup_delay_chain(sdhci_am654, timing); + sdhci_am654->dll_enable = false; + } regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, sdhci_am654->clkbuf_sel); @@ -306,16 +325,29 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); unsigned char timing = host->mmc->ios.timing; u32 otap_del_sel; + u32 itap_del_ena; + u32 itap_del_sel; u32 mask, val; - /* Setup DLL Output TAP delay */ + /* Setup Output TAP delay */ otap_del_sel = sdhci_am654->otap_del_sel[timing]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; val = (0x1 << OTAPDLYENA_SHIFT) | (otap_del_sel << OTAPDLYSEL_SHIFT); - regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); + /* Setup Input TAP delay */ + itap_del_ena = sdhci_am654->itap_del_ena[timing]; + itap_del_sel = sdhci_am654->itap_del_sel[timing]; + + mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK; + val |= (itap_del_ena << ITAPDLYENA_SHIFT) | + (itap_del_sel << ITAPDLYSEL_SHIFT); + + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, + 1 << ITAPCHGWIN_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, sdhci_am654->clkbuf_sel); @@ -408,40 +440,105 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) return 0; } -#define ITAP_MAX 32 +#define ITAPDLY_LENGTH 32 +#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1) + +static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window + *fail_window, u8 num_fails, bool circular_buffer) +{ + u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0; + u8 first_fail_start = 0, last_fail_end = 0; + struct device *dev = mmc_dev(host->mmc); + struct window pass_window = {0, 0, 0}; + int prev_fail_end = -1; + u8 i; + + if (!num_fails) + return ITAPDLY_LAST_INDEX >> 1; + + if (fail_window->length == ITAPDLY_LENGTH) { + dev_err(dev, "No passing ITAPDLY, return 0\n"); + return 0; + } + + first_fail_start = fail_window->start; + last_fail_end = fail_window[num_fails - 1].end; + + for (i = 0; i < num_fails; i++) { + start_fail = fail_window[i].start; + end_fail = fail_window[i].end; + pass_length = start_fail - (prev_fail_end + 1); + + if (pass_length > pass_window.length) { + pass_window.start = prev_fail_end + 1; + pass_window.length = pass_length; + } + prev_fail_end = end_fail; + } + + if (!circular_buffer) + pass_length = ITAPDLY_LAST_INDEX - last_fail_end; + else + pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start; + + if (pass_length > pass_window.length) { + pass_window.start = last_fail_end + 1; + pass_window.length = pass_length; + } + + if (!circular_buffer) + itap = pass_window.start + (pass_window.length >> 1); + else + itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH; + + return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap; +} + static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, u32 opcode) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); - int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len; - u32 itap; + unsigned char timing = host->mmc->ios.timing; + struct window fail_window[ITAPDLY_LENGTH]; + u8 curr_pass, itap; + u8 fail_index = 0; + u8 prev_pass = 1; + + memset(fail_window, 0, sizeof(fail_window)); /* Enable ITAPDLY */ - regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK, - 1 << ITAPDLYENA_SHIFT); + sdhci_am654->itap_del_ena[timing] = 0x1; + + for (itap = 0; itap < ITAPDLY_LENGTH; itap++) { + sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]); - for (itap = 0; itap < ITAP_MAX; itap++) { - sdhci_am654_write_itapdly(sdhci_am654, itap); + curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL); - cur_val = !mmc_send_tuning(host->mmc, opcode, NULL); - if (cur_val && !prev_val) - pass_window = itap; + if (!curr_pass && prev_pass) + fail_window[fail_index].start = itap; - if (!cur_val) - fail_len++; + if (!curr_pass) { + fail_window[fail_index].end = itap; + fail_window[fail_index].length++; + } + + if (curr_pass && !prev_pass) + fail_index++; - prev_val = cur_val; + prev_pass = curr_pass; } - /* - * Having determined the length of the failing window and start of - * the passing window calculate the length of the passing window and - * set the final value halfway through it considering the range as a - * circular buffer - */ - pass_len = ITAP_MAX - fail_len; - itap = (pass_window + (pass_len >> 1)) % ITAP_MAX; - sdhci_am654_write_itapdly(sdhci_am654, itap); + + if (fail_window[fail_index].length != 0) + fail_index++; + + itap = sdhci_am654_calculate_itap(host, fail_window, fail_index, + sdhci_am654->dll_enable); + + sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]); + + /* Save ITAPDLY */ + sdhci_am654->itap_del_sel[timing] = itap; return 0; } @@ -590,9 +687,12 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, host->mmc->caps2 &= ~td[i].capability; } - if (td[i].itap_binding) - device_property_read_u32(dev, td[i].itap_binding, - &sdhci_am654->itap_del_sel[i]); + if (td[i].itap_binding) { + ret = device_property_read_u32(dev, td[i].itap_binding, + &sdhci_am654->itap_del_sel[i]); + if (!ret) + sdhci_am654->itap_del_ena[i] = 0x1; + } } return 0; diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 0ab5433f6cf6f2..cddd9e3010ee16 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -2667,29 +2667,10 @@ static struct sdio_driver ath10k_sdio_driver = { .probe = ath10k_sdio_probe, .remove = ath10k_sdio_remove, .drv = { - .owner = THIS_MODULE, .pm = ATH10K_SDIO_PM_OPS, }, }; - -static int __init ath10k_sdio_init(void) -{ - int ret; - - ret = sdio_register_driver(&ath10k_sdio_driver); - if (ret) - pr_err("sdio driver registration failed: %d\n", ret); - - return ret; -} - -static void __exit ath10k_sdio_exit(void) -{ - sdio_unregister_driver(&ath10k_sdio_driver); -} - -module_init(ath10k_sdio_init); -module_exit(ath10k_sdio_exit); +module_sdio_driver(ath10k_sdio_driver); MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN SDIO devices"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 00679a990e3dac..13391c2d82aae2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1238,7 +1238,6 @@ static struct sdio_driver brcmf_sdmmc_driver = { .name = KBUILD_MODNAME, .id_table = brcmf_sdmmc_ids, .drv = { - .owner = THIS_MODULE, .pm = pm_sleep_ptr(&brcmf_sdio_pm_ops), .coredump = brcmf_dev_coredump, }, diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 8b86f95fa32e26..d8bd3977573818 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -979,7 +979,6 @@ static struct sdio_driver mwifiex_sdio = { .probe = mwifiex_sdio_probe, .remove = mwifiex_sdio_remove, .drv = { - .owner = THIS_MODULE, .coredump = mwifiex_sdio_coredump, .pm = &mwifiex_sdio_pm_ops, } diff --git a/drivers/net/wireless/silabs/wfx/bus_sdio.c b/drivers/net/wireless/silabs/wfx/bus_sdio.c index 909d5f346a01b0..f290eecde773fb 100644 --- a/drivers/net/wireless/silabs/wfx/bus_sdio.c +++ b/drivers/net/wireless/silabs/wfx/bus_sdio.c @@ -267,7 +267,6 @@ struct sdio_driver wfx_sdio_driver = { .probe = wfx_sdio_probe, .remove = wfx_sdio_remove, .drv = { - .owner = THIS_MODULE, .of_match_table = wfx_sdio_of_match, } }; diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 478855b8e406f9..fed1f5f4a8d333 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -106,7 +106,10 @@ struct sdio_driver { .class = (dev_class), \ .vendor = SDIO_ANY_ID, .device = SDIO_ANY_ID -extern int sdio_register_driver(struct sdio_driver *); +/* use a macro to avoid include chaining to get THIS_MODULE */ +#define sdio_register_driver(drv) \ + __sdio_register_driver(drv, THIS_MODULE) +extern int __sdio_register_driver(struct sdio_driver *, struct module *); extern void sdio_unregister_driver(struct sdio_driver *); /** |