Skip to content

Commit fda1e0a

Browse files
srestorulf
authored andcommitted
mmc: sdhci-of-dwcmshc: Add command queue support for rockchip SOCs
This adds CQE support for the Rockchip RK3588 and RK3576 platform. To be functional, the eMMC device-tree node must have a 'supports-cqe;' flag property. As the RK3576 device-tree has been upstreamed with the 'supports-cqe;' property set by default, the kernel already tried to use CQE, which results in system hang during suspend. This fixes the issue. Co-developed-by: Yifeng Zhao <yifeng.zhao@rock-chips.com> Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent eadea8e commit fda1e0a

File tree

1 file changed

+90
-3
lines changed

1 file changed

+90
-3
lines changed

drivers/mmc/host/sdhci-of-dwcmshc.c

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include "sdhci-pltfm.h"
3030
#include "cqhci.h"
31+
#include "sdhci-cqhci.h"
3132

3233
#define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16)
3334

@@ -87,6 +88,8 @@
8788
#define DWCMSHC_EMMC_DLL_TXCLK 0x808
8889
#define DWCMSHC_EMMC_DLL_STRBIN 0x80c
8990
#define DECMSHC_EMMC_DLL_CMDOUT 0x810
91+
#define DECMSHC_EMMC_MISC_CON 0x81C
92+
#define MISC_INTCLK_EN BIT(1)
9093
#define DWCMSHC_EMMC_DLL_STATUS0 0x840
9194
#define DWCMSHC_EMMC_DLL_START BIT(0)
9295
#define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
@@ -282,6 +285,7 @@ struct dwcmshc_priv {
282285

283286
struct dwcmshc_pltfm_data {
284287
const struct sdhci_pltfm_data pdata;
288+
const struct cqhci_host_ops *cqhci_host_ops;
285289
int (*init)(struct device *dev, struct sdhci_host *host, struct dwcmshc_priv *dwc_priv);
286290
void (*postinit)(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv);
287291
};
@@ -620,6 +624,68 @@ static void dwcmshc_cqhci_dumpregs(struct mmc_host *mmc)
620624
sdhci_dumpregs(mmc_priv(mmc));
621625
}
622626

627+
static void rk35xx_sdhci_cqe_pre_enable(struct mmc_host *mmc)
628+
{
629+
struct sdhci_host *host = mmc_priv(mmc);
630+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
631+
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
632+
u32 reg;
633+
634+
reg = sdhci_readl(host, dwc_priv->vendor_specific_area2 + CQHCI_CFG);
635+
reg |= CQHCI_ENABLE;
636+
sdhci_writel(host, reg, dwc_priv->vendor_specific_area2 + CQHCI_CFG);
637+
}
638+
639+
static void rk35xx_sdhci_cqe_enable(struct mmc_host *mmc)
640+
{
641+
struct sdhci_host *host = mmc_priv(mmc);
642+
u32 reg;
643+
644+
reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
645+
while (reg & SDHCI_DATA_AVAILABLE) {
646+
sdhci_readl(host, SDHCI_BUFFER);
647+
reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
648+
}
649+
650+
sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
651+
652+
sdhci_cqe_enable(mmc);
653+
}
654+
655+
static void rk35xx_sdhci_cqe_disable(struct mmc_host *mmc, bool recovery)
656+
{
657+
struct sdhci_host *host = mmc_priv(mmc);
658+
unsigned long flags;
659+
u32 ctrl;
660+
661+
/*
662+
* During CQE command transfers, command complete bit gets latched.
663+
* So s/w should clear command complete interrupt status when CQE is
664+
* either halted or disabled. Otherwise unexpected SDCHI legacy
665+
* interrupt gets triggered when CQE is halted/disabled.
666+
*/
667+
spin_lock_irqsave(&host->lock, flags);
668+
ctrl = sdhci_readl(host, SDHCI_INT_ENABLE);
669+
ctrl |= SDHCI_INT_RESPONSE;
670+
sdhci_writel(host, ctrl, SDHCI_INT_ENABLE);
671+
sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
672+
spin_unlock_irqrestore(&host->lock, flags);
673+
674+
sdhci_cqe_disable(mmc, recovery);
675+
}
676+
677+
static void rk35xx_sdhci_cqe_post_disable(struct mmc_host *mmc)
678+
{
679+
struct sdhci_host *host = mmc_priv(mmc);
680+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
681+
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
682+
u32 ctrl;
683+
684+
ctrl = sdhci_readl(host, dwc_priv->vendor_specific_area2 + CQHCI_CFG);
685+
ctrl &= ~CQHCI_ENABLE;
686+
sdhci_writel(host, ctrl, dwc_priv->vendor_specific_area2 + CQHCI_CFG);
687+
}
688+
623689
static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock)
624690
{
625691
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -738,6 +804,10 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
738804
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
739805
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
740806
struct rk35xx_priv *priv = dwc_priv->priv;
807+
u32 extra = sdhci_readl(host, DECMSHC_EMMC_MISC_CON);
808+
809+
if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL))
810+
cqhci_deactivate(host->mmc);
741811

