All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver
@ 2016-02-18 10:52 Masahiro Yamada
  2016-02-18 10:52 ` [U-Boot] [PATCH v4 1/3] mmc: uniphier: add driver for UniPhier SD/MMC host controller Masahiro Yamada
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Masahiro Yamada @ 2016-02-18 10:52 UTC (permalink / raw)
  To: u-boot



Changes in v4:
  - Add some comments about HOST_MODE register
  - Rename uniphier_sd_wait_irq() to uniphier_sd_wait_for_irq()

Changes in v3:
  - Use dev_err/dev_dbg instead of pr_err/pr_debug
  - Tidy up uniphier_sd_set_ios()
  - Allow to use DMA even in SPL if the target address is DMA'able

Changes in v2:
  - Fix the divisor bug on the older IP (on PH1-LD4, PH1-sLD8, PH1-Pro4)
  - Increase time out because "mmc erase" can sometimes take long
  - Move HOST_MODE register setting to uniphier_sd_init()
    because this register does not need setting multipule times.

Masahiro Yamada (3):
  mmc: uniphier: add driver for UniPhier SD/MMC host controller
  ARM: uniphier: enable UniPhier SD/MMC host driver
  ARM: dts: uniphier: add SD/MMC host controller nodes

 arch/arm/Kconfig                             |   1 +
 arch/arm/dts/uniphier-ph1-ld4-ref.dts        |   4 +
 arch/arm/dts/uniphier-ph1-ld4.dtsi           |  25 +
 arch/arm/dts/uniphier-ph1-ld6b-ref.dts       |   4 +
 arch/arm/dts/uniphier-ph1-pro4-ace.dts       |   4 +
 arch/arm/dts/uniphier-ph1-pro4-ref.dts       |   8 +
 arch/arm/dts/uniphier-ph1-pro4-sanji.dts     |   4 +
 arch/arm/dts/uniphier-ph1-pro4.dtsi          |  37 ++
 arch/arm/dts/uniphier-ph1-pro5-4kbox.dts     |   8 +
 arch/arm/dts/uniphier-ph1-pro5.dtsi          |  24 +
 arch/arm/dts/uniphier-ph1-sld3-ref.dts       |   4 +
 arch/arm/dts/uniphier-ph1-sld3.dtsi          |  19 +
 arch/arm/dts/uniphier-ph1-sld8-ref.dts       |   4 +
 arch/arm/dts/uniphier-ph1-sld8.dtsi          |  25 +
 arch/arm/dts/uniphier-pinctrl.dtsi           |  15 +
 arch/arm/dts/uniphier-proxstream2-gentil.dts |   4 +
 arch/arm/dts/uniphier-proxstream2-vodka.dts  |   4 +
 arch/arm/dts/uniphier-proxstream2.dtsi       |  24 +
 configs/uniphier_ld4_sld8_defconfig          |   1 +
 configs/uniphier_pro4_defconfig              |   1 +
 configs/uniphier_pro5_defconfig              |   1 +
 configs/uniphier_pxs2_ld6b_defconfig         |   1 +
 configs/uniphier_sld3_defconfig              |   1 +
 doc/README.uniphier                          |   1 +
 drivers/mmc/Kconfig                          |   6 +
 drivers/mmc/Makefile                         |   1 +
 drivers/mmc/uniphier-sd.c                    | 751 +++++++++++++++++++++++++++
 include/configs/uniphier.h                   |   4 +
 28 files changed, 986 insertions(+)
 create mode 100644 drivers/mmc/uniphier-sd.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH v4 1/3] mmc: uniphier: add driver for UniPhier SD/MMC host controller
  2016-02-18 10:52 [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver Masahiro Yamada
@ 2016-02-18 10:52 ` Masahiro Yamada
  2016-02-18 10:52 ` [U-Boot] [PATCH v4 2/3] ARM: uniphier: enable UniPhier SD/MMC host driver Masahiro Yamada
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Masahiro Yamada @ 2016-02-18 10:52 UTC (permalink / raw)
  To: u-boot

Add a driver for the on-chip SD/eMMC host controller used by
UniPhier SoC family.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

Changes in v4:
  - Add some comments about HOST_MODE register
  - Rename uniphier_sd_wait_irq() to uniphier_sd_wait_for_irq()

Changes in v3:
  - Use dev_err/dev_dbg instead of pr_err/pr_debug
  - Tidy up uniphier_sd_set_ios()
  - Allow to use DMA even in SPL if the target address is DMA'able

Changes in v2:
  - Fix the divisor bug on the older IP (on PH1-LD4, PH1-sLD8, PH1-Pro4)
  - Increase time out because "mmc erase" can sometimes take long
  - Move HOST_MODE register setting to uniphier_sd_init()
    because this register does not need setting multipule times.

 doc/README.uniphier       |   1 +
 drivers/mmc/Kconfig       |   6 +
 drivers/mmc/Makefile      |   1 +
 drivers/mmc/uniphier-sd.c | 751 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 759 insertions(+)
 create mode 100644 drivers/mmc/uniphier-sd.c

diff --git a/doc/README.uniphier b/doc/README.uniphier
index f03c207..c270ecb 100644
--- a/doc/README.uniphier
+++ b/doc/README.uniphier
@@ -93,6 +93,7 @@ Supported devices
 
  - UART (on-chip)
  - NAND
+ - SD/eMMC
  - USB 2.0 (EHCI)
  - USB 3.0 (xHCI)
  - GPIO
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 9f4b766..faffefd 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -37,4 +37,10 @@ config PIC32_SDHCI
 	help
 	  Support for Microchip PIC32 SDHCI controller.
 
+config MMC_UNIPHIER
+	bool "UniPhier SD/MMC Host Controller support"
+	depends on ARCH_UNIPHIER
+	help
+	  This selects support for the SD/MMC Host Controller on UniPhier SoCs.
+
 endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index c9c3e3e..b85e4bf 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
 obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
 obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
 obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
+obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o
 obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
 
 ifdef CONFIG_SPL_BUILD
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c
new file mode 100644
index 0000000..3bc4d94
--- /dev/null
+++ b/drivers/mmc/uniphier-sd.c
@@ -0,0 +1,751 @@
+/*
+ * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <fdtdec.h>
+#include <mapmem.h>
+#include <mmc.h>
+#include <dm/device.h>
+#include <linux/compat.h>
+#include <linux/io.h>
+#include <asm/unaligned.h>
+#include <asm/dma-mapping.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define UNIPHIER_SD_CMD			0x000	/* command */
+#define   UNIPHIER_SD_CMD_NOSTOP	BIT(14)	/* No automatic CMD12 issue */
+#define   UNIPHIER_SD_CMD_MULTI		BIT(13)	/* multiple block transfer */
+#define   UNIPHIER_SD_CMD_RD		BIT(12)	/* 1: read, 0: write */
+#define   UNIPHIER_SD_CMD_DATA		BIT(11)	/* data transfer */
+#define   UNIPHIER_SD_CMD_APP		BIT(6)	/* ACMD preceded by CMD55 */
+#define   UNIPHIER_SD_CMD_NORMAL	(0 << 8)/* auto-detect of resp-type */
+#define   UNIPHIER_SD_CMD_RSP_NONE	(3 << 8)/* response: none */
+#define   UNIPHIER_SD_CMD_RSP_R1	(4 << 8)/* response: R1, R5, R6, R7 */
+#define   UNIPHIER_SD_CMD_RSP_R1B	(5 << 8)/* response: R1b, R5b */
+#define   UNIPHIER_SD_CMD_RSP_R2	(6 << 8)/* response: R2 */
+#define   UNIPHIER_SD_CMD_RSP_R3	(7 << 8)/* response: R3, R4 */
+#define UNIPHIER_SD_ARG			0x008	/* command argument */
+#define UNIPHIER_SD_STOP		0x010	/* stop action control */
+#define   UNIPHIER_SD_STOP_SEC		BIT(8)	/* use sector count */
+#define   UNIPHIER_SD_STOP_STP		BIT(0)	/* issue CMD12 */
+#define UNIPHIER_SD_SECCNT		0x014	/* sector counter */
+#define UNIPHIER_SD_RSP10		0x018	/* response[39:8] */
+#define UNIPHIER_SD_RSP32		0x020	/* response[71:40] */
+#define UNIPHIER_SD_RSP54		0x028	/* response[103:72] */
+#define UNIPHIER_SD_RSP76		0x030	/* response[127:104] */
+#define UNIPHIER_SD_INFO1		0x038	/* IRQ status 1 */
+#define   UNIPHIER_SD_INFO1_CD		BIT(5)	/* state of card detect */
+#define   UNIPHIER_SD_INFO1_INSERT	BIT(4)	/* card inserted */
+#define   UNIPHIER_SD_INFO1_REMOVE	BIT(3)	/* card removed */
+#define   UNIPHIER_SD_INFO1_CMP		BIT(2)	/* data complete */
+#define   UNIPHIER_SD_INFO1_RSP		BIT(0)	/* response complete */
+#define UNIPHIER_SD_INFO2		0x03c	/* IRQ status 2 */
+#define   UNIPHIER_SD_INFO2_ERR_ILA	BIT(15)	/* illegal access err */
+#define   UNIPHIER_SD_INFO2_CBSY	BIT(14)	/* command busy */
+#define   UNIPHIER_SD_INFO2_BWE		BIT(9)	/* write buffer ready */
+#define   UNIPHIER_SD_INFO2_BRE		BIT(8)	/* read buffer ready */
+#define   UNIPHIER_SD_INFO2_DAT0	BIT(7)	/* SDDAT0 */
+#define   UNIPHIER_SD_INFO2_ERR_RTO	BIT(6)	/* response time out */
+#define   UNIPHIER_SD_INFO2_ERR_ILR	BIT(5)	/* illegal read err */
+#define   UNIPHIER_SD_INFO2_ERR_ILW	BIT(4)	/* illegal write err */
+#define   UNIPHIER_SD_INFO2_ERR_TO	BIT(3)	/* time out error */
+#define   UNIPHIER_SD_INFO2_ERR_END	BIT(2)	/* END bit error */
+#define   UNIPHIER_SD_INFO2_ERR_CRC	BIT(1)	/* CRC error */
+#define   UNIPHIER_SD_INFO2_ERR_IDX	BIT(0)	/* cmd index error */
+#define UNIPHIER_SD_INFO1_MASK		0x040
+#define UNIPHIER_SD_INFO2_MASK		0x044
+#define UNIPHIER_SD_CLKCTL		0x048	/* clock divisor */
+#define   UNIPHIER_SD_CLKCTL_DIV_MASK	0x104ff
+#define   UNIPHIER_SD_CLKCTL_DIV1024	BIT(16)	/* SDCLK = CLK / 1024 */
+#define   UNIPHIER_SD_CLKCTL_DIV512	BIT(7)	/* SDCLK = CLK / 512 */
+#define   UNIPHIER_SD_CLKCTL_DIV256	BIT(6)	/* SDCLK = CLK / 256 */
+#define   UNIPHIER_SD_CLKCTL_DIV128	BIT(5)	/* SDCLK = CLK / 128 */
+#define   UNIPHIER_SD_CLKCTL_DIV64	BIT(4)	/* SDCLK = CLK / 64 */
+#define   UNIPHIER_SD_CLKCTL_DIV32	BIT(3)	/* SDCLK = CLK / 32 */
+#define   UNIPHIER_SD_CLKCTL_DIV16	BIT(2)	/* SDCLK = CLK / 16 */
+#define   UNIPHIER_SD_CLKCTL_DIV8	BIT(1)	/* SDCLK = CLK / 8 */
+#define   UNIPHIER_SD_CLKCTL_DIV4	BIT(0)	/* SDCLK = CLK / 4 */
+#define   UNIPHIER_SD_CLKCTL_DIV2	0	/* SDCLK = CLK / 2 */
+#define   UNIPHIER_SD_CLKCTL_DIV1	BIT(10)	/* SDCLK = CLK */
+#define   UNIPHIER_SD_CLKCTL_OFFEN	BIT(9)	/* stop SDCLK when unused */
+#define   UNIPHIER_SD_CLKCTL_SCLKEN	BIT(8)	/* SDCLK output enable */
+#define UNIPHIER_SD_SIZE		0x04c	/* block size */
+#define UNIPHIER_SD_OPTION		0x050
+#define   UNIPHIER_SD_OPTION_WIDTH_MASK	(5 << 13)
+#define   UNIPHIER_SD_OPTION_WIDTH_1	(4 << 13)
+#define   UNIPHIER_SD_OPTION_WIDTH_4	(0 << 13)
+#define   UNIPHIER_SD_OPTION_WIDTH_8	(1 << 13)
+#define UNIPHIER_SD_BUF			0x060	/* read/write buffer */
+#define UNIPHIER_SD_EXTMODE		0x1b0
+#define   UNIPHIER_SD_EXTMODE_DMA_EN	BIT(1)	/* transfer 1: DMA, 0: pio */
+#define UNIPHIER_SD_SOFT_RST		0x1c0
+#define UNIPHIER_SD_SOFT_RST_RSTX	BIT(0)	/* reset deassert */
+#define UNIPHIER_SD_VERSION		0x1c4	/* version register */
+#define UNIPHIER_SD_VERSION_IP		0xff	/* IP version */
+#define UNIPHIER_SD_HOST_MODE		0x1c8
+#define UNIPHIER_SD_IF_MODE		0x1cc
+#define   UNIPHIER_SD_IF_MODE_DDR	BIT(0)	/* DDR mode */
+#define UNIPHIER_SD_VOLT		0x1e4	/* voltage switch */
+#define   UNIPHIER_SD_VOLT_MASK		(3 << 0)
+#define   UNIPHIER_SD_VOLT_OFF		(0 << 0)
+#define   UNIPHIER_SD_VOLT_330		(1 << 0)/* 3.3V signal */
+#define   UNIPHIER_SD_VOLT_180		(2 << 0)/* 1.8V signal */
+#define UNIPHIER_SD_DMA_MODE		0x410
+#define   UNIPHIER_SD_DMA_MODE_DIR_RD	BIT(16)	/* 1: from device, 0: to dev */
+#define   UNIPHIER_SD_DMA_MODE_ADDR_INC	BIT(0)	/* 1: address inc, 0: fixed */
+#define UNIPHIER_SD_DMA_CTL		0x414
+#define   UNIPHIER_SD_DMA_CTL_START	BIT(0)	/* start DMA (auto cleared) */
+#define UNIPHIER_SD_DMA_RST		0x418
+#define   UNIPHIER_SD_DMA_RST_RD	BIT(9)
+#define   UNIPHIER_SD_DMA_RST_WR	BIT(8)
+#define UNIPHIER_SD_DMA_INFO1		0x420
+#define   UNIPHIER_SD_DMA_INFO1_END_RD2	BIT(20)	/* DMA from device is complete*/
+#define   UNIPHIER_SD_DMA_INFO1_END_RD	BIT(17)	/* Don't use!  Hardware bug */
+#define   UNIPHIER_SD_DMA_INFO1_END_WR	BIT(16)	/* DMA to device is complete */
+#define UNIPHIER_SD_DMA_INFO1_MASK	0x424
+#define UNIPHIER_SD_DMA_INFO2		0x428
+#define   UNIPHIER_SD_DMA_INFO2_ERR_RD	BIT(17)
+#define   UNIPHIER_SD_DMA_INFO2_ERR_WR	BIT(16)
+#define UNIPHIER_SD_DMA_INFO2_MASK	0x42c
+#define UNIPHIER_SD_DMA_ADDR_L		0x440
+#define UNIPHIER_SD_DMA_ADDR_H		0x444
+
+/* alignment required by the DMA engine of this controller */
+#define UNIPHIER_SD_DMA_MINALIGN	0x10
+
+struct uniphier_sd_priv {
+	struct mmc_config cfg;
+	struct mmc *mmc;
+	struct udevice *dev;
+	void __iomem *regbase;
+	unsigned long mclk;
+	unsigned int version;
+	u32 caps;
+#define UNIPHIER_SD_CAP_NONREMOVABLE	BIT(0)	/* Nonremovable e.g. eMMC */
+#define UNIPHIER_SD_CAP_DMA_INTERNAL	BIT(1)	/* have internal DMA engine */
+#define UNIPHIER_SD_CAP_DIV1024		BIT(2)	/* divisor 1024 is available */
+};
+
+static dma_addr_t __dma_map_single(void *ptr, size_t size,
+				   enum dma_data_direction dir)
+{
+	unsigned long addr = (unsigned long)ptr;
+
+	if (dir == DMA_FROM_DEVICE)
+		invalidate_dcache_range(addr, addr + size);
+	else
+		flush_dcache_range(addr, addr + size);
+
+	return addr;
+}
+
+static void __dma_unmap_single(dma_addr_t addr, size_t size,
+			       enum dma_data_direction dir)
+{
+	if (dir != DMA_TO_DEVICE)
+		invalidate_dcache_range(addr, addr + size);
+}
+
+static int uniphier_sd_check_error(struct uniphier_sd_priv *priv)
+{
+	u32 info2 = readl(priv->regbase + UNIPHIER_SD_INFO2);
+
+	if (info2 & UNIPHIER_SD_INFO2_ERR_RTO) {
+		/*
+		 * TIMEOUT must be returned for unsupported command.  Do not
+		 * display error log since this might be a part of sequence to
+		 * distinguish between SD and MMC.
+		 */
+		return TIMEOUT;
+	}
+
+	if (info2 & UNIPHIER_SD_INFO2_ERR_TO) {
+		dev_err(priv->dev, "timeout error\n");
+		return -ETIMEDOUT;
+	}
+
+	if (info2 & (UNIPHIER_SD_INFO2_ERR_END | UNIPHIER_SD_INFO2_ERR_CRC |
+		     UNIPHIER_SD_INFO2_ERR_IDX)) {
+		dev_err(priv->dev, "communication out of sync\n");
+		return -EILSEQ;
+	}
+
+	if (info2 & (UNIPHIER_SD_INFO2_ERR_ILA | UNIPHIER_SD_INFO2_ERR_ILR |
+		     UNIPHIER_SD_INFO2_ERR_ILW)) {
+		dev_err(priv->dev, "illegal access\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int uniphier_sd_wait_for_irq(struct uniphier_sd_priv *priv,
+				    unsigned int reg, u32 flag)
+{
+	long wait = 1000000;
+	int ret;
+
+	while (!(readl(priv->regbase + reg) & flag)) {
+		if (wait-- < 0) {
+			dev_err(priv->dev, "timeout\n");
+			return -ETIMEDOUT;
+		}
+
+		ret = uniphier_sd_check_error(priv);
+		if (ret)
+			return ret;
+
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static int uniphier_sd_pio_read_one_block(struct mmc *mmc, u32 **pbuf,
+					  uint blocksize)
+{
+	struct uniphier_sd_priv *priv = mmc->priv;
+	int i, ret;
+
+	/* wait until the buffer is filled with data */
+	ret = uniphier_sd_wait_for_irq(priv, UNIPHIER_SD_INFO2,
+				       UNIPHIER_SD_INFO2_BRE);
+	if (ret)
+		return ret;
+
+	/*
+	 * Clear the status flag _before_ read the buffer out because
+	 * UNIPHIER_SD_INFO2_BRE is edge-triggered, not level-triggered.
+	 */
+	writel(0, priv->regbase + UNIPHIER_SD_INFO2);
+
+	if (likely(IS_ALIGNED((unsigned long)*pbuf, 4))) {
+		for (i = 0; i < blocksize / 4; i++)
+			*(*pbuf)++ = readl(priv->regbase + UNIPHIER_SD_BUF);
+	} else {
+		for (i = 0; i < blocksize / 4; i++)
+			put_unaligned(readl(priv->regbase + UNIPHIER_SD_BUF),
+				      (*pbuf)++);
+	}
+
+	return 0;
+}
+
+static int uniphier_sd_pio_write_one_block(struct mmc *mmc, const u32 **pbuf,
+					   uint blocksize)
+{
+	struct uniphier_sd_priv *priv = mmc->priv;
+	int i, ret;
+
+	/* wait until the buffer becomes empty */
+	ret = uniphier_sd_wait_for_irq(priv, UNIPHIER_SD_INFO2,
+				       UNIPHIER_SD_INFO2_BWE);
+	if (ret)
+		return ret;
+
+	writel(0, priv->regbase + UNIPHIER_SD_INFO2);
+
+	if (likely(IS_ALIGNED((unsigned long)*pbuf, 4))) {
+		for (i = 0; i < blocksize / 4; i++)
+			writel(*(*pbuf)++, priv->regbase + UNIPHIER_SD_BUF);
+	} else {
+		for (i = 0; i < blocksize / 4; i++)
+			writel(get_unaligned((*pbuf)++),
+			       priv->regbase + UNIPHIER_SD_BUF);
+	}
+
+	return 0;
+}
+
+static int uniphier_sd_pio_xfer(struct mmc *mmc, struct mmc_data *data)
+{
+	u32 *dest = (u32 *)data->dest;
+	const u32 *src = (const u32 *)data->src;
+	int i, ret;
+
+	for (i = 0; i < data->blocks; i++) {
+		if (data->flags & MMC_DATA_READ)
+			ret = uniphier_sd_pio_read_one_block(mmc, &dest,
+							     data->blocksize);
+		else
+			ret = uniphier_sd_pio_write_one_block(mmc, &src,
+							      data->blocksize);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void uniphier_sd_dma_start(struct uniphier_sd_priv *priv,
+				  dma_addr_t dma_addr)
+{
+	u32 tmp;
+
+	writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO1);
+	writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO2);
+
+	/* enable DMA */
+	tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE);
+	tmp |= UNIPHIER_SD_EXTMODE_DMA_EN;
+	writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE);
+
+	writel(dma_addr & U32_MAX, priv->regbase + UNIPHIER_SD_DMA_ADDR_L);
+
+	/* suppress the warning "right shift count >= width of type" */
+	dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr));
+
+	writel(dma_addr & U32_MAX, priv->regbase + UNIPHIER_SD_DMA_ADDR_H);
+
+	writel(UNIPHIER_SD_DMA_CTL_START, priv->regbase + UNIPHIER_SD_DMA_CTL);
+}
+
+static int uniphier_sd_dma_wait_for_irq(struct uniphier_sd_priv *priv, u32 flag,
+					unsigned int blocks)
+{
+	long wait = 1000000 + 10 * blocks;
+
+	while (!(readl(priv->regbase + UNIPHIER_SD_DMA_INFO1) & flag)) {
+		if (wait-- < 0) {
+			dev_err(priv->dev, "timeout during DMA\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(10);
+	}
+
+	if (readl(priv->regbase + UNIPHIER_SD_DMA_INFO2)) {
+		dev_err(priv->dev, "error during DMA\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int uniphier_sd_dma_xfer(struct mmc *mmc, struct mmc_data *data)
+{
+	struct uniphier_sd_priv *priv = mmc->priv;
+	size_t len = data->blocks * data->blocksize;
+	void *buf;
+	enum dma_data_direction dir;
+	dma_addr_t dma_addr;
+	u32 poll_flag, tmp;
+	int ret;
+
+	tmp = readl(priv->regbase + UNIPHIER_SD_DMA_MODE);
+
+	if (data->flags & MMC_DATA_READ) {
+		buf = data->dest;
+		dir = DMA_FROM_DEVICE;
+		poll_flag = UNIPHIER_SD_DMA_INFO1_END_RD2;
+		tmp |= UNIPHIER_SD_DMA_MODE_DIR_RD;
+	} else {
+		buf = (void *)data->src;
+		dir = DMA_TO_DEVICE;
+		poll_flag = UNIPHIER_SD_DMA_INFO1_END_WR;
+		tmp &= ~UNIPHIER_SD_DMA_MODE_DIR_RD;
+	}
+
+	writel(tmp, priv->regbase + UNIPHIER_SD_DMA_MODE);
+
+	dma_addr = __dma_map_single(buf, len, dir);
+
+	uniphier_sd_dma_start(priv, dma_addr);
+
+	ret = uniphier_sd_dma_wait_for_irq(priv, poll_flag, data->blocks);
+
+	__dma_unmap_single(dma_addr, len, dir);
+
+	return ret;
+}
+
+/* check if the address is DMA'able */
+static bool uniphier_sd_addr_is_dmaable(unsigned long addr)
+{
+	if (!IS_ALIGNED(addr, UNIPHIER_SD_DMA_MINALIGN))
+		return false;
+
+#if defined(CONFIG_ARCH_UNIPHIER) && !defined(CONFIG_ARM64) && \
+	defined(CONFIG_SPL_BUILD)
+	/*
+	 * For UniPhier ARMv7 SoCs, the stack is allocated in the locked ways
+	 * of L2, which is unreachable from the DMA engine.
+	 */
+	if (addr < CONFIG_SPL_STACK)
+		return false;
+#endif
+
+	return true;
+}
+
+static int uniphier_sd_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+				struct mmc_data *data)
+{
+	struct uniphier_sd_priv *priv = mmc->priv;
+	int ret;
+	u32 tmp;
+
+	if (readl(priv->regbase + UNIPHIER_SD_INFO2) & UNIPHIER_SD_INFO2_CBSY) {
+		dev_err(priv->dev, "command busy\n");
+		return -EBUSY;
+	}
+
+	/* clear all status flags */
+	writel(0, priv->regbase + UNIPHIER_SD_INFO1);
+	writel(0, priv->regbase + UNIPHIER_SD_INFO2);
+
+	/* disable DMA once */
+	tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE);
+	tmp &= ~UNIPHIER_SD_EXTMODE_DMA_EN;
+	writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE);
+
+	writel(cmd->cmdarg, priv->regbase + UNIPHIER_SD_ARG);
+
+	tmp = cmd->cmdidx;
+
+	if (data) {
+		writel(data->blocksize, priv->regbase + UNIPHIER_SD_SIZE);
+		writel(data->blocks, priv->regbase + UNIPHIER_SD_SECCNT);
+
+		/* Do not send CMD12 automatically */
+		tmp |= UNIPHIER_SD_CMD_NOSTOP | UNIPHIER_SD_CMD_DATA;
+
+		if (data->blocks > 1)
+			tmp |= UNIPHIER_SD_CMD_MULTI;
+
+		if (data->flags & MMC_DATA_READ)
+			tmp |= UNIPHIER_SD_CMD_RD;
+	}
+
+	/*
+	 * Do not use the response type auto-detection on this hardware.
+	 * CMD8, for example, has different response types on SD and eMMC,
+	 * while this controller always assumes the response type for SD.
+	 * Set the response type manually.
+	 */
+	switch (cmd->resp_type) {
+	case MMC_RSP_NONE:
+		tmp |= UNIPHIER_SD_CMD_RSP_NONE;
+		break;
+	case MMC_RSP_R1:
+		tmp |= UNIPHIER_SD_CMD_RSP_R1;
+		break;
+	case MMC_RSP_R1b:
+		tmp |= UNIPHIER_SD_CMD_RSP_R1B;
+		break;
+	case MMC_RSP_R2:
+		tmp |= UNIPHIER_SD_CMD_RSP_R2;
+		break;
+	case MMC_RSP_R3:
+		tmp |= UNIPHIER_SD_CMD_RSP_R3;
+		break;
+	default:
+		dev_err(priv->dev, "unknown response type\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(priv->dev, "sending CMD%d (SD_CMD=%08x, SD_ARG=%08x)\n",
+		cmd->cmdidx, tmp, cmd->cmdarg);
+	writel(tmp, priv->regbase + UNIPHIER_SD_CMD);
+
+	ret = uniphier_sd_wait_for_irq(priv, UNIPHIER_SD_INFO1,
+				       UNIPHIER_SD_INFO1_RSP);
+	if (ret)
+		return ret;
+
+	if (cmd->resp_type & MMC_RSP_136) {
+		u32 rsp_127_104 = readl(priv->regbase + UNIPHIER_SD_RSP76);
+		u32 rsp_103_72 = readl(priv->regbase + UNIPHIER_SD_RSP54);
+		u32 rsp_71_40 = readl(priv->regbase + UNIPHIER_SD_RSP32);
+		u32 rsp_39_8 = readl(priv->regbase + UNIPHIER_SD_RSP10);
+
+		cmd->response[0] = (rsp_127_104 & 0xffffff) << 8 |
+							(rsp_103_72 & 0xff);
+		cmd->response[1] = (rsp_103_72  & 0xffffff) << 8 |
+							(rsp_71_40 & 0xff);
+		cmd->response[2] = (rsp_71_40   & 0xffffff) << 8 |
+							(rsp_39_8 & 0xff);
+		cmd->response[3] = (rsp_39_8    & 0xffffff) << 8;
+	} else {
+		/* bit 39-8 */
+		cmd->response[0] = readl(priv->regbase + UNIPHIER_SD_RSP10);
+	}
+
+	if (data) {
+		/* use DMA if the HW supports it and the buffer is aligned */
+		if (priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL &&
+		    uniphier_sd_addr_is_dmaable((long)data->src))
+			ret = uniphier_sd_dma_xfer(mmc, data);
+		else
+			ret = uniphier_sd_pio_xfer(mmc, data);
+
+		ret = uniphier_sd_wait_for_irq(priv, UNIPHIER_SD_INFO1,
+					       UNIPHIER_SD_INFO1_CMP);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static void uniphier_sd_set_bus_width(struct uniphier_sd_priv *priv,
+				      struct mmc *mmc)
+{
+	u32 val, tmp;
+
+	switch (mmc->bus_width) {
+	case 1:
+		val = UNIPHIER_SD_OPTION_WIDTH_1;
+		break;
+	case 4:
+		val = UNIPHIER_SD_OPTION_WIDTH_4;
+		break;
+	case 8:
+		val = UNIPHIER_SD_OPTION_WIDTH_8;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	tmp = readl(priv->regbase + UNIPHIER_SD_OPTION);
+	tmp &= ~UNIPHIER_SD_OPTION_WIDTH_MASK;
+	tmp |= val;
+	writel(tmp, priv->regbase + UNIPHIER_SD_OPTION);
+}
+
+static void uniphier_sd_set_ddr_mode(struct uniphier_sd_priv *priv,
+				     struct mmc *mmc)
+{
+	u32 tmp;
+
+	tmp = readl(priv->regbase + UNIPHIER_SD_IF_MODE);
+	if (mmc->ddr_mode)
+		tmp |= UNIPHIER_SD_IF_MODE_DDR;
+	else
+		tmp &= ~UNIPHIER_SD_IF_MODE_DDR;
+	writel(tmp, priv->regbase + UNIPHIER_SD_IF_MODE);
+}
+
+static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv,
+				     struct mmc *mmc)
+{
+	unsigned int divisor;
+	u32 val, tmp;
+
+	if (!mmc->clock)
+		return;
+
+	divisor = DIV_ROUND_UP(priv->mclk, mmc->clock);
+
+	if (divisor <= 1)
+		val = UNIPHIER_SD_CLKCTL_DIV1;
+	else if (divisor <= 2)
+		val = UNIPHIER_SD_CLKCTL_DIV2;
+	else if (divisor <= 4)
+		val = UNIPHIER_SD_CLKCTL_DIV4;
+	else if (divisor <= 8)
+		val = UNIPHIER_SD_CLKCTL_DIV8;
+	else if (divisor <= 16)
+		val = UNIPHIER_SD_CLKCTL_DIV16;
+	else if (divisor <= 32)
+		val = UNIPHIER_SD_CLKCTL_DIV32;
+	else if (divisor <= 64)
+		val = UNIPHIER_SD_CLKCTL_DIV64;
+	else if (divisor <= 128)
+		val = UNIPHIER_SD_CLKCTL_DIV128;
+	else if (divisor <= 256)
+		val = UNIPHIER_SD_CLKCTL_DIV256;
+	else if (divisor <= 512 || !(priv->caps & UNIPHIER_SD_CAP_DIV1024))
+		val = UNIPHIER_SD_CLKCTL_DIV512;
+	else
+		val = UNIPHIER_SD_CLKCTL_DIV1024;
+
+	tmp = readl(priv->regbase + UNIPHIER_SD_CLKCTL);
+
+	/* stop the clock before changing its rate to avoid a glitch signal */
+	tmp &= ~UNIPHIER_SD_CLKCTL_SCLKEN;
+	writel(tmp, priv->regbase + UNIPHIER_SD_CLKCTL);
+
+	tmp &= ~UNIPHIER_SD_CLKCTL_DIV_MASK;
+	tmp |= val | UNIPHIER_SD_CLKCTL_OFFEN;
+	writel(tmp, priv->regbase + UNIPHIER_SD_CLKCTL);
+
+	tmp |= UNIPHIER_SD_CLKCTL_SCLKEN;
+	writel(tmp, priv->regbase + UNIPHIER_SD_CLKCTL);
+}
+
+static void uniphier_sd_set_ios(struct mmc *mmc)
+{
+	struct uniphier_sd_priv *priv = mmc->priv;
+
+	dev_dbg(priv->dev, "clock %uHz, DDRmode %d, width %u\n",
+		mmc->clock, mmc->ddr_mode, mmc->bus_width);
+
+	uniphier_sd_set_bus_width(priv, mmc);
+	uniphier_sd_set_ddr_mode(priv, mmc);
+	uniphier_sd_set_clk_rate(priv, mmc);
+
+	udelay(1000);
+}
+
+static int uniphier_sd_init(struct mmc *mmc)
+{
+	struct uniphier_sd_priv *priv = mmc->priv;
+	u32 tmp;
+
+	/* soft reset of the host */
+	tmp = readl(priv->regbase + UNIPHIER_SD_SOFT_RST);
+	tmp &= ~UNIPHIER_SD_SOFT_RST_RSTX;
+	writel(tmp, priv->regbase + UNIPHIER_SD_SOFT_RST);
+	tmp |= UNIPHIER_SD_SOFT_RST_RSTX;
+	writel(tmp, priv->regbase + UNIPHIER_SD_SOFT_RST);
+
+	/* FIXME: implement eMMC hw_reset */
+
+	writel(UNIPHIER_SD_STOP_SEC, priv->regbase + UNIPHIER_SD_STOP);
+
+	/*
+	 * Connected to 32bit AXI.
+	 * This register dropped backward compatibility at version 0x10.
+	 * Write an appropriate value depending on the IP version.
+	 */
+	writel(priv->version >= 0x10 ? 0x00000101 : 0x00000000,
+	       priv->regbase + UNIPHIER_SD_HOST_MODE);
+
+	if (priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL) {
+		tmp = readl(priv->regbase + UNIPHIER_SD_DMA_MODE);
+		tmp |= UNIPHIER_SD_DMA_MODE_ADDR_INC;
+		writel(tmp, priv->regbase + UNIPHIER_SD_DMA_MODE);
+	}
+
+	return 0;
+}
+
+static int uniphier_sd_getcd(struct mmc *mmc)
+{
+	struct uniphier_sd_priv *priv = mmc->priv;
+
+	if (priv->caps & UNIPHIER_SD_CAP_NONREMOVABLE)
+		return 1;
+
+	return !!(readl(priv->regbase + UNIPHIER_SD_INFO1) &
+		  UNIPHIER_SD_INFO1_CD);
+}
+
+static const struct mmc_ops uniphier_sd_ops = {
+	.send_cmd = uniphier_sd_send_cmd,
+	.set_ios = uniphier_sd_set_ios,
+	.init = uniphier_sd_init,
+	.getcd = uniphier_sd_getcd,
+};
+
+int uniphier_sd_probe(struct udevice *dev)
+{
+	struct uniphier_sd_priv *priv = dev_get_priv(dev);
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	fdt_addr_t base;
+	fdt_size_t size;
+	struct udevice *clk_dev;
+	int clk_id;
+	int ret;
+
+	priv->dev = dev;
+
+	base = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
+	priv->regbase = map_sysmem(base, size);
+	if (!priv->regbase)
+		return -ENOMEM;
+
+	clk_id = clk_get_by_index(dev, 0, &clk_dev);
+	if (clk_id < 0) {
+		dev_err(dev, "failed to get host clock\n");
+		return clk_id;
+	}
+
+	/* set to max rate */
+	priv->mclk = clk_set_periph_rate(clk_dev, clk_id, ULONG_MAX);
+	if (IS_ERR_VALUE(priv->mclk)) {
+		dev_err(dev, "failed to set rate for host clock\n");
+		return priv->mclk;
+	}
+
+	ret = clk_enable(clk_dev, clk_id);
+	if (ret) {
+		dev_err(dev, "failed to enable host clock\n");
+		return ret;
+	}
+
+	priv->cfg.name = dev->name;
+	priv->cfg.ops = &uniphier_sd_ops;
+	priv->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+	switch (fdtdec_get_int(gd->fdt_blob, dev->of_offset, "bus-width", 1)) {
+	case 8:
+		priv->cfg.host_caps |= MMC_MODE_8BIT;
+		break;
+	case 4:
+		priv->cfg.host_caps |= MMC_MODE_4BIT;
+		break;
+	case 1:
+		break;
+	default:
+		dev_err(dev, "Invalid \"bus-width\" value\n");
+		return -EINVAL;
+	}
+
+	if (fdt_get_property(gd->fdt_blob, dev->of_offset, "non-removable",
+			     NULL))
+		priv->caps |= UNIPHIER_SD_CAP_NONREMOVABLE;
+
+	priv->version = readl(priv->regbase + UNIPHIER_SD_VERSION) &
+							UNIPHIER_SD_VERSION_IP;
+	dev_dbg(dev, "version %x\n", priv->version);
+	if (priv->version >= 0x10) {
+		priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL;
+		priv->caps |= UNIPHIER_SD_CAP_DIV1024;
+	}
+
+	priv->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
+	priv->cfg.f_min = priv->mclk /
+			(priv->caps & UNIPHIER_SD_CAP_DIV1024 ? 1024 : 512);
+	priv->cfg.f_max = priv->mclk;
+	priv->cfg.b_max = U32_MAX; /* max value of UNIPHIER_SD_SECCNT */
+
+	priv->mmc = mmc_create(&priv->cfg, priv);
+	if (!priv->mmc)
+		return -EIO;
+
+	upriv->mmc = priv->mmc;
+
+	return 0;
+}
+
+int uniphier_sd_remove(struct udevice *dev)
+{
+	struct uniphier_sd_priv *priv = dev_get_priv(dev);
+
+	unmap_sysmem(priv->regbase);
+	mmc_destroy(priv->mmc);
+
+	return 0;
+}
+
+static const struct udevice_id uniphier_sd_match[] = {
+	{ .compatible = "socionext,uniphier-sdhc" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(uniphier_mmc) = {
+	.name = "uniphier-mmc",
+	.id = UCLASS_MMC,
+	.of_match = uniphier_sd_match,
+	.probe = uniphier_sd_probe,
+	.remove = uniphier_sd_remove,
+	.priv_auto_alloc_size = sizeof(struct uniphier_sd_priv),
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH v4 2/3] ARM: uniphier: enable UniPhier SD/MMC host driver
  2016-02-18 10:52 [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver Masahiro Yamada
  2016-02-18 10:52 ` [U-Boot] [PATCH v4 1/3] mmc: uniphier: add driver for UniPhier SD/MMC host controller Masahiro Yamada
