[PATCH 1/4] drivers: mmc: bcm63158_sdhci: initial support
Philippe Reynes
philippe.reynes at softathome.com
Wed Apr 13 19:13:40 CEST 2022
Adds a driver to support shdci on bcm63158.
Signed-off-by: Philippe Reynes <philippe.reynes at softathome.com>
---
drivers/mmc/Kconfig | 12 +++
drivers/mmc/Makefile | 1 +
drivers/mmc/bcm63158_sdhci.c | 153 +++++++++++++++++++++++++++++++++++
3 files changed, 166 insertions(+)
create mode 100644 drivers/mmc/bcm63158_sdhci.c
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index f04cc44e19..a08e8245cf 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -520,6 +520,18 @@ config MMC_SDHCI_BCM2835
If unsure, say N.
+config MMC_SDHCI_BCM63158
+ bool "SDHCI support for the BCM63158 SD/MMC Controller"
+ depends on ARCH_BCM63158
+ depends on MMC_SDHCI
+ help
+ This selects the BCM63158 SD/MMC controller.
+
+ If you have a BCM63158 platform with SD or MMC devices,
+ say Y here.
+
+ If unsure, say N.
+
config MMC_SDHCI_BCMSTB
tristate "SDHCI support for the BCMSTB SD/MMC Controller"
depends on MMC_SDHCI
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 17ebc04203..5cebd55549 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_ASPEED) += aspeed_sdhci.o
obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o
obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o
+obj-$(CONFIG_MMC_SDHCI_BCM63158) += bcm63158_sdhci.o
obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o
obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o
obj-$(CONFIG_MMC_SDHCI_AM654) += am654_sdhci.o
diff --git a/drivers/mmc/bcm63158_sdhci.c b/drivers/mmc/bcm63158_sdhci.c
new file mode 100644
index 0000000000..42295d113d
--- /dev/null
+++ b/drivers/mmc/bcm63158_sdhci.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Philippe Reynes <philippe.reynes at softathome.com>
+ *
+ * based on:
+ * drivers/mmc/bcmstb_sdhci.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/err.h>
+#include <dm/device_compat.h>
+
+/* 400KHz is max freq for card ID etc. Use that as min */
+#define MIN_FREQ 400000
+
+#define BCM63158_MMC_BOOT_MAIN_CTL_REG 0x0
+#define BCM63158_MMC_BOOT_STATUS_REG 0x4
+#define BCM63158_MMC_BOOT_MODE_MASK 1
+
+struct sdhci_bcm63158_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+static int sdhci_bcm63158_bind(struct udevice *dev)
+{
+ struct sdhci_bcm63158_plat *plat = dev_get_plat(dev);
+
+ return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static int sdhci_bcm63158_set_normal_mode(void *boot_regs)
+{
+ void *boot_main_ctl_reg = boot_regs + BCM63158_MMC_BOOT_MAIN_CTL_REG;
+ void *boot_status_reg = boot_regs + BCM63158_MMC_BOOT_STATUS_REG;
+ u32 status;
+ int i, max_retry = 10;
+ int ret = -1;
+
+ status = readl(boot_status_reg);
+ if ((status & BCM63158_MMC_BOOT_MODE_MASK) == 0) {
+ ret = 0;
+ goto out;
+ }
+
+ clrbits_32(boot_main_ctl_reg, BCM63158_MMC_BOOT_MODE_MASK);
+
+ for (i = 0; i < max_retry; i++) {
+ status = readl(boot_status_reg);
+ if ((status & BCM63158_MMC_BOOT_MODE_MASK) == 0) {
+ ret = 0;
+ goto out;
+ }
+
+ mdelay(10);
+ }
+
+ log_err("%s: can't set mode normal\n", __func__);
+
+ out:
+ return ret;
+}
+
+static int sdhci_bcm63158_probe(struct udevice *dev)
+{
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct sdhci_bcm63158_plat *plat = dev_get_plat(dev);
+ struct sdhci_host *host = dev_get_priv(dev);
+ struct resource res;
+ void *boot_regs;
+ int ret;
+
+ host->name = dev->name;
+
+ /* Get sdhci controller base address */
+ ret = dev_read_resource_byname(dev, "sdhci-base", &res);
+ if (ret) {
+ dev_err(dev, "can't get regs sdhci-base address(ret = %d)!\n", ret);
+ return ret;
+ }
+
+ host->quirks |= SDHCI_QUIRK_WAIT_SEND_CMD;
+ host->ioaddr = devm_ioremap(dev, res.start, resource_size(&res));
+ if (IS_ERR(host->ioaddr))
+ return PTR_ERR(host->ioaddr);
+
+ /* Get sdhci boot controller base address */
+ ret = dev_read_resource_byname(dev, "sdhci-boot", &res);
+ if (ret) {
+ dev_err(dev, "can't get regs sdhci-boot address(ret = %d)!\n", ret);
+ return ret;
+ }
+
+ boot_regs = devm_ioremap(dev, res.start, resource_size(&res));
+ if (IS_ERR(boot_regs))
+ return PTR_ERR(boot_regs);
+
+ /* Set normal mode instead of boot mode */
+ ret = sdhci_bcm63158_set_normal_mode(boot_regs);
+ if (ret)
+ return ret;
+
+ ret = mmc_of_parse(dev, &plat->cfg);
+ if (ret)
+ return ret;
+
+ /*
+ * see commit:
+ * 425d83346d7 ("mmc: bcm: fix uninitialized pointer deref on probe")
+ *
+ * Since commit
+ * 3d296365e4e8 ("mmc: sdhci: Add support for sdhci-caps-mask")
+ * the function sdhci_setup_cfg() xpects a valid sdhci_host mmc field.
+ */
+ host->mmc = &plat->mmc;
+ host->mmc->dev = dev;
+
+ /* Use default max frequency from caps register */
+ ret = sdhci_setup_cfg(&plat->cfg, host,
+ 0,
+ MIN_FREQ);
+ if (ret)
+ return ret;
+
+ upriv->mmc = &plat->mmc;
+ host->mmc = &plat->mmc;
+ host->mmc->priv = host;
+
+ return sdhci_probe(dev);
+}
+
+static const struct udevice_id sdhci_bcm63158_match[] = {
+ { .compatible = "brcm,bcm63158-sdhci" },
+ { }
+};
+
+U_BOOT_DRIVER(sdhci_bcm63158) = {
+ .name = "sdhci-bcm63158",
+ .id = UCLASS_MMC,
+ .of_match = sdhci_bcm63158_match,
+ .ops = &sdhci_ops,
+ .bind = sdhci_bcm63158_bind,
+ .probe = sdhci_bcm63158_probe,
+ .priv_auto = sizeof(struct sdhci_host),
+ .plat_auto = sizeof(struct sdhci_bcm63158_plat),
+};
--
2.25.1
More information about the U-Boot
mailing list