Lines Matching +full:host +full:- +full:only

1 // SPDX-License-Identifier: GPL-2.0-only
8 * Date: 2016-8-24
22 #include <linux/dma-mapping.h>
24 #include "sdhci-pltfm.h"
25 #include "sdhci-xenon.h"
27 static int xenon_enable_internal_clk(struct sdhci_host *host) in xenon_enable_internal_clk() argument
32 reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); in xenon_enable_internal_clk()
34 sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL); in xenon_enable_internal_clk()
40 reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); in xenon_enable_internal_clk()
44 dev_err(mmc_dev(host->mmc), "Internal clock never stabilised.\n"); in xenon_enable_internal_clk()
45 return -ETIMEDOUT; in xenon_enable_internal_clk()
53 /* Set SDCLK-off-while-idle */
54 static void xenon_set_sdclk_off_idle(struct sdhci_host *host, in xenon_set_sdclk_off_idle() argument
60 reg = sdhci_readl(host, XENON_SYS_OP_CTRL); in xenon_set_sdclk_off_idle()
68 sdhci_writel(host, reg, XENON_SYS_OP_CTRL); in xenon_set_sdclk_off_idle()
72 static void xenon_set_acg(struct sdhci_host *host, bool enable) in xenon_set_acg() argument
76 reg = sdhci_readl(host, XENON_SYS_OP_CTRL); in xenon_set_acg()
81 sdhci_writel(host, reg, XENON_SYS_OP_CTRL); in xenon_set_acg()
85 static void xenon_enable_sdhc(struct sdhci_host *host, in xenon_enable_sdhc() argument
90 reg = sdhci_readl(host, XENON_SYS_OP_CTRL); in xenon_enable_sdhc()
92 sdhci_writel(host, reg, XENON_SYS_OP_CTRL); in xenon_enable_sdhc()
94 host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; in xenon_enable_sdhc()
99 host->mmc->caps &= ~MMC_CAP_BUS_WIDTH_TEST; in xenon_enable_sdhc()
103 static void xenon_disable_sdhc(struct sdhci_host *host, in xenon_disable_sdhc() argument
108 reg = sdhci_readl(host, XENON_SYS_OP_CTRL); in xenon_disable_sdhc()
110 sdhci_writel(host, reg, XENON_SYS_OP_CTRL); in xenon_disable_sdhc()
114 static void xenon_enable_sdhc_parallel_tran(struct sdhci_host *host, in xenon_enable_sdhc_parallel_tran() argument
119 reg = sdhci_readl(host, XENON_SYS_EXT_OP_CTRL); in xenon_enable_sdhc_parallel_tran()
121 sdhci_writel(host, reg, XENON_SYS_EXT_OP_CTRL); in xenon_enable_sdhc_parallel_tran()
125 static void xenon_mask_cmd_conflict_err(struct sdhci_host *host) in xenon_mask_cmd_conflict_err() argument
129 reg = sdhci_readl(host, XENON_SYS_EXT_OP_CTRL); in xenon_mask_cmd_conflict_err()
131 sdhci_writel(host, reg, XENON_SYS_EXT_OP_CTRL); in xenon_mask_cmd_conflict_err()
134 static void xenon_retune_setup(struct sdhci_host *host) in xenon_retune_setup() argument
136 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_retune_setup()
140 /* Disable the Re-Tuning Request functionality */ in xenon_retune_setup()
141 reg = sdhci_readl(host, XENON_SLOT_RETUNING_REQ_CTRL); in xenon_retune_setup()
143 sdhci_writel(host, reg, XENON_SLOT_RETUNING_REQ_CTRL); in xenon_retune_setup()
145 /* Disable the Re-tuning Interrupt */ in xenon_retune_setup()
146 reg = sdhci_readl(host, SDHCI_SIGNAL_ENABLE); in xenon_retune_setup()
148 sdhci_writel(host, reg, SDHCI_SIGNAL_ENABLE); in xenon_retune_setup()
149 reg = sdhci_readl(host, SDHCI_INT_ENABLE); in xenon_retune_setup()
151 sdhci_writel(host, reg, SDHCI_INT_ENABLE); in xenon_retune_setup()
154 host->tuning_mode = SDHCI_TUNING_MODE_1; in xenon_retune_setup()
155 /* Set re-tuning period */ in xenon_retune_setup()
156 host->tuning_count = 1 << (priv->tuning_count - 1); in xenon_retune_setup()
163 static void xenon_reset_exit(struct sdhci_host *host, in xenon_reset_exit() argument
166 /* Only SOFTWARE RESET ALL will clear the register setting */ in xenon_reset_exit()
170 /* Disable tuning request and auto-retuning again */ in xenon_reset_exit()
171 xenon_retune_setup(host); in xenon_reset_exit()
178 xenon_set_acg(host, false); in xenon_reset_exit()
180 xenon_set_sdclk_off_idle(host, sdhc_id, false); in xenon_reset_exit()
182 xenon_mask_cmd_conflict_err(host); in xenon_reset_exit()
185 static void xenon_reset(struct sdhci_host *host, u8 mask) in xenon_reset() argument
187 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_reset()
190 sdhci_reset(host, mask); in xenon_reset()
191 xenon_reset_exit(host, priv->sdhc_id, mask); in xenon_reset()
198 static void xenon_set_uhs_signaling(struct sdhci_host *host, in xenon_set_uhs_signaling() argument
203 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); in xenon_set_uhs_signaling()
204 /* Select Bus Speed Mode for host */ in xenon_set_uhs_signaling()
221 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); in xenon_set_uhs_signaling()
224 static void xenon_set_power(struct sdhci_host *host, unsigned char mode, in xenon_set_power() argument
227 struct mmc_host *mmc = host->mmc; in xenon_set_power()
228 u8 pwr = host->pwr; in xenon_set_power()
230 sdhci_set_power_noreg(host, mode, vdd); in xenon_set_power()
232 if (host->pwr == pwr) in xenon_set_power()
235 if (host->pwr == 0) in xenon_set_power()
238 if (!IS_ERR(mmc->supply.vmmc)) in xenon_set_power()
239 mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); in xenon_set_power()
242 static void xenon_voltage_switch(struct sdhci_host *host) in xenon_voltage_switch() argument
248 static unsigned int xenon_get_max_clock(struct sdhci_host *host) in xenon_get_max_clock() argument
250 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_get_max_clock()
252 if (pltfm_host->clk) in xenon_get_max_clock()
253 return sdhci_pltfm_clk_get_max_clock(host); in xenon_get_max_clock()
255 return pltfm_host->clock; in xenon_get_max_clock()
280 struct sdhci_host *host = mmc_priv(mmc); in xenon_set_ios() local
281 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_set_ios()
292 if ((ios->timing == MMC_TIMING_MMC_HS400) || in xenon_set_ios()
293 (ios->timing == MMC_TIMING_MMC_HS200) || in xenon_set_ios()
294 (ios->timing == MMC_TIMING_MMC_HS)) { in xenon_set_ios()
295 host->preset_enabled = false; in xenon_set_ios()
296 host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; in xenon_set_ios()
297 host->flags &= ~SDHCI_PV_ENABLED; in xenon_set_ios()
299 reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); in xenon_set_ios()
301 sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); in xenon_set_ios()
303 host->quirks2 &= ~SDHCI_QUIRK2_PRESET_VALUE_BROKEN; in xenon_set_ios()
307 xenon_phy_adj(host, ios); in xenon_set_ios()
309 if (host->clock > XENON_DEFAULT_SDCLK_FREQ) in xenon_set_ios()
310 xenon_set_sdclk_off_idle(host, priv->sdhc_id, true); in xenon_set_ios()
316 struct sdhci_host *host = mmc_priv(mmc); in xenon_start_signal_voltage_switch() local
328 xenon_enable_internal_clk(host); in xenon_start_signal_voltage_switch()
330 xenon_soc_pad_ctrl(host, ios->signal_voltage); in xenon_start_signal_voltage_switch()
337 if (PTR_ERR(mmc->supply.vqmmc) == -ENODEV) in xenon_start_signal_voltage_switch()
345 * priv->init_card_type will be used in PHY timing adjustment.
349 struct sdhci_host *host = mmc_priv(mmc); in xenon_init_card() local
350 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_init_card()
354 priv->init_card_type = card->type; in xenon_init_card()
359 struct sdhci_host *host = mmc_priv(mmc); in xenon_execute_tuning() local
361 if (host->timing == MMC_TIMING_UHS_DDR50 || in xenon_execute_tuning()
362 host->timing == MMC_TIMING_MMC_DDR52) in xenon_execute_tuning()
366 * Currently force Xenon driver back to support mode 1 only, in xenon_execute_tuning()
370 if (host->tuning_mode != SDHCI_TUNING_MODE_1) in xenon_execute_tuning()
371 xenon_retune_setup(host); in xenon_execute_tuning()
378 struct sdhci_host *host = mmc_priv(mmc); in xenon_enable_sdio_irq() local
379 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_enable_sdio_irq()
382 u8 sdhc_id = priv->sdhc_id; in xenon_enable_sdio_irq()
391 reg = sdhci_readl(host, XENON_SYS_CFG_INFO); in xenon_enable_sdio_irq()
393 sdhci_writel(host, reg, XENON_SYS_CFG_INFO); in xenon_enable_sdio_irq()
396 reg = sdhci_readl(host, XENON_SYS_CFG_INFO); in xenon_enable_sdio_irq()
398 sdhci_writel(host, reg, XENON_SYS_CFG_INFO); in xenon_enable_sdio_irq()
402 static void xenon_replace_mmc_host_ops(struct sdhci_host *host) in xenon_replace_mmc_host_ops() argument
404 host->mmc_host_ops.set_ios = xenon_set_ios; in xenon_replace_mmc_host_ops()
405 host->mmc_host_ops.start_signal_voltage_switch = in xenon_replace_mmc_host_ops()
407 host->mmc_host_ops.init_card = xenon_init_card; in xenon_replace_mmc_host_ops()
408 host->mmc_host_ops.execute_tuning = xenon_execute_tuning; in xenon_replace_mmc_host_ops()
409 host->mmc_host_ops.enable_sdio_irq = xenon_enable_sdio_irq; in xenon_replace_mmc_host_ops()
414 * sdhc-id: the index of current SDHC.
416 * tun-count: the interval between re-tuning
420 struct device *dev = &pdev->dev; in xenon_probe_params()
421 struct sdhci_host *host = platform_get_drvdata(pdev); in xenon_probe_params() local
422 struct mmc_host *mmc = host->mmc; in xenon_probe_params()
423 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_probe_params()
430 if (priv->hw_version == XENON_AP806) in xenon_probe_params()
431 host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; in xenon_probe_params()
434 if (!device_property_read_u32(dev, "marvell,xenon-sdhc-id", &sdhc_id)) { in xenon_probe_params()
435 nr_sdhc = sdhci_readl(host, XENON_SYS_CFG_INFO); in xenon_probe_params()
440 return -EINVAL; in xenon_probe_params()
443 priv->sdhc_id = sdhc_id; in xenon_probe_params()
446 if (!device_property_read_u32(dev, "marvell,xenon-tun-count", in xenon_probe_params()
449 dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n", in xenon_probe_params()
454 priv->tuning_count = tuning_count; in xenon_probe_params()
457 * AC5/X/IM HW has only 31-bits passed in the crossbar switch. in xenon_probe_params()
460 * represented. In this case, disable ADMA, 64-bit DMA and allow only SDMA. in xenon_probe_params()
462 * generic SDHCI driver, which will make sure DMA is only done in xenon_probe_params()
465 if (priv->hw_version == XENON_AC5) { in xenon_probe_params()
468 host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; in xenon_probe_params()
469 host->quirks2 |= SDHCI_QUIRK2_BROKEN_64_BIT_DMA; in xenon_probe_params()
473 return xenon_phy_parse_params(dev, host); in xenon_probe_params()
476 static int xenon_sdhc_prepare(struct sdhci_host *host) in xenon_sdhc_prepare() argument
478 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_sdhc_prepare()
480 u8 sdhc_id = priv->sdhc_id; in xenon_sdhc_prepare()
483 xenon_enable_sdhc(host, sdhc_id); in xenon_sdhc_prepare()
486 xenon_set_acg(host, true); in xenon_sdhc_prepare()
489 xenon_enable_sdhc_parallel_tran(host, sdhc_id); in xenon_sdhc_prepare()
491 /* Disable SDCLK-Off-While-Idle before card init */ in xenon_sdhc_prepare()
492 xenon_set_sdclk_off_idle(host, sdhc_id, false); in xenon_sdhc_prepare()
494 xenon_mask_cmd_conflict_err(host); in xenon_sdhc_prepare()
499 static void xenon_sdhc_unprepare(struct sdhci_host *host) in xenon_sdhc_unprepare() argument
501 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_sdhc_unprepare()
503 u8 sdhc_id = priv->sdhc_id; in xenon_sdhc_unprepare()
506 xenon_disable_sdhc(host, sdhc_id); in xenon_sdhc_unprepare()
512 struct device *dev = &pdev->dev; in xenon_probe()
513 struct sdhci_host *host; in xenon_probe() local
517 host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata, in xenon_probe()
519 if (IS_ERR(host)) in xenon_probe()
520 return PTR_ERR(host); in xenon_probe()
522 pltfm_host = sdhci_priv(host); in xenon_probe()
525 priv->hw_version = (unsigned long)device_get_match_data(&pdev->dev); in xenon_probe()
531 xenon_replace_mmc_host_ops(host); in xenon_probe()
533 if (dev->of_node) { in xenon_probe()
534 pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); in xenon_probe()
535 if (IS_ERR(pltfm_host->clk)) { in xenon_probe()
536 err = PTR_ERR(pltfm_host->clk); in xenon_probe()
537 dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err); in xenon_probe()
540 err = clk_prepare_enable(pltfm_host->clk); in xenon_probe()
544 priv->axi_clk = devm_clk_get(&pdev->dev, "axi"); in xenon_probe()
545 if (IS_ERR(priv->axi_clk)) { in xenon_probe()
546 err = PTR_ERR(priv->axi_clk); in xenon_probe()
547 if (err == -EPROBE_DEFER) in xenon_probe()
550 err = clk_prepare_enable(priv->axi_clk); in xenon_probe()
556 err = mmc_of_parse(host->mmc); in xenon_probe()
562 xenon_set_acg(host, false); in xenon_probe()
569 err = xenon_sdhc_prepare(host); in xenon_probe()
573 pm_runtime_get_noresume(&pdev->dev); in xenon_probe()
574 pm_runtime_set_active(&pdev->dev); in xenon_probe()
575 pm_runtime_set_autosuspend_delay(&pdev->dev, 50); in xenon_probe()
576 pm_runtime_use_autosuspend(&pdev->dev); in xenon_probe()
577 pm_runtime_enable(&pdev->dev); in xenon_probe()
578 pm_suspend_ignore_children(&pdev->dev, 1); in xenon_probe()
580 err = sdhci_add_host(host); in xenon_probe()
584 pm_runtime_put_autosuspend(&pdev->dev); in xenon_probe()
587 * then we disable ADMA and 64-bit DMA. in xenon_probe()
589 * 32-bit. Since DDR starts at 0x2_0000_0000, we must use in xenon_probe()
590 * 34-bit DMA mask to access this DDR memory: in xenon_probe()
592 if (priv->hw_version == XENON_AC5 && in xenon_probe()
593 host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) in xenon_probe()
594 dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); in xenon_probe()
599 pm_runtime_disable(&pdev->dev); in xenon_probe()
600 pm_runtime_put_noidle(&pdev->dev); in xenon_probe()
601 xenon_sdhc_unprepare(host); in xenon_probe()
603 clk_disable_unprepare(priv->axi_clk); in xenon_probe()
605 clk_disable_unprepare(pltfm_host->clk); in xenon_probe()
613 struct sdhci_host *host = platform_get_drvdata(pdev); in xenon_remove() local
614 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_remove()
617 pm_runtime_get_sync(&pdev->dev); in xenon_remove()
618 pm_runtime_disable(&pdev->dev); in xenon_remove()
619 pm_runtime_put_noidle(&pdev->dev); in xenon_remove()
621 sdhci_remove_host(host, 0); in xenon_remove()
623 xenon_sdhc_unprepare(host); in xenon_remove()
624 clk_disable_unprepare(priv->axi_clk); in xenon_remove()
625 clk_disable_unprepare(pltfm_host->clk); in xenon_remove()
633 struct sdhci_host *host = dev_get_drvdata(dev); in xenon_suspend() local
634 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_suspend()
640 priv->restore_needed = true; in xenon_suspend()
648 struct sdhci_host *host = dev_get_drvdata(dev); in xenon_runtime_suspend() local
649 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_runtime_suspend()
653 ret = sdhci_runtime_suspend_host(host); in xenon_runtime_suspend()
657 if (host->tuning_mode != SDHCI_TUNING_MODE_3) in xenon_runtime_suspend()
658 mmc_retune_needed(host->mmc); in xenon_runtime_suspend()
660 clk_disable_unprepare(pltfm_host->clk); in xenon_runtime_suspend()
662 * Need to update the priv->clock here, or when runtime resume in xenon_runtime_suspend()
666 priv->clock = 0; in xenon_runtime_suspend()
672 struct sdhci_host *host = dev_get_drvdata(dev); in xenon_runtime_resume() local
673 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in xenon_runtime_resume()
677 ret = clk_prepare_enable(pltfm_host->clk); in xenon_runtime_resume()
683 if (priv->restore_needed) { in xenon_runtime_resume()
684 ret = xenon_sdhc_prepare(host); in xenon_runtime_resume()
687 priv->restore_needed = false; in xenon_runtime_resume()
690 ret = sdhci_runtime_resume_host(host, 0); in xenon_runtime_resume()
695 clk_disable_unprepare(pltfm_host->clk); in xenon_runtime_resume()
709 { .compatible = "marvell,armada-ap806-sdhci", .data = (void *)XENON_AP806},
710 { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807},
711 { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110},
712 { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700},
713 { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5},
730 .name = "xenon-sdhci",