Lines Matching +full:dw +full:- +full:mshc +full:- +full:sdr +full:- +full:timing

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver
19 #include "dw_mmc-pltfm.h"
20 #include "dw_mmc-exynos.h"
22 /* Variations in Exynos specific dw-mshc controller */
53 .compatible = "samsung,exynos4210-dw-mshc",
56 .compatible = "samsung,exynos4412-dw-mshc",
59 .compatible = "samsung,exynos5250-dw-mshc",
62 .compatible = "samsung,exynos5420-dw-mshc",
65 .compatible = "samsung,exynos5420-dw-mshc-smu",
68 .compatible = "samsung,exynos7-dw-mshc",
71 .compatible = "samsung,exynos7-dw-mshc-smu",
74 .compatible = "axis,artpec8-dw-mshc",
81 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_get_ciu_div()
83 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) in dw_mci_exynos_get_ciu_div()
85 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) in dw_mci_exynos_get_ciu_div()
87 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_get_ciu_div()
88 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_get_ciu_div()
89 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_get_ciu_div()
97 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_config_smu()
101 * set for non-ecryption mode at this time. in dw_mci_exynos_config_smu()
103 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || in dw_mci_exynos_config_smu()
104 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { in dw_mci_exynos_config_smu()
116 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_priv_init()
120 if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) { in dw_mci_exynos_priv_init()
121 priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL); in dw_mci_exynos_priv_init()
122 priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN); in dw_mci_exynos_priv_init()
123 priv->saved_dqs_en |= AXI_NON_BLOCKING_WR; in dw_mci_exynos_priv_init()
124 mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en); in dw_mci_exynos_priv_init()
125 if (!priv->dqs_delay) in dw_mci_exynos_priv_init()
126 priv->dqs_delay = in dw_mci_exynos_priv_init()
127 DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); in dw_mci_exynos_priv_init()
130 if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) { in dw_mci_exynos_priv_init()
131 /* Quirk needed for the ARTPEC-8 SoC */ in dw_mci_exynos_priv_init()
132 host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT; in dw_mci_exynos_priv_init()
135 host->bus_hz /= (priv->ciu_div + 1); in dw_mci_exynos_priv_init()
140 static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) in dw_mci_exynos_set_clksel_timing() argument
142 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_set_clksel_timing()
145 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_set_clksel_timing()
146 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_set_clksel_timing()
147 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_set_clksel_timing()
152 clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing; in dw_mci_exynos_set_clksel_timing()
154 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_set_clksel_timing()
155 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_set_clksel_timing()
156 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_set_clksel_timing()
163 * use of bit 29 (which is reserved on standard MSHC controllers) for in dw_mci_exynos_set_clksel_timing()
168 if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->slot) in dw_mci_exynos_set_clksel_timing()
169 set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags); in dw_mci_exynos_set_clksel_timing()
190 * dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
203 * dw_mci_exynos_resume_noirq - Exynos-specific resume code
216 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_resume_noirq()
224 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_resume_noirq()
225 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_resume_noirq()
226 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_resume_noirq()
232 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_resume_noirq()
233 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_resume_noirq()
234 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_resume_noirq()
246 static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) in dw_mci_exynos_config_hs400() argument
248 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_config_hs400()
255 if ((priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) || in dw_mci_exynos_config_hs400()
256 (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)) { in dw_mci_exynos_config_hs400()
257 if (timing == MMC_TIMING_MMC_HS400) in dw_mci_exynos_config_hs400()
258 dev_warn(host->dev, in dw_mci_exynos_config_hs400()
263 dqs = priv->saved_dqs_en; in dw_mci_exynos_config_hs400()
264 strobe = priv->saved_strobe_ctrl; in dw_mci_exynos_config_hs400()
266 if (timing == MMC_TIMING_MMC_HS400) { in dw_mci_exynos_config_hs400()
268 strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay); in dw_mci_exynos_config_hs400()
269 } else if (timing == MMC_TIMING_UHS_SDR104) { in dw_mci_exynos_config_hs400()
281 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_adjust_clock()
289 if (!wanted || IS_ERR(host->ciu_clk)) in dw_mci_exynos_adjust_clock()
296 if (wanted == priv->cur_speed) in dw_mci_exynos_adjust_clock()
300 ret = clk_set_rate(host->ciu_clk, wanted * div); in dw_mci_exynos_adjust_clock()
302 dev_warn(host->dev, in dw_mci_exynos_adjust_clock()
303 "failed to set clk-rate %u error: %d\n", in dw_mci_exynos_adjust_clock()
305 actual = clk_get_rate(host->ciu_clk); in dw_mci_exynos_adjust_clock()
306 host->bus_hz = actual / div; in dw_mci_exynos_adjust_clock()
307 priv->cur_speed = wanted; in dw_mci_exynos_adjust_clock()
308 host->current_speed = 0; in dw_mci_exynos_adjust_clock()
313 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_set_ios()
314 unsigned int wanted = ios->clock; in dw_mci_exynos_set_ios()
315 u32 timing = ios->timing, clksel; in dw_mci_exynos_set_ios() local
317 switch (timing) { in dw_mci_exynos_set_ios()
319 /* Update tuned sample timing */ in dw_mci_exynos_set_ios()
321 priv->hs400_timing, priv->tuned_sample); in dw_mci_exynos_set_ios()
325 clksel = priv->ddr_timing; in dw_mci_exynos_set_ios()
327 if (ios->bus_width == MMC_BUS_WIDTH_8) in dw_mci_exynos_set_ios()
332 clksel = (priv->sdr_timing & 0xfff8ffff) | in dw_mci_exynos_set_ios()
333 (priv->ciu_div << 16); in dw_mci_exynos_set_ios()
336 clksel = (priv->ddr_timing & 0xfff8ffff) | in dw_mci_exynos_set_ios()
337 (priv->ciu_div << 16); in dw_mci_exynos_set_ios()
340 clksel = priv->sdr_timing; in dw_mci_exynos_set_ios()
343 /* Set clock timing for the requested speed mode*/ in dw_mci_exynos_set_ios()
347 dw_mci_exynos_config_hs400(host, timing); in dw_mci_exynos_set_ios()
356 struct device_node *np = host->dev->of_node; in dw_mci_exynos_parse_dt()
357 u32 timing[2]; in dw_mci_exynos_parse_dt() local
362 priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); in dw_mci_exynos_parse_dt()
364 return -ENOMEM; in dw_mci_exynos_parse_dt()
368 priv->ctrl_type = exynos_compat[idx].ctrl_type; in dw_mci_exynos_parse_dt()
371 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) in dw_mci_exynos_parse_dt()
372 priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1; in dw_mci_exynos_parse_dt()
373 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) in dw_mci_exynos_parse_dt()
374 priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1; in dw_mci_exynos_parse_dt()
376 of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div); in dw_mci_exynos_parse_dt()
377 priv->ciu_div = div; in dw_mci_exynos_parse_dt()
381 "samsung,dw-mshc-sdr-timing", timing, 2); in dw_mci_exynos_parse_dt()
385 priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); in dw_mci_exynos_parse_dt()
388 "samsung,dw-mshc-ddr-timing", timing, 2); in dw_mci_exynos_parse_dt()
392 priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); in dw_mci_exynos_parse_dt()
395 "samsung,dw-mshc-hs400-timing", timing, 2); in dw_mci_exynos_parse_dt()
397 "samsung,read-strobe-delay", &priv->dqs_delay)) in dw_mci_exynos_parse_dt()
398 dev_dbg(host->dev, in dw_mci_exynos_parse_dt()
399 "read-strobe-delay is not found, assuming usage of default value\n"); in dw_mci_exynos_parse_dt()
401 priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], in dw_mci_exynos_parse_dt()
403 host->priv = priv; in dw_mci_exynos_parse_dt()
409 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_get_clksmpl()
411 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_get_clksmpl()
412 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_get_clksmpl()
413 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_get_clksmpl()
422 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_set_clksmpl()
424 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_set_clksmpl()
425 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_set_clksmpl()
426 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_set_clksmpl()
431 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_set_clksmpl()
432 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_set_clksmpl()
433 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_set_clksmpl()
441 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_move_next_clksmpl()
445 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_move_next_clksmpl()
446 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_move_next_clksmpl()
447 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_move_next_clksmpl()
455 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || in dw_mci_exynos_move_next_clksmpl()
456 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || in dw_mci_exynos_move_next_clksmpl()
457 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) in dw_mci_exynos_move_next_clksmpl()
469 s8 i, loc = -1; in dw_mci_exynos_get_best_clksmpl()
488 * If there is no cadiates value, then it needs to return -EIO. in dw_mci_exynos_get_best_clksmpl()
505 struct dw_mci *host = slot->host; in dw_mci_exynos_execute_tuning()
506 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_execute_tuning()
507 struct mmc_host *mmc = slot->mmc; in dw_mci_exynos_execute_tuning()
526 priv->tuned_sample = found; in dw_mci_exynos_execute_tuning()
528 ret = -EIO; in dw_mci_exynos_execute_tuning()
529 dev_warn(&mmc->class_dev, in dw_mci_exynos_execute_tuning()
539 struct dw_mci_exynos_priv_data *priv = host->priv; in dw_mci_exynos_prepare_hs400_tuning()
541 dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing); in dw_mci_exynos_prepare_hs400_tuning()
542 dw_mci_exynos_adjust_clock(host, (ios->clock) << 1); in dw_mci_exynos_prepare_hs400_tuning()
558 tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC); in dw_mci_exynos_set_data_timeout()
566 * ((TMOUT[10:8] - 1) * 0xFFFFFF + TMOUT[31:11] * 8) in dw_mci_exynos_set_data_timeout()
576 tmp = tmp - ((tmp2 - 1) * 0xFFFFFF); in dw_mci_exynos_set_data_timeout()
581 dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: %#08x", in dw_mci_exynos_set_data_timeout()
591 return (((drto_clks & 0x7) - 1) * 0xFFFFFF) + ((drto_clks & 0xFFFFF8)); in dw_mci_exynos_get_drto_clks()
624 { .compatible = "samsung,exynos4412-dw-mshc",
626 { .compatible = "samsung,exynos5250-dw-mshc",
628 { .compatible = "samsung,exynos5420-dw-mshc",
630 { .compatible = "samsung,exynos5420-dw-mshc-smu",
632 { .compatible = "samsung,exynos7-dw-mshc",
634 { .compatible = "samsung,exynos7-dw-mshc-smu",
636 { .compatible = "axis,artpec8-dw-mshc",
648 match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node); in dw_mci_exynos_probe()
649 drv_data = match->data; in dw_mci_exynos_probe()
651 pm_runtime_get_noresume(&pdev->dev); in dw_mci_exynos_probe()
652 pm_runtime_set_active(&pdev->dev); in dw_mci_exynos_probe()
653 pm_runtime_enable(&pdev->dev); in dw_mci_exynos_probe()
657 pm_runtime_disable(&pdev->dev); in dw_mci_exynos_probe()
658 pm_runtime_set_suspended(&pdev->dev); in dw_mci_exynos_probe()
659 pm_runtime_put_noidle(&pdev->dev); in dw_mci_exynos_probe()
669 pm_runtime_disable(&pdev->dev); in dw_mci_exynos_remove()
670 pm_runtime_set_suspended(&pdev->dev); in dw_mci_exynos_remove()
671 pm_runtime_put_noidle(&pdev->dev); in dw_mci_exynos_remove()
697 MODULE_DESCRIPTION("Samsung Specific DW-MSHC Driver Extension");