// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Marvell Xenon SDHC as a platform device * * Copyright (C) 2016 Marvell, All Rights Reserved. * * Author: Hu Ziji <huziji@marvell.com> * Date: 2016-8-24 * * Inspired by Jisheng Zhang <jszhang@marvell.com> * Special thanks to Video BG4 project team.
*/
reg = sdhci_readl(host, XENON_SYS_OP_CTRL); /* Get the bit shift basing on the SDHC index */
mask = (0x1 << (XENON_SDCLK_IDLEOFF_ENABLE_SHIFT + sdhc_id)); if (enable)
reg |= mask; else
reg &= ~mask;
sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
}
/* Enable/Disable the Auto Clock Gating function */ staticvoid xenon_set_acg(struct sdhci_host *host, bool enable)
{
u32 reg;
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; /* * Force to clear BUS_TEST to * skip bus_test_pre and bus_test_post
*/
host->mmc->caps &= ~MMC_CAP_BUS_WIDTH_TEST;
}
/* Force to use Tuning Mode 1 */
host->tuning_mode = SDHCI_TUNING_MODE_1; /* Set re-tuning period */
host->tuning_count = 1 << (priv->tuning_count - 1);
}
/* * Operations inside struct sdhci_ops
*/ /* Recover the Register Setting cleared during SOFTWARE_RESET_ALL */ staticvoid xenon_reset_exit(struct sdhci_host *host, unsignedchar sdhc_id, u8 mask)
{ /* Only SOFTWARE RESET ALL will clear the register setting */ if (!(mask & SDHCI_RESET_ALL)) return;
/* Disable tuning request and auto-retuning again */
xenon_retune_setup(host);
/* * The ACG should be turned off at the early init time, in order * to solve a possible issues with the 1.8V regulator stabilization. * The feature is enabled in later stage.
*/
xenon_set_acg(host, false);
/* * HS400/HS200/eMMC HS doesn't have Preset Value register. * However, sdhci_set_ios will read HS400/HS200 Preset register. * Disable Preset Value register for HS400/HS200. * eMMC HS with preset_enabled set will trigger a bug in * get_preset_value().
*/ if ((ios->timing == MMC_TIMING_MMC_HS400) ||
(ios->timing == MMC_TIMING_MMC_HS200) ||
(ios->timing == MMC_TIMING_MMC_HS)) {
host->preset_enabled = false;
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
host->flags &= ~SDHCI_PV_ENABLED;
/* * Before SD/SDIO set signal voltage, SD bus clock should be * disabled. However, sdhci_set_clock will also disable the Internal * clock in mmc_set_signal_voltage(). * If Internal clock is disabled, the 3.3V/1.8V bit can not be updated. * Thus here manually enable internal clock. * * After switch completes, it is unnecessary to disable internal clock, * since keeping internal clock active obeys SD spec.
*/
xenon_enable_internal_clk(host);
xenon_soc_pad_ctrl(host, ios->signal_voltage);
/* * If Vqmmc is fixed on platform, vqmmc regulator should be unavailable. * Thus SDHCI_CTRL_VDD_180 bit might not work then. * Skip the standard voltage switch to avoid any issue.
*/ if (PTR_ERR(mmc->supply.vqmmc) == -ENODEV) return 0;
if (host->timing == MMC_TIMING_UHS_DDR50 ||
host->timing == MMC_TIMING_MMC_DDR52) return 0;
/* * Currently force Xenon driver back to support mode 1 only, * even though Xenon might claim to support mode 2 or mode 3. * It requires more time to test mode 2/mode 3 on more platforms.
*/ if (host->tuning_mode != SDHCI_TUNING_MODE_1)
xenon_retune_setup(host);
/* * Parse Xenon specific DT properties: * sdhc-id: the index of current SDHC. * Refer to XENON_SYS_CFG_INFO register * tun-count: the interval between re-tuning
*/ staticint xenon_probe_params(struct platform_device *pdev)
{ struct device *dev = &pdev->dev; struct sdhci_host *host = platform_get_drvdata(pdev); struct mmc_host *mmc = host->mmc; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
u32 sdhc_id, nr_sdhc;
u32 tuning_count; struct sysinfo si;
/* Disable HS200 on Armada AP806 */ if (priv->hw_version == XENON_AP806)
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
sdhc_id = 0x0; if (!device_property_read_u32(dev, "marvell,xenon-sdhc-id", &sdhc_id)) {
nr_sdhc = sdhci_readl(host, XENON_SYS_CFG_INFO);
nr_sdhc &= XENON_NR_SUPPORTED_SLOT_MASK; if (unlikely(sdhc_id > nr_sdhc)) {
dev_err(mmc_dev(mmc), "SDHC Index %d exceeds Number of SDHCs %d\n",
sdhc_id, nr_sdhc); return -EINVAL;
}
}
priv->sdhc_id = sdhc_id;
tuning_count = XENON_DEF_TUNING_COUNT; if (!device_property_read_u32(dev, "marvell,xenon-tun-count",
&tuning_count)) { if (unlikely(tuning_count >= XENON_TMR_RETUN_NO_PRESENT)) {
dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n",
XENON_DEF_TUNING_COUNT);
tuning_count = XENON_DEF_TUNING_COUNT;
}
}
priv->tuning_count = tuning_count;
/* * AC5/X/IM HW has only 31-bits passed in the crossbar switch. * If we have more than 2GB of memory, this means we might pass * memory pointers which are above 2GB and which cannot be properly * represented. In this case, disable ADMA, 64-bit DMA and allow only SDMA. * This effectively will enable bounce buffer quirk in the * generic SDHCI driver, which will make sure DMA is only done * from supported memory regions:
*/ if (priv->hw_version == XENON_AC5) {
si_meminfo(&si); if (si.totalram * si.mem_unit > SZ_2G) {
host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
host->quirks2 |= SDHCI_QUIRK2_BROKEN_64_BIT_DMA;
}
}
err = sdhci_add_host(host); if (err) goto remove_sdhc;
pm_runtime_put_autosuspend(&pdev->dev); /* * If we previously detected AC5 with over 2GB of memory, * then we disable ADMA and 64-bit DMA. * This means generic SDHCI driver has set the DMA mask to * 32-bit. Since DDR starts at 0x2_0000_0000, we must use * 34-bit DMA mask to access this DDR memory:
*/ if (priv->hw_version == XENON_AC5 &&
host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA)
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
clk_disable_unprepare(pltfm_host->clk); /* * Need to update the priv->clock here, or when runtime resume * back, phy don't aware the clock change and won't adjust phy * which will cause cmd err
*/
priv->clock = 0; return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.