742812
if (mask & SDHCI_RESET_ALL && priv->reset) {
743813
reset_control_assert(priv->reset);
@@ -746,6 +816,9 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
746816
}
747817

748818
sdhci_reset(host, mask);
819+
820+
/* Enable INTERNAL CLOCK */
821+
sdhci_writel(host, MISC_INTCLK_EN | extra, DECMSHC_EMMC_MISC_CON);
749822
}
750823

751824
static int dwcmshc_rk35xx_init(struct device *dev, struct sdhci_host *host,
@@ -1664,6 +1737,15 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_bf3_pdata = {
16641737
};
16651738
#endif
16661739

1740+
static const struct cqhci_host_ops rk35xx_cqhci_ops = {
1741+
.pre_enable = rk35xx_sdhci_cqe_pre_enable,
1742+
.enable = rk35xx_sdhci_cqe_enable,
1743+
.disable = rk35xx_sdhci_cqe_disable,
1744+
.post_disable = rk35xx_sdhci_cqe_post_disable,
1745+
.dumpregs = dwcmshc_cqhci_dumpregs,
1746+
.set_tran_desc = dwcmshc_set_tran_desc,
1747+
};
1748+
16671749
static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
16681750
.pdata = {
16691751
.ops = &sdhci_dwcmshc_rk35xx_ops,
@@ -1672,6 +1754,7 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
16721754
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
16731755
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
16741756
},
1757+
.cqhci_host_ops = &rk35xx_cqhci_ops,
16751758
.init = dwcmshc_rk35xx_init,
16761759
.postinit = dwcmshc_rk35xx_postinit,
16771760
};
@@ -1732,7 +1815,8 @@ static const struct cqhci_host_ops dwcmshc_cqhci_ops = {
17321815
.set_tran_desc = dwcmshc_set_tran_desc,
17331816
};
17341817

1735-
static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *pdev)
1818+
static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *pdev,
1819+
const struct dwcmshc_pltfm_data *pltfm_data)
17361820
{
17371821
struct cqhci_host *cq_host;
17381822
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -1762,7 +1846,10 @@ static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *
17621846
}
17631847

17641848
cq_host->mmio = host->ioaddr + priv->vendor_specific_area2;
1765-
cq_host->ops = &dwcmshc_cqhci_ops;
1849+
if (pltfm_data->cqhci_host_ops)
1850+
cq_host->ops = pltfm_data->cqhci_host_ops;
1851+
else
1852+
cq_host->ops = &dwcmshc_cqhci_ops;
17661853

17671854
/* Enable using of 128-bit task descriptors */
17681855
dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
@@ -1934,7 +2021,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
19342021
priv->vendor_specific_area2 =
19352022
sdhci_readw(host, DWCMSHC_P_VENDOR_AREA2);
19362023

1937-
dwcmshc_cqhci_init(host, pdev);
2024+
dwcmshc_cqhci_init(host, pdev, pltfm_data);
19382025
}
19392026

19402027
if (pltfm_data->postinit)

0 commit comments

Comments
 (0)