From 2ef0767967138d333360ec0f399f1d68646741c3 Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Wed, 22 May 2024 15:20:52 +0800 Subject: [PATCH] mmc: sdhci-of-dwcmshc: add command queue support for rockchip SOCs Signed-off-by: Yifeng Zhao Change-Id: I96c3dfb56d4dd3af3e70cdd59bbd16403abd2fcb --- drivers/mmc/host/sdhci-of-dwcmshc.c | 101 ++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index fcd6c85a8447..24db6a819fa2 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -23,6 +23,7 @@ #include "sdhci-pltfm.h" #include "mmc_hsq.h" #include "cqhci.h" +#include "sdhci-cqhci.h" #define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16) @@ -48,6 +49,8 @@ #define DWCMSHC_EMMC_DLL_TXCLK 0x808 #define DWCMSHC_EMMC_DLL_STRBIN 0x80c #define DECMSHC_EMMC_DLL_CMDOUT 0x810 +#define DECMSHC_EMMC_MISC_CON 0x81C +#define MISC_INTCLK_EN BIT(1) #define DWCMSHC_EMMC_DLL_STATUS0 0x840 #define DWCMSHC_EMMC_DLL_STATUS1 0x844 #define DWCMSHC_EMMC_DLL_START BIT(0) @@ -299,6 +302,61 @@ static void dwcmshc_sdhci_cqe_enable(struct mmc_host *mmc) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } +static void rk35xx_sdhci_cqe_enable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); + u32 reg; + + reg = sdhci_readl(host, dwc_priv->vendor_specific_area2 + CQHCI_CFG); + reg |= CQHCI_ENABLE; + sdhci_writel(host, reg, dwc_priv->vendor_specific_area2 + CQHCI_CFG); + + reg = sdhci_readl(host, SDHCI_PRESENT_STATE); + while (reg & SDHCI_DATA_AVAILABLE) { + sdhci_readl(host, SDHCI_BUFFER); + reg = sdhci_readl(host, SDHCI_PRESENT_STATE); + } + + sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); + + sdhci_cqe_enable(mmc); + + sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); +} + +static void rk35xx_sdhci_cqe_disabled(struct mmc_host *mmc, bool recovery) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); + unsigned long flags; + u32 ctrl; + + mmc->cqe_ops->cqe_wait_for_idle(mmc); + spin_lock_irqsave(&host->lock, flags); + + /* + * During CQE command transfers, command complete bit gets latched. + * So s/w should clear command complete interrupt status when CQE is + * either halted or disabled. Otherwise unexpected SDCHI legacy + * interrupt gets triggered when CQE is halted/disabled. + */ + ctrl = sdhci_readl(host, SDHCI_INT_ENABLE); + ctrl |= SDHCI_INT_RESPONSE; + sdhci_writel(host, ctrl, SDHCI_INT_ENABLE); + sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS); + + spin_unlock_irqrestore(&host->lock, flags); + + sdhci_cqe_disable(mmc, recovery); + + ctrl = sdhci_readl(host, dwc_priv->vendor_specific_area2 + CQHCI_CFG); + ctrl &= ~CQHCI_ENABLE; + sdhci_writel(host, ctrl, dwc_priv->vendor_specific_area2 + CQHCI_CFG); +} + static void dwcmshc_set_tran_desc(struct cqhci_host *cq_host, u8 **desc, dma_addr_t addr, int len, bool end, bool dma64) { @@ -469,6 +527,7 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); struct rk35xx_priv *priv = dwc_priv->priv; + u32 extra = sdhci_readl(host, DECMSHC_EMMC_MISC_CON); if (mask & SDHCI_RESET_ALL && priv->reset) { reset_control_assert(priv->reset); @@ -477,12 +536,17 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) } sdhci_reset(host, mask); + + /* Enable INTERNAL CLOCK */ + sdhci_writel(host, MISC_INTCLK_EN | extra, DECMSHC_EMMC_MISC_CON); } static void sdhci_dwcmshc_request_done(struct sdhci_host *host, struct mmc_request *mrq) { - if (mmc_hsq_finalize_request(host->mmc, mrq)) - return; + if (!(host->mmc->caps2 & MMC_CAP2_CQE)) { + if (mmc_hsq_finalize_request(host->mmc, mrq)) + return; + } mmc_request_done(host->mmc, mrq); } @@ -537,11 +601,19 @@ static const struct cqhci_host_ops dwcmshc_cqhci_ops = { .set_tran_desc = dwcmshc_set_tran_desc, }; +static const struct cqhci_host_ops rk35xx_cqhci_ops = { + .enable = rk35xx_sdhci_cqe_enable, + .disable = rk35xx_sdhci_cqe_disabled, + .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); + struct rk35xx_priv *rk_priv = priv->priv; bool dma64 = false; u16 clk; int err; @@ -567,7 +639,10 @@ static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device * } cq_host->mmio = host->ioaddr + priv->vendor_specific_area2; - cq_host->ops = &dwcmshc_cqhci_ops; + if (rk_priv) + cq_host->ops = &rk35xx_cqhci_ops; + else + cq_host->ops = &dwcmshc_cqhci_ops; /* Enable using of 128-bit task descriptors */ dma64 = host->flags & SDHCI_USE_64_BIT_DMA; @@ -811,16 +886,6 @@ static int dwcmshc_probe(struct platform_device *pdev) host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning; - hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL); - if (!hsq) { - err = -ENOMEM; - goto err_clk; - } - - err = mmc_hsq_init(hsq, host->mmc); - if (err) - goto err_clk; - if (drv_data->flags & RK_PLATFROM) { rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL); if (!rk_priv) { @@ -859,6 +924,16 @@ static int dwcmshc_probe(struct platform_device *pdev) sdhci_readw(host, DWCMSHC_P_VENDOR_AREA2); dwcmshc_cqhci_init(host, pdev); + } else { + hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL); + if (!hsq) { + err = -ENOMEM; + goto err_setup_host; + } + + err = mmc_hsq_init(hsq, host->mmc); + if (err) + goto err_setup_host; } if (rk_priv)