diff mbox series

[1/4] drivers: mmc: bcm63158_sdhci: initial support

Message ID 20220413171343.178153-2-philippe.reynes@softathome.com
State Deferred
Delegated to: Tom Rini
Headers show
Series mmc: add support for bcm63158 | expand

Commit Message

Philippe Reynes April 13, 2022, 5:13 p.m. UTC
Adds a driver to support shdci on bcm63158.

Signed-off-by: Philippe Reynes <philippe.reynes@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 mbox series

Patch

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@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),
+};