@ 2016-02-18 10:52 ` Masahiro Yamada
  2016-02-18 10:52 ` [U-Boot] [PATCH v4 3/3] ARM: dts: uniphier: add SD/MMC host controller nodes Masahiro Yamada
  2016-02-26 15:41 ` [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver Masahiro Yamada
  3 siblings, 0 replies; 5+ messages in thread
From: Masahiro Yamada @ 2016-02-18 10:52 UTC (permalink / raw)
  To: u-boot

Enable the driver in all UniPhier defconfig files and add some
needed defines to the common files.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 arch/arm/Kconfig                     | 1 +
 configs/uniphier_ld4_sld8_defconfig  | 1 +
 configs/uniphier_pro4_defconfig      | 1 +
 configs/uniphier_pro5_defconfig      | 1 +
 configs/uniphier_pxs2_ld6b_defconfig | 1 +
 configs/uniphier_sld3_defconfig      | 1 +
 include/configs/uniphier.h           | 4 ++++
 7 files changed, 10 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 94bd7ec..37b20ff 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -700,6 +700,7 @@ config ARCH_UNIPHIER
 	select DM_GPIO
 	select DM_SERIAL
 	select DM_I2C
+	select DM_MMC
 	help
 	  Support for UniPhier SoC family developed by Socionext Inc.
 	  (formerly, System LSI Business Division of Panasonic Corporation)
diff --git a/configs/uniphier_ld4_sld8_defconfig b/configs/uniphier_ld4_sld8_defconfig
index dbee08e..892bccc 100644
--- a/configs/uniphier_ld4_sld8_defconfig
+++ b/configs/uniphier_ld4_sld8_defconfig
@@ -21,6 +21,7 @@ CONFIG_CMD_TIME=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_SPL_SIMPLE_BUS=y
 CONFIG_GPIO_UNIPHIER=y
+CONFIG_MMC_UNIPHIER=y
 CONFIG_NAND_DENALI=y
 CONFIG_SYS_NAND_DENALI_64BIT=y
 CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
diff --git a/configs/uniphier_pro4_defconfig b/configs/uniphier_pro4_defconfig
index 3c2f7b0..45ef883 100644
--- a/configs/uniphier_pro4_defconfig
+++ b/configs/uniphier_pro4_defconfig
@@ -20,6 +20,7 @@ CONFIG_CMD_TIME=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_SPL_SIMPLE_BUS=y
 CONFIG_GPIO_UNIPHIER=y
+CONFIG_MMC_UNIPHIER=y
 CONFIG_NAND_DENALI=y
 CONFIG_SYS_NAND_DENALI_64BIT=y
 CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
diff --git a/configs/uniphier_pro5_defconfig b/configs/uniphier_pro5_defconfig
index cf5f1ce..0029cd3 100644
--- a/configs/uniphier_pro5_defconfig
+++ b/configs/uniphier_pro5_defconfig
@@ -20,6 +20,7 @@ CONFIG_CMD_TIME=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_SPL_SIMPLE_BUS=y
 CONFIG_GPIO_UNIPHIER=y
+CONFIG_MMC_UNIPHIER=y
 CONFIG_NAND_DENALI=y
 CONFIG_SYS_NAND_DENALI_64BIT=y
 CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
diff --git a/configs/uniphier_pxs2_ld6b_defconfig b/configs/uniphier_pxs2_ld6b_defconfig
index 00a2900..0115c21 100644
--- a/configs/uniphier_pxs2_ld6b_defconfig
+++ b/configs/uniphier_pxs2_ld6b_defconfig
@@ -21,6 +21,7 @@ CONFIG_CMD_TIME=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_SPL_SIMPLE_BUS=y
 CONFIG_GPIO_UNIPHIER=y
+CONFIG_MMC_UNIPHIER=y
 CONFIG_NAND_DENALI=y
 CONFIG_SYS_NAND_DENALI_64BIT=y
 CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
diff --git a/configs/uniphier_sld3_defconfig b/configs/uniphier_sld3_defconfig
index 013fc8a..5f0d678 100644
--- a/configs/uniphier_sld3_defconfig
+++ b/configs/uniphier_sld3_defconfig
@@ -18,6 +18,7 @@ CONFIG_CMD_TIME=y
 # CONFIG_CMD_MISC is not set
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_GPIO_UNIPHIER=y
+CONFIG_MMC_UNIPHIER=y
 CONFIG_NAND_DENALI=y
 CONFIG_SYS_NAND_DENALI_64BIT=y
 CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h
index fcec0c0..9d14155 100644
--- a/include/configs/uniphier.h
+++ b/include/configs/uniphier.h
@@ -146,6 +146,10 @@
 #define CONFIG_FAT_WRITE
 #define CONFIG_DOS_PARTITION
 
+/* SD/MMC */
+#define CONFIG_CMD_MMC
+#define CONFIG_GENERIC_MMC
+
 /* memtest works on */
 #define CONFIG_SYS_MEMTEST_START	CONFIG_SYS_SDRAM_BASE
 #define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_SDRAM_BASE + 0x01000000)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH v4 3/3] ARM: dts: uniphier: add SD/MMC host controller nodes
  2016-02-18 10:52 [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver Masahiro Yamada
  2016-02-18 10:52 ` [U-Boot] [PATCH v4 1/3] mmc: uniphier: add driver for UniPhier SD/MMC host controller Masahiro Yamada
  2016-02-18 10:52 ` [U-Boot] [PATCH v4 2/3] ARM: uniphier: enable UniPhier SD/MMC host driver Masahiro Yamada
@ 2016-02-18 10:52 ` Masahiro Yamada
  2016-02-26 15:41 ` [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver Masahiro Yamada
  3 siblings, 0 replies; 5+ messages in thread
From: Masahiro Yamada @ 2016-02-18 10:52 UTC (permalink / raw)
  To: u-boot

This host controller is available for all UniPhier SoCs.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 arch/arm/dts/uniphier-ph1-ld4-ref.dts        |  4 +++
 arch/arm/dts/uniphier-ph1-ld4.dtsi           | 25 +++++++++++++++++++
 arch/arm/dts/uniphier-ph1-ld6b-ref.dts       |  4 +++
 arch/arm/dts/uniphier-ph1-pro4-ace.dts       |  4 +++
 arch/arm/dts/uniphier-ph1-pro4-ref.dts       |  8 ++++++
 arch/arm/dts/uniphier-ph1-pro4-sanji.dts     |  4 +++
 arch/arm/dts/uniphier-ph1-pro4.dtsi          | 37 ++++++++++++++++++++++++++++
 arch/arm/dts/uniphier-ph1-pro5-4kbox.dts     |  8 ++++++
 arch/arm/dts/uniphier-ph1-pro5.dtsi          | 24 ++++++++++++++++++
 arch/arm/dts/uniphier-ph1-sld3-ref.dts       |  4 +++
 arch/arm/dts/uniphier-ph1-sld3.dtsi          | 19 ++++++++++++++
 arch/arm/dts/uniphier-ph1-sld8-ref.dts       |  4 +++
 arch/arm/dts/uniphier-ph1-sld8.dtsi          | 25 +++++++++++++++++++
 arch/arm/dts/uniphier-pinctrl.dtsi           | 15 +++++++++++
 arch/arm/dts/uniphier-proxstream2-gentil.dts |  4 +++
 arch/arm/dts/uniphier-proxstream2-vodka.dts  |  4 +++
 arch/arm/dts/uniphier-proxstream2.dtsi       | 24 ++++++++++++++++++
 17 files changed, 217 insertions(+)

diff --git a/arch/arm/dts/uniphier-ph1-ld4-ref.dts b/arch/arm/dts/uniphier-ph1-ld4-ref.dts
index f62916d..d7b0007 100644
--- a/arch/arm/dts/uniphier-ph1-ld4-ref.dts
+++ b/arch/arm/dts/uniphier-ph1-ld4-ref.dts
@@ -51,6 +51,10 @@
 	status = "okay";
 };
 
+&sd {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-ph1-ld4.dtsi b/arch/arm/dts/uniphier-ph1-ld4.dtsi
index f13c6db..5ae029e 100644
--- a/arch/arm/dts/uniphier-ph1-ld4.dtsi
+++ b/arch/arm/dts/uniphier-ph1-ld4.dtsi
@@ -220,6 +220,31 @@
 		clock-frequency = <100000>;
 	};
 
+	sd: sdhc at 5a400000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x5a400000 0x200>;
+		interrupts = <0 76 4>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_sd>;
+		pinctrl-1 = <&pinctrl_sd_1v8>;
+		clocks = <&mio 0>;
+		bus-width = <4>;
+	};
+
+	emmc: sdhc at 5a500000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x5a500000 0x200>;
+		interrupts = <0 78 4>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_emmc>;
+		pinctrl-1 = <&pinctrl_emmc_1v8>;
+		clocks = <&mio 1>;
+		bus-width = <8>;
+		non-removable;
+	};
+
 	usb0: usb at 5a800100 {
 		compatible = "socionext,uniphier-ehci", "generic-ehci";
 		status = "disabled";
diff --git a/arch/arm/dts/uniphier-ph1-ld6b-ref.dts b/arch/arm/dts/uniphier-ph1-ld6b-ref.dts
index dca408b..13a29fd 100644
--- a/arch/arm/dts/uniphier-ph1-ld6b-ref.dts
+++ b/arch/arm/dts/uniphier-ph1-ld6b-ref.dts
@@ -53,6 +53,10 @@
 	status = "okay";
 };
 
+&sd {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-ph1-pro4-ace.dts b/arch/arm/dts/uniphier-ph1-pro4-ace.dts
index 6e741ea..37e0853 100644
--- a/arch/arm/dts/uniphier-ph1-pro4-ace.dts
+++ b/arch/arm/dts/uniphier-ph1-pro4-ace.dts
@@ -69,6 +69,10 @@
 	status = "okay";
 };
 
+&sd {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-ph1-pro4-ref.dts b/arch/arm/dts/uniphier-ph1-pro4-ref.dts
index 202a642..07a9783 100644
--- a/arch/arm/dts/uniphier-ph1-pro4-ref.dts
+++ b/arch/arm/dts/uniphier-ph1-pro4-ref.dts
@@ -54,6 +54,14 @@
 	status = "okay";
 };
 
+&sd {
+	status = "okay";
+};
+
+&sd1 {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-ph1-pro4-sanji.dts b/arch/arm/dts/uniphier-ph1-pro4-sanji.dts
index 91a71ef..1ca1042 100644
--- a/arch/arm/dts/uniphier-ph1-pro4-sanji.dts
+++ b/arch/arm/dts/uniphier-ph1-pro4-sanji.dts
@@ -64,6 +64,10 @@
 	status = "okay";
 };
 
+&emmc {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-ph1-pro4.dtsi b/arch/arm/dts/uniphier-ph1-pro4.dtsi
index 6637aea..d5767b6 100644
--- a/arch/arm/dts/uniphier-ph1-pro4.dtsi
+++ b/arch/arm/dts/uniphier-ph1-pro4.dtsi
@@ -343,6 +343,43 @@
 		clock-frequency = <400000>;
 	};
 
+	sd: sdhc at 5a400000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x5a400000 0x200>;
+		interrupts = <0 76 4>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_sd>;
+		pinctrl-1 = <&pinctrl_sd_1v8>;
+		clocks = <&mio 0>;
+		bus-width = <4>;
+	};
+
+	emmc: sdhc at 5a500000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x5a500000 0x200>;
+		interrupts = <0 78 4>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_emmc>;
+		pinctrl-1 = <&pinctrl_emmc_1v8>;
+		clocks = <&mio 1>;
+		bus-width = <8>;
+		non-removable;
+	};
+
+	sd1: sdhc at 5a600000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x5a600000 0x200>;
+		interrupts = <0 85 4>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_sd1>;
+		pinctrl-1 = <&pinctrl_sd1_1v8>;
+		clocks = <&mio 2>;
+		bus-width = <4>;
+	};
+
 	usb2: usb at 5a800100 {
 		compatible = "socionext,uniphier-ehci", "generic-ehci";
 		status = "disabled";
diff --git a/arch/arm/dts/uniphier-ph1-pro5-4kbox.dts b/arch/arm/dts/uniphier-ph1-pro5-4kbox.dts
index 02a3362..cbdc3eb 100644
--- a/arch/arm/dts/uniphier-ph1-pro5-4kbox.dts
+++ b/arch/arm/dts/uniphier-ph1-pro5-4kbox.dts
@@ -47,6 +47,14 @@
 	status = "okay";
 };
 
+&emmc {
+	status = "okay";
+};
+
+&sd {
+	status = "okay";
+};
+
 /* for U-Boot only */
 / {
 	soc {
diff --git a/arch/arm/dts/uniphier-ph1-pro5.dtsi b/arch/arm/dts/uniphier-ph1-pro5.dtsi
index 67a435e..bd1b4b1 100644
--- a/arch/arm/dts/uniphier-ph1-pro5.dtsi
+++ b/arch/arm/dts/uniphier-ph1-pro5.dtsi
@@ -355,6 +355,30 @@
 		clock-frequency = <400000>;
 	};
 
+	emmc: sdhc at 68400000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x68400000 0x800>;
+		interrupts = <0 78 4>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_emmc>;
+		clocks = <&mio 1>;
+		bus-width = <8>;
+		non-removable;
+	};
+
+	sd: sdhc at 68800000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x68800000 0x800>;
+		interrupts = <0 76 4>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_sd>;
+		pinctrl-1 = <&pinctrl_sd_1v8>;
+		clocks = <&mio 0>;
+		bus-width = <4>;
+	};
+
 	usb0: usb at 65a00000 {
 		compatible = "socionext,uniphier-xhci", "generic-xhci";
 		status = "disabled";
diff --git a/arch/arm/dts/uniphier-ph1-sld3-ref.dts b/arch/arm/dts/uniphier-ph1-sld3-ref.dts
index ff17945..c7213c9 100644
--- a/arch/arm/dts/uniphier-ph1-sld3-ref.dts
+++ b/arch/arm/dts/uniphier-ph1-sld3-ref.dts
@@ -52,6 +52,10 @@
 	status = "okay";
 };
 
+&sd {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-ph1-sld3.dtsi b/arch/arm/dts/uniphier-ph1-sld3.dtsi
index 9a6ca57..789713d 100644
--- a/arch/arm/dts/uniphier-ph1-sld3.dtsi
+++ b/arch/arm/dts/uniphier-ph1-sld3.dtsi
@@ -298,6 +298,25 @@
 			clocks = <&sysctrl 10>, <&sysctrl 18>;
 		};
 
+		emmc: sdhc at 5a400000 {
+			compatible = "socionext,uniphier-sdhc";
+			status = "disabled";
+			reg = <0x5a400000 0x200>;
+			interrupts = <0 78 4>;
+			clocks = <&mio 1>;
+			bus-width = <8>;
+			non-removable;
+		};
+
+		sd: sdhc at 5a500000 {
+			compatible = "socionext,uniphier-sdhc";
+			status = "disabled";
+			reg = <0x5a500000 0x200>;
+			interrupts = <0 76 4>;
+			clocks = <&mio 0>;
+			bus-width = <4>;
+		};
+
 		usb0: usb at 5a800100 {
 			compatible = "socionext,uniphier-ehci", "generic-ehci";
 			status = "disabled";
diff --git a/arch/arm/dts/uniphier-ph1-sld8-ref.dts b/arch/arm/dts/uniphier-ph1-sld8-ref.dts
index b5b6f65..ec5c5bd 100644
--- a/arch/arm/dts/uniphier-ph1-sld8-ref.dts
+++ b/arch/arm/dts/uniphier-ph1-sld8-ref.dts
@@ -51,6 +51,10 @@
 	status = "okay";
 };
 
+&sd {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-ph1-sld8.dtsi b/arch/arm/dts/uniphier-ph1-sld8.dtsi
index 985848a..61e0b45 100644
--- a/arch/arm/dts/uniphier-ph1-sld8.dtsi
+++ b/arch/arm/dts/uniphier-ph1-sld8.dtsi
@@ -220,6 +220,31 @@
 		clock-frequency = <100000>;
 	};
 
+	sd: sdhc at 5a400000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x5a400000 0x200>;
+		interrupts = <0 76 4>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_sd>;
+		pinctrl-1 = <&pinctrl_sd_1v8>;
+		clocks = <&mio 0>;
+		bus-width = <4>;
+	};
+
+	emmc: sdhc at 5a500000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		interrupts = <0 78 4>;
+		reg = <0x5a500000 0x200>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_emmc>;
+		pinctrl-1 = <&pinctrl_emmc_1v8>;
+		clocks = <&mio 1>;
+		bus-width = <8>;
+		non-removable;
+	};
+
 	usb0: usb at 5a800100 {
 		compatible = "socionext,uniphier-ehci", "generic-ehci";
 		status = "disabled";
diff --git a/arch/arm/dts/uniphier-pinctrl.dtsi b/arch/arm/dts/uniphier-pinctrl.dtsi
index b1691d0..494139a 100644
--- a/arch/arm/dts/uniphier-pinctrl.dtsi
+++ b/arch/arm/dts/uniphier-pinctrl.dtsi
@@ -12,6 +12,11 @@
 		function = "emmc";
 	};
 
+	pinctrl_emmc_1v8: emmc_grp_1v8 {
+		groups = "emmc", "emmc_dat8";
+		function = "emmc";
+	};
+
 	pinctrl_i2c0: i2c0_grp {
 		groups = "i2c0";
 		function = "i2c0";
@@ -37,11 +42,21 @@
 		function = "sd";
 	};
 
+	pinctrl_sd_1v8: sd_grp_1v8 {
+		groups = "sd";
+		function = "sd";
+	};
+
 	pinctrl_sd1: sd1_grp {
 		groups = "sd1";
 		function = "sd1";
 	};
 
+	pinctrl_sd1_1v8: sd1_grp_1v8 {
+		groups = "sd1";
+		function = "sd1";
+	};
+
 	pinctrl_uart0: uart0_grp {
 		groups = "uart0";
 		function = "uart0";
diff --git a/arch/arm/dts/uniphier-proxstream2-gentil.dts b/arch/arm/dts/uniphier-proxstream2-gentil.dts
index dc0def3..c3551fe 100644
--- a/arch/arm/dts/uniphier-proxstream2-gentil.dts
+++ b/arch/arm/dts/uniphier-proxstream2-gentil.dts
@@ -52,6 +52,10 @@
 	status = "okay";
 };
 
+&emmc {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-proxstream2-vodka.dts b/arch/arm/dts/uniphier-proxstream2-vodka.dts
index 3703ad3..d61e0b6 100644
--- a/arch/arm/dts/uniphier-proxstream2-vodka.dts
+++ b/arch/arm/dts/uniphier-proxstream2-vodka.dts
@@ -41,6 +41,10 @@
 	status = "okay";
 };
 
+&emmc {
+	status = "okay";
+};
+
 &usb0 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-proxstream2.dtsi b/arch/arm/dts/uniphier-proxstream2.dtsi
index 21fad0c..12968bd 100644
--- a/arch/arm/dts/uniphier-proxstream2.dtsi
+++ b/arch/arm/dts/uniphier-proxstream2.dtsi
@@ -359,6 +359,30 @@
 		clock-frequency = <400000>;
 	};
 
+	emmc: sdhc at 5a000000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x5a000000 0x800>;
+		interrupts = <0 78 4>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_emmc>;
+		clocks = <&mio 1>;
+		bus-width = <8>;
+		non-removable;
+	};
+
+	sd: sdhc at 5a400000 {
+		compatible = "socionext,uniphier-sdhc";
+		status = "disabled";
+		reg = <0x5a400000 0x800>;
+		interrupts = <0 76 4>;
+		pinctrl-names = "default", "1.8v";
+		pinctrl-0 = <&pinctrl_sd>;
+		pinctrl-1 = <&pinctrl_sd_1v8>;
+		clocks = <&mio 0>;
+		bus-width = <4>;
+	};
+
 	usb0: usb at 65a00000 {
 		compatible = "socionext,uniphier-xhci", "generic-xhci";
 		status = "disabled";
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver
  2016-02-18 10:52 [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver Masahiro Yamada
                   ` (2 preceding siblings ...)
  2016-02-18 10:52 ` [U-Boot] [PATCH v4 3/3] ARM: dts: uniphier: add SD/MMC host controller nodes Masahiro Yamada
@ 2016-02-26 15:41 ` Masahiro Yamada
  3 siblings, 0 replies; 5+ messages in thread
