All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v4 03/21] mmc: Add support for Qualcomm SDHCI controller
Date: Thu, 31 Mar 2016 23:12:16 +0200	[thread overview]
Message-ID: <1459458754-29559-4-git-send-email-mateusz.kulikowski@gmail.com> (raw)
In-Reply-To: <1459458754-29559-1-git-send-email-mateusz.kulikowski@gmail.com>

Add support for SD/eMMC controller present on some Qualcomm Snapdragon
devices. This controller implements SDHCI 2.0 interface but requires
vendor-specific initialization.
Driver works in PIO mode as ADMA is not supported by U-Boot (yet).

Signed-off-by: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Simon Glass <sjg@chromium.org>
---

Changes in v4: None
Changes in v3: None
Changes in v2:
- Add reviewed-by

Changes in v1:
- Added commit message
- Added DT binding documentation
- Added Kconfig help
- Reordered includes
- Dropped redundant fields from msm_sdhc
- Cleaned up clock init code (+ added error handling)
- Dropped mdelay - use wait_for_bit instead in reset code
- Added missing newline after declarations
- Added error handling if "reg" is missing
- Converted base address to pointer

 doc/device-tree-bindings/mmc/msm_sdhci.txt |  25 ++++
 drivers/mmc/Kconfig                        |   9 ++
 drivers/mmc/Makefile                       |   1 +
 drivers/mmc/msm_sdhci.c                    | 180 +++++++++++++++++++++++++++++
 4 files changed, 215 insertions(+)
 create mode 100644 doc/device-tree-bindings/mmc/msm_sdhci.txt
 create mode 100644 drivers/mmc/msm_sdhci.c

diff --git a/doc/device-tree-bindings/mmc/msm_sdhci.txt b/doc/device-tree-bindings/mmc/msm_sdhci.txt
new file mode 100644
index 0000000..08a290c
--- /dev/null
+++ b/doc/device-tree-bindings/mmc/msm_sdhci.txt
@@ -0,0 +1,25 @@
+Qualcomm Snapdragon SDHCI controller
+
+Required properties:
+- compatible : "qcom,sdhci-msm-v4"
+- reg: Base address and length of registers:
+	- Host controller registers (SDHCI)
+	- SD Core registers
+- clock: interface clock (must accept SD bus clock as a frequency)
+
+Optional properties:
+- index: If there is more than one controller - controller index (required
+	by generic SDHCI code).
+- bus_width: Width of SD/eMMC bus (default 4)
+- clock-frequency: Frequency of SD/eMMC bus (default 400 kHz)
+
+Example:
+
+sdhci at 07864000 {
+	compatible = "qcom,sdhci-msm-v4";
+	reg = <0x7864900 0x11c 0x7864000 0x800>;
+	index = <0x1>;
+	bus-width = <0x4>;
+	clock = <&clkc 1>;
+	clock-frequency = <200000000>;
+};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index dc8532f..4d3df11 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -16,6 +16,15 @@ config DM_MMC
 	  appear as block devices in U-Boot and can support filesystems such
 	  as EXT4 and FAT.
 
+config MSM_SDHCI
+	bool "Qualcomm SDHCI controller"
+	depends on DM_MMC
+	help
+	  Enables support for SDHCI 2.0 controller present on some Qualcomm
+          Snapdragon devices. This device is compatible with eMMC v4.5 and
+          SD 3.0 specifications. Both SD and eMMC devices are supported.
+	  Card-detect gpios are not supported.
+
 config ROCKCHIP_DWMMC
 	bool "Rockchip SD/MMC controller support"
 	depends on DM_MMC && OF_CONTROL
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index b85e4bf..585aaf3 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -50,3 +50,4 @@ else
 obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
 endif
 obj-$(CONFIG_PIC32_SDHCI) += pic32_sdhci.o
+obj-$(CONFIG_MSM_SDHCI) += msm_sdhci.o
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
new file mode 100644
index 0000000..1e2a29b
--- /dev/null
+++ b/drivers/mmc/msm_sdhci.c
@@ -0,0 +1,180 @@
+/*
+ * Qualcomm SDHCI driver - SD/eMMC controller
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * Based on Linux driver
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <sdhci.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+/* Non-standard registers needed for SDHCI startup */
+#define SDCC_MCI_POWER   0x0
+#define SDCC_MCI_POWER_SW_RST BIT(7)
+
+/* This is undocumented register */
+#define SDCC_MCI_VERSION             0x50
+#define SDCC_MCI_VERSION_MAJOR_SHIFT 28
+#define SDCC_MCI_VERSION_MAJOR_MASK  (0xf << SDCC_MCI_VERSION_MAJOR_SHIFT)
+#define SDCC_MCI_VERSION_MINOR_MASK  0xff
+
+#define SDCC_MCI_STATUS2 0x6C
+#define SDCC_MCI_STATUS2_MCI_ACT 0x1
+#define SDCC_MCI_HC_MODE 0x78
+
+/* Offset to SDHCI registers */
+#define SDCC_SDHCI_OFFSET 0x900
+
+/* Non standard (?) SDHCI register */
+#define SDHCI_VENDOR_SPEC_CAPABILITIES0  0x11c
+
+struct msm_sdhc {
+	struct sdhci_host host;
+	void *base;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int msm_sdc_clk_init(struct udevice *dev)
+{
+	uint clk_rate = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
+					"clock-frequency", 400000);
+	uint clkd[2]; /* clk_id and clk_no */
+	int clk_offset;
+	struct udevice *clk;
+	int ret;
+
+	ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd,
+				   2);
+	if (ret)
+		return ret;
+
+	clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
+	if (clk_offset < 0)
+		return clk_offset;
+
+	ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk);
+	if (ret)
+		return ret;
+
+	ret = clk_set_periph_rate(clk, clkd[1], clk_rate);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int msm_sdc_probe(struct udevice *dev)
+{
+	struct msm_sdhc *prv = dev_get_priv(dev);
+	struct sdhci_host *host = &prv->host;
+	u32 core_version, core_minor, core_major;
+	int ret;
+
+	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B;
+
+	/* Init clocks */
+	ret = msm_sdc_clk_init(dev);
+	if (ret)
+		return ret;
+
+	/* Reset the core and Enable SDHC mode */
+	writel(readl(prv->base + SDCC_MCI_POWER) | SDCC_MCI_POWER_SW_RST,
+	       prv->base + SDCC_MCI_POWER);
+
+
+	/* Wait for reset to be written to register */
+	if (wait_for_bit(__func__, prv->base + SDCC_MCI_STATUS2,
+			 SDCC_MCI_STATUS2_MCI_ACT, false, 10, false)) {
+		printf("msm_sdhci: reset request failed\n");
+		return -EIO;
+	}
+
+	/* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
+	if (wait_for_bit(__func__, prv->base + SDCC_MCI_POWER,
+			 SDCC_MCI_POWER_SW_RST, false, 2, false)) {
+		printf("msm_sdhci: stuck in reset\n");
+		return -ETIMEDOUT;
+	}
+
+	/* Enable host-controller mode */
+	writel(1, prv->base + SDCC_MCI_HC_MODE);
+
+	core_version = readl(prv->base + SDCC_MCI_VERSION);
+
+	core_major = (core_version & SDCC_MCI_VERSION_MAJOR_MASK);
+	core_major >>= SDCC_MCI_VERSION_MAJOR_SHIFT;
+
+	core_minor = core_version & SDCC_MCI_VERSION_MINOR_MASK;
+
+	/*
+	 * Support for some capabilities is not advertised by newer
+	 * controller versions and must be explicitly enabled.
+	 */
+	if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) {
+		u32 caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
+		caps |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT;
+		writel(caps, host->ioaddr + SDHCI_VENDOR_SPEC_CAPABILITIES0);
+	}
+
+	/* Set host controller version */
+	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+	/* automatically detect max and min speed */
+	return add_sdhci(host, 0, 0);
+}
+
+static int msm_sdc_remove(struct udevice *dev)
+{
+	struct msm_sdhc *priv = dev_get_priv(dev);
+
+	 /* Disable host-controller mode */
+	writel(0, priv->base + SDCC_MCI_HC_MODE);
+
+	return 0;
+}
+
+static int msm_ofdata_to_platdata(struct udevice *dev)
+{
+	struct udevice *parent = dev->parent;
+	struct msm_sdhc *priv = dev_get_priv(dev);
+	struct sdhci_host *host = &priv->host;
+
+	host->name = strdup(dev->name);
+	host->ioaddr = (void *)dev_get_addr(dev);
+	host->bus_width = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+					 "bus-width", 4);
+	host->index = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "index", 0);
+	priv->base = (void *)fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
+							      parent->of_offset,
+							      dev->of_offset,
+							      "reg", 1, NULL);
+	if (priv->base == (void *)FDT_ADDR_T_NONE ||
+	    host->ioaddr == (void *)FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct udevice_id msm_mmc_ids[] = {
+	{ .compatible = "qcom,sdhci-msm-v4" },
+	{ }
+};
+
+U_BOOT_DRIVER(msm_sdc_drv) = {
+	.name		= "msm_sdc",
+	.id		= UCLASS_MMC,
+	.of_match	= msm_mmc_ids,
+	.ofdata_to_platdata = msm_ofdata_to_platdata,
+	.probe		= msm_sdc_probe,
+	.remove		= msm_sdc_remove,
+	.priv_auto_alloc_size = sizeof(struct msm_sdhc),
+};
-- 
2.5.0

  parent reply	other threads:[~2016-03-31 21:12 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-31 21:12 [U-Boot] [PATCH v4 00/21] Add support for 96boards Dragonboard410C board Mateusz Kulikowski
2016-03-31 21:12 ` [U-Boot] [PATCH v4 01/21] serial: Add support for Qualcomm serial port Mateusz Kulikowski
2016-04-02  2:01   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 02/21] gpio: Add support for Qualcomm gpio controller Mateusz Kulikowski
2016-04-02  2:01   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` Mateusz Kulikowski [this message]
2016-04-02  2:01   ` [U-Boot] [U-Boot, v4, 03/21] mmc: Add support for Qualcomm SDHCI controller Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 04/21] ehci-hcd: Add init_after_reset Mateusz Kulikowski
2016-04-02  2:01   ` [U-Boot] [U-Boot,v4,04/21] " Tom Rini
2016-04-03 10:58     ` Bernhard Nortmann
2016-04-03 11:40       ` Mateusz Kulikowski
2016-03-31 21:12 ` [U-Boot] [PATCH v4 05/21] usb: ulpi: Add Kconfig options for ULPI Mateusz Kulikowski
2016-04-02  2:01   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 06/21] Migrate CONFIG_ULPI* to Kconfig Mateusz Kulikowski
2016-04-02  2:02   ` [U-Boot] [U-Boot,v4,06/21] " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 07/21] usb: ulpi: Fix viewport_addr type Mateusz Kulikowski
2016-04-02  2:02   ` [U-Boot] [U-Boot,v4,07/21] " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 08/21] usb: ulpi: Fix compile warning in read/write on 64-bit machines Mateusz Kulikowski
2016-04-02  2:02   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 09/21] eth: asix88179: Print packet length properly Mateusz Kulikowski
2016-04-02  2:02   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 10/21] usb: Rename ehci-fsl.h to ehci-ci.h Mateusz Kulikowski
2016-04-02  2:02   ` [U-Boot] [U-Boot,v4,10/21] " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 11/21] usb: ehci-ci: Add missing registers Mateusz Kulikowski
2016-04-02  2:02   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 12/21] ehci-ci.h: drop generic USBCMD fields Mateusz Kulikowski
2016-04-02  2:03   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 13/21] ehci: Add support for Qualcomm EHCI Mateusz Kulikowski
2016-04-02  2:03   ` [U-Boot] [U-Boot,v4,13/21] " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 14/21] drivers: Add SPMI bus uclass Mateusz Kulikowski
2016-04-02  2:04   ` [U-Boot] [U-Boot,v4,14/21] " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 15/21] spmi: Add sandbox test driver Mateusz Kulikowski
2016-04-02  2:04   ` [U-Boot] [U-Boot,v4,15/21] " Tom Rini
2016-04-04 15:49     ` Stephen Warren
2016-04-04 16:19       ` Mateusz Kulikowski
2016-04-04 17:09         ` Stephen Warren
2016-04-04 18:02           ` Mateusz Kulikowski
2016-04-04 17:16       ` Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 16/21] drivers: spmi: Add support for Qualcomm SPMI bus driver Mateusz Kulikowski
2016-04-02  2:04   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 17/21] pmic: Add support for Qualcomm PM8916 PMIC Mateusz Kulikowski
2016-04-02  2:04   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 18/21] gpio: Add support for Qualcomm PM8916 gpios Mateusz Kulikowski
2016-04-02  2:05   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 19/21] arm: Add support for Qualcomm Snapdragon family Mateusz Kulikowski
2016-04-02  2:05   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-03-31 21:12 ` [U-Boot] [PATCH v4 20/21] board: Add Qualcomm Dragonboard 410C support Mateusz Kulikowski
2016-04-02  2:05   ` [U-Boot] [U-Boot, v4, " Tom Rini
2016-04-04 23:13   ` [U-Boot] [PATCH v4 " Andreas Färber
2016-04-04 23:54     ` Daniel Glöckner
2016-04-05  0:15       ` Andreas Färber
2016-03-31 21:12 ` [U-Boot] [PATCH v4 21/21] Add myself as Snapdragon and SPMI maintainer Mateusz Kulikowski
2016-04-02  2:06   ` [U-Boot] [U-Boot, v4, " Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1459458754-29559-4-git-send-email-mateusz.kulikowski@gmail.com \
    --to=mateusz.kulikowski@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.