aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc/host/mtk-sd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/mtk-sd.c')
-rw-r--r--drivers/mmc/host/mtk-sd.c292
1 files changed, 222 insertions, 70 deletions
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 89018b6c97b9..efb0d2d5716b 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -33,6 +33,7 @@
#include <linux/mmc/slot-gpio.h>
#include "cqhci.h"
+#include "mmc_hsq.h"
#define MAX_BD_NUM 1024
#define MSDC_NR_CLOCKS 3
@@ -65,6 +66,7 @@
#define SDC_RESP3 0x4c
#define SDC_BLK_NUM 0x50
#define SDC_ADV_CFG0 0x64
+#define MSDC_NEW_RX_CFG 0x68
#define EMMC_IOCON 0x7c
#define SDC_ACMD_RESP 0x80
#define DMA_SA_H4BIT 0x8c
@@ -91,6 +93,7 @@
#define EMMC_TOP_CONTROL 0x00
#define EMMC_TOP_CMD 0x04
#define EMMC50_PAD_DS_TUNE 0x0c
+#define LOOP_TEST_CONTROL 0x30
/*--------------------------------------------------------------------------*/
/* Register Mask */
@@ -202,9 +205,13 @@
#define SDC_STS_CMDBUSY BIT(1) /* RW */
#define SDC_STS_SWR_COMPL BIT(31) /* RW */
-#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */
/* SDC_ADV_CFG0 mask */
+#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */
#define SDC_RX_ENHANCE_EN BIT(20) /* RW */
+#define SDC_NEW_TX_EN BIT(31) /* RW */
+
+/* MSDC_NEW_RX_CFG mask */
+#define MSDC_NEW_RX_PATH_SEL BIT(0) /* RW */
/* DMA_SA_H4BIT mask */
#define DMA_ADDR_HIGH_4BIT GENMASK(3, 0) /* RW */
@@ -226,6 +233,7 @@
/* MSDC_PATCH_BIT mask */
#define MSDC_PATCH_BIT_ODDSUPP BIT(1) /* RW */
+#define MSDC_PATCH_BIT_RD_DAT_SEL BIT(3) /* RW */
#define MSDC_INT_DAT_LATCH_CK_SEL GENMASK(9, 7)
#define MSDC_CKGEN_MSDC_DLY_SEL GENMASK(14, 10)
#define MSDC_PATCH_BIT_IODSSEL BIT(16) /* RW */
@@ -247,6 +255,8 @@
#define MSDC_PB2_SUPPORT_64G BIT(1) /* RW */
#define MSDC_PB2_RESPWAIT GENMASK(3, 2) /* RW */
#define MSDC_PB2_RESPSTSENSEL GENMASK(18, 16) /* RW */
+#define MSDC_PB2_POP_EN_CNT GENMASK(23, 20) /* RW */
+#define MSDC_PB2_CFGCRCSTSEDGE BIT(25) /* RW */
#define MSDC_PB2_CRCSTSENSEL GENMASK(31, 29) /* RW */
#define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* RW */
@@ -311,6 +321,12 @@
#define PAD_DS_DLY1 GENMASK(14, 10) /* RW */
#define PAD_DS_DLY3 GENMASK(4, 0) /* RW */
+/* LOOP_TEST_CONTROL mask */
+#define TEST_LOOP_DSCLK_MUX_SEL BIT(0) /* RW */
+#define TEST_LOOP_LATCH_MUX_SEL BIT(1) /* RW */
+#define LOOP_EN_SEL_CLK BIT(20) /* RW */
+#define TEST_HS400_CMD_LOOP_MUX_SEL BIT(31) /* RW */
+
#define REQ_CMD_EIO BIT(0)
#define REQ_CMD_TMO BIT(1)
#define REQ_DAT_ERR BIT(2)
@@ -391,6 +407,7 @@ struct msdc_save_para {
u32 emmc_top_control;
u32 emmc_top_cmd;
u32 emmc50_pad_ds_tune;
+ u32 loop_test_control;
};
struct mtk_mmc_compatible {
@@ -402,9 +419,13 @@ struct mtk_mmc_compatible {
bool data_tune;
bool busy_check;
bool stop_clk_fix;
+ u8 stop_dly_sel;
+ u8 pop_en_cnt;
bool enhance_rx;
bool support_64g;
bool use_internal_cd;
+ bool support_new_tx;
+ bool support_new_rx;
};
struct msdc_tune_para {
@@ -473,6 +494,7 @@ struct msdc_host {
bool hs400_tuning; /* hs400 mode online tuning */
bool internal_cd; /* Use internal card-detect logic */
bool cqhci; /* support eMMC hw cmdq */
+ bool hsq_en; /* Host Software Queue is enabled */
struct msdc_save_para save_para; /* used when gate HCLK */
struct msdc_tune_para def_tune_para; /* default tune setting */
struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
@@ -502,6 +524,7 @@ static const struct mtk_mmc_compatible mt2712_compat = {
.data_tune = true,
.busy_check = true,
.stop_clk_fix = true,
+ .stop_dly_sel = 3,
.enhance_rx = true,
.support_64g = true,
};
@@ -515,6 +538,7 @@ static const struct mtk_mmc_compatible mt6779_compat = {
.data_tune = true,
.busy_check = true,
.stop_clk_fix = true,
+ .stop_dly_sel = 3,
.enhance_rx = true,
.support_64g = true,
};
@@ -554,6 +578,7 @@ static const struct mtk_mmc_compatible mt7622_compat = {
.data_tune = true,
.busy_check = true,
.stop_clk_fix = true,
+ .stop_dly_sel = 3,
.enhance_rx = true,
.support_64g = false,
};
@@ -567,6 +592,7 @@ static const struct mtk_mmc_compatible mt7986_compat = {
.data_tune = true,
.busy_check = true,
.stop_clk_fix = true,
+ .stop_dly_sel = 3,
.enhance_rx = true,
.support_64g = true,
};
@@ -606,6 +632,7 @@ static const struct mtk_mmc_compatible mt8183_compat = {
.data_tune = true,
.busy_check = true,
.stop_clk_fix = true,
+ .stop_dly_sel = 3,
.enhance_rx = true,
.support_64g = true,
};
@@ -619,6 +646,24 @@ static const struct mtk_mmc_compatible mt8516_compat = {
.data_tune = true,
.busy_check = true,
.stop_clk_fix = true,
+ .stop_dly_sel = 3,
+};
+
+static const struct mtk_mmc_compatible mt8196_compat = {
+ .clk_div_bits = 12,
+ .recheck_sdio_irq = false,
+ .hs400_tune = false,
+ .pad_tune_reg = MSDC_PAD_TUNE0,
+ .async_fifo = true,
+ .data_tune = true,
+ .busy_check = true,
+ .stop_clk_fix = true,
+ .stop_dly_sel = 1,
+ .pop_en_cnt = 2,
+ .enhance_rx = true,
+ .support_64g = true,
+ .support_new_tx = true,
+ .support_new_rx = true,
};
static const struct of_device_id msdc_of_ids[] = {
@@ -629,9 +674,11 @@ static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
{ .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat},
+ { .compatible = "mediatek,mt7988-mmc", .data = &mt7986_compat},
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
+ { .compatible = "mediatek,mt8196-mmc", .data = &mt8196_compat},
{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
{}
@@ -872,6 +919,41 @@ static int msdc_ungate_clock(struct msdc_host *host)
(val & MSDC_CFG_CKSTB), 1, 20000);
}
+static void msdc_new_tx_setting(struct msdc_host *host)
+{
+ if (!host->top_base)
+ return;
+
+ sdr_set_bits(host->top_base + LOOP_TEST_CONTROL,
+ TEST_LOOP_DSCLK_MUX_SEL);
+ sdr_set_bits(host->top_base + LOOP_TEST_CONTROL,
+ TEST_LOOP_LATCH_MUX_SEL);
+ sdr_clr_bits(host->top_base + LOOP_TEST_CONTROL,
+ TEST_HS400_CMD_LOOP_MUX_SEL);
+
+ switch (host->timing) {
+ case MMC_TIMING_LEGACY:
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR12:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ sdr_clr_bits(host->top_base + LOOP_TEST_CONTROL,
+ LOOP_EN_SEL_CLK);
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ case MMC_TIMING_MMC_HS400:
+ sdr_set_bits(host->top_base + LOOP_TEST_CONTROL,
+ LOOP_EN_SEL_CLK);
+ break;
+ default:
+ break;
+ }
+}
+
static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
{
struct mmc_host *mmc = mmc_from_priv(host);
@@ -881,6 +963,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
u32 sclk;
u32 tune_reg = host->dev_comp->pad_tune_reg;
u32 val;
+ bool timing_changed;
if (!hz) {
dev_dbg(host->dev, "set mclk to 0\n");
@@ -890,6 +973,11 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
return;
}
+ if (host->timing != timing)
+ timing_changed = true;
+ else
+ timing_changed = false;
+
flags = readl(host->base + MSDC_INTEN);
sdr_clr_bits(host->base + MSDC_INTEN, flags);
if (host->dev_comp->clk_div_bits == 8)
@@ -996,6 +1084,9 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
sdr_set_field(host->base + tune_reg,
MSDC_PAD_TUNE_CMDRRDLY,
host->hs400_cmd_int_delay);
+ if (host->dev_comp->support_new_tx && timing_changed)
+ msdc_new_tx_setting(host);
+
dev_dbg(host->dev, "sclk: %d, timing: %d\n", mmc->actual_clock,
timing);
}
@@ -1163,7 +1254,9 @@ static void msdc_track_cmd_data(struct msdc_host *host, struct mmc_command *cmd)
static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
{
+ struct mmc_host *mmc = mmc_from_priv(host);
unsigned long flags;
+ bool hsq_req_done;
/*
* No need check the return value of cancel_delayed_work, as only ONE
@@ -1171,6 +1264,27 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
*/
cancel_delayed_work(&host->req_timeout);
+ /*
+ * If the request was handled from Host Software Queue, there's almost
+ * nothing to do here, and we also don't need to reset mrq as any race
+ * condition would not have any room to happen, since HSQ stores the
+ * "scheduled" mrqs in an internal array of mrq slots anyway.
+ * However, if the controller experienced an error, we still want to
+ * reset it as soon as possible.
+ *
+ * Note that non-HSQ requests will still be happening at times, even
+ * though it is enabled, and that's what is going to reset host->mrq.
+ * Also, msdc_unprepare_data() is going to be called by HSQ when needed
+ * as HSQ request finalization will eventually call the .post_req()
+ * callback of this driver which, in turn, unprepares the data.
+ */
+ hsq_req_done = host->hsq_en ? mmc_hsq_finalize_request(mmc, mrq) : false;
+ if (hsq_req_done) {
+ if (host->error)
+ msdc_reset_hw(host);
+ return;
+ }
+
spin_lock_irqsave(&host->lock, flags);
host->mrq = NULL;
spin_unlock_irqrestore(&host->lock, flags);
@@ -1180,7 +1294,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
msdc_unprepare_data(host, mrq->data);
if (host->error)
msdc_reset_hw(host);
- mmc_request_done(mmc_from_priv(host), mrq);
+ mmc_request_done(mmc, mrq);
if (host->dev_comp->recheck_sdio_irq)
msdc_recheck_sdio_irq(host);
}
@@ -1340,7 +1454,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
struct msdc_host *host = mmc_priv(mmc);
host->error = 0;
- WARN_ON(host->mrq);
+ WARN_ON(!host->hsq_en && host->mrq);
host->mrq = mrq;
if (mrq->data)
@@ -1704,6 +1818,17 @@ static void msdc_init_hw(struct msdc_host *host)
reset_control_deassert(host->reset);
}
+ /* New tx/rx enable bit need to be 0->1 for hardware check */
+ if (host->dev_comp->support_new_tx) {
+ sdr_clr_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN);
+ sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN);
+ msdc_new_tx_setting(host);
+ }
+ if (host->dev_comp->support_new_rx) {
+ sdr_clr_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL);
+ sdr_set_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL);
+ }
+
/* Configure to MMC/SD mode, clock free running */
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN);
@@ -1742,8 +1867,16 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
if (host->dev_comp->stop_clk_fix) {
- sdr_set_field(host->base + MSDC_PATCH_BIT1,
- MSDC_PATCH_BIT1_STOP_DLY, 3);
+ if (host->dev_comp->stop_dly_sel)
+ sdr_set_field(host->base + MSDC_PATCH_BIT1,
+ MSDC_PATCH_BIT1_STOP_DLY,
+ host->dev_comp->stop_dly_sel);
+
+ if (host->dev_comp->pop_en_cnt)
+ sdr_set_field(host->base + MSDC_PATCH_BIT2,
+ MSDC_PB2_POP_EN_CNT,
+ host->dev_comp->pop_en_cnt);
+
sdr_clr_bits(host->base + SDC_FIFO_CFG,
SDC_FIFO_CFG_WRVALIDSEL);
sdr_clr_bits(host->base + SDC_FIFO_CFG,
@@ -2055,6 +2188,19 @@ static inline void msdc_set_data_delay(struct msdc_host *host, u32 value)
}
}
+static inline void msdc_set_data_sample_edge(struct msdc_host *host, bool rising)
+{
+ u32 value = rising ? 0 : 1;
+
+ if (host->dev_comp->support_new_rx) {
+ sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_PATCH_BIT_RD_DAT_SEL, value);
+ sdr_set_field(host->base + MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTSEDGE, value);
+ } else {
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DSPL, value);
+ sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL, value);
+ }
+}
+
static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
{
struct msdc_host *host = mmc_priv(mmc);
@@ -2210,8 +2356,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL,
host->latch_ck);
- sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
- sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, true);
for (i = 0; i < host->tuning_step; i++) {
msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL);
@@ -2224,8 +2369,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
goto skip_fall;
- sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
- sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, false);
for (i = 0; i < host->tuning_step; i++) {
msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL);
@@ -2237,12 +2381,10 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
if (final_maxlen == final_rise_delay.maxlen) {
- sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
- sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, true);
final_delay = final_rise_delay.final_phase;
} else {
- sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
- sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, false);
final_delay = final_fall_delay.final_phase;
}
msdc_set_data_delay(host, final_delay);
@@ -2267,8 +2409,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
host->latch_ck);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- sdr_clr_bits(host->base + MSDC_IOCON,
- MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, true);
for (i = 0; i < host->tuning_step; i++) {
msdc_set_cmd_delay(host, i);
msdc_set_data_delay(host, i);
@@ -2283,8 +2424,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
goto skip_fall;
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- sdr_set_bits(host->base + MSDC_IOCON,
- MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, false);
for (i = 0; i < host->tuning_step; i++) {
msdc_set_cmd_delay(host, i);
msdc_set_data_delay(host, i);
@@ -2298,13 +2438,11 @@ skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
if (final_maxlen == final_rise_delay.maxlen) {
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- sdr_clr_bits(host->base + MSDC_IOCON,
- MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, true);
final_delay = final_rise_delay.final_phase;
} else {
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- sdr_set_bits(host->base + MSDC_IOCON,
- MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, false);
final_delay = final_fall_delay.final_phase;
}
@@ -2324,8 +2462,7 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (host->dev_comp->data_tune && host->dev_comp->async_fifo) {
ret = msdc_tune_together(mmc, opcode);
if (host->hs400_mode) {
- sdr_clr_bits(host->base + MSDC_IOCON,
- MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ msdc_set_data_sample_edge(host, true);
msdc_set_data_delay(host, 0);
}
goto tune_done;
@@ -2727,7 +2864,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct msdc_host *host;
- struct resource *res;
int ret;
if (!pdev->dev.of_node) {
@@ -2736,77 +2872,64 @@ static int msdc_drv_probe(struct platform_device *pdev)
}
/* Allocate MMC host for this device */
- mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev);
+ mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(struct msdc_host));
if (!mmc)
return -ENOMEM;
host = mmc_priv(mmc);
ret = mmc_of_parse(mmc);
if (ret)
- goto host_free;
+ return ret;
host->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(host->base)) {
- ret = PTR_ERR(host->base);
- goto host_free;
- }
+ if (IS_ERR(host->base))
+ return PTR_ERR(host->base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (res) {
- host->top_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(host->top_base))
- host->top_base = NULL;
- }
+ host->top_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(host->top_base))
+ host->top_base = NULL;
ret = mmc_regulator_get_supply(mmc);
if (ret)
- goto host_free;
+ return ret;
ret = msdc_of_clock_parse(pdev, host);
if (ret)
- goto host_free;
+ return ret;
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"hrst");
- if (IS_ERR(host->reset)) {
- ret = PTR_ERR(host->reset);
- goto host_free;
- }
+ if (IS_ERR(host->reset))
+ return PTR_ERR(host->reset);
/* only eMMC has crypto property */
if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
if (IS_ERR(host->crypto_clk))
- host->crypto_clk = NULL;
- else
+ return PTR_ERR(host->crypto_clk);
+ else if (host->crypto_clk)
mmc->caps2 |= MMC_CAP2_CRYPTO;
}
host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0) {
- ret = host->irq;
- goto host_free;
- }
+ if (host->irq < 0)
+ return host->irq;
host->pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR(host->pinctrl)) {
- ret = PTR_ERR(host->pinctrl);
- dev_err(&pdev->dev, "Cannot find pinctrl!\n");
- goto host_free;
- }
+ if (IS_ERR(host->pinctrl))
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->pinctrl),
+ "Cannot find pinctrl");
host->pins_default = pinctrl_lookup_state(host->pinctrl, "default");
if (IS_ERR(host->pins_default)) {
- ret = PTR_ERR(host->pins_default);
dev_err(&pdev->dev, "Cannot find pinctrl default!\n");
- goto host_free;
+ return PTR_ERR(host->pins_default);
}
host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs");
if (IS_ERR(host->pins_uhs)) {
- ret = PTR_ERR(host->pins_uhs);
dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n");
- goto host_free;
+ return PTR_ERR(host->pins_uhs);
}
/* Support for SDIO eint irq ? */
@@ -2885,7 +3008,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
ret = msdc_ungate_clock(host);
if (ret) {
dev_err(&pdev->dev, "Cannot ungate clocks!\n");
- goto release_mem;
+ goto release_clk;
}
msdc_init_hw(host);
@@ -2895,20 +3018,33 @@ static int msdc_drv_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!host->cq_host) {
ret = -ENOMEM;
- goto host_free;
+ goto release;
}
host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
host->cq_host->mmio = host->base + 0x800;
host->cq_host->ops = &msdc_cmdq_ops;
ret = cqhci_init(host->cq_host, mmc, true);
if (ret)
- goto host_free;
+ goto release;
mmc->max_segs = 128;
/* cqhci 16bit length */
/* 0 size, means 65536 so we don't have to -1 here */
mmc->max_seg_size = 64 * 1024;
/* Reduce CIT to 0x40 that corresponds to 2.35us */
msdc_cqe_cit_cal(host, 2350);
+ } else if (mmc->caps2 & MMC_CAP2_NO_SDIO) {
+ /* Use HSQ on eMMC/SD (but not on SDIO) if HW CQE not supported */
+ struct mmc_hsq *hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
+ if (!hsq) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ ret = mmc_hsq_init(hsq, mmc);
+ if (ret)
+ goto release;
+
+ host->hsq_en = true;
}
ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
@@ -2929,9 +3065,10 @@ static int msdc_drv_probe(struct platform_device *pdev)
end:
pm_runtime_disable(host->dev);
release:
- platform_set_drvdata(pdev, NULL);
msdc_deinit_hw(host);
+release_clk:
msdc_gate_clock(host);
+ platform_set_drvdata(pdev, NULL);
release_mem:
if (host->dma.gpd)
dma_free_coherent(&pdev->dev,
@@ -2939,11 +3076,8 @@ release_mem:
host->dma.gpd, host->dma.gpd_addr);
if (host->dma.bd)
dma_free_coherent(&pdev->dev,
- MAX_BD_NUM * sizeof(struct mt_bdma_desc),
- host->dma.bd, host->dma.bd_addr);
-host_free:
- mmc_free_host(mmc);
-
+ MAX_BD_NUM * sizeof(struct mt_bdma_desc),
+ host->dma.bd, host->dma.bd_addr);
return ret;
}
@@ -2968,9 +3102,7 @@ static void msdc_drv_remove(struct platform_device *pdev)
2 * sizeof(struct mt_gpdma_desc),
host->dma.gpd, host->dma.gpd_addr);
dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc),
- host->dma.bd, host->dma.bd_addr);
-
- mmc_free_host(mmc);
+ host->dma.bd, host->dma.bd_addr);
}
static void msdc_save_reg(struct msdc_host *host)
@@ -2995,6 +3127,8 @@ static void msdc_save_reg(struct msdc_host *host)
readl(host->top_base + EMMC_TOP_CMD);
host->save_para.emmc50_pad_ds_tune =
readl(host->top_base + EMMC50_PAD_DS_TUNE);
+ host->save_para.loop_test_control =
+ readl(host->top_base + LOOP_TEST_CONTROL);
} else {
host->save_para.pad_tune = readl(host->base + tune_reg);
}
@@ -3005,6 +3139,15 @@ static void msdc_restore_reg(struct msdc_host *host)
struct mmc_host *mmc = mmc_from_priv(host);
u32 tune_reg = host->dev_comp->pad_tune_reg;
+ if (host->dev_comp->support_new_tx) {
+ sdr_clr_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN);
+ sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN);
+ }
+ if (host->dev_comp->support_new_rx) {
+ sdr_clr_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL);
+ sdr_set_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL);
+ }
+
writel(host->save_para.msdc_cfg, host->base + MSDC_CFG);
writel(host->save_para.iocon, host->base + MSDC_IOCON);
writel(host->save_para.sdc_cfg, host->base + SDC_CFG);
@@ -3023,6 +3166,8 @@ static void msdc_restore_reg(struct msdc_host *host)
host->top_base + EMMC_TOP_CMD);
writel(host->save_para.emmc50_pad_ds_tune,
host->top_base + EMMC50_PAD_DS_TUNE);
+ writel(host->save_para.loop_test_control,
+ host->top_base + LOOP_TEST_CONTROL);
} else {
writel(host->save_para.pad_tune, host->base + tune_reg);
}
@@ -3036,6 +3181,9 @@ static int __maybe_unused msdc_runtime_suspend(struct device *dev)
struct mmc_host *mmc = dev_get_drvdata(dev);
struct msdc_host *host = mmc_priv(mmc);
+ if (host->hsq_en)
+ mmc_hsq_suspend(mmc);
+
msdc_save_reg(host);
if (sdio_irq_claimed(mmc)) {
@@ -3066,6 +3214,10 @@ static int __maybe_unused msdc_runtime_resume(struct device *dev)
pinctrl_select_state(host->pinctrl, host->pins_uhs);
enable_irq(host->irq);
}
+
+ if (host->hsq_en)
+ mmc_hsq_resume(mmc);
+
return 0;
}
@@ -3112,7 +3264,7 @@ static const struct dev_pm_ops msdc_dev_pm_ops = {
static struct platform_driver mt_msdc_driver = {
.probe = msdc_drv_probe,
- .remove_new = msdc_drv_remove,
+ .remove = msdc_drv_remove,
.driver = {
.name = "mtk-msdc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,