From 89dfb7cc1a9dc9e7f90e822cb402d3f848f1650a Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Mon, 29 Jun 2026 13:05:31 +0530 Subject: [PATCH 01/35] dt-bindings: mmc: sdhci-msm: add ICE phandle On newer Qualcomm SoCs (starting with sc7280/kodiak), ICE is modelled as a dedicated DT node. Add the optional qcom,ice phandle to reference that node from the SDHCI controller. When qcom,ice is present, disallow an embedded ICE register region in the SDHCI node to avoid double modelling. Older SoCs without qcom,ice remain valid. Co-developed-by: Abel Vesa Signed-off-by: Abel Vesa Co-developed-by: Abhinaba Rakshit Signed-off-by: Abhinaba Rakshit Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neeraj Soni Signed-off-by: Kuldeep Singh Signed-off-by: Ulf Hansson --- .../bindings/mmc/qcom,sdhci-msm.yaml | 95 +++++++++++++------ 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/qcom,sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/qcom,sdhci-msm.yaml index bd558a11b792..b3fcc1673c10 100644 --- a/Documentation/devicetree/bindings/mmc/qcom,sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/qcom,sdhci-msm.yaml @@ -145,6 +145,11 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 description: platform specific settings for DLL_CONFIG reg. + qcom,ice: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the Inline Crypto Engine (ICE) hardware block for this controller. + iommus: minItems: 1 maxItems: 8 @@ -198,35 +203,69 @@ allOf: enum: - qcom,sdhci-msm-v4 then: - properties: - reg: - minItems: 2 - items: - - description: Host controller register map - - description: SD Core register map - - description: CQE register map - - description: Inline Crypto Engine register map - reg-names: - minItems: 2 - items: - - const: hc - - const: core - - const: cqhci - - const: ice + if: + required: + - qcom,ice + then: + properties: + reg: + minItems: 2 + items: + - description: Host controller register map + - description: SD Core register map + - description: CQE register map + reg-names: + minItems: 2 + items: + - const: hc + - const: core + - const: cqhci + else: + properties: + reg: + minItems: 2 + items: + - description: Host controller register map + - description: SD Core register map + - description: CQE register map + - description: Inline Crypto Engine register map + reg-names: + minItems: 2 + items: + - const: hc + - const: core + - const: cqhci + - const: ice else: - properties: - reg: - minItems: 1 - items: - - description: Host controller register map - - description: CQE register map - - description: Inline Crypto Engine register map - reg-names: - minItems: 1 - items: - - const: hc - - const: cqhci - - const: ice + if: + required: + - qcom,ice + then: + properties: + reg: + minItems: 1 + items: + - description: Host controller register map + - description: CQE register map + reg-names: + minItems: 1 + items: + - const: hc + - const: cqhci + else: + properties: + reg: + minItems: 1 + items: + - description: Host controller register map + - description: CQE register map + - description: Inline Crypto Engine register map + reg-names: + minItems: 1 + items: + - const: hc + - const: cqhci + - const: ice unevaluatedProperties: false From 3f78a256230bc61002a83cd5ad6995fe44f2addb Mon Sep 17 00:00:00 2001 From: Chanwoo Lee Date: Tue, 2 Jun 2026 18:40:55 +0900 Subject: [PATCH 02/35] mmc: core: Remove unused buffer allocation in sd_enable_cache() sd_enable_cache() allocates a 512-byte buffer that is never used, hence let's just drop it. Signed-off-by: Chanwoo Lee Reviewed-by: Avri Altman Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/sd.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 948948ca9b4a..c763efb10f64 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1379,15 +1379,10 @@ out: static int sd_enable_cache(struct mmc_card *card) { - u8 *reg_buf; int err; card->ext_perf.feature_enabled &= ~SD_EXT_PERF_CACHE; - reg_buf = kzalloc(512, GFP_KERNEL); - if (!reg_buf) - return -ENOMEM; - /* * Set Cache Enable at bit 0 in the performance enhancement register at * 260 bytes offset. @@ -1397,7 +1392,7 @@ static int sd_enable_cache(struct mmc_card *card) if (err) { pr_warn("%s: error %d writing Cache Enable bit\n", mmc_hostname(card->host), err); - goto out; + return err; } err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false, @@ -1405,8 +1400,6 @@ static int sd_enable_cache(struct mmc_card *card) if (!err) card->ext_perf.feature_enabled |= SD_EXT_PERF_CACHE; -out: - kfree(reg_buf); return err; } From e8a80efa630ee9ba0c565b4401d798e3481f4ab5 Mon Sep 17 00:00:00 2001 From: Chanwoo Lee Date: Wed, 24 Jun 2026 11:19:03 +0900 Subject: [PATCH 03/35] mmc: cqhci: Remove unused intmask parameter from cqhci_irq() The intmask parameter of cqhci_irq() is never used within the function body. The function reads the CQHCI interrupt status directly via cqhci_readl() and processes interrupts independently of the SDHCI intmask value passed by callers. Signed-off-by: Chanwoo Lee Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/cqhci-core.c | 3 +-- drivers/mmc/host/cqhci.h | 3 +-- drivers/mmc/host/mtk-sd.c | 2 +- drivers/mmc/host/sdhci-brcmstb.c | 2 +- drivers/mmc/host/sdhci-esdhc-imx.c | 2 +- drivers/mmc/host/sdhci-msm.c | 2 +- drivers/mmc/host/sdhci-of-arasan.c | 2 +- drivers/mmc/host/sdhci-of-dwcmshc.c | 2 +- drivers/mmc/host/sdhci-pci-core.c | 2 +- drivers/mmc/host/sdhci-pci-gli.c | 2 +- drivers/mmc/host/sdhci-tegra.c | 2 +- drivers/mmc/host/sdhci_am654.c | 2 +- 12 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index 178277d90c31..98ceb0b9a6d1 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -819,8 +819,7 @@ static void cqhci_finish_mrq(struct mmc_host *mmc, unsigned int tag) mmc_cqe_request_done(mmc, mrq); } -irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, - int data_error) +irqreturn_t cqhci_irq(struct mmc_host *mmc, int cmd_error, int data_error) { u32 status; unsigned long tag = 0, comp_status; diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 3668856531c1..8fbbc48c3f85 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -315,8 +315,7 @@ static inline u32 cqhci_readl(struct cqhci_host *host, int reg) struct platform_device; -irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, - int data_error); +irqreturn_t cqhci_irq(struct mmc_host *mmc, int cmd_error, int data_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); diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index b2680cc054bd..01ea3adbdf3b 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1805,7 +1805,7 @@ static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts) cmd_err, dat_err, intsts); } - return cqhci_irq(mmc, 0, cmd_err, dat_err); + return cqhci_irq(mmc, cmd_err, dat_err); } static irqreturn_t msdc_irq(int irq, void *dev_id) diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index 57e45951644e..1de2f05fd958 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -430,7 +430,7 @@ static u32 sdhci_brcmstb_cqhci_irq(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 18ecddd6df6f..d0fa83f67a80 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1503,7 +1503,7 @@ static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 0882ce74e0c9..ceed47ccfda8 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2165,7 +2165,7 @@ static u32 sdhci_msm_cqe_irq(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 785d3acb18c5..4ca73e7d799e 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -555,7 +555,7 @@ static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index eef53455b8ee..4c5fa6a6931d 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -624,7 +624,7 @@ static u32 dwcmshc_cqe_irq_handler(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index c347fac24515..b121d896a804 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -215,7 +215,7 @@ static u32 sdhci_cqhci_irq(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 6e4084407662..b55618566d65 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -1760,7 +1760,7 @@ static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 820ce4dae58b..221e48b59f48 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1280,7 +1280,7 @@ static u32 sdhci_tegra_cqhci_irq(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index d235b0aecfdb..2a27db2f558b 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -462,7 +462,7 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; - cqhci_irq(host->mmc, intmask, cmd_error, data_error); + cqhci_irq(host->mmc, cmd_error, data_error); return 0; } From cb3fcb8d118b874178251d1f02613f60d25e4ddc Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 3 Jun 2026 10:39:35 +0200 Subject: [PATCH 04/35] mmc: dw_mmc: stop and complete DMA also in STATE_DATA_BUSY state When transfer was stopped in STATE_DATA_BUSY state, there was no call to dma_ops->cleanup function, so the DMA mapped buffer was never properly unmapped. Fix this by calling dw_mci_stop_dma() function also in that state to ensure proper cleanup call when DMA transfer was used. Signed-off-by: Marek Szyprowski Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d734d010444d..cf5cecc5491d 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2057,6 +2057,7 @@ static void dw_mci_work_func(struct work_struct *t) } dw_mci_stop_fault_timer(host); + dw_mci_stop_dma(host); host->data = NULL; set_bit(EVENT_DATA_COMPLETE, &host->completed_events); err = dw_mci_data_complete(host, data); From ab9c44bbf6d7df22518ea66329595023c00be1bc Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Mon, 8 Jun 2026 19:54:51 -0700 Subject: [PATCH 05/35] ARM: PXA: remove remnants of PXA93x support Support for PXA93x chips was removed in commit d711b8a2987a ("ARM: pxa: remove pxa93x support"), but some code to handle them remains. Remove it. Discovered while searching for CONFIG_* symbols referenced in code but not defined in any Kconfig file. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Ulf Hansson --- drivers/mmc/host/pxamci.c | 3 +- include/linux/soc/pxa/cpu.h | 56 ------------------------------------- 2 files changed, 1 insertion(+), 58 deletions(-) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index b5ea058ed467..f8427f071c00 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -43,8 +43,7 @@ #define NR_SG 1 #define CLKRT_OFF (~0) -#define mmc_has_26MHz() (cpu_is_pxa300() || cpu_is_pxa310() \ - || cpu_is_pxa935()) +#define mmc_has_26MHz() (cpu_is_pxa300() || cpu_is_pxa310()) struct pxamci_host { struct mmc_host *mmc; diff --git a/include/linux/soc/pxa/cpu.h b/include/linux/soc/pxa/cpu.h index 5782450ee45c..38bacdae684f 100644 --- a/include/linux/soc/pxa/cpu.h +++ b/include/linux/soc/pxa/cpu.h @@ -46,14 +46,6 @@ * PXA31x A2 0x69056892 0x2E649013 * PXA32x B1 0x69056825 0x5E642013 * PXA32x B2 0x69056826 0x6E642013 - * - * PXA930 B0 0x69056835 0x5E643013 - * PXA930 B1 0x69056837 0x7E643013 - * PXA930 B2 0x69056838 0x8E643013 - * - * PXA935 A0 0x56056931 0x1E653013 - * PXA935 B0 0x56056936 0x6E653013 - * PXA935 B1 0x56056938 0x8E653013 */ #ifdef CONFIG_PXA25x #define __cpu_is_pxa210(id) \ @@ -126,26 +118,6 @@ #define __cpu_is_pxa320(id) (0) #endif -#ifdef CONFIG_CPU_PXA930 -#define __cpu_is_pxa930(id) \ - ({ \ - unsigned int _id = (id) >> 4 & 0xfff; \ - _id == 0x683; \ - }) -#else -#define __cpu_is_pxa930(id) (0) -#endif - -#ifdef CONFIG_CPU_PXA935 -#define __cpu_is_pxa935(id) \ - ({ \ - unsigned int _id = (id) >> 4 & 0xfff; \ - _id == 0x693; \ - }) -#else -#define __cpu_is_pxa935(id) (0) -#endif - #define cpu_is_pxa210() \ ({ \ __cpu_is_pxa210(read_cpuid_id()); \ @@ -186,18 +158,6 @@ __cpu_is_pxa320(read_cpuid_id()); \ }) -#define cpu_is_pxa930() \ - ({ \ - __cpu_is_pxa930(read_cpuid_id()); \ - }) - -#define cpu_is_pxa935() \ - ({ \ - __cpu_is_pxa935(read_cpuid_id()); \ - }) - - - /* * CPUID Core Generation Bit * <= 0x2 for pxa21x/pxa25x/pxa26x/pxa27x @@ -218,22 +178,11 @@ __cpu_is_pxa300(id) \ || __cpu_is_pxa310(id) \ || __cpu_is_pxa320(id) \ - || __cpu_is_pxa93x(id); \ }) #else #define __cpu_is_pxa3xx(id) (0) #endif -#if defined(CONFIG_CPU_PXA930) || defined(CONFIG_CPU_PXA935) -#define __cpu_is_pxa93x(id) \ - ({ \ - __cpu_is_pxa930(id) \ - || __cpu_is_pxa935(id); \ - }) -#else -#define __cpu_is_pxa93x(id) (0) -#endif - #define cpu_is_pxa2xx() \ ({ \ __cpu_is_pxa2xx(read_cpuid_id()); \ @@ -244,9 +193,4 @@ __cpu_is_pxa3xx(read_cpuid_id()); \ }) -#define cpu_is_pxa93x() \ - ({ \ - __cpu_is_pxa93x(read_cpuid_id()); \ - }) - #endif From 86e23edba75867554b19dc407263035cb244484c Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 10 Jun 2026 00:13:00 +1000 Subject: [PATCH 06/35] mmc: sdhci-esdhc-mcf: do not use readl()/writel() on ColdFire The implementation of the readX() and writeX() family of IO access functions is non-standard on ColdFire platforms. They check the supplied IO address and will return either big or little endian results based on that check. This is non-standard, they are expected to always return little-endian byte ordered data. Unfortunately this behavior also means that ioreadX()/iowroteX() and their big-endian counter parts ioreadXbe()/iowriteXbe() are wrong. This is now in the process of being cleaned up and fixed. Change the use of the readX() and writeX() access functions in this driver to use the recently defined specific ColdFire internal SoC hardware IO access functions mcf_read8()/mcf_read16()/mcf_read32() and mcf_write8()/mcf_write16()/mcf_write32(). There is no functional change to the driver. Though it does have the effect of making the IO access slightly more efficient, since there is no longer a need to do the address check at every register access. Signed-off-by: Greg Ungerer Tested-by: Angelo Dureghello Acked-by: Angelo Dureghello Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-mcf.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-mcf.c b/drivers/mmc/host/sdhci-esdhc-mcf.c index 375fce5639d7..6853521e8b2c 100644 --- a/drivers/mmc/host/sdhci-esdhc-mcf.c +++ b/drivers/mmc/host/sdhci-esdhc-mcf.c @@ -55,7 +55,7 @@ static inline void esdhc_clrset_be(struct sdhci_host *host, if (reg == SDHCI_HOST_CONTROL) val |= ESDHC_PROCTL_D3CD; - writel((readl(base) & ~mask) | val, base); + mcf_write32((mcf_read32(base) & ~mask) | val, base); } /* @@ -71,7 +71,7 @@ static void esdhc_mcf_writeb_be(struct sdhci_host *host, u8 val, int reg) if (reg == SDHCI_HOST_CONTROL) { u32 host_ctrl = ESDHC_DEFAULT_HOST_CONTROL; u8 dma_bits = (val & SDHCI_CTRL_DMA_MASK) >> 3; - u8 tmp = readb(host->ioaddr + SDHCI_HOST_CONTROL + 1); + u8 tmp = mcf_read8(host->ioaddr + SDHCI_HOST_CONTROL + 1); tmp &= ~0x03; tmp |= dma_bits; @@ -82,12 +82,12 @@ static void esdhc_mcf_writeb_be(struct sdhci_host *host, u8 val, int reg) */ host_ctrl |= val; host_ctrl |= (dma_bits << 8); - writel(host_ctrl, host->ioaddr + SDHCI_HOST_CONTROL); + mcf_write32(host_ctrl, host->ioaddr + SDHCI_HOST_CONTROL); return; } - writel((readl(base) & mask) | (val << shift), base); + mcf_write32((mcf_read32(base) & mask) | (val << shift), base); } static void esdhc_mcf_writew_be(struct sdhci_host *host, u16 val, int reg) @@ -110,24 +110,24 @@ static void esdhc_mcf_writew_be(struct sdhci_host *host, u16 val, int reg) * As for the fsl driver, * we have to set the mode in a single write here. */ - writel(val << 16 | mcf_data->aside, + mcf_write32(val << 16 | mcf_data->aside, host->ioaddr + SDHCI_TRANSFER_MODE); return; } - writel((readl(base) & mask) | (val << shift), base); + mcf_write32((mcf_read32(base) & mask) | (val << shift), base); } static void esdhc_mcf_writel_be(struct sdhci_host *host, u32 val, int reg) { - writel(val, host->ioaddr + reg); + mcf_write32(val, host->ioaddr + reg); } static u8 esdhc_mcf_readb_be(struct sdhci_host *host, int reg) { if (reg == SDHCI_HOST_CONTROL) { u8 __iomem *base = host->ioaddr + (reg & ~3); - u16 val = readw(base + 2); + u16 val = mcf_read16(base + 2); u8 dma_bits = (val >> 5) & SDHCI_CTRL_DMA_MASK; u8 host_ctrl = val & 0xff; @@ -137,7 +137,7 @@ static u8 esdhc_mcf_readb_be(struct sdhci_host *host, int reg) return host_ctrl; } - return readb(host->ioaddr + (reg ^ 0x3)); + return mcf_read8(host->ioaddr + (reg ^ 0x3)); } static u16 esdhc_mcf_readw_be(struct sdhci_host *host, int reg) @@ -149,14 +149,14 @@ static u16 esdhc_mcf_readw_be(struct sdhci_host *host, int reg) if (reg == SDHCI_HOST_VERSION) reg -= 2; - return readw(host->ioaddr + (reg ^ 0x2)); + return mcf_read16(host->ioaddr + (reg ^ 0x2)); } static u32 esdhc_mcf_readl_be(struct sdhci_host *host, int reg) { u32 val; - val = readl(host->ioaddr + reg); + val = mcf_read32(host->ioaddr + reg); /* * RM (25.3.9) sd pin clock must never exceed 25Mhz. @@ -245,7 +245,7 @@ static void esdhc_mcf_pltfm_set_clock(struct sdhci_host *host, * fvco = fsys * outdvi1 + 1 * fshdc = fvco / outdiv3 + 1 */ - temp = readl(pll_dr); + temp = mcf_read32(pll_dr); fsys = pltfm_host->clock; fvco = fsys * ((temp & 0x1f) + 1); fesdhc = fvco / (((temp >> 10) & 0x1f) + 1); From 1f8c98dc954debe776ee81f889a73b5522f2e5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 10 Jun 2026 10:41:04 +0200 Subject: [PATCH 07/35] mmc: wbsd: Drop unused assignment of pnp_device_id driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver explicitly sets the .driver_data member of struct pnp_device_id to zero without relying on that value. Drop these unused assignments. While touching this array use a named initializer for .id and simplify the list terminator. This patch doesn't modify the compiled array, only its representation in source form benefits. The former was confirmed with an x86 build. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Ulf Hansson --- drivers/mmc/host/wbsd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index c33a0223ce7f..51706898239e 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -52,9 +52,9 @@ #ifdef CONFIG_PNP static const struct pnp_device_id pnp_dev_table[] = { - { "WEC0517", 0 }, - { "WEC0518", 0 }, - { "", 0 }, + { .id = "WEC0517" }, + { .id = "WEC0518" }, + { } }; MODULE_DEVICE_TABLE(pnp, pnp_dev_table); From e29e650077e01dddf69bc8fac31e0cd60043aa7c Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Tue, 23 Jun 2026 14:11:12 +0800 Subject: [PATCH 08/35] mmc: moxart: report DMA completion timeout moxart_transfer_dma() waits for the DMA completion but ignores wait_for_completion_interruptible_timeout(). It then unconditionally reports the full transfer length in data->bytes_xfered. Terminate the DMA channel and set data->error when the wait is interrupted or times out. Only report host->data_len as transferred after the completion is observed. Signed-off-by: Pengpeng Hou Signed-off-by: Ulf Hansson --- drivers/mmc/host/moxart-mmc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index 3dd8f232052f..4a4d8b19b18c 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -264,6 +264,7 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host) u32 len, dir_slave; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *dma_chan; + long timeout; if (host->data_len == data->bytes_xfered) return; @@ -296,11 +297,17 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host) dma_async_issue_pending(dma_chan); } - wait_for_completion_interruptible_timeout(&host->dma_complete, - host->timeout); + timeout = wait_for_completion_interruptible_timeout(&host->dma_complete, + host->timeout); + if (timeout <= 0) { + dmaengine_terminate_sync(dma_chan); + data->error = timeout ?: -ETIMEDOUT; + goto unmap; + } data->bytes_xfered = host->data_len; +unmap: dma_unmap_sg(dma_chan->device->dev, data->sg, data->sg_len, mmc_get_dma_dir(data)); From e82628c9153d3091623b4879c8c3ef5cd9f4fadc Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Thu, 18 Jun 2026 17:02:09 -0500 Subject: [PATCH 09/35] MAINTAINERS: Add myself to maintain TI AM654 SDHCI host drver Since actively working on TI AM654 SDHCI driver, adding myself as a maintainer of this driver. Signed-off-by: Judith Mendez Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4a8b0fd665ce..6a0996faa091 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26957,6 +26957,13 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git F: drivers/media/platform/ti/am437x/ +TI AM654 SDHCI DRIVER +M: Judith Mendez +L: linux-mmc@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/mmc/sdhci-am654.yaml +F: drivers/mmc/host/sdhci_am654.c + TI BANDGAP AND THERMAL DRIVER M: Eduardo Valentin M: Keerthy From 0aae2c73175821a71c0e20607f8e333be5b71940 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 22 Jun 2026 15:50:36 +0100 Subject: [PATCH 10/35] mmc: cqhci: fix to missed endian conversions Fix two places where the wrong type or conversion of little-endian types to fix the following sparse warnings: drivers/mmc/host/cqhci-core.c:487:15: warning: incorrect type in assignment (different base types) drivers/mmc/host/cqhci-core.c:487:15: expected restricted __le32 [usertype] drivers/mmc/host/cqhci-core.c:487:15: got int drivers/mmc/host/cqhci-core.c:566:19: warning: incorrect type in assignment (different base types) drivers/mmc/host/cqhci-core.c:566:19: expected unsigned long long [usertype] *task_desc drivers/mmc/host/cqhci-core.c:566:19: got restricted __le64 [usertype] * Signed-off-by: Ben Dooks Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/cqhci-core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index 98ceb0b9a6d1..a466cd88b043 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -484,11 +484,11 @@ void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, { __le32 *attr = (__le32 __force *)desc; - *attr = (CQHCI_VALID(1) | - CQHCI_END(end ? 1 : 0) | - CQHCI_INT(0) | - CQHCI_ACT(0x4) | - CQHCI_DAT_LENGTH(len)); + *attr = cpu_to_le32((CQHCI_VALID(1) | + CQHCI_END(end ? 1 : 0) | + CQHCI_INT(0) | + CQHCI_ACT(0x4) | + CQHCI_DAT_LENGTH(len))); if (dma64) { __le64 *dataddr = (__le64 __force *)(desc + 4); @@ -542,7 +542,7 @@ static int cqhci_prep_tran_desc(struct mmc_request *mrq, static void cqhci_prep_dcmd_desc(struct mmc_host *mmc, struct mmc_request *mrq) { - u64 *task_desc = NULL; + __le64 *task_desc = NULL; u64 data = 0; u8 resp_type; u8 *desc; @@ -574,7 +574,7 @@ static void cqhci_prep_dcmd_desc(struct mmc_host *mmc, CQHCI_CMD_TIMING(timing) | CQHCI_RESP_TYPE(resp_type)); if (cq_host->ops->update_dcmd_desc) cq_host->ops->update_dcmd_desc(mmc, mrq, &data); - *task_desc |= data; + *task_desc |= cpu_to_le64(data); desc = (u8 *)task_desc; pr_debug("%s: cqhci: dcmd: cmd: %d timing: %d resp: %d\n", mmc_hostname(mmc), mrq->cmd->opcode, timing, resp_type); From f13ca4f2b01ed38765ded9ea53f33fa16addd497 Mon Sep 17 00:00:00 2001 From: Eduard Bostina Date: Wed, 24 Jun 2026 16:31:11 +0000 Subject: [PATCH 11/35] dt-bindings: mmc: Convert TI OMAP2420 MMC to DT schema Convert the Texas Instruments MMC host controller bindings to DT schema. Note that the OMAP2420 driver will not work with OMAP2430 or later omaps. Please see the OMAP HSMMC driver for current OMAPs. Signed-off-by: Eduard Bostina Reviewed-by: Krzysztof Kozlowski Signed-off-by: Ulf Hansson --- .../bindings/mmc/ti,omap2420-mmc.yaml | 60 +++++++++++++++++++ .../devicetree/bindings/mmc/ti-omap.txt | 26 -------- 2 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 Documentation/devicetree/bindings/mmc/ti,omap2420-mmc.yaml delete mode 100644 Documentation/devicetree/bindings/mmc/ti-omap.txt diff --git a/Documentation/devicetree/bindings/mmc/ti,omap2420-mmc.yaml b/Documentation/devicetree/bindings/mmc/ti,omap2420-mmc.yaml new file mode 100644 index 000000000000..794d5ec0b58e --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/ti,omap2420-mmc.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mmc/ti,omap2420-mmc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments MMC host controller for OMAP1 and 2420 + +maintainers: + - Eduard Bostina + +description: | + The MMC Host Controller on TI OMAP1 and 2420 family provides + an interface for MMC, SD, and SDIO types of memory cards. + +allOf: + - $ref: /schemas/mmc/mmc-controller.yaml# + +properties: + compatible: + const: ti,omap2420-mmc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + ti,hwmods: + description: | + Name of the hwmod associated to the MMC controller. Must be + "msdi" where n is the controller instance starting from 1. + $ref: /schemas/types.yaml#/definitions/string + pattern: "^msdi([1-9]|[1-9][0-9]+)$" + + dmas: + maxItems: 2 + + dma-names: + items: + - const: tx + - const: rx + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + mmc@4809c000 { + compatible = "ti,omap2420-mmc"; + ti,hwmods = "msdi1"; + reg = <0x4809c000 0x80>; + interrupts = <83>; + dmas = <&sdma 61 &sdma 62>; + dma-names = "tx", "rx"; + }; diff --git a/Documentation/devicetree/bindings/mmc/ti-omap.txt b/Documentation/devicetree/bindings/mmc/ti-omap.txt deleted file mode 100644 index 02fd31cf361d..000000000000 --- a/Documentation/devicetree/bindings/mmc/ti-omap.txt +++ /dev/null @@ -1,26 +0,0 @@ -* TI MMC host controller for OMAP1 and 2420 - -The MMC Host Controller on TI OMAP1 and 2420 family provides -an interface for MMC, SD, and SDIO types of memory cards. - -This file documents differences between the core properties described -by mmc.txt and the properties used by the omap mmc driver. - -Note that this driver will not work with omap2430 or later omaps, -please see the omap hsmmc driver for the current omaps. - -Required properties: -- compatible: Must be "ti,omap2420-mmc", for OMAP2420 controllers -- ti,hwmods: For 2420, must be "msdi", where n is controller - instance starting 1 - -Examples: - - msdi1: mmc@4809c000 { - compatible = "ti,omap2420-mmc"; - ti,hwmods = "msdi1"; - reg = <0x4809c000 0x80>; - interrupts = <83>; - dmas = <&sdma 61 &sdma 62>; - dma-names = "tx", "rx"; - }; From 33b55cd1d3988fba909b422070fdfc5b388abade Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Mon, 29 Jun 2026 15:25:07 +0800 Subject: [PATCH 12/35] mmc: litex_mmc: Set width from linux request Previously, the litex_mmc driver force the 4 bits bus width. This means that the gateware with 1 bit bus width is not fit. However, litesdcard does support setting bus width, which make the 1 bit bus width gateware possible to be used. Add logic for setting bus width in the set_ios() function. Signed-off-by: Inochi Amaoto Signed-off-by: Ulf Hansson --- drivers/mmc/host/litex_mmc.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c index 06a6f24702e0..2e1a1650e132 100644 --- a/drivers/mmc/host/litex_mmc.c +++ b/drivers/mmc/host/litex_mmc.c @@ -28,6 +28,7 @@ #define LITEX_PHY_CLOCKERDIV 0x04 #define LITEX_PHY_INITIALIZE 0x08 #define LITEX_PHY_WRITESTATUS 0x0C +#define LITEX_PHY_SETTINGS 0x18 #define LITEX_CORE_CMDARG 0x00 #define LITEX_CORE_CMDCMD 0x04 #define LITEX_CORE_CMDSND 0x08 @@ -71,6 +72,10 @@ #define SD_INIT_DELAY_US 1000 #define SD_INIT_CLK_HZ 400000 +#define SD_PHY_SPEED_1X 0 +#define SD_PHY_SPEED_4X 1 +#define SD_PHY_SPEED_8X 2 + #define SDIRQ_CARD_DETECT 1 #define SDIRQ_SD_TO_MEM_DONE 2 #define SDIRQ_MEM_TO_SD_DONE 4 @@ -95,6 +100,8 @@ struct litex_mmc_host { unsigned int ref_clk; unsigned int sd_clk; + u8 width; + u32 resp[4]; u16 rca; @@ -450,6 +457,24 @@ static void litex_mmc_setclk(struct litex_mmc_host *host, unsigned int freq) static void litex_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct litex_mmc_host *host = mmc_priv(mmc); + unsigned int bus_width = SD_PHY_SPEED_1X; + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + bus_width = SD_PHY_SPEED_1X; + break; + case MMC_BUS_WIDTH_4: + bus_width = SD_PHY_SPEED_4X; + break; + case MMC_BUS_WIDTH_8: + bus_width = SD_PHY_SPEED_8X; + break; + } + + if (host->width != ios->bus_width) { + litex_write8(host->sdphy + LITEX_PHY_SETTINGS, bus_width); + host->width = ios->bus_width; + } /* * The SD specification requires at least 74 idle clocks before CMD0. @@ -462,13 +487,6 @@ static void litex_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) return; } - /* - * NOTE: Ignore any ios->bus_width updates; they occur right after - * the mmc core sends its own acmd6 bus-width change notification, - * which is redundant since we snoop on the command flow and inject - * an early acmd6 before the first data transfer command is sent! - */ - /* Update sd_clk */ if (ios->clock != host->sd_clk) litex_mmc_setclk(host, ios->clock); @@ -554,6 +572,7 @@ static int litex_mmc_probe(struct platform_device *pdev) */ host->is_bus_width_set = false; host->app_cmd = false; + host->width = MMC_BUS_WIDTH_1; /* LiteSDCard can support 64-bit DMA addressing */ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); @@ -586,6 +605,9 @@ static int litex_mmc_probe(struct platform_device *pdev) litex_write8(host->sdreader + LITEX_BLK2MEM_ENA, 0); litex_write8(host->sdwriter + LITEX_MEM2BLK_ENA, 0); + /* Ensure the litex is at bus width x1 */ + litex_write8(host->sdphy + LITEX_PHY_SETTINGS, SD_PHY_SPEED_1X); + init_completion(&host->cmd_done); ret = litex_mmc_irq_init(pdev, host); if (ret) From a303ea393319667fc6892cea4717abf946a478d8 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Mon, 29 Jun 2026 15:25:08 +0800 Subject: [PATCH 13/35] mmc: litex_mmc: Remove unused logic for the fixed bus width As the set_ios() function in litex_mmc driver does support setting bus width, it is not necessary to leave the logic for fixed bus width. Clean up these unneeded code. Signed-off-by: Inochi Amaoto Signed-off-by: Ulf Hansson --- drivers/mmc/host/litex_mmc.c | 95 ++---------------------------------- 1 file changed, 3 insertions(+), 92 deletions(-) diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c index 2e1a1650e132..332fef8b6646 100644 --- a/drivers/mmc/host/litex_mmc.c +++ b/drivers/mmc/host/litex_mmc.c @@ -103,10 +103,6 @@ struct litex_mmc_host { u8 width; u32 resp[4]; - u16 rca; - - bool is_bus_width_set; - bool app_cmd; }; static int litex_mmc_sdcard_wait_done(void __iomem *reg, struct device *dev) @@ -171,11 +167,6 @@ static int litex_mmc_send_cmd(struct litex_mmc_host *host, host->sdcore + LITEX_CORE_CMDRSP, 0x10); } - if (!host->app_cmd && cmd == SD_SEND_RELATIVE_ADDR) - host->rca = (host->resp[3] >> 16); - - host->app_cmd = (cmd == MMC_APP_CMD); - if (transfer == SD_CTL_DATA_XFER_NONE) return ret; /* OK from prior litex_mmc_sdcard_wait_done() */ @@ -197,51 +188,6 @@ static int litex_mmc_send_cmd(struct litex_mmc_host *host, return ret; } -static int litex_mmc_send_app_cmd(struct litex_mmc_host *host) -{ - return litex_mmc_send_cmd(host, MMC_APP_CMD, host->rca << 16, - SD_CTL_RESP_SHORT, SD_CTL_DATA_XFER_NONE); -} - -static int litex_mmc_send_set_bus_w_cmd(struct litex_mmc_host *host, u32 width) -{ - return litex_mmc_send_cmd(host, SD_APP_SET_BUS_WIDTH, width, - SD_CTL_RESP_SHORT, SD_CTL_DATA_XFER_NONE); -} - -static int litex_mmc_set_bus_width(struct litex_mmc_host *host) -{ - bool app_cmd_sent; - int ret; - - if (host->is_bus_width_set) - return 0; - - /* Ensure 'app_cmd' precedes 'app_set_bus_width_cmd' */ - app_cmd_sent = host->app_cmd; /* was preceding command app_cmd? */ - if (!app_cmd_sent) { - ret = litex_mmc_send_app_cmd(host); - if (ret) - return ret; - } - - /* LiteSDCard only supports 4-bit bus width */ - ret = litex_mmc_send_set_bus_w_cmd(host, MMC_BUS_WIDTH_4); - if (ret) - return ret; - - /* Re-send 'app_cmd' if necessary */ - if (app_cmd_sent) { - ret = litex_mmc_send_app_cmd(host); - if (ret) - return ret; - } - - host->is_bus_width_set = true; - - return 0; -} - static int litex_mmc_get_cd(struct mmc_host *mmc) { struct litex_mmc_host *host = mmc_priv(mmc); @@ -254,9 +200,6 @@ static int litex_mmc_get_cd(struct mmc_host *mmc) if (ret) return ret; - /* Ensure bus width will be set (again) upon card (re)insertion */ - host->is_bus_width_set = false; - return 0; } @@ -372,39 +315,19 @@ static void litex_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) litex_mmc_response_len(sbc), SD_CTL_DATA_XFER_NONE); if (sbc->error) { - host->is_bus_width_set = false; mmc_request_done(mmc, mrq); return; } } - if (data) { - /* - * LiteSDCard only supports 4-bit bus width; therefore, we MUST - * inject a SET_BUS_WIDTH (acmd6) before the very first data - * transfer, earlier than when the mmc subsystem would normally - * get around to it! - */ - cmd->error = litex_mmc_set_bus_width(host); - if (cmd->error) { - dev_err(dev, "Can't set bus width!\n"); - mmc_request_done(mmc, mrq); - return; - } - + if (data) litex_mmc_do_dma(host, data, &len, &direct, &transfer); - } do { cmd->error = litex_mmc_send_cmd(host, cmd->opcode, cmd->arg, response_len, transfer); } while (cmd->error && retries-- > 0); - if (cmd->error) { - /* Card may be gone; don't assume bus width is still set */ - host->is_bus_width_set = false; - } - if (response_len == SD_CTL_RESP_SHORT) { /* Pull short response fields from appropriate host registers */ cmd->resp[0] = host->resp[3]; @@ -417,13 +340,10 @@ static void litex_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) } /* Send stop-transmission command if required */ - if (stop && (cmd->error || !sbc)) { + if (stop && (cmd->error || !sbc)) stop->error = litex_mmc_send_cmd(host, stop->opcode, stop->arg, litex_mmc_response_len(stop), SD_CTL_DATA_XFER_NONE); - if (stop->error) - host->is_bus_width_set = false; - } if (data) { dma_unmap_sg(dev, data->sg, data->sg_len, @@ -564,14 +484,6 @@ static int litex_mmc_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(clk), "can't get clock\n"); host->ref_clk = clk_get_rate(clk); host->sd_clk = 0; - - /* - * LiteSDCard only supports 4-bit bus width; therefore, we MUST inject - * a SET_BUS_WIDTH (acmd6) before the very first data transfer, earlier - * than when the mmc subsystem would normally get around to it! - */ - host->is_bus_width_set = false; - host->app_cmd = false; host->width = MMC_BUS_WIDTH_1; /* LiteSDCard can support 64-bit DMA addressing */ @@ -632,9 +544,8 @@ static int litex_mmc_probe(struct platform_device *pdev) if (ret) return ret; - /* Force 4-bit bus_width (only width supported by hardware) */ + /* Only drop 8-bit bus_width support */ mmc->caps &= ~MMC_CAP_8_BIT_DATA; - mmc->caps |= MMC_CAP_4_BIT_DATA; /* Set default capabilities */ mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | From 4e9dc8c1ef70c4a31ccf5bd7742a50999e09401d Mon Sep 17 00:00:00 2001 From: Charan Pedumuru Date: Mon, 29 Jun 2026 16:26:39 +0000 Subject: [PATCH 14/35] arm: dts: st: align MMC node names with established convention Rename sdhci@9060000 and sdhci@9080000 nodes to mmc@9060000 and mmc@9080000 in stih407-family.dtsi and update all derived board files atomically to prevent orphaned node overrides. Signed-off-by: Charan Pedumuru Signed-off-by: Ulf Hansson --- arch/arm/boot/dts/st/stih407-family.dtsi | 4 ++-- arch/arm/boot/dts/st/stih410-b2260.dts | 4 ++-- arch/arm/boot/dts/st/stih418-b2199.dts | 4 ++-- arch/arm/boot/dts/st/stih418.dtsi | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/st/stih407-family.dtsi b/arch/arm/boot/dts/st/stih407-family.dtsi index 3e6a0542e3ae..08acba209c56 100644 --- a/arch/arm/boot/dts/st/stih407-family.dtsi +++ b/arch/arm/boot/dts/st/stih407-family.dtsi @@ -596,7 +596,7 @@ status = "disabled"; }; - mmc0: sdhci@9060000 { + mmc0: mmc@9060000 { compatible = "st,sdhci-stih407", "st,sdhci"; status = "disabled"; reg = <0x09060000 0x7ff>, <0x9061008 0x20>; @@ -611,7 +611,7 @@ bus-width = <8>; }; - mmc1: sdhci@9080000 { + mmc1: mmc@9080000 { compatible = "st,sdhci-stih407", "st,sdhci"; status = "disabled"; reg = <0x09080000 0x7ff>; diff --git a/arch/arm/boot/dts/st/stih410-b2260.dts b/arch/arm/boot/dts/st/stih410-b2260.dts index 736b1e059b0a..44048a98648e 100644 --- a/arch/arm/boot/dts/st/stih410-b2260.dts +++ b/arch/arm/boot/dts/st/stih410-b2260.dts @@ -141,14 +141,14 @@ status = "okay"; }; - mmc0: sdhci@9060000 { + mmc0: mmc@9060000 { pinctrl-0 = <&pinctrl_sd0>; bus-width = <4>; status = "okay"; }; /* high speed expansion connector */ - mmc1: sdhci@9080000 { + mmc1: mmc@9080000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stih418-b2199.dts b/arch/arm/boot/dts/st/stih418-b2199.dts index 53ac6c2b7b7d..4ea174597365 100644 --- a/arch/arm/boot/dts/st/stih418-b2199.dts +++ b/arch/arm/boot/dts/st/stih418-b2199.dts @@ -82,11 +82,11 @@ st,i2c-min-sda-pulse-width-us = <5>; }; - mmc1: sdhci@9080000 { + mmc1: mmc@9080000 { status = "okay"; }; - mmc0: sdhci@9060000 { + mmc0: mmc@9060000 { status = "okay"; max-frequency = <200000000>; sd-uhs-sdr50; diff --git a/arch/arm/boot/dts/st/stih418.dtsi b/arch/arm/boot/dts/st/stih418.dtsi index 8fb8b3af5e49..1a5fbbedc8cd 100644 --- a/arch/arm/boot/dts/st/stih418.dtsi +++ b/arch/arm/boot/dts/st/stih418.dtsi @@ -136,7 +136,7 @@ phy-names = "usb"; }; - mmc0: sdhci@9060000 { + mmc0: mmc@9060000 { assigned-clocks = <&clk_s_c0_flexgen CLK_MMC_0>; assigned-clock-parents = <&clk_s_c0_pll1 0>; assigned-clock-rates = <200000000>; From c53d1b813d7b074d053a09473354e13c71a4dcfe Mon Sep 17 00:00:00 2001 From: Charan Pedumuru Date: Mon, 29 Jun 2026 16:26:40 +0000 Subject: [PATCH 15/35] dt-bindings: mmc: st,sdhci: Convert to DT schema Convert STMicroelectronics sdhci-st MMC/SD controller binding from text format to YAML DT schema. Changes during conversion: - Preserve optional 'icn' clock and 'top-mmc-delay' register region via minItems: 1 on their respective properties. - Conditionally require reg-names when two reg entries are present via an allOf if/then block, preventing silent runtime failure in devm_platform_ioremap_resource_byname(). - Constrain max-frequency to enum [200000000, 100000000, 50000000] with a default of 50000000, matching the driver's behaviour in sdhci-st.c. Signed-off-by: Charan Pedumuru Reviewed-by: Rob Herring (Arm) Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/sdhci-st.txt | 110 ------------------ .../devicetree/bindings/mmc/st,sdhci.yaml | 105 +++++++++++++++++ 2 files changed, 105 insertions(+), 110 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mmc/sdhci-st.txt create mode 100644 Documentation/devicetree/bindings/mmc/st,sdhci.yaml diff --git a/Documentation/devicetree/bindings/mmc/sdhci-st.txt b/Documentation/devicetree/bindings/mmc/sdhci-st.txt deleted file mode 100644 index ccf82b4ee838..000000000000 --- a/Documentation/devicetree/bindings/mmc/sdhci-st.txt +++ /dev/null @@ -1,110 +0,0 @@ -* STMicroelectronics sdhci-st MMC/SD controller - -This file documents the differences between the core properties in -Documentation/devicetree/bindings/mmc/mmc.txt and the properties -used by the sdhci-st driver. - -Required properties: -- compatible: Must be "st,sdhci" and it can be compatible to "st,sdhci-stih407" - to set the internal glue logic used for configuring the MMC - subsystem (mmcss) inside the FlashSS (available in STiH407 SoC - family). - -- clock-names: Should be "mmc" and "icn". (NB: The latter is not compulsory) - See: Documentation/devicetree/bindings/resource-names.txt -- clocks: Phandle to the clock. - See: Documentation/devicetree/bindings/clock/clock-bindings.txt - -- interrupts: One mmc interrupt should be described here. -- interrupt-names: Should be "mmcirq". - -- pinctrl-names: A pinctrl state names "default" must be defined. -- pinctrl-0: Phandle referencing pin configuration of the sd/emmc controller. - See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - -- reg: This must provide the host controller base address and it can also - contain the FlashSS Top register for TX/RX delay used by the driver - to configure DLL inside the flashSS, if so reg-names must also be - specified. - -Optional properties: -- reg-names: Should be "mmc" and "top-mmc-delay". "top-mmc-delay" is optional - for eMMC on stih407 family silicon to configure DLL inside FlashSS. - -- non-removable: Non-removable slot. Also used for configuring mmcss in STiH407 SoC - family. - See: Documentation/devicetree/bindings/mmc/mmc.txt. - -- bus-width: Number of data lines. - See: Documentation/devicetree/bindings/mmc/mmc.txt. - -- max-frequency: Can be 200MHz, 100MHz or 50MHz (default) and used for - configuring the CCONFIG3 in the mmcss. - See: Documentation/devicetree/bindings/mmc/mmc.txt. - -- resets: Phandle and reset specifier pair to softreset line of HC IP. - See: Documentation/devicetree/bindings/reset/reset.txt - -- vqmmc-supply: Phandle to the regulator dt node, mentioned as the vcc/vdd - supply in eMMC/SD specs. - -- sd-uhs-sdr50: To enable the SDR50 in the mmcss. - See: Documentation/devicetree/bindings/mmc/mmc.txt. - -- sd-uhs-sdr104: To enable the SDR104 in the mmcss. - See: Documentation/devicetree/bindings/mmc/mmc.txt. - -- sd-uhs-ddr50: To enable the DDR50 in the mmcss. - See: Documentation/devicetree/bindings/mmc/mmc.txt. - -Example: - -/* Example stih416e eMMC configuration */ - -mmc0: sdhci@fe81e000 { - compatible = "st,sdhci"; - reg = <0xfe81e000 0x1000>; - interrupts = ; - interrupt-names = "mmcirq"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_mmc0>; - clock-names = "mmc"; - clocks = <&clk_s_a1_ls 1>; - bus-width = <8> - -/* Example SD stih407 family configuration */ - -mmc1: sdhci@9080000 { - compatible = "st,sdhci-stih407", "st,sdhci"; - reg = <0x09080000 0x7ff>; - reg-names = "mmc"; - interrupts = ; - interrupt-names = "mmcirq"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_sd1>; - clock-names = "mmc"; - clocks = <&clk_s_c0_flexgen CLK_MMC_1>; - resets = <&softreset STIH407_MMC1_SOFTRESET>; - bus-width = <4>; -}; - -/* Example eMMC stih407 family configuration */ - -mmc0: sdhci@9060000 { - compatible = "st,sdhci-stih407", "st,sdhci"; - reg = <0x09060000 0x7ff>, <0x9061008 0x20>; - reg-names = "mmc", "top-mmc-delay"; - interrupts = ; - interrupt-names = "mmcirq"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_mmc0>; - clock-names = "mmc"; - clocks = <&clk_s_c0_flexgen CLK_MMC_0>; - vqmmc-supply = <&vmmc_reg>; - max-frequency = <200000000>; - bus-width = <8>; - non-removable; - sd-uhs-sdr50; - sd-uhs-sdr104; - sd-uhs-ddr50; -}; diff --git a/Documentation/devicetree/bindings/mmc/st,sdhci.yaml b/Documentation/devicetree/bindings/mmc/st,sdhci.yaml new file mode 100644 index 000000000000..798af599d374 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/st,sdhci.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mmc/st,sdhci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics SDHCI-ST MMC/SD Controller + +maintainers: + - Peter Griffin + +description: + The STMicroelectronics SDHCI-ST MMC/SD host controller is compliant with + the SD Host Controller Interface (SDHCI) specification and is used to + interface with MMC, SD and SDIO cards. The ST SDHCI controller extends the + standard SDHCI capabilities with platform-specific configurations such as + additional register regions, clock inputs, and delay control mechanisms + required for signal timing adjustments to support high-speed modes across + different ST SoCs. + +allOf: + - $ref: mmc-controller.yaml# + - if: + properties: + reg: + minItems: 2 + required: + - reg + then: + required: + - reg-names + +properties: + compatible: + oneOf: + - const: st,sdhci + - items: + - const: st,sdhci-stih407 + - const: st,sdhci + + reg: + minItems: 1 + items: + - description: MMC controller base registers + - description: FlashSS Top registers for TX/RX DLL delay configuration + + reg-names: + minItems: 1 + items: + - const: mmc + - const: top-mmc-delay + + clocks: + minItems: 1 + items: + - description: Clock for the MMC controller + - description: Interconnect (ICN) clock + + clock-names: + minItems: 1 + items: + - const: mmc + - const: icn + + interrupts: + maxItems: 1 + + interrupt-names: + const: mmcirq + + resets: + maxItems: 1 + + max-frequency: + enum: [200000000, 100000000, 50000000] + default: 50000000 + +required: + - reg + - compatible + - clocks + - clock-names + - interrupts + - interrupt-names + +unevaluatedProperties: false + +examples: + - | + #include + #include + mmc@9060000 { + compatible = "st,sdhci-stih407", "st,sdhci"; + reg = <0x09060000 0x7ff>, <0x9061008 0x20>; + reg-names = "mmc", "top-mmc-delay"; + interrupts = ; + interrupt-names = "mmcirq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc0>; + clock-names = "mmc", "icn"; + clocks = <&clk_s_c0_flexgen CLK_MMC_0>, + <&clk_s_c0_flexgen CLK_RX_ICN_HVA>; + bus-width = <8>; + }; +... From 9b3732cce41d177acac731e0b8024d72f0dfde38 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 20:41:15 +0800 Subject: [PATCH 16/35] mmc: sdhci-of-ma35d1: add missing MODULE_DEVICE_TABLE() The driver has an OF match table wired to .of_match_table, but does not export the table with MODULE_DEVICE_TABLE(). Add the missing MODULE_DEVICE_TABLE(of, ...) entry so module alias information is generated for OF based module autoloading. Signed-off-by: Pengpeng Hou Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-ma35d1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-of-ma35d1.c b/drivers/mmc/host/sdhci-of-ma35d1.c index a3b676894838..2a826de97779 100644 --- a/drivers/mmc/host/sdhci-of-ma35d1.c +++ b/drivers/mmc/host/sdhci-of-ma35d1.c @@ -290,6 +290,7 @@ static const struct of_device_id sdhci_ma35_dt_ids[] = { { .compatible = "nuvoton,ma35d1-sdhci" }, {} }; +MODULE_DEVICE_TABLE(of, sdhci_ma35_dt_ids); static struct platform_driver sdhci_ma35_driver = { .driver = { From 5253aee00a4383cb0482d5e99bde48b8054ae2c0 Mon Sep 17 00:00:00 2001 From: Xu Rao Date: Mon, 6 Jul 2026 17:25:00 +0800 Subject: [PATCH 17/35] mmc: block: reject invalid perdev_minors before division The mmcblk.perdev_minors module parameter is parsed as a signed int and is used during mmc_blk_init() to compute the number of supported block devices. Passing perdev_minors=0 makes the init path divide by zero when it computes max_devices. Negative values are invalid as well and would make max_devices negative before it is later used as an IDA limit. Reject non-positive perdev_minors values before registering any mmcblk resources. Signed-off-by: Xu Rao Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 54a923ba4f1e..e760d13ee325 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -3337,6 +3337,11 @@ static int __init mmc_blk_init(void) { int res; + if (perdev_minors <= 0) { + pr_err("mmcblk: invalid minors per device: %d\n", perdev_minors); + return -EINVAL; + } + res = bus_register(&mmc_rpmb_bus_type); if (res < 0) { pr_err("mmcblk: could not register RPMB bus type\n"); From ba1da04104c97ed28ac12ce9b4bee595635ede97 Mon Sep 17 00:00:00 2001 From: Satyansh Shukla Date: Mon, 6 Jul 2026 06:33:57 -0600 Subject: [PATCH 18/35] mmc: sdhci-of-dwcmshc: Log eMMC reset calls Log when the BlueField-3 eMMC hardware reset path is invoked. This makes it easier to diagnose cases where the controller recovery path depends on issuing an eMMC reset, and helps confirm that the reset sequence was attempted on affected systems. Signed-off-by: Satyansh Shukla Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-dwcmshc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index ba942c76f9ca..1baa2379c9c3 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -2013,6 +2013,7 @@ static void dwcmshc_bf3_hw_reset(struct sdhci_host *host) { struct arm_smccc_res res = { 0 }; + pr_debug("%s: resetting...\n", __func__); arm_smccc_smc(BLUEFIELD_SMC_SET_EMMC_RST_N, 0, 0, 0, 0, 0, 0, 0, &res); if (res.a0) From 483c948324a3823871c004560a92545759d3253c Mon Sep 17 00:00:00 2001 From: Sean Rhodes Date: Mon, 6 Jul 2026 16:40:43 +0100 Subject: [PATCH 19/35] misc: rtsx_usb: avoid USB I/O in runtime autosuspend The runtime autosuspend callback currently queries card status and clears OCP by issuing USB register accesses. This can run from the USB runtime-PM path itself, which is the wrong place to start more device I/O. Keep a cached copy of the card-status bits from normal status reads instead. During runtime autosuspend, use that cached value only to preserve the existing Memory Stick autosuspend deferral. Do not treat raw SD_CD as an autosuspend blocker, because tray-based SD readers can assert SD_CD with an empty tray. A real SD card is protected by the SD/MMC child runtime-PM usage once powered. Also stop clearing OCP from the runtime autosuspend callback, so the callback does not issue USB commands. Fixes: bb400d2120bd ("mfd: rtsx_usb: Defer autosuspend while card exists") Signed-off-by: Sean Rhodes Acked-by: Greg Kroah-Hartman Signed-off-by: Ulf Hansson --- drivers/misc/cardreader/rtsx_usb.c | 26 ++++++++++++++++++++------ include/linux/rtsx_usb.h | 3 +++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c index 1830e9ed2521..a127744918f4 100644 --- a/drivers/misc/cardreader/rtsx_usb.c +++ b/drivers/misc/cardreader/rtsx_usb.c @@ -312,6 +312,9 @@ int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status) if (ret < 0) return ret; + ucr->card_status_cache = *status; + ucr->card_status_valid = true; + return 0; } EXPORT_SYMBOL_GPL(rtsx_usb_get_card_status); @@ -623,6 +626,7 @@ static int rtsx_usb_probe(struct usb_interface *intf, { struct usb_device *usb_dev = interface_to_usbdev(intf); struct rtsx_ucr *ucr; + u16 status; int ret; dev_dbg(&intf->dev, @@ -659,6 +663,9 @@ static int rtsx_usb_probe(struct usb_interface *intf, if (ret) goto out_init_fail; + /* Prime cached status for runtime autosuspend decisions. */ + rtsx_usb_get_card_status(ucr, &status); + /* initialize USB SG transfer timer */ timer_setup(&ucr->sg_timer, rtsx_usb_sg_timed_out, 0); @@ -713,22 +720,29 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message) struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf); u16 val = 0; + bool valid = false; dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n", __func__, message.event); if (PMSG_IS_AUTO(message)) { if (mutex_trylock(&ucr->dev_mutex)) { - rtsx_usb_get_card_status(ucr, &val); + valid = ucr->card_status_valid; + if (valid) + val = ucr->card_status_cache; mutex_unlock(&ucr->dev_mutex); - /* Defer the autosuspend if card exists */ - if (val & (SD_CD | MS_CD)) { + /* + * Do not issue USB commands from runtime autosuspend. + * Raw SD_CD is not authoritative on tray-based readers, + * while a real SD card is protected by the SD/MMC child + * runtime-PM reference once the card is powered. Keep + * the historical Memory Stick autosuspend deferral when + * the cached status says MS media is present. + */ + if (valid && (val & MS_CD)) { device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child); return -EAGAIN; - } else { - /* if the card does not exists, clear OCP status */ - rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR); } } else { /* There is an ongoing operation*/ diff --git a/include/linux/rtsx_usb.h b/include/linux/rtsx_usb.h index 276b509c03e3..0fc5a74700a8 100644 --- a/include/linux/rtsx_usb.h +++ b/include/linux/rtsx_usb.h @@ -61,6 +61,9 @@ struct rtsx_ucr { struct timer_list sg_timer; struct mutex dev_mutex; + + u16 card_status_cache; + bool card_status_valid; }; /* buffer size */ From 7185b6d33b170cae54fb562ead44452810b6c231 Mon Sep 17 00:00:00 2001 From: Sean Rhodes Date: Mon, 6 Jul 2026 16:40:44 +0100 Subject: [PATCH 20/35] mmc: rtsx_usb_sdmmc: suppress false CD after init timeout Some Realtek USB SD readers with a tray keep raw SD_CD asserted when an empty tray is inserted. The MMC core then repeatedly tries to initialize non-existent media, sees command timeouts, calls ->get_cd() again, and starts the same detect cycle over. Do not qualify media by open-coding MMC commands in ->get_cd(). Instead, let the normal MMC rescan path probe the card. If an initialization command times out before a card has been attached, suppress the raw SD_CD signal so the host can settle and the USB parent can autosuspend. Clear the suppression only when raw SD_CD drops. On the affected tray reader, changing media requires removing and reinserting the tray, so a low CD transition is the signal that a new insertion attempt can be trusted again. Signed-off-by: Sean Rhodes Acked-by: Greg Kroah-Hartman Signed-off-by: Ulf Hansson --- drivers/mmc/host/rtsx_usb_sdmmc.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 84674659a84d..bf37fab233cf 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -44,6 +44,7 @@ struct rtsx_usb_sdmmc { bool double_clk; bool host_removal; bool card_exist; + bool suppress_cd; bool initial_mode; bool ddr_mode; @@ -774,6 +775,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc) struct rtsx_ucr *ucr = host->ucr; int err; u16 val; + bool cd; if (host->host_removal) return -ENOMEDIUM; @@ -791,8 +793,14 @@ static int sdmmc_get_cd(struct mmc_host *mmc) /* get OCP status */ host->ocp_stat = (val >> 4) & 0x03; + cd = val & SD_CD; - if (val & SD_CD) { + if (!cd) { + WRITE_ONCE(host->suppress_cd, false); + goto no_card; + } + + if (!READ_ONCE(host->suppress_cd)) { host->card_exist = true; return 1; } @@ -874,6 +882,8 @@ finish_detect_card: * detect card when fail to update card existence state and * speed up card removal when retry */ + if (!mmc->card && cmd->error == -ETIMEDOUT) + WRITE_ONCE(host->suppress_cd, true); sdmmc_get_cd(mmc); dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); } @@ -1359,6 +1369,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host) host->power_mode = MMC_POWER_OFF; host->ocp_stat = 0; + host->suppress_cd = false; } static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) From 30f4bb1f1047c4d8623464dbb3dc6838421b5360 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 6 Jul 2026 13:58:03 -0600 Subject: [PATCH 21/35] dt-bindings: mmc: rockchip-dw-mshc: Add RV1106 compatible Add the compatible for the MMC controllers of the Rockchip RV1106, which are compatible with the RK3288 variant. Unlike the newer controller in the RV1103B, which uses the RK3576 fallback, the RV1106 controller is the older IP whose drive and sample phases are set through clocks provided by the GRF, so the RK3288 fallback is the correct one here. Signed-off-by: Simon Glass Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml index 4965bb518c54..21ecfaa454f4 100644 --- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml +++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml @@ -43,6 +43,7 @@ properties: - rockchip,rk3562-dw-mshc - rockchip,rk3568-dw-mshc - rockchip,rk3588-dw-mshc + - rockchip,rv1106-dw-mshc - rockchip,rv1108-dw-mshc - rockchip,rv1126-dw-mshc - const: rockchip,rk3288-dw-mshc From 6029de0f14131eb38994b1054c7c8bd854028bc7 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 10 Jul 2026 17:12:54 +0100 Subject: [PATCH 22/35] mmc: dw_mmc: move declaration of dw_mci_pmops The dw_mci_pmops is exported out of dw_mmc.c so move the declaration of ton dw_mmc.h from dw_mmc-pltfm.h to fix the following sparse warning: drivers/mmc/host/dw_mmc.c:3512:25: warning: symbol 'dw_mci_pmops' was not declared. Should it be static? Signed-off-by: Ben Dooks Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-pltfm.h | 1 - drivers/mmc/host/dw_mmc.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc-pltfm.h b/drivers/mmc/host/dw_mmc-pltfm.h index ef1b05d484c3..f3193662abf1 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.h +++ b/drivers/mmc/host/dw_mmc-pltfm.h @@ -11,6 +11,5 @@ extern int dw_mci_pltfm_register(struct platform_device *pdev, const struct dw_mci_drv_data *drv_data); extern void dw_mci_pltfm_remove(struct platform_device *pdev); -extern const struct dev_pm_ops dw_mci_pmops; #endif /* _DW_MMC_PLTFM_H_ */ diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 9ffcd3946cff..38610c89d54a 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -19,6 +19,8 @@ #include #include +extern const struct dev_pm_ops dw_mci_pmops; + enum dw_mci_state { STATE_IDLE = 0, STATE_SENDING_CMD, From 5608386899d9de8030980bce3d05bded28f9bfb8 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 14 Jul 2026 08:44:56 +0000 Subject: [PATCH 23/35] mmc: bcm2835: DMA mapping improvements As pointed out by sashiko bot in [0], recent proposed changes to dma_max_mapping_size() may affect the driver. While the issue reported may be a false positive, Robin pointed out some other DMA-related issues in the driver which are addressed here: - the DMA max mapping size is irrelevant for the programmed IO mode of operation - we should not call dma_max_mapping_size() on the MMC host platform device, but rather the DMA engine device In addition, it's better to use the device returned from dmaengine_get_dma_device() for dma_umap_sg() and dma_unmap_sg(), and not reference the DMA channel device directly. [0] https://lore.kernel.org/linux-scsi/d82926fe-4557-401d-ae58-4302fef5657c@oracle.com/#t Signed-off-by: John Garry Signed-off-by: Ulf Hansson --- drivers/mmc/host/bcm2835.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index ee63835b3ca0..c949a3eaae79 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -188,7 +188,7 @@ struct bcm2835_host { u32 drain_words; struct page *drain_page; u32 drain_offset; - bool use_dma; + struct device *dma_dev; }; static void bcm2835_dumpcmd(struct bcm2835_host *host, struct mmc_command *cmd, @@ -494,8 +494,7 @@ void bcm2835_prepare_dma(struct bcm2835_host *host, struct mmc_data *data) &host->dma_cfg_rx : &host->dma_cfg_tx); - sg_len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len, - dir_data); + sg_len = dma_map_sg(host->dma_dev, data->sg, data->sg_len, dir_data); if (!sg_len) return; @@ -503,8 +502,7 @@ void bcm2835_prepare_dma(struct bcm2835_host *host, struct mmc_data *data) DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { - dma_unmap_sg(dma_chan->device->dev, data->sg, data->sg_len, - dir_data); + dma_unmap_sg(host->dma_dev, data->sg, data->sg_len, dir_data); return; } @@ -1057,7 +1055,7 @@ static void bcm2835_dma_complete_work(struct work_struct *work) data = host->data; if (host->dma_chan) { - dma_unmap_sg(host->dma_chan->device->dev, + dma_unmap_sg(host->dma_dev, data->sg, data->sg_len, host->dma_dir); @@ -1201,7 +1199,7 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } - if (host->use_dma && mrq->data && (mrq->data->blocks > PIO_THRESHOLD)) + if (host->dma_dev && mrq->data && (mrq->data->blocks > PIO_THRESHOLD)) bcm2835_prepare_dma(host, mrq->data); host->use_sbc = !!mrq->sbc && host->mrq->data && @@ -1281,10 +1279,7 @@ static int bcm2835_add_host(struct bcm2835_host *host) if (!host->dma_chan_rxtx) { dev_warn(dev, "unable to initialise DMA channel. Falling back to PIO\n"); - host->use_dma = false; } else { - host->use_dma = true; - host->dma_cfg_tx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; host->dma_cfg_tx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; host->dma_cfg_tx.direction = DMA_MEM_TO_DEV; @@ -1297,15 +1292,21 @@ static int bcm2835_add_host(struct bcm2835_host *host) host->dma_cfg_rx.src_addr = host->phys_addr + SDDATA; host->dma_cfg_rx.dst_addr = 0; - if (dmaengine_slave_config(host->dma_chan_rxtx, - &host->dma_cfg_tx) != 0 || - dmaengine_slave_config(host->dma_chan_rxtx, - &host->dma_cfg_rx) != 0) - host->use_dma = false; + if (!dmaengine_slave_config(host->dma_chan_rxtx, + &host->dma_cfg_tx) && + !dmaengine_slave_config(host->dma_chan_rxtx, + &host->dma_cfg_rx)) { + host->dma_dev = + dmaengine_get_dma_device(host->dma_chan_rxtx); + } } mmc->max_segs = 128; - mmc->max_req_size = min_t(size_t, 524288, dma_max_mapping_size(dev)); + mmc->max_req_size = 524288; + if (host->dma_dev) { + mmc->max_req_size = min_t(size_t, mmc->max_req_size, + dma_max_mapping_size(host->dma_dev)); + } mmc->max_seg_size = mmc->max_req_size; mmc->max_blk_size = 1024; mmc->max_blk_count = 65535; @@ -1336,10 +1337,10 @@ static int bcm2835_add_host(struct bcm2835_host *host) } pio_limit_string[0] = '\0'; - if (host->use_dma && (PIO_THRESHOLD > 0)) + if (host->dma_dev && (PIO_THRESHOLD > 0)) sprintf(pio_limit_string, " (>%d)", PIO_THRESHOLD); dev_info(dev, "loaded - DMA %s%s\n", - host->use_dma ? "enabled" : "disabled", pio_limit_string); + host->dma_dev ? "enabled" : "disabled", pio_limit_string); return 0; } From d9686ea2cd4ced566c1e93b4467771016709c33c Mon Sep 17 00:00:00 2001 From: Pan Chuang Date: Fri, 17 Jul 2026 18:14:49 +0800 Subject: [PATCH 24/35] mmc: host: Remove redundant dev_err()/dev_err_probe() Since commit 55b48e23f5c4 ("genirq/devres: Add error handling in devm_request_*_irq()"), devm_request_irq() and devm_request_threaded_irq() automatically log detailed error messages on failure. Remove the now-redundant driver-specific dev_err() and dev_err_probe() calls. Signed-off-by: Pan Chuang Reviewed-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/alcor.c | 3 +-- drivers/mmc/host/cavium-octeon.c | 10 ++-------- drivers/mmc/host/meson-mx-sdio.c | 5 +---- drivers/mmc/host/mvsdio.c | 4 +--- drivers/mmc/host/omap_hsmmc.c | 4 +--- drivers/mmc/host/owl-mmc.c | 5 +---- drivers/mmc/host/sdhci-msm.c | 4 +--- drivers/mmc/host/sh_mmcif.c | 8 ++------ 8 files changed, 10 insertions(+), 33 deletions(-) diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c index 721db54739c1..45528909a758 100644 --- a/drivers/mmc/host/alcor.c +++ b/drivers/mmc/host/alcor.c @@ -1103,8 +1103,7 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) alcor_irq, alcor_irq_thread, IRQF_SHARED, DRV_NAME_ALCOR_PCI_SDMMC, host); if (ret) - return dev_err_probe(&pdev->dev, ret, - "Failed to get irq for data line\n"); + return ret; mutex_init(&host->cmd_mutex); INIT_DELAYED_WORK(&host->timeout_work, alcor_timeout_timer); diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c index 8a0daddd9200..1bfc1a4f9fe9 100644 --- a/drivers/mmc/host/cavium-octeon.c +++ b/drivers/mmc/host/cavium-octeon.c @@ -240,21 +240,15 @@ static int octeon_mmc_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, mmc_irq[i], cvm_mmc_interrupt, 0, cvm_mmc_irq_names[i], host); - if (ret < 0) { - dev_err(&pdev->dev, "Error: devm_request_irq %d\n", - mmc_irq[i]); + if (ret < 0) return ret; - } } } else { ret = devm_request_irq(&pdev->dev, mmc_irq[0], cvm_mmc_interrupt, 0, KBUILD_MODNAME, host); - if (ret < 0) { - dev_err(&pdev->dev, "Error: devm_request_irq %d\n", - mmc_irq[0]); + if (ret < 0) return ret; - } } host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev, diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index 5921e2cb2180..bef5e843f449 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -683,11 +683,8 @@ static int meson_mx_mmc_probe(struct platform_device *pdev) meson_mx_mmc_irq, meson_mx_mmc_irq_thread, IRQF_ONESHOT, NULL, host); - if (ret) { - dev_err_probe(host->controller_dev, ret, - "Failed to request IRQ\n"); + if (ret) goto error_unregister_slot_pdev; - } core_clk = devm_clk_get_enabled(host->controller_dev, "core"); if (IS_ERR(core_clk)) { diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 79df2fa89a3f..cf705b265e21 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -764,10 +764,8 @@ static int mvsd_probe(struct platform_device *pdev) mvsd_power_down(host); ret = devm_request_irq(&pdev->dev, irq, mvsd_irq, 0, DRIVER_NAME, host); - if (ret) { - dev_err(&pdev->dev, "cannot assign irq %d\n", irq); + if (ret) goto out; - } timer_setup(&host->timer, mvsd_timeout_timer, 0); platform_set_drvdata(pdev, mmc); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 58c881f2725b..63a9fb970975 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1915,10 +1915,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev) /* Request IRQ for MMC operations */ ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0, mmc_hostname(mmc), host); - if (ret) { - dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); + if (ret) goto err_irq; - } ret = omap_hsmmc_reg_get(host); if (ret) diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c index 349082d76a99..d5b8a110267b 100644 --- a/drivers/mmc/host/owl-mmc.c +++ b/drivers/mmc/host/owl-mmc.c @@ -635,11 +635,8 @@ static int owl_mmc_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, owl_host->irq, owl_irq_handler, 0, dev_name(&pdev->dev), owl_host); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq %d\n", - owl_host->irq); + if (ret) goto err_release_channel; - } ret = mmc_add_host(mmc); if (ret) { diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index ceed47ccfda8..4aff965f0e2e 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2864,10 +2864,8 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL, sdhci_msm_pwr_irq, IRQF_ONESHOT, dev_name(&pdev->dev), host); - if (ret) { - dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret); + if (ret) goto clk_disable; - } msm_host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY; diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 9831956de1c8..7706d01b149e 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1505,18 +1505,14 @@ static int sh_mmcif_probe(struct platform_device *pdev) name = irq[1] < 0 ? dev_name(dev) : "sh_mmc:error"; ret = devm_request_threaded_irq(dev, irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, name, host); - if (ret) { - dev_err(dev, "request_irq error (%s)\n", name); + if (ret) goto err_clk; - } if (irq[1] >= 0) { ret = devm_request_threaded_irq(dev, irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); - if (ret) { - dev_err(dev, "request_irq error (sh_mmc:int)\n"); + if (ret) goto err_clk; - } } mutex_init(&host->thread_lock); From 08f4661d40f41d6bfb94da1907eb3f7f172e652f Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 22 Jul 2026 13:46:43 -0700 Subject: [PATCH 25/35] mmc: moxart: use platform helpers for resource and IRQ Replace of_address_to_resource() and the following devm_ioremap_resource() with a single devm_platform_get_and_ioremap_resource() call in moxart_probe(). This requests the register region and maps it once, which is equivalent to the previous devm_ioremap_resource() behavior, and drops the now-redundant separate resource lookup. Similarly replace irq_of_parse_and_map() with platform_get_irq(), which returns a negative errno on failure (including -EPROBE_DEFER) instead of 0, and tighten the error check to irq < 0. Both substitutions are equivalent for a DT-backed platform device. The remaining OF usage (mmc_of_parse() and the of_device_id table) is covered by already-included headers, so linux/of_address.h and linux/of_irq.h are dropped. No functional change; the MMC register window is requested and mapped exactly once, so there is no overlapping region claim. Built for ARM (allmodconfig + CONFIG_MMC_MOXART) with LLVM=1; drivers/mmc/host/moxart-mmc.o compiles cleanly. Assisted-by: opencode:hy3-free Signed-off-by: Rosen Penev Signed-off-by: Ulf Hansson --- drivers/mmc/host/moxart-mmc.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index 4a4d8b19b18c..28aed13549a6 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include #include @@ -555,8 +553,7 @@ static const struct mmc_host_ops moxart_ops = { static int moxart_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; - struct resource res_mmc; + struct resource *res_mmc; struct mmc_host *mmc; struct moxart_host *host = NULL; struct dma_slave_config cfg; @@ -565,30 +562,24 @@ static int moxart_probe(struct platform_device *pdev) int irq, ret; u32 i; + reg_mmc = devm_platform_get_and_ioremap_resource(pdev, 0, &res_mmc); + if (IS_ERR(reg_mmc)) + return PTR_ERR(reg_mmc); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) { dev_err(dev, "devm_mmc_alloc_host failed\n"); return -ENOMEM; } - ret = of_address_to_resource(node, 0, &res_mmc); - if (ret) - return dev_err_probe(dev, ret, - "of_address_to_resource failed\n"); - - irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) - return dev_err_probe(dev, -EINVAL, - "irq_of_parse_and_map failed\n"); - clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk); - reg_mmc = devm_ioremap_resource(dev, &res_mmc); - if (IS_ERR(reg_mmc)) - return PTR_ERR(reg_mmc); - ret = mmc_of_parse(mmc); if (ret) return ret; @@ -596,7 +587,7 @@ static int moxart_probe(struct platform_device *pdev) host = mmc_priv(mmc); host->mmc = mmc; host->base = reg_mmc; - host->reg_phys = res_mmc.start; + host->reg_phys = res_mmc->start; host->timeout = msecs_to_jiffies(1000); host->sysclk = clk_get_rate(clk); host->fifo_width = readl(host->base + REG_FEATURE) << 2; From 088eaa92fcebaa6b957ccf9635afdf39643a577d Mon Sep 17 00:00:00 2001 From: Fan Wu Date: Thu, 23 Jul 2026 11:28:41 +0000 Subject: [PATCH 26/35] mmc: via-sdmmc: stop card-detect handling on probe failure request_irq() registers the SD card-detect interrupt and the probe enables it before mmc_add_host() runs. If mmc_add_host() fails, the error path only unmaps the registers and returns: the interrupt stays registered, so the handler keeps running against the host once it is freed. via_sdc_isr() dereferences sdhost and its MMIO base and schedules carddet_work, which via_sdc_card_detect() also runs against freed memory through its container_of() dereference. Add a probe-error path that disables and frees the interrupt and cancels carddet_work before unmapping. carddet_work can re-enable the device interrupt via via_reset_pcictrl(), which restores PCIINTCTRL, so mask it again after cancelling the work. This issue was found by an in-house static analysis tool and confirmed by manual code review. Fixes: e4e46fb61e3b ("mmc: via-sdmmc: fix return value check of mmc_add_host()") Cc: stable@vger.kernel.org Assisted-by: Codex:gpt-5.6 Signed-off-by: Fan Wu Signed-off-by: Ulf Hansson --- drivers/mmc/host/via-sdmmc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 8c049f8355cd..632de678532d 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -1153,10 +1153,16 @@ static int via_sd_probe(struct pci_dev *pcidev, ret = mmc_add_host(mmc); if (ret) - goto unmap; + goto free_irq; return 0; +free_irq: + writeb(0x0, sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); + free_irq(pcidev->irq, sdhost); + cancel_work_sync(&sdhost->carddet_work); + /* carddet_work may re-enable the interrupt via via_reset_pcictrl(). */ + writeb(0x0, sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); unmap: iounmap(sdhost->mmiobase); release: From 57e5d877f898d5e5c9d672a77bb6bdd24f0d9bf5 Mon Sep 17 00:00:00 2001 From: Fan Wu Date: Thu, 23 Jul 2026 11:28:42 +0000 Subject: [PATCH 27/35] mmc: via-sdmmc: cancel card-detect work on remove Disabling the device interrupt and freeing the IRQ prevents new card-detect work from being queued, but carddet_work already queued by the handler can still run after via_sd_remove() returns. via_sdc_card_detect() recovers the host through container_of() and dereferences its MMIO base; once remove() returns the host can be freed, so that work would touch freed memory. Cancel carddet_work after freeing the IRQ and before cancelling finish_bh_work, which the card-detect handler can also queue. carddet_work can re-enable the interrupt through via_reset_pcictrl(); mask it again afterwards. This issue was found by an in-house static analysis tool and confirmed by manual code review. Fixes: f0bf7f61b840 ("mmc: Add new via-sdmmc host controller driver") Cc: stable@vger.kernel.org Assisted-by: Codex:gpt-5.6 Signed-off-by: Fan Wu Signed-off-by: Ulf Hansson --- drivers/mmc/host/via-sdmmc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 632de678532d..4910d0f444ba 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -1205,6 +1205,10 @@ static void via_sd_remove(struct pci_dev *pcidev) free_irq(pcidev->irq, sdhost); + cancel_work_sync(&sdhost->carddet_work); + /* carddet_work may re-enable the interrupt via via_reset_pcictrl(). */ + writeb(0x0, sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); + timer_delete_sync(&sdhost->timer); cancel_work_sync(&sdhost->finish_bh_work); From 8a5a1e727fcaf4bc9f742bf71a4de7eb49de9623 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 26 Jul 2026 14:57:40 -0700 Subject: [PATCH 28/35] mmc: omap_hsmmc: use platform_get_irq_optional for wake IRQ Replace irq_of_parse_and_map() with platform_get_irq_optional() to get the wake IRQ. This is a more portable approach that works with both DT and non-DT platforms, and follows the modern platform API conventions for optional IRQ resources. The wake IRQ is now fetched earlier in the probe function alongside the main IRQ, and the -EPROBE_DEFER case is handled properly before the deferred probe can be triggered. Signed-off-by: Rosen Penev Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 63a9fb970975..308a8905e196 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1764,7 +1764,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) struct mmc_host *mmc; struct omap_hsmmc_host *host = NULL; struct resource *res; - int ret, irq; + int ret, irq, wake_irq; const struct of_device_id *match; const struct omap_mmc_of_data *data; void __iomem *base; @@ -1792,6 +1792,11 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (irq < 0) return irq; + wake_irq = platform_get_irq_optional(pdev, 1); + if (wake_irq == -EPROBE_DEFER) + return wake_irq; + wake_irq = max(wake_irq, 0); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); @@ -1811,6 +1816,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->use_dma = 1; host->dma_ch = -1; host->irq = irq; + host->wake_irq = wake_irq; host->mapbase = res->start + pdata->reg_offset; host->base = base + pdata->reg_offset; host->power_mode = MMC_POWER_OFF; @@ -1820,9 +1826,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); - if (pdev->dev.of_node) - host->wake_irq = irq_of_parse_and_map(pdev->dev.of_node, 1); - mmc->ops = &omap_hsmmc_ops; mmc->f_min = OMAP_MMC_MIN_CLOCK; From c06323331aeb6d6a0ae5e3a89ab4486a2133c18b Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Fri, 24 Jul 2026 07:56:55 +0000 Subject: [PATCH 29/35] dt-bindings: mmc: tegra: Document Tegra238 SDHCI Add the compatible string for the SDHCI block found on the Tegra238 SoC. Signed-off-by: Prathamesh Shete Reviewed-by: Jon Hunter Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml index 72987f0326a1..0926a0cb892e 100644 --- a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml @@ -39,6 +39,10 @@ properties: - nvidia,tegra234-sdhci - const: nvidia,tegra186-sdhci + - items: + - const: nvidia,tegra238-sdhci + - const: nvidia,tegra194-sdhci + reg: maxItems: 1 From 114939f96ecf07d044800d63be0cf4000ba275bc Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Fri, 24 Jul 2026 07:56:56 +0000 Subject: [PATCH 30/35] mmc: sdhci-tegra: Add Tegra238 SoC data Add a new SoC data structure for Tegra238 platforms and register the nvidia,tegra238-sdhci compatible string. Configure the supported features and tap delay values for the Tegra238 SDHCI controller. Signed-off-by: Prathamesh Shete Reviewed-by: Jon Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 221e48b59f48..5fd900ff9eb5 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1572,7 +1572,22 @@ static const struct sdhci_tegra_soc_data soc_data_tegra234 = { .max_tap_delay = 111, }; +static const struct sdhci_tegra_soc_data soc_data_tegra238 = { + .pdata = &sdhci_tegra186_pdata, + .dma_mask = DMA_BIT_MASK(39), + .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | + NVQUIRK_HAS_PADCALIB | + NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | + NVQUIRK_ENABLE_SDR50 | + NVQUIRK_ENABLE_SDR104 | + NVQUIRK_PROGRAM_STREAMID | + NVQUIRK_HAS_TMCLK, + .min_tap_delay = 95, + .max_tap_delay = 111, +}; + static const struct of_device_id sdhci_tegra_dt_match[] = { + { .compatible = "nvidia,tegra238-sdhci", .data = &soc_data_tegra238 }, { .compatible = "nvidia,tegra234-sdhci", .data = &soc_data_tegra234 }, { .compatible = "nvidia,tegra194-sdhci", .data = &soc_data_tegra194 }, { .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 }, From 237eb3172a536e75049dd0fbec8164bad27f81d8 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Fri, 24 Jul 2026 07:56:57 +0000 Subject: [PATCH 31/35] dt-bindings: mmc: tegra: Document Tegra264 SDHCI Add the compatible string for the SDHCI block found on the Tegra264 SoC. Signed-off-by: Prathamesh Shete Reviewed-by: Jon Hunter Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml index 0926a0cb892e..3cac067c7c98 100644 --- a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.yaml @@ -40,7 +40,9 @@ properties: - const: nvidia,tegra186-sdhci - items: - - const: nvidia,tegra238-sdhci + - enum: + - nvidia,tegra238-sdhci + - nvidia,tegra264-sdhci - const: nvidia,tegra194-sdhci reg: From f92c238425e17b50095797276dbae757582ca3a5 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Fri, 24 Jul 2026 07:56:58 +0000 Subject: [PATCH 32/35] mmc: sdhci-tegra: Add Tegra264 SoC data Add a new SoC data structure for Tegra264 platforms and register the nvidia,tegra264-sdhci compatible string. Configure the supported features and tap delay values for the Tegra264 SDHCI controller. Signed-off-by: Prathamesh Shete Reviewed-by: Jon Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 5fd900ff9eb5..5c5efb62d7ec 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1572,6 +1572,20 @@ static const struct sdhci_tegra_soc_data soc_data_tegra234 = { .max_tap_delay = 111, }; +static const struct sdhci_tegra_soc_data soc_data_tegra264 = { + .pdata = &sdhci_tegra186_pdata, + .dma_mask = DMA_BIT_MASK(39), + .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | + NVQUIRK_HAS_PADCALIB | + NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | + NVQUIRK_ENABLE_SDR50 | + NVQUIRK_ENABLE_SDR104 | + NVQUIRK_PROGRAM_STREAMID | + NVQUIRK_HAS_TMCLK, + .min_tap_delay = 95, + .max_tap_delay = 111, +}; + static const struct sdhci_tegra_soc_data soc_data_tegra238 = { .pdata = &sdhci_tegra186_pdata, .dma_mask = DMA_BIT_MASK(39), @@ -1587,6 +1601,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra238 = { }; static const struct of_device_id sdhci_tegra_dt_match[] = { + { .compatible = "nvidia,tegra264-sdhci", .data = &soc_data_tegra264 }, { .compatible = "nvidia,tegra238-sdhci", .data = &soc_data_tegra238 }, { .compatible = "nvidia,tegra234-sdhci", .data = &soc_data_tegra234 }, { .compatible = "nvidia,tegra194-sdhci", .data = &soc_data_tegra194 }, From b65a40521d94299796f4128cc468a9781286ce92 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Thu, 30 Jul 2026 18:00:31 +0200 Subject: [PATCH 33/35] dt-bindings: mmc: Document fixed-layout NVMEM provider support Allow an eMMC hardware partition node to describe an NVMEM layout so the partition can be exposed as an NVMEM provider. This lets a partition (e.g. an eMMC boot partition) store device-specific information such as a WiFi MAC address or a Bluetooth BD address and reference it through NVMEM cells. Accept "fixed-layout" as the partition node compatible, in addition to "fixed-partitions", so the layout can be described directly on the partition node. Reviewed-by: Rob Herring (Arm) Signed-off-by: Loic Poulain Reviewed-by: Bartosz Golaszewski Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/mmc-card.yaml | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/mmc-card.yaml b/Documentation/devicetree/bindings/mmc/mmc-card.yaml index a61d6c96df75..042289450847 100644 --- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml +++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml @@ -38,7 +38,9 @@ patternProperties: properties: compatible: contains: - const: fixed-partitions + enum: + - fixed-partitions + - fixed-layout required: - compatible @@ -86,6 +88,25 @@ examples: read-only; }; }; + + partitions-boot2 { + compatible = "fixed-layout"; + + #address-cells = <1>; + #size-cells = <1>; + + mac-addr@4400 { + compatible = "mac-base"; + reg = <0x4400 0x6>; + #nvmem-cell-cells = <1>; + }; + + bd-addr@5400 { + compatible = "mac-base"; + reg = <0x5400 0x6>; + #nvmem-cell-cells = <1>; + }; + }; }; }; From 8dc697aabf7c49f1d40351f21e13a22ee030f508 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 31 Jul 2026 18:21:45 +0200 Subject: [PATCH 34/35] dt-bindings: mmc: sunxi: add compatible string for Allwinner A733 MMC0/1/2 The A733 MMC0/1/2 controllers are compatible with the D1 ones. Add an A733-specific compatible string, with the D1 as fallback. Signed-off-by: Jerome Brunet Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml b/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml index 9f3b1edacaa0..9e9610bb1eda 100644 --- a/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml +++ b/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml @@ -56,7 +56,9 @@ properties: - const: allwinner,sun50i-h616-mmc - const: allwinner,sun50i-a100-mmc - items: - - const: allwinner,sun55i-a523-mmc + - enum: + - allwinner,sun55i-a523-mmc + - allwinner,sun60i-a733-mmc - const: allwinner,sun20i-d1-mmc reg: From 35e689fb79dcbaa8d69cc4a58a7ad4d0d7346e4a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 6 Aug 2026 13:51:12 +0200 Subject: [PATCH 35/35] ARM: PXA: Fix build error for PXA93x Add a missing semicolon to fix the build error for PXA93x. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202607301822.cl0lEkQt-lkp@intel.com/ Fixes: ab9c44bbf6d7 ("ARM: PXA: remove remnants of PXA93x support") Cc: Ethan Nelson-Moore Signed-off-by: Ulf Hansson --- include/linux/soc/pxa/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/soc/pxa/cpu.h b/include/linux/soc/pxa/cpu.h index 38bacdae684f..c5b275a80854 100644 --- a/include/linux/soc/pxa/cpu.h +++ b/include/linux/soc/pxa/cpu.h @@ -177,7 +177,7 @@ ({ \ __cpu_is_pxa300(id) \ || __cpu_is_pxa310(id) \ - || __cpu_is_pxa320(id) \ + || __cpu_is_pxa320(id); \ }) #else #define __cpu_is_pxa3xx(id) (0)