diff options
Diffstat (limited to 'drivers/mmc/host/mtk-sd.c')
-rw-r--r-- | drivers/mmc/host/mtk-sd.c | 145 |
1 files changed, 126 insertions, 19 deletions
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index aef30bba00b9..4c239a4cf8d9 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -66,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 @@ -92,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 */ @@ -203,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 */ @@ -227,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 */ @@ -249,6 +256,7 @@ #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 */ @@ -313,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) @@ -393,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 { @@ -409,6 +424,8 @@ struct mtk_mmc_compatible { bool enhance_rx; bool support_64g; bool use_internal_cd; + bool support_new_tx; + bool support_new_rx; }; struct msdc_tune_para { @@ -632,6 +649,23 @@ static const struct mtk_mmc_compatible mt8516_compat = { .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[] = { { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, @@ -643,6 +677,7 @@ static const struct of_device_id msdc_of_ids[] = { { .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}, {} @@ -883,6 +918,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); @@ -892,6 +962,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"); @@ -901,6 +972,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) @@ -1007,6 +1083,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); } @@ -1738,6 +1817,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); @@ -2097,6 +2187,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); @@ -2252,8 +2355,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); @@ -2266,8 +2368,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); @@ -2279,12 +2380,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); @@ -2309,8 +2408,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); @@ -2325,8 +2423,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); @@ -2340,13 +2437,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; } @@ -2366,8 +2461,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; @@ -3030,6 +3124,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); } @@ -3040,6 +3136,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); @@ -3058,6 +3163,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); } |