Skip to content

Commit 53ab7f7

Browse files
skhimichUlf Hansson
authored andcommitted
mmc: sdhci-of-dwcmshc: Implement SDHCI CQE support
For enabling CQE support just set 'supports-cqe' in your DevTree file for appropriate mmc node. Signed-off-by: Sergey Khimich <serghox@gmail.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Link: https://lore.kernel.org/r/20240319115932.4108904-3-serghox@gmail.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent 52bf134 commit 53ab7f7

2 files changed

Lines changed: 190 additions & 2 deletions

File tree

drivers/mmc/host/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ config MMC_SDHCI_OF_DWCMSHC
233233
depends on MMC_SDHCI_PLTFM
234234
depends on OF
235235
depends on COMMON_CLK
236+
select MMC_CQHCI
236237
help
237238
This selects Synopsys DesignWare Cores Mobile Storage Controller
238239
support.

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

Lines changed: 189 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/sizes.h>
2222

2323
#include "sdhci-pltfm.h"
24+
#include "cqhci.h"
2425

2526
#define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16)
2627

@@ -52,6 +53,9 @@
5253
#define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits [31:24] */
5354
#define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */
5455

56+
/* DWC IP vendor area 2 pointer */
57+
#define DWCMSHC_P_VENDOR_AREA2 0xea
58+
5559
/* Sophgo CV18XX specific Registers */
5660
#define CV18XX_SDHCI_MSHC_CTRL 0x00
5761
#define CV18XX_EMMC_FUNC_EN BIT(0)
@@ -181,6 +185,10 @@
181185
#define BOUNDARY_OK(addr, len) \
182186
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
183187

188+
#define DWCMSHC_SDHCI_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \
189+
SDHCI_TRNS_BLK_CNT_EN | \
190+
SDHCI_TRNS_DMA)
191+
184192
enum dwcmshc_rk_type {
185193
DWCMSHC_RK3568,
186194
DWCMSHC_RK3588,
@@ -196,7 +204,9 @@ struct rk35xx_priv {
196204

197205
struct dwcmshc_priv {
198206
struct clk *bus_clk;
199-
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
207+
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA1 reg */
208+
int vendor_specific_area2; /* P_VENDOR_SPECIFIC_AREA2 reg */
209+
200210
void *priv; /* pointer to SoC private stuff */
201211
u16 delay_line;
202212
u16 flags;
@@ -455,6 +465,90 @@ static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
455465
sdhci_writel(host, vendor, reg);
456466
}
457467

468+
static int dwcmshc_execute_tuning(struct mmc_host *mmc, u32 opcode)
469+
{
470+
int err = sdhci_execute_tuning(mmc, opcode);
471+
struct sdhci_host *host = mmc_priv(mmc);
472+
473+
if (err)
474+
return err;
475+
476+
/*
477+
* Tuning can leave the IP in an active state (Buffer Read Enable bit
478+
* set) which prevents the entry to low power states (i.e. S0i3). Data
479+
* reset will clear it.
480+
*/
481+
sdhci_reset(host, SDHCI_RESET_DATA);
482+
483+
return 0;
484+
}
485+
486+
static u32 dwcmshc_cqe_irq_handler(struct sdhci_host *host, u32 intmask)
487+
{
488+
int cmd_error = 0;
489+
int data_error = 0;
490+
491+
if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
492+
return intmask;
493+
494+
cqhci_irq(host->mmc, intmask, cmd_error, data_error);
495+
496+
return 0;
497+
}
498+
499+
static void dwcmshc_sdhci_cqe_enable(struct mmc_host *mmc)
500+
{
501+
struct sdhci_host *host = mmc_priv(mmc);
502+
u8 ctrl;
503+
504+
sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
505+
506+
sdhci_cqe_enable(mmc);
507+
508+
/*
509+
* The "DesignWare Cores Mobile Storage Host Controller
510+
* DWC_mshc / DWC_mshc_lite Databook" says:
511+
* when Host Version 4 Enable" is 1 in Host Control 2 register,
512+
* SDHCI_CTRL_ADMA32 bit means ADMA2 is selected.
513+
* Selection of 32-bit/64-bit System Addressing:
514+
* either 32-bit or 64-bit system addressing is selected by
515+
* 64-bit Addressing bit in Host Control 2 register.
516+
*
517+
* On the other hand the "DesignWare Cores Mobile Storage Host
518+
* Controller DWC_mshc / DWC_mshc_lite User Guide" says, that we have to
519+
* set DMA_SEL to ADMA2 _only_ mode in the Host Control 2 register.
520+
*/
521+
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
522+
ctrl &= ~SDHCI_CTRL_DMA_MASK;
523+
ctrl |= SDHCI_CTRL_ADMA32;
524+
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
525+
}
526+
527+
static void dwcmshc_set_tran_desc(struct cqhci_host *cq_host, u8 **desc,
528+
dma_addr_t addr, int len, bool end, bool dma64)
529+
{
530+
int tmplen, offset;
531+
532+
if (likely(!len || BOUNDARY_OK(addr, len))) {
533+
cqhci_set_tran_desc(*desc, addr, len, end, dma64);
534+
return;
535+
}
536+
537+
offset = addr & (SZ_128M - 1);
538+
tmplen = SZ_128M - offset;
539+
cqhci_set_tran_desc(*desc, addr, tmplen, false, dma64);
540+
541+
addr += tmplen;
542+
len -= tmplen;
543+
*desc += cq_host->trans_desc_len;
544+
cqhci_set_tran_desc(*desc, addr, len, end, dma64);
545+
}
546+
547+
static void dwcmshc_cqhci_dumpregs(struct mmc_host *mmc)
548+
{
549+
sdhci_dumpregs(mmc_priv(mmc));
550+
}
551+
458552
static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock)
459553
{
460554
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -692,6 +786,7 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = {
692786
.get_max_clock = dwcmshc_get_max_clock,
693787
.reset = sdhci_reset,
694788
.adma_write_desc = dwcmshc_adma_write_desc,
789+
.irq = dwcmshc_cqe_irq_handler,
695790
};
696791

697792
static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
@@ -758,6 +853,73 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = {
758853
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
759854
};
760855

856+
static const struct cqhci_host_ops dwcmshc_cqhci_ops = {
857+
.enable = dwcmshc_sdhci_cqe_enable,
858+
.disable = sdhci_cqe_disable,
859+
.dumpregs = dwcmshc_cqhci_dumpregs,
860+
.set_tran_desc = dwcmshc_set_tran_desc,
861+
};
862+
863+
static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *pdev)
864+
{
865+
struct cqhci_host *cq_host;
866+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
867+
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
868+
bool dma64 = false;
869+
u16 clk;
870+
int err;
871+
872+
host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
873+
cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL);
874+
if (!cq_host) {
875+
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: not enough memory\n");
876+
goto dsbl_cqe_caps;
877+
}
878+
879+
/*
880+
* For dwcmshc host controller we have to enable internal clock
881+
* before access to some registers from Vendor Specific Area 2.
882+
*/
883+
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
884+
clk |= SDHCI_CLOCK_INT_EN;
885+
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
886+
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
887+
if (!(clk & SDHCI_CLOCK_INT_EN)) {
888+
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: internal clock enable error\n");
889+
goto free_cq_host;
890+
}
891+
892+
cq_host->mmio = host->ioaddr + priv->vendor_specific_area2;
893+
cq_host->ops = &dwcmshc_cqhci_ops;
894+
895+
/* Enable using of 128-bit task descriptors */
896+
dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
897+
if (dma64) {
898+
dev_dbg(mmc_dev(host->mmc), "128-bit task descriptors\n");
899+
cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
900+
}
901+
err = cqhci_init(cq_host, host->mmc, dma64);
902+
if (err) {
903+
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: error %d\n", err);
904+
goto int_clock_disable;
905+
}
906+
907+
dev_dbg(mmc_dev(host->mmc), "CQE init done\n");
908+
909+
return;
910+
911+
int_clock_disable:
912+
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
913+
clk &= ~SDHCI_CLOCK_INT_EN;
914+
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
915+
916+
free_cq_host:
917+
devm_kfree(&pdev->dev, cq_host);
918+
919+
dsbl_cqe_caps:
920+
host->mmc->caps2 &= ~(MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD);
921+
}
922+
761923
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
762924
{
763925
int err;
@@ -862,7 +1024,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
8621024
struct rk35xx_priv *rk_priv = NULL;
8631025
const struct sdhci_pltfm_data *pltfm_data;
8641026
int err;
865-
u32 extra;
1027+
u32 extra, caps;
8661028

8671029
pltfm_data = device_get_match_data(&pdev->dev);
8681030
if (!pltfm_data) {
@@ -913,6 +1075,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
9131075

9141076
host->mmc_host_ops.request = dwcmshc_request;
9151077
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
1078+
host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning;
9161079

9171080
if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) {
9181081
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL);
@@ -962,6 +1125,10 @@ static int dwcmshc_probe(struct platform_device *pdev)
9621125
sdhci_enable_v4_mode(host);
9631126
#endif
9641127

1128+
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
1129+
if (caps & SDHCI_CAN_64BIT_V4)
1130+
sdhci_enable_v4_mode(host);
1131+
9651132
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
9661133

9671134
pm_runtime_get_noresume(dev);
@@ -972,6 +1139,14 @@ static int dwcmshc_probe(struct platform_device *pdev)
9721139
if (err)
9731140
goto err_rpm;
9741141

1142+
/* Setup Command Queue Engine if enabled */
1143+
if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
1144+
priv->vendor_specific_area2 =
1145+
sdhci_readw(host, DWCMSHC_P_VENDOR_AREA2);
1146+
1147+
dwcmshc_cqhci_init(host, pdev);
1148+
}
1149+
9751150
if (rk_priv)
9761151
dwcmshc_rk35xx_postinit(host, priv);
9771152

@@ -1044,6 +1219,12 @@ static int dwcmshc_suspend(struct device *dev)
10441219

10451220
pm_runtime_resume(dev);
10461221

1222+
if (host->mmc->caps2 & MMC_CAP2_CQE) {
1223+
ret = cqhci_suspend(host->mmc);
1224+
if (ret)
1225+
return ret;
1226+
}
1227+
10471228
ret = sdhci_suspend_host(host);
10481229
if (ret)
10491230
return ret;
@@ -1088,6 +1269,12 @@ static int dwcmshc_resume(struct device *dev)
10881269
if (ret)
10891270
goto disable_rockchip_clks;
10901271

1272+
if (host->mmc->caps2 & MMC_CAP2_CQE) {
1273+
ret = cqhci_resume(host->mmc);
1274+
if (ret)
1275+
goto disable_rockchip_clks;
1276+
}
1277+
10911278
return 0;
10921279

10931280
disable_rockchip_clks:

0 commit comments

Comments
 (0)