uboot/drivers/mmc/sti_sdhci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
   4 * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <mmc.h>
  10#include <reset-uclass.h>
  11#include <sdhci.h>
  12#include <asm/arch/sdhci.h>
  13
  14DECLARE_GLOBAL_DATA_PTR;
  15
  16struct sti_sdhci_plat {
  17        struct mmc_config cfg;
  18        struct mmc mmc;
  19        struct reset_ctl reset;
  20        int instance;
  21};
  22
  23/**
  24 * sti_mmc_core_config: configure the Arasan HC
  25 * @dev : udevice
  26 *
  27 * Description: this function is to configure the Arasan MMC HC.
  28 * This should be called when the system starts in case of, on the SoC,
  29 * it is needed to configure the host controller.
  30 * This happens on some SoCs, i.e. StiH410, where the MMC0 inside the flashSS
  31 * needs to be configured as MMC 4.5 to have full capabilities.
  32 * W/o these settings the SDHCI could configure and use the embedded controller
  33 * with limited features.
  34 */
  35static int sti_mmc_core_config(struct udevice *dev)
  36{
  37        struct sti_sdhci_plat *plat = dev_get_platdata(dev);
  38        struct sdhci_host *host = dev_get_priv(dev);
  39        int ret;
  40
  41        /* only MMC1 has a reset line */
  42        if (plat->instance) {
  43                ret = reset_deassert(&plat->reset);
  44                if (ret < 0) {
  45                        pr_err("MMC1 deassert failed: %d", ret);
  46                        return ret;
  47                }
  48        }
  49
  50        writel(STI_FLASHSS_MMC_CORE_CONFIG_1,
  51               host->ioaddr + FLASHSS_MMC_CORE_CONFIG_1);
  52
  53        if (plat->instance) {
  54                writel(STI_FLASHSS_MMC_CORE_CONFIG2,
  55                       host->ioaddr + FLASHSS_MMC_CORE_CONFIG_2);
  56                writel(STI_FLASHSS_MMC_CORE_CONFIG3,
  57                       host->ioaddr + FLASHSS_MMC_CORE_CONFIG_3);
  58        } else {
  59                writel(STI_FLASHSS_SDCARD_CORE_CONFIG2,
  60                       host->ioaddr + FLASHSS_MMC_CORE_CONFIG_2);
  61                writel(STI_FLASHSS_SDCARD_CORE_CONFIG3,
  62                       host->ioaddr + FLASHSS_MMC_CORE_CONFIG_3);
  63        }
  64        writel(STI_FLASHSS_MMC_CORE_CONFIG4,
  65               host->ioaddr + FLASHSS_MMC_CORE_CONFIG_4);
  66
  67        return 0;
  68}
  69
  70static int sti_sdhci_probe(struct udevice *dev)
  71{
  72        struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
  73        struct sti_sdhci_plat *plat = dev_get_platdata(dev);
  74        struct sdhci_host *host = dev_get_priv(dev);
  75        int ret;
  76
  77        /*
  78         * identify current mmc instance, mmc1 has a reset, not mmc0
  79         * MMC0 is wired to the SD slot,
  80         * MMC1 is wired on the high speed connector
  81         */
  82        ret = reset_get_by_index(dev, 0, &plat->reset);
  83        if (!ret)
  84                plat->instance = 1;
  85        else
  86                if (ret == -ENOENT)
  87                        plat->instance = 0;
  88                else
  89                        return ret;
  90
  91        ret = sti_mmc_core_config(dev);
  92        if (ret)
  93                return ret;
  94
  95        host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
  96                       SDHCI_QUIRK_32BIT_DMA_ADDR |
  97                       SDHCI_QUIRK_NO_HISPD_BIT;
  98
  99        host->host_caps = MMC_MODE_DDR_52MHz;
 100
 101        ret = sdhci_setup_cfg(&plat->cfg, host, 50000000, 400000);
 102        if (ret)
 103                return ret;
 104
 105        host->mmc = &plat->mmc;
 106        host->mmc->priv = host;
 107        host->mmc->dev = dev;
 108        upriv->mmc = host->mmc;
 109
 110        return sdhci_probe(dev);
 111}
 112
 113static int sti_sdhci_ofdata_to_platdata(struct udevice *dev)
 114{
 115        struct sdhci_host *host = dev_get_priv(dev);
 116
 117        host->name = strdup(dev->name);
 118        host->ioaddr = (void *)devfdt_get_addr(dev);
 119
 120        host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
 121                                         "bus-width", 4);
 122
 123        return 0;
 124}
 125
 126static int sti_sdhci_bind(struct udevice *dev)
 127{
 128        struct sti_sdhci_plat *plat = dev_get_platdata(dev);
 129
 130        return sdhci_bind(dev, &plat->mmc, &plat->cfg);
 131}
 132
 133static const struct udevice_id sti_sdhci_ids[] = {
 134        { .compatible = "st,sdhci" },
 135        { }
 136};
 137
 138U_BOOT_DRIVER(sti_mmc) = {
 139        .name = "sti_sdhci",
 140        .id = UCLASS_MMC,
 141        .of_match = sti_sdhci_ids,
 142        .bind = sti_sdhci_bind,
 143        .ops = &sdhci_ops,
 144        .ofdata_to_platdata = sti_sdhci_ofdata_to_platdata,
 145        .probe = sti_sdhci_probe,
 146        .priv_auto_alloc_size = sizeof(struct sdhci_host),
 147        .platdata_auto_alloc_size = sizeof(struct sti_sdhci_plat),
 148};
 149