All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] ARM: sunxi: Add driver for SD/MMC hosts found on allwinner sunxi SOCs
@ 2013-12-14 21:58 ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: Chris Ball, Maxime Ripard
  Cc: David Lanzendörfer, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi All,

This patchset adds support for the SD/MMC hosts found on sun4i, sun5i and
sun7i SOCs. It is based on the driver Allwinner ships in their Android kernel
sources.

Initial porting to upstream kernels done by David Lanzendörfer.

I've spend a lot of time cleaning this up, so hopefuly it is ready to go
upstream now, please review.

Note David Lanzendörfer will maintain this driver in the future. I jumped into
the process of creating this driver to iron out a few blocker bugs and ended
up also doing a lot of cleanup as David was busy. David should have time to
work on this again now, so if a v2 of the patch-set is needed, he will likely
post it.

Thanks & Regards,

Hans

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/groups/opt_out.

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

* [PATCH 0/5] ARM: sunxi: Add driver for SD/MMC hosts found on allwinner sunxi SOCs
@ 2013-12-14 21:58 ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi All,

This patchset adds support for the SD/MMC hosts found on sun4i, sun5i and
sun7i SOCs. It is based on the driver Allwinner ships in their Android kernel
sources.

Initial porting to upstream kernels done by David Lanzend?rfer.

I've spend a lot of time cleaning this up, so hopefuly it is ready to go
upstream now, please review.

Note David Lanzend?rfer will maintain this driver in the future. I jumped into
the process of creating this driver to iron out a few blocker bugs and ended
up also doing a lot of cleanup as David was busy. David should have time to
work on this again now, so if a v2 of the patch-set is needed, he will likely
post it.

Thanks & Regards,

Hans

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

* [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-14 21:58 ` Hans de Goede
@ 2013-12-14 21:58     ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: Chris Ball, Maxime Ripard
  Cc: David Lanzendörfer, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Hans de Goede

From: David Lanzendörfer <david.lanzendoerfer-Z7Kmv9EsliU@public.gmane.org>

This is based on the driver Allwinner ships in there Android kernel sources.

Initial porting to upstream kernels done by David Lanzendörfer, additional
fixes and cleanups by Hans de Goede.

Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 drivers/mmc/host/Kconfig     |   8 +
 drivers/mmc/host/Makefile    |   2 +
 drivers/mmc/host/sunxi-mci.c | 908 +++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sunxi-mci.h | 246 ++++++++++++
 include/linux/clk/sunxi.h    |  22 ++
 5 files changed, 1186 insertions(+)
 create mode 100644 drivers/mmc/host/sunxi-mci.c
 create mode 100644 drivers/mmc/host/sunxi-mci.h
 create mode 100644 include/linux/clk/sunxi.h

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7fc5099..69a7171 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
 	help
 	  Say Y here to include driver code to support SD/MMC card interface
 	  of Realtek PCI-E card reader
+
+config MMC_SUNXI
+	tristate "Allwinner sunxi SD/MMC Host Controller support"
+	depends on ARCH_SUNXI
+	default y
+	help
+	  This selects support for the SD/MMC Host Controller on
+	  Allwinner sunxi SoCs.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index c41d0c3..f76f783 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -52,6 +52,8 @@ obj-$(CONFIG_MMC_WMT)		+= wmt-sdmmc.o
 
 obj-$(CONFIG_MMC_REALTEK_PCI)	+= rtsx_pci_sdmmc.o
 
+obj-$(CONFIG_MMC_SUNXI)		+= sunxi-mci.o
+
 obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
 obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
diff --git a/drivers/mmc/host/sunxi-mci.c b/drivers/mmc/host/sunxi-mci.c
new file mode 100644
index 0000000..e091ebb
--- /dev/null
+++ b/drivers/mmc/host/sunxi-mci.c
@@ -0,0 +1,908 @@
+/*
+ * Driver for sunxi SD/MMC host controllers
+ * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
+ * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh-jFKXxz0WcGyYHARAtoI1EgC/G2K4zDHf@public.gmane.org>
+ * (C) Copyright 2013-2013 O2S GmbH <www.o2s.ch>
+ * (C) Copyright 2013-2013 David Lanzendörfer <david.lanzendoerfer@o2s.ch>
+ * (C) Copyright 2013-2013 Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <linux/clk.h>
+#include <linux/clk-private.h>
+#include <linux/clk/sunxi.h>
+
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+
+#include "sunxi-mci.h"
+
+static void sunxi_mmc_init_host(struct mmc_host *mmc)
+{
+	u32 rval;
+	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
+
+	/* reset controller */
+	rval = mci_readl(smc_host, REG_GCTRL) | SDXC_HWReset;
+	mci_writel(smc_host, REG_GCTRL, rval);
+
+	mci_writel(smc_host, REG_FTRGL, 0x20070008);
+	mci_writel(smc_host, REG_TMOUT, 0xffffffff);
+	mci_writel(smc_host, REG_IMASK, smc_host->sdio_imask);
+	mci_writel(smc_host, REG_RINTR, 0xffffffff);
+	mci_writel(smc_host, REG_DBGC, 0xdeb);
+	mci_writel(smc_host, REG_FUNS, 0xceaa0000);
+	mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);
+	rval = mci_readl(smc_host, REG_GCTRL)|SDXC_INTEnb;
+	rval &= ~SDXC_AccessDoneDirect;
+	mci_writel(smc_host, REG_GCTRL, rval);
+}
+
+static void sunxi_mmc_exit_host(struct sunxi_mmc_host *smc_host)
+{
+	mci_writel(smc_host, REG_GCTRL, SDXC_HWReset);
+}
+
+/* /\* UHS-I Operation Modes */
+/*  * DS		25MHz	12.5MB/s	3.3V */
+/*  * HS		50MHz	25MB/s		3.3V */
+/*  * SDR12	25MHz	12.5MB/s	1.8V */
+/*  * SDR25	50MHz	25MB/s		1.8V */
+/*  * SDR50	100MHz	50MB/s		1.8V */
+/*  * SDR104	208MHz	104MB/s		1.8V */
+/*  * DDR50	50MHz	50MB/s		1.8V */
+/*  * MMC Operation Modes */
+/*  * DS		26MHz	26MB/s		3/1.8/1.2V */
+/*  * HS		52MHz	52MB/s		3/1.8/1.2V */
+/*  * HSDDR	52MHz	104MB/s		3/1.8/1.2V */
+/*  * HS200	200MHz	200MB/s		1.8/1.2V */
+/*  * */
+/*  * Spec. Timing */
+/*  * SD3.0 */
+/*  * Fcclk    Tcclk   Fsclk   Tsclk   Tis     Tih     odly  RTis     RTih */
+/*  * 400K     2.5us   24M     41ns    5ns     5ns     1     2209ns   41ns */
+/*  * 25M      40ns    600M    1.67ns  5ns     5ns     3     14.99ns  5.01ns */
+/*  * 50M      20ns    600M    1.67ns  6ns     2ns     3     14.99ns  5.01ns */
+/*  * 50MDDR   20ns    600M    1.67ns  6ns     0.8ns   2     6.67ns   3.33ns */
+/*  * 104M     9.6ns   600M    1.67ns  3ns     0.8ns   1     7.93ns   1.67ns */
+/*  * 208M     4.8ns   600M    1.67ns  1.4ns   0.8ns   1     3.33ns   1.67ns */
+
+/*  * 25M      40ns    300M    3.33ns  5ns     5ns     2     13.34ns   6.66ns */
+/*  * 50M      20ns    300M    3.33ns  6ns     2ns     2     13.34ns   6.66ns */
+/*  * 50MDDR   20ns    300M    3.33ns  6ns     0.8ns   1     6.67ns    3.33ns */
+/*  * 104M     9.6ns   300M    3.33ns  3ns     0.8ns   0     7.93ns    1.67ns */
+/*  * 208M     4.8ns   300M    3.33ns  1.4ns   0.8ns   0     3.13ns    1.67ns */
+
+/*  * eMMC4.5 */
+/*  * 400K     2.5us   24M     41ns    3ns     3ns     1     2209ns    41ns */
+/*  * 25M      40ns    600M    1.67ns  3ns     3ns     3     14.99ns   5.01ns */
+/*  * 50M      20ns    600M    1.67ns  3ns     3ns     3     14.99ns   5.01ns */
+/*  * 50MDDR   20ns    600M    1.67ns  2.5ns   2.5ns   2     6.67ns    3.33ns */
+/*  * 200M     5ns     600M    1.67ns  1.4ns   0.8ns   1     3.33ns    1.67ns */
+/*  *\/ */
+
+static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
+				    struct mmc_data *data)
+{
+	struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
+	struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma;
+	int i, max_len = (1 << host->idma_des_size_bits);
+
+	for (i = 0; i < data->sg_len; i++) {
+		pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN |
+				 SDXC_IDMAC_DES0_DIC;
+
+		if (data->sg[i].length == max_len)
+			pdes[i].buf_size = 0; /* 0 == max_len */
+		else
+			pdes[i].buf_size = data->sg[i].length;
+
+		pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]);
+		pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1];
+	}
+	pdes[0].config |= SDXC_IDMAC_DES0_FD;
+	pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD;
+
+	wmb(); /* Ensure idma_des hit main mem before we start the idmac */
+}
+
+static enum dma_data_direction sunxi_mmc_get_dma_dir(struct mmc_data *data)
+{
+	if (data->flags & MMC_DATA_WRITE)
+		return DMA_TO_DEVICE;
+	else
+		return DMA_FROM_DEVICE;
+}
+
+static int sunxi_mmc_prepare_dma(struct sunxi_mmc_host *smc_host,
+				 struct mmc_data *data)
+{
+	u32 dma_len;
+	u32 i;
+	u32 temp;
+	struct scatterlist *sg;
+
+	dma_len = dma_map_sg(mmc_dev(smc_host->mmc), data->sg, data->sg_len,
+			     sunxi_mmc_get_dma_dir(data));
+	if (dma_len == 0) {
+		dev_err(mmc_dev(smc_host->mmc), "dma_map_sg failed\n");
+		return -ENOMEM;
+	}
+
+	for_each_sg(data->sg, sg, data->sg_len, i) {
+		if (sg->offset & 3 || sg->length & 3) {
+			dev_err(mmc_dev(smc_host->mmc),
+				"unaligned scatterlist: os %x length %d\n",
+				sg->offset, sg->length);
+			return -EINVAL;
+		}
+	}
+
+	sunxi_mmc_init_idma_des(smc_host, data);
+
+	temp = mci_readl(smc_host, REG_GCTRL);
+	temp |= SDXC_DMAEnb;
+	mci_writel(smc_host, REG_GCTRL, temp);
+	temp |= SDXC_DMAReset;
+	mci_writel(smc_host, REG_GCTRL, temp);
+
+	mci_writel(smc_host, REG_DMAC, SDXC_IDMACSoftRST);
+
+	if (!(data->flags & MMC_DATA_WRITE))
+		mci_writel(smc_host, REG_IDIE, SDXC_IDMACReceiveInt);
+
+	mci_writel(smc_host, REG_DMAC, SDXC_IDMACFixBurst | SDXC_IDMACIDMAOn);
+
+	return 0;
+}
+
+static void sunxi_mmc_send_manual_stop(struct sunxi_mmc_host *host,
+				       struct mmc_request *req)
+{
+	u32 cmd_val = SDXC_Start | SDXC_RspExp | SDXC_StopAbortCMD
+			| SDXC_CheckRspCRC | MMC_STOP_TRANSMISSION;
+	u32 ri = 0;
+	unsigned long expire = jiffies + msecs_to_jiffies(1000);
+
+	mci_writel(host, REG_CARG, 0);
+	mci_writel(host, REG_CMDR, cmd_val);
+	do {
+		ri = mci_readl(host, REG_RINTR);
+	} while (!(ri & (SDXC_CmdDone | SDXC_IntErrBit)) &&
+		 time_before(jiffies, expire));
+
+	if (ri & SDXC_IntErrBit) {
+		dev_err(mmc_dev(host->mmc), "send stop command failed\n");
+		if (req->stop)
+			req->stop->resp[0] = -ETIMEDOUT;
+	} else {
+		if (req->stop)
+			req->stop->resp[0] = mci_readl(host, REG_RESP0);
+	}
+
+	mci_writel(host, REG_RINTR, 0xffff);
+}
+
+static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *smc_host)
+{
+	struct mmc_command *cmd = smc_host->mrq->cmd;
+	struct mmc_data *data = smc_host->mrq->data;
+
+	/* For some cmds timeout is normal with sd/mmc cards */
+	if ((smc_host->int_sum & SDXC_IntErrBit) == SDXC_RespTimeout &&
+			(cmd->opcode == 5 || cmd->opcode == 52))
+		return;
+
+	dev_err(mmc_dev(smc_host->mmc),
+		"smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
+		smc_host->mmc->index, cmd->opcode,
+		data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
+		smc_host->int_sum & SDXC_RespErr     ? " RE"     : "",
+		smc_host->int_sum & SDXC_RespCRCErr  ? " RCE"    : "",
+		smc_host->int_sum & SDXC_DataCRCErr  ? " DCE"    : "",
+		smc_host->int_sum & SDXC_RespTimeout ? " RTO"    : "",
+		smc_host->int_sum & SDXC_DataTimeout ? " DTO"    : "",
+		smc_host->int_sum & SDXC_FIFORunErr  ? " FE"     : "",
+		smc_host->int_sum & SDXC_HardWLocked ? " HL"     : "",
+		smc_host->int_sum & SDXC_StartBitErr ? " SBE"    : "",
+		smc_host->int_sum & SDXC_EndBitErr   ? " EBE"    : ""
+		);
+}
+
+static void sunxi_mmc_finalize_request(struct sunxi_mmc_host *host)
+{
+	struct mmc_request *mrq;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&host->lock, iflags);
+
+	mrq = host->mrq;
+	if (!mrq) {
+		spin_unlock_irqrestore(&host->lock, iflags);
+		dev_err(mmc_dev(host->mmc), "no request to finalize\n");
+		return;
+	}
+
+	if (host->int_sum & SDXC_IntErrBit) {
+		sunxi_mmc_dump_errinfo(host);
+		mrq->cmd->error = -ETIMEDOUT;
+		if (mrq->data)
+			mrq->data->error = -ETIMEDOUT;
+		if (mrq->stop)
+			mrq->stop->error = -ETIMEDOUT;
+	} else {
+		if (mrq->cmd->flags & MMC_RSP_136) {
+			mrq->cmd->resp[0] = mci_readl(host, REG_RESP3);
+			mrq->cmd->resp[1] = mci_readl(host, REG_RESP2);
+			mrq->cmd->resp[2] = mci_readl(host, REG_RESP1);
+			mrq->cmd->resp[3] = mci_readl(host, REG_RESP0);
+		} else {
+			mrq->cmd->resp[0] = mci_readl(host, REG_RESP0);
+		}
+		if (mrq->data)
+			mrq->data->bytes_xfered =
+				mrq->data->blocks * mrq->data->blksz;
+	}
+
+	if (mrq->data) {
+		struct mmc_data *data = mrq->data;
+		u32 temp;
+
+		mci_writel(host, REG_IDST, 0x337);
+		mci_writel(host, REG_DMAC, 0);
+		temp = mci_readl(host, REG_GCTRL);
+		mci_writel(host, REG_GCTRL, temp|SDXC_DMAReset);
+		temp &= ~SDXC_DMAEnb;
+		mci_writel(host, REG_GCTRL, temp);
+		temp |= SDXC_FIFOReset;
+		mci_writel(host, REG_GCTRL, temp);
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+				     sunxi_mmc_get_dma_dir(data));
+	}
+
+	mci_writel(host, REG_RINTR, 0xffff);
+
+	dev_dbg(mmc_dev(host->mmc), "req done, resp %08x %08x %08x %08x\n",
+		mrq->cmd->resp[0], mrq->cmd->resp[1],
+		mrq->cmd->resp[2], mrq->cmd->resp[3]);
+
+	host->mrq = NULL;
+	host->int_sum = 0;
+	host->wait_dma = 0;
+
+	spin_unlock_irqrestore(&host->lock, iflags);
+
+	if (mrq->data && mrq->data->error) {
+		dev_err(mmc_dev(host->mmc),
+			"data error, sending stop command\n");
+		sunxi_mmc_send_manual_stop(host, mrq);
+	}
+
+	mmc_request_done(host->mmc, mrq);
+}
+
+static s32 sunxi_mmc_get_ro(struct mmc_host *mmc)
+{
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+
+	int read_only = 0;
+
+	if (gpio_is_valid(host->wp_pin)) {
+		pinctrl_request_gpio(host->wp_pin);
+		read_only = gpio_get_value(host->wp_pin);
+	}
+
+	return read_only;
+}
+
+static irqreturn_t sunxi_mmc_irq(int irq, void *dev_id)
+{
+	struct sunxi_mmc_host *host = dev_id;
+	u32 finalize = 0;
+	u32 sdio_int = 0;
+	u32 msk_int;
+	u32 idma_int;
+
+	spin_lock(&host->lock);
+
+	idma_int  = mci_readl(host, REG_IDST);
+	msk_int   = mci_readl(host, REG_MISTA);
+
+	dev_dbg(mmc_dev(host->mmc), "irq: rq %p mi %08x idi %08x\n",
+		host->mrq, msk_int, idma_int);
+
+	if (host->mrq) {
+		if (idma_int & SDXC_IDMACReceiveInt)
+			host->wait_dma = 0;
+
+		host->int_sum |= msk_int;
+
+		/* Wait for CmdDone on RespTimeout before finishing the req */
+		if ((host->int_sum & SDXC_RespTimeout) &&
+				!(host->int_sum & SDXC_CmdDone))
+			mci_writel(host, REG_IMASK,
+				   host->sdio_imask | SDXC_CmdDone);
+		else if (host->int_sum & SDXC_IntErrBit)
+			finalize = 1; /* Don't wait for dma on error */
+		else if (host->int_sum & SDXC_IntDoneBit && !host->wait_dma)
+			finalize = 1; /* Done */
+
+		if (finalize) {
+			mci_writel(host, REG_IMASK, host->sdio_imask);
+			mci_writel(host, REG_IDIE, 0);
+		}
+	}
+
+	if (msk_int & SDXC_SDIOInt)
+		sdio_int = 1;
+
+	mci_writel(host, REG_RINTR, msk_int);
+	mci_writel(host, REG_IDST, idma_int);
+
+	spin_unlock(&host->lock);
+
+	if (finalize)
+		tasklet_schedule(&host->tasklet);
+
+	if (sdio_int)
+		mmc_signal_sdio_irq(host->mmc);
+
+	return IRQ_HANDLED;
+}
+
+static void sunxi_mmc_tasklet(unsigned long data)
+{
+	struct sunxi_mmc_host *smc_host = (struct sunxi_mmc_host *) data;
+	sunxi_mmc_finalize_request(smc_host);
+}
+
+static void sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
+{
+	unsigned long expire = jiffies + msecs_to_jiffies(2000);
+	u32 rval;
+
+	rval = mci_readl(host, REG_CLKCR);
+	rval &= ~(SDXC_CardClkOn | SDXC_LowPowerOn);
+	if (oclk_en)
+		rval |= SDXC_CardClkOn;
+	if (!host->io_flag)
+		rval |= SDXC_LowPowerOn;
+	mci_writel(host, REG_CLKCR, rval);
+
+	rval = SDXC_Start | SDXC_UPCLKOnly | SDXC_WaitPreOver;
+	if (host->voltage_switching)
+		rval |= SDXC_VolSwitch;
+	mci_writel(host, REG_CMDR, rval);
+	do {
+		rval = mci_readl(host, REG_CMDR);
+	} while (time_before(jiffies, expire) && (rval & SDXC_Start));
+
+	if (rval & SDXC_Start) {
+		dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n");
+		host->ferror = 1;
+	}
+}
+
+static void sunxi_mmc_set_clk_dly(struct sunxi_mmc_host *smc_host,
+				  u32 oclk_dly, u32 sclk_dly)
+{
+	unsigned long iflags;
+	struct clk_hw *hw = __clk_get_hw(smc_host->clk_mod);
+
+	spin_lock_irqsave(&smc_host->lock, iflags);
+	clk_sunxi_mmc_phase_control(hw, sclk_dly, oclk_dly);
+	spin_unlock_irqrestore(&smc_host->lock, iflags);
+}
+
+struct sunxi_mmc_clk_dly mmc_clk_dly[MMC_CLK_MOD_NUM] = {
+	{ MMC_CLK_400K, 0, 7 },
+	{ MMC_CLK_25M, 0, 5 },
+	{ MMC_CLK_50M, 3, 5 },
+	{ MMC_CLK_50MDDR, 2, 4 },
+	{ MMC_CLK_50MDDR_8BIT, 2, 4 },
+	{ MMC_CLK_100M, 1, 4 },
+	{ MMC_CLK_200M, 1, 4 },
+};
+
+static void sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *smc_host,
+				   unsigned int rate)
+{
+	u32 newrate;
+	u32 src_clk;
+	u32 oclk_dly;
+	u32 sclk_dly;
+	u32 temp;
+	struct sunxi_mmc_clk_dly *dly = NULL;
+
+	newrate = clk_round_rate(smc_host->clk_mod, rate);
+	if (smc_host->clk_mod_rate == newrate) {
+		dev_dbg(mmc_dev(smc_host->mmc), "clk already %d, rounded %d\n",
+			rate, newrate);
+		return;
+	}
+
+	dev_dbg(mmc_dev(smc_host->mmc), "setting clk to %d, rounded %d\n",
+		rate, newrate);
+
+	/* setting clock rate */
+	clk_disable(smc_host->clk_mod);
+	clk_set_rate(smc_host->clk_mod, newrate);
+	clk_enable(smc_host->clk_mod);
+	smc_host->clk_mod_rate = newrate = clk_get_rate(smc_host->clk_mod);
+	dev_dbg(mmc_dev(smc_host->mmc), "clk is now %d\n", newrate);
+
+	sunxi_mmc_oclk_onoff(smc_host, 0);
+	/* clear internal divider */
+	temp = mci_readl(smc_host, REG_CLKCR);
+	temp &= ~0xff;
+	mci_writel(smc_host, REG_CLKCR, temp);
+
+	/* determine delays */
+	if (rate <= 400000) {
+		dly = &mmc_clk_dly[MMC_CLK_400K];
+	} else if (rate <= 25000000) {
+		dly = &mmc_clk_dly[MMC_CLK_25M];
+	} else if (rate <= 50000000) {
+		if (smc_host->ddr) {
+			if (smc_host->bus_width == 8)
+				dly = &mmc_clk_dly[MMC_CLK_50MDDR_8BIT];
+			else
+				dly = &mmc_clk_dly[MMC_CLK_50MDDR];
+		} else {
+			dly = &mmc_clk_dly[MMC_CLK_50M];
+		}
+	} else if (rate <= 104000000) {
+		dly = &mmc_clk_dly[MMC_CLK_100M];
+	} else if (rate <= 208000000) {
+		dly = &mmc_clk_dly[MMC_CLK_200M];
+	} else
+		dly = &mmc_clk_dly[MMC_CLK_50M];
+
+	oclk_dly = dly->oclk_dly;
+	sclk_dly = dly->sclk_dly;
+
+	src_clk = clk_get_rate(clk_get_parent(smc_host->clk_mod));
+	if (src_clk >= 300000000 && src_clk <= 400000000) {
+		if (oclk_dly)
+			oclk_dly--;
+		if (sclk_dly)
+			sclk_dly--;
+	}
+
+	sunxi_mmc_set_clk_dly(smc_host, oclk_dly, sclk_dly);
+	sunxi_mmc_oclk_onoff(smc_host, 1);
+
+	/* oclk_onoff sets various irq status bits, clear these */
+	mci_writel(smc_host, REG_RINTR,
+		   mci_readl(smc_host, REG_RINTR) & ~SDXC_SDIOInt);
+}
+
+static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+	u32 temp;
+	s32 err;
+
+	/* Set the power state */
+	switch (ios->power_mode) {
+	case MMC_POWER_ON:
+		break;
+
+	case MMC_POWER_UP:
+		if (!IS_ERR(host->vmmc)) {
+			mmc_regulator_set_ocr(host->mmc, host->vmmc, ios->vdd);
+			udelay(200);
+		}
+
+		err =  clk_prepare_enable(host->clk_ahb);
+		if (err) {
+			dev_err(mmc_dev(host->mmc), "AHB clk err %d\n", err);
+			host->ferror = 1;
+			return;
+		}
+		err =  clk_prepare_enable(host->clk_mod);
+		if (err) {
+			dev_err(mmc_dev(host->mmc), "MOD clk err %d\n", err);
+			host->ferror = 1;
+			return;
+		}
+
+		sunxi_mmc_init_host(mmc);
+		enable_irq(host->irq);
+
+		dev_dbg(mmc_dev(host->mmc), "power on!\n");
+		host->ferror = 0;
+		break;
+
+	case MMC_POWER_OFF:
+		dev_dbg(mmc_dev(host->mmc), "power off!\n");
+		disable_irq(host->irq);
+		sunxi_mmc_exit_host(host);
+		clk_disable_unprepare(host->clk_ahb);
+		clk_disable_unprepare(host->clk_mod);
+		if (!IS_ERR(host->vmmc))
+			mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
+		host->ferror = 0;
+		break;
+	}
+
+	/* set bus width */
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_1:
+		mci_writel(host, REG_WIDTH, SDXC_WIDTH1);
+		host->bus_width = 1;
+		break;
+	case MMC_BUS_WIDTH_4:
+		mci_writel(host, REG_WIDTH, SDXC_WIDTH4);
+		host->bus_width = 4;
+		break;
+	case MMC_BUS_WIDTH_8:
+		mci_writel(host, REG_WIDTH, SDXC_WIDTH8);
+		host->bus_width = 8;
+		break;
+	}
+
+	/* set ddr mode */
+	temp = mci_readl(host, REG_GCTRL);
+	if (ios->timing == MMC_TIMING_UHS_DDR50) {
+		temp |= SDXC_DDR_MODE;
+		host->ddr = 1;
+	} else {
+		temp &= ~SDXC_DDR_MODE;
+		host->ddr = 0;
+	}
+	mci_writel(host, REG_GCTRL, temp);
+
+	/* set up clock */
+	if (ios->clock && ios->power_mode) {
+		dev_dbg(mmc_dev(host->mmc), "ios->clock: %d\n", ios->clock);
+		sunxi_mmc_clk_set_rate(host, ios->clock);
+		usleep_range(50000, 55000);
+	}
+}
+
+static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
+	unsigned long flags;
+	u32 imask;
+
+	spin_lock_irqsave(&smc_host->lock, flags);
+	imask = mci_readl(smc_host, REG_IMASK);
+	if (enable) {
+		smc_host->sdio_imask = SDXC_SDIOInt;
+		imask |= SDXC_SDIOInt;
+	} else {
+		smc_host->sdio_imask = 0;
+		imask &= ~SDXC_SDIOInt;
+	}
+	mci_writel(smc_host, REG_IMASK, imask);
+	spin_unlock_irqrestore(&smc_host->lock, flags);
+}
+
+static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
+{
+	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
+	mci_writel(smc_host, REG_HWRST, 0);
+	udelay(10);
+	mci_writel(smc_host, REG_HWRST, 1);
+	udelay(300);
+}
+
+static int sunxi_mmc_card_present(struct mmc_host *mmc)
+{
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+
+	switch (host->cd_mode) {
+	case CARD_DETECT_BY_GPIO_POLL:
+		return !gpio_get_value(host->cd_pin); /* Signal inverted */
+	case CARD_ALWAYS_PRESENT:
+		return 1;
+	}
+	return 0; /* Never reached */
+}
+
+static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+	struct mmc_command *cmd = mrq->cmd;
+	struct mmc_data *data = mrq->data;
+	unsigned long iflags;
+	u32 imask = SDXC_IntErrBit;
+	u32 cmd_val = SDXC_Start | (cmd->opcode & 0x3f);
+	u32 byte_cnt = 0;
+	int ret;
+
+	if (!sunxi_mmc_card_present(mmc) || host->ferror) {
+		dev_dbg(mmc_dev(host->mmc), "no medium present\n");
+		mrq->cmd->error = -ENOMEDIUM;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
+	if (data) {
+		byte_cnt = data->blksz * data->blocks;
+		mci_writel(host, REG_BLKSZ, data->blksz);
+		mci_writel(host, REG_BCNTR, byte_cnt);
+		ret = sunxi_mmc_prepare_dma(host, data);
+		if (ret < 0) {
+			dev_err(mmc_dev(host->mmc), "prepare DMA failed\n");
+			cmd->error = ret;
+			cmd->data->error = ret;
+			mmc_request_done(host->mmc, mrq);
+			return;
+		}
+	}
+
+	if (cmd->opcode == MMC_GO_IDLE_STATE) {
+		cmd_val |= SDXC_SendInitSeq;
+		imask |= SDXC_CmdDone;
+	}
+
+	if (cmd->opcode == SD_SWITCH_VOLTAGE) {
+		cmd_val |= SDXC_VolSwitch;
+		imask |= SDXC_VolChgDone;
+		host->voltage_switching = 1;
+		sunxi_mmc_oclk_onoff(host, 1);
+	}
+
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		cmd_val |= SDXC_RspExp;
+		if (cmd->flags & MMC_RSP_136)
+			cmd_val |= SDXC_LongRsp;
+		if (cmd->flags & MMC_RSP_CRC)
+			cmd_val |= SDXC_CheckRspCRC;
+
+		if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) {
+			cmd_val |= SDXC_DataExp | SDXC_WaitPreOver;
+			if (cmd->data->flags & MMC_DATA_STREAM) {
+				imask |= SDXC_AutoCMDDone;
+				cmd_val |= SDXC_Seqmod | SDXC_SendAutoStop;
+			}
+			if (cmd->data->stop) {
+				imask |= SDXC_AutoCMDDone;
+				cmd_val |= SDXC_SendAutoStop;
+			} else
+				imask |= SDXC_DataOver;
+
+			if (cmd->data->flags & MMC_DATA_WRITE)
+				cmd_val |= SDXC_Write;
+			else
+				host->wait_dma = 1;
+		} else
+			imask |= SDXC_CmdDone;
+	} else
+		imask |= SDXC_CmdDone;
+
+	dev_dbg(mmc_dev(host->mmc), "cmd %d(%08x) arg %x ie 0x%08x len %d\n",
+		cmd_val & 0x3f, cmd_val, cmd->arg, imask,
+		mrq->data ? mrq->data->blksz * mrq->data->blocks : 0);
+
+	spin_lock_irqsave(&host->lock, iflags);
+	host->mrq = mrq;
+	mci_writel(host, REG_IMASK, host->sdio_imask | imask);
+	spin_unlock_irqrestore(&host->lock, iflags);
+
+	mci_writel(host, REG_CARG, cmd->arg);
+	mci_writel(host, REG_CMDR, cmd_val);
+}
+
+static const struct of_device_id sunxi_mmc_of_match[] = {
+	{ .compatible = "allwinner,sun4i-mmc", },
+	{ .compatible = "allwinner,sun5i-mmc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
+
+static struct mmc_host_ops sunxi_mmc_ops = {
+	.request	 = sunxi_mmc_request,
+	.set_ios	 = sunxi_mmc_set_ios,
+	.get_ro		 = sunxi_mmc_get_ro,
+	.get_cd		 = sunxi_mmc_card_present,
+	.enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
+	.hw_reset	 = sunxi_mmc_hw_reset,
+};
+
+static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
+				      struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (of_device_is_compatible(np, "allwinner,sun4i-mmc"))
+		host->idma_des_size_bits = 13;
+	else
+		host->idma_des_size_bits = 16;
+
+	host->vmmc = devm_regulator_get_optional(&pdev->dev, "vmmc");
+	if (IS_ERR(host->vmmc) && PTR_ERR(host->vmmc) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	host->reg_base = devm_ioremap_resource(&pdev->dev,
+			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
+	if (IS_ERR(host->reg_base))
+		return PTR_ERR(host->reg_base);
+
+	host->irq = platform_get_irq(pdev, 0);
+	ret = devm_request_irq(&pdev->dev, host->irq, sunxi_mmc_irq, 0,
+			       "sunxi-mci", host);
+	if (ret)
+		return ret;
+	disable_irq(host->irq);
+
+	host->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(host->clk_ahb)) {
+		dev_err(&pdev->dev, "Could not get ahb clock\n");
+		return PTR_ERR(host->clk_ahb);
+	}
+
+	host->clk_mod = devm_clk_get(&pdev->dev, "mod");
+	if (IS_ERR(host->clk_mod)) {
+		dev_err(&pdev->dev, "Could not get mod clock\n");
+		return PTR_ERR(host->clk_mod);
+	}
+
+	of_property_read_u32(np, "bus-width", &host->bus_width);
+	if (host->bus_width != 1 && host->bus_width != 4) {
+		dev_err(&pdev->dev, "Invalid bus-width %d\n", host->bus_width);
+		return -EINVAL;
+	}
+
+	of_property_read_u32(np, "cd-mode", &host->cd_mode);
+	switch (host->cd_mode) {
+	case CARD_DETECT_BY_GPIO_POLL:
+		host->cd_pin = of_get_named_gpio(np, "cd-gpios", 0);
+		if (!gpio_is_valid(host->cd_pin)) {
+			dev_err(&pdev->dev, "Invalid cd-gpios\n");
+			return -EINVAL;
+		}
+		ret = devm_gpio_request(&pdev->dev, host->cd_pin, "mmc_cd");
+		if (ret) {
+			dev_err(&pdev->dev, "Could not get cd-gpios\n");
+			return ret;
+		}
+		gpio_direction_input(host->cd_pin);
+		break;
+	case CARD_ALWAYS_PRESENT:
+		break;
+	default:
+		dev_err(&pdev->dev, "Invalid cd-mode %d\n", host->cd_mode);
+		return -EINVAL;
+	}
+
+	host->wp_pin = of_get_named_gpio(np, "wp-gpios", 0);
+	if (gpio_is_valid(host->wp_pin)) {
+		ret = devm_gpio_request(&pdev->dev, host->wp_pin, "mmc_wp");
+		if (ret) {
+			dev_err(&pdev->dev, "Could not get wp-gpios\n");
+			return ret;
+		}
+		gpio_direction_input(host->wp_pin);
+	}
+
+	return 0;
+}
+
+static int sunxi_mmc_probe(struct platform_device *pdev)
+{
+	struct sunxi_mmc_host *host;
+	struct mmc_host *mmc;
+	int ret;
+
+	mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);
+	if (!mmc) {
+		dev_err(&pdev->dev, "mmc alloc host failed\n");
+		return -ENOMEM;
+	}
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	spin_lock_init(&host->lock);
+	tasklet_init(&host->tasklet, sunxi_mmc_tasklet, (unsigned long)host);
+
+	ret = sunxi_mmc_resource_request(host, pdev);
+	if (ret)
+		goto error_free_host;
+
+	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
+					  &host->sg_dma, GFP_KERNEL);
+	if (!host->sg_cpu) {
+		dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n");
+		ret = -ENOMEM;
+		goto error_free_host;
+	}
+
+	mmc->ops		= &sunxi_mmc_ops;
+	mmc->max_blk_count	= 8192;
+	mmc->max_blk_size	= 4096;
+	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
+	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
+	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
+	/* 400kHz ~ 50MHz */
+	mmc->f_min		=   400000;
+	mmc->f_max		= 50000000;
+	/* available voltages */
+	if (!IS_ERR(host->vmmc))
+		mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vmmc);
+	else
+		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+		MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
+		MMC_CAP_UHS_DDR50 | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL |
+		MMC_CAP_DRIVER_TYPE_A;
+	if (host->bus_width == 4)
+		mmc->caps |= MMC_CAP_4_BIT_DATA;
+	mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP;
+
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto error_free_dma;
+
+	dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq);
+	platform_set_drvdata(pdev, mmc);
+	return 0;
+
+error_free_dma:
+	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+error_free_host:
+	mmc_free_host(mmc);
+	return ret;
+}
+
+static int sunxi_mmc_remove(struct platform_device *pdev)
+{
+	struct mmc_host	*mmc = platform_get_drvdata(pdev);
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+
+	mmc_remove_host(mmc);
+	sunxi_mmc_exit_host(host);
+	tasklet_disable(&host->tasklet);
+	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+	mmc_free_host(mmc);
+
+	return 0;
+}
+
+static struct platform_driver sunxi_mmc_driver = {
+	.driver = {
+		.name	= "sunxi-mci",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(sunxi_mmc_of_match),
+	},
+	.probe		= sunxi_mmc_probe,
+	.remove		= sunxi_mmc_remove,
+};
+module_platform_driver(sunxi_mmc_driver);
+
+MODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Lanzendörfer <david.lanzendoerfer-Z7Kmv9EsliU@public.gmane.org>");
+MODULE_ALIAS("platform:sunxi-mmc");
diff --git a/drivers/mmc/host/sunxi-mci.h b/drivers/mmc/host/sunxi-mci.h
new file mode 100644
index 0000000..332d3ae
--- /dev/null
+++ b/drivers/mmc/host/sunxi-mci.h
@@ -0,0 +1,246 @@
+/*
+ * Driver for sunxi SD/MMC host controllers
+ * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
+ * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh-jFKXxz0WcGyYHARAtoI1EgC/G2K4zDHf@public.gmane.org>
+ * (C) Copyright 2013-2013 O2S GmbH <www.o2s.ch>
+ * (C) Copyright 2013-2013 David Lanzendörfer <david.lanzendoerfer@o2s.ch>
+ * (C) Copyright 2013-2013 Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef __SUNXI_MCI_H__
+#define __SUNXI_MCI_H__
+
+/* register offset define */
+#define SDXC_REG_GCTRL	(0x00) /* SMC Global Control Register */
+#define SDXC_REG_CLKCR	(0x04) /* SMC Clock Control Register */
+#define SDXC_REG_TMOUT	(0x08) /* SMC Time Out Register */
+#define SDXC_REG_WIDTH	(0x0C) /* SMC Bus Width Register */
+#define SDXC_REG_BLKSZ	(0x10) /* SMC Block Size Register */
+#define SDXC_REG_BCNTR	(0x14) /* SMC Byte Count Register */
+#define SDXC_REG_CMDR	(0x18) /* SMC Command Register */
+#define SDXC_REG_CARG	(0x1C) /* SMC Argument Register */
+#define SDXC_REG_RESP0	(0x20) /* SMC Response Register 0 */
+#define SDXC_REG_RESP1	(0x24) /* SMC Response Register 1 */
+#define SDXC_REG_RESP2	(0x28) /* SMC Response Register 2 */
+#define SDXC_REG_RESP3	(0x2C) /* SMC Response Register 3 */
+#define SDXC_REG_IMASK	(0x30) /* SMC Interrupt Mask Register */
+#define SDXC_REG_MISTA	(0x34) /* SMC Masked Interrupt Status Register */
+#define SDXC_REG_RINTR	(0x38) /* SMC Raw Interrupt Status Register */
+#define SDXC_REG_STAS	(0x3C) /* SMC Status Register */
+#define SDXC_REG_FTRGL	(0x40) /* SMC FIFO Threshold Watermark Registe */
+#define SDXC_REG_FUNS	(0x44) /* SMC Function Select Register */
+#define SDXC_REG_CBCR	(0x48) /* SMC CIU Byte Count Register */
+#define SDXC_REG_BBCR	(0x4C) /* SMC BIU Byte Count Register */
+#define SDXC_REG_DBGC	(0x50) /* SMC Debug Enable Register */
+#define SDXC_REG_HWRST	(0x78) /* SMC Card Hardware Reset for Register */
+#define SDXC_REG_DMAC	(0x80) /* SMC IDMAC Control Register */
+#define SDXC_REG_DLBA	(0x84) /* SMC IDMAC Descriptor List Base Addre */
+#define SDXC_REG_IDST	(0x88) /* SMC IDMAC Status Register */
+#define SDXC_REG_IDIE	(0x8C) /* SMC IDMAC Interrupt Enable Register */
+#define SDXC_REG_CHDA	(0x90)
+#define SDXC_REG_CBDA	(0x94)
+
+#define mci_readl(host, reg) \
+	__raw_readl((host)->reg_base + SDXC_##reg)
+#define mci_writel(host, reg, value) \
+	__raw_writel((value), (host)->reg_base + SDXC_##reg)
+
+/* global control register bits */
+#define SDXC_SoftReset		BIT(0)
+#define SDXC_FIFOReset		BIT(1)
+#define SDXC_DMAReset		BIT(2)
+#define SDXC_HWReset		(SDXC_SoftReset|SDXC_FIFOReset|SDXC_DMAReset)
+#define SDXC_INTEnb		BIT(4)
+#define SDXC_DMAEnb		BIT(5)
+#define SDXC_DebounceEnb	BIT(8)
+#define SDXC_PosedgeLatchData	BIT(9)
+#define SDXC_DDR_MODE		BIT(10)
+#define SDXC_MemAccessDone	BIT(29)
+#define SDXC_AccessDoneDirect	BIT(30)
+#define SDXC_ACCESS_BY_AHB	BIT(31)
+#define SDXC_ACCESS_BY_DMA	(0U << 31)
+/* clock control bits */
+#define SDXC_CardClkOn		BIT(16)
+#define SDXC_LowPowerOn		BIT(17)
+/* bus width */
+#define SDXC_WIDTH1		(0)
+#define SDXC_WIDTH4		(1)
+#define SDXC_WIDTH8		(2)
+/* smc command bits */
+#define SDXC_RspExp		BIT(6)
+#define SDXC_LongRsp		BIT(7)
+#define SDXC_CheckRspCRC	BIT(8)
+#define SDXC_DataExp		BIT(9)
+#define SDXC_Write		BIT(10)
+#define SDXC_Seqmod		BIT(11)
+#define SDXC_SendAutoStop	BIT(12)
+#define SDXC_WaitPreOver	BIT(13)
+#define SDXC_StopAbortCMD	BIT(14)
+#define SDXC_SendInitSeq	BIT(15)
+#define SDXC_UPCLKOnly		BIT(21)
+#define SDXC_RdCEATADev		BIT(22)
+#define SDXC_CCSExp		BIT(23)
+#define SDXC_EnbBoot		BIT(24)
+#define SDXC_AltBootOpt		BIT(25)
+#define SDXC_BootACKExp		BIT(26)
+#define SDXC_BootAbort		BIT(27)
+#define SDXC_VolSwitch	        BIT(28)
+#define SDXC_UseHoldReg	        BIT(29)
+#define SDXC_Start	        BIT(31)
+/* interrupt bits */
+#define SDXC_RespErr		BIT(1)
+#define SDXC_CmdDone		BIT(2)
+#define SDXC_DataOver		BIT(3)
+#define SDXC_TxDataReq		BIT(4)
+#define SDXC_RxDataReq		BIT(5)
+#define SDXC_RespCRCErr		BIT(6)
+#define SDXC_DataCRCErr		BIT(7)
+#define SDXC_RespTimeout	BIT(8)
+#define SDXC_DataTimeout	BIT(9)
+#define SDXC_VolChgDone		BIT(10)
+#define SDXC_FIFORunErr		BIT(11)
+#define SDXC_HardWLocked	BIT(12)
+#define SDXC_StartBitErr	BIT(13)
+#define SDXC_AutoCMDDone	BIT(14)
+#define SDXC_EndBitErr		BIT(15)
+#define SDXC_SDIOInt		BIT(16)
+#define SDXC_CardInsert		BIT(30)
+#define SDXC_CardRemove		BIT(31)
+#define SDXC_IntErrBit		(SDXC_RespErr | SDXC_RespCRCErr | \
+				 SDXC_DataCRCErr | SDXC_RespTimeout | \
+				 SDXC_DataTimeout | SDXC_FIFORunErr | \
+				 SDXC_HardWLocked | SDXC_StartBitErr | \
+				 SDXC_EndBitErr) /* 0xbbc2 */
+#define SDXC_IntDoneBit		(SDXC_AutoCMDDone | SDXC_DataOver | \
+				 SDXC_CmdDone | SDXC_VolChgDone)
+/* status */
+#define SDXC_RXWLFlag		BIT(0)
+#define SDXC_TXWLFlag		BIT(1)
+#define SDXC_FIFOEmpty		BIT(2)
+#define SDXC_FIFOFull		BIT(3)
+#define SDXC_CardPresent	BIT(8)
+#define SDXC_CardDataBusy	BIT(9)
+#define SDXC_DataFSMBusy	BIT(10)
+#define SDXC_DMAReq		BIT(31)
+#define SDXC_FIFO_SIZE		(16)
+/* Function select */
+#define SDXC_CEATAOn		(0xceaaU << 16)
+#define SDXC_SendIrqRsp		BIT(0)
+#define SDXC_SDIORdWait		BIT(1)
+#define SDXC_AbtRdData		BIT(2)
+#define SDXC_SendCCSD		BIT(8)
+#define SDXC_SendAutoStopCCSD	BIT(9)
+#define SDXC_CEATADevIntEnb	BIT(10)
+/* IDMA controller bus mod bit field */
+#define SDXC_IDMACSoftRST	BIT(0)
+#define SDXC_IDMACFixBurst	BIT(1)
+#define SDXC_IDMACIDMAOn	BIT(7)
+#define SDXC_IDMACRefetchDES	BIT(31)
+/* IDMA status bit field */
+#define SDXC_IDMACTransmitInt	BIT(0)
+#define SDXC_IDMACReceiveInt	BIT(1)
+#define SDXC_IDMACFatalBusErr	BIT(2)
+#define SDXC_IDMACDesInvalid	BIT(4)
+#define SDXC_IDMACCardErrSum	BIT(5)
+#define SDXC_IDMACNormalIntSum	BIT(8)
+#define SDXC_IDMACAbnormalIntSum BIT(9)
+#define SDXC_IDMACHostAbtInTx	BIT(10)
+#define SDXC_IDMACHostAbtInRx	BIT(10)
+#define SDXC_IDMACIdle		(0U << 13)
+#define SDXC_IDMACSuspend	(1U << 13)
+#define SDXC_IDMACDESCRd	(2U << 13)
+#define SDXC_IDMACDESCCheck	(3U << 13)
+#define SDXC_IDMACRdReqWait	(4U << 13)
+#define SDXC_IDMACWrReqWait	(5U << 13)
+#define SDXC_IDMACRd		(6U << 13)
+#define SDXC_IDMACWr		(7U << 13)
+#define SDXC_IDMACDESCClose	(8U << 13)
+
+struct sunxi_idma_des {
+	u32	config;
+#define SDXC_IDMAC_DES0_DIC	BIT(1)  /* disable interrupt on completion */
+#define SDXC_IDMAC_DES0_LD	BIT(2)  /* last descriptor */
+#define SDXC_IDMAC_DES0_FD	BIT(3)  /* first descriptor */
+#define SDXC_IDMAC_DES0_CH	BIT(4)  /* chain mode */
+#define SDXC_IDMAC_DES0_ER	BIT(5)  /* end of ring */
+#define SDXC_IDMAC_DES0_CES	BIT(30) /* card error summary */
+#define SDXC_IDMAC_DES0_OWN	BIT(31) /* 1-idma owns it, 0-host owns it */
+
+	/*
+	 * If the idma-des-size-bits of property is ie 13, bufsize bits are:
+	 *  Bits  0-12: buf1 size
+	 *  Bits 13-25: buf2 size
+	 *  Bits 26-31: not used
+	 * Since we only ever set buf1 size, we can simply store it directly.
+	 */
+	u32	buf_size;
+	u32	buf_addr_ptr1;
+	u32	buf_addr_ptr2;
+};
+
+struct sunxi_mmc_host {
+	struct mmc_host *mmc;
+	struct regulator *vmmc;
+
+	/* IO mapping base */
+	void __iomem *reg_base;
+
+	spinlock_t lock;
+	struct tasklet_struct tasklet;
+
+	/* clock management */
+	struct clk *clk_ahb;
+	struct clk *clk_mod;
+
+	/* indicator pins */
+	int wp_pin;
+	int cd_pin;
+	int cd_mode;
+#define CARD_DETECT_BY_GPIO_POLL (1)	/* mmc detected by gpio check */
+#define CARD_ALWAYS_PRESENT      (2)	/* mmc always present */
+
+	/* ios information */
+	u32		clk_mod_rate;
+	u32		bus_width;
+	u32		idma_des_size_bits;
+	u32		ddr;
+	u32		voltage_switching;
+
+	/* irq */
+	int		irq;
+	u32		int_sum;
+	u32		sdio_imask;
+
+	/* flags */
+	u32		power_on:1;
+	u32		io_flag:1;
+	u32		wait_dma:1;
+
+	dma_addr_t	sg_dma;
+	void		*sg_cpu;
+
+	struct mmc_request *mrq;
+	u32		ferror;
+};
+
+#define MMC_CLK_400K            0
+#define MMC_CLK_25M             1
+#define MMC_CLK_50M             2
+#define MMC_CLK_50MDDR          3
+#define MMC_CLK_50MDDR_8BIT     4
+#define MMC_CLK_100M            5
+#define MMC_CLK_200M            6
+#define MMC_CLK_MOD_NUM         7
+
+struct sunxi_mmc_clk_dly {
+	u32 mode;
+	u32 oclk_dly;
+	u32 sclk_dly;
+};
+
+#endif
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
new file mode 100644
index 0000000..1ef5c89
--- /dev/null
+++ b/include/linux/clk/sunxi.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013 - Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_CLK_SUNXI_H_
+#define __LINUX_CLK_SUNXI_H_
+
+#include <linux/clk.h>
+
+void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
+
+#endif
-- 
1.8.4.2

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/groups/opt_out.

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

* [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-14 21:58     ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: linux-arm-kernel

From: David Lanzend??rfer <david.lanzendoerfer@o2s.ch>

This is based on the driver Allwinner ships in there Android kernel sources.

Initial porting to upstream kernels done by David Lanzend??rfer, additional
fixes and cleanups by Hans de Goede.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/mmc/host/Kconfig     |   8 +
 drivers/mmc/host/Makefile    |   2 +
 drivers/mmc/host/sunxi-mci.c | 908 +++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sunxi-mci.h | 246 ++++++++++++
 include/linux/clk/sunxi.h    |  22 ++
 5 files changed, 1186 insertions(+)
 create mode 100644 drivers/mmc/host/sunxi-mci.c
 create mode 100644 drivers/mmc/host/sunxi-mci.h
 create mode 100644 include/linux/clk/sunxi.h

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7fc5099..69a7171 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
 	help
 	  Say Y here to include driver code to support SD/MMC card interface
 	  of Realtek PCI-E card reader
+
+config MMC_SUNXI
+	tristate "Allwinner sunxi SD/MMC Host Controller support"
+	depends on ARCH_SUNXI
+	default y
+	help
+	  This selects support for the SD/MMC Host Controller on
+	  Allwinner sunxi SoCs.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index c41d0c3..f76f783 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -52,6 +52,8 @@ obj-$(CONFIG_MMC_WMT)		+= wmt-sdmmc.o
 
 obj-$(CONFIG_MMC_REALTEK_PCI)	+= rtsx_pci_sdmmc.o
 
+obj-$(CONFIG_MMC_SUNXI)		+= sunxi-mci.o
+
 obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
 obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
diff --git a/drivers/mmc/host/sunxi-mci.c b/drivers/mmc/host/sunxi-mci.c
new file mode 100644
index 0000000..e091ebb
--- /dev/null
+++ b/drivers/mmc/host/sunxi-mci.c
@@ -0,0 +1,908 @@
+/*
+ * Driver for sunxi SD/MMC host controllers
+ * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
+ * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com>
+ * (C) Copyright 2013-2013 O2S GmbH <www.o2s.ch>
+ * (C) Copyright 2013-2013 David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
+ * (C) Copyright 2013-2013 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <linux/clk.h>
+#include <linux/clk-private.h>
+#include <linux/clk/sunxi.h>
+
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+
+#include "sunxi-mci.h"
+
+static void sunxi_mmc_init_host(struct mmc_host *mmc)
+{
+	u32 rval;
+	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
+
+	/* reset controller */
+	rval = mci_readl(smc_host, REG_GCTRL) | SDXC_HWReset;
+	mci_writel(smc_host, REG_GCTRL, rval);
+
+	mci_writel(smc_host, REG_FTRGL, 0x20070008);
+	mci_writel(smc_host, REG_TMOUT, 0xffffffff);
+	mci_writel(smc_host, REG_IMASK, smc_host->sdio_imask);
+	mci_writel(smc_host, REG_RINTR, 0xffffffff);
+	mci_writel(smc_host, REG_DBGC, 0xdeb);
+	mci_writel(smc_host, REG_FUNS, 0xceaa0000);
+	mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);
+	rval = mci_readl(smc_host, REG_GCTRL)|SDXC_INTEnb;
+	rval &= ~SDXC_AccessDoneDirect;
+	mci_writel(smc_host, REG_GCTRL, rval);
+}
+
+static void sunxi_mmc_exit_host(struct sunxi_mmc_host *smc_host)
+{
+	mci_writel(smc_host, REG_GCTRL, SDXC_HWReset);
+}
+
+/* /\* UHS-I Operation Modes */
+/*  * DS		25MHz	12.5MB/s	3.3V */
+/*  * HS		50MHz	25MB/s		3.3V */
+/*  * SDR12	25MHz	12.5MB/s	1.8V */
+/*  * SDR25	50MHz	25MB/s		1.8V */
+/*  * SDR50	100MHz	50MB/s		1.8V */
+/*  * SDR104	208MHz	104MB/s		1.8V */
+/*  * DDR50	50MHz	50MB/s		1.8V */
+/*  * MMC Operation Modes */
+/*  * DS		26MHz	26MB/s		3/1.8/1.2V */
+/*  * HS		52MHz	52MB/s		3/1.8/1.2V */
+/*  * HSDDR	52MHz	104MB/s		3/1.8/1.2V */
+/*  * HS200	200MHz	200MB/s		1.8/1.2V */
+/*  * */
+/*  * Spec. Timing */
+/*  * SD3.0 */
+/*  * Fcclk    Tcclk   Fsclk   Tsclk   Tis     Tih     odly  RTis     RTih */
+/*  * 400K     2.5us   24M     41ns    5ns     5ns     1     2209ns   41ns */
+/*  * 25M      40ns    600M    1.67ns  5ns     5ns     3     14.99ns  5.01ns */
+/*  * 50M      20ns    600M    1.67ns  6ns     2ns     3     14.99ns  5.01ns */
+/*  * 50MDDR   20ns    600M    1.67ns  6ns     0.8ns   2     6.67ns   3.33ns */
+/*  * 104M     9.6ns   600M    1.67ns  3ns     0.8ns   1     7.93ns   1.67ns */
+/*  * 208M     4.8ns   600M    1.67ns  1.4ns   0.8ns   1     3.33ns   1.67ns */
+
+/*  * 25M      40ns    300M    3.33ns  5ns     5ns     2     13.34ns   6.66ns */
+/*  * 50M      20ns    300M    3.33ns  6ns     2ns     2     13.34ns   6.66ns */
+/*  * 50MDDR   20ns    300M    3.33ns  6ns     0.8ns   1     6.67ns    3.33ns */
+/*  * 104M     9.6ns   300M    3.33ns  3ns     0.8ns   0     7.93ns    1.67ns */
+/*  * 208M     4.8ns   300M    3.33ns  1.4ns   0.8ns   0     3.13ns    1.67ns */
+
+/*  * eMMC4.5 */
+/*  * 400K     2.5us   24M     41ns    3ns     3ns     1     2209ns    41ns */
+/*  * 25M      40ns    600M    1.67ns  3ns     3ns     3     14.99ns   5.01ns */
+/*  * 50M      20ns    600M    1.67ns  3ns     3ns     3     14.99ns   5.01ns */
+/*  * 50MDDR   20ns    600M    1.67ns  2.5ns   2.5ns   2     6.67ns    3.33ns */
+/*  * 200M     5ns     600M    1.67ns  1.4ns   0.8ns   1     3.33ns    1.67ns */
+/*  *\/ */
+
+static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
+				    struct mmc_data *data)
+{
+	struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
+	struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma;
+	int i, max_len = (1 << host->idma_des_size_bits);
+
+	for (i = 0; i < data->sg_len; i++) {
+		pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN |
+				 SDXC_IDMAC_DES0_DIC;
+
+		if (data->sg[i].length == max_len)
+			pdes[i].buf_size = 0; /* 0 == max_len */
+		else
+			pdes[i].buf_size = data->sg[i].length;
+
+		pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]);
+		pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1];
+	}
+	pdes[0].config |= SDXC_IDMAC_DES0_FD;
+	pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD;
+
+	wmb(); /* Ensure idma_des hit main mem before we start the idmac */
+}
+
+static enum dma_data_direction sunxi_mmc_get_dma_dir(struct mmc_data *data)
+{
+	if (data->flags & MMC_DATA_WRITE)
+		return DMA_TO_DEVICE;
+	else
+		return DMA_FROM_DEVICE;
+}
+
+static int sunxi_mmc_prepare_dma(struct sunxi_mmc_host *smc_host,
+				 struct mmc_data *data)
+{
+	u32 dma_len;
+	u32 i;
+	u32 temp;
+	struct scatterlist *sg;
+
+	dma_len = dma_map_sg(mmc_dev(smc_host->mmc), data->sg, data->sg_len,
+			     sunxi_mmc_get_dma_dir(data));
+	if (dma_len == 0) {
+		dev_err(mmc_dev(smc_host->mmc), "dma_map_sg failed\n");
+		return -ENOMEM;
+	}
+
+	for_each_sg(data->sg, sg, data->sg_len, i) {
+		if (sg->offset & 3 || sg->length & 3) {
+			dev_err(mmc_dev(smc_host->mmc),
+				"unaligned scatterlist: os %x length %d\n",
+				sg->offset, sg->length);
+			return -EINVAL;
+		}
+	}
+
+	sunxi_mmc_init_idma_des(smc_host, data);
+
+	temp = mci_readl(smc_host, REG_GCTRL);
+	temp |= SDXC_DMAEnb;
+	mci_writel(smc_host, REG_GCTRL, temp);
+	temp |= SDXC_DMAReset;
+	mci_writel(smc_host, REG_GCTRL, temp);
+
+	mci_writel(smc_host, REG_DMAC, SDXC_IDMACSoftRST);
+
+	if (!(data->flags & MMC_DATA_WRITE))
+		mci_writel(smc_host, REG_IDIE, SDXC_IDMACReceiveInt);
+
+	mci_writel(smc_host, REG_DMAC, SDXC_IDMACFixBurst | SDXC_IDMACIDMAOn);
+
+	return 0;
+}
+
+static void sunxi_mmc_send_manual_stop(struct sunxi_mmc_host *host,
+				       struct mmc_request *req)
+{
+	u32 cmd_val = SDXC_Start | SDXC_RspExp | SDXC_StopAbortCMD
+			| SDXC_CheckRspCRC | MMC_STOP_TRANSMISSION;
+	u32 ri = 0;
+	unsigned long expire = jiffies + msecs_to_jiffies(1000);
+
+	mci_writel(host, REG_CARG, 0);
+	mci_writel(host, REG_CMDR, cmd_val);
+	do {
+		ri = mci_readl(host, REG_RINTR);
+	} while (!(ri & (SDXC_CmdDone | SDXC_IntErrBit)) &&
+		 time_before(jiffies, expire));
+
+	if (ri & SDXC_IntErrBit) {
+		dev_err(mmc_dev(host->mmc), "send stop command failed\n");
+		if (req->stop)
+			req->stop->resp[0] = -ETIMEDOUT;
+	} else {
+		if (req->stop)
+			req->stop->resp[0] = mci_readl(host, REG_RESP0);
+	}
+
+	mci_writel(host, REG_RINTR, 0xffff);
+}
+
+static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *smc_host)
+{
+	struct mmc_command *cmd = smc_host->mrq->cmd;
+	struct mmc_data *data = smc_host->mrq->data;
+
+	/* For some cmds timeout is normal with sd/mmc cards */
+	if ((smc_host->int_sum & SDXC_IntErrBit) == SDXC_RespTimeout &&
+			(cmd->opcode == 5 || cmd->opcode == 52))
+		return;
+
+	dev_err(mmc_dev(smc_host->mmc),
+		"smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
+		smc_host->mmc->index, cmd->opcode,
+		data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
+		smc_host->int_sum & SDXC_RespErr     ? " RE"     : "",
+		smc_host->int_sum & SDXC_RespCRCErr  ? " RCE"    : "",
+		smc_host->int_sum & SDXC_DataCRCErr  ? " DCE"    : "",
+		smc_host->int_sum & SDXC_RespTimeout ? " RTO"    : "",
+		smc_host->int_sum & SDXC_DataTimeout ? " DTO"    : "",
+		smc_host->int_sum & SDXC_FIFORunErr  ? " FE"     : "",
+		smc_host->int_sum & SDXC_HardWLocked ? " HL"     : "",
+		smc_host->int_sum & SDXC_StartBitErr ? " SBE"    : "",
+		smc_host->int_sum & SDXC_EndBitErr   ? " EBE"    : ""
+		);
+}
+
+static void sunxi_mmc_finalize_request(struct sunxi_mmc_host *host)
+{
+	struct mmc_request *mrq;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&host->lock, iflags);
+
+	mrq = host->mrq;
+	if (!mrq) {
+		spin_unlock_irqrestore(&host->lock, iflags);
+		dev_err(mmc_dev(host->mmc), "no request to finalize\n");
+		return;
+	}
+
+	if (host->int_sum & SDXC_IntErrBit) {
+		sunxi_mmc_dump_errinfo(host);
+		mrq->cmd->error = -ETIMEDOUT;
+		if (mrq->data)
+			mrq->data->error = -ETIMEDOUT;
+		if (mrq->stop)
+			mrq->stop->error = -ETIMEDOUT;
+	} else {
+		if (mrq->cmd->flags & MMC_RSP_136) {
+			mrq->cmd->resp[0] = mci_readl(host, REG_RESP3);
+			mrq->cmd->resp[1] = mci_readl(host, REG_RESP2);
+			mrq->cmd->resp[2] = mci_readl(host, REG_RESP1);
+			mrq->cmd->resp[3] = mci_readl(host, REG_RESP0);
+		} else {
+			mrq->cmd->resp[0] = mci_readl(host, REG_RESP0);
+		}
+		if (mrq->data)
+			mrq->data->bytes_xfered =
+				mrq->data->blocks * mrq->data->blksz;
+	}
+
+	if (mrq->data) {
+		struct mmc_data *data = mrq->data;
+		u32 temp;
+
+		mci_writel(host, REG_IDST, 0x337);
+		mci_writel(host, REG_DMAC, 0);
+		temp = mci_readl(host, REG_GCTRL);
+		mci_writel(host, REG_GCTRL, temp|SDXC_DMAReset);
+		temp &= ~SDXC_DMAEnb;
+		mci_writel(host, REG_GCTRL, temp);
+		temp |= SDXC_FIFOReset;
+		mci_writel(host, REG_GCTRL, temp);
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+				     sunxi_mmc_get_dma_dir(data));
+	}
+
+	mci_writel(host, REG_RINTR, 0xffff);
+
+	dev_dbg(mmc_dev(host->mmc), "req done, resp %08x %08x %08x %08x\n",
+		mrq->cmd->resp[0], mrq->cmd->resp[1],
+		mrq->cmd->resp[2], mrq->cmd->resp[3]);
+
+	host->mrq = NULL;
+	host->int_sum = 0;
+	host->wait_dma = 0;
+
+	spin_unlock_irqrestore(&host->lock, iflags);
+
+	if (mrq->data && mrq->data->error) {
+		dev_err(mmc_dev(host->mmc),
+			"data error, sending stop command\n");
+		sunxi_mmc_send_manual_stop(host, mrq);
+	}
+
+	mmc_request_done(host->mmc, mrq);
+}
+
+static s32 sunxi_mmc_get_ro(struct mmc_host *mmc)
+{
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+
+	int read_only = 0;
+
+	if (gpio_is_valid(host->wp_pin)) {
+		pinctrl_request_gpio(host->wp_pin);
+		read_only = gpio_get_value(host->wp_pin);
+	}
+
+	return read_only;
+}
+
+static irqreturn_t sunxi_mmc_irq(int irq, void *dev_id)
+{
+	struct sunxi_mmc_host *host = dev_id;
+	u32 finalize = 0;
+	u32 sdio_int = 0;
+	u32 msk_int;
+	u32 idma_int;
+
+	spin_lock(&host->lock);
+
+	idma_int  = mci_readl(host, REG_IDST);
+	msk_int   = mci_readl(host, REG_MISTA);
+
+	dev_dbg(mmc_dev(host->mmc), "irq: rq %p mi %08x idi %08x\n",
+		host->mrq, msk_int, idma_int);
+
+	if (host->mrq) {
+		if (idma_int & SDXC_IDMACReceiveInt)
+			host->wait_dma = 0;
+
+		host->int_sum |= msk_int;
+
+		/* Wait for CmdDone on RespTimeout before finishing the req */
+		if ((host->int_sum & SDXC_RespTimeout) &&
+				!(host->int_sum & SDXC_CmdDone))
+			mci_writel(host, REG_IMASK,
+				   host->sdio_imask | SDXC_CmdDone);
+		else if (host->int_sum & SDXC_IntErrBit)
+			finalize = 1; /* Don't wait for dma on error */
+		else if (host->int_sum & SDXC_IntDoneBit && !host->wait_dma)
+			finalize = 1; /* Done */
+
+		if (finalize) {
+			mci_writel(host, REG_IMASK, host->sdio_imask);
+			mci_writel(host, REG_IDIE, 0);
+		}
+	}
+
+	if (msk_int & SDXC_SDIOInt)
+		sdio_int = 1;
+
+	mci_writel(host, REG_RINTR, msk_int);
+	mci_writel(host, REG_IDST, idma_int);
+
+	spin_unlock(&host->lock);
+
+	if (finalize)
+		tasklet_schedule(&host->tasklet);
+
+	if (sdio_int)
+		mmc_signal_sdio_irq(host->mmc);
+
+	return IRQ_HANDLED;
+}
+
+static void sunxi_mmc_tasklet(unsigned long data)
+{
+	struct sunxi_mmc_host *smc_host = (struct sunxi_mmc_host *) data;
+	sunxi_mmc_finalize_request(smc_host);
+}
+
+static void sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
+{
+	unsigned long expire = jiffies + msecs_to_jiffies(2000);
+	u32 rval;
+
+	rval = mci_readl(host, REG_CLKCR);
+	rval &= ~(SDXC_CardClkOn | SDXC_LowPowerOn);
+	if (oclk_en)
+		rval |= SDXC_CardClkOn;
+	if (!host->io_flag)
+		rval |= SDXC_LowPowerOn;
+	mci_writel(host, REG_CLKCR, rval);
+
+	rval = SDXC_Start | SDXC_UPCLKOnly | SDXC_WaitPreOver;
+	if (host->voltage_switching)
+		rval |= SDXC_VolSwitch;
+	mci_writel(host, REG_CMDR, rval);
+	do {
+		rval = mci_readl(host, REG_CMDR);
+	} while (time_before(jiffies, expire) && (rval & SDXC_Start));
+
+	if (rval & SDXC_Start) {
+		dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n");
+		host->ferror = 1;
+	}
+}
+
+static void sunxi_mmc_set_clk_dly(struct sunxi_mmc_host *smc_host,
+				  u32 oclk_dly, u32 sclk_dly)
+{
+	unsigned long iflags;
+	struct clk_hw *hw = __clk_get_hw(smc_host->clk_mod);
+
+	spin_lock_irqsave(&smc_host->lock, iflags);
+	clk_sunxi_mmc_phase_control(hw, sclk_dly, oclk_dly);
+	spin_unlock_irqrestore(&smc_host->lock, iflags);
+}
+
+struct sunxi_mmc_clk_dly mmc_clk_dly[MMC_CLK_MOD_NUM] = {
+	{ MMC_CLK_400K, 0, 7 },
+	{ MMC_CLK_25M, 0, 5 },
+	{ MMC_CLK_50M, 3, 5 },
+	{ MMC_CLK_50MDDR, 2, 4 },
+	{ MMC_CLK_50MDDR_8BIT, 2, 4 },
+	{ MMC_CLK_100M, 1, 4 },
+	{ MMC_CLK_200M, 1, 4 },
+};
+
+static void sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *smc_host,
+				   unsigned int rate)
+{
+	u32 newrate;
+	u32 src_clk;
+	u32 oclk_dly;
+	u32 sclk_dly;
+	u32 temp;
+	struct sunxi_mmc_clk_dly *dly = NULL;
+
+	newrate = clk_round_rate(smc_host->clk_mod, rate);
+	if (smc_host->clk_mod_rate == newrate) {
+		dev_dbg(mmc_dev(smc_host->mmc), "clk already %d, rounded %d\n",
+			rate, newrate);
+		return;
+	}
+
+	dev_dbg(mmc_dev(smc_host->mmc), "setting clk to %d, rounded %d\n",
+		rate, newrate);
+
+	/* setting clock rate */
+	clk_disable(smc_host->clk_mod);
+	clk_set_rate(smc_host->clk_mod, newrate);
+	clk_enable(smc_host->clk_mod);
+	smc_host->clk_mod_rate = newrate = clk_get_rate(smc_host->clk_mod);
+	dev_dbg(mmc_dev(smc_host->mmc), "clk is now %d\n", newrate);
+
+	sunxi_mmc_oclk_onoff(smc_host, 0);
+	/* clear internal divider */
+	temp = mci_readl(smc_host, REG_CLKCR);
+	temp &= ~0xff;
+	mci_writel(smc_host, REG_CLKCR, temp);
+
+	/* determine delays */
+	if (rate <= 400000) {
+		dly = &mmc_clk_dly[MMC_CLK_400K];
+	} else if (rate <= 25000000) {
+		dly = &mmc_clk_dly[MMC_CLK_25M];
+	} else if (rate <= 50000000) {
+		if (smc_host->ddr) {
+			if (smc_host->bus_width == 8)
+				dly = &mmc_clk_dly[MMC_CLK_50MDDR_8BIT];
+			else
+				dly = &mmc_clk_dly[MMC_CLK_50MDDR];
+		} else {
+			dly = &mmc_clk_dly[MMC_CLK_50M];
+		}
+	} else if (rate <= 104000000) {
+		dly = &mmc_clk_dly[MMC_CLK_100M];
+	} else if (rate <= 208000000) {
+		dly = &mmc_clk_dly[MMC_CLK_200M];
+	} else
+		dly = &mmc_clk_dly[MMC_CLK_50M];
+
+	oclk_dly = dly->oclk_dly;
+	sclk_dly = dly->sclk_dly;
+
+	src_clk = clk_get_rate(clk_get_parent(smc_host->clk_mod));
+	if (src_clk >= 300000000 && src_clk <= 400000000) {
+		if (oclk_dly)
+			oclk_dly--;
+		if (sclk_dly)
+			sclk_dly--;
+	}
+
+	sunxi_mmc_set_clk_dly(smc_host, oclk_dly, sclk_dly);
+	sunxi_mmc_oclk_onoff(smc_host, 1);
+
+	/* oclk_onoff sets various irq status bits, clear these */
+	mci_writel(smc_host, REG_RINTR,
+		   mci_readl(smc_host, REG_RINTR) & ~SDXC_SDIOInt);
+}
+
+static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+	u32 temp;
+	s32 err;
+
+	/* Set the power state */
+	switch (ios->power_mode) {
+	case MMC_POWER_ON:
+		break;
+
+	case MMC_POWER_UP:
+		if (!IS_ERR(host->vmmc)) {
+			mmc_regulator_set_ocr(host->mmc, host->vmmc, ios->vdd);
+			udelay(200);
+		}
+
+		err =  clk_prepare_enable(host->clk_ahb);
+		if (err) {
+			dev_err(mmc_dev(host->mmc), "AHB clk err %d\n", err);
+			host->ferror = 1;
+			return;
+		}
+		err =  clk_prepare_enable(host->clk_mod);
+		if (err) {
+			dev_err(mmc_dev(host->mmc), "MOD clk err %d\n", err);
+			host->ferror = 1;
+			return;
+		}
+
+		sunxi_mmc_init_host(mmc);
+		enable_irq(host->irq);
+
+		dev_dbg(mmc_dev(host->mmc), "power on!\n");
+		host->ferror = 0;
+		break;
+
+	case MMC_POWER_OFF:
+		dev_dbg(mmc_dev(host->mmc), "power off!\n");
+		disable_irq(host->irq);
+		sunxi_mmc_exit_host(host);
+		clk_disable_unprepare(host->clk_ahb);
+		clk_disable_unprepare(host->clk_mod);
+		if (!IS_ERR(host->vmmc))
+			mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
+		host->ferror = 0;
+		break;
+	}
+
+	/* set bus width */
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_1:
+		mci_writel(host, REG_WIDTH, SDXC_WIDTH1);
+		host->bus_width = 1;
+		break;
+	case MMC_BUS_WIDTH_4:
+		mci_writel(host, REG_WIDTH, SDXC_WIDTH4);
+		host->bus_width = 4;
+		break;
+	case MMC_BUS_WIDTH_8:
+		mci_writel(host, REG_WIDTH, SDXC_WIDTH8);
+		host->bus_width = 8;
+		break;
+	}
+
+	/* set ddr mode */
+	temp = mci_readl(host, REG_GCTRL);
+	if (ios->timing == MMC_TIMING_UHS_DDR50) {
+		temp |= SDXC_DDR_MODE;
+		host->ddr = 1;
+	} else {
+		temp &= ~SDXC_DDR_MODE;
+		host->ddr = 0;
+	}
+	mci_writel(host, REG_GCTRL, temp);
+
+	/* set up clock */
+	if (ios->clock && ios->power_mode) {
+		dev_dbg(mmc_dev(host->mmc), "ios->clock: %d\n", ios->clock);
+		sunxi_mmc_clk_set_rate(host, ios->clock);
+		usleep_range(50000, 55000);
+	}
+}
+
+static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
+	unsigned long flags;
+	u32 imask;
+
+	spin_lock_irqsave(&smc_host->lock, flags);
+	imask = mci_readl(smc_host, REG_IMASK);
+	if (enable) {
+		smc_host->sdio_imask = SDXC_SDIOInt;
+		imask |= SDXC_SDIOInt;
+	} else {
+		smc_host->sdio_imask = 0;
+		imask &= ~SDXC_SDIOInt;
+	}
+	mci_writel(smc_host, REG_IMASK, imask);
+	spin_unlock_irqrestore(&smc_host->lock, flags);
+}
+
+static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
+{
+	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
+	mci_writel(smc_host, REG_HWRST, 0);
+	udelay(10);
+	mci_writel(smc_host, REG_HWRST, 1);
+	udelay(300);
+}
+
+static int sunxi_mmc_card_present(struct mmc_host *mmc)
+{
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+
+	switch (host->cd_mode) {
+	case CARD_DETECT_BY_GPIO_POLL:
+		return !gpio_get_value(host->cd_pin); /* Signal inverted */
+	case CARD_ALWAYS_PRESENT:
+		return 1;
+	}
+	return 0; /* Never reached */
+}
+
+static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+	struct mmc_command *cmd = mrq->cmd;
+	struct mmc_data *data = mrq->data;
+	unsigned long iflags;
+	u32 imask = SDXC_IntErrBit;
+	u32 cmd_val = SDXC_Start | (cmd->opcode & 0x3f);
+	u32 byte_cnt = 0;
+	int ret;
+
+	if (!sunxi_mmc_card_present(mmc) || host->ferror) {
+		dev_dbg(mmc_dev(host->mmc), "no medium present\n");
+		mrq->cmd->error = -ENOMEDIUM;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
+	if (data) {
+		byte_cnt = data->blksz * data->blocks;
+		mci_writel(host, REG_BLKSZ, data->blksz);
+		mci_writel(host, REG_BCNTR, byte_cnt);
+		ret = sunxi_mmc_prepare_dma(host, data);
+		if (ret < 0) {
+			dev_err(mmc_dev(host->mmc), "prepare DMA failed\n");
+			cmd->error = ret;
+			cmd->data->error = ret;
+			mmc_request_done(host->mmc, mrq);
+			return;
+		}
+	}
+
+	if (cmd->opcode == MMC_GO_IDLE_STATE) {
+		cmd_val |= SDXC_SendInitSeq;
+		imask |= SDXC_CmdDone;
+	}
+
+	if (cmd->opcode == SD_SWITCH_VOLTAGE) {
+		cmd_val |= SDXC_VolSwitch;
+		imask |= SDXC_VolChgDone;
+		host->voltage_switching = 1;
+		sunxi_mmc_oclk_onoff(host, 1);
+	}
+
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		cmd_val |= SDXC_RspExp;
+		if (cmd->flags & MMC_RSP_136)
+			cmd_val |= SDXC_LongRsp;
+		if (cmd->flags & MMC_RSP_CRC)
+			cmd_val |= SDXC_CheckRspCRC;
+
+		if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) {
+			cmd_val |= SDXC_DataExp | SDXC_WaitPreOver;
+			if (cmd->data->flags & MMC_DATA_STREAM) {
+				imask |= SDXC_AutoCMDDone;
+				cmd_val |= SDXC_Seqmod | SDXC_SendAutoStop;
+			}
+			if (cmd->data->stop) {
+				imask |= SDXC_AutoCMDDone;
+				cmd_val |= SDXC_SendAutoStop;
+			} else
+				imask |= SDXC_DataOver;
+
+			if (cmd->data->flags & MMC_DATA_WRITE)
+				cmd_val |= SDXC_Write;
+			else
+				host->wait_dma = 1;
+		} else
+			imask |= SDXC_CmdDone;
+	} else
+		imask |= SDXC_CmdDone;
+
+	dev_dbg(mmc_dev(host->mmc), "cmd %d(%08x) arg %x ie 0x%08x len %d\n",
+		cmd_val & 0x3f, cmd_val, cmd->arg, imask,
+		mrq->data ? mrq->data->blksz * mrq->data->blocks : 0);
+
+	spin_lock_irqsave(&host->lock, iflags);
+	host->mrq = mrq;
+	mci_writel(host, REG_IMASK, host->sdio_imask | imask);
+	spin_unlock_irqrestore(&host->lock, iflags);
+
+	mci_writel(host, REG_CARG, cmd->arg);
+	mci_writel(host, REG_CMDR, cmd_val);
+}
+
+static const struct of_device_id sunxi_mmc_of_match[] = {
+	{ .compatible = "allwinner,sun4i-mmc", },
+	{ .compatible = "allwinner,sun5i-mmc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
+
+static struct mmc_host_ops sunxi_mmc_ops = {
+	.request	 = sunxi_mmc_request,
+	.set_ios	 = sunxi_mmc_set_ios,
+	.get_ro		 = sunxi_mmc_get_ro,
+	.get_cd		 = sunxi_mmc_card_present,
+	.enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
+	.hw_reset	 = sunxi_mmc_hw_reset,
+};
+
+static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
+				      struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (of_device_is_compatible(np, "allwinner,sun4i-mmc"))
+		host->idma_des_size_bits = 13;
+	else
+		host->idma_des_size_bits = 16;
+
+	host->vmmc = devm_regulator_get_optional(&pdev->dev, "vmmc");
+	if (IS_ERR(host->vmmc) && PTR_ERR(host->vmmc) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	host->reg_base = devm_ioremap_resource(&pdev->dev,
+			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
+	if (IS_ERR(host->reg_base))
+		return PTR_ERR(host->reg_base);
+
+	host->irq = platform_get_irq(pdev, 0);
+	ret = devm_request_irq(&pdev->dev, host->irq, sunxi_mmc_irq, 0,
+			       "sunxi-mci", host);
+	if (ret)
+		return ret;
+	disable_irq(host->irq);
+
+	host->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(host->clk_ahb)) {
+		dev_err(&pdev->dev, "Could not get ahb clock\n");
+		return PTR_ERR(host->clk_ahb);
+	}
+
+	host->clk_mod = devm_clk_get(&pdev->dev, "mod");
+	if (IS_ERR(host->clk_mod)) {
+		dev_err(&pdev->dev, "Could not get mod clock\n");
+		return PTR_ERR(host->clk_mod);
+	}
+
+	of_property_read_u32(np, "bus-width", &host->bus_width);
+	if (host->bus_width != 1 && host->bus_width != 4) {
+		dev_err(&pdev->dev, "Invalid bus-width %d\n", host->bus_width);
+		return -EINVAL;
+	}
+
+	of_property_read_u32(np, "cd-mode", &host->cd_mode);
+	switch (host->cd_mode) {
+	case CARD_DETECT_BY_GPIO_POLL:
+		host->cd_pin = of_get_named_gpio(np, "cd-gpios", 0);
+		if (!gpio_is_valid(host->cd_pin)) {
+			dev_err(&pdev->dev, "Invalid cd-gpios\n");
+			return -EINVAL;
+		}
+		ret = devm_gpio_request(&pdev->dev, host->cd_pin, "mmc_cd");
+		if (ret) {
+			dev_err(&pdev->dev, "Could not get cd-gpios\n");
+			return ret;
+		}
+		gpio_direction_input(host->cd_pin);
+		break;
+	case CARD_ALWAYS_PRESENT:
+		break;
+	default:
+		dev_err(&pdev->dev, "Invalid cd-mode %d\n", host->cd_mode);
+		return -EINVAL;
+	}
+
+	host->wp_pin = of_get_named_gpio(np, "wp-gpios", 0);
+	if (gpio_is_valid(host->wp_pin)) {
+		ret = devm_gpio_request(&pdev->dev, host->wp_pin, "mmc_wp");
+		if (ret) {
+			dev_err(&pdev->dev, "Could not get wp-gpios\n");
+			return ret;
+		}
+		gpio_direction_input(host->wp_pin);
+	}
+
+	return 0;
+}
+
+static int sunxi_mmc_probe(struct platform_device *pdev)
+{
+	struct sunxi_mmc_host *host;
+	struct mmc_host *mmc;
+	int ret;
+
+	mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);
+	if (!mmc) {
+		dev_err(&pdev->dev, "mmc alloc host failed\n");
+		return -ENOMEM;
+	}
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	spin_lock_init(&host->lock);
+	tasklet_init(&host->tasklet, sunxi_mmc_tasklet, (unsigned long)host);
+
+	ret = sunxi_mmc_resource_request(host, pdev);
+	if (ret)
+		goto error_free_host;
+
+	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
+					  &host->sg_dma, GFP_KERNEL);
+	if (!host->sg_cpu) {
+		dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n");
+		ret = -ENOMEM;
+		goto error_free_host;
+	}
+
+	mmc->ops		= &sunxi_mmc_ops;
+	mmc->max_blk_count	= 8192;
+	mmc->max_blk_size	= 4096;
+	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
+	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
+	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
+	/* 400kHz ~ 50MHz */
+	mmc->f_min		=   400000;
+	mmc->f_max		= 50000000;
+	/* available voltages */
+	if (!IS_ERR(host->vmmc))
+		mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vmmc);
+	else
+		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+		MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
+		MMC_CAP_UHS_DDR50 | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL |
+		MMC_CAP_DRIVER_TYPE_A;
+	if (host->bus_width == 4)
+		mmc->caps |= MMC_CAP_4_BIT_DATA;
+	mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP;
+
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto error_free_dma;
+
+	dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq);
+	platform_set_drvdata(pdev, mmc);
+	return 0;
+
+error_free_dma:
+	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+error_free_host:
+	mmc_free_host(mmc);
+	return ret;
+}
+
+static int sunxi_mmc_remove(struct platform_device *pdev)
+{
+	struct mmc_host	*mmc = platform_get_drvdata(pdev);
+	struct sunxi_mmc_host *host = mmc_priv(mmc);
+
+	mmc_remove_host(mmc);
+	sunxi_mmc_exit_host(host);
+	tasklet_disable(&host->tasklet);
+	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+	mmc_free_host(mmc);
+
+	return 0;
+}
+
+static struct platform_driver sunxi_mmc_driver = {
+	.driver = {
+		.name	= "sunxi-mci",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(sunxi_mmc_of_match),
+	},
+	.probe		= sunxi_mmc_probe,
+	.remove		= sunxi_mmc_remove,
+};
+module_platform_driver(sunxi_mmc_driver);
+
+MODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Lanzend?rfer <david.lanzendoerfer@o2s.ch>");
+MODULE_ALIAS("platform:sunxi-mmc");
diff --git a/drivers/mmc/host/sunxi-mci.h b/drivers/mmc/host/sunxi-mci.h
new file mode 100644
index 0000000..332d3ae
--- /dev/null
+++ b/drivers/mmc/host/sunxi-mci.h
@@ -0,0 +1,246 @@
+/*
+ * Driver for sunxi SD/MMC host controllers
+ * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
+ * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com>
+ * (C) Copyright 2013-2013 O2S GmbH <www.o2s.ch>
+ * (C) Copyright 2013-2013 David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
+ * (C) Copyright 2013-2013 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef __SUNXI_MCI_H__
+#define __SUNXI_MCI_H__
+
+/* register offset define */
+#define SDXC_REG_GCTRL	(0x00) /* SMC Global Control Register */
+#define SDXC_REG_CLKCR	(0x04) /* SMC Clock Control Register */
+#define SDXC_REG_TMOUT	(0x08) /* SMC Time Out Register */
+#define SDXC_REG_WIDTH	(0x0C) /* SMC Bus Width Register */
+#define SDXC_REG_BLKSZ	(0x10) /* SMC Block Size Register */
+#define SDXC_REG_BCNTR	(0x14) /* SMC Byte Count Register */
+#define SDXC_REG_CMDR	(0x18) /* SMC Command Register */
+#define SDXC_REG_CARG	(0x1C) /* SMC Argument Register */
+#define SDXC_REG_RESP0	(0x20) /* SMC Response Register 0 */
+#define SDXC_REG_RESP1	(0x24) /* SMC Response Register 1 */
+#define SDXC_REG_RESP2	(0x28) /* SMC Response Register 2 */
+#define SDXC_REG_RESP3	(0x2C) /* SMC Response Register 3 */
+#define SDXC_REG_IMASK	(0x30) /* SMC Interrupt Mask Register */
+#define SDXC_REG_MISTA	(0x34) /* SMC Masked Interrupt Status Register */
+#define SDXC_REG_RINTR	(0x38) /* SMC Raw Interrupt Status Register */
+#define SDXC_REG_STAS	(0x3C) /* SMC Status Register */
+#define SDXC_REG_FTRGL	(0x40) /* SMC FIFO Threshold Watermark Registe */
+#define SDXC_REG_FUNS	(0x44) /* SMC Function Select Register */
+#define SDXC_REG_CBCR	(0x48) /* SMC CIU Byte Count Register */
+#define SDXC_REG_BBCR	(0x4C) /* SMC BIU Byte Count Register */
+#define SDXC_REG_DBGC	(0x50) /* SMC Debug Enable Register */
+#define SDXC_REG_HWRST	(0x78) /* SMC Card Hardware Reset for Register */
+#define SDXC_REG_DMAC	(0x80) /* SMC IDMAC Control Register */
+#define SDXC_REG_DLBA	(0x84) /* SMC IDMAC Descriptor List Base Addre */
+#define SDXC_REG_IDST	(0x88) /* SMC IDMAC Status Register */
+#define SDXC_REG_IDIE	(0x8C) /* SMC IDMAC Interrupt Enable Register */
+#define SDXC_REG_CHDA	(0x90)
+#define SDXC_REG_CBDA	(0x94)
+
+#define mci_readl(host, reg) \
+	__raw_readl((host)->reg_base + SDXC_##reg)
+#define mci_writel(host, reg, value) \
+	__raw_writel((value), (host)->reg_base + SDXC_##reg)
+
+/* global control register bits */
+#define SDXC_SoftReset		BIT(0)
+#define SDXC_FIFOReset		BIT(1)
+#define SDXC_DMAReset		BIT(2)
+#define SDXC_HWReset		(SDXC_SoftReset|SDXC_FIFOReset|SDXC_DMAReset)
+#define SDXC_INTEnb		BIT(4)
+#define SDXC_DMAEnb		BIT(5)
+#define SDXC_DebounceEnb	BIT(8)
+#define SDXC_PosedgeLatchData	BIT(9)
+#define SDXC_DDR_MODE		BIT(10)
+#define SDXC_MemAccessDone	BIT(29)
+#define SDXC_AccessDoneDirect	BIT(30)
+#define SDXC_ACCESS_BY_AHB	BIT(31)
+#define SDXC_ACCESS_BY_DMA	(0U << 31)
+/* clock control bits */
+#define SDXC_CardClkOn		BIT(16)
+#define SDXC_LowPowerOn		BIT(17)
+/* bus width */
+#define SDXC_WIDTH1		(0)
+#define SDXC_WIDTH4		(1)
+#define SDXC_WIDTH8		(2)
+/* smc command bits */
+#define SDXC_RspExp		BIT(6)
+#define SDXC_LongRsp		BIT(7)
+#define SDXC_CheckRspCRC	BIT(8)
+#define SDXC_DataExp		BIT(9)
+#define SDXC_Write		BIT(10)
+#define SDXC_Seqmod		BIT(11)
+#define SDXC_SendAutoStop	BIT(12)
+#define SDXC_WaitPreOver	BIT(13)
+#define SDXC_StopAbortCMD	BIT(14)
+#define SDXC_SendInitSeq	BIT(15)
+#define SDXC_UPCLKOnly		BIT(21)
+#define SDXC_RdCEATADev		BIT(22)
+#define SDXC_CCSExp		BIT(23)
+#define SDXC_EnbBoot		BIT(24)
+#define SDXC_AltBootOpt		BIT(25)
+#define SDXC_BootACKExp		BIT(26)
+#define SDXC_BootAbort		BIT(27)
+#define SDXC_VolSwitch	        BIT(28)
+#define SDXC_UseHoldReg	        BIT(29)
+#define SDXC_Start	        BIT(31)
+/* interrupt bits */
+#define SDXC_RespErr		BIT(1)
+#define SDXC_CmdDone		BIT(2)
+#define SDXC_DataOver		BIT(3)
+#define SDXC_TxDataReq		BIT(4)
+#define SDXC_RxDataReq		BIT(5)
+#define SDXC_RespCRCErr		BIT(6)
+#define SDXC_DataCRCErr		BIT(7)
+#define SDXC_RespTimeout	BIT(8)
+#define SDXC_DataTimeout	BIT(9)
+#define SDXC_VolChgDone		BIT(10)
+#define SDXC_FIFORunErr		BIT(11)
+#define SDXC_HardWLocked	BIT(12)
+#define SDXC_StartBitErr	BIT(13)
+#define SDXC_AutoCMDDone	BIT(14)
+#define SDXC_EndBitErr		BIT(15)
+#define SDXC_SDIOInt		BIT(16)
+#define SDXC_CardInsert		BIT(30)
+#define SDXC_CardRemove		BIT(31)
+#define SDXC_IntErrBit		(SDXC_RespErr | SDXC_RespCRCErr | \
+				 SDXC_DataCRCErr | SDXC_RespTimeout | \
+				 SDXC_DataTimeout | SDXC_FIFORunErr | \
+				 SDXC_HardWLocked | SDXC_StartBitErr | \
+				 SDXC_EndBitErr) /* 0xbbc2 */
+#define SDXC_IntDoneBit		(SDXC_AutoCMDDone | SDXC_DataOver | \
+				 SDXC_CmdDone | SDXC_VolChgDone)
+/* status */
+#define SDXC_RXWLFlag		BIT(0)
+#define SDXC_TXWLFlag		BIT(1)
+#define SDXC_FIFOEmpty		BIT(2)
+#define SDXC_FIFOFull		BIT(3)
+#define SDXC_CardPresent	BIT(8)
+#define SDXC_CardDataBusy	BIT(9)
+#define SDXC_DataFSMBusy	BIT(10)
+#define SDXC_DMAReq		BIT(31)
+#define SDXC_FIFO_SIZE		(16)
+/* Function select */
+#define SDXC_CEATAOn		(0xceaaU << 16)
+#define SDXC_SendIrqRsp		BIT(0)
+#define SDXC_SDIORdWait		BIT(1)
+#define SDXC_AbtRdData		BIT(2)
+#define SDXC_SendCCSD		BIT(8)
+#define SDXC_SendAutoStopCCSD	BIT(9)
+#define SDXC_CEATADevIntEnb	BIT(10)
+/* IDMA controller bus mod bit field */
+#define SDXC_IDMACSoftRST	BIT(0)
+#define SDXC_IDMACFixBurst	BIT(1)
+#define SDXC_IDMACIDMAOn	BIT(7)
+#define SDXC_IDMACRefetchDES	BIT(31)
+/* IDMA status bit field */
+#define SDXC_IDMACTransmitInt	BIT(0)
+#define SDXC_IDMACReceiveInt	BIT(1)
+#define SDXC_IDMACFatalBusErr	BIT(2)
+#define SDXC_IDMACDesInvalid	BIT(4)
+#define SDXC_IDMACCardErrSum	BIT(5)
+#define SDXC_IDMACNormalIntSum	BIT(8)
+#define SDXC_IDMACAbnormalIntSum BIT(9)
+#define SDXC_IDMACHostAbtInTx	BIT(10)
+#define SDXC_IDMACHostAbtInRx	BIT(10)
+#define SDXC_IDMACIdle		(0U << 13)
+#define SDXC_IDMACSuspend	(1U << 13)
+#define SDXC_IDMACDESCRd	(2U << 13)
+#define SDXC_IDMACDESCCheck	(3U << 13)
+#define SDXC_IDMACRdReqWait	(4U << 13)
+#define SDXC_IDMACWrReqWait	(5U << 13)
+#define SDXC_IDMACRd		(6U << 13)
+#define SDXC_IDMACWr		(7U << 13)
+#define SDXC_IDMACDESCClose	(8U << 13)
+
+struct sunxi_idma_des {
+	u32	config;
+#define SDXC_IDMAC_DES0_DIC	BIT(1)  /* disable interrupt on completion */
+#define SDXC_IDMAC_DES0_LD	BIT(2)  /* last descriptor */
+#define SDXC_IDMAC_DES0_FD	BIT(3)  /* first descriptor */
+#define SDXC_IDMAC_DES0_CH	BIT(4)  /* chain mode */
+#define SDXC_IDMAC_DES0_ER	BIT(5)  /* end of ring */
+#define SDXC_IDMAC_DES0_CES	BIT(30) /* card error summary */
+#define SDXC_IDMAC_DES0_OWN	BIT(31) /* 1-idma owns it, 0-host owns it */
+
+	/*
+	 * If the idma-des-size-bits of property is ie 13, bufsize bits are:
+	 *  Bits  0-12: buf1 size
+	 *  Bits 13-25: buf2 size
+	 *  Bits 26-31: not used
+	 * Since we only ever set buf1 size, we can simply store it directly.
+	 */
+	u32	buf_size;
+	u32	buf_addr_ptr1;
+	u32	buf_addr_ptr2;
+};
+
+struct sunxi_mmc_host {
+	struct mmc_host *mmc;
+	struct regulator *vmmc;
+
+	/* IO mapping base */
+	void __iomem *reg_base;
+
+	spinlock_t lock;
+	struct tasklet_struct tasklet;
+
+	/* clock management */
+	struct clk *clk_ahb;
+	struct clk *clk_mod;
+
+	/* indicator pins */
+	int wp_pin;
+	int cd_pin;
+	int cd_mode;
+#define CARD_DETECT_BY_GPIO_POLL (1)	/* mmc detected by gpio check */
+#define CARD_ALWAYS_PRESENT      (2)	/* mmc always present */
+
+	/* ios information */
+	u32		clk_mod_rate;
+	u32		bus_width;
+	u32		idma_des_size_bits;
+	u32		ddr;
+	u32		voltage_switching;
+
+	/* irq */
+	int		irq;
+	u32		int_sum;
+	u32		sdio_imask;
+
+	/* flags */
+	u32		power_on:1;
+	u32		io_flag:1;
+	u32		wait_dma:1;
+
+	dma_addr_t	sg_dma;
+	void		*sg_cpu;
+
+	struct mmc_request *mrq;
+	u32		ferror;
+};
+
+#define MMC_CLK_400K            0
+#define MMC_CLK_25M             1
+#define MMC_CLK_50M             2
+#define MMC_CLK_50MDDR          3
+#define MMC_CLK_50MDDR_8BIT     4
+#define MMC_CLK_100M            5
+#define MMC_CLK_200M            6
+#define MMC_CLK_MOD_NUM         7
+
+struct sunxi_mmc_clk_dly {
+	u32 mode;
+	u32 oclk_dly;
+	u32 sclk_dly;
+};
+
+#endif
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
new file mode 100644
index 0000000..1ef5c89
--- /dev/null
+++ b/include/linux/clk/sunxi.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013 - Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_CLK_SUNXI_H_
+#define __LINUX_CLK_SUNXI_H_
+
+#include <linux/clk.h>
+
+void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
+
+#endif
-- 
1.8.4.2

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

* [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
  2013-12-14 21:58 ` Hans de Goede
@ 2013-12-14 21:58     ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: Chris Ball, Maxime Ripard
  Cc: David Lanzendörfer, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Hans de Goede

Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 16 ++++++++++++++++
 arch/arm/boot/dts/sun4i-a10.dtsi           | 16 ++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 425a7db..d193937 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -42,7 +42,23 @@
 			};
 		};
 
+		sdc0: sdc@01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_cubieboard>;
+			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl@01c20800 {
+			mmc0_cd_pin_cubieboard: mmc0_cd_pin@0 {
+				allwinner,pins = "PH1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_cubieboard: led_pins@0 {
 				allwinner,pins = "PH20", "PH21";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 4dccdb0..13bccd5 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -306,6 +306,15 @@
 			#size-cells = <0>;
 		};
 
+		sdc0: sdc@01c0f000 {
+			compatible = "allwinner,sun4i-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>, <&mmc0>;
+			interrupts = <32>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
 		intc: interrupt-controller@01c20400 {
 			compatible = "allwinner,sun4i-ic";
 			reg = <0x01c20400 0x400>;
@@ -376,6 +385,13 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			sdc0_pins_a: sdc0@0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
 		};
 
 		timer@01c20c00 {
-- 
1.8.4.2

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

* [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
@ 2013-12-14 21:58     ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 16 ++++++++++++++++
 arch/arm/boot/dts/sun4i-a10.dtsi           | 16 ++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 425a7db..d193937 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -42,7 +42,23 @@
 			};
 		};
 
+		sdc0: sdc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_cubieboard>;
+			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl at 01c20800 {
+			mmc0_cd_pin_cubieboard: mmc0_cd_pin at 0 {
+				allwinner,pins = "PH1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_cubieboard: led_pins at 0 {
 				allwinner,pins = "PH20", "PH21";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 4dccdb0..13bccd5 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -306,6 +306,15 @@
 			#size-cells = <0>;
 		};
 
+		sdc0: sdc at 01c0f000 {
+			compatible = "allwinner,sun4i-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>, <&mmc0>;
+			interrupts = <32>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
 		intc: interrupt-controller at 01c20400 {
 			compatible = "allwinner,sun4i-ic";
 			reg = <0x01c20400 0x400>;
@@ -376,6 +385,13 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			sdc0_pins_a: sdc0 at 0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
 		};
 
 		timer at 01c20c00 {
-- 
1.8.4.2

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

* [PATCH 3/5] ARM: dts: sun5i: Add new sun5i-a13-olinuxino-micro board
  2013-12-14 21:58 ` Hans de Goede
@ 2013-12-14 21:58     ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: Chris Ball, Maxime Ripard
  Cc: David Lanzendörfer, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Hans de Goede

Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/Makefile                      |  1 +
 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts | 66 +++++++++++++++++++++++++
 2 files changed, 67 insertions(+)
 create mode 100644 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index d57c1a6..b663ed7 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -255,6 +255,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \
 	sun4i-a10-hackberry.dtb \
 	sun5i-a10s-olinuxino-micro.dtb \
 	sun5i-a13-olinuxino.dtb \
+	sun5i-a13-olinuxino-micro.dtb \
 	sun6i-a31-colombus.dtb \
 	sun7i-a20-cubieboard2.dtb \
 	sun7i-a20-cubietruck.dtb \
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
new file mode 100644
index 0000000..26df7e8
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "sun5i-a13.dtsi"
+
+/ {
+	model = "Olimex A13-Olinuxino Micro";
+	compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
+
+	soc@01c00000 {
+		pinctrl@01c20800 {
+			led_pins_olinuxinom: led_pins@0 {
+				allwinner,pins = "PG9";
+				allwinner,function = "gpio_out";
+				allwinner,drive = <1>;
+				allwinner,pull = <0>;
+			};
+		};
+
+		uart1: serial@01c28400 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart1_pins_b>;
+			status = "okay";
+		};
+
+		i2c0: i2c@01c2ac00 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_pins_a>;
+			status = "okay";
+		};
+
+		i2c1: i2c@01c2b000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c1_pins_a>;
+			status = "okay";
+		};
+
+		i2c2: i2c@01c2b400 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c2_pins_a>;
+			status = "okay";
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins_olinuxinom>;
+
+		power {
+			gpios = <&pio 6 9 0>;
+			default-state = "on";
+		};
+	};
+};
-- 
1.8.4.2

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

* [PATCH 3/5] ARM: dts: sun5i: Add new sun5i-a13-olinuxino-micro board
@ 2013-12-14 21:58     ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 arch/arm/boot/dts/Makefile                      |  1 +
 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts | 66 +++++++++++++++++++++++++
 2 files changed, 67 insertions(+)
 create mode 100644 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index d57c1a6..b663ed7 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -255,6 +255,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \
 	sun4i-a10-hackberry.dtb \
 	sun5i-a10s-olinuxino-micro.dtb \
 	sun5i-a13-olinuxino.dtb \
+	sun5i-a13-olinuxino-micro.dtb \
 	sun6i-a31-colombus.dtb \
 	sun7i-a20-cubieboard2.dtb \
 	sun7i-a20-cubietruck.dtb \
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
new file mode 100644
index 0000000..26df7e8
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "sun5i-a13.dtsi"
+
+/ {
+	model = "Olimex A13-Olinuxino Micro";
+	compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
+
+	soc at 01c00000 {
+		pinctrl at 01c20800 {
+			led_pins_olinuxinom: led_pins at 0 {
+				allwinner,pins = "PG9";
+				allwinner,function = "gpio_out";
+				allwinner,drive = <1>;
+				allwinner,pull = <0>;
+			};
+		};
+
+		uart1: serial at 01c28400 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart1_pins_b>;
+			status = "okay";
+		};
+
+		i2c0: i2c at 01c2ac00 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_pins_a>;
+			status = "okay";
+		};
+
+		i2c1: i2c at 01c2b000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c1_pins_a>;
+			status = "okay";
+		};
+
+		i2c2: i2c at 01c2b400 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c2_pins_a>;
+			status = "okay";
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins_olinuxinom>;
+
+		power {
+			gpios = <&pio 6 9 0>;
+			default-state = "on";
+		};
+	};
+};
-- 
1.8.4.2

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

* [PATCH 4/5] ARM: dts: sun5i: add mmc support
  2013-12-14 21:58 ` Hans de Goede
@ 2013-12-14 21:58     ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: Chris Ball, Maxime Ripard
  Cc: David Lanzendörfer, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Hans de Goede

Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts | 32 ++++++++++++++++++++++
 arch/arm/boot/dts/sun5i-a10s.dtsi                | 34 ++++++++++++++++++++++++
 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts  | 16 +++++++++++
 arch/arm/boot/dts/sun5i-a13-olinuxino.dts        | 16 +++++++++++
 arch/arm/boot/dts/sun5i-a13.dtsi                 | 17 ++++++++++++
 5 files changed, 115 insertions(+)

diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
index 3c9f8b3..e53fb12 100644
--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
@@ -34,7 +34,39 @@
 			};
 		};
 
+		sdc0: sdc@01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_olinuxino_micro>;
+			cd-gpios = <&pio 6 1 0>; /* PG1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
+		sdc1: sdc@01c10000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc1_pins_a>;
+			pinctrl-1 = <&mmc1_cd_pin_olinuxino_micro>;
+			cd-gpios = <&pio 6 13 0>; /* PG13 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl@01c20800 {
+			mmc0_cd_pin_olinuxino_micro: mmc0_cd_pin@0 {
+				allwinner,pins = "PG1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			mmc1_cd_pin_olinuxino_micro: mmc1_cd_pin@0 {
+				allwinner,pins = "PG13";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_olinuxino: led_pins@0 {
 				allwinner,pins = "PE3";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 83e183c..fdbc290 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -274,6 +274,26 @@
 			#size-cells = <0>;
 		};
 
+		sdc0: sdc@01c0f000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>, <&mmc0>;
+			clock-names = "ahb", "mod";
+			interrupts = <32>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
+		sdc1: sdc@01c10000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c10000 0x1000>;
+			clocks = <&ahb_gates 9>, <&mmc1>;
+			clock-names = "ahb", "mod";
+			interrupts = <33>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
 		intc: interrupt-controller@01c20400 {
 			compatible = "allwinner,sun4i-ic";
 			reg = <0x01c20400 0x400>;
@@ -344,6 +364,20 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			sdc0_pins_a: sdc0@0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
+
+			sdc1_pins_a: sdc1@0 {
+				allwinner,pins = "PG3","PG4","PG5","PG6","PG7","PG8";
+				allwinner,function = "mmc1";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
 		};
 
 		timer@01c20c00 {
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
index 26df7e8..247cd79 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
@@ -19,7 +19,23 @@
 	compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
 
 	soc@01c00000 {
+		sdc0: sdc@01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_olinuxinom>;
+			cd-gpios = <&pio 6 0 0>; /* PG0 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl@01c20800 {
+			mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 {
+				allwinner,pins = "PG0";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_olinuxinom: led_pins@0 {
 				allwinner,pins = "PG9";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
index 9e508dc..ce22c81 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -23,7 +23,23 @@
 	};
 
 	soc@01c00000 {
+		sdc0: sdc@01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_olinuxino>;
+			cd-gpios = <&pio 6 0 0>; /* PG0 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl@01c20800 {
+			mmc0_cd_pin_olinuxino: mmc0_cd_pin@0 {
+				allwinner,pins = "PG0";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_olinuxino: led_pins@0 {
 				allwinner,pins = "PG9";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 0bb4300..0ca0819 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -255,6 +255,16 @@
 		#size-cells = <1>;
 		ranges;
 
+		sdc0: sdc@01c0f000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>, <&mmc0>;
+			clock-names = "ahb", "mod";
+			interrupts = <32>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
 		intc: interrupt-controller@01c20400 {
 			compatible = "allwinner,sun4i-ic";
 			reg = <0x01c20400 0x400>;
@@ -307,6 +317,13 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			sdc0_pins_a: sdc0@0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
 		};
 
 		timer@01c20c00 {
-- 
1.8.4.2

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

* [PATCH 4/5] ARM: dts: sun5i: add mmc support
@ 2013-12-14 21:58     ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts | 32 ++++++++++++++++++++++
 arch/arm/boot/dts/sun5i-a10s.dtsi                | 34 ++++++++++++++++++++++++
 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts  | 16 +++++++++++
 arch/arm/boot/dts/sun5i-a13-olinuxino.dts        | 16 +++++++++++
 arch/arm/boot/dts/sun5i-a13.dtsi                 | 17 ++++++++++++
 5 files changed, 115 insertions(+)

diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
index 3c9f8b3..e53fb12 100644
--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
@@ -34,7 +34,39 @@
 			};
 		};
 
+		sdc0: sdc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_olinuxino_micro>;
+			cd-gpios = <&pio 6 1 0>; /* PG1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
+		sdc1: sdc at 01c10000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc1_pins_a>;
+			pinctrl-1 = <&mmc1_cd_pin_olinuxino_micro>;
+			cd-gpios = <&pio 6 13 0>; /* PG13 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl at 01c20800 {
+			mmc0_cd_pin_olinuxino_micro: mmc0_cd_pin at 0 {
+				allwinner,pins = "PG1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			mmc1_cd_pin_olinuxino_micro: mmc1_cd_pin at 0 {
+				allwinner,pins = "PG13";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_olinuxino: led_pins at 0 {
 				allwinner,pins = "PE3";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 83e183c..fdbc290 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -274,6 +274,26 @@
 			#size-cells = <0>;
 		};
 
+		sdc0: sdc at 01c0f000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>, <&mmc0>;
+			clock-names = "ahb", "mod";
+			interrupts = <32>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
+		sdc1: sdc at 01c10000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c10000 0x1000>;
+			clocks = <&ahb_gates 9>, <&mmc1>;
+			clock-names = "ahb", "mod";
+			interrupts = <33>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
 		intc: interrupt-controller at 01c20400 {
 			compatible = "allwinner,sun4i-ic";
 			reg = <0x01c20400 0x400>;
@@ -344,6 +364,20 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			sdc0_pins_a: sdc0 at 0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
+
+			sdc1_pins_a: sdc1 at 0 {
+				allwinner,pins = "PG3","PG4","PG5","PG6","PG7","PG8";
+				allwinner,function = "mmc1";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
 		};
 
 		timer at 01c20c00 {
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
index 26df7e8..247cd79 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
@@ -19,7 +19,23 @@
 	compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
 
 	soc at 01c00000 {
+		sdc0: sdc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_olinuxinom>;
+			cd-gpios = <&pio 6 0 0>; /* PG0 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl at 01c20800 {
+			mmc0_cd_pin_olinuxinom: mmc0_cd_pin at 0 {
+				allwinner,pins = "PG0";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_olinuxinom: led_pins at 0 {
 				allwinner,pins = "PG9";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
index 9e508dc..ce22c81 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -23,7 +23,23 @@
 	};
 
 	soc at 01c00000 {
+		sdc0: sdc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_olinuxino>;
+			cd-gpios = <&pio 6 0 0>; /* PG0 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl at 01c20800 {
+			mmc0_cd_pin_olinuxino: mmc0_cd_pin at 0 {
+				allwinner,pins = "PG0";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_olinuxino: led_pins at 0 {
 				allwinner,pins = "PG9";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 0bb4300..0ca0819 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -255,6 +255,16 @@
 		#size-cells = <1>;
 		ranges;
 
+		sdc0: sdc at 01c0f000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>, <&mmc0>;
+			clock-names = "ahb", "mod";
+			interrupts = <32>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
 		intc: interrupt-controller at 01c20400 {
 			compatible = "allwinner,sun4i-ic";
 			reg = <0x01c20400 0x400>;
@@ -307,6 +317,13 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			sdc0_pins_a: sdc0 at 0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
 		};
 
 		timer at 01c20c00 {
-- 
1.8.4.2

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

* [PATCH 5/5] ARM: dts: sun7i: Add support for mmc
  2013-12-14 21:58 ` Hans de Goede
@ 2013-12-14 21:58     ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: Chris Ball, Maxime Ripard
  Cc: David Lanzendörfer, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Hans de Goede

Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 arch/arm/boot/dts/sun7i-a20-cubieboard2.dts     | 16 ++++++++++++
 arch/arm/boot/dts/sun7i-a20-cubietruck.dts      | 16 ++++++++++++
 arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 32 +++++++++++++++++++++++
 arch/arm/boot/dts/sun7i-a20.dtsi                | 34 +++++++++++++++++++++++++
 4 files changed, 98 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index 5c51cb8..6aef299 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -34,7 +34,23 @@
 			};
 		};
 
+		sdc0: sdc@01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_cubieboard2>;
+			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl@01c20800 {
+			mmc0_cd_pin_cubieboard2: mmc0_cd_pin@0 {
+				allwinner,pins = "PH1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_cubieboard2: led_pins@0 {
 				allwinner,pins = "PH20", "PH21";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 8a1009d..302c785 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -19,7 +19,23 @@
 	compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
 
 	soc@01c00000 {
+		sdc0: sdc@01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_cubietruck>;
+			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl@01c20800 {
+			mmc0_cd_pin_cubietruck: mmc0_cd_pin@0 {
+				allwinner,pins = "PH1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_cubietruck: led_pins@0 {
 				allwinner,pins = "PH7", "PH11", "PH20", "PH21";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index ead3013..f271db9 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -34,7 +34,39 @@
 			};
 		};
 
+		sdc0: sdc@01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_olinuxinom>;
+			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
+		sdc3: sdc@01c12000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc3_pins_a>;
+			pinctrl-1 = <&mmc3_cd_pin_olinuxinom>;
+			cd-gpios = <&pio 7 11 0>; /* PH11 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl@01c20800 {
+			mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 {
+				allwinner,pins = "PH1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			mmc3_cd_pin_olinuxinom: mmc3_cd_pin@0 {
+				allwinner,pins = "PH11";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_olinuxino: led_pins@0 {
 				allwinner,pins = "PH2";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 0552a64..4416cac 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -303,6 +303,26 @@
 			#size-cells = <0>;
 		};
 
+		sdc0: sdc@01c0f000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>, <&mmc0>;
+			clock-names = "ahb", "mod";
+			interrupts = <0 32 4>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
+		sdc3: sdc@01c12000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c12000 0x1000>;
+			clocks = <&ahb_gates 11>, <&mmc3>;
+			clock-names = "ahb", "mod";
+			interrupts = <0 35 4>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
 		pio: pinctrl@01c20800 {
 			compatible = "allwinner,sun7i-a20-pinctrl";
 			reg = <0x01c20800 0x400>;
@@ -366,6 +386,20 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			sdc0_pins_a: sdc0@0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
+
+			sdc3_pins_a: sdc3@0 {
+				allwinner,pins = "PI4","PI5","PI6","PI7","PI8","PI9";
+				allwinner,function = "mmc3";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
 		};
 
 		timer@01c20c00 {
-- 
1.8.4.2

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

* [PATCH 5/5] ARM: dts: sun7i: Add support for mmc
@ 2013-12-14 21:58     ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-14 21:58 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 arch/arm/boot/dts/sun7i-a20-cubieboard2.dts     | 16 ++++++++++++
 arch/arm/boot/dts/sun7i-a20-cubietruck.dts      | 16 ++++++++++++
 arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 32 +++++++++++++++++++++++
 arch/arm/boot/dts/sun7i-a20.dtsi                | 34 +++++++++++++++++++++++++
 4 files changed, 98 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index 5c51cb8..6aef299 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -34,7 +34,23 @@
 			};
 		};
 
+		sdc0: sdc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_cubieboard2>;
+			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl at 01c20800 {
+			mmc0_cd_pin_cubieboard2: mmc0_cd_pin at 0 {
+				allwinner,pins = "PH1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_cubieboard2: led_pins at 0 {
 				allwinner,pins = "PH20", "PH21";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 8a1009d..302c785 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -19,7 +19,23 @@
 	compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
 
 	soc at 01c00000 {
+		sdc0: sdc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_cubietruck>;
+			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl at 01c20800 {
+			mmc0_cd_pin_cubietruck: mmc0_cd_pin at 0 {
+				allwinner,pins = "PH1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_cubietruck: led_pins at 0 {
 				allwinner,pins = "PH7", "PH11", "PH20", "PH21";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index ead3013..f271db9 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -34,7 +34,39 @@
 			};
 		};
 
+		sdc0: sdc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc0_pins_a>;
+			pinctrl-1 = <&mmc0_cd_pin_olinuxinom>;
+			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
+		sdc3: sdc at 01c12000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&sdc3_pins_a>;
+			pinctrl-1 = <&mmc3_cd_pin_olinuxinom>;
+			cd-gpios = <&pio 7 11 0>; /* PH11 */
+			cd-mode = <1>;
+			status = "okay";
+		};
+
 		pinctrl at 01c20800 {
+			mmc0_cd_pin_olinuxinom: mmc0_cd_pin at 0 {
+				allwinner,pins = "PH1";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
+			mmc3_cd_pin_olinuxinom: mmc3_cd_pin at 0 {
+				allwinner,pins = "PH11";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <0>;
+			};
+
 			led_pins_olinuxino: led_pins at 0 {
 				allwinner,pins = "PH2";
 				allwinner,function = "gpio_out";
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 0552a64..4416cac 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -303,6 +303,26 @@
 			#size-cells = <0>;
 		};
 
+		sdc0: sdc at 01c0f000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>, <&mmc0>;
+			clock-names = "ahb", "mod";
+			interrupts = <0 32 4>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
+		sdc3: sdc at 01c12000 {
+			compatible = "allwinner,sun5i-mmc";
+			reg = <0x01c12000 0x1000>;
+			clocks = <&ahb_gates 11>, <&mmc3>;
+			clock-names = "ahb", "mod";
+			interrupts = <0 35 4>;
+			bus-width = <4>;
+			status = "disabled";
+		};
+
 		pio: pinctrl at 01c20800 {
 			compatible = "allwinner,sun7i-a20-pinctrl";
 			reg = <0x01c20800 0x400>;
@@ -366,6 +386,20 @@
 				allwinner,drive = <0>;
 				allwinner,pull = <0>;
 			};
+
+			sdc0_pins_a: sdc0 at 0 {
+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
+
+			sdc3_pins_a: sdc3 at 0 {
+				allwinner,pins = "PI4","PI5","PI6","PI7","PI8","PI9";
+				allwinner,function = "mmc3";
+				allwinner,drive = <3>;
+				allwinner,pull = <1>;
+			};
 		};
 
 		timer at 01c20c00 {
-- 
1.8.4.2

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

* Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-14 21:58     ` Hans de Goede
@ 2013-12-15 13:44         ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-15 13:44 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 43138 bytes --]

Hi Hans,

I won't comment on the MMC driver itself, and leave Chris comment on
that, but still, I have a few things.

On Sat, Dec 14, 2013 at 10:58:11PM +0100, Hans de Goede wrote:
> From: David Lanzendörfer <david.lanzendoerfer-Z7Kmv9EsliU@public.gmane.org>
> 
> This is based on the driver Allwinner ships in there Android kernel sources.
> 
> Initial porting to upstream kernels done by David Lanzendörfer, additional
> fixes and cleanups by Hans de Goede.
> 
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Your commit log is a bit sparse. What capabilities this controller
has? Is it using DMA? If so, how? What SoCs are supported/it has been
tested on? etc.

Also, you probably needs David's SoB here.

> ---
>  drivers/mmc/host/Kconfig     |   8 +
>  drivers/mmc/host/Makefile    |   2 +
>  drivers/mmc/host/sunxi-mci.c | 908 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sunxi-mci.h | 246 ++++++++++++
>  include/linux/clk/sunxi.h    |  22 ++

Please add your dt bindings documentation in Documentation/devicetree/bindings

>  5 files changed, 1186 insertions(+)
>  create mode 100644 drivers/mmc/host/sunxi-mci.c
>  create mode 100644 drivers/mmc/host/sunxi-mci.h
>  create mode 100644 include/linux/clk/sunxi.h
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 7fc5099..69a7171 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
>  	help
>  	  Say Y here to include driver code to support SD/MMC card interface
>  	  of Realtek PCI-E card reader
> +
> +config MMC_SUNXI
> +	tristate "Allwinner sunxi SD/MMC Host Controller support"
> +	depends on ARCH_SUNXI
> +	default y

I'm not that fond of these "default y" patterns. It forces the driver
down to every user of the multiplatform kernels. I'd suggest removing
the default and adding the driver to the defconfigs we have.

> +	help
> +	  This selects support for the SD/MMC Host Controller on
> +	  Allwinner sunxi SoCs.
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index c41d0c3..f76f783 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -52,6 +52,8 @@ obj-$(CONFIG_MMC_WMT)		+= wmt-sdmmc.o
>  
>  obj-$(CONFIG_MMC_REALTEK_PCI)	+= rtsx_pci_sdmmc.o
>  
> +obj-$(CONFIG_MMC_SUNXI)		+= sunxi-mci.o
> +
>  obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
>  obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
>  obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
> diff --git a/drivers/mmc/host/sunxi-mci.c b/drivers/mmc/host/sunxi-mci.c
> new file mode 100644
> index 0000000..e091ebb
> --- /dev/null
> +++ b/drivers/mmc/host/sunxi-mci.c
> @@ -0,0 +1,908 @@
> +/*
> + * Driver for sunxi SD/MMC host controllers
> + * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
> + * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh-jFKXxz0WcGyYHARAtoI1EgC/G2K4zDHf@public.gmane.org>
> + * (C) Copyright 2013-2013 O2S GmbH <www.o2s.ch>
> + * (C) Copyright 2013-2013 David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
> + * (C) Copyright 2013-2013 Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +
> +#include <linux/clk.h>
> +#include <linux/clk-private.h>
> +#include <linux/clk/sunxi.h>
> +
> +#include <linux/gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/scatterlist.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/slab.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <linux/of_address.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_platform.h>
> +
> +#include <linux/mmc/host.h>
> +#include <linux/mmc/sd.h>
> +#include <linux/mmc/mmc.h>
> +#include <linux/mmc/core.h>
> +#include <linux/mmc/card.h>
> +
> +#include "sunxi-mci.h"
> +
> +static void sunxi_mmc_init_host(struct mmc_host *mmc)
> +{
> +	u32 rval;
> +	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
> +
> +	/* reset controller */
> +	rval = mci_readl(smc_host, REG_GCTRL) | SDXC_HWReset;
> +	mci_writel(smc_host, REG_GCTRL, rval);
> +
> +	mci_writel(smc_host, REG_FTRGL, 0x20070008);
> +	mci_writel(smc_host, REG_TMOUT, 0xffffffff);
> +	mci_writel(smc_host, REG_IMASK, smc_host->sdio_imask);
> +	mci_writel(smc_host, REG_RINTR, 0xffffffff);
> +	mci_writel(smc_host, REG_DBGC, 0xdeb);
> +	mci_writel(smc_host, REG_FUNS, 0xceaa0000);
> +	mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);

I suppose we have no idea what these magics are all about ? :(

> +	rval = mci_readl(smc_host, REG_GCTRL)|SDXC_INTEnb;
> +	rval &= ~SDXC_AccessDoneDirect;
> +	mci_writel(smc_host, REG_GCTRL, rval);
> +}
> +
> +static void sunxi_mmc_exit_host(struct sunxi_mmc_host *smc_host)
> +{
> +	mci_writel(smc_host, REG_GCTRL, SDXC_HWReset);
> +}
> +
> +/* /\* UHS-I Operation Modes */
> +/*  * DS		25MHz	12.5MB/s	3.3V */
> +/*  * HS		50MHz	25MB/s		3.3V */
> +/*  * SDR12	25MHz	12.5MB/s	1.8V */
> +/*  * SDR25	50MHz	25MB/s		1.8V */
> +/*  * SDR50	100MHz	50MB/s		1.8V */
> +/*  * SDR104	208MHz	104MB/s		1.8V */
> +/*  * DDR50	50MHz	50MB/s		1.8V */
> +/*  * MMC Operation Modes */
> +/*  * DS		26MHz	26MB/s		3/1.8/1.2V */
> +/*  * HS		52MHz	52MB/s		3/1.8/1.2V */
> +/*  * HSDDR	52MHz	104MB/s		3/1.8/1.2V */
> +/*  * HS200	200MHz	200MB/s		1.8/1.2V */
> +/*  * */
> +/*  * Spec. Timing */
> +/*  * SD3.0 */
> +/*  * Fcclk    Tcclk   Fsclk   Tsclk   Tis     Tih     odly  RTis     RTih */
> +/*  * 400K     2.5us   24M     41ns    5ns     5ns     1     2209ns   41ns */
> +/*  * 25M      40ns    600M    1.67ns  5ns     5ns     3     14.99ns  5.01ns */
> +/*  * 50M      20ns    600M    1.67ns  6ns     2ns     3     14.99ns  5.01ns */
> +/*  * 50MDDR   20ns    600M    1.67ns  6ns     0.8ns   2     6.67ns   3.33ns */
> +/*  * 104M     9.6ns   600M    1.67ns  3ns     0.8ns   1     7.93ns   1.67ns */
> +/*  * 208M     4.8ns   600M    1.67ns  1.4ns   0.8ns   1     3.33ns   1.67ns */
> +
> +/*  * 25M      40ns    300M    3.33ns  5ns     5ns     2     13.34ns   6.66ns */
> +/*  * 50M      20ns    300M    3.33ns  6ns     2ns     2     13.34ns   6.66ns */
> +/*  * 50MDDR   20ns    300M    3.33ns  6ns     0.8ns   1     6.67ns    3.33ns */
> +/*  * 104M     9.6ns   300M    3.33ns  3ns     0.8ns   0     7.93ns    1.67ns */
> +/*  * 208M     4.8ns   300M    3.33ns  1.4ns   0.8ns   0     3.13ns    1.67ns */
> +
> +/*  * eMMC4.5 */
> +/*  * 400K     2.5us   24M     41ns    3ns     3ns     1     2209ns    41ns */
> +/*  * 25M      40ns    600M    1.67ns  3ns     3ns     3     14.99ns   5.01ns */
> +/*  * 50M      20ns    600M    1.67ns  3ns     3ns     3     14.99ns   5.01ns */
> +/*  * 50MDDR   20ns    600M    1.67ns  2.5ns   2.5ns   2     6.67ns    3.33ns */
> +/*  * 200M     5ns     600M    1.67ns  1.4ns   0.8ns   1     3.33ns    1.67ns */
> +/*  *\/ */
> +
> +static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
> +				    struct mmc_data *data)
> +{
> +	struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
> +	struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma;
> +	int i, max_len = (1 << host->idma_des_size_bits);
> +
> +	for (i = 0; i < data->sg_len; i++) {
> +		pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN |
> +				 SDXC_IDMAC_DES0_DIC;
> +
> +		if (data->sg[i].length == max_len)
> +			pdes[i].buf_size = 0; /* 0 == max_len */
> +		else
> +			pdes[i].buf_size = data->sg[i].length;
> +
> +		pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]);
> +		pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1];
> +	}

Please add a newline.

> +	pdes[0].config |= SDXC_IDMAC_DES0_FD;
> +	pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD;
> +
> +	wmb(); /* Ensure idma_des hit main mem before we start the idmac */
> +}
> +
> +static enum dma_data_direction sunxi_mmc_get_dma_dir(struct mmc_data *data)
> +{
> +	if (data->flags & MMC_DATA_WRITE)
> +		return DMA_TO_DEVICE;
> +	else
> +		return DMA_FROM_DEVICE;
> +}
> +
> +static int sunxi_mmc_prepare_dma(struct sunxi_mmc_host *smc_host,
> +				 struct mmc_data *data)
> +{
> +	u32 dma_len;
> +	u32 i;
> +	u32 temp;
> +	struct scatterlist *sg;
> +
> +	dma_len = dma_map_sg(mmc_dev(smc_host->mmc), data->sg, data->sg_len,
> +			     sunxi_mmc_get_dma_dir(data));
> +	if (dma_len == 0) {
> +		dev_err(mmc_dev(smc_host->mmc), "dma_map_sg failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	for_each_sg(data->sg, sg, data->sg_len, i) {
> +		if (sg->offset & 3 || sg->length & 3) {
> +			dev_err(mmc_dev(smc_host->mmc),
> +				"unaligned scatterlist: os %x length %d\n",
> +				sg->offset, sg->length);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	sunxi_mmc_init_idma_des(smc_host, data);
> +
> +	temp = mci_readl(smc_host, REG_GCTRL);
> +	temp |= SDXC_DMAEnb;
> +	mci_writel(smc_host, REG_GCTRL, temp);
> +	temp |= SDXC_DMAReset;
> +	mci_writel(smc_host, REG_GCTRL, temp);
> +
> +	mci_writel(smc_host, REG_DMAC, SDXC_IDMACSoftRST);
> +
> +	if (!(data->flags & MMC_DATA_WRITE))
> +		mci_writel(smc_host, REG_IDIE, SDXC_IDMACReceiveInt);
> +
> +	mci_writel(smc_host, REG_DMAC, SDXC_IDMACFixBurst | SDXC_IDMACIDMAOn);
> +
> +	return 0;
> +}
> +
> +static void sunxi_mmc_send_manual_stop(struct sunxi_mmc_host *host,
> +				       struct mmc_request *req)
> +{
> +	u32 cmd_val = SDXC_Start | SDXC_RspExp | SDXC_StopAbortCMD
> +			| SDXC_CheckRspCRC | MMC_STOP_TRANSMISSION;
> +	u32 ri = 0;
> +	unsigned long expire = jiffies + msecs_to_jiffies(1000);
> +
> +	mci_writel(host, REG_CARG, 0);
> +	mci_writel(host, REG_CMDR, cmd_val);

Please add a newline.

> +	do {
> +		ri = mci_readl(host, REG_RINTR);
> +	} while (!(ri & (SDXC_CmdDone | SDXC_IntErrBit)) &&
> +		 time_before(jiffies, expire));
> +
> +	if (ri & SDXC_IntErrBit) {
> +		dev_err(mmc_dev(host->mmc), "send stop command failed\n");
> +		if (req->stop)
> +			req->stop->resp[0] = -ETIMEDOUT;
> +	} else {
> +		if (req->stop)
> +			req->stop->resp[0] = mci_readl(host, REG_RESP0);
> +	}
> +
> +	mci_writel(host, REG_RINTR, 0xffff);
> +}
> +
> +static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *smc_host)
> +{
> +	struct mmc_command *cmd = smc_host->mrq->cmd;
> +	struct mmc_data *data = smc_host->mrq->data;
> +
> +	/* For some cmds timeout is normal with sd/mmc cards */
> +	if ((smc_host->int_sum & SDXC_IntErrBit) == SDXC_RespTimeout &&
> +			(cmd->opcode == 5 || cmd->opcode == 52))
> +		return;
> +
> +	dev_err(mmc_dev(smc_host->mmc),
> +		"smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
> +		smc_host->mmc->index, cmd->opcode,
> +		data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
> +		smc_host->int_sum & SDXC_RespErr     ? " RE"     : "",
> +		smc_host->int_sum & SDXC_RespCRCErr  ? " RCE"    : "",
> +		smc_host->int_sum & SDXC_DataCRCErr  ? " DCE"    : "",
> +		smc_host->int_sum & SDXC_RespTimeout ? " RTO"    : "",
> +		smc_host->int_sum & SDXC_DataTimeout ? " DTO"    : "",
> +		smc_host->int_sum & SDXC_FIFORunErr  ? " FE"     : "",
> +		smc_host->int_sum & SDXC_HardWLocked ? " HL"     : "",
> +		smc_host->int_sum & SDXC_StartBitErr ? " SBE"    : "",
> +		smc_host->int_sum & SDXC_EndBitErr   ? " EBE"    : ""
> +		);
> +}
> +
> +static void sunxi_mmc_finalize_request(struct sunxi_mmc_host *host)
> +{
> +	struct mmc_request *mrq;
> +	unsigned long iflags;
> +
> +	spin_lock_irqsave(&host->lock, iflags);
> +
> +	mrq = host->mrq;
> +	if (!mrq) {
> +		spin_unlock_irqrestore(&host->lock, iflags);
> +		dev_err(mmc_dev(host->mmc), "no request to finalize\n");
> +		return;
> +	}
> +
> +	if (host->int_sum & SDXC_IntErrBit) {
> +		sunxi_mmc_dump_errinfo(host);
> +		mrq->cmd->error = -ETIMEDOUT;
> +		if (mrq->data)
> +			mrq->data->error = -ETIMEDOUT;
> +		if (mrq->stop)
> +			mrq->stop->error = -ETIMEDOUT;
> +	} else {
> +		if (mrq->cmd->flags & MMC_RSP_136) {
> +			mrq->cmd->resp[0] = mci_readl(host, REG_RESP3);
> +			mrq->cmd->resp[1] = mci_readl(host, REG_RESP2);
> +			mrq->cmd->resp[2] = mci_readl(host, REG_RESP1);
> +			mrq->cmd->resp[3] = mci_readl(host, REG_RESP0);
> +		} else {
> +			mrq->cmd->resp[0] = mci_readl(host, REG_RESP0);
> +		}
> +		if (mrq->data)
> +			mrq->data->bytes_xfered =
> +				mrq->data->blocks * mrq->data->blksz;
> +	}
> +
> +	if (mrq->data) {
> +		struct mmc_data *data = mrq->data;
> +		u32 temp;
> +
> +		mci_writel(host, REG_IDST, 0x337);
> +		mci_writel(host, REG_DMAC, 0);
> +		temp = mci_readl(host, REG_GCTRL);
> +		mci_writel(host, REG_GCTRL, temp|SDXC_DMAReset);
> +		temp &= ~SDXC_DMAEnb;
> +		mci_writel(host, REG_GCTRL, temp);
> +		temp |= SDXC_FIFOReset;
> +		mci_writel(host, REG_GCTRL, temp);
> +		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
> +				     sunxi_mmc_get_dma_dir(data));
> +	}
> +
> +	mci_writel(host, REG_RINTR, 0xffff);
> +
> +	dev_dbg(mmc_dev(host->mmc), "req done, resp %08x %08x %08x %08x\n",
> +		mrq->cmd->resp[0], mrq->cmd->resp[1],
> +		mrq->cmd->resp[2], mrq->cmd->resp[3]);
> +
> +	host->mrq = NULL;
> +	host->int_sum = 0;
> +	host->wait_dma = 0;
> +
> +	spin_unlock_irqrestore(&host->lock, iflags);
> +
> +	if (mrq->data && mrq->data->error) {
> +		dev_err(mmc_dev(host->mmc),
> +			"data error, sending stop command\n");
> +		sunxi_mmc_send_manual_stop(host, mrq);
> +	}
> +
> +	mmc_request_done(host->mmc, mrq);
> +}
> +
> +static s32 sunxi_mmc_get_ro(struct mmc_host *mmc)
> +{
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +
> +	int read_only = 0;
> +
> +	if (gpio_is_valid(host->wp_pin)) {
> +		pinctrl_request_gpio(host->wp_pin);

This is actually not needed. It's already called by gpio_request.

> +		read_only = gpio_get_value(host->wp_pin);
> +	}
> +
> +	return read_only;
> +}
> +
> +static irqreturn_t sunxi_mmc_irq(int irq, void *dev_id)
> +{
> +	struct sunxi_mmc_host *host = dev_id;
> +	u32 finalize = 0;
> +	u32 sdio_int = 0;
> +	u32 msk_int;
> +	u32 idma_int;
> +
> +	spin_lock(&host->lock);
> +
> +	idma_int  = mci_readl(host, REG_IDST);
> +	msk_int   = mci_readl(host, REG_MISTA);
> +
> +	dev_dbg(mmc_dev(host->mmc), "irq: rq %p mi %08x idi %08x\n",
> +		host->mrq, msk_int, idma_int);
> +
> +	if (host->mrq) {
> +		if (idma_int & SDXC_IDMACReceiveInt)
> +			host->wait_dma = 0;
> +
> +		host->int_sum |= msk_int;
> +
> +		/* Wait for CmdDone on RespTimeout before finishing the req */
> +		if ((host->int_sum & SDXC_RespTimeout) &&
> +				!(host->int_sum & SDXC_CmdDone))
> +			mci_writel(host, REG_IMASK,
> +				   host->sdio_imask | SDXC_CmdDone);
> +		else if (host->int_sum & SDXC_IntErrBit)
> +			finalize = 1; /* Don't wait for dma on error */
> +		else if (host->int_sum & SDXC_IntDoneBit && !host->wait_dma)
> +			finalize = 1; /* Done */
> +
> +		if (finalize) {
> +			mci_writel(host, REG_IMASK, host->sdio_imask);
> +			mci_writel(host, REG_IDIE, 0);
> +		}
> +	}
> +
> +	if (msk_int & SDXC_SDIOInt)
> +		sdio_int = 1;
> +
> +	mci_writel(host, REG_RINTR, msk_int);
> +	mci_writel(host, REG_IDST, idma_int);
> +
> +	spin_unlock(&host->lock);
> +
> +	if (finalize)
> +		tasklet_schedule(&host->tasklet);
> +
> +	if (sdio_int)
> +		mmc_signal_sdio_irq(host->mmc);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void sunxi_mmc_tasklet(unsigned long data)
> +{
> +	struct sunxi_mmc_host *smc_host = (struct sunxi_mmc_host *) data;
> +	sunxi_mmc_finalize_request(smc_host);
> +}
> +
> +static void sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
> +{
> +	unsigned long expire = jiffies + msecs_to_jiffies(2000);
> +	u32 rval;
> +
> +	rval = mci_readl(host, REG_CLKCR);
> +	rval &= ~(SDXC_CardClkOn | SDXC_LowPowerOn);

Please add a newline.

> +	if (oclk_en)
> +		rval |= SDXC_CardClkOn;

Please add a newline.

> +	if (!host->io_flag)
> +		rval |= SDXC_LowPowerOn;

Please add a newline.

> +	mci_writel(host, REG_CLKCR, rval);
> +
> +	rval = SDXC_Start | SDXC_UPCLKOnly | SDXC_WaitPreOver;
> +	if (host->voltage_switching)
> +		rval |= SDXC_VolSwitch;
> +	mci_writel(host, REG_CMDR, rval);
> +	do {
> +		rval = mci_readl(host, REG_CMDR);
> +	} while (time_before(jiffies, expire) && (rval & SDXC_Start));
> +
> +	if (rval & SDXC_Start) {
> +		dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n");
> +		host->ferror = 1;
> +	}
> +}
> +
> +static void sunxi_mmc_set_clk_dly(struct sunxi_mmc_host *smc_host,
> +				  u32 oclk_dly, u32 sclk_dly)
> +{
> +	unsigned long iflags;
> +	struct clk_hw *hw = __clk_get_hw(smc_host->clk_mod);
> +
> +	spin_lock_irqsave(&smc_host->lock, iflags);
> +	clk_sunxi_mmc_phase_control(hw, sclk_dly, oclk_dly);
> +	spin_unlock_irqrestore(&smc_host->lock, iflags);
> +}
> +
> +struct sunxi_mmc_clk_dly mmc_clk_dly[MMC_CLK_MOD_NUM] = {
> +	{ MMC_CLK_400K, 0, 7 },
> +	{ MMC_CLK_25M, 0, 5 },
> +	{ MMC_CLK_50M, 3, 5 },
> +	{ MMC_CLK_50MDDR, 2, 4 },
> +	{ MMC_CLK_50MDDR_8BIT, 2, 4 },
> +	{ MMC_CLK_100M, 1, 4 },
> +	{ MMC_CLK_200M, 1, 4 },
> +};
> +
> +static void sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *smc_host,
> +				   unsigned int rate)
> +{
> +	u32 newrate;
> +	u32 src_clk;
> +	u32 oclk_dly;
> +	u32 sclk_dly;
> +	u32 temp;
> +	struct sunxi_mmc_clk_dly *dly = NULL;
> +
> +	newrate = clk_round_rate(smc_host->clk_mod, rate);
> +	if (smc_host->clk_mod_rate == newrate) {
> +		dev_dbg(mmc_dev(smc_host->mmc), "clk already %d, rounded %d\n",
> +			rate, newrate);
> +		return;
> +	}
> +
> +	dev_dbg(mmc_dev(smc_host->mmc), "setting clk to %d, rounded %d\n",
> +		rate, newrate);
> +
> +	/* setting clock rate */
> +	clk_disable(smc_host->clk_mod);
> +	clk_set_rate(smc_host->clk_mod, newrate);
> +	clk_enable(smc_host->clk_mod);
> +	smc_host->clk_mod_rate = newrate = clk_get_rate(smc_host->clk_mod);
> +	dev_dbg(mmc_dev(smc_host->mmc), "clk is now %d\n", newrate);
> +
> +	sunxi_mmc_oclk_onoff(smc_host, 0);
> +	/* clear internal divider */
> +	temp = mci_readl(smc_host, REG_CLKCR);
> +	temp &= ~0xff;
> +	mci_writel(smc_host, REG_CLKCR, temp);
> +
> +	/* determine delays */
> +	if (rate <= 400000) {
> +		dly = &mmc_clk_dly[MMC_CLK_400K];
> +	} else if (rate <= 25000000) {
> +		dly = &mmc_clk_dly[MMC_CLK_25M];
> +	} else if (rate <= 50000000) {
> +		if (smc_host->ddr) {
> +			if (smc_host->bus_width == 8)
> +				dly = &mmc_clk_dly[MMC_CLK_50MDDR_8BIT];
> +			else
> +				dly = &mmc_clk_dly[MMC_CLK_50MDDR];
> +		} else {
> +			dly = &mmc_clk_dly[MMC_CLK_50M];
> +		}
> +	} else if (rate <= 104000000) {
> +		dly = &mmc_clk_dly[MMC_CLK_100M];
> +	} else if (rate <= 208000000) {
> +		dly = &mmc_clk_dly[MMC_CLK_200M];
> +	} else
> +		dly = &mmc_clk_dly[MMC_CLK_50M];

You need some brackets around that else statement

> +
> +	oclk_dly = dly->oclk_dly;
> +	sclk_dly = dly->sclk_dly;
> +
> +	src_clk = clk_get_rate(clk_get_parent(smc_host->clk_mod));
> +	if (src_clk >= 300000000 && src_clk <= 400000000) {
> +		if (oclk_dly)
> +			oclk_dly--;
> +		if (sclk_dly)
> +			sclk_dly--;
> +	}
> +
> +	sunxi_mmc_set_clk_dly(smc_host, oclk_dly, sclk_dly);
> +	sunxi_mmc_oclk_onoff(smc_host, 1);
> +
> +	/* oclk_onoff sets various irq status bits, clear these */
> +	mci_writel(smc_host, REG_RINTR,
> +		   mci_readl(smc_host, REG_RINTR) & ~SDXC_SDIOInt);
> +}
> +
> +static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +	u32 temp;
> +	s32 err;
> +
> +	/* Set the power state */
> +	switch (ios->power_mode) {
> +	case MMC_POWER_ON:
> +		break;
> +
> +	case MMC_POWER_UP:
> +		if (!IS_ERR(host->vmmc)) {
> +			mmc_regulator_set_ocr(host->mmc, host->vmmc, ios->vdd);
> +			udelay(200);
> +		}
> +
> +		err =  clk_prepare_enable(host->clk_ahb);
> +		if (err) {
> +			dev_err(mmc_dev(host->mmc), "AHB clk err %d\n", err);
> +			host->ferror = 1;
> +			return;
> +		}
> +		err =  clk_prepare_enable(host->clk_mod);
> +		if (err) {
> +			dev_err(mmc_dev(host->mmc), "MOD clk err %d\n", err);
> +			host->ferror = 1;
> +			return;
> +		}
> +
> +		sunxi_mmc_init_host(mmc);
> +		enable_irq(host->irq);
> +
> +		dev_dbg(mmc_dev(host->mmc), "power on!\n");
> +		host->ferror = 0;
> +		break;
> +
> +	case MMC_POWER_OFF:
> +		dev_dbg(mmc_dev(host->mmc), "power off!\n");
> +		disable_irq(host->irq);
> +		sunxi_mmc_exit_host(host);
> +		clk_disable_unprepare(host->clk_ahb);
> +		clk_disable_unprepare(host->clk_mod);
> +		if (!IS_ERR(host->vmmc))
> +			mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
> +		host->ferror = 0;
> +		break;
> +	}
> +
> +	/* set bus width */
> +	switch (ios->bus_width) {
> +	case MMC_BUS_WIDTH_1:
> +		mci_writel(host, REG_WIDTH, SDXC_WIDTH1);
> +		host->bus_width = 1;
> +		break;
> +	case MMC_BUS_WIDTH_4:
> +		mci_writel(host, REG_WIDTH, SDXC_WIDTH4);
> +		host->bus_width = 4;
> +		break;
> +	case MMC_BUS_WIDTH_8:
> +		mci_writel(host, REG_WIDTH, SDXC_WIDTH8);
> +		host->bus_width = 8;
> +		break;
> +	}
> +
> +	/* set ddr mode */
> +	temp = mci_readl(host, REG_GCTRL);
> +	if (ios->timing == MMC_TIMING_UHS_DDR50) {
> +		temp |= SDXC_DDR_MODE;
> +		host->ddr = 1;
> +	} else {
> +		temp &= ~SDXC_DDR_MODE;
> +		host->ddr = 0;
> +	}
> +	mci_writel(host, REG_GCTRL, temp);
> +
> +	/* set up clock */
> +	if (ios->clock && ios->power_mode) {
> +		dev_dbg(mmc_dev(host->mmc), "ios->clock: %d\n", ios->clock);
> +		sunxi_mmc_clk_set_rate(host, ios->clock);
> +		usleep_range(50000, 55000);
> +	}
> +}
> +
> +static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> +{
> +	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
> +	unsigned long flags;
> +	u32 imask;
> +
> +	spin_lock_irqsave(&smc_host->lock, flags);
> +	imask = mci_readl(smc_host, REG_IMASK);
> +	if (enable) {
> +		smc_host->sdio_imask = SDXC_SDIOInt;
> +		imask |= SDXC_SDIOInt;
> +	} else {
> +		smc_host->sdio_imask = 0;
> +		imask &= ~SDXC_SDIOInt;
> +	}
> +	mci_writel(smc_host, REG_IMASK, imask);
> +	spin_unlock_irqrestore(&smc_host->lock, flags);
> +}
> +
> +static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
> +{
> +	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
> +	mci_writel(smc_host, REG_HWRST, 0);
> +	udelay(10);
> +	mci_writel(smc_host, REG_HWRST, 1);
> +	udelay(300);
> +}
> +
> +static int sunxi_mmc_card_present(struct mmc_host *mmc)
> +{
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +
> +	switch (host->cd_mode) {
> +	case CARD_DETECT_BY_GPIO_POLL:
> +		return !gpio_get_value(host->cd_pin); /* Signal inverted */
> +	case CARD_ALWAYS_PRESENT:
> +		return 1;
> +	}
> +	return 0; /* Never reached */
> +}
> +
> +static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> +{
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +	struct mmc_command *cmd = mrq->cmd;
> +	struct mmc_data *data = mrq->data;
> +	unsigned long iflags;
> +	u32 imask = SDXC_IntErrBit;
> +	u32 cmd_val = SDXC_Start | (cmd->opcode & 0x3f);
> +	u32 byte_cnt = 0;
> +	int ret;
> +
> +	if (!sunxi_mmc_card_present(mmc) || host->ferror) {
> +		dev_dbg(mmc_dev(host->mmc), "no medium present\n");
> +		mrq->cmd->error = -ENOMEDIUM;
> +		mmc_request_done(mmc, mrq);
> +		return;
> +	}
> +
> +	if (data) {
> +		byte_cnt = data->blksz * data->blocks;
> +		mci_writel(host, REG_BLKSZ, data->blksz);
> +		mci_writel(host, REG_BCNTR, byte_cnt);
> +		ret = sunxi_mmc_prepare_dma(host, data);
> +		if (ret < 0) {
> +			dev_err(mmc_dev(host->mmc), "prepare DMA failed\n");
> +			cmd->error = ret;
> +			cmd->data->error = ret;
> +			mmc_request_done(host->mmc, mrq);
> +			return;
> +		}
> +	}
> +
> +	if (cmd->opcode == MMC_GO_IDLE_STATE) {
> +		cmd_val |= SDXC_SendInitSeq;
> +		imask |= SDXC_CmdDone;
> +	}
> +
> +	if (cmd->opcode == SD_SWITCH_VOLTAGE) {
> +		cmd_val |= SDXC_VolSwitch;
> +		imask |= SDXC_VolChgDone;
> +		host->voltage_switching = 1;
> +		sunxi_mmc_oclk_onoff(host, 1);
> +	}
> +
> +	if (cmd->flags & MMC_RSP_PRESENT) {
> +		cmd_val |= SDXC_RspExp;
> +		if (cmd->flags & MMC_RSP_136)
> +			cmd_val |= SDXC_LongRsp;
> +		if (cmd->flags & MMC_RSP_CRC)
> +			cmd_val |= SDXC_CheckRspCRC;
> +
> +		if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) {
> +			cmd_val |= SDXC_DataExp | SDXC_WaitPreOver;
> +			if (cmd->data->flags & MMC_DATA_STREAM) {
> +				imask |= SDXC_AutoCMDDone;
> +				cmd_val |= SDXC_Seqmod | SDXC_SendAutoStop;
> +			}
> +			if (cmd->data->stop) {
> +				imask |= SDXC_AutoCMDDone;
> +				cmd_val |= SDXC_SendAutoStop;
> +			} else
> +				imask |= SDXC_DataOver;
> +
> +			if (cmd->data->flags & MMC_DATA_WRITE)
> +				cmd_val |= SDXC_Write;
> +			else
> +				host->wait_dma = 1;
> +		} else
> +			imask |= SDXC_CmdDone;
> +	} else
> +		imask |= SDXC_CmdDone;
> +
> +	dev_dbg(mmc_dev(host->mmc), "cmd %d(%08x) arg %x ie 0x%08x len %d\n",
> +		cmd_val & 0x3f, cmd_val, cmd->arg, imask,
> +		mrq->data ? mrq->data->blksz * mrq->data->blocks : 0);
> +
> +	spin_lock_irqsave(&host->lock, iflags);
> +	host->mrq = mrq;
> +	mci_writel(host, REG_IMASK, host->sdio_imask | imask);
> +	spin_unlock_irqrestore(&host->lock, iflags);
> +
> +	mci_writel(host, REG_CARG, cmd->arg);
> +	mci_writel(host, REG_CMDR, cmd_val);
> +}
> +
> +static const struct of_device_id sunxi_mmc_of_match[] = {
> +	{ .compatible = "allwinner,sun4i-mmc", },
> +	{ .compatible = "allwinner,sun5i-mmc", },

Please use sun5i-a13-mmc as your compatible.


> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
> +
> +static struct mmc_host_ops sunxi_mmc_ops = {
> +	.request	 = sunxi_mmc_request,
> +	.set_ios	 = sunxi_mmc_set_ios,
> +	.get_ro		 = sunxi_mmc_get_ro,
> +	.get_cd		 = sunxi_mmc_card_present,
> +	.enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
> +	.hw_reset	 = sunxi_mmc_hw_reset,
> +};
> +
> +static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
> +				      struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int ret;
> +
> +	if (of_device_is_compatible(np, "allwinner,sun4i-mmc"))
> +		host->idma_des_size_bits = 13;
> +	else
> +		host->idma_des_size_bits = 16;
> +
> +	host->vmmc = devm_regulator_get_optional(&pdev->dev, "vmmc");
> +	if (IS_ERR(host->vmmc) && PTR_ERR(host->vmmc) == -EPROBE_DEFER)
> +		return -EPROBE_DEFER;
> +
> +	host->reg_base = devm_ioremap_resource(&pdev->dev,
> +			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
> +	if (IS_ERR(host->reg_base))
> +		return PTR_ERR(host->reg_base);
> +
> +	host->irq = platform_get_irq(pdev, 0);
> +	ret = devm_request_irq(&pdev->dev, host->irq, sunxi_mmc_irq, 0,
> +			       "sunxi-mci", host);
> +	if (ret)
> +		return ret;
> +	disable_irq(host->irq);
> +
> +	host->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
> +	if (IS_ERR(host->clk_ahb)) {
> +		dev_err(&pdev->dev, "Could not get ahb clock\n");
> +		return PTR_ERR(host->clk_ahb);
> +	}
> +
> +	host->clk_mod = devm_clk_get(&pdev->dev, "mod");
> +	if (IS_ERR(host->clk_mod)) {
> +		dev_err(&pdev->dev, "Could not get mod clock\n");
> +		return PTR_ERR(host->clk_mod);
> +	}
> +
> +	of_property_read_u32(np, "bus-width", &host->bus_width);
> +	if (host->bus_width != 1 && host->bus_width != 4) {
> +		dev_err(&pdev->dev, "Invalid bus-width %d\n", host->bus_width);
> +		return -EINVAL;
> +	}
> +
> +	of_property_read_u32(np, "cd-mode", &host->cd_mode);
> +	switch (host->cd_mode) {
> +	case CARD_DETECT_BY_GPIO_POLL:
> +		host->cd_pin = of_get_named_gpio(np, "cd-gpios", 0);
> +		if (!gpio_is_valid(host->cd_pin)) {
> +			dev_err(&pdev->dev, "Invalid cd-gpios\n");
> +			return -EINVAL;
> +		}
> +		ret = devm_gpio_request(&pdev->dev, host->cd_pin, "mmc_cd");
> +		if (ret) {
> +			dev_err(&pdev->dev, "Could not get cd-gpios\n");
> +			return ret;
> +		}
> +		gpio_direction_input(host->cd_pin);
> +		break;
> +	case CARD_ALWAYS_PRESENT:
> +		break;
> +	default:
> +		dev_err(&pdev->dev, "Invalid cd-mode %d\n", host->cd_mode);
> +		return -EINVAL;
> +	}
> +
> +	host->wp_pin = of_get_named_gpio(np, "wp-gpios", 0);
> +	if (gpio_is_valid(host->wp_pin)) {
> +		ret = devm_gpio_request(&pdev->dev, host->wp_pin, "mmc_wp");
> +		if (ret) {
> +			dev_err(&pdev->dev, "Could not get wp-gpios\n");
> +			return ret;
> +		}
> +		gpio_direction_input(host->wp_pin);
> +	}
> +
> +	return 0;
> +}
> +
> +static int sunxi_mmc_probe(struct platform_device *pdev)
> +{
> +	struct sunxi_mmc_host *host;
> +	struct mmc_host *mmc;
> +	int ret;
> +
> +	mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);
> +	if (!mmc) {
> +		dev_err(&pdev->dev, "mmc alloc host failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	host = mmc_priv(mmc);
> +	host->mmc = mmc;
> +	spin_lock_init(&host->lock);
> +	tasklet_init(&host->tasklet, sunxi_mmc_tasklet, (unsigned long)host);
> +
> +	ret = sunxi_mmc_resource_request(host, pdev);
> +	if (ret)
> +		goto error_free_host;
> +
> +	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
> +					  &host->sg_dma, GFP_KERNEL);
> +	if (!host->sg_cpu) {
> +		dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n");
> +		ret = -ENOMEM;
> +		goto error_free_host;
> +	}
> +
> +	mmc->ops		= &sunxi_mmc_ops;
> +	mmc->max_blk_count	= 8192;
> +	mmc->max_blk_size	= 4096;
> +	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
> +	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
> +	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
> +	/* 400kHz ~ 50MHz */
> +	mmc->f_min		=   400000;
> +	mmc->f_max		= 50000000;

Hmmm, the tables earlier seem to suggest it can do much more than that.

> +	/* available voltages */
> +	if (!IS_ERR(host->vmmc))
> +		mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vmmc);
> +	else
> +		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
> +
> +	mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
> +		MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
> +		MMC_CAP_UHS_DDR50 | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL |
> +		MMC_CAP_DRIVER_TYPE_A;

Please add a newline.

> +	if (host->bus_width == 4)
> +		mmc->caps |= MMC_CAP_4_BIT_DATA;

Please add a newline.

> +	mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP;
> +
> +	ret = mmc_add_host(mmc);
> +	if (ret)
> +		goto error_free_dma;
> +
> +	dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq);
> +	platform_set_drvdata(pdev, mmc);
> +	return 0;
> +
> +error_free_dma:
> +	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
> +error_free_host:
> +	mmc_free_host(mmc);
> +	return ret;
> +}
> +
> +static int sunxi_mmc_remove(struct platform_device *pdev)
> +{
> +	struct mmc_host	*mmc = platform_get_drvdata(pdev);
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +
> +	mmc_remove_host(mmc);
> +	sunxi_mmc_exit_host(host);
> +	tasklet_disable(&host->tasklet);
> +	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
> +	mmc_free_host(mmc);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver sunxi_mmc_driver = {
> +	.driver = {
> +		.name	= "sunxi-mci",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(sunxi_mmc_of_match),
> +	},
> +	.probe		= sunxi_mmc_probe,
> +	.remove		= sunxi_mmc_remove,
> +};
> +module_platform_driver(sunxi_mmc_driver);
> +
> +MODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("David Lanzend?rfer <david.lanzendoerfer-Z7Kmv9EsliU@public.gmane.org>");
> +MODULE_ALIAS("platform:sunxi-mmc");
> diff --git a/drivers/mmc/host/sunxi-mci.h b/drivers/mmc/host/sunxi-mci.h
> new file mode 100644
> index 0000000..332d3ae
> --- /dev/null
> +++ b/drivers/mmc/host/sunxi-mci.h
> @@ -0,0 +1,246 @@
> +/*
> + * Driver for sunxi SD/MMC host controllers
> + * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
> + * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh-jFKXxz0WcGyYHARAtoI1EgC/G2K4zDHf@public.gmane.org>
> + * (C) Copyright 2013-2013 O2S GmbH <www.o2s.ch>
> + * (C) Copyright 2013-2013 David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
> + * (C) Copyright 2013-2013 Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef __SUNXI_MCI_H__
> +#define __SUNXI_MCI_H__
> +
> +/* register offset define */
> +#define SDXC_REG_GCTRL	(0x00) /* SMC Global Control Register */
> +#define SDXC_REG_CLKCR	(0x04) /* SMC Clock Control Register */
> +#define SDXC_REG_TMOUT	(0x08) /* SMC Time Out Register */
> +#define SDXC_REG_WIDTH	(0x0C) /* SMC Bus Width Register */
> +#define SDXC_REG_BLKSZ	(0x10) /* SMC Block Size Register */
> +#define SDXC_REG_BCNTR	(0x14) /* SMC Byte Count Register */
> +#define SDXC_REG_CMDR	(0x18) /* SMC Command Register */
> +#define SDXC_REG_CARG	(0x1C) /* SMC Argument Register */
> +#define SDXC_REG_RESP0	(0x20) /* SMC Response Register 0 */
> +#define SDXC_REG_RESP1	(0x24) /* SMC Response Register 1 */
> +#define SDXC_REG_RESP2	(0x28) /* SMC Response Register 2 */
> +#define SDXC_REG_RESP3	(0x2C) /* SMC Response Register 3 */
> +#define SDXC_REG_IMASK	(0x30) /* SMC Interrupt Mask Register */
> +#define SDXC_REG_MISTA	(0x34) /* SMC Masked Interrupt Status Register */
> +#define SDXC_REG_RINTR	(0x38) /* SMC Raw Interrupt Status Register */
> +#define SDXC_REG_STAS	(0x3C) /* SMC Status Register */
> +#define SDXC_REG_FTRGL	(0x40) /* SMC FIFO Threshold Watermark Registe */
> +#define SDXC_REG_FUNS	(0x44) /* SMC Function Select Register */
> +#define SDXC_REG_CBCR	(0x48) /* SMC CIU Byte Count Register */
> +#define SDXC_REG_BBCR	(0x4C) /* SMC BIU Byte Count Register */
> +#define SDXC_REG_DBGC	(0x50) /* SMC Debug Enable Register */
> +#define SDXC_REG_HWRST	(0x78) /* SMC Card Hardware Reset for Register */
> +#define SDXC_REG_DMAC	(0x80) /* SMC IDMAC Control Register */
> +#define SDXC_REG_DLBA	(0x84) /* SMC IDMAC Descriptor List Base Addre */
> +#define SDXC_REG_IDST	(0x88) /* SMC IDMAC Status Register */
> +#define SDXC_REG_IDIE	(0x8C) /* SMC IDMAC Interrupt Enable Register */
> +#define SDXC_REG_CHDA	(0x90)
> +#define SDXC_REG_CBDA	(0x94)
> +
> +#define mci_readl(host, reg) \
> +	__raw_readl((host)->reg_base + SDXC_##reg)
> +#define mci_writel(host, reg, value) \
> +	__raw_writel((value), (host)->reg_base + SDXC_##reg)

No barriers ? :(

> +/* global control register bits */
> +#define SDXC_SoftReset		BIT(0)
> +#define SDXC_FIFOReset		BIT(1)
> +#define SDXC_DMAReset		BIT(2)
> +#define SDXC_HWReset		(SDXC_SoftReset|SDXC_FIFOReset|SDXC_DMAReset)
> +#define SDXC_INTEnb		BIT(4)
> +#define SDXC_DMAEnb		BIT(5)
> +#define SDXC_DebounceEnb	BIT(8)
> +#define SDXC_PosedgeLatchData	BIT(9)
> +#define SDXC_DDR_MODE		BIT(10)
> +#define SDXC_MemAccessDone	BIT(29)
> +#define SDXC_AccessDoneDirect	BIT(30)
> +#define SDXC_ACCESS_BY_AHB	BIT(31)
> +#define SDXC_ACCESS_BY_DMA	(0U << 31)
> +/* clock control bits */
> +#define SDXC_CardClkOn		BIT(16)
> +#define SDXC_LowPowerOn		BIT(17)
> +/* bus width */
> +#define SDXC_WIDTH1		(0)
> +#define SDXC_WIDTH4		(1)
> +#define SDXC_WIDTH8		(2)
> +/* smc command bits */
> +#define SDXC_RspExp		BIT(6)
> +#define SDXC_LongRsp		BIT(7)
> +#define SDXC_CheckRspCRC	BIT(8)
> +#define SDXC_DataExp		BIT(9)
> +#define SDXC_Write		BIT(10)
> +#define SDXC_Seqmod		BIT(11)
> +#define SDXC_SendAutoStop	BIT(12)
> +#define SDXC_WaitPreOver	BIT(13)
> +#define SDXC_StopAbortCMD	BIT(14)
> +#define SDXC_SendInitSeq	BIT(15)
> +#define SDXC_UPCLKOnly		BIT(21)
> +#define SDXC_RdCEATADev		BIT(22)
> +#define SDXC_CCSExp		BIT(23)
> +#define SDXC_EnbBoot		BIT(24)
> +#define SDXC_AltBootOpt		BIT(25)
> +#define SDXC_BootACKExp		BIT(26)
> +#define SDXC_BootAbort		BIT(27)
> +#define SDXC_VolSwitch	        BIT(28)
> +#define SDXC_UseHoldReg	        BIT(29)
> +#define SDXC_Start	        BIT(31)
> +/* interrupt bits */
> +#define SDXC_RespErr		BIT(1)
> +#define SDXC_CmdDone		BIT(2)
> +#define SDXC_DataOver		BIT(3)
> +#define SDXC_TxDataReq		BIT(4)
> +#define SDXC_RxDataReq		BIT(5)
> +#define SDXC_RespCRCErr		BIT(6)
> +#define SDXC_DataCRCErr		BIT(7)
> +#define SDXC_RespTimeout	BIT(8)
> +#define SDXC_DataTimeout	BIT(9)
> +#define SDXC_VolChgDone		BIT(10)
> +#define SDXC_FIFORunErr		BIT(11)
> +#define SDXC_HardWLocked	BIT(12)
> +#define SDXC_StartBitErr	BIT(13)
> +#define SDXC_AutoCMDDone	BIT(14)
> +#define SDXC_EndBitErr		BIT(15)
> +#define SDXC_SDIOInt		BIT(16)
> +#define SDXC_CardInsert		BIT(30)
> +#define SDXC_CardRemove		BIT(31)
> +#define SDXC_IntErrBit		(SDXC_RespErr | SDXC_RespCRCErr | \
> +				 SDXC_DataCRCErr | SDXC_RespTimeout | \
> +				 SDXC_DataTimeout | SDXC_FIFORunErr | \
> +				 SDXC_HardWLocked | SDXC_StartBitErr | \
> +				 SDXC_EndBitErr) /* 0xbbc2 */
> +#define SDXC_IntDoneBit		(SDXC_AutoCMDDone | SDXC_DataOver | \
> +				 SDXC_CmdDone | SDXC_VolChgDone)
> +/* status */
> +#define SDXC_RXWLFlag		BIT(0)
> +#define SDXC_TXWLFlag		BIT(1)
> +#define SDXC_FIFOEmpty		BIT(2)
> +#define SDXC_FIFOFull		BIT(3)
> +#define SDXC_CardPresent	BIT(8)
> +#define SDXC_CardDataBusy	BIT(9)
> +#define SDXC_DataFSMBusy	BIT(10)
> +#define SDXC_DMAReq		BIT(31)
> +#define SDXC_FIFO_SIZE		(16)
> +/* Function select */
> +#define SDXC_CEATAOn		(0xceaaU << 16)
> +#define SDXC_SendIrqRsp		BIT(0)
> +#define SDXC_SDIORdWait		BIT(1)
> +#define SDXC_AbtRdData		BIT(2)
> +#define SDXC_SendCCSD		BIT(8)
> +#define SDXC_SendAutoStopCCSD	BIT(9)
> +#define SDXC_CEATADevIntEnb	BIT(10)
> +/* IDMA controller bus mod bit field */
> +#define SDXC_IDMACSoftRST	BIT(0)
> +#define SDXC_IDMACFixBurst	BIT(1)
> +#define SDXC_IDMACIDMAOn	BIT(7)
> +#define SDXC_IDMACRefetchDES	BIT(31)
> +/* IDMA status bit field */
> +#define SDXC_IDMACTransmitInt	BIT(0)
> +#define SDXC_IDMACReceiveInt	BIT(1)
> +#define SDXC_IDMACFatalBusErr	BIT(2)
> +#define SDXC_IDMACDesInvalid	BIT(4)
> +#define SDXC_IDMACCardErrSum	BIT(5)
> +#define SDXC_IDMACNormalIntSum	BIT(8)
> +#define SDXC_IDMACAbnormalIntSum BIT(9)
> +#define SDXC_IDMACHostAbtInTx	BIT(10)
> +#define SDXC_IDMACHostAbtInRx	BIT(10)
> +#define SDXC_IDMACIdle		(0U << 13)
> +#define SDXC_IDMACSuspend	(1U << 13)
> +#define SDXC_IDMACDESCRd	(2U << 13)
> +#define SDXC_IDMACDESCCheck	(3U << 13)
> +#define SDXC_IDMACRdReqWait	(4U << 13)
> +#define SDXC_IDMACWrReqWait	(5U << 13)
> +#define SDXC_IDMACRd		(6U << 13)
> +#define SDXC_IDMACWr		(7U << 13)
> +#define SDXC_IDMACDESCClose	(8U << 13)
> +
> +struct sunxi_idma_des {
> +	u32	config;
> +#define SDXC_IDMAC_DES0_DIC	BIT(1)  /* disable interrupt on completion */
> +#define SDXC_IDMAC_DES0_LD	BIT(2)  /* last descriptor */
> +#define SDXC_IDMAC_DES0_FD	BIT(3)  /* first descriptor */
> +#define SDXC_IDMAC_DES0_CH	BIT(4)  /* chain mode */
> +#define SDXC_IDMAC_DES0_ER	BIT(5)  /* end of ring */
> +#define SDXC_IDMAC_DES0_CES	BIT(30) /* card error summary */
> +#define SDXC_IDMAC_DES0_OWN	BIT(31) /* 1-idma owns it, 0-host owns it */
> +
> +	/*
> +	 * If the idma-des-size-bits of property is ie 13, bufsize bits are:
> +	 *  Bits  0-12: buf1 size
> +	 *  Bits 13-25: buf2 size
> +	 *  Bits 26-31: not used
> +	 * Since we only ever set buf1 size, we can simply store it directly.
> +	 */
> +	u32	buf_size;
> +	u32	buf_addr_ptr1;
> +	u32	buf_addr_ptr2;
> +};
> +
> +struct sunxi_mmc_host {
> +	struct mmc_host *mmc;
> +	struct regulator *vmmc;
> +
> +	/* IO mapping base */
> +	void __iomem *reg_base;
> +
> +	spinlock_t lock;
> +	struct tasklet_struct tasklet;
> +
> +	/* clock management */
> +	struct clk *clk_ahb;
> +	struct clk *clk_mod;
> +
> +	/* indicator pins */
> +	int wp_pin;
> +	int cd_pin;
> +	int cd_mode;
> +#define CARD_DETECT_BY_GPIO_POLL (1)	/* mmc detected by gpio check */
> +#define CARD_ALWAYS_PRESENT      (2)	/* mmc always present */

Just a question here, have you tested to use the external interrupts?
(Is that even possible on the pins that are used as card detect?)

> +	/* ios information */
> +	u32		clk_mod_rate;
> +	u32		bus_width;
> +	u32		idma_des_size_bits;
> +	u32		ddr;
> +	u32		voltage_switching;
> +
> +	/* irq */
> +	int		irq;
> +	u32		int_sum;
> +	u32		sdio_imask;
> +
> +	/* flags */
> +	u32		power_on:1;
> +	u32		io_flag:1;
> +	u32		wait_dma:1;
> +
> +	dma_addr_t	sg_dma;
> +	void		*sg_cpu;
> +
> +	struct mmc_request *mrq;
> +	u32		ferror;
> +};
> +
> +#define MMC_CLK_400K            0
> +#define MMC_CLK_25M             1
> +#define MMC_CLK_50M             2
> +#define MMC_CLK_50MDDR          3
> +#define MMC_CLK_50MDDR_8BIT     4
> +#define MMC_CLK_100M            5
> +#define MMC_CLK_200M            6
> +#define MMC_CLK_MOD_NUM         7
> +
> +struct sunxi_mmc_clk_dly {
> +	u32 mode;
> +	u32 oclk_dly;
> +	u32 sclk_dly;
> +};
> +
> +#endif
> diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
> new file mode 100644
> index 0000000..1ef5c89
> --- /dev/null
> +++ b/include/linux/clk/sunxi.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright 2013 - Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __LINUX_CLK_SUNXI_H_
> +#define __LINUX_CLK_SUNXI_H_
> +
> +#include <linux/clk.h>
> +
> +void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
> +
> +#endif

Hmmm, I see no implementation for this function. Didn't you forget
a file here? (and it should probably be a separate patch anyway).

Thanks a lot for this work,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 13:44         ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-15 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Hans,

I won't comment on the MMC driver itself, and leave Chris comment on
that, but still, I have a few things.

On Sat, Dec 14, 2013 at 10:58:11PM +0100, Hans de Goede wrote:
> From: David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
> 
> This is based on the driver Allwinner ships in there Android kernel sources.
> 
> Initial porting to upstream kernels done by David Lanzend?rfer, additional
> fixes and cleanups by Hans de Goede.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Your commit log is a bit sparse. What capabilities this controller
has? Is it using DMA? If so, how? What SoCs are supported/it has been
tested on? etc.

Also, you probably needs David's SoB here.

> ---
>  drivers/mmc/host/Kconfig     |   8 +
>  drivers/mmc/host/Makefile    |   2 +
>  drivers/mmc/host/sunxi-mci.c | 908 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sunxi-mci.h | 246 ++++++++++++
>  include/linux/clk/sunxi.h    |  22 ++

Please add your dt bindings documentation in Documentation/devicetree/bindings

>  5 files changed, 1186 insertions(+)
>  create mode 100644 drivers/mmc/host/sunxi-mci.c
>  create mode 100644 drivers/mmc/host/sunxi-mci.h
>  create mode 100644 include/linux/clk/sunxi.h
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 7fc5099..69a7171 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
>  	help
>  	  Say Y here to include driver code to support SD/MMC card interface
>  	  of Realtek PCI-E card reader
> +
> +config MMC_SUNXI
> +	tristate "Allwinner sunxi SD/MMC Host Controller support"
> +	depends on ARCH_SUNXI
> +	default y

I'm not that fond of these "default y" patterns. It forces the driver
down to every user of the multiplatform kernels. I'd suggest removing
the default and adding the driver to the defconfigs we have.

> +	help
> +	  This selects support for the SD/MMC Host Controller on
> +	  Allwinner sunxi SoCs.
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index c41d0c3..f76f783 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -52,6 +52,8 @@ obj-$(CONFIG_MMC_WMT)		+= wmt-sdmmc.o
>  
>  obj-$(CONFIG_MMC_REALTEK_PCI)	+= rtsx_pci_sdmmc.o
>  
> +obj-$(CONFIG_MMC_SUNXI)		+= sunxi-mci.o
> +
>  obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
>  obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
>  obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
> diff --git a/drivers/mmc/host/sunxi-mci.c b/drivers/mmc/host/sunxi-mci.c
> new file mode 100644
> index 0000000..e091ebb
> --- /dev/null
> +++ b/drivers/mmc/host/sunxi-mci.c
> @@ -0,0 +1,908 @@
> +/*
> + * Driver for sunxi SD/MMC host controllers
> + * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
> + * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com>
> + * (C) Copyright 2013-2013 O2S GmbH <www.o2s.ch>
> + * (C) Copyright 2013-2013 David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
> + * (C) Copyright 2013-2013 Hans de Goede <hdegoede@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +
> +#include <linux/clk.h>
> +#include <linux/clk-private.h>
> +#include <linux/clk/sunxi.h>
> +
> +#include <linux/gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/scatterlist.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/slab.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <linux/of_address.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_platform.h>
> +
> +#include <linux/mmc/host.h>
> +#include <linux/mmc/sd.h>
> +#include <linux/mmc/mmc.h>
> +#include <linux/mmc/core.h>
> +#include <linux/mmc/card.h>
> +
> +#include "sunxi-mci.h"
> +
> +static void sunxi_mmc_init_host(struct mmc_host *mmc)
> +{
> +	u32 rval;
> +	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
> +
> +	/* reset controller */
> +	rval = mci_readl(smc_host, REG_GCTRL) | SDXC_HWReset;
> +	mci_writel(smc_host, REG_GCTRL, rval);
> +
> +	mci_writel(smc_host, REG_FTRGL, 0x20070008);
> +	mci_writel(smc_host, REG_TMOUT, 0xffffffff);
> +	mci_writel(smc_host, REG_IMASK, smc_host->sdio_imask);
> +	mci_writel(smc_host, REG_RINTR, 0xffffffff);
> +	mci_writel(smc_host, REG_DBGC, 0xdeb);
> +	mci_writel(smc_host, REG_FUNS, 0xceaa0000);
> +	mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);

I suppose we have no idea what these magics are all about ? :(

> +	rval = mci_readl(smc_host, REG_GCTRL)|SDXC_INTEnb;
> +	rval &= ~SDXC_AccessDoneDirect;
> +	mci_writel(smc_host, REG_GCTRL, rval);
> +}
> +
> +static void sunxi_mmc_exit_host(struct sunxi_mmc_host *smc_host)
> +{
> +	mci_writel(smc_host, REG_GCTRL, SDXC_HWReset);
> +}
> +
> +/* /\* UHS-I Operation Modes */
> +/*  * DS		25MHz	12.5MB/s	3.3V */
> +/*  * HS		50MHz	25MB/s		3.3V */
> +/*  * SDR12	25MHz	12.5MB/s	1.8V */
> +/*  * SDR25	50MHz	25MB/s		1.8V */
> +/*  * SDR50	100MHz	50MB/s		1.8V */
> +/*  * SDR104	208MHz	104MB/s		1.8V */
> +/*  * DDR50	50MHz	50MB/s		1.8V */
> +/*  * MMC Operation Modes */
> +/*  * DS		26MHz	26MB/s		3/1.8/1.2V */
> +/*  * HS		52MHz	52MB/s		3/1.8/1.2V */
> +/*  * HSDDR	52MHz	104MB/s		3/1.8/1.2V */
> +/*  * HS200	200MHz	200MB/s		1.8/1.2V */
> +/*  * */
> +/*  * Spec. Timing */
> +/*  * SD3.0 */
> +/*  * Fcclk    Tcclk   Fsclk   Tsclk   Tis     Tih     odly  RTis     RTih */
> +/*  * 400K     2.5us   24M     41ns    5ns     5ns     1     2209ns   41ns */
> +/*  * 25M      40ns    600M    1.67ns  5ns     5ns     3     14.99ns  5.01ns */
> +/*  * 50M      20ns    600M    1.67ns  6ns     2ns     3     14.99ns  5.01ns */
> +/*  * 50MDDR   20ns    600M    1.67ns  6ns     0.8ns   2     6.67ns   3.33ns */
> +/*  * 104M     9.6ns   600M    1.67ns  3ns     0.8ns   1     7.93ns   1.67ns */
> +/*  * 208M     4.8ns   600M    1.67ns  1.4ns   0.8ns   1     3.33ns   1.67ns */
> +
> +/*  * 25M      40ns    300M    3.33ns  5ns     5ns     2     13.34ns   6.66ns */
> +/*  * 50M      20ns    300M    3.33ns  6ns     2ns     2     13.34ns   6.66ns */
> +/*  * 50MDDR   20ns    300M    3.33ns  6ns     0.8ns   1     6.67ns    3.33ns */
> +/*  * 104M     9.6ns   300M    3.33ns  3ns     0.8ns   0     7.93ns    1.67ns */
> +/*  * 208M     4.8ns   300M    3.33ns  1.4ns   0.8ns   0     3.13ns    1.67ns */
> +
> +/*  * eMMC4.5 */
> +/*  * 400K     2.5us   24M     41ns    3ns     3ns     1     2209ns    41ns */
> +/*  * 25M      40ns    600M    1.67ns  3ns     3ns     3     14.99ns   5.01ns */
> +/*  * 50M      20ns    600M    1.67ns  3ns     3ns     3     14.99ns   5.01ns */
> +/*  * 50MDDR   20ns    600M    1.67ns  2.5ns   2.5ns   2     6.67ns    3.33ns */
> +/*  * 200M     5ns     600M    1.67ns  1.4ns   0.8ns   1     3.33ns    1.67ns */
> +/*  *\/ */
> +
> +static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
> +				    struct mmc_data *data)
> +{
> +	struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
> +	struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma;
> +	int i, max_len = (1 << host->idma_des_size_bits);
> +
> +	for (i = 0; i < data->sg_len; i++) {
> +		pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN |
> +				 SDXC_IDMAC_DES0_DIC;
> +
> +		if (data->sg[i].length == max_len)
> +			pdes[i].buf_size = 0; /* 0 == max_len */
> +		else
> +			pdes[i].buf_size = data->sg[i].length;
> +
> +		pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]);
> +		pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1];
> +	}

Please add a newline.

> +	pdes[0].config |= SDXC_IDMAC_DES0_FD;
> +	pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD;
> +
> +	wmb(); /* Ensure idma_des hit main mem before we start the idmac */
> +}
> +
> +static enum dma_data_direction sunxi_mmc_get_dma_dir(struct mmc_data *data)
> +{
> +	if (data->flags & MMC_DATA_WRITE)
> +		return DMA_TO_DEVICE;
> +	else
> +		return DMA_FROM_DEVICE;
> +}
> +
> +static int sunxi_mmc_prepare_dma(struct sunxi_mmc_host *smc_host,
> +				 struct mmc_data *data)
> +{
> +	u32 dma_len;
> +	u32 i;
> +	u32 temp;
> +	struct scatterlist *sg;
> +
> +	dma_len = dma_map_sg(mmc_dev(smc_host->mmc), data->sg, data->sg_len,
> +			     sunxi_mmc_get_dma_dir(data));
> +	if (dma_len == 0) {
> +		dev_err(mmc_dev(smc_host->mmc), "dma_map_sg failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	for_each_sg(data->sg, sg, data->sg_len, i) {
> +		if (sg->offset & 3 || sg->length & 3) {
> +			dev_err(mmc_dev(smc_host->mmc),
> +				"unaligned scatterlist: os %x length %d\n",
> +				sg->offset, sg->length);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	sunxi_mmc_init_idma_des(smc_host, data);
> +
> +	temp = mci_readl(smc_host, REG_GCTRL);
> +	temp |= SDXC_DMAEnb;
> +	mci_writel(smc_host, REG_GCTRL, temp);
> +	temp |= SDXC_DMAReset;
> +	mci_writel(smc_host, REG_GCTRL, temp);
> +
> +	mci_writel(smc_host, REG_DMAC, SDXC_IDMACSoftRST);
> +
> +	if (!(data->flags & MMC_DATA_WRITE))
> +		mci_writel(smc_host, REG_IDIE, SDXC_IDMACReceiveInt);
> +
> +	mci_writel(smc_host, REG_DMAC, SDXC_IDMACFixBurst | SDXC_IDMACIDMAOn);
> +
> +	return 0;
> +}
> +
> +static void sunxi_mmc_send_manual_stop(struct sunxi_mmc_host *host,
> +				       struct mmc_request *req)
> +{
> +	u32 cmd_val = SDXC_Start | SDXC_RspExp | SDXC_StopAbortCMD
> +			| SDXC_CheckRspCRC | MMC_STOP_TRANSMISSION;
> +	u32 ri = 0;
> +	unsigned long expire = jiffies + msecs_to_jiffies(1000);
> +
> +	mci_writel(host, REG_CARG, 0);
> +	mci_writel(host, REG_CMDR, cmd_val);

Please add a newline.

> +	do {
> +		ri = mci_readl(host, REG_RINTR);
> +	} while (!(ri & (SDXC_CmdDone | SDXC_IntErrBit)) &&
> +		 time_before(jiffies, expire));
> +
> +	if (ri & SDXC_IntErrBit) {
> +		dev_err(mmc_dev(host->mmc), "send stop command failed\n");
> +		if (req->stop)
> +			req->stop->resp[0] = -ETIMEDOUT;
> +	} else {
> +		if (req->stop)
> +			req->stop->resp[0] = mci_readl(host, REG_RESP0);
> +	}
> +
> +	mci_writel(host, REG_RINTR, 0xffff);
> +}
> +
> +static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *smc_host)
> +{
> +	struct mmc_command *cmd = smc_host->mrq->cmd;
> +	struct mmc_data *data = smc_host->mrq->data;
> +
> +	/* For some cmds timeout is normal with sd/mmc cards */
> +	if ((smc_host->int_sum & SDXC_IntErrBit) == SDXC_RespTimeout &&
> +			(cmd->opcode == 5 || cmd->opcode == 52))
> +		return;
> +
> +	dev_err(mmc_dev(smc_host->mmc),
> +		"smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
> +		smc_host->mmc->index, cmd->opcode,
> +		data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
> +		smc_host->int_sum & SDXC_RespErr     ? " RE"     : "",
> +		smc_host->int_sum & SDXC_RespCRCErr  ? " RCE"    : "",
> +		smc_host->int_sum & SDXC_DataCRCErr  ? " DCE"    : "",
> +		smc_host->int_sum & SDXC_RespTimeout ? " RTO"    : "",
> +		smc_host->int_sum & SDXC_DataTimeout ? " DTO"    : "",
> +		smc_host->int_sum & SDXC_FIFORunErr  ? " FE"     : "",
> +		smc_host->int_sum & SDXC_HardWLocked ? " HL"     : "",
> +		smc_host->int_sum & SDXC_StartBitErr ? " SBE"    : "",
> +		smc_host->int_sum & SDXC_EndBitErr   ? " EBE"    : ""
> +		);
> +}
> +
> +static void sunxi_mmc_finalize_request(struct sunxi_mmc_host *host)
> +{
> +	struct mmc_request *mrq;
> +	unsigned long iflags;
> +
> +	spin_lock_irqsave(&host->lock, iflags);
> +
> +	mrq = host->mrq;
> +	if (!mrq) {
> +		spin_unlock_irqrestore(&host->lock, iflags);
> +		dev_err(mmc_dev(host->mmc), "no request to finalize\n");
> +		return;
> +	}
> +
> +	if (host->int_sum & SDXC_IntErrBit) {
> +		sunxi_mmc_dump_errinfo(host);
> +		mrq->cmd->error = -ETIMEDOUT;
> +		if (mrq->data)
> +			mrq->data->error = -ETIMEDOUT;
> +		if (mrq->stop)
> +			mrq->stop->error = -ETIMEDOUT;
> +	} else {
> +		if (mrq->cmd->flags & MMC_RSP_136) {
> +			mrq->cmd->resp[0] = mci_readl(host, REG_RESP3);
> +			mrq->cmd->resp[1] = mci_readl(host, REG_RESP2);
> +			mrq->cmd->resp[2] = mci_readl(host, REG_RESP1);
> +			mrq->cmd->resp[3] = mci_readl(host, REG_RESP0);
> +		} else {
> +			mrq->cmd->resp[0] = mci_readl(host, REG_RESP0);
> +		}
> +		if (mrq->data)
> +			mrq->data->bytes_xfered =
> +				mrq->data->blocks * mrq->data->blksz;
> +	}
> +
> +	if (mrq->data) {
> +		struct mmc_data *data = mrq->data;
> +		u32 temp;
> +
> +		mci_writel(host, REG_IDST, 0x337);
> +		mci_writel(host, REG_DMAC, 0);
> +		temp = mci_readl(host, REG_GCTRL);
> +		mci_writel(host, REG_GCTRL, temp|SDXC_DMAReset);
> +		temp &= ~SDXC_DMAEnb;
> +		mci_writel(host, REG_GCTRL, temp);
> +		temp |= SDXC_FIFOReset;
> +		mci_writel(host, REG_GCTRL, temp);
> +		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
> +				     sunxi_mmc_get_dma_dir(data));
> +	}
> +
> +	mci_writel(host, REG_RINTR, 0xffff);
> +
> +	dev_dbg(mmc_dev(host->mmc), "req done, resp %08x %08x %08x %08x\n",
> +		mrq->cmd->resp[0], mrq->cmd->resp[1],
> +		mrq->cmd->resp[2], mrq->cmd->resp[3]);
> +
> +	host->mrq = NULL;
> +	host->int_sum = 0;
> +	host->wait_dma = 0;
> +
> +	spin_unlock_irqrestore(&host->lock, iflags);
> +
> +	if (mrq->data && mrq->data->error) {
> +		dev_err(mmc_dev(host->mmc),
> +			"data error, sending stop command\n");
> +		sunxi_mmc_send_manual_stop(host, mrq);
> +	}
> +
> +	mmc_request_done(host->mmc, mrq);
> +}
> +
> +static s32 sunxi_mmc_get_ro(struct mmc_host *mmc)
> +{
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +
> +	int read_only = 0;
> +
> +	if (gpio_is_valid(host->wp_pin)) {
> +		pinctrl_request_gpio(host->wp_pin);

This is actually not needed. It's already called by gpio_request.

> +		read_only = gpio_get_value(host->wp_pin);
> +	}
> +
> +	return read_only;
> +}
> +
> +static irqreturn_t sunxi_mmc_irq(int irq, void *dev_id)
> +{
> +	struct sunxi_mmc_host *host = dev_id;
> +	u32 finalize = 0;
> +	u32 sdio_int = 0;
> +	u32 msk_int;
> +	u32 idma_int;
> +
> +	spin_lock(&host->lock);
> +
> +	idma_int  = mci_readl(host, REG_IDST);
> +	msk_int   = mci_readl(host, REG_MISTA);
> +
> +	dev_dbg(mmc_dev(host->mmc), "irq: rq %p mi %08x idi %08x\n",
> +		host->mrq, msk_int, idma_int);
> +
> +	if (host->mrq) {
> +		if (idma_int & SDXC_IDMACReceiveInt)
> +			host->wait_dma = 0;
> +
> +		host->int_sum |= msk_int;
> +
> +		/* Wait for CmdDone on RespTimeout before finishing the req */
> +		if ((host->int_sum & SDXC_RespTimeout) &&
> +				!(host->int_sum & SDXC_CmdDone))
> +			mci_writel(host, REG_IMASK,
> +				   host->sdio_imask | SDXC_CmdDone);
> +		else if (host->int_sum & SDXC_IntErrBit)
> +			finalize = 1; /* Don't wait for dma on error */
> +		else if (host->int_sum & SDXC_IntDoneBit && !host->wait_dma)
> +			finalize = 1; /* Done */
> +
> +		if (finalize) {
> +			mci_writel(host, REG_IMASK, host->sdio_imask);
> +			mci_writel(host, REG_IDIE, 0);
> +		}
> +	}
> +
> +	if (msk_int & SDXC_SDIOInt)
> +		sdio_int = 1;
> +
> +	mci_writel(host, REG_RINTR, msk_int);
> +	mci_writel(host, REG_IDST, idma_int);
> +
> +	spin_unlock(&host->lock);
> +
> +	if (finalize)
> +		tasklet_schedule(&host->tasklet);
> +
> +	if (sdio_int)
> +		mmc_signal_sdio_irq(host->mmc);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void sunxi_mmc_tasklet(unsigned long data)
> +{
> +	struct sunxi_mmc_host *smc_host = (struct sunxi_mmc_host *) data;
> +	sunxi_mmc_finalize_request(smc_host);
> +}
> +
> +static void sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
> +{
> +	unsigned long expire = jiffies + msecs_to_jiffies(2000);
> +	u32 rval;
> +
> +	rval = mci_readl(host, REG_CLKCR);
> +	rval &= ~(SDXC_CardClkOn | SDXC_LowPowerOn);

Please add a newline.

> +	if (oclk_en)
> +		rval |= SDXC_CardClkOn;

Please add a newline.

> +	if (!host->io_flag)
> +		rval |= SDXC_LowPowerOn;

Please add a newline.

> +	mci_writel(host, REG_CLKCR, rval);
> +
> +	rval = SDXC_Start | SDXC_UPCLKOnly | SDXC_WaitPreOver;
> +	if (host->voltage_switching)
> +		rval |= SDXC_VolSwitch;
> +	mci_writel(host, REG_CMDR, rval);
> +	do {
> +		rval = mci_readl(host, REG_CMDR);
> +	} while (time_before(jiffies, expire) && (rval & SDXC_Start));
> +
> +	if (rval & SDXC_Start) {
> +		dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n");
> +		host->ferror = 1;
> +	}
> +}
> +
> +static void sunxi_mmc_set_clk_dly(struct sunxi_mmc_host *smc_host,
> +				  u32 oclk_dly, u32 sclk_dly)
> +{
> +	unsigned long iflags;
> +	struct clk_hw *hw = __clk_get_hw(smc_host->clk_mod);
> +
> +	spin_lock_irqsave(&smc_host->lock, iflags);
> +	clk_sunxi_mmc_phase_control(hw, sclk_dly, oclk_dly);
> +	spin_unlock_irqrestore(&smc_host->lock, iflags);
> +}
> +
> +struct sunxi_mmc_clk_dly mmc_clk_dly[MMC_CLK_MOD_NUM] = {
> +	{ MMC_CLK_400K, 0, 7 },
> +	{ MMC_CLK_25M, 0, 5 },
> +	{ MMC_CLK_50M, 3, 5 },
> +	{ MMC_CLK_50MDDR, 2, 4 },
> +	{ MMC_CLK_50MDDR_8BIT, 2, 4 },
> +	{ MMC_CLK_100M, 1, 4 },
> +	{ MMC_CLK_200M, 1, 4 },
> +};
> +
> +static void sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *smc_host,
> +				   unsigned int rate)
> +{
> +	u32 newrate;
> +	u32 src_clk;
> +	u32 oclk_dly;
> +	u32 sclk_dly;
> +	u32 temp;
> +	struct sunxi_mmc_clk_dly *dly = NULL;
> +
> +	newrate = clk_round_rate(smc_host->clk_mod, rate);
> +	if (smc_host->clk_mod_rate == newrate) {
> +		dev_dbg(mmc_dev(smc_host->mmc), "clk already %d, rounded %d\n",
> +			rate, newrate);
> +		return;
> +	}
> +
> +	dev_dbg(mmc_dev(smc_host->mmc), "setting clk to %d, rounded %d\n",
> +		rate, newrate);
> +
> +	/* setting clock rate */
> +	clk_disable(smc_host->clk_mod);
> +	clk_set_rate(smc_host->clk_mod, newrate);
> +	clk_enable(smc_host->clk_mod);
> +	smc_host->clk_mod_rate = newrate = clk_get_rate(smc_host->clk_mod);
> +	dev_dbg(mmc_dev(smc_host->mmc), "clk is now %d\n", newrate);
> +
> +	sunxi_mmc_oclk_onoff(smc_host, 0);
> +	/* clear internal divider */
> +	temp = mci_readl(smc_host, REG_CLKCR);
> +	temp &= ~0xff;
> +	mci_writel(smc_host, REG_CLKCR, temp);
> +
> +	/* determine delays */
> +	if (rate <= 400000) {
> +		dly = &mmc_clk_dly[MMC_CLK_400K];
> +	} else if (rate <= 25000000) {
> +		dly = &mmc_clk_dly[MMC_CLK_25M];
> +	} else if (rate <= 50000000) {
> +		if (smc_host->ddr) {
> +			if (smc_host->bus_width == 8)
> +				dly = &mmc_clk_dly[MMC_CLK_50MDDR_8BIT];
> +			else
> +				dly = &mmc_clk_dly[MMC_CLK_50MDDR];
> +		} else {
> +			dly = &mmc_clk_dly[MMC_CLK_50M];
> +		}
> +	} else if (rate <= 104000000) {
> +		dly = &mmc_clk_dly[MMC_CLK_100M];
> +	} else if (rate <= 208000000) {
> +		dly = &mmc_clk_dly[MMC_CLK_200M];
> +	} else
> +		dly = &mmc_clk_dly[MMC_CLK_50M];

You need some brackets around that else statement

> +
> +	oclk_dly = dly->oclk_dly;
> +	sclk_dly = dly->sclk_dly;
> +
> +	src_clk = clk_get_rate(clk_get_parent(smc_host->clk_mod));
> +	if (src_clk >= 300000000 && src_clk <= 400000000) {
> +		if (oclk_dly)
> +			oclk_dly--;
> +		if (sclk_dly)
> +			sclk_dly--;
> +	}
> +
> +	sunxi_mmc_set_clk_dly(smc_host, oclk_dly, sclk_dly);
> +	sunxi_mmc_oclk_onoff(smc_host, 1);
> +
> +	/* oclk_onoff sets various irq status bits, clear these */
> +	mci_writel(smc_host, REG_RINTR,
> +		   mci_readl(smc_host, REG_RINTR) & ~SDXC_SDIOInt);
> +}
> +
> +static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +	u32 temp;
> +	s32 err;
> +
> +	/* Set the power state */
> +	switch (ios->power_mode) {
> +	case MMC_POWER_ON:
> +		break;
> +
> +	case MMC_POWER_UP:
> +		if (!IS_ERR(host->vmmc)) {
> +			mmc_regulator_set_ocr(host->mmc, host->vmmc, ios->vdd);
> +			udelay(200);
> +		}
> +
> +		err =  clk_prepare_enable(host->clk_ahb);
> +		if (err) {
> +			dev_err(mmc_dev(host->mmc), "AHB clk err %d\n", err);
> +			host->ferror = 1;
> +			return;
> +		}
> +		err =  clk_prepare_enable(host->clk_mod);
> +		if (err) {
> +			dev_err(mmc_dev(host->mmc), "MOD clk err %d\n", err);
> +			host->ferror = 1;
> +			return;
> +		}
> +
> +		sunxi_mmc_init_host(mmc);
> +		enable_irq(host->irq);
> +
> +		dev_dbg(mmc_dev(host->mmc), "power on!\n");
> +		host->ferror = 0;
> +		break;
> +
> +	case MMC_POWER_OFF:
> +		dev_dbg(mmc_dev(host->mmc), "power off!\n");
> +		disable_irq(host->irq);
> +		sunxi_mmc_exit_host(host);
> +		clk_disable_unprepare(host->clk_ahb);
> +		clk_disable_unprepare(host->clk_mod);
> +		if (!IS_ERR(host->vmmc))
> +			mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
> +		host->ferror = 0;
> +		break;
> +	}
> +
> +	/* set bus width */
> +	switch (ios->bus_width) {
> +	case MMC_BUS_WIDTH_1:
> +		mci_writel(host, REG_WIDTH, SDXC_WIDTH1);
> +		host->bus_width = 1;
> +		break;
> +	case MMC_BUS_WIDTH_4:
> +		mci_writel(host, REG_WIDTH, SDXC_WIDTH4);
> +		host->bus_width = 4;
> +		break;
> +	case MMC_BUS_WIDTH_8:
> +		mci_writel(host, REG_WIDTH, SDXC_WIDTH8);
> +		host->bus_width = 8;
> +		break;
> +	}
> +
> +	/* set ddr mode */
> +	temp = mci_readl(host, REG_GCTRL);
> +	if (ios->timing == MMC_TIMING_UHS_DDR50) {
> +		temp |= SDXC_DDR_MODE;
> +		host->ddr = 1;
> +	} else {
> +		temp &= ~SDXC_DDR_MODE;
> +		host->ddr = 0;
> +	}
> +	mci_writel(host, REG_GCTRL, temp);
> +
> +	/* set up clock */
> +	if (ios->clock && ios->power_mode) {
> +		dev_dbg(mmc_dev(host->mmc), "ios->clock: %d\n", ios->clock);
> +		sunxi_mmc_clk_set_rate(host, ios->clock);
> +		usleep_range(50000, 55000);
> +	}
> +}
> +
> +static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> +{
> +	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
> +	unsigned long flags;
> +	u32 imask;
> +
> +	spin_lock_irqsave(&smc_host->lock, flags);
> +	imask = mci_readl(smc_host, REG_IMASK);
> +	if (enable) {
> +		smc_host->sdio_imask = SDXC_SDIOInt;
> +		imask |= SDXC_SDIOInt;
> +	} else {
> +		smc_host->sdio_imask = 0;
> +		imask &= ~SDXC_SDIOInt;
> +	}
> +	mci_writel(smc_host, REG_IMASK, imask);
> +	spin_unlock_irqrestore(&smc_host->lock, flags);
> +}
> +
> +static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
> +{
> +	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
> +	mci_writel(smc_host, REG_HWRST, 0);
> +	udelay(10);
> +	mci_writel(smc_host, REG_HWRST, 1);
> +	udelay(300);
> +}
> +
> +static int sunxi_mmc_card_present(struct mmc_host *mmc)
> +{
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +
> +	switch (host->cd_mode) {
> +	case CARD_DETECT_BY_GPIO_POLL:
> +		return !gpio_get_value(host->cd_pin); /* Signal inverted */
> +	case CARD_ALWAYS_PRESENT:
> +		return 1;
> +	}
> +	return 0; /* Never reached */
> +}
> +
> +static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> +{
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +	struct mmc_command *cmd = mrq->cmd;
> +	struct mmc_data *data = mrq->data;
> +	unsigned long iflags;
> +	u32 imask = SDXC_IntErrBit;
> +	u32 cmd_val = SDXC_Start | (cmd->opcode & 0x3f);
> +	u32 byte_cnt = 0;
> +	int ret;
> +
> +	if (!sunxi_mmc_card_present(mmc) || host->ferror) {
> +		dev_dbg(mmc_dev(host->mmc), "no medium present\n");
> +		mrq->cmd->error = -ENOMEDIUM;
> +		mmc_request_done(mmc, mrq);
> +		return;
> +	}
> +
> +	if (data) {
> +		byte_cnt = data->blksz * data->blocks;
> +		mci_writel(host, REG_BLKSZ, data->blksz);
> +		mci_writel(host, REG_BCNTR, byte_cnt);
> +		ret = sunxi_mmc_prepare_dma(host, data);
> +		if (ret < 0) {
> +			dev_err(mmc_dev(host->mmc), "prepare DMA failed\n");
> +			cmd->error = ret;
> +			cmd->data->error = ret;
> +			mmc_request_done(host->mmc, mrq);
> +			return;
> +		}
> +	}
> +
> +	if (cmd->opcode == MMC_GO_IDLE_STATE) {
> +		cmd_val |= SDXC_SendInitSeq;
> +		imask |= SDXC_CmdDone;
> +	}
> +
> +	if (cmd->opcode == SD_SWITCH_VOLTAGE) {
> +		cmd_val |= SDXC_VolSwitch;
> +		imask |= SDXC_VolChgDone;
> +		host->voltage_switching = 1;
> +		sunxi_mmc_oclk_onoff(host, 1);
> +	}
> +
> +	if (cmd->flags & MMC_RSP_PRESENT) {
> +		cmd_val |= SDXC_RspExp;
> +		if (cmd->flags & MMC_RSP_136)
> +			cmd_val |= SDXC_LongRsp;
> +		if (cmd->flags & MMC_RSP_CRC)
> +			cmd_val |= SDXC_CheckRspCRC;
> +
> +		if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) {
> +			cmd_val |= SDXC_DataExp | SDXC_WaitPreOver;
> +			if (cmd->data->flags & MMC_DATA_STREAM) {
> +				imask |= SDXC_AutoCMDDone;
> +				cmd_val |= SDXC_Seqmod | SDXC_SendAutoStop;
> +			}
> +			if (cmd->data->stop) {
> +				imask |= SDXC_AutoCMDDone;
> +				cmd_val |= SDXC_SendAutoStop;
> +			} else
> +				imask |= SDXC_DataOver;
> +
> +			if (cmd->data->flags & MMC_DATA_WRITE)
> +				cmd_val |= SDXC_Write;
> +			else
> +				host->wait_dma = 1;
> +		} else
> +			imask |= SDXC_CmdDone;
> +	} else
> +		imask |= SDXC_CmdDone;
> +
> +	dev_dbg(mmc_dev(host->mmc), "cmd %d(%08x) arg %x ie 0x%08x len %d\n",
> +		cmd_val & 0x3f, cmd_val, cmd->arg, imask,
> +		mrq->data ? mrq->data->blksz * mrq->data->blocks : 0);
> +
> +	spin_lock_irqsave(&host->lock, iflags);
> +	host->mrq = mrq;
> +	mci_writel(host, REG_IMASK, host->sdio_imask | imask);
> +	spin_unlock_irqrestore(&host->lock, iflags);
> +
> +	mci_writel(host, REG_CARG, cmd->arg);
> +	mci_writel(host, REG_CMDR, cmd_val);
> +}
> +
> +static const struct of_device_id sunxi_mmc_of_match[] = {
> +	{ .compatible = "allwinner,sun4i-mmc", },
> +	{ .compatible = "allwinner,sun5i-mmc", },

Please use sun5i-a13-mmc as your compatible.


> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
> +
> +static struct mmc_host_ops sunxi_mmc_ops = {
> +	.request	 = sunxi_mmc_request,
> +	.set_ios	 = sunxi_mmc_set_ios,
> +	.get_ro		 = sunxi_mmc_get_ro,
> +	.get_cd		 = sunxi_mmc_card_present,
> +	.enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
> +	.hw_reset	 = sunxi_mmc_hw_reset,
> +};
> +
> +static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
> +				      struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int ret;
> +
> +	if (of_device_is_compatible(np, "allwinner,sun4i-mmc"))
> +		host->idma_des_size_bits = 13;
> +	else
> +		host->idma_des_size_bits = 16;
> +
> +	host->vmmc = devm_regulator_get_optional(&pdev->dev, "vmmc");
> +	if (IS_ERR(host->vmmc) && PTR_ERR(host->vmmc) == -EPROBE_DEFER)
> +		return -EPROBE_DEFER;
> +
> +	host->reg_base = devm_ioremap_resource(&pdev->dev,
> +			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
> +	if (IS_ERR(host->reg_base))
> +		return PTR_ERR(host->reg_base);
> +
> +	host->irq = platform_get_irq(pdev, 0);
> +	ret = devm_request_irq(&pdev->dev, host->irq, sunxi_mmc_irq, 0,
> +			       "sunxi-mci", host);
> +	if (ret)
> +		return ret;
> +	disable_irq(host->irq);
> +
> +	host->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
> +	if (IS_ERR(host->clk_ahb)) {
> +		dev_err(&pdev->dev, "Could not get ahb clock\n");
> +		return PTR_ERR(host->clk_ahb);
> +	}
> +
> +	host->clk_mod = devm_clk_get(&pdev->dev, "mod");
> +	if (IS_ERR(host->clk_mod)) {
> +		dev_err(&pdev->dev, "Could not get mod clock\n");
> +		return PTR_ERR(host->clk_mod);
> +	}
> +
> +	of_property_read_u32(np, "bus-width", &host->bus_width);
> +	if (host->bus_width != 1 && host->bus_width != 4) {
> +		dev_err(&pdev->dev, "Invalid bus-width %d\n", host->bus_width);
> +		return -EINVAL;
> +	}
> +
> +	of_property_read_u32(np, "cd-mode", &host->cd_mode);
> +	switch (host->cd_mode) {
> +	case CARD_DETECT_BY_GPIO_POLL:
> +		host->cd_pin = of_get_named_gpio(np, "cd-gpios", 0);
> +		if (!gpio_is_valid(host->cd_pin)) {
> +			dev_err(&pdev->dev, "Invalid cd-gpios\n");
> +			return -EINVAL;
> +		}
> +		ret = devm_gpio_request(&pdev->dev, host->cd_pin, "mmc_cd");
> +		if (ret) {
> +			dev_err(&pdev->dev, "Could not get cd-gpios\n");
> +			return ret;
> +		}
> +		gpio_direction_input(host->cd_pin);
> +		break;
> +	case CARD_ALWAYS_PRESENT:
> +		break;
> +	default:
> +		dev_err(&pdev->dev, "Invalid cd-mode %d\n", host->cd_mode);
> +		return -EINVAL;
> +	}
> +
> +	host->wp_pin = of_get_named_gpio(np, "wp-gpios", 0);
> +	if (gpio_is_valid(host->wp_pin)) {
> +		ret = devm_gpio_request(&pdev->dev, host->wp_pin, "mmc_wp");
> +		if (ret) {
> +			dev_err(&pdev->dev, "Could not get wp-gpios\n");
> +			return ret;
> +		}
> +		gpio_direction_input(host->wp_pin);
> +	}
> +
> +	return 0;
> +}
> +
> +static int sunxi_mmc_probe(struct platform_device *pdev)
> +{
> +	struct sunxi_mmc_host *host;
> +	struct mmc_host *mmc;
> +	int ret;
> +
> +	mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);
> +	if (!mmc) {
> +		dev_err(&pdev->dev, "mmc alloc host failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	host = mmc_priv(mmc);
> +	host->mmc = mmc;
> +	spin_lock_init(&host->lock);
> +	tasklet_init(&host->tasklet, sunxi_mmc_tasklet, (unsigned long)host);
> +
> +	ret = sunxi_mmc_resource_request(host, pdev);
> +	if (ret)
> +		goto error_free_host;
> +
> +	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
> +					  &host->sg_dma, GFP_KERNEL);
> +	if (!host->sg_cpu) {
> +		dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n");
> +		ret = -ENOMEM;
> +		goto error_free_host;
> +	}
> +
> +	mmc->ops		= &sunxi_mmc_ops;
> +	mmc->max_blk_count	= 8192;
> +	mmc->max_blk_size	= 4096;
> +	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
> +	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
> +	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
> +	/* 400kHz ~ 50MHz */
> +	mmc->f_min		=   400000;
> +	mmc->f_max		= 50000000;

Hmmm, the tables earlier seem to suggest it can do much more than that.

> +	/* available voltages */
> +	if (!IS_ERR(host->vmmc))
> +		mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vmmc);
> +	else
> +		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
> +
> +	mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
> +		MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
> +		MMC_CAP_UHS_DDR50 | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL |
> +		MMC_CAP_DRIVER_TYPE_A;

Please add a newline.

> +	if (host->bus_width == 4)
> +		mmc->caps |= MMC_CAP_4_BIT_DATA;

Please add a newline.

> +	mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP;
> +
> +	ret = mmc_add_host(mmc);
> +	if (ret)
> +		goto error_free_dma;
> +
> +	dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq);
> +	platform_set_drvdata(pdev, mmc);
> +	return 0;
> +
> +error_free_dma:
> +	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
> +error_free_host:
> +	mmc_free_host(mmc);
> +	return ret;
> +}
> +
> +static int sunxi_mmc_remove(struct platform_device *pdev)
> +{
> +	struct mmc_host	*mmc = platform_get_drvdata(pdev);
> +	struct sunxi_mmc_host *host = mmc_priv(mmc);
> +
> +	mmc_remove_host(mmc);
> +	sunxi_mmc_exit_host(host);
> +	tasklet_disable(&host->tasklet);
> +	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
> +	mmc_free_host(mmc);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver sunxi_mmc_driver = {
> +	.driver = {
> +		.name	= "sunxi-mci",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(sunxi_mmc_of_match),
> +	},
> +	.probe		= sunxi_mmc_probe,
> +	.remove		= sunxi_mmc_remove,
> +};
> +module_platform_driver(sunxi_mmc_driver);
> +
> +MODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("David Lanzend?rfer <david.lanzendoerfer@o2s.ch>");
> +MODULE_ALIAS("platform:sunxi-mmc");
> diff --git a/drivers/mmc/host/sunxi-mci.h b/drivers/mmc/host/sunxi-mci.h
> new file mode 100644
> index 0000000..332d3ae
> --- /dev/null
> +++ b/drivers/mmc/host/sunxi-mci.h
> @@ -0,0 +1,246 @@
> +/*
> + * Driver for sunxi SD/MMC host controllers
> + * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
> + * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com>
> + * (C) Copyright 2013-2013 O2S GmbH <www.o2s.ch>
> + * (C) Copyright 2013-2013 David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
> + * (C) Copyright 2013-2013 Hans de Goede <hdegoede@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef __SUNXI_MCI_H__
> +#define __SUNXI_MCI_H__
> +
> +/* register offset define */
> +#define SDXC_REG_GCTRL	(0x00) /* SMC Global Control Register */
> +#define SDXC_REG_CLKCR	(0x04) /* SMC Clock Control Register */
> +#define SDXC_REG_TMOUT	(0x08) /* SMC Time Out Register */
> +#define SDXC_REG_WIDTH	(0x0C) /* SMC Bus Width Register */
> +#define SDXC_REG_BLKSZ	(0x10) /* SMC Block Size Register */
> +#define SDXC_REG_BCNTR	(0x14) /* SMC Byte Count Register */
> +#define SDXC_REG_CMDR	(0x18) /* SMC Command Register */
> +#define SDXC_REG_CARG	(0x1C) /* SMC Argument Register */
> +#define SDXC_REG_RESP0	(0x20) /* SMC Response Register 0 */
> +#define SDXC_REG_RESP1	(0x24) /* SMC Response Register 1 */
> +#define SDXC_REG_RESP2	(0x28) /* SMC Response Register 2 */
> +#define SDXC_REG_RESP3	(0x2C) /* SMC Response Register 3 */
> +#define SDXC_REG_IMASK	(0x30) /* SMC Interrupt Mask Register */
> +#define SDXC_REG_MISTA	(0x34) /* SMC Masked Interrupt Status Register */
> +#define SDXC_REG_RINTR	(0x38) /* SMC Raw Interrupt Status Register */
> +#define SDXC_REG_STAS	(0x3C) /* SMC Status Register */
> +#define SDXC_REG_FTRGL	(0x40) /* SMC FIFO Threshold Watermark Registe */
> +#define SDXC_REG_FUNS	(0x44) /* SMC Function Select Register */
> +#define SDXC_REG_CBCR	(0x48) /* SMC CIU Byte Count Register */
> +#define SDXC_REG_BBCR	(0x4C) /* SMC BIU Byte Count Register */
> +#define SDXC_REG_DBGC	(0x50) /* SMC Debug Enable Register */
> +#define SDXC_REG_HWRST	(0x78) /* SMC Card Hardware Reset for Register */
> +#define SDXC_REG_DMAC	(0x80) /* SMC IDMAC Control Register */
> +#define SDXC_REG_DLBA	(0x84) /* SMC IDMAC Descriptor List Base Addre */
> +#define SDXC_REG_IDST	(0x88) /* SMC IDMAC Status Register */
> +#define SDXC_REG_IDIE	(0x8C) /* SMC IDMAC Interrupt Enable Register */
> +#define SDXC_REG_CHDA	(0x90)
> +#define SDXC_REG_CBDA	(0x94)
> +
> +#define mci_readl(host, reg) \
> +	__raw_readl((host)->reg_base + SDXC_##reg)
> +#define mci_writel(host, reg, value) \
> +	__raw_writel((value), (host)->reg_base + SDXC_##reg)

No barriers ? :(

> +/* global control register bits */
> +#define SDXC_SoftReset		BIT(0)
> +#define SDXC_FIFOReset		BIT(1)
> +#define SDXC_DMAReset		BIT(2)
> +#define SDXC_HWReset		(SDXC_SoftReset|SDXC_FIFOReset|SDXC_DMAReset)
> +#define SDXC_INTEnb		BIT(4)
> +#define SDXC_DMAEnb		BIT(5)
> +#define SDXC_DebounceEnb	BIT(8)
> +#define SDXC_PosedgeLatchData	BIT(9)
> +#define SDXC_DDR_MODE		BIT(10)
> +#define SDXC_MemAccessDone	BIT(29)
> +#define SDXC_AccessDoneDirect	BIT(30)
> +#define SDXC_ACCESS_BY_AHB	BIT(31)
> +#define SDXC_ACCESS_BY_DMA	(0U << 31)
> +/* clock control bits */
> +#define SDXC_CardClkOn		BIT(16)
> +#define SDXC_LowPowerOn		BIT(17)
> +/* bus width */
> +#define SDXC_WIDTH1		(0)
> +#define SDXC_WIDTH4		(1)
> +#define SDXC_WIDTH8		(2)
> +/* smc command bits */
> +#define SDXC_RspExp		BIT(6)
> +#define SDXC_LongRsp		BIT(7)
> +#define SDXC_CheckRspCRC	BIT(8)
> +#define SDXC_DataExp		BIT(9)
> +#define SDXC_Write		BIT(10)
> +#define SDXC_Seqmod		BIT(11)
> +#define SDXC_SendAutoStop	BIT(12)
> +#define SDXC_WaitPreOver	BIT(13)
> +#define SDXC_StopAbortCMD	BIT(14)
> +#define SDXC_SendInitSeq	BIT(15)
> +#define SDXC_UPCLKOnly		BIT(21)
> +#define SDXC_RdCEATADev		BIT(22)
> +#define SDXC_CCSExp		BIT(23)
> +#define SDXC_EnbBoot		BIT(24)
> +#define SDXC_AltBootOpt		BIT(25)
> +#define SDXC_BootACKExp		BIT(26)
> +#define SDXC_BootAbort		BIT(27)
> +#define SDXC_VolSwitch	        BIT(28)
> +#define SDXC_UseHoldReg	        BIT(29)
> +#define SDXC_Start	        BIT(31)
> +/* interrupt bits */
> +#define SDXC_RespErr		BIT(1)
> +#define SDXC_CmdDone		BIT(2)
> +#define SDXC_DataOver		BIT(3)
> +#define SDXC_TxDataReq		BIT(4)
> +#define SDXC_RxDataReq		BIT(5)
> +#define SDXC_RespCRCErr		BIT(6)
> +#define SDXC_DataCRCErr		BIT(7)
> +#define SDXC_RespTimeout	BIT(8)
> +#define SDXC_DataTimeout	BIT(9)
> +#define SDXC_VolChgDone		BIT(10)
> +#define SDXC_FIFORunErr		BIT(11)
> +#define SDXC_HardWLocked	BIT(12)
> +#define SDXC_StartBitErr	BIT(13)
> +#define SDXC_AutoCMDDone	BIT(14)
> +#define SDXC_EndBitErr		BIT(15)
> +#define SDXC_SDIOInt		BIT(16)
> +#define SDXC_CardInsert		BIT(30)
> +#define SDXC_CardRemove		BIT(31)
> +#define SDXC_IntErrBit		(SDXC_RespErr | SDXC_RespCRCErr | \
> +				 SDXC_DataCRCErr | SDXC_RespTimeout | \
> +				 SDXC_DataTimeout | SDXC_FIFORunErr | \
> +				 SDXC_HardWLocked | SDXC_StartBitErr | \
> +				 SDXC_EndBitErr) /* 0xbbc2 */
> +#define SDXC_IntDoneBit		(SDXC_AutoCMDDone | SDXC_DataOver | \
> +				 SDXC_CmdDone | SDXC_VolChgDone)
> +/* status */
> +#define SDXC_RXWLFlag		BIT(0)
> +#define SDXC_TXWLFlag		BIT(1)
> +#define SDXC_FIFOEmpty		BIT(2)
> +#define SDXC_FIFOFull		BIT(3)
> +#define SDXC_CardPresent	BIT(8)
> +#define SDXC_CardDataBusy	BIT(9)
> +#define SDXC_DataFSMBusy	BIT(10)
> +#define SDXC_DMAReq		BIT(31)
> +#define SDXC_FIFO_SIZE		(16)
> +/* Function select */
> +#define SDXC_CEATAOn		(0xceaaU << 16)
> +#define SDXC_SendIrqRsp		BIT(0)
> +#define SDXC_SDIORdWait		BIT(1)
> +#define SDXC_AbtRdData		BIT(2)
> +#define SDXC_SendCCSD		BIT(8)
> +#define SDXC_SendAutoStopCCSD	BIT(9)
> +#define SDXC_CEATADevIntEnb	BIT(10)
> +/* IDMA controller bus mod bit field */
> +#define SDXC_IDMACSoftRST	BIT(0)
> +#define SDXC_IDMACFixBurst	BIT(1)
> +#define SDXC_IDMACIDMAOn	BIT(7)
> +#define SDXC_IDMACRefetchDES	BIT(31)
> +/* IDMA status bit field */
> +#define SDXC_IDMACTransmitInt	BIT(0)
> +#define SDXC_IDMACReceiveInt	BIT(1)
> +#define SDXC_IDMACFatalBusErr	BIT(2)
> +#define SDXC_IDMACDesInvalid	BIT(4)
> +#define SDXC_IDMACCardErrSum	BIT(5)
> +#define SDXC_IDMACNormalIntSum	BIT(8)
> +#define SDXC_IDMACAbnormalIntSum BIT(9)
> +#define SDXC_IDMACHostAbtInTx	BIT(10)
> +#define SDXC_IDMACHostAbtInRx	BIT(10)
> +#define SDXC_IDMACIdle		(0U << 13)
> +#define SDXC_IDMACSuspend	(1U << 13)
> +#define SDXC_IDMACDESCRd	(2U << 13)
> +#define SDXC_IDMACDESCCheck	(3U << 13)
> +#define SDXC_IDMACRdReqWait	(4U << 13)
> +#define SDXC_IDMACWrReqWait	(5U << 13)
> +#define SDXC_IDMACRd		(6U << 13)
> +#define SDXC_IDMACWr		(7U << 13)
> +#define SDXC_IDMACDESCClose	(8U << 13)
> +
> +struct sunxi_idma_des {
> +	u32	config;
> +#define SDXC_IDMAC_DES0_DIC	BIT(1)  /* disable interrupt on completion */
> +#define SDXC_IDMAC_DES0_LD	BIT(2)  /* last descriptor */
> +#define SDXC_IDMAC_DES0_FD	BIT(3)  /* first descriptor */
> +#define SDXC_IDMAC_DES0_CH	BIT(4)  /* chain mode */
> +#define SDXC_IDMAC_DES0_ER	BIT(5)  /* end of ring */
> +#define SDXC_IDMAC_DES0_CES	BIT(30) /* card error summary */
> +#define SDXC_IDMAC_DES0_OWN	BIT(31) /* 1-idma owns it, 0-host owns it */
> +
> +	/*
> +	 * If the idma-des-size-bits of property is ie 13, bufsize bits are:
> +	 *  Bits  0-12: buf1 size
> +	 *  Bits 13-25: buf2 size
> +	 *  Bits 26-31: not used
> +	 * Since we only ever set buf1 size, we can simply store it directly.
> +	 */
> +	u32	buf_size;
> +	u32	buf_addr_ptr1;
> +	u32	buf_addr_ptr2;
> +};
> +
> +struct sunxi_mmc_host {
> +	struct mmc_host *mmc;
> +	struct regulator *vmmc;
> +
> +	/* IO mapping base */
> +	void __iomem *reg_base;
> +
> +	spinlock_t lock;
> +	struct tasklet_struct tasklet;
> +
> +	/* clock management */
> +	struct clk *clk_ahb;
> +	struct clk *clk_mod;
> +
> +	/* indicator pins */
> +	int wp_pin;
> +	int cd_pin;
> +	int cd_mode;
> +#define CARD_DETECT_BY_GPIO_POLL (1)	/* mmc detected by gpio check */
> +#define CARD_ALWAYS_PRESENT      (2)	/* mmc always present */

Just a question here, have you tested to use the external interrupts?
(Is that even possible on the pins that are used as card detect?)

> +	/* ios information */
> +	u32		clk_mod_rate;
> +	u32		bus_width;
> +	u32		idma_des_size_bits;
> +	u32		ddr;
> +	u32		voltage_switching;
> +
> +	/* irq */
> +	int		irq;
> +	u32		int_sum;
> +	u32		sdio_imask;
> +
> +	/* flags */
> +	u32		power_on:1;
> +	u32		io_flag:1;
> +	u32		wait_dma:1;
> +
> +	dma_addr_t	sg_dma;
> +	void		*sg_cpu;
> +
> +	struct mmc_request *mrq;
> +	u32		ferror;
> +};
> +
> +#define MMC_CLK_400K            0
> +#define MMC_CLK_25M             1
> +#define MMC_CLK_50M             2
> +#define MMC_CLK_50MDDR          3
> +#define MMC_CLK_50MDDR_8BIT     4
> +#define MMC_CLK_100M            5
> +#define MMC_CLK_200M            6
> +#define MMC_CLK_MOD_NUM         7
> +
> +struct sunxi_mmc_clk_dly {
> +	u32 mode;
> +	u32 oclk_dly;
> +	u32 sclk_dly;
> +};
> +
> +#endif
> diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
> new file mode 100644
> index 0000000..1ef5c89
> --- /dev/null
> +++ b/include/linux/clk/sunxi.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright 2013 - Hans de Goede <hdegoede@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __LINUX_CLK_SUNXI_H_
> +#define __LINUX_CLK_SUNXI_H_
> +
> +#include <linux/clk.h>
> +
> +void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
> +
> +#endif

Hmmm, I see no implementation for this function. Didn't you forget
a file here? (and it should probably be a separate patch anyway).

Thanks a lot for this work,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131215/0d14372c/attachment-0001.sig>

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

* Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
  2013-12-14 21:58     ` Hans de Goede
@ 2013-12-15 13:58         ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-15 13:58 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 2834 bytes --]

Hi Hans,

On Sat, Dec 14, 2013 at 10:58:12PM +0100, Hans de Goede wrote:
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Commit-log :)

> ---
>  arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 16 ++++++++++++++++
>  arch/arm/boot/dts/sun4i-a10.dtsi           | 16 ++++++++++++++++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
> index 425a7db..d193937 100644
> --- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
> +++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
> @@ -42,7 +42,23 @@
>  			};
>  		};
>  
> +		sdc0: sdc@01c0f000 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&sdc0_pins_a>;
> +			pinctrl-1 = <&mmc0_cd_pin_cubieboard>;
> +			cd-gpios = <&pio 7 1 0>; /* PH1 */
> +			cd-mode = <1>;
> +			status = "okay";
> +		};
> +
>  		pinctrl@01c20800 {
> +			mmc0_cd_pin_cubieboard: mmc0_cd_pin@0 {
> +				allwinner,pins = "PH1";
> +				allwinner,function = "gpio_in";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
> +

You seem to be using mmc and sdc without any real distinction. Please
try to be consistent and use only one of the two (and I have a slight
preference for mmc :))

>  			led_pins_cubieboard: led_pins@0 {
>  				allwinner,pins = "PH20", "PH21";
>  				allwinner,function = "gpio_out";
> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
> index 4dccdb0..13bccd5 100644
> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
> @@ -306,6 +306,15 @@
>  			#size-cells = <0>;
>  		};
>  
> +		sdc0: sdc@01c0f000 {
> +			compatible = "allwinner,sun4i-mmc";
> +			reg = <0x01c0f000 0x1000>;
> +			clocks = <&ahb_gates 8>, <&mmc0>;
> +			interrupts = <32>;
> +			bus-width = <4>;
> +			status = "disabled";
> +		};
> +

The A10 has much more mmc controller doesn't it?

Could you add all of them in the DT ?

>  		intc: interrupt-controller@01c20400 {
>  			compatible = "allwinner,sun4i-ic";
>  			reg = <0x01c20400 0x400>;
> @@ -376,6 +385,13 @@
>  				allwinner,drive = <0>;
>  				allwinner,pull = <0>;
>  			};
> +
> +			sdc0_pins_a: sdc0@0 {
> +				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
> +				allwinner,function = "mmc0";
> +				allwinner,drive = <3>;
> +				allwinner,pull = <1>;

Wow, you need both the pullups and a 40mA output?

Ideally, I'd like this patch to be splitted into three:
  - One that adds the MMC controller nodes to the DTSI
  - One that adds the muxing options you need to the pinctrl node
  - One that enables the controller on the boards

Thanks,

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
@ 2013-12-15 13:58         ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-15 13:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Hans,

On Sat, Dec 14, 2013 at 10:58:12PM +0100, Hans de Goede wrote:
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Commit-log :)

> ---
>  arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 16 ++++++++++++++++
>  arch/arm/boot/dts/sun4i-a10.dtsi           | 16 ++++++++++++++++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
> index 425a7db..d193937 100644
> --- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
> +++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
> @@ -42,7 +42,23 @@
>  			};
>  		};
>  
> +		sdc0: sdc at 01c0f000 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&sdc0_pins_a>;
> +			pinctrl-1 = <&mmc0_cd_pin_cubieboard>;
> +			cd-gpios = <&pio 7 1 0>; /* PH1 */
> +			cd-mode = <1>;
> +			status = "okay";
> +		};
> +
>  		pinctrl at 01c20800 {
> +			mmc0_cd_pin_cubieboard: mmc0_cd_pin at 0 {
> +				allwinner,pins = "PH1";
> +				allwinner,function = "gpio_in";
> +				allwinner,drive = <0>;
> +				allwinner,pull = <0>;
> +			};
> +

You seem to be using mmc and sdc without any real distinction. Please
try to be consistent and use only one of the two (and I have a slight
preference for mmc :))

>  			led_pins_cubieboard: led_pins at 0 {
>  				allwinner,pins = "PH20", "PH21";
>  				allwinner,function = "gpio_out";
> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
> index 4dccdb0..13bccd5 100644
> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
> @@ -306,6 +306,15 @@
>  			#size-cells = <0>;
>  		};
>  
> +		sdc0: sdc at 01c0f000 {
> +			compatible = "allwinner,sun4i-mmc";
> +			reg = <0x01c0f000 0x1000>;
> +			clocks = <&ahb_gates 8>, <&mmc0>;
> +			interrupts = <32>;
> +			bus-width = <4>;
> +			status = "disabled";
> +		};
> +

The A10 has much more mmc controller doesn't it?

Could you add all of them in the DT ?

>  		intc: interrupt-controller at 01c20400 {
>  			compatible = "allwinner,sun4i-ic";
>  			reg = <0x01c20400 0x400>;
> @@ -376,6 +385,13 @@
>  				allwinner,drive = <0>;
>  				allwinner,pull = <0>;
>  			};
> +
> +			sdc0_pins_a: sdc0 at 0 {
> +				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
> +				allwinner,function = "mmc0";
> +				allwinner,drive = <3>;
> +				allwinner,pull = <1>;

Wow, you need both the pullups and a 40mA output?

Ideally, I'd like this patch to be splitted into three:
  - One that adds the MMC controller nodes to the DTSI
  - One that adds the muxing options you need to the pinctrl node
  - One that enables the controller on the boards

Thanks,

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131215/644832a7/attachment.sig>

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

* Re: [PATCH 3/5] ARM: dts: sun5i: Add new sun5i-a13-olinuxino-micro board
  2013-12-14 21:58     ` Hans de Goede
@ 2013-12-15 14:04         ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-15 14:04 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 3345 bytes --]

On Sat, Dec 14, 2013 at 10:58:13PM +0100, Hans de Goede wrote:
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Commit log :)

Please detail what the board is, what features it has, etc.

Other than that, I'm mostly ok with this patch (except that you can
also probably add your copyright, but that's your call :))

Could you send it as a single patch, separate from this serie (since
it's not really related in the end).

Thanks!
Maxime

> ---
>  arch/arm/boot/dts/Makefile                      |  1 +
>  arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts | 66 +++++++++++++++++++++++++
>  2 files changed, 67 insertions(+)
>  create mode 100644 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
> 
> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> index d57c1a6..b663ed7 100644
> --- a/arch/arm/boot/dts/Makefile
> +++ b/arch/arm/boot/dts/Makefile
> @@ -255,6 +255,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \
>  	sun4i-a10-hackberry.dtb \
>  	sun5i-a10s-olinuxino-micro.dtb \
>  	sun5i-a13-olinuxino.dtb \
> +	sun5i-a13-olinuxino-micro.dtb \
>  	sun6i-a31-colombus.dtb \
>  	sun7i-a20-cubieboard2.dtb \
>  	sun7i-a20-cubietruck.dtb \
> diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
> new file mode 100644
> index 0000000..26df7e8
> --- /dev/null
> +++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
> @@ -0,0 +1,66 @@
> +/*
> + * Copyright 2012 Maxime Ripard
> + *
> + * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +/dts-v1/;
> +/include/ "sun5i-a13.dtsi"
> +
> +/ {
> +	model = "Olimex A13-Olinuxino Micro";
> +	compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
> +
> +	soc@01c00000 {
> +		pinctrl@01c20800 {
> +			led_pins_olinuxinom: led_pins@0 {
> +				allwinner,pins = "PG9";
> +				allwinner,function = "gpio_out";
> +				allwinner,drive = <1>;
> +				allwinner,pull = <0>;
> +			};
> +		};
> +
> +		uart1: serial@01c28400 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&uart1_pins_b>;
> +			status = "okay";
> +		};
> +
> +		i2c0: i2c@01c2ac00 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&i2c0_pins_a>;
> +			status = "okay";
> +		};
> +
> +		i2c1: i2c@01c2b000 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&i2c1_pins_a>;
> +			status = "okay";
> +		};
> +
> +		i2c2: i2c@01c2b400 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&i2c2_pins_a>;
> +			status = "okay";
> +		};
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&led_pins_olinuxinom>;
> +
> +		power {

Could you add a label here?

Something like a13-olinuxino-micro:green:power ?

> +			gpios = <&pio 6 9 0>;
> +			default-state = "on";
> +		};
> +	};
> +};

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [PATCH 3/5] ARM: dts: sun5i: Add new sun5i-a13-olinuxino-micro board
@ 2013-12-15 14:04         ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-15 14:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Dec 14, 2013 at 10:58:13PM +0100, Hans de Goede wrote:
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Commit log :)

Please detail what the board is, what features it has, etc.

Other than that, I'm mostly ok with this patch (except that you can
also probably add your copyright, but that's your call :))

Could you send it as a single patch, separate from this serie (since
it's not really related in the end).

Thanks!
Maxime

> ---
>  arch/arm/boot/dts/Makefile                      |  1 +
>  arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts | 66 +++++++++++++++++++++++++
>  2 files changed, 67 insertions(+)
>  create mode 100644 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
> 
> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> index d57c1a6..b663ed7 100644
> --- a/arch/arm/boot/dts/Makefile
> +++ b/arch/arm/boot/dts/Makefile
> @@ -255,6 +255,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \
>  	sun4i-a10-hackberry.dtb \
>  	sun5i-a10s-olinuxino-micro.dtb \
>  	sun5i-a13-olinuxino.dtb \
> +	sun5i-a13-olinuxino-micro.dtb \
>  	sun6i-a31-colombus.dtb \
>  	sun7i-a20-cubieboard2.dtb \
>  	sun7i-a20-cubietruck.dtb \
> diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
> new file mode 100644
> index 0000000..26df7e8
> --- /dev/null
> +++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
> @@ -0,0 +1,66 @@
> +/*
> + * Copyright 2012 Maxime Ripard
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +/dts-v1/;
> +/include/ "sun5i-a13.dtsi"
> +
> +/ {
> +	model = "Olimex A13-Olinuxino Micro";
> +	compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
> +
> +	soc at 01c00000 {
> +		pinctrl at 01c20800 {
> +			led_pins_olinuxinom: led_pins at 0 {
> +				allwinner,pins = "PG9";
> +				allwinner,function = "gpio_out";
> +				allwinner,drive = <1>;
> +				allwinner,pull = <0>;
> +			};
> +		};
> +
> +		uart1: serial at 01c28400 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&uart1_pins_b>;
> +			status = "okay";
> +		};
> +
> +		i2c0: i2c at 01c2ac00 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&i2c0_pins_a>;
> +			status = "okay";
> +		};
> +
> +		i2c1: i2c at 01c2b000 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&i2c1_pins_a>;
> +			status = "okay";
> +		};
> +
> +		i2c2: i2c at 01c2b400 {
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&i2c2_pins_a>;
> +			status = "okay";
> +		};
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&led_pins_olinuxinom>;
> +
> +		power {

Could you add a label here?

Something like a13-olinuxino-micro:green:power ?

> +			gpios = <&pio 6 9 0>;
> +			default-state = "on";
> +		};
> +	};
> +};

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131215/0c6225d3/attachment-0001.sig>

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

* Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 13:44         ` Maxime Ripard
@ 2013-12-15 14:20           ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-15 14:20 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

On 12/15/2013 02:44 PM, Maxime Ripard wrote:
> Hi Hans,
>
> I won't comment on the MMC driver itself, and leave Chris comment on
> that, but still, I have a few things.
>
> On Sat, Dec 14, 2013 at 10:58:11PM +0100, Hans de Goede wrote:
>> From: David Lanzendörfer <david.lanzendoerfer-Z7Kmv9EsliU@public.gmane.org>
>>
>> This is based on the driver Allwinner ships in there Android kernel sources.
>>
>> Initial porting to upstream kernels done by David Lanzendörfer, additional
>> fixes and cleanups by Hans de Goede.
>>
>> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>
> Your commit log is a bit sparse. What capabilities this controller
> has? Is it using DMA? If so, how? What SoCs are supported/it has been
> tested on? etc.

David, since you'll be doing v2 I guess you'll be filling in v2. FYI
I've tested this on sun4i-a10, sun5i-a10s sun5i-a13 and sun7i-a20.

It uses dma in bus-master mode using a built-in designware idmac controller,
which is identical to the one found in the mmc-dw hosts. Note the rest of
the host is not identical, I've looked into reusing the mmc-dw driver but
that does not seem like a good idea (manual sending stop commands
versus auto stop on sunxi, completely different registers, etc.).

>
> Also, you probably needs David's SoB here.

The plan is for David to send v2 of this patch-set so that should take care of
that :)

>
>> ---
>>   drivers/mmc/host/Kconfig     |   8 +
>>   drivers/mmc/host/Makefile    |   2 +
>>   drivers/mmc/host/sunxi-mci.c | 908 +++++++++++++++++++++++++++++++++++++++++++
>>   drivers/mmc/host/sunxi-mci.h | 246 ++++++++++++
>>   include/linux/clk/sunxi.h    |  22 ++
>
> Please add your dt bindings documentation in Documentation/devicetree/bindings
>

<snip>

>> +#include "sunxi-mci.h"
>> +
>> +static void sunxi_mmc_init_host(struct mmc_host *mmc)
>> +{
>> +	u32 rval;
>> +	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
>> +
>> +	/* reset controller */
>> +	rval = mci_readl(smc_host, REG_GCTRL) | SDXC_HWReset;
>> +	mci_writel(smc_host, REG_GCTRL, rval);
>> +
>> +	mci_writel(smc_host, REG_FTRGL, 0x20070008);

These set tx/rx FIFO thresholds, I think 7 is one, 8 is the
other (no idea which is which) and the 2 is magic ...

>> +	mci_writel(smc_host, REG_TMOUT, 0xffffffff);
>> +	mci_writel(smc_host, REG_IMASK, smc_host->sdio_imask);
>> +	mci_writel(smc_host, REG_RINTR, 0xffffffff);

This simple clears any interrupt flags left set by uboot

>> +	mci_writel(smc_host, REG_DBGC, 0xdeb);

Unknown

>> +	mci_writel(smc_host, REG_FUNS, 0xceaa0000);

There actually is a define for this in the .h file
called: "SDXC_CEATAOn" no idea what that means though,
I guess we should use the define here. David can you
fix this in v2 ?

>> +	mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);
>
> I suppose we have no idea what these magics are all about ? :(

See above, we have some idea, but not much.

>
>> +	rval = mci_readl(smc_host, REG_GCTRL)|SDXC_INTEnb;
>> +	rval &= ~SDXC_AccessDoneDirect;
>> +	mci_writel(smc_host, REG_GCTRL, rval);
>> +}

<snip>

>> +static const struct of_device_id sunxi_mmc_of_match[] = {
>> +	{ .compatible = "allwinner,sun4i-mmc", },
>> +	{ .compatible = "allwinner,sun5i-mmc", },
>
> Please use sun5i-a13-mmc as your compatible.

Can you explain a bit why? In essence currently we have
2 versions of the mmc controller, those found on sun4i
and those found on sun5i and sun7i. I thought that the
norm was to use the oldest soc version in which a revision
of an ip-block first appears as the compatible string ?

Note I've tested this with both a13 and a10s SOCs, if we
add a sun5i-a13-mmc we should also add a sun5i-a10s-mmc
and a sun5i-a20-mmc, or would that then be sun7i-a20-mmc?

To me just having sun5i-mmc for sun5i+ socs seems simpler.

<snip>

>> +	mmc->ops		= &sunxi_mmc_ops;
>> +	mmc->max_blk_count	= 8192;
>> +	mmc->max_blk_size	= 4096;
>> +	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
>> +	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
>> +	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
>> +	/* 400kHz ~ 50MHz */
>> +	mmc->f_min		=   400000;
>> +	mmc->f_max		= 50000000;
>
> Hmmm, the tables earlier seem to suggest it can do much more than that.

I know, but this is what the allwinner android kernels are using, actually
in case of sdc3 they are putting 200000000 in f_max (as that is often
used for sdio cards) but then later in set_ios they clamp the passed
in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
worked. Hence I've simply gone for a safe range for now. If someone has
cards capable of doing 200 MHz we could certainly run various tests and
try to improve this, but for now this seems a sane range to start with.

<snip>

 >> +	/* indicator pins */
 >> +	int wp_pin;
 >> +	int cd_pin;
 >> +	int cd_mode;
 >> +#define CARD_DETECT_BY_GPIO_POLL (1)	/* mmc detected by gpio check */
 >> +#define CARD_ALWAYS_PRESENT      (2)	/* mmc always present */
 >
 > Just a question here, have you tested to use the external interrupts?
 > (Is that even possible on the pins that are used as card detect?)
 >

No I've not tried that, there was code for this in the original allwinner
driver, but no boards were actually using it.

As for it being possible on the pins being used, it is possible on (most)
port H pins and the cubie* and a20-olinuxino-micro boards are using PH pins
for cd. Others are not.  One thing which worries me about this is debouncing,
using polling is automatically debounced, using an external interrupt won't
be. Ideally there would be some common code somewhere to deal with gpio
connected buttons (which this in essence is) which does debouncing ...

Again I think this is something best left as a future enhancement.

<snip>

>> diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
>> new file mode 100644
>> index 0000000..1ef5c89
>> --- /dev/null
>> +++ b/include/linux/clk/sunxi.h
>> @@ -0,0 +1,22 @@
>> +/*
>> + * Copyright 2013 - Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef __LINUX_CLK_SUNXI_H_
>> +#define __LINUX_CLK_SUNXI_H_
>> +
>> +#include <linux/clk.h>
>> +
>> +void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
>> +
>> +#endif
>
> Hmmm, I see no implementation for this function. Didn't you forget
> a file here? (and it should probably be a separate patch anyway).

The implementation is part of Emilio's clk branch, but he forgot
to add a header for it, so I'm fixing that up here, I guess this
should go through Emlio's tree as a separate patch.

> Thanks a lot for this work,

You're welcome. I think it is great to see how far along upstream sunxi
support has come thanks to work of all involved. It is really becoming
usable now :)

Regards,

Hans

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/groups/opt_out.

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

* [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 14:20           ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-15 14:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/15/2013 02:44 PM, Maxime Ripard wrote:
> Hi Hans,
>
> I won't comment on the MMC driver itself, and leave Chris comment on
> that, but still, I have a few things.
>
> On Sat, Dec 14, 2013 at 10:58:11PM +0100, Hans de Goede wrote:
>> From: David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
>>
>> This is based on the driver Allwinner ships in there Android kernel sources.
>>
>> Initial porting to upstream kernels done by David Lanzend?rfer, additional
>> fixes and cleanups by Hans de Goede.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>
> Your commit log is a bit sparse. What capabilities this controller
> has? Is it using DMA? If so, how? What SoCs are supported/it has been
> tested on? etc.

David, since you'll be doing v2 I guess you'll be filling in v2. FYI
I've tested this on sun4i-a10, sun5i-a10s sun5i-a13 and sun7i-a20.

It uses dma in bus-master mode using a built-in designware idmac controller,
which is identical to the one found in the mmc-dw hosts. Note the rest of
the host is not identical, I've looked into reusing the mmc-dw driver but
that does not seem like a good idea (manual sending stop commands
versus auto stop on sunxi, completely different registers, etc.).

>
> Also, you probably needs David's SoB here.

The plan is for David to send v2 of this patch-set so that should take care of
that :)

>
>> ---
>>   drivers/mmc/host/Kconfig     |   8 +
>>   drivers/mmc/host/Makefile    |   2 +
>>   drivers/mmc/host/sunxi-mci.c | 908 +++++++++++++++++++++++++++++++++++++++++++
>>   drivers/mmc/host/sunxi-mci.h | 246 ++++++++++++
>>   include/linux/clk/sunxi.h    |  22 ++
>
> Please add your dt bindings documentation in Documentation/devicetree/bindings
>

<snip>

>> +#include "sunxi-mci.h"
>> +
>> +static void sunxi_mmc_init_host(struct mmc_host *mmc)
>> +{
>> +	u32 rval;
>> +	struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
>> +
>> +	/* reset controller */
>> +	rval = mci_readl(smc_host, REG_GCTRL) | SDXC_HWReset;
>> +	mci_writel(smc_host, REG_GCTRL, rval);
>> +
>> +	mci_writel(smc_host, REG_FTRGL, 0x20070008);

These set tx/rx FIFO thresholds, I think 7 is one, 8 is the
other (no idea which is which) and the 2 is magic ...

>> +	mci_writel(smc_host, REG_TMOUT, 0xffffffff);
>> +	mci_writel(smc_host, REG_IMASK, smc_host->sdio_imask);
>> +	mci_writel(smc_host, REG_RINTR, 0xffffffff);

This simple clears any interrupt flags left set by uboot

>> +	mci_writel(smc_host, REG_DBGC, 0xdeb);

Unknown

>> +	mci_writel(smc_host, REG_FUNS, 0xceaa0000);

There actually is a define for this in the .h file
called: "SDXC_CEATAOn" no idea what that means though,
I guess we should use the define here. David can you
fix this in v2 ?

>> +	mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);
>
> I suppose we have no idea what these magics are all about ? :(

See above, we have some idea, but not much.

>
>> +	rval = mci_readl(smc_host, REG_GCTRL)|SDXC_INTEnb;
>> +	rval &= ~SDXC_AccessDoneDirect;
>> +	mci_writel(smc_host, REG_GCTRL, rval);
>> +}

<snip>

>> +static const struct of_device_id sunxi_mmc_of_match[] = {
>> +	{ .compatible = "allwinner,sun4i-mmc", },
>> +	{ .compatible = "allwinner,sun5i-mmc", },
>
> Please use sun5i-a13-mmc as your compatible.

Can you explain a bit why? In essence currently we have
2 versions of the mmc controller, those found on sun4i
and those found on sun5i and sun7i. I thought that the
norm was to use the oldest soc version in which a revision
of an ip-block first appears as the compatible string ?

Note I've tested this with both a13 and a10s SOCs, if we
add a sun5i-a13-mmc we should also add a sun5i-a10s-mmc
and a sun5i-a20-mmc, or would that then be sun7i-a20-mmc?

To me just having sun5i-mmc for sun5i+ socs seems simpler.

<snip>

>> +	mmc->ops		= &sunxi_mmc_ops;
>> +	mmc->max_blk_count	= 8192;
>> +	mmc->max_blk_size	= 4096;
>> +	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
>> +	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
>> +	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
>> +	/* 400kHz ~ 50MHz */
>> +	mmc->f_min		=   400000;
>> +	mmc->f_max		= 50000000;
>
> Hmmm, the tables earlier seem to suggest it can do much more than that.

I know, but this is what the allwinner android kernels are using, actually
in case of sdc3 they are putting 200000000 in f_max (as that is often
used for sdio cards) but then later in set_ios they clamp the passed
in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
worked. Hence I've simply gone for a safe range for now. If someone has
cards capable of doing 200 MHz we could certainly run various tests and
try to improve this, but for now this seems a sane range to start with.

<snip>

 >> +	/* indicator pins */
 >> +	int wp_pin;
 >> +	int cd_pin;
 >> +	int cd_mode;
 >> +#define CARD_DETECT_BY_GPIO_POLL (1)	/* mmc detected by gpio check */
 >> +#define CARD_ALWAYS_PRESENT      (2)	/* mmc always present */
 >
 > Just a question here, have you tested to use the external interrupts?
 > (Is that even possible on the pins that are used as card detect?)
 >

No I've not tried that, there was code for this in the original allwinner
driver, but no boards were actually using it.

As for it being possible on the pins being used, it is possible on (most)
port H pins and the cubie* and a20-olinuxino-micro boards are using PH pins
for cd. Others are not.  One thing which worries me about this is debouncing,
using polling is automatically debounced, using an external interrupt won't
be. Ideally there would be some common code somewhere to deal with gpio
connected buttons (which this in essence is) which does debouncing ...

Again I think this is something best left as a future enhancement.

<snip>

>> diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
>> new file mode 100644
>> index 0000000..1ef5c89
>> --- /dev/null
>> +++ b/include/linux/clk/sunxi.h
>> @@ -0,0 +1,22 @@
>> +/*
>> + * Copyright 2013 - Hans de Goede <hdegoede@redhat.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef __LINUX_CLK_SUNXI_H_
>> +#define __LINUX_CLK_SUNXI_H_
>> +
>> +#include <linux/clk.h>
>> +
>> +void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
>> +
>> +#endif
>
> Hmmm, I see no implementation for this function. Didn't you forget
> a file here? (and it should probably be a separate patch anyway).

The implementation is part of Emilio's clk branch, but he forgot
to add a header for it, so I'm fixing that up here, I guess this
should go through Emlio's tree as a separate patch.

> Thanks a lot for this work,

You're welcome. I think it is great to see how far along upstream sunxi
support has come thanks to work of all involved. It is really becoming
usable now :)

Regards,

Hans

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

* Re: Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
  2013-12-15 13:58         ` Maxime Ripard
@ 2013-12-15 14:31           ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-15 14:31 UTC (permalink / raw)
  To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
  Cc: Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

On 12/15/2013 02:58 PM, Maxime Ripard wrote:
> Hi Hans,
>
> On Sat, Dec 14, 2013 at 10:58:12PM +0100, Hans de Goede wrote:
>> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>
> Commit-log :)

Heh.

Note as said before I expect David to take things from here.

>
>> ---
>>   arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 16 ++++++++++++++++
>>   arch/arm/boot/dts/sun4i-a10.dtsi           | 16 ++++++++++++++++
>>   2 files changed, 32 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
>> index 425a7db..d193937 100644
>> --- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
>> +++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
>> @@ -42,7 +42,23 @@
>>   			};
>>   		};
>>
>> +		sdc0: sdc@01c0f000 {
>> +			pinctrl-names = "default";
>> +			pinctrl-0 = <&sdc0_pins_a>;
>> +			pinctrl-1 = <&mmc0_cd_pin_cubieboard>;
>> +			cd-gpios = <&pio 7 1 0>; /* PH1 */
>> +			cd-mode = <1>;
>> +			status = "okay";
>> +		};
>> +
>>   		pinctrl@01c20800 {
>> +			mmc0_cd_pin_cubieboard: mmc0_cd_pin@0 {
>> +				allwinner,pins = "PH1";
>> +				allwinner,function = "gpio_in";
>> +				allwinner,drive = <0>;
>> +				allwinner,pull = <0>;
>> +			};
>> +
>
> You seem to be using mmc and sdc without any real distinction. Please
> try to be consistent and use only one of the two (and I have a slight
> preference for mmc :))

I just took what David was using. I agree picking one and staying with
it would be better.

>
>>   			led_pins_cubieboard: led_pins@0 {
>>   				allwinner,pins = "PH20", "PH21";
>>   				allwinner,function = "gpio_out";
>> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
>> index 4dccdb0..13bccd5 100644
>> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
>> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
>> @@ -306,6 +306,15 @@
>>   			#size-cells = <0>;
>>   		};
>>
>> +		sdc0: sdc@01c0f000 {
>> +			compatible = "allwinner,sun4i-mmc";
>> +			reg = <0x01c0f000 0x1000>;
>> +			clocks = <&ahb_gates 8>, <&mmc0>;
>> +			interrupts = <32>;
>> +			bus-width = <4>;
>> +			status = "disabled";
>> +		};
>> +
>
> The A10 has much more mmc controller doesn't it?

Yes 4 of them.

> Could you add all of them in the DT ?
>
>>   		intc: interrupt-controller@01c20400 {
>>   			compatible = "allwinner,sun4i-ic";
>>   			reg = <0x01c20400 0x400>;
>> @@ -376,6 +385,13 @@
>>   				allwinner,drive = <0>;
>>   				allwinner,pull = <0>;
>>   			};
>> +
>> +			sdc0_pins_a: sdc0@0 {
>> +				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
>> +				allwinner,function = "mmc0";
>> +				allwinner,drive = <3>;
>> +				allwinner,pull = <1>;
>
> Wow, you need both the pullups and a 40mA output?

Yes and no. The pullups are enabled by uboot and the allwinner
sources, most of my testing has been done without them, which
seems to work fine. I've enabled them to be consisten with the
allwinner sources and u-boot.

As for drive = <3>, we need drive = <2> for normal modes,
and drive = <3> for ddr mode. I simply picked <3> to keep
things KISS. It should not matter much in power usage, as
it will only make the flanks of the signal more steep. Once the
desired output level is reached the current will drop off. It will
use more current when changing the level, but for half the time,
so the effective power usage (current * time) is the same.

> Ideally, I'd like this patch to be splitted into three:
>    - One that adds the MMC controller nodes to the DTSI
>    - One that adds the muxing options you need to the pinctrl node
>    - One that enables the controller on the boards

Sounds like a good job for David. Note I've a lot more boards for
which I would like to add mmc support or dts files in general
(will do so as time permits).

For those boards which already have a dts I'll send mmc adding dts
patches to David for now so he can add the changes to the patch-set.

How do you want to deal with new boards ? Send the addition of the
base board to you (and CC David as he will need them in his tree too),
and then send a patch to add mmc to the dts to David ?

Or should I simply make it one big patch including mmc in the initial
commit ?

Regards,

Hans

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

* [linux-sunxi] Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
@ 2013-12-15 14:31           ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-15 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/15/2013 02:58 PM, Maxime Ripard wrote:
> Hi Hans,
>
> On Sat, Dec 14, 2013 at 10:58:12PM +0100, Hans de Goede wrote:
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>
> Commit-log :)

Heh.

Note as said before I expect David to take things from here.

>
>> ---
>>   arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 16 ++++++++++++++++
>>   arch/arm/boot/dts/sun4i-a10.dtsi           | 16 ++++++++++++++++
>>   2 files changed, 32 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
>> index 425a7db..d193937 100644
>> --- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
>> +++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
>> @@ -42,7 +42,23 @@
>>   			};
>>   		};
>>
>> +		sdc0: sdc at 01c0f000 {
>> +			pinctrl-names = "default";
>> +			pinctrl-0 = <&sdc0_pins_a>;
>> +			pinctrl-1 = <&mmc0_cd_pin_cubieboard>;
>> +			cd-gpios = <&pio 7 1 0>; /* PH1 */
>> +			cd-mode = <1>;
>> +			status = "okay";
>> +		};
>> +
>>   		pinctrl at 01c20800 {
>> +			mmc0_cd_pin_cubieboard: mmc0_cd_pin at 0 {
>> +				allwinner,pins = "PH1";
>> +				allwinner,function = "gpio_in";
>> +				allwinner,drive = <0>;
>> +				allwinner,pull = <0>;
>> +			};
>> +
>
> You seem to be using mmc and sdc without any real distinction. Please
> try to be consistent and use only one of the two (and I have a slight
> preference for mmc :))

I just took what David was using. I agree picking one and staying with
it would be better.

>
>>   			led_pins_cubieboard: led_pins at 0 {
>>   				allwinner,pins = "PH20", "PH21";
>>   				allwinner,function = "gpio_out";
>> diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
>> index 4dccdb0..13bccd5 100644
>> --- a/arch/arm/boot/dts/sun4i-a10.dtsi
>> +++ b/arch/arm/boot/dts/sun4i-a10.dtsi
>> @@ -306,6 +306,15 @@
>>   			#size-cells = <0>;
>>   		};
>>
>> +		sdc0: sdc at 01c0f000 {
>> +			compatible = "allwinner,sun4i-mmc";
>> +			reg = <0x01c0f000 0x1000>;
>> +			clocks = <&ahb_gates 8>, <&mmc0>;
>> +			interrupts = <32>;
>> +			bus-width = <4>;
>> +			status = "disabled";
>> +		};
>> +
>
> The A10 has much more mmc controller doesn't it?

Yes 4 of them.

> Could you add all of them in the DT ?
>
>>   		intc: interrupt-controller at 01c20400 {
>>   			compatible = "allwinner,sun4i-ic";
>>   			reg = <0x01c20400 0x400>;
>> @@ -376,6 +385,13 @@
>>   				allwinner,drive = <0>;
>>   				allwinner,pull = <0>;
>>   			};
>> +
>> +			sdc0_pins_a: sdc0 at 0 {
>> +				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
>> +				allwinner,function = "mmc0";
>> +				allwinner,drive = <3>;
>> +				allwinner,pull = <1>;
>
> Wow, you need both the pullups and a 40mA output?

Yes and no. The pullups are enabled by uboot and the allwinner
sources, most of my testing has been done without them, which
seems to work fine. I've enabled them to be consisten with the
allwinner sources and u-boot.

As for drive = <3>, we need drive = <2> for normal modes,
and drive = <3> for ddr mode. I simply picked <3> to keep
things KISS. It should not matter much in power usage, as
it will only make the flanks of the signal more steep. Once the
desired output level is reached the current will drop off. It will
use more current when changing the level, but for half the time,
so the effective power usage (current * time) is the same.

> Ideally, I'd like this patch to be splitted into three:
>    - One that adds the MMC controller nodes to the DTSI
>    - One that adds the muxing options you need to the pinctrl node
>    - One that enables the controller on the boards

Sounds like a good job for David. Note I've a lot more boards for
which I would like to add mmc support or dts files in general
(will do so as time permits).

For those boards which already have a dts I'll send mmc adding dts
patches to David for now so he can add the changes to the patch-set.

How do you want to deal with new boards ? Send the addition of the
base board to you (and CC David as he will need them in his tree too),
and then send a patch to add mmc to the dts to David ?

Or should I simply make it one big patch including mmc in the initial
commit ?

Regards,

Hans

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

* Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 14:20           ` Hans de Goede
@ 2013-12-15 16:21               ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-15 16:21 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 6784 bytes --]

On Sun, Dec 15, 2013 at 03:20:19PM +0100, Hans de Goede wrote:
> On 12/15/2013 02:44 PM, Maxime Ripard wrote:
> >Hi Hans,
> >
> >I won't comment on the MMC driver itself, and leave Chris comment on
> >that, but still, I have a few things.
> >
> >On Sat, Dec 14, 2013 at 10:58:11PM +0100, Hans de Goede wrote:
> >>From: David Lanzendörfer <david.lanzendoerfer-Z7Kmv9EsliU@public.gmane.org>
> >>
> >>This is based on the driver Allwinner ships in there Android kernel sources.
> >>
> >>Initial porting to upstream kernels done by David Lanzendörfer, additional
> >>fixes and cleanups by Hans de Goede.
> >>
> >>Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> >
> >Your commit log is a bit sparse. What capabilities this controller
> >has? Is it using DMA? If so, how? What SoCs are supported/it has been
> >tested on? etc.
> 
> David, since you'll be doing v2 I guess you'll be filling in v2. FYI
> I've tested this on sun4i-a10, sun5i-a10s sun5i-a13 and sun7i-a20.
> 
> It uses dma in bus-master mode using a built-in designware idmac controller,
> which is identical to the one found in the mmc-dw hosts. Note the rest of
> the host is not identical, I've looked into reusing the mmc-dw driver but
> that does not seem like a good idea (manual sending stop commands
> versus auto stop on sunxi, completely different registers, etc.).

Thanks :)

This is exactly what I expect from a commit log of such driver ;)

> >>+static const struct of_device_id sunxi_mmc_of_match[] = {
> >>+	{ .compatible = "allwinner,sun4i-mmc", },
> >>+	{ .compatible = "allwinner,sun5i-mmc", },
> >
> >Please use sun5i-a13-mmc as your compatible.
> 
> Can you explain a bit why? In essence currently we have
> 2 versions of the mmc controller, those found on sun4i
> and those found on sun5i and sun7i. I thought that the
> norm was to use the oldest soc version in which a revision
> of an ip-block first appears as the compatible string ?

Indeed.

> Note I've tested this with both a13 and a10s SOCs, if we
> add a sun5i-a13-mmc we should also add a sun5i-a10s-mmc
> and a sun5i-a20-mmc, or would that then be sun7i-a20-mmc?

And the A13 has been the first SoC in the sun5i family, hence why we
should use sun5i-a13 as the prefix here. If the A10s and A20 would not
have been compatible with the A13 MMC controller, we would have used
sun5i-a10s-mmc and sun7i-a20-mmc, respectively.

> To me just having sun5i-mmc for sun5i+ socs seems simpler.

And if we ever find out that A10s or A13 differs in some way, we will
end up introducing a compatible that will be sun5i-a10s-mmc, along
with the sun5i-mmc we already have, which is not really the more
consistent thing we would have done.

> <snip>
> 
> >>+	mmc->ops		= &sunxi_mmc_ops;
> >>+	mmc->max_blk_count	= 8192;
> >>+	mmc->max_blk_size	= 4096;
> >>+	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
> >>+	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
> >>+	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
> >>+	/* 400kHz ~ 50MHz */
> >>+	mmc->f_min		=   400000;
> >>+	mmc->f_max		= 50000000;
> >
> >Hmmm, the tables earlier seem to suggest it can do much more than that.
> 
> I know, but this is what the allwinner android kernels are using, actually
> in case of sdc3 they are putting 200000000 in f_max (as that is often
> used for sdio cards) but then later in set_ios they clamp the passed
> in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
> worked. Hence I've simply gone for a safe range for now. If someone has
> cards capable of doing 200 MHz we could certainly run various tests and
> try to improve this, but for now this seems a sane range to start with.

That's probably something that you should mention in your comment then :)

> <snip>
> 
> >> +	/* indicator pins */
> >> +	int wp_pin;
> >> +	int cd_pin;
> >> +	int cd_mode;
> >> +#define CARD_DETECT_BY_GPIO_POLL (1)	/* mmc detected by gpio check */
> >> +#define CARD_ALWAYS_PRESENT      (2)	/* mmc always present */
> >
> > Just a question here, have you tested to use the external interrupts?
> > (Is that even possible on the pins that are used as card detect?)
> >
> 
> No I've not tried that, there was code for this in the original allwinner
> driver, but no boards were actually using it.
> 
> As for it being possible on the pins being used, it is possible on (most)
> port H pins and the cubie* and a20-olinuxino-micro boards are using PH pins
> for cd. Others are not.  One thing which worries me about this is debouncing,
> using polling is automatically debounced, using an external interrupt won't
> be. Ideally there would be some common code somewhere to deal with gpio
> connected buttons (which this in essence is) which does debouncing ...
> 
> Again I think this is something best left as a future enhancement.

Yep, definitely, I was just being curious :)

> >>diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
> >>new file mode 100644
> >>index 0000000..1ef5c89
> >>--- /dev/null
> >>+++ b/include/linux/clk/sunxi.h
> >>@@ -0,0 +1,22 @@
> >>+/*
> >>+ * Copyright 2013 - Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> >>+ *
> >>+ * This program is free software; you can redistribute it and/or modify
> >>+ * it under the terms of the GNU General Public License as published by
> >>+ * the Free Software Foundation; either version 2 of the License, or
> >>+ * (at your option) any later version.
> >>+ *
> >>+ * This program is distributed in the hope that it will be useful,
> >>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >>+ * GNU General Public License for more details.
> >>+ */
> >>+
> >>+#ifndef __LINUX_CLK_SUNXI_H_
> >>+#define __LINUX_CLK_SUNXI_H_
> >>+
> >>+#include <linux/clk.h>
> >>+
> >>+void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
> >>+
> >>+#endif
> >
> >Hmmm, I see no implementation for this function. Didn't you forget
> >a file here? (and it should probably be a separate patch anyway).
> 
> The implementation is part of Emilio's clk branch, but he forgot
> to add a header for it, so I'm fixing that up here, I guess this
> should go through Emlio's tree as a separate patch.

As far as I know, this work has never been posted, let alone
merged. Anyway, the dependencies you have is something that you should
mention in your cover letter, so that we know what to merge, in which
order, and when to merge it.

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 16:21               ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-15 16:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Dec 15, 2013 at 03:20:19PM +0100, Hans de Goede wrote:
> On 12/15/2013 02:44 PM, Maxime Ripard wrote:
> >Hi Hans,
> >
> >I won't comment on the MMC driver itself, and leave Chris comment on
> >that, but still, I have a few things.
> >
> >On Sat, Dec 14, 2013 at 10:58:11PM +0100, Hans de Goede wrote:
> >>From: David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
> >>
> >>This is based on the driver Allwinner ships in there Android kernel sources.
> >>
> >>Initial porting to upstream kernels done by David Lanzend?rfer, additional
> >>fixes and cleanups by Hans de Goede.
> >>
> >>Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >
> >Your commit log is a bit sparse. What capabilities this controller
> >has? Is it using DMA? If so, how? What SoCs are supported/it has been
> >tested on? etc.
> 
> David, since you'll be doing v2 I guess you'll be filling in v2. FYI
> I've tested this on sun4i-a10, sun5i-a10s sun5i-a13 and sun7i-a20.
> 
> It uses dma in bus-master mode using a built-in designware idmac controller,
> which is identical to the one found in the mmc-dw hosts. Note the rest of
> the host is not identical, I've looked into reusing the mmc-dw driver but
> that does not seem like a good idea (manual sending stop commands
> versus auto stop on sunxi, completely different registers, etc.).

Thanks :)

This is exactly what I expect from a commit log of such driver ;)

> >>+static const struct of_device_id sunxi_mmc_of_match[] = {
> >>+	{ .compatible = "allwinner,sun4i-mmc", },
> >>+	{ .compatible = "allwinner,sun5i-mmc", },
> >
> >Please use sun5i-a13-mmc as your compatible.
> 
> Can you explain a bit why? In essence currently we have
> 2 versions of the mmc controller, those found on sun4i
> and those found on sun5i and sun7i. I thought that the
> norm was to use the oldest soc version in which a revision
> of an ip-block first appears as the compatible string ?

Indeed.

> Note I've tested this with both a13 and a10s SOCs, if we
> add a sun5i-a13-mmc we should also add a sun5i-a10s-mmc
> and a sun5i-a20-mmc, or would that then be sun7i-a20-mmc?

And the A13 has been the first SoC in the sun5i family, hence why we
should use sun5i-a13 as the prefix here. If the A10s and A20 would not
have been compatible with the A13 MMC controller, we would have used
sun5i-a10s-mmc and sun7i-a20-mmc, respectively.

> To me just having sun5i-mmc for sun5i+ socs seems simpler.

And if we ever find out that A10s or A13 differs in some way, we will
end up introducing a compatible that will be sun5i-a10s-mmc, along
with the sun5i-mmc we already have, which is not really the more
consistent thing we would have done.

> <snip>
> 
> >>+	mmc->ops		= &sunxi_mmc_ops;
> >>+	mmc->max_blk_count	= 8192;
> >>+	mmc->max_blk_size	= 4096;
> >>+	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
> >>+	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
> >>+	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
> >>+	/* 400kHz ~ 50MHz */
> >>+	mmc->f_min		=   400000;
> >>+	mmc->f_max		= 50000000;
> >
> >Hmmm, the tables earlier seem to suggest it can do much more than that.
> 
> I know, but this is what the allwinner android kernels are using, actually
> in case of sdc3 they are putting 200000000 in f_max (as that is often
> used for sdio cards) but then later in set_ios they clamp the passed
> in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
> worked. Hence I've simply gone for a safe range for now. If someone has
> cards capable of doing 200 MHz we could certainly run various tests and
> try to improve this, but for now this seems a sane range to start with.

That's probably something that you should mention in your comment then :)

> <snip>
> 
> >> +	/* indicator pins */
> >> +	int wp_pin;
> >> +	int cd_pin;
> >> +	int cd_mode;
> >> +#define CARD_DETECT_BY_GPIO_POLL (1)	/* mmc detected by gpio check */
> >> +#define CARD_ALWAYS_PRESENT      (2)	/* mmc always present */
> >
> > Just a question here, have you tested to use the external interrupts?
> > (Is that even possible on the pins that are used as card detect?)
> >
> 
> No I've not tried that, there was code for this in the original allwinner
> driver, but no boards were actually using it.
> 
> As for it being possible on the pins being used, it is possible on (most)
> port H pins and the cubie* and a20-olinuxino-micro boards are using PH pins
> for cd. Others are not.  One thing which worries me about this is debouncing,
> using polling is automatically debounced, using an external interrupt won't
> be. Ideally there would be some common code somewhere to deal with gpio
> connected buttons (which this in essence is) which does debouncing ...
> 
> Again I think this is something best left as a future enhancement.

Yep, definitely, I was just being curious :)

> >>diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
> >>new file mode 100644
> >>index 0000000..1ef5c89
> >>--- /dev/null
> >>+++ b/include/linux/clk/sunxi.h
> >>@@ -0,0 +1,22 @@
> >>+/*
> >>+ * Copyright 2013 - Hans de Goede <hdegoede@redhat.com>
> >>+ *
> >>+ * This program is free software; you can redistribute it and/or modify
> >>+ * it under the terms of the GNU General Public License as published by
> >>+ * the Free Software Foundation; either version 2 of the License, or
> >>+ * (at your option) any later version.
> >>+ *
> >>+ * This program is distributed in the hope that it will be useful,
> >>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >>+ * GNU General Public License for more details.
> >>+ */
> >>+
> >>+#ifndef __LINUX_CLK_SUNXI_H_
> >>+#define __LINUX_CLK_SUNXI_H_
> >>+
> >>+#include <linux/clk.h>
> >>+
> >>+void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
> >>+
> >>+#endif
> >
> >Hmmm, I see no implementation for this function. Didn't you forget
> >a file here? (and it should probably be a separate patch anyway).
> 
> The implementation is part of Emilio's clk branch, but he forgot
> to add a header for it, so I'm fixing that up here, I guess this
> should go through Emlio's tree as a separate patch.

As far as I know, this work has never been posted, let alone
merged. Anyway, the dependencies you have is something that you should
mention in your cover letter, so that we know what to merge, in which
order, and when to merge it.

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131215/06403cd2/attachment-0001.sig>

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

* Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 14:20           ` Hans de Goede
@ 2013-12-15 16:33               ` David Lanzendörfer
  -1 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-15 16:33 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Maxime Ripard, Chris Ball, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 876 bytes --]

Hi
> David, since you'll be doing v2 I guess you'll be filling in v2. FYI
> I've tested this on sun4i-a10, sun5i-a10s sun5i-a13 and sun7i-a20.
Yeah. I'll take care of it.
I'll work out a V2 which incorporates all the comments made on the first patch
set you've handed in.

> It uses dma in bus-master mode using a built-in designware idmac controller,
> which is identical to the one found in the mmc-dw hosts. Note the rest of
> the host is not identical, I've looked into reusing the mmc-dw driver but
> that does not seem like a good idea (manual sending stop commands
> versus auto stop on sunxi, completely different registers, etc.).
It's already a good thing, that I know now what the command set of the IDMAC 
controller is, since I had no idea how to configure it exactly.

> The plan is for David to send v2 of this patch-set so that should take care
> of that :)
ok

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 16:33               ` David Lanzendörfer
  0 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-15 16:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi
> David, since you'll be doing v2 I guess you'll be filling in v2. FYI
> I've tested this on sun4i-a10, sun5i-a10s sun5i-a13 and sun7i-a20.
Yeah. I'll take care of it.
I'll work out a V2 which incorporates all the comments made on the first patch
set you've handed in.

> It uses dma in bus-master mode using a built-in designware idmac controller,
> which is identical to the one found in the mmc-dw hosts. Note the rest of
> the host is not identical, I've looked into reusing the mmc-dw driver but
> that does not seem like a good idea (manual sending stop commands
> versus auto stop on sunxi, completely different registers, etc.).
It's already a good thing, that I know now what the command set of the IDMAC 
controller is, since I had no idea how to configure it exactly.

> The plan is for David to send v2 of this patch-set so that should take care
> of that :)
ok
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131215/86b73642/attachment.sig>

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 16:21               ` Maxime Ripard
@ 2013-12-15 18:41                 ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-15 18:41 UTC (permalink / raw)
  To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
  Cc: Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

On 12/15/2013 05:21 PM, Maxime Ripard wrote:
> On Sun, Dec 15, 2013 at 03:20:19PM +0100, Hans de Goede wrote:
<snip>

>>>> +static const struct of_device_id sunxi_mmc_of_match[] = {
>>>> +	{ .compatible = "allwinner,sun4i-mmc", },
>>>> +	{ .compatible = "allwinner,sun5i-mmc", },
>>>
>>> Please use sun5i-a13-mmc as your compatible.
>>
>> Can you explain a bit why? In essence currently we have
>> 2 versions of the mmc controller, those found on sun4i
>> and those found on sun5i and sun7i. I thought that the
>> norm was to use the oldest soc version in which a revision
>> of an ip-block first appears as the compatible string ?
>
> Indeed.
>
>> Note I've tested this with both a13 and a10s SOCs, if we
>> add a sun5i-a13-mmc we should also add a sun5i-a10s-mmc
>> and a sun5i-a20-mmc, or would that then be sun7i-a20-mmc?
>
> And the A13 has been the first SoC in the sun5i family, hence why we
> should use sun5i-a13 as the prefix here. If the A10s and A20 would not
> have been compatible with the A13 MMC controller, we would have used
> sun5i-a10s-mmc and sun7i-a20-mmc, respectively.

Ah I see, you meant s/allwinner,sun5i-mmc/allwinner,sun5i-a13-mmc/

I interpreted your remark as adding an extra allwinner,sun5i-a13-mmc
compatible string. Using allwinner,sun5i-a13-mmc instead of
allwinner,sun5i-mmc makes sense. David having us both editing the
driver at the same time seems counter-productive, can you take care
of this too?

>
>> To me just having sun5i-mmc for sun5i+ socs seems simpler.
>
> And if we ever find out that A10s or A13 differs in some way, we will
> end up introducing a compatible that will be sun5i-a10s-mmc, along
> with the sun5i-mmc we already have, which is not really the more
> consistent thing we would have done.
>
>> <snip>
>>
>>>> +	mmc->ops		= &sunxi_mmc_ops;
>>>> +	mmc->max_blk_count	= 8192;
>>>> +	mmc->max_blk_size	= 4096;
>>>> +	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
>>>> +	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
>>>> +	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
>>>> +	/* 400kHz ~ 50MHz */
>>>> +	mmc->f_min		=   400000;
>>>> +	mmc->f_max		= 50000000;
>>>
>>> Hmmm, the tables earlier seem to suggest it can do much more than that.
>>
>> I know, but this is what the allwinner android kernels are using, actually
>> in case of sdc3 they are putting 200000000 in f_max (as that is often
>> used for sdio cards) but then later in set_ios they clamp the passed
>> in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
>> worked. Hence I've simply gone for a safe range for now. If someone has
>> cards capable of doing 200 MHz we could certainly run various tests and
>> try to improve this, but for now this seems a sane range to start with.
>
> That's probably something that you should mention in your comment then :)

Good point, David ?

<snip>

>>> Hmmm, I see no implementation for this function. Didn't you forget
>>> a file here? (and it should probably be a separate patch anyway).
>>
>> The implementation is part of Emilio's clk branch, but he forgot
>> to add a header for it, so I'm fixing that up here, I guess this
>> should go through Emlio's tree as a separate patch.
>
> As far as I know, this work has never been posted, let alone
> merged.

I don't know if it has been posted, but it has been in his tree for a
while now. Anyways I'll send him a standalone patch for the clk/sunxi.h
file.

 > Anyway, the dependencies you have is something that you should
 > mention in your cover letter, so that we know what to merge, in which
 > order, and when to merge it.

Right, my bad, sorry. I was so happy I was finally ready to send the patch
upstream (I finally had fixed everything on my todo list), I rushed the
cover letter a bit. I was planning on putting things like this in there,
as well as why we didn't try to extend the mmc-dw driver, but I forgot.

Thanks & Regards,

Hans

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 18:41                 ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-15 18:41 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/15/2013 05:21 PM, Maxime Ripard wrote:
> On Sun, Dec 15, 2013 at 03:20:19PM +0100, Hans de Goede wrote:
<snip>

>>>> +static const struct of_device_id sunxi_mmc_of_match[] = {
>>>> +	{ .compatible = "allwinner,sun4i-mmc", },
>>>> +	{ .compatible = "allwinner,sun5i-mmc", },
>>>
>>> Please use sun5i-a13-mmc as your compatible.
>>
>> Can you explain a bit why? In essence currently we have
>> 2 versions of the mmc controller, those found on sun4i
>> and those found on sun5i and sun7i. I thought that the
>> norm was to use the oldest soc version in which a revision
>> of an ip-block first appears as the compatible string ?
>
> Indeed.
>
>> Note I've tested this with both a13 and a10s SOCs, if we
>> add a sun5i-a13-mmc we should also add a sun5i-a10s-mmc
>> and a sun5i-a20-mmc, or would that then be sun7i-a20-mmc?
>
> And the A13 has been the first SoC in the sun5i family, hence why we
> should use sun5i-a13 as the prefix here. If the A10s and A20 would not
> have been compatible with the A13 MMC controller, we would have used
> sun5i-a10s-mmc and sun7i-a20-mmc, respectively.

Ah I see, you meant s/allwinner,sun5i-mmc/allwinner,sun5i-a13-mmc/

I interpreted your remark as adding an extra allwinner,sun5i-a13-mmc
compatible string. Using allwinner,sun5i-a13-mmc instead of
allwinner,sun5i-mmc makes sense. David having us both editing the
driver at the same time seems counter-productive, can you take care
of this too?

>
>> To me just having sun5i-mmc for sun5i+ socs seems simpler.
>
> And if we ever find out that A10s or A13 differs in some way, we will
> end up introducing a compatible that will be sun5i-a10s-mmc, along
> with the sun5i-mmc we already have, which is not really the more
> consistent thing we would have done.
>
>> <snip>
>>
>>>> +	mmc->ops		= &sunxi_mmc_ops;
>>>> +	mmc->max_blk_count	= 8192;
>>>> +	mmc->max_blk_size	= 4096;
>>>> +	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
>>>> +	mmc->max_seg_size	= (1 << host->idma_des_size_bits);
>>>> +	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
>>>> +	/* 400kHz ~ 50MHz */
>>>> +	mmc->f_min		=   400000;
>>>> +	mmc->f_max		= 50000000;
>>>
>>> Hmmm, the tables earlier seem to suggest it can do much more than that.
>>
>> I know, but this is what the allwinner android kernels are using, actually
>> in case of sdc3 they are putting 200000000 in f_max (as that is often
>> used for sdio cards) but then later in set_ios they clamp the passed
>> in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
>> worked. Hence I've simply gone for a safe range for now. If someone has
>> cards capable of doing 200 MHz we could certainly run various tests and
>> try to improve this, but for now this seems a sane range to start with.
>
> That's probably something that you should mention in your comment then :)

Good point, David ?

<snip>

>>> Hmmm, I see no implementation for this function. Didn't you forget
>>> a file here? (and it should probably be a separate patch anyway).
>>
>> The implementation is part of Emilio's clk branch, but he forgot
>> to add a header for it, so I'm fixing that up here, I guess this
>> should go through Emlio's tree as a separate patch.
>
> As far as I know, this work has never been posted, let alone
> merged.

I don't know if it has been posted, but it has been in his tree for a
while now. Anyways I'll send him a standalone patch for the clk/sunxi.h
file.

 > Anyway, the dependencies you have is something that you should
 > mention in your cover letter, so that we know what to merge, in which
 > order, and when to merge it.

Right, my bad, sorry. I was so happy I was finally ready to send the patch
upstream (I finally had fixed everything on my todo list), I rushed the
cover letter a bit. I was planning on putting things like this in there,
as well as why we didn't try to extend the mmc-dw driver, but I forgot.

Thanks & Regards,

Hans

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 18:41                 ` [linux-sunxi] " Hans de Goede
@ 2013-12-15 19:35                     ` David Lanzendörfer
  -1 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-15 19:35 UTC (permalink / raw)
  To: Hans de Goede
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chris Ball,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 1337 bytes --]

Hi

> >>>> [...]
> >>>> +	mmc->f_max		= 50000000;
> >>>> [...]
> >> [...]
> >> in case of sdc3 they are putting 200000000 in f_max (as that is often
> >> used for sdio cards) but then later in set_ios they clamp the passed
> >> in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
> >> worked. Hence I've simply gone for a safe range for now. If someone has
> >> cards capable of doing 200 MHz we could certainly run various tests and
> >> try to improve this, but for now this seems a sane range to start with.
> > That's probably something that you should mention in your comment then :)
> Good point, David ?
Yes.
a) We should mention any reason why we did what.
b) If there is room for optimization we should mention that as well since:
	i) we won't remember every single detail in half a year
	ii) someone else might need to follow our considerations

> Right, my bad, sorry. I was so happy I was finally ready to send the patch
> upstream (I finally had fixed everything on my todo list), I rushed the
> cover letter a bit. I was planning on putting things like this in there,
> as well as why we didn't try to extend the mmc-dw driver, but I forgot.
Do you have something like this in mind? -> drivers/mmc/host/dw_mmc-exynos.c
Might actually be working if it actually is the same IDMAC controller.

cheers
David

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 19:35                     ` David Lanzendörfer
  0 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-15 19:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi

> >>>> [...]
> >>>> +	mmc->f_max		= 50000000;
> >>>> [...]
> >> [...]
> >> in case of sdc3 they are putting 200000000 in f_max (as that is often
> >> used for sdio cards) but then later in set_ios they clamp the passed
> >> in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
> >> worked. Hence I've simply gone for a safe range for now. If someone has
> >> cards capable of doing 200 MHz we could certainly run various tests and
> >> try to improve this, but for now this seems a sane range to start with.
> > That's probably something that you should mention in your comment then :)
> Good point, David ?
Yes.
a) We should mention any reason why we did what.
b) If there is room for optimization we should mention that as well since:
	i) we won't remember every single detail in half a year
	ii) someone else might need to follow our considerations

> Right, my bad, sorry. I was so happy I was finally ready to send the patch
> upstream (I finally had fixed everything on my todo list), I rushed the
> cover letter a bit. I was planning on putting things like this in there,
> as well as why we didn't try to extend the mmc-dw driver, but I forgot.
Do you have something like this in mind? -> drivers/mmc/host/dw_mmc-exynos.c
Might actually be working if it actually is the same IDMAC controller.

cheers
David
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131215/31695d5c/attachment.sig>

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 19:35                     ` [linux-sunxi] " David Lanzendörfer
@ 2013-12-15 20:18                         ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-15 20:18 UTC (permalink / raw)
  To: David Lanzendörfer
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chris Ball,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

On 12/15/2013 08:35 PM, David Lanzendörfer wrote:
> Hi
>
>>>>>> [...]
>>>>>> +	mmc->f_max		= 50000000;
>>>>>> [...]
>>>> [...]
>>>> in case of sdc3 they are putting 200000000 in f_max (as that is often
>>>> used for sdio cards) but then later in set_ios they clamp the passed
>>>> in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
>>>> worked. Hence I've simply gone for a safe range for now. If someone has
>>>> cards capable of doing 200 MHz we could certainly run various tests and
>>>> try to improve this, but for now this seems a sane range to start with.
>>> That's probably something that you should mention in your comment then :)
>> Good point, David ?
> Yes.
> a) We should mention any reason why we did what.
> b) If there is room for optimization we should mention that as well since:
> 	i) we won't remember every single detail in half a year
> 	ii) someone else might need to follow our considerations
>
>> Right, my bad, sorry. I was so happy I was finally ready to send the patch
>> upstream (I finally had fixed everything on my todo list), I rushed the
>> cover letter a bit. I was planning on putting things like this in there,
>> as well as why we didn't try to extend the mmc-dw driver, but I forgot.
> Do you have something like this in mind? -> drivers/mmc/host/dw_mmc-exynos.c

No, as explained in my previous mail the idmac being shared seemed to be the
only 2 things the dw-mmc controller and the sunxi-mmc controller have in common.

Looking at dw_mmc-exynos.c it still pretty much is the classic dw-mmc controller
with some extra bits, where as the sunxi controller is significantly different
(which allows us to write a significant simpler driver).

Regards,

Hans

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/groups/opt_out.

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 20:18                         ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-15 20:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/15/2013 08:35 PM, David Lanzend?rfer wrote:
> Hi
>
>>>>>> [...]
>>>>>> +	mmc->f_max		= 50000000;
>>>>>> [...]
>>>> [...]
>>>> in case of sdc3 they are putting 200000000 in f_max (as that is often
>>>> used for sdio cards) but then later in set_ios they clamp the passed
>>>> in clock to 47000000 Mhz, so I seriously doubt that 200Mhz has actually
>>>> worked. Hence I've simply gone for a safe range for now. If someone has
>>>> cards capable of doing 200 MHz we could certainly run various tests and
>>>> try to improve this, but for now this seems a sane range to start with.
>>> That's probably something that you should mention in your comment then :)
>> Good point, David ?
> Yes.
> a) We should mention any reason why we did what.
> b) If there is room for optimization we should mention that as well since:
> 	i) we won't remember every single detail in half a year
> 	ii) someone else might need to follow our considerations
>
>> Right, my bad, sorry. I was so happy I was finally ready to send the patch
>> upstream (I finally had fixed everything on my todo list), I rushed the
>> cover letter a bit. I was planning on putting things like this in there,
>> as well as why we didn't try to extend the mmc-dw driver, but I forgot.
> Do you have something like this in mind? -> drivers/mmc/host/dw_mmc-exynos.c

No, as explained in my previous mail the idmac being shared seemed to be the
only 2 things the dw-mmc controller and the sunxi-mmc controller have in common.

Looking at dw_mmc-exynos.c it still pretty much is the classic dw-mmc controller
with some extra bits, where as the sunxi controller is significantly different
(which allows us to write a significant simpler driver).

Regards,

Hans

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 20:18                         ` [linux-sunxi] " Hans de Goede
@ 2013-12-15 21:19                             ` David Lanzendörfer
  -1 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-15 21:19 UTC (permalink / raw)
  To: Hans de Goede
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chris Ball,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 703 bytes --]

> > [...]
> > Do you have something like this in mind? ->
> > drivers/mmc/host/dw_mmc-exynos.c
> No, as explained in my previous mail the idmac being shared seemed to be the
> only 2 things the dw-mmc controller and the sunxi-mmc controller have in
> common.
Ok.

> Looking at dw_mmc-exynos.c it still pretty much is the classic dw-mmc
> controller with some extra bits, where as the sunxi controller is
> significantly different (which allows us to write a significant simpler
> driver).
Do you have an outline for such a driver as you imagine it?
I'd be interested into some "experiments".
Maybe you have a repository where you could push a dedicated tree
for some colaboration on this?

regards
David

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 21:19                             ` David Lanzendörfer
  0 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-15 21:19 UTC (permalink / raw)
  To: linux-arm-kernel

> > [...]
> > Do you have something like this in mind? ->
> > drivers/mmc/host/dw_mmc-exynos.c
> No, as explained in my previous mail the idmac being shared seemed to be the
> only 2 things the dw-mmc controller and the sunxi-mmc controller have in
> common.
Ok.

> Looking at dw_mmc-exynos.c it still pretty much is the classic dw-mmc
> controller with some extra bits, where as the sunxi controller is
> significantly different (which allows us to write a significant simpler
> driver).
Do you have an outline for such a driver as you imagine it?
I'd be interested into some "experiments".
Maybe you have a repository where you could push a dedicated tree
for some colaboration on this?

regards
David
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131215/87862fea/attachment.sig>

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

* Re: [linux-sunxi] Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
  2013-12-15 14:31           ` [linux-sunxi] " Hans de Goede
@ 2013-12-15 21:44             ` Henrik Nordström
  -1 siblings, 0 replies; 62+ messages in thread
From: Henrik Nordström @ 2013-12-15 21:44 UTC (permalink / raw)
  To: linux-sunxi
  Cc: linux-mmc, Chris Ball, David Lanzendörfer, linux-arm-kernel,
	devicetree

sön 2013-12-15 klockan 15:31 +0100 skrev Hans de Goede:

> Yes and no. The pullups are enabled by uboot and the allwinner
> sources, most of my testing has been done without them, which
> seems to work fine. I've enabled them to be consisten with the
> allwinner sources and u-boot.

Many boards have external pullups where needed for the MMC bus. On such
boards it's likely not a good idea to enable internal pullups.

Regards
Henrik


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [linux-sunxi] Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
@ 2013-12-15 21:44             ` Henrik Nordström
  0 siblings, 0 replies; 62+ messages in thread
From: Henrik Nordström @ 2013-12-15 21:44 UTC (permalink / raw)
  To: linux-arm-kernel

s?n 2013-12-15 klockan 15:31 +0100 skrev Hans de Goede:

> Yes and no. The pullups are enabled by uboot and the allwinner
> sources, most of my testing has been done without them, which
> seems to work fine. I've enabled them to be consisten with the
> allwinner sources and u-boot.

Many boards have external pullups where needed for the MMC bus. On such
boards it's likely not a good idea to enable internal pullups.

Regards
Henrik

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 13:44         ` Maxime Ripard
@ 2013-12-15 22:01           ` Michal Suchanek
  -1 siblings, 0 replies; 62+ messages in thread
From: Michal Suchanek @ 2013-12-15 22:01 UTC (permalink / raw)
  To: linux-sunxi
  Cc: Hans de Goede, Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA, devicetree,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 15 December 2013 14:44, Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
>> --- a/drivers/mmc/host/Kconfig
>> +++ b/drivers/mmc/host/Kconfig
>> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
>>       help
>>         Say Y here to include driver code to support SD/MMC card interface
>>         of Realtek PCI-E card reader
>> +
>> +config MMC_SUNXI
>> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
>> +     depends on ARCH_SUNXI
>> +     default y
>
> I'm not that fond of these "default y" patterns. It forces the driver
> down to every user of the multiplatform kernels. I'd suggest removing
> the default and adding the driver to the defconfigs we have.

And why would you build support for sunxi without building support for
sunxi mmc?

Like 90%+ sunxi devices actually have a SD slot or an eMMC or a SDIO
card connected so what's the point of supporting sunxi without sunxi
mmc?

Thanks

Michal

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-15 22:01           ` Michal Suchanek
  0 siblings, 0 replies; 62+ messages in thread
From: Michal Suchanek @ 2013-12-15 22:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 15 December 2013 14:44, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
>> --- a/drivers/mmc/host/Kconfig
>> +++ b/drivers/mmc/host/Kconfig
>> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
>>       help
>>         Say Y here to include driver code to support SD/MMC card interface
>>         of Realtek PCI-E card reader
>> +
>> +config MMC_SUNXI
>> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
>> +     depends on ARCH_SUNXI
>> +     default y
>
> I'm not that fond of these "default y" patterns. It forces the driver
> down to every user of the multiplatform kernels. I'd suggest removing
> the default and adding the driver to the defconfigs we have.

And why would you build support for sunxi without building support for
sunxi mmc?

Like 90%+ sunxi devices actually have a SD slot or an eMMC or a SDIO
card connected so what's the point of supporting sunxi without sunxi
mmc?

Thanks

Michal

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

* Re: Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
  2013-12-15 14:31           ` [linux-sunxi] " Hans de Goede
@ 2013-12-16  9:04               ` David Lanzendörfer
  -1 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-16  9:04 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Hans de Goede, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA, Chris Ball,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2291 bytes --]

Hi
> Note as said before I expect David to take things from here.
I will start working on it this evening.

> I just took what David was using. I agree picking one and staying with
> it would be better.
There is a reason why my working branch was called "plsdsif"
(short for "Please don't shout at me in Finnish")

> Yes and no. The pullups are enabled by uboot and the allwinner
> sources, most of my testing has been done without them, which
> seems to work fine. I've enabled them to be consisten with the
> allwinner sources and u-boot.
Ok

> As for drive = <3>, we need drive = <2> for normal modes,
> and drive = <3> for ddr mode. I simply picked <3> to keep
> things KISS. It should not matter much in power usage, as
> it will only make the flanks of the signal more steep. Once the
> desired output level is reached the current will drop off. It will
> use more current when changing the level, but for half the time,
> so the effective power usage (current * time) is the same.
In this case lets implement a switch which enables the pull ups for DDR
mode and lets disable it by default in turn.
This way we can make sure that we don't have doubled pull up,
since this could actually mess up some circuitry.

> > Ideally, I'd like this patch to be splitted into three:
> >    - One that adds the MMC controller nodes to the DTSI
> >    - One that adds the muxing options you need to the pinctrl node
> >    - One that enables the controller on the boards
> Sounds like a good job for David. Note I've a lot more boards for
> which I would like to add mmc support or dts files in general
> (will do so as time permits).
Ok. I will work on it this evening.

> For those boards which already have a dts I'll send mmc adding dts
> patches to David for now so he can add the changes to the patch-set.
Ok. I will create another branch and will incorporate your DTS files.

> How do you want to deal with new boards ? Send the addition of the
> base board to you (and CC David as he will need them in his tree too),
> and then send a patch to add mmc to the dts to David ?
Sounds good to me...
 
> Or should I simply make it one big patch including mmc in the initial
> commit ?
I imagine that a messy approach. Especially if I'm supposed to refactor
the patchset into a new one...

cheers

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* [linux-sunxi] Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
@ 2013-12-16  9:04               ` David Lanzendörfer
  0 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-16  9:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi
> Note as said before I expect David to take things from here.
I will start working on it this evening.

> I just took what David was using. I agree picking one and staying with
> it would be better.
There is a reason why my working branch was called "plsdsif"
(short for "Please don't shout at me in Finnish")

> Yes and no. The pullups are enabled by uboot and the allwinner
> sources, most of my testing has been done without them, which
> seems to work fine. I've enabled them to be consisten with the
> allwinner sources and u-boot.
Ok

> As for drive = <3>, we need drive = <2> for normal modes,
> and drive = <3> for ddr mode. I simply picked <3> to keep
> things KISS. It should not matter much in power usage, as
> it will only make the flanks of the signal more steep. Once the
> desired output level is reached the current will drop off. It will
> use more current when changing the level, but for half the time,
> so the effective power usage (current * time) is the same.
In this case lets implement a switch which enables the pull ups for DDR
mode and lets disable it by default in turn.
This way we can make sure that we don't have doubled pull up,
since this could actually mess up some circuitry.

> > Ideally, I'd like this patch to be splitted into three:
> >    - One that adds the MMC controller nodes to the DTSI
> >    - One that adds the muxing options you need to the pinctrl node
> >    - One that enables the controller on the boards
> Sounds like a good job for David. Note I've a lot more boards for
> which I would like to add mmc support or dts files in general
> (will do so as time permits).
Ok. I will work on it this evening.

> For those boards which already have a dts I'll send mmc adding dts
> patches to David for now so he can add the changes to the patch-set.
Ok. I will create another branch and will incorporate your DTS files.

> How do you want to deal with new boards ? Send the addition of the
> base board to you (and CC David as he will need them in his tree too),
> and then send a patch to add mmc to the dts to David ?
Sounds good to me...
 
> Or should I simply make it one big patch including mmc in the initial
> commit ?
I imagine that a messy approach. Especially if I'm supposed to refactor
the patchset into a new one...

cheers
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131216/21d5a173/attachment.sig>

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

* Re: Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
  2013-12-15 14:31           ` [linux-sunxi] " Hans de Goede
@ 2013-12-16 10:02               ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-16 10:02 UTC (permalink / raw)
  To: Hans de Goede
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chris Ball,
	David Lanzendörfer, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 2857 bytes --]

Hi Hans,

Damn google-groups removed me from Cc :)

On Sun, Dec 15, 2013 at 03:31:29PM +0100, Hans de Goede wrote:
> >>@@ -376,6 +385,13 @@
> >>  				allwinner,drive = <0>;
> >>  				allwinner,pull = <0>;
> >>  			};
> >>+
> >>+			sdc0_pins_a: sdc0@0 {
> >>+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
> >>+				allwinner,function = "mmc0";
> >>+				allwinner,drive = <3>;
> >>+				allwinner,pull = <1>;
> >
> >Wow, you need both the pullups and a 40mA output?
> 
> Yes and no. The pullups are enabled by uboot and the allwinner
> sources, most of my testing has been done without them, which
> seems to work fine. I've enabled them to be consisten with the
> allwinner sources and u-boot.

Henrik was suggesting that in most boards it's not required to set up
the internal pullups. Maybe we can just disable them by default, and
we will always be able to enable them at the board level if needed.

> As for drive = <3>, we need drive = <2> for normal modes,
> and drive = <3> for ddr mode. I simply picked <3> to keep
> things KISS. It should not matter much in power usage, as
> it will only make the flanks of the signal more steep. Once the
> desired output level is reached the current will drop off. It will
> use more current when changing the level, but for half the time,
> so the effective power usage (current * time) is the same.

Ok, let's keep it to 40mA then. It will indeed be simpler :)

> >Ideally, I'd like this patch to be splitted into three:
> >   - One that adds the MMC controller nodes to the DTSI
> >   - One that adds the muxing options you need to the pinctrl node
> >   - One that enables the controller on the boards
> 
> Sounds like a good job for David. Note I've a lot more boards for
> which I would like to add mmc support or dts files in general
> (will do so as time permits).
> 
> For those boards which already have a dts I'll send mmc adding dts
> patches to David for now so he can add the changes to the patch-set.
> 
> How do you want to deal with new boards ? Send the addition of the
> base board to you (and CC David as he will need them in his tree too),
> and then send a patch to add mmc to the dts to David ?

I don't really like having a variable-sweep patch serie. Just send
your DT additions to me, saying that you depend on the MMC serie from
David.

I'm pretty happy with the DT bindings so far, so we can even merge
these DT patches before the MMC driver has been merged

> Or should I simply make it one big patch including mmc in the initial
> commit ?

I really prefer to have patches as small as possible (while being
reasonable). It's much easier to merge and allows to have a cleaner
history.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [linux-sunxi] Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
@ 2013-12-16 10:02               ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-16 10:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Hans,

Damn google-groups removed me from Cc :)

On Sun, Dec 15, 2013 at 03:31:29PM +0100, Hans de Goede wrote:
> >>@@ -376,6 +385,13 @@
> >>  				allwinner,drive = <0>;
> >>  				allwinner,pull = <0>;
> >>  			};
> >>+
> >>+			sdc0_pins_a: sdc0 at 0 {
> >>+				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
> >>+				allwinner,function = "mmc0";
> >>+				allwinner,drive = <3>;
> >>+				allwinner,pull = <1>;
> >
> >Wow, you need both the pullups and a 40mA output?
> 
> Yes and no. The pullups are enabled by uboot and the allwinner
> sources, most of my testing has been done without them, which
> seems to work fine. I've enabled them to be consisten with the
> allwinner sources and u-boot.

Henrik was suggesting that in most boards it's not required to set up
the internal pullups. Maybe we can just disable them by default, and
we will always be able to enable them at the board level if needed.

> As for drive = <3>, we need drive = <2> for normal modes,
> and drive = <3> for ddr mode. I simply picked <3> to keep
> things KISS. It should not matter much in power usage, as
> it will only make the flanks of the signal more steep. Once the
> desired output level is reached the current will drop off. It will
> use more current when changing the level, but for half the time,
> so the effective power usage (current * time) is the same.

Ok, let's keep it to 40mA then. It will indeed be simpler :)

> >Ideally, I'd like this patch to be splitted into three:
> >   - One that adds the MMC controller nodes to the DTSI
> >   - One that adds the muxing options you need to the pinctrl node
> >   - One that enables the controller on the boards
> 
> Sounds like a good job for David. Note I've a lot more boards for
> which I would like to add mmc support or dts files in general
> (will do so as time permits).
> 
> For those boards which already have a dts I'll send mmc adding dts
> patches to David for now so he can add the changes to the patch-set.
> 
> How do you want to deal with new boards ? Send the addition of the
> base board to you (and CC David as he will need them in his tree too),
> and then send a patch to add mmc to the dts to David ?

I don't really like having a variable-sweep patch serie. Just send
your DT additions to me, saying that you depend on the MMC serie from
David.

I'm pretty happy with the DT bindings so far, so we can even merge
these DT patches before the MMC driver has been merged

> Or should I simply make it one big patch including mmc in the initial
> commit ?

I really prefer to have patches as small as possible (while being
reasonable). It's much easier to merge and allows to have a cleaner
history.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131216/e1472527/attachment.sig>

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 22:01           ` [linux-sunxi] " Michal Suchanek
@ 2013-12-16 10:05               ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-16 10:05 UTC (permalink / raw)
  To: Michal Suchanek
  Cc: linux-sunxi, Hans de Goede, Chris Ball, David Lanzendörfer,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA, devicetree,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 1359 bytes --]

On Sun, Dec 15, 2013 at 11:01:17PM +0100, Michal Suchanek wrote:
> On 15 December 2013 14:44, Maxime Ripard
> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> >> --- a/drivers/mmc/host/Kconfig
> >> +++ b/drivers/mmc/host/Kconfig
> >> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
> >>       help
> >>         Say Y here to include driver code to support SD/MMC card interface
> >>         of Realtek PCI-E card reader
> >> +
> >> +config MMC_SUNXI
> >> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
> >> +     depends on ARCH_SUNXI
> >> +     default y
> >
> > I'm not that fond of these "default y" patterns. It forces the driver
> > down to every user of the multiplatform kernels. I'd suggest removing
> > the default and adding the driver to the defconfigs we have.
> 
> And why would you build support for sunxi without building support for
> sunxi mmc?

Because you can?

And where am I actually suggesting to do so?

> Like 90%+ sunxi devices actually have a SD slot or an eMMC or a SDIO
> card connected so what's the point of supporting sunxi without sunxi
> mmc?

And does your assumption still stand if you take into account all the
other ARM boards?

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-16 10:05               ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-16 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Dec 15, 2013 at 11:01:17PM +0100, Michal Suchanek wrote:
> On 15 December 2013 14:44, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> >> --- a/drivers/mmc/host/Kconfig
> >> +++ b/drivers/mmc/host/Kconfig
> >> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
> >>       help
> >>         Say Y here to include driver code to support SD/MMC card interface
> >>         of Realtek PCI-E card reader
> >> +
> >> +config MMC_SUNXI
> >> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
> >> +     depends on ARCH_SUNXI
> >> +     default y
> >
> > I'm not that fond of these "default y" patterns. It forces the driver
> > down to every user of the multiplatform kernels. I'd suggest removing
> > the default and adding the driver to the defconfigs we have.
> 
> And why would you build support for sunxi without building support for
> sunxi mmc?

Because you can?

And where am I actually suggesting to do so?

> Like 90%+ sunxi devices actually have a SD slot or an eMMC or a SDIO
> card connected so what's the point of supporting sunxi without sunxi
> mmc?

And does your assumption still stand if you take into account all the
other ARM boards?

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131216/34d20ff6/attachment.sig>

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-16 10:05               ` [linux-sunxi] " Maxime Ripard
@ 2013-12-16 11:59                 ` Michal Suchanek
  -1 siblings, 0 replies; 62+ messages in thread
From: Michal Suchanek @ 2013-12-16 11:59 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: linux-sunxi, Hans de Goede, Chris Ball, David Lanzendörfer,
	linux-mmc, devicetree,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 16 December 2013 11:05, Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> On Sun, Dec 15, 2013 at 11:01:17PM +0100, Michal Suchanek wrote:
>> On 15 December 2013 14:44, Maxime Ripard
>> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
>> >> --- a/drivers/mmc/host/Kconfig
>> >> +++ b/drivers/mmc/host/Kconfig
>> >> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
>> >>       help
>> >>         Say Y here to include driver code to support SD/MMC card interface
>> >>         of Realtek PCI-E card reader
>> >> +
>> >> +config MMC_SUNXI
>> >> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
>> >> +     depends on ARCH_SUNXI
>> >> +     default y
>> >
>> > I'm not that fond of these "default y" patterns. It forces the driver
>> > down to every user of the multiplatform kernels. I'd suggest removing
>> > the default and adding the driver to the defconfigs we have.
>>
>> And why would you build support for sunxi without building support for
>> sunxi mmc?
>
> Because you can?

But does that need to be the default? And is that sane default?

>
> And where am I actually suggesting to do so?

Just a few lines above. You suggest it should not be built by default.

>
>> Like 90%+ sunxi devices actually have a SD slot or an eMMC or a SDIO
>> card connected so what's the point of supporting sunxi without sunxi
>> mmc?
>
> And does your assumption still stand if you take into account all the
> other ARM boards?

Sure. It depends on sunxi platform so if you compile in support for
that 90%+ boards you just added have something connected to a mmc
controller so the sane thing is to also add the mmc controller.

Thanks

Michal

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-16 11:59                 ` Michal Suchanek
  0 siblings, 0 replies; 62+ messages in thread
From: Michal Suchanek @ 2013-12-16 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 16 December 2013 11:05, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Sun, Dec 15, 2013 at 11:01:17PM +0100, Michal Suchanek wrote:
>> On 15 December 2013 14:44, Maxime Ripard
>> <maxime.ripard@free-electrons.com> wrote:
>> >> --- a/drivers/mmc/host/Kconfig
>> >> +++ b/drivers/mmc/host/Kconfig
>> >> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
>> >>       help
>> >>         Say Y here to include driver code to support SD/MMC card interface
>> >>         of Realtek PCI-E card reader
>> >> +
>> >> +config MMC_SUNXI
>> >> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
>> >> +     depends on ARCH_SUNXI
>> >> +     default y
>> >
>> > I'm not that fond of these "default y" patterns. It forces the driver
>> > down to every user of the multiplatform kernels. I'd suggest removing
>> > the default and adding the driver to the defconfigs we have.
>>
>> And why would you build support for sunxi without building support for
>> sunxi mmc?
>
> Because you can?

But does that need to be the default? And is that sane default?

>
> And where am I actually suggesting to do so?

Just a few lines above. You suggest it should not be built by default.

>
>> Like 90%+ sunxi devices actually have a SD slot or an eMMC or a SDIO
>> card connected so what's the point of supporting sunxi without sunxi
>> mmc?
>
> And does your assumption still stand if you take into account all the
> other ARM boards?

Sure. It depends on sunxi platform so if you compile in support for
that 90%+ boards you just added have something connected to a mmc
controller so the sane thing is to also add the mmc controller.

Thanks

Michal

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 21:19                             ` [linux-sunxi] " David Lanzendörfer
@ 2013-12-16 12:21                                 ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-16 12:21 UTC (permalink / raw)
  To: David Lanzendörfer
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chris Ball,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

On 12/15/2013 10:19 PM, David Lanzendörfer wrote:
>>> [...]
>>> Do you have something like this in mind? ->
>>> drivers/mmc/host/dw_mmc-exynos.c
>> No, as explained in my previous mail the idmac being shared seemed to be the
>> only 2 things the dw-mmc controller and the sunxi-mmc controller have in
>> common.
> Ok.
>
>> Looking at dw_mmc-exynos.c it still pretty much is the classic dw-mmc
>> controller with some extra bits, where as the sunxi controller is
>> significantly different (which allows us to write a significant simpler
>> driver).
> Do you have an outline for such a driver as you imagine it?
> I'd be interested into some "experiments".
> Maybe you have a repository where you could push a dedicated tree
> for some colaboration on this?

I think that we're miss-communicating a bit here. What I'm trying to say
is that trying to extend the dw_mmc driver to support sunxi is a bad
idea because the sunxi hardware is quite different. And that the
sunxi hardware having autostop allows the existing sunxi-mci driver to
be much simpler then the dw-mmc driver.

IOW the much simpler driver already exists and it is the sunxi-mci
driver.

Regards,

Hans

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/groups/opt_out.

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-16 12:21                                 ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-16 12:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/15/2013 10:19 PM, David Lanzend?rfer wrote:
>>> [...]
>>> Do you have something like this in mind? ->
>>> drivers/mmc/host/dw_mmc-exynos.c
>> No, as explained in my previous mail the idmac being shared seemed to be the
>> only 2 things the dw-mmc controller and the sunxi-mmc controller have in
>> common.
> Ok.
>
>> Looking at dw_mmc-exynos.c it still pretty much is the classic dw-mmc
>> controller with some extra bits, where as the sunxi controller is
>> significantly different (which allows us to write a significant simpler
>> driver).
> Do you have an outline for such a driver as you imagine it?
> I'd be interested into some "experiments".
> Maybe you have a repository where you could push a dedicated tree
> for some colaboration on this?

I think that we're miss-communicating a bit here. What I'm trying to say
is that trying to extend the dw_mmc driver to support sunxi is a bad
idea because the sunxi hardware is quite different. And that the
sunxi hardware having autostop allows the existing sunxi-mci driver to
be much simpler then the dw-mmc driver.

IOW the much simpler driver already exists and it is the sunxi-mci
driver.

Regards,

Hans

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

* Re: Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
  2013-12-16  9:04               ` [linux-sunxi] " David Lanzendörfer
@ 2013-12-16 12:32                   ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-16 12:32 UTC (permalink / raw)
  To: David Lanzendörfer,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA, Chris Ball,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi,

On 12/16/2013 10:04 AM, David Lanzendörfer wrote:

<snip>

>> Yes and no. The pullups are enabled by uboot and the allwinner
>> sources, most of my testing has been done without them, which
>> seems to work fine. I've enabled them to be consisten with the
>> allwinner sources and u-boot.
> Ok
>
>> As for drive = <3>, we need drive = <2> for normal modes,
>> and drive = <3> for ddr mode. I simply picked <3> to keep
>> things KISS. It should not matter much in power usage, as
>> it will only make the flanks of the signal more steep. Once the
>> desired output level is reached the current will drop off. It will
>> use more current when changing the level, but for half the time,
>> so the effective power usage (current * time) is the same.
> In this case lets implement a switch which enables the pull ups for DDR
> mode and lets disable it by default in turn.

I assume you mean enable drive = <3> mode and use drive = <2> mode
by default? Changing drive level at runtime, rather the at dts configure
time seems to be non trivial.

Also see Maxime's mail further down in this thread where he says he
is fine with keeping drive level at <3> but suggest disabling
the pull-ups by default. I'm fine with disabling the pull-ups by
default, so lets disable the pull-ups and keep the drive level at 3.

> This way we can make sure that we don't have doubled pull up,
> since this could actually mess up some circuitry.
>
>>> Ideally, I'd like this patch to be splitted into three:
>>>     - One that adds the MMC controller nodes to the DTSI
>>>     - One that adds the muxing options you need to the pinctrl node
>>>     - One that enables the controller on the boards
>> Sounds like a good job for David. Note I've a lot more boards for
>> which I would like to add mmc support or dts files in general
>> (will do so as time permits).
> Ok. I will work on it this evening.
>
>> For those boards which already have a dts I'll send mmc adding dts
>> patches to David for now so he can add the changes to the patch-set.
> Ok. I will create another branch and will incorporate your DTS files.
>
>> How do you want to deal with new boards ? Send the addition of the
>> base board to you (and CC David as he will need them in his tree too),
>> and then send a patch to add mmc to the dts to David ?
> Sounds good to me...

In Maxime's reply I was talking about above he suggests to simply
send complete dts files with the new mmc node present to him, so I'll do
that instead if / when I add dts files for new boards.

Regards,

Hans

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/groups/opt_out.

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

* [linux-sunxi] Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
@ 2013-12-16 12:32                   ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-16 12:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/16/2013 10:04 AM, David Lanzend?rfer wrote:

<snip>

>> Yes and no. The pullups are enabled by uboot and the allwinner
>> sources, most of my testing has been done without them, which
>> seems to work fine. I've enabled them to be consisten with the
>> allwinner sources and u-boot.
> Ok
>
>> As for drive = <3>, we need drive = <2> for normal modes,
>> and drive = <3> for ddr mode. I simply picked <3> to keep
>> things KISS. It should not matter much in power usage, as
>> it will only make the flanks of the signal more steep. Once the
>> desired output level is reached the current will drop off. It will
>> use more current when changing the level, but for half the time,
>> so the effective power usage (current * time) is the same.
> In this case lets implement a switch which enables the pull ups for DDR
> mode and lets disable it by default in turn.

I assume you mean enable drive = <3> mode and use drive = <2> mode
by default? Changing drive level at runtime, rather the at dts configure
time seems to be non trivial.

Also see Maxime's mail further down in this thread where he says he
is fine with keeping drive level at <3> but suggest disabling
the pull-ups by default. I'm fine with disabling the pull-ups by
default, so lets disable the pull-ups and keep the drive level at 3.

> This way we can make sure that we don't have doubled pull up,
> since this could actually mess up some circuitry.
>
>>> Ideally, I'd like this patch to be splitted into three:
>>>     - One that adds the MMC controller nodes to the DTSI
>>>     - One that adds the muxing options you need to the pinctrl node
>>>     - One that enables the controller on the boards
>> Sounds like a good job for David. Note I've a lot more boards for
>> which I would like to add mmc support or dts files in general
>> (will do so as time permits).
> Ok. I will work on it this evening.
>
>> For those boards which already have a dts I'll send mmc adding dts
>> patches to David for now so he can add the changes to the patch-set.
> Ok. I will create another branch and will incorporate your DTS files.
>
>> How do you want to deal with new boards ? Send the addition of the
>> base board to you (and CC David as he will need them in his tree too),
>> and then send a patch to add mmc to the dts to David ?
> Sounds good to me...

In Maxime's reply I was talking about above he suggests to simply
send complete dts files with the new mmc node present to him, so I'll do
that instead if / when I add dts files for new boards.

Regards,

Hans

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

* Re: Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
  2013-12-16 10:02               ` [linux-sunxi] " Maxime Ripard
@ 2013-12-16 12:34                 ` Hans de Goede
  -1 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-16 12:34 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chris Ball,
	David Lanzendörfer, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

On 12/16/2013 11:02 AM, Maxime Ripard wrote:
> Hi Hans,
>
> Damn google-groups removed me from Cc :)
>
> On Sun, Dec 15, 2013 at 03:31:29PM +0100, Hans de Goede wrote:
>>>> @@ -376,6 +385,13 @@
>>>>   				allwinner,drive = <0>;
>>>>   				allwinner,pull = <0>;
>>>>   			};
>>>> +
>>>> +			sdc0_pins_a: sdc0@0 {
>>>> +				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
>>>> +				allwinner,function = "mmc0";
>>>> +				allwinner,drive = <3>;
>>>> +				allwinner,pull = <1>;
>>>
>>> Wow, you need both the pullups and a 40mA output?
>>
>> Yes and no. The pullups are enabled by uboot and the allwinner
>> sources, most of my testing has been done without them, which
>> seems to work fine. I've enabled them to be consisten with the
>> allwinner sources and u-boot.
>
> Henrik was suggesting that in most boards it's not required to set up
> the internal pullups. Maybe we can just disable them by default, and
> we will always be able to enable them at the board level if needed.

Ok, I'm fine with disabling the pull-ups by default.

>> As for drive = <3>, we need drive = <2> for normal modes,
>> and drive = <3> for ddr mode. I simply picked <3> to keep
>> things KISS. It should not matter much in power usage, as
>> it will only make the flanks of the signal more steep. Once the
>> desired output level is reached the current will drop off. It will
>> use more current when changing the level, but for half the time,
>> so the effective power usage (current * time) is the same.
>
> Ok, let's keep it to 40mA then. It will indeed be simpler :)

Ack.

>
>>> Ideally, I'd like this patch to be splitted into three:
>>>    - One that adds the MMC controller nodes to the DTSI
>>>    - One that adds the muxing options you need to the pinctrl node
>>>    - One that enables the controller on the boards
>>
>> Sounds like a good job for David. Note I've a lot more boards for
>> which I would like to add mmc support or dts files in general
>> (will do so as time permits).
>>
>> For those boards which already have a dts I'll send mmc adding dts
>> patches to David for now so he can add the changes to the patch-set.
>>
>> How do you want to deal with new boards ? Send the addition of the
>> base board to you (and CC David as he will need them in his tree too),
>> and then send a patch to add mmc to the dts to David ?
>
> I don't really like having a variable-sweep patch serie. Just send
> your DT additions to me, saying that you depend on the MMC serie from
> David.

Ok will do if / when I've dts files for new boards.

Regards,

Hans

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

* [linux-sunxi] Re: [PATCH 2/5] ARM: dts: sun4i: Add support for mmc
@ 2013-12-16 12:34                 ` Hans de Goede
  0 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2013-12-16 12:34 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/16/2013 11:02 AM, Maxime Ripard wrote:
> Hi Hans,
>
> Damn google-groups removed me from Cc :)
>
> On Sun, Dec 15, 2013 at 03:31:29PM +0100, Hans de Goede wrote:
>>>> @@ -376,6 +385,13 @@
>>>>   				allwinner,drive = <0>;
>>>>   				allwinner,pull = <0>;
>>>>   			};
>>>> +
>>>> +			sdc0_pins_a: sdc0 at 0 {
>>>> +				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
>>>> +				allwinner,function = "mmc0";
>>>> +				allwinner,drive = <3>;
>>>> +				allwinner,pull = <1>;
>>>
>>> Wow, you need both the pullups and a 40mA output?
>>
>> Yes and no. The pullups are enabled by uboot and the allwinner
>> sources, most of my testing has been done without them, which
>> seems to work fine. I've enabled them to be consisten with the
>> allwinner sources and u-boot.
>
> Henrik was suggesting that in most boards it's not required to set up
> the internal pullups. Maybe we can just disable them by default, and
> we will always be able to enable them at the board level if needed.

Ok, I'm fine with disabling the pull-ups by default.

>> As for drive = <3>, we need drive = <2> for normal modes,
>> and drive = <3> for ddr mode. I simply picked <3> to keep
>> things KISS. It should not matter much in power usage, as
>> it will only make the flanks of the signal more steep. Once the
>> desired output level is reached the current will drop off. It will
>> use more current when changing the level, but for half the time,
>> so the effective power usage (current * time) is the same.
>
> Ok, let's keep it to 40mA then. It will indeed be simpler :)

Ack.

>
>>> Ideally, I'd like this patch to be splitted into three:
>>>    - One that adds the MMC controller nodes to the DTSI
>>>    - One that adds the muxing options you need to the pinctrl node
>>>    - One that enables the controller on the boards
>>
>> Sounds like a good job for David. Note I've a lot more boards for
>> which I would like to add mmc support or dts files in general
>> (will do so as time permits).
>>
>> For those boards which already have a dts I'll send mmc adding dts
>> patches to David for now so he can add the changes to the patch-set.
>>
>> How do you want to deal with new boards ? Send the addition of the
>> base board to you (and CC David as he will need them in his tree too),
>> and then send a patch to add mmc to the dts to David ?
>
> I don't really like having a variable-sweep patch serie. Just send
> your DT additions to me, saying that you depend on the MMC serie from
> David.

Ok will do if / when I've dts files for new boards.

Regards,

Hans

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-16 11:59                 ` [linux-sunxi] " Michal Suchanek
@ 2013-12-16 12:49                     ` Ian Campbell
  -1 siblings, 0 replies; 62+ messages in thread
From: Ian Campbell @ 2013-12-16 12:49 UTC (permalink / raw)
  To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
  Cc: Maxime Ripard, Hans de Goede, Chris Ball,
	David Lanzendörfer, linux-mmc, devicetree,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Mon, 2013-12-16 at 12:59 +0100, Michal Suchanek wrote:
> On 16 December 2013 11:05, Maxime Ripard
> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> > On Sun, Dec 15, 2013 at 11:01:17PM +0100, Michal Suchanek wrote:
> >> On 15 December 2013 14:44, Maxime Ripard
> >> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> >> >> --- a/drivers/mmc/host/Kconfig
> >> >> +++ b/drivers/mmc/host/Kconfig
> >> >> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
> >> >>       help
> >> >>         Say Y here to include driver code to support SD/MMC card interface
> >> >>         of Realtek PCI-E card reader
> >> >> +
> >> >> +config MMC_SUNXI
> >> >> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
> >> >> +     depends on ARCH_SUNXI
> >> >> +     default y
> >> >
> >> > I'm not that fond of these "default y" patterns. It forces the driver
> >> > down to every user of the multiplatform kernels. I'd suggest removing
> >> > the default and adding the driver to the defconfigs we have.
> >>
> >> And why would you build support for sunxi without building support for
> >> sunxi mmc?
> >
> > Because you can?
> 
> But does that need to be the default? And is that sane default?
> 
> >
> > And where am I actually suggesting to do so?
> 
> Just a few lines above. You suggest it should not be built by default.

I'm pretty sure this isn't specific to sunxi, in the past Linus has
complained about the inappropriate use of "default y". Apparently it
should only be used rarely.

Note that default in the Kconfig is different to the defconfig file.

Ian.

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-16 12:49                     ` Ian Campbell
  0 siblings, 0 replies; 62+ messages in thread
From: Ian Campbell @ 2013-12-16 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 2013-12-16 at 12:59 +0100, Michal Suchanek wrote:
> On 16 December 2013 11:05, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Sun, Dec 15, 2013 at 11:01:17PM +0100, Michal Suchanek wrote:
> >> On 15 December 2013 14:44, Maxime Ripard
> >> <maxime.ripard@free-electrons.com> wrote:
> >> >> --- a/drivers/mmc/host/Kconfig
> >> >> +++ b/drivers/mmc/host/Kconfig
> >> >> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
> >> >>       help
> >> >>         Say Y here to include driver code to support SD/MMC card interface
> >> >>         of Realtek PCI-E card reader
> >> >> +
> >> >> +config MMC_SUNXI
> >> >> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
> >> >> +     depends on ARCH_SUNXI
> >> >> +     default y
> >> >
> >> > I'm not that fond of these "default y" patterns. It forces the driver
> >> > down to every user of the multiplatform kernels. I'd suggest removing
> >> > the default and adding the driver to the defconfigs we have.
> >>
> >> And why would you build support for sunxi without building support for
> >> sunxi mmc?
> >
> > Because you can?
> 
> But does that need to be the default? And is that sane default?
> 
> >
> > And where am I actually suggesting to do so?
> 
> Just a few lines above. You suggest it should not be built by default.

I'm pretty sure this isn't specific to sunxi, in the past Linus has
complained about the inappropriate use of "default y". Apparently it
should only be used rarely.

Note that default in the Kconfig is different to the defconfig file.

Ian.

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-16 11:59                 ` [linux-sunxi] " Michal Suchanek
@ 2013-12-16 12:53                     ` Maxime Ripard
  -1 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-16 12:53 UTC (permalink / raw)
  To: Michal Suchanek
  Cc: linux-sunxi, Hans de Goede, Chris Ball, David Lanzendörfer,
	linux-mmc, devicetree,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 1658 bytes --]

On Mon, Dec 16, 2013 at 12:59:31PM +0100, Michal Suchanek wrote:
> On 16 December 2013 11:05, Maxime Ripard
> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> > On Sun, Dec 15, 2013 at 11:01:17PM +0100, Michal Suchanek wrote:
> >> On 15 December 2013 14:44, Maxime Ripard
> >> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> >> >> --- a/drivers/mmc/host/Kconfig
> >> >> +++ b/drivers/mmc/host/Kconfig
> >> >> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
> >> >>       help
> >> >>         Say Y here to include driver code to support SD/MMC card interface
> >> >>         of Realtek PCI-E card reader
> >> >> +
> >> >> +config MMC_SUNXI
> >> >> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
> >> >> +     depends on ARCH_SUNXI
> >> >> +     default y
> >> >
> >> > I'm not that fond of these "default y" patterns. It forces the driver
> >> > down to every user of the multiplatform kernels. I'd suggest removing
> >> > the default and adding the driver to the defconfigs we have.
> >>
> >> And why would you build support for sunxi without building support for
> >> sunxi mmc?
> >
> > Because you can?
> 
> But does that need to be the default? And is that sane default?
> 
> >
> > And where am I actually suggesting to do so?
> 
> Just a few lines above. You suggest it should not be built by default.

No, this is not what I'm saying. I'm saying that this default should
be enforced at the defconfig level, and not at the Kconfig level.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-16 12:53                     ` Maxime Ripard
  0 siblings, 0 replies; 62+ messages in thread
From: Maxime Ripard @ 2013-12-16 12:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 16, 2013 at 12:59:31PM +0100, Michal Suchanek wrote:
> On 16 December 2013 11:05, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Sun, Dec 15, 2013 at 11:01:17PM +0100, Michal Suchanek wrote:
> >> On 15 December 2013 14:44, Maxime Ripard
> >> <maxime.ripard@free-electrons.com> wrote:
> >> >> --- a/drivers/mmc/host/Kconfig
> >> >> +++ b/drivers/mmc/host/Kconfig
> >> >> @@ -665,3 +665,11 @@ config MMC_REALTEK_PCI
> >> >>       help
> >> >>         Say Y here to include driver code to support SD/MMC card interface
> >> >>         of Realtek PCI-E card reader
> >> >> +
> >> >> +config MMC_SUNXI
> >> >> +     tristate "Allwinner sunxi SD/MMC Host Controller support"
> >> >> +     depends on ARCH_SUNXI
> >> >> +     default y
> >> >
> >> > I'm not that fond of these "default y" patterns. It forces the driver
> >> > down to every user of the multiplatform kernels. I'd suggest removing
> >> > the default and adding the driver to the defconfigs we have.
> >>
> >> And why would you build support for sunxi without building support for
> >> sunxi mmc?
> >
> > Because you can?
> 
> But does that need to be the default? And is that sane default?
> 
> >
> > And where am I actually suggesting to do so?
> 
> Just a few lines above. You suggest it should not be built by default.

No, this is not what I'm saying. I'm saying that this default should
be enforced at the defconfig level, and not at the Kconfig level.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131216/bb3f54ed/attachment.sig>

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

* Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-14 21:58     ` Hans de Goede
@ 2013-12-17 13:43       ` Mark Brown
  -1 siblings, 0 replies; 62+ messages in thread
From: Mark Brown @ 2013-12-17 13:43 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Chris Ball, Maxime Ripard, devicetree, linux-mmc, linux-sunxi,
	David Lanzendörfer, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 397 bytes --]

On Sat, Dec 14, 2013 at 10:58:11PM +0100, Hans de Goede wrote:

> +config MMC_SUNXI
> +	tristate "Allwinner sunxi SD/MMC Host Controller support"
> +	depends on ARCH_SUNXI

This should be ARCH_SUNXI || COMPILE_TEST to increase build coverage
especially for people doing subsystem or kernel global work.

> +	default y

As others pointed out this shouldn't be here, consider multiplatform
kernels.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-17 13:43       ` Mark Brown
  0 siblings, 0 replies; 62+ messages in thread
From: Mark Brown @ 2013-12-17 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Dec 14, 2013 at 10:58:11PM +0100, Hans de Goede wrote:

> +config MMC_SUNXI
> +	tristate "Allwinner sunxi SD/MMC Host Controller support"
> +	depends on ARCH_SUNXI

This should be ARCH_SUNXI || COMPILE_TEST to increase build coverage
especially for people doing subsystem or kernel global work.

> +	default y

As others pointed out this shouldn't be here, consider multiplatform
kernels.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131217/5b223810/attachment.sig>

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

* Re: Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-16 12:21                                 ` [linux-sunxi] " Hans de Goede
@ 2013-12-23 10:36                                     ` David Lanzendörfer
  -1 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-23 10:36 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Hans de Goede, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chris Ball,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 862 bytes --]

> I think that we're miss-communicating a bit here. What I'm trying to say
> is that trying to extend the dw_mmc driver to support sunxi is a bad
> idea because the sunxi hardware is quite different. And that the
> sunxi hardware having autostop allows the existing sunxi-mci driver to
> be much simpler then the dw-mmc driver.

> IOW the much simpler driver already exists and it is the sunxi-mci
> driver.
Ah! Ok. Now I get it.
Well then. I'll try to incorporate all the changes within this endless thread 
until I can get together a patchset v2 I can hand in.
Now that the lectures have ended for this semester I won't be too tired for 
straight thinking on daily basis and will be able to create such a patchset.
And please excuse my contentless answers onto the last few questions
but I really wasn't myself - so to say -  at this time (half asleep)

-david

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* [linux-sunxi] Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2013-12-23 10:36                                     ` David Lanzendörfer
  0 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2013-12-23 10:36 UTC (permalink / raw)
  To: linux-arm-kernel

> I think that we're miss-communicating a bit here. What I'm trying to say
> is that trying to extend the dw_mmc driver to support sunxi is a bad
> idea because the sunxi hardware is quite different. And that the
> sunxi hardware having autostop allows the existing sunxi-mci driver to
> be much simpler then the dw-mmc driver.

> IOW the much simpler driver already exists and it is the sunxi-mci
> driver.
Ah! Ok. Now I get it.
Well then. I'll try to incorporate all the changes within this endless thread 
until I can get together a patchset v2 I can hand in.
Now that the lectures have ended for this semester I won't be too tired for 
straight thinking on daily basis and will be able to create such a patchset.
And please excuse my contentless answers onto the last few questions
but I really wasn't myself - so to say -  at this time (half asleep)

-david
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131223/f5d4c97a/attachment-0001.sig>

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

* Re: [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  2013-12-15 13:44         ` Maxime Ripard
@ 2014-02-05 13:33           ` David Lanzendörfer
  -1 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2014-02-05 13:33 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Maxime Ripard, Hans de Goede, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chris Ball

[-- Attachment #1: Type: text/plain, Size: 858 bytes --]

Hi
> I'm not that fond of these "default y" patterns. It forces the driver
> down to every user of the multiplatform kernels. I'd suggest removing
> the default and adding the driver to the defconfigs we have.
Ok. Removed it.

> > +static void sunxi_mmc_init_host(struct mmc_host *mmc)
> > +{
> > [...]
> > +	mci_writel(smc_host, REG_FUNS, 0xceaa0000);
> > +	mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);
> I suppose we have no idea what these magics are all about ? :(
That's the parameters I could extract from the Chinese code.
Without proper documentation it will always stay magic what exactly these
values are meaning.

> > +#define mci_readl(host, reg) \
> > +	__raw_readl((host)->reg_base + SDXC_##reg)
> > +#define mci_writel(host, reg, value) \
> > +	__raw_writel((value), (host)->reg_base + SDXC_##reg)
> No barriers ? :(
Fixed that...

cheers

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
@ 2014-02-05 13:33           ` David Lanzendörfer
  0 siblings, 0 replies; 62+ messages in thread
From: David Lanzendörfer @ 2014-02-05 13:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi
> I'm not that fond of these "default y" patterns. It forces the driver
> down to every user of the multiplatform kernels. I'd suggest removing
> the default and adding the driver to the defconfigs we have.
Ok. Removed it.

> > +static void sunxi_mmc_init_host(struct mmc_host *mmc)
> > +{
> > [...]
> > +	mci_writel(smc_host, REG_FUNS, 0xceaa0000);
> > +	mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);
> I suppose we have no idea what these magics are all about ? :(
That's the parameters I could extract from the Chinese code.
Without proper documentation it will always stay magic what exactly these
values are meaning.

> > +#define mci_readl(host, reg) \
> > +	__raw_readl((host)->reg_base + SDXC_##reg)
> > +#define mci_writel(host, reg, value) \
> > +	__raw_writel((value), (host)->reg_base + SDXC_##reg)
> No barriers ? :(
Fixed that...

cheers
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140205/13e73392/attachment-0001.sig>

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

end of thread, other threads:[~2014-02-05 13:33 UTC | newest]

Thread overview: 62+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-14 21:58 [PATCH 0/5] ARM: sunxi: Add driver for SD/MMC hosts found on allwinner sunxi SOCs Hans de Goede
2013-12-14 21:58 ` Hans de Goede
     [not found] ` <1387058295-20641-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-14 21:58   ` [PATCH 1/5] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs Hans de Goede
2013-12-14 21:58     ` Hans de Goede
     [not found]     ` <1387058295-20641-2-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-15 13:44       ` Maxime Ripard
2013-12-15 13:44         ` Maxime Ripard
2013-12-15 14:20         ` Hans de Goede
2013-12-15 14:20           ` Hans de Goede
     [not found]           ` <52ADBAA3.7060507-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-15 16:21             ` Maxime Ripard
2013-12-15 16:21               ` Maxime Ripard
2013-12-15 18:41               ` Hans de Goede
2013-12-15 18:41                 ` [linux-sunxi] " Hans de Goede
     [not found]                 ` <52ADF7D8.2010900-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-15 19:35                   ` David Lanzendörfer
2013-12-15 19:35                     ` [linux-sunxi] " David Lanzendörfer
     [not found]                     ` <2378731.6b9MyH8v8A-GPtPHOohwlnjSbz6xCtQhw@public.gmane.org>
2013-12-15 20:18                       ` Hans de Goede
2013-12-15 20:18                         ` [linux-sunxi] " Hans de Goede
     [not found]                         ` <52AE0E87.2040304-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-15 21:19                           ` David Lanzendörfer
2013-12-15 21:19                             ` [linux-sunxi] " David Lanzendörfer
     [not found]                             ` <1743952.noztKtcF2Y-GPtPHOohwlnjSbz6xCtQhw@public.gmane.org>
2013-12-16 12:21                               ` Hans de Goede
2013-12-16 12:21                                 ` [linux-sunxi] " Hans de Goede
     [not found]                                 ` <52AEF060.6000405-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-23 10:36                                   ` David Lanzendörfer
2013-12-23 10:36                                     ` [linux-sunxi] " David Lanzendörfer
2013-12-15 16:33             ` David Lanzendörfer
2013-12-15 16:33               ` David Lanzendörfer
2013-12-15 22:01         ` Michal Suchanek
2013-12-15 22:01           ` [linux-sunxi] " Michal Suchanek
     [not found]           ` <CAOMqctRspBPmNsyXye_gpfwGoZ=gMcCzEjM+hD3g+ZfQix7G6Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-12-16 10:05             ` Maxime Ripard
2013-12-16 10:05               ` [linux-sunxi] " Maxime Ripard
2013-12-16 11:59               ` Michal Suchanek
2013-12-16 11:59                 ` [linux-sunxi] " Michal Suchanek
     [not found]                 ` <CAOMqctTdasLxJki0xu4aq_sEgujDt3Jdu=BXy9WvQeji282_Rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-12-16 12:49                   ` Ian Campbell
2013-12-16 12:49                     ` [linux-sunxi] " Ian Campbell
2013-12-16 12:53                   ` Maxime Ripard
2013-12-16 12:53                     ` [linux-sunxi] " Maxime Ripard
2014-02-05 13:33         ` David Lanzendörfer
2014-02-05 13:33           ` David Lanzendörfer
2013-12-17 13:43     ` Mark Brown
2013-12-17 13:43       ` Mark Brown
2013-12-14 21:58   ` [PATCH 2/5] ARM: dts: sun4i: Add support for mmc Hans de Goede
2013-12-14 21:58     ` Hans de Goede
     [not found]     ` <1387058295-20641-3-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-15 13:58       ` Maxime Ripard
2013-12-15 13:58         ` Maxime Ripard
2013-12-15 14:31         ` Hans de Goede
2013-12-15 14:31           ` [linux-sunxi] " Hans de Goede
2013-12-15 21:44           ` Henrik Nordström
2013-12-15 21:44             ` Henrik Nordström
     [not found]           ` <52ADBD41.4050104-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-16  9:04             ` David Lanzendörfer
2013-12-16  9:04               ` [linux-sunxi] " David Lanzendörfer
     [not found]               ` <11015171.YHkHMOrD9M-pgFh0Jf6HD9Xzn/AsuzBOg@public.gmane.org>
2013-12-16 12:32                 ` Hans de Goede
2013-12-16 12:32                   ` [linux-sunxi] " Hans de Goede
2013-12-16 10:02             ` Maxime Ripard
2013-12-16 10:02               ` [linux-sunxi] " Maxime Ripard
2013-12-16 12:34               ` Hans de Goede
2013-12-16 12:34                 ` [linux-sunxi] " Hans de Goede
2013-12-14 21:58   ` [PATCH 3/5] ARM: dts: sun5i: Add new sun5i-a13-olinuxino-micro board Hans de Goede
2013-12-14 21:58     ` Hans de Goede
     [not found]     ` <1387058295-20641-4-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-12-15 14:04       ` Maxime Ripard
2013-12-15 14:04         ` Maxime Ripard
2013-12-14 21:58   ` [PATCH 4/5] ARM: dts: sun5i: add mmc support Hans de Goede
2013-12-14 21:58     ` Hans de Goede
2013-12-14 21:58   ` [PATCH 5/5] ARM: dts: sun7i: Add support for mmc Hans de Goede
2013-12-14 21:58     ` Hans de Goede

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.