From: Masahiro Yamada @ 2016-02-26 15:41 UTC (permalink / raw)
  To: u-boot

2016-02-18 19:52 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
>
>
> Changes in v4:
>   - Add some comments about HOST_MODE register
>   - Rename uniphier_sd_wait_irq() to uniphier_sd_wait_for_irq()
>
> Changes in v3:
>   - Use dev_err/dev_dbg instead of pr_err/pr_debug
>   - Tidy up uniphier_sd_set_ios()
>   - Allow to use DMA even in SPL if the target address is DMA'able
>
> Changes in v2:
>   - Fix the divisor bug on the older IP (on PH1-LD4, PH1-sLD8, PH1-Pro4)
>   - Increase time out because "mmc erase" can sometimes take long
>   - Move HOST_MODE register setting to uniphier_sd_init()
>     because this register does not need setting multipule times.
>
> Masahiro Yamada (3):
>   mmc: uniphier: add driver for UniPhier SD/MMC host controller
>   ARM: uniphier: enable UniPhier SD/MMC host driver
>   ARM: dts: uniphier: add SD/MMC host controller nodes
>

Series, applied to u-boot-uniphier.



-- 
Best Regards
Masahiro Yamada

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-02-26 15:41 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-18 10:52 [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver Masahiro Yamada
2016-02-18 10:52 ` [U-Boot] [PATCH v4 1/3] mmc: uniphier: add driver for UniPhier SD/MMC host controller Masahiro Yamada
2016-02-18 10:52 ` [U-Boot] [PATCH v4 2/3] ARM: uniphier: enable UniPhier SD/MMC host driver Masahiro Yamada
2016-02-18 10:52 ` [U-Boot] [PATCH v4 3/3] ARM: dts: uniphier: add SD/MMC host controller nodes Masahiro Yamada
2016-02-26 15:41 ` [U-Boot] [PATCH v4 0/3] UniPhier SD/eMMC controller driver Masahiro Yamada

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.