1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
283b3248eSFelipe Balbi /*
383b3248eSFelipe Balbi * Copyright (c) 2017 Intel Corporation
483b3248eSFelipe Balbi */
583b3248eSFelipe Balbi #include <common.h>
683b3248eSFelipe Balbi #include <dm.h>
783b3248eSFelipe Balbi #include <dm/device.h>
883b3248eSFelipe Balbi #include <linux/io.h>
983b3248eSFelipe Balbi #include <linux/sizes.h>
1083b3248eSFelipe Balbi #include <malloc.h>
1183b3248eSFelipe Balbi #include <mmc.h>
1283b3248eSFelipe Balbi #include <sdhci.h>
1383b3248eSFelipe Balbi
1483b3248eSFelipe Balbi #define SDHCI_TANGIER_FMAX 200000000
1583b3248eSFelipe Balbi #define SDHCI_TANGIER_FMIN 400000
1683b3248eSFelipe Balbi
1783b3248eSFelipe Balbi struct sdhci_tangier_plat {
1883b3248eSFelipe Balbi struct mmc_config cfg;
1983b3248eSFelipe Balbi struct mmc mmc;
2083b3248eSFelipe Balbi void __iomem *ioaddr;
2183b3248eSFelipe Balbi };
2283b3248eSFelipe Balbi
sdhci_tangier_bind(struct udevice * dev)2383b3248eSFelipe Balbi static int sdhci_tangier_bind(struct udevice *dev)
2483b3248eSFelipe Balbi {
2583b3248eSFelipe Balbi struct sdhci_tangier_plat *plat = dev_get_platdata(dev);
2683b3248eSFelipe Balbi
2783b3248eSFelipe Balbi return sdhci_bind(dev, &plat->mmc, &plat->cfg);
2883b3248eSFelipe Balbi }
2983b3248eSFelipe Balbi
sdhci_tangier_probe(struct udevice * dev)3083b3248eSFelipe Balbi static int sdhci_tangier_probe(struct udevice *dev)
3183b3248eSFelipe Balbi {
3283b3248eSFelipe Balbi struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
3383b3248eSFelipe Balbi struct sdhci_tangier_plat *plat = dev_get_platdata(dev);
3483b3248eSFelipe Balbi struct sdhci_host *host = dev_get_priv(dev);
3583b3248eSFelipe Balbi fdt_addr_t base;
3683b3248eSFelipe Balbi int ret;
3783b3248eSFelipe Balbi
38a821c4afSSimon Glass base = devfdt_get_addr(dev);
3983b3248eSFelipe Balbi if (base == FDT_ADDR_T_NONE)
4083b3248eSFelipe Balbi return -EINVAL;
4183b3248eSFelipe Balbi
4283b3248eSFelipe Balbi plat->ioaddr = devm_ioremap(dev, base, SZ_1K);
4383b3248eSFelipe Balbi if (!plat->ioaddr)
4483b3248eSFelipe Balbi return -ENOMEM;
4583b3248eSFelipe Balbi
4683b3248eSFelipe Balbi host->name = dev->name;
4783b3248eSFelipe Balbi host->ioaddr = plat->ioaddr;
4883b3248eSFelipe Balbi host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE |
4983b3248eSFelipe Balbi SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD;
5083b3248eSFelipe Balbi
5183b3248eSFelipe Balbi /* MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195 */
5283b3248eSFelipe Balbi host->voltages = MMC_VDD_165_195;
5383b3248eSFelipe Balbi
5483b3248eSFelipe Balbi ret = sdhci_setup_cfg(&plat->cfg, host, SDHCI_TANGIER_FMAX,
5583b3248eSFelipe Balbi SDHCI_TANGIER_FMIN);
5683b3248eSFelipe Balbi if (ret)
5783b3248eSFelipe Balbi return ret;
5883b3248eSFelipe Balbi
5983b3248eSFelipe Balbi upriv->mmc = &plat->mmc;
6083b3248eSFelipe Balbi host->mmc = &plat->mmc;
6183b3248eSFelipe Balbi host->mmc->priv = host;
6283b3248eSFelipe Balbi
6383b3248eSFelipe Balbi return sdhci_probe(dev);
6483b3248eSFelipe Balbi }
6583b3248eSFelipe Balbi
6683b3248eSFelipe Balbi static const struct udevice_id sdhci_tangier_match[] = {
6783b3248eSFelipe Balbi { .compatible = "intel,sdhci-tangier" },
6883b3248eSFelipe Balbi { /* sentinel */ }
6983b3248eSFelipe Balbi };
7083b3248eSFelipe Balbi
7183b3248eSFelipe Balbi U_BOOT_DRIVER(sdhci_tangier) = {
7283b3248eSFelipe Balbi .name = "sdhci-tangier",
7383b3248eSFelipe Balbi .id = UCLASS_MMC,
7483b3248eSFelipe Balbi .of_match = sdhci_tangier_match,
7583b3248eSFelipe Balbi .bind = sdhci_tangier_bind,
7683b3248eSFelipe Balbi .probe = sdhci_tangier_probe,
7783b3248eSFelipe Balbi .ops = &sdhci_ops,
7883b3248eSFelipe Balbi .priv_auto_alloc_size = sizeof(struct sdhci_host),
7983b3248eSFelipe Balbi .platdata_auto_alloc_size = sizeof(struct sdhci_tangier_plat),
8083b3248eSFelipe Balbi };
81