mmc: bcmstb: Add support for bcm2712 SD controller 69/307169/2
authorIvan T. Ivanov <iivanov@suse.de>
Tue, 23 Jan 2024 08:07:57 +0000 (10:07 +0200)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 14 Mar 2024 08:31:56 +0000 (09:31 +0100)
Make sure that core SDHCI accessors are used and add
device specific card detection initialization, which
is borrowed from vendor Linux driver code.

Tested-by: Jens Maus <mail@jens-maus.de>
Tested-by: Darko Alavanja <darko.alavanja@konsulko.com>
Signed-off-by: Ivan T. Ivanov <iivanov@suse.de>
Signed-off-by: Matthias Brugger <mbrugger@suse.com>
[backport of the commit 10127cdbab64831175a56c782d34183ac57358b7 from mainline]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Change-Id: If66eedd51c77b59dc8c97543419897e32258d4d1

drivers/mmc/bcmstb_sdhci.c

index dc96818..49846ad 100644 (file)
  */
 #define BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY   400000
 
-/*
- * This driver has only been tested with eMMC devices; SD devices may
- * not work.
- */
+#define SDIO_CFG_CTRL                          0x0
+#define  SDIO_CFG_CTRL_SDCD_N_TEST_EN          BIT(31)
+#define  SDIO_CFG_CTRL_SDCD_N_TEST_LEV         BIT(30)
+
+#define SDIO_CFG_SD_PIN_SEL                    0x44
+#define  SDIO_CFG_SD_PIN_SEL_MASK              0x3
+#define  SDIO_CFG_SD_PIN_SEL_CARD              BIT(1)
+
 struct sdhci_bcmstb_plat {
        struct mmc_config cfg;
        struct mmc mmc;
 };
 
+struct sdhci_brcmstb_dev_priv {
+       int (*init)(struct udevice *dev);
+};
+
+static int sdhci_brcmstb_init_2712(struct udevice *dev)
+{
+       struct sdhci_host *host = dev_get_priv(dev);
+       void *cfg_regs;
+       u32 reg;
+
+       /* Map in the non-standard CFG registers */
+       cfg_regs = dev_remap_addr_name(dev, "cfg");
+       if (!cfg_regs)
+               return -ENOENT;
+
+       if ((host->mmc->host_caps & MMC_CAP_NONREMOVABLE) ||
+           (host->mmc->host_caps & MMC_CAP_NEEDS_POLL)) {
+               /* Force presence */
+               reg = readl(cfg_regs + SDIO_CFG_CTRL);
+               reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV;
+               reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN;
+               writel(reg, cfg_regs + SDIO_CFG_CTRL);
+       } else {
+               /* Enable card detection line */
+               reg = readl(cfg_regs + SDIO_CFG_SD_PIN_SEL);
+               reg &= ~SDIO_CFG_SD_PIN_SEL_MASK;
+               reg |= SDIO_CFG_SD_PIN_SEL_CARD;
+               writel(reg, cfg_regs + SDIO_CFG_SD_PIN_SEL);
+       }
+
+       return 0;
+}
+
 static int sdhci_bcmstb_bind(struct udevice *dev)
 {
        struct sdhci_bcmstb_plat *plat = dev_get_plat(dev);
@@ -54,14 +91,20 @@ static int sdhci_bcmstb_bind(struct udevice *dev)
        return sdhci_bind(dev, &plat->mmc, &plat->cfg);
 }
 
+/* No specific SDHCI operations are required */
+static const struct sdhci_ops bcmstb_sdhci_ops = { 0 };
+
 static int sdhci_bcmstb_probe(struct udevice *dev)
 {
        struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
        struct sdhci_bcmstb_plat *plat = dev_get_plat(dev);
        struct sdhci_host *host = dev_get_priv(dev);
+       struct sdhci_brcmstb_dev_priv *dev_priv;
        fdt_addr_t base;
        int ret;
 
+       dev_priv = (struct sdhci_brcmstb_dev_priv *)dev_get_driver_data(dev);
+
        base = dev_read_addr(dev);
        if (base == FDT_ADDR_T_NONE)
                return -EINVAL;
@@ -75,6 +118,8 @@ static int sdhci_bcmstb_probe(struct udevice *dev)
 
        host->mmc = &plat->mmc;
        host->mmc->dev = dev;
+       host->ops = &bcmstb_sdhci_ops;
+
        ret = sdhci_setup_cfg(&plat->cfg, host,
                              BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY,
                              BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY);
@@ -84,10 +129,21 @@ static int sdhci_bcmstb_probe(struct udevice *dev)
        upriv->mmc = &plat->mmc;
        host->mmc->priv = host;
 
+       if (dev_priv && dev_priv->init) {
+               ret = dev_priv->init(dev);
+               if (ret)
+                       return ret;
+       }
+
        return sdhci_probe(dev);
 }
 
+static const struct sdhci_brcmstb_dev_priv match_priv_2712 = {
+       .init = sdhci_brcmstb_init_2712,
+};
+
 static const struct udevice_id sdhci_bcmstb_match[] = {
+       { .compatible = "brcm,bcm2712-sdhci", .data = (ulong)&match_priv_2712 },
        { .compatible = "brcm,bcm7425-sdhci" },
        { .compatible = "brcm,sdhci-brcmstb" },
        { }