Skip to content

Commit 3c4019f

Browse files
Sowjanya Komatinenistorulf
authored andcommitted
mmc: tegra: HW Command Queue Support for Tegra SDMMC
This patch adds HW Command Queue for supported Tegra SDMMC controllers. Signed-off-by: Sowjanya Komatineni <[email protected]> Acked-by: Adrian Hunter <[email protected]> Acked-by: Thierry Reding <[email protected]> Signed-off-by: Ulf Hansson <[email protected]>
1 parent 4c4faff commit 3c4019f

File tree

2 files changed

+114
-4
lines changed

2 files changed

+114
-4
lines changed

drivers/mmc/host/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ config MMC_SDHCI_TEGRA
251251
depends on ARCH_TEGRA
252252
depends on MMC_SDHCI_PLTFM
253253
select MMC_SDHCI_IO_ACCESSORS
254+
select MMC_CQHCI
254255
help
255256
This selects the Tegra SD/MMC controller. If you have a Tegra
256257
platform with SD or MMC devices, say Y or M here.

drivers/mmc/host/sdhci-tegra.c

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <linux/ktime.h>
3434

3535
#include "sdhci-pltfm.h"
36+
#include "cqhci.h"
3637

3738
/* Tegra SDHOST controller vendor register definitions */
3839
#define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100
@@ -90,6 +91,9 @@
9091
#define NVQUIRK_NEEDS_PAD_CONTROL BIT(7)
9192
#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8)
9293

94+
/* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */
95+
#define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000
96+
9397
struct sdhci_tegra_soc_data {
9498
const struct sdhci_pltfm_data *pdata;
9599
u32 nvquirks;
@@ -131,6 +135,7 @@ struct sdhci_tegra {
131135
u32 default_tap;
132136
u32 default_trim;
133137
u32 dqs_trim;
138+
bool enable_hwcq;
134139
};
135140

136141
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
@@ -685,6 +690,20 @@ static void tegra_sdhci_parse_tap_and_trim(struct sdhci_host *host)
685690
tegra_host->dqs_trim = 0x11;
686691
}
687692

693+
static void tegra_sdhci_parse_dt(struct sdhci_host *host)
694+
{
695+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
696+
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
697+
698+
if (device_property_read_bool(host->mmc->parent, "supports-cqe"))
699+
tegra_host->enable_hwcq = true;
700+
else
701+
tegra_host->enable_hwcq = false;
702+
703+
tegra_sdhci_parse_pad_autocal_dt(host);
704+
tegra_sdhci_parse_tap_and_trim(host);
705+
}
706+
688707
static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
689708
{
690709
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -914,6 +933,49 @@ static void tegra_sdhci_voltage_switch(struct sdhci_host *host)
914933
tegra_host->pad_calib_required = true;
915934
}
916935

936+
static void sdhci_tegra_cqe_enable(struct mmc_host *mmc)
937+
{
938+
struct cqhci_host *cq_host = mmc->cqe_private;
939+
u32 cqcfg = 0;
940+
941+
/*
942+
* Tegra SDMMC Controller design prevents write access to BLOCK_COUNT
943+
* registers when CQE is enabled.
944+
*/
945+
cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
946+
if (cqcfg & CQHCI_ENABLE)
947+
cqhci_writel(cq_host, (cqcfg & ~CQHCI_ENABLE), CQHCI_CFG);
948+
949+
sdhci_cqe_enable(mmc);
950+
951+
if (cqcfg & CQHCI_ENABLE)
952+
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
953+
}
954+
955+
static void sdhci_tegra_dumpregs(struct mmc_host *mmc)
956+
{
957+
sdhci_dumpregs(mmc_priv(mmc));
958+
}
959+
960+
static u32 sdhci_tegra_cqhci_irq(struct sdhci_host *host, u32 intmask)
961+
{
962+
int cmd_error = 0;
963+
int data_error = 0;
964+
965+
if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
966+
return intmask;
967+
968+
cqhci_irq(host->mmc, intmask, cmd_error, data_error);
969+
970+
return 0;
971+
}
972+
973+
static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = {
974+
.enable = sdhci_tegra_cqe_enable,
975+
.disable = sdhci_cqe_disable,
976+
.dumpregs = sdhci_tegra_dumpregs,
977+
};
978+
917979
static const struct sdhci_ops tegra_sdhci_ops = {
918980
.get_ro = tegra_sdhci_get_ro,
919981
.read_w = tegra_sdhci_readw,
@@ -1067,6 +1129,7 @@ static const struct sdhci_ops tegra186_sdhci_ops = {
10671129
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
10681130
.voltage_switch = tegra_sdhci_voltage_switch,
10691131
.get_max_clock = tegra_sdhci_get_max_clock,
1132+
.irq = sdhci_tegra_cqhci_irq,
10701133
};
10711134

10721135
static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
@@ -1108,6 +1171,54 @@ static const struct of_device_id sdhci_tegra_dt_match[] = {
11081171
};
11091172
MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match);
11101173

1174+
static int sdhci_tegra_add_host(struct sdhci_host *host)
1175+
{
1176+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1177+
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
1178+
struct cqhci_host *cq_host;
1179+
bool dma64;
1180+
int ret;
1181+
1182+
if (!tegra_host->enable_hwcq)
1183+
return sdhci_add_host(host);
1184+
1185+
sdhci_enable_v4_mode(host);
1186+
1187+
ret = sdhci_setup_host(host);
1188+
if (ret)
1189+
return ret;
1190+
1191+
host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
1192+
1193+
cq_host = devm_kzalloc(host->mmc->parent,
1194+
sizeof(*cq_host), GFP_KERNEL);
1195+
if (!cq_host) {
1196+
ret = -ENOMEM;
1197+
goto cleanup;
1198+
}
1199+
1200+
cq_host->mmio = host->ioaddr + SDHCI_TEGRA_CQE_BASE_ADDR;
1201+
cq_host->ops = &sdhci_tegra_cqhci_ops;
1202+
1203+
dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
1204+
if (dma64)
1205+
cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
1206+
1207+
ret = cqhci_init(cq_host, host->mmc, dma64);
1208+
if (ret)
1209+
goto cleanup;
1210+
1211+
ret = __sdhci_add_host(host);
1212+
if (ret)
1213+
goto cleanup;
1214+
1215+
return 0;
1216+
1217+
cleanup:
1218+
sdhci_cleanup_host(host);
1219+
return ret;
1220+
}
1221+
11111222
static int sdhci_tegra_probe(struct platform_device *pdev)
11121223
{
11131224
const struct of_device_id *match;
@@ -1155,9 +1266,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
11551266
if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
11561267
host->mmc->caps |= MMC_CAP_1_8V_DDR;
11571268

1158-
tegra_sdhci_parse_pad_autocal_dt(host);
1159-
1160-
tegra_sdhci_parse_tap_and_trim(host);
1269+
tegra_sdhci_parse_dt(host);
11611270

11621271
tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
11631272
GPIOD_OUT_HIGH);
@@ -1195,7 +1304,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
11951304

11961305
usleep_range(2000, 4000);
11971306

1198-
rc = sdhci_add_host(host);
1307+
rc = sdhci_tegra_add_host(host);
11991308
if (rc)
12001309
goto err_add_host;
12011310

0 commit comments

Comments
 (0)