mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [RFC 0/2] mci: Dove SDHCI driver
@ 2013-07-05 21:22 Sebastian Hesselbarth
  2013-07-05 21:22 ` [RFC 1/2] mci: add more defines to sdhci include Sebastian Hesselbarth
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Sebastian Hesselbarth @ 2013-07-05 21:22 UTC (permalink / raw)
  To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox

This RFC presents a working SDHCI driver for the IP found on Marvell
Dove SoCs.

@Sascha: We talked about refactoring common SDHCI code and I just want
to show what I came up with for Dove. After thinking about existing barebox
SDHCI, I had the impression that I should reimplement Dove SDHCI with writel
as it is already made in other SDHCI drivers.

I will be not checking mails regularily nor working on Barebox for the next
two weeks, so feel free to simply ignore the RFC. But I thought it will be
a good way to discuss your plans for common SDHCI code.

Sebastian Hesselbarth (2):
  mci: add more defines to sdhci include
  mci: add Marvell Dove SDHCI driver

 drivers/mci/Kconfig      |    7 +
 drivers/mci/Makefile     |    1 +
 drivers/mci/dove-sdhci.c |  365 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mci/sdhci.h      |   86 +++++++++++
 4 files changed, 459 insertions(+)
 create mode 100644 drivers/mci/dove-sdhci.c

---
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: barebox@lists.infradead.org
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [RFC 1/2] mci: add more defines to sdhci include
  2013-07-05 21:22 [RFC 0/2] mci: Dove SDHCI driver Sebastian Hesselbarth
@ 2013-07-05 21:22 ` Sebastian Hesselbarth
  2013-07-05 21:22 ` [RFC 2/2] mci: add Marvell Dove SDHCI driver Sebastian Hesselbarth
  2013-07-09 17:38 ` [RFC 0/2] mci: " Sascha Hauer
  2 siblings, 0 replies; 8+ messages in thread
From: Sebastian Hesselbarth @ 2013-07-05 21:22 UTC (permalink / raw)
  To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox

This adds more byte/word aligned defines to sdhci.h for controllers
supporting byte/word reads.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/mci/sdhci.h |   86 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index b2d6779..267cb17 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -3,21 +3,107 @@
 
 #define SDHCI_DMA_ADDRESS					0x00
 #define SDHCI_BLOCK_SIZE__BLOCK_COUNT				0x04
+#define SDHCI_BLOCK_SIZE					0x04
+#define  SDHCI_DMA_BOUNDARY_512K		SDHCI_DMA_BOUNDARY(7)
+#define  SDHCI_DMA_BOUNDARY_256K		SDHCI_DMA_BOUNDARY(6)
+#define  SDHCI_DMA_BOUNDARY_128K		SDHCI_DMA_BOUNDARY(5)
+#define  SDHCI_DMA_BOUNDARY_64K			SDHCI_DMA_BOUNDARY(4)
+#define  SDHCI_DMA_BOUNDARY_32K			SDHCI_DMA_BOUNDARY(3)
+#define  SDHCI_DMA_BOUNDARY_16K			SDHCI_DMA_BOUNDARY(2)
+#define  SDHCI_DMA_BOUNDARY_8K			SDHCI_DMA_BOUNDARY(1)
+#define  SDHCI_DMA_BOUNDARY_4K			SDHCI_DMA_BOUNDARY(0)
+#define  SDHCI_DMA_BOUNDARY(x)			(((x) & 0x7) << 12)
+#define  SDHCI_TRANSFER_BLOCK_SIZE(x)		((x) & 0xfff)
+#define SDHCI_BLOCK_COUNT					0x06
 #define SDHCI_ARGUMENT						0x08
 #define SDHCI_TRANSFER_MODE__COMMAND				0x0c
+#define SDHCI_TRANSFER_MODE					0x0c
+#define  SDHCI_MULTIPLE_BLOCKS			BIT(5)
+#define  SDHCI_DATA_TO_HOST			BIT(4)
+#define  SDHCI_AUTO_CMD23_EN			SDHCI_AUTO_CMD(2)
+#define  SDHCI_AUTO_CMD12_EN			SDHCI_AUTO_CMD(1)
+#define  SDHCI_AUTO_CMD(x)			(((x) & 0x3) << 2)
+#define  SDHCI_BLOCK_COUNT_EN			BIT(1)
+#define  SDHCI_DMA_EN				BIT(0)
+#define SDHCI_COMMAND						0x0e
+#define  SDHCI_CMD_INDEX(c)			(((c) & 0x3f) << 8)
+#define  SDHCI_CMD_TYPE_ABORT			SDHCI_CMD_TYPE(3)
+#define  SDHCI_CMD_TYPE_RESUME			SDHCI_CMD_TYPE(2)
+#define  SDHCI_CMD_TYPE_SUSPEND			SDHCI_CMD_TYPE(1)
+#define  SDHCI_CMD_TYPE_NORMAL			SDHCI_CMD_TYPE(0)
+#define  SDHCI_CMD_TYPE(x)			(((x) & 0x3) << 6)
+#define  SDHCI_DATA_PRESENT			BIT(5)
+#define  SDHCI_CMD_INDEX_CHECK_EN		BIT(4)
+#define  SDHCI_CMD_CRC_CHECK_EN			BIT(3)
+#define  SDHCI_RESP_TYPE_48_BUSY		3
+#define  SDHCI_RESP_TYPE_48			2
+#define  SDHCI_RESP_TYPE_136			1
+#define  SDHCI_RESP_NONE			0
+#define SDHCI_RESPONSE						0x10
 #define SDHCI_RESPONSE_0					0x10
 #define SDHCI_RESPONSE_1					0x14
 #define SDHCI_RESPONSE_2					0x18
 #define SDHCI_RESPONSE_3					0x1c
 #define SDHCI_BUFFER						0x20
 #define SDHCI_PRESENT_STATE					0x24
+#define SDHCI_PRESENT_STATE0					0x24
+#define  SDHCI_CMD_INHIBIT_DATA			BIT(1)
+#define  SDHCI_CMD_INHIBIT_CMD			BIT(0)
+#define SDHCI_PRESENT_STATE1					0x26
 #define SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL	0x28
+#define SDHCI_HOST_CONTROL					0x28
+#define  SDHCI_DATA_WIDTH_8BIT			BIT(5)
+#define  SDHCI_DMA_ADMA64			SDHCI_DMA(3)
+#define  SDHCI_DMA_ADMA32			SDHCI_DMA(2)
+#define  SDHCI_DMA_ADMA1			SDHCI_DMA(1)
+#define  SDHCI_DMA_SDMA				SDHCI_DMA(0)
+#define  SDHCI_DMA(x)				(((x) & 0x3) << 3)
+#define  SDHCI_HIGHSPEED_EN			BIT(2)
+#define  SDHCI_DATA_WIDTH_4BIT			BIT(1)
+#define  SDHCI_LED_EN				BIT(0)
+#define SDHCI_POWER_CONTROL					0x29
+#define  SDHCI_BUS_VOLTAGE_330			SDHCI_BUS_VOLTAGE(7)
+#define  SDHCI_BUS_VOLTAGE_300			SDHCI_BUS_VOLTAGE(6)
+#define  SDHCI_BUS_VOLTAGE_180			SDHCI_BUS_VOLTAGE(5)
+#define  SDHCI_BUS_VOLTAGE(v)			((v) << 1)
+#define  SDHCI_BUS_POWER_EN			BIT(0)
+#define SDHCI_BLOCK_GAP_CONTROL					0x2a
 #define SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET	0x2c
+#define SDHCI_CLOCK_CONTROL					0x2c
+#define  SDHCI_FREQ_SEL(x)			(((x) & 0xff) << 8)
+#define  SDHCI_SDCLOCK_EN			BIT(2)
+#define  SDHCI_INTCLOCK_STABLE			BIT(1)
+#define  SDHCI_INTCLOCK_EN			BIT(0)
+#define SDHCI_TIMEOUT_CONTROL					0x2e
+#define SDHCI_SOFTWARE_RESET					0x2f
+#define  SDHCI_RESET_DATA			BIT(2)
+#define  SDHCI_RESET_CMD			BIT(1)
+#define  SDHCI_RESET_ALL			BIT(0)
 #define SDHCI_INT_STATUS					0x30
+#define SDHCI_INT_NORMAL_STATUS					0x30
+#define  SDHCI_INT_ERROR			BIT(15)
+#define  SDHCI_INT_XFER_COMPLETE		BIT(1)
+#define  SDHCI_INT_CMD_COMPLETE			BIT(0)
+#define SDHCI_INT_ERROR_STATUS					0x32
 #define SDHCI_INT_ENABLE					0x34
 #define SDHCI_SIGNAL_ENABLE					0x38
 #define SDHCI_ACMD12_ERR__HOST_CONTROL2				0x3C
 #define SDHCI_CAPABILITIES					0x40
+#define SDHCI_CAPABILITIES_1					0x42
+#define  SDHCI_HOSTCAP_VOLTAGE_180		BIT(10)
+#define  SDHCI_HOSTCAP_VOLTAGE_300		BIT(9)
+#define  SDHCI_HOSTCAP_VOLTAGE_330		BIT(8)
+#define  SDHCI_HOSTCAP_SUSPEND_RESUME		BIT(7)
+#define  SDHCI_HOSTCAP_DMA			BIT(6)
+#define  SDHCI_HOSTCAP_HIGHSPEED		BIT(5)
+#define  SDHCI_HOSTCAP_8BIT			BIT(2)
+#define  SDHCI_HOSTCAP_MAXBLOCKLEN_512B		0x0
+#define  SDHCI_HOSTCAP_MAXBLOCKLEN_1024B	0x1
+#define  SDHCI_HOSTCAP_MAXBLOCKLEN_2048B	0x2
+#define  SDHCI_HOSTCAP_MAXBLOCKLEN(r)		(512 * (1 << ((r) & 0xf)))
+
+#define SDHCI_SPEC_300_MAX_CLK_DIVIDER	2046
+#define SDHCI_SPEC_200_MAX_CLK_DIVIDER	256
 
 #define COMMAND_CMD(x)		((x & 0x3f) << 24)
 #define COMMAND_CMDTYP_NORMAL	0x0
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [RFC 2/2] mci: add Marvell Dove SDHCI driver
  2013-07-05 21:22 [RFC 0/2] mci: Dove SDHCI driver Sebastian Hesselbarth
  2013-07-05 21:22 ` [RFC 1/2] mci: add more defines to sdhci include Sebastian Hesselbarth
@ 2013-07-05 21:22 ` Sebastian Hesselbarth
  2015-02-17 23:43   ` Michael Grzeschik
  2013-07-09 17:38 ` [RFC 0/2] mci: " Sascha Hauer
  2 siblings, 1 reply; 8+ messages in thread
From: Sebastian Hesselbarth @ 2013-07-05 21:22 UTC (permalink / raw)
  To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox

This adds a driver for the SDHCI controller found on Marvell Dove SoCs.
Despite a missing pinctrl driver, corresponding MPP config has to be
set on a per board basis.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/mci/Kconfig      |    7 +
 drivers/mci/Makefile     |    1 +
 drivers/mci/dove-sdhci.c |  365 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 373 insertions(+)
 create mode 100644 drivers/mci/dove-sdhci.c

diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 7aff7df..554ce9e 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -52,6 +52,13 @@ config MCI_BCM2835
 	bool "MCI support for BCM2835"
 	depends on ARCH_BCM2835
 
+config MCI_DOVE
+	bool "Marvell Dove SDHCI"
+	depends on ARCH_DOVE
+	help
+	  Enable this entry to add support to read and write SD cards on a
+	  Marvell Dove SoC based system.
+
 config MCI_IMX
 	bool "i.MX"
 	depends on ARCH_IMX27 || ARCH_IMX31
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index df06a08..59e39cc 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -1,6 +1,7 @@
 obj-$(CONFIG_MCI)		+= mci-core.o
 obj-$(CONFIG_MCI_ATMEL)		+= atmel_mci.o
 obj-$(CONFIG_MCI_BCM2835)	+= mci-bcm2835.o
+obj-$(CONFIG_MCI_DOVE)		+= dove-sdhci.o
 obj-$(CONFIG_MCI_IMX)		+= imx.o
 obj-$(CONFIG_MCI_IMX_ESDHC)	+= imx-esdhc.o
 obj-$(CONFIG_MCI_MXS)		+= mxs.o
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
new file mode 100644
index 0000000..91ef8b0
--- /dev/null
+++ b/drivers/mci/dove-sdhci.c
@@ -0,0 +1,365 @@
+/*
+ * Marvell Dove SDHCI MCI driver
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ */
+
+#include <clock.h>
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <malloc.h>
+#include <mci.h>
+#include <linux/err.h>
+
+#include "sdhci.h"
+
+struct dove_sdhci {
+	struct mci_host mci;
+	void __iomem *base;
+};
+
+#define priv_from_mci_host(h)	\
+	container_of(h, struct dove_sdhci, mci);
+
+static inline void dove_sdhci_writel(struct dove_sdhci *p, int reg, u32 val)
+{
+	writel(val, p->base + reg);
+}
+
+static inline void dove_sdhci_writew(struct dove_sdhci *p, int reg, u16 val)
+{
+	writew(val, p->base + reg);
+}
+
+static inline void dove_sdhci_writeb(struct dove_sdhci *p, int reg, u8 val)
+{
+	writeb(val, p->base + reg);
+}
+
+static inline u32 dove_sdhci_readl(struct dove_sdhci *p, int reg)
+{
+	return readl(p->base + reg);
+}
+
+static inline u16 dove_sdhci_readw(struct dove_sdhci *p, int reg)
+{
+	return readw(p->base + reg);
+}
+
+static inline u8 dove_sdhci_readb(struct dove_sdhci *p, int reg)
+{
+	return readb(p->base + reg);
+}
+
+static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask)
+{
+	u16 status;
+	u64 start;
+
+	start = get_time_ns();
+	while (1) {
+		status = dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS);
+		if (status & SDHCI_INT_ERROR)
+			return -EPERM;
+		if (status & mask)
+			break;
+		if (is_timeout(start, 100 * MSECOND)) {
+			dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for done\n");
+			return -ETIMEDOUT;
+		}
+	}
+	return 0;
+}
+
+static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
+				struct mci_data *data)
+{
+	u16 val;
+	u64 start;
+	int ret;
+	struct dove_sdhci *host = priv_from_mci_host(mci);
+
+	dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
+
+	/* Do not wait for CMD_INHIBIT_DAT on stop commands */
+	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+		val = SDHCI_CMD_INHIBIT_CMD;
+	else
+		val = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
+
+	/* Wait for bus idle */
+	start = get_time_ns();
+	while (1) {
+		if (!(dove_sdhci_readw(host, SDHCI_PRESENT_STATE0) & val))
+			break;
+		if (is_timeout(start, 10 * MSECOND)) {
+			dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for idle\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	/* setup transfer data */
+	if (data) {
+		if (data->flags & MMC_DATA_READ)
+			dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, (u32)data->dest);
+		else
+			dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, (u32)data->src);
+		dove_sdhci_writew(host, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K |
+				SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
+		dove_sdhci_writew(host, SDHCI_BLOCK_COUNT, data->blocks);
+		dove_sdhci_writeb(host, SDHCI_TIMEOUT_CONTROL, 0xe);
+	}
+
+	/* setup transfer mode */
+	val = 0;
+	if (data) {
+		val |= SDHCI_DMA_EN | SDHCI_BLOCK_COUNT_EN;
+		if (data->blocks > 1)
+			val |= SDHCI_MULTIPLE_BLOCKS;
+		if (data->flags & MMC_DATA_READ)
+			val |= SDHCI_DATA_TO_HOST;
+	}
+	dove_sdhci_writew(host, SDHCI_TRANSFER_MODE, val);
+
+	dove_sdhci_writel(host, SDHCI_ARGUMENT, cmd->cmdarg);
+
+	if (!(cmd->resp_type & MMC_RSP_PRESENT))
+		val = SDHCI_RESP_NONE;
+	else if (cmd->resp_type & MMC_RSP_136)
+		val = SDHCI_RESP_TYPE_136;
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		val = SDHCI_RESP_TYPE_48_BUSY;
+	else
+		val = SDHCI_RESP_TYPE_48;
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		val |= SDHCI_CMD_CRC_CHECK_EN;
+	if (cmd->resp_type & MMC_RSP_OPCODE)
+		val |= SDHCI_CMD_INDEX_CHECK_EN;
+	if (data)
+		val |= SDHCI_DATA_PRESENT;
+	val |= SDHCI_CMD_INDEX(cmd->cmdidx);
+
+	dove_sdhci_writew(host, SDHCI_COMMAND, val);
+
+	ret = dove_sdhci_wait_for_done(host, SDHCI_INT_CMD_COMPLETE);
+	if (ret) {
+		dev_err(host->mci.hw_dev, "error on command %d\n", cmd->cmdidx);
+		dev_err(host->mci.hw_dev, "state = %04x %04x, interrupt = %04x %04x\n",
+			dove_sdhci_readw(host, SDHCI_PRESENT_STATE0),
+			dove_sdhci_readw(host, SDHCI_PRESENT_STATE1),
+			dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS),
+			dove_sdhci_readw(host, SDHCI_INT_ERROR_STATUS));
+		goto cmd_error;
+	}
+
+	/* CRC is stripped so we need to do some shifting. */
+	if (cmd->resp_type & MMC_RSP_136) {
+		int i;
+		for (i = 0; i < 4; i++) {
+			cmd->response[i] = dove_sdhci_readl(host,
+					SDHCI_RESPONSE_0 + 4*(3-i)) << 8;
+			if (i != 3)
+				cmd->response[i] |= dove_sdhci_readb(host,
+					SDHCI_RESPONSE_0 + 4*(3-i) - 1);
+		}
+	} else
+		cmd->response[0] = dove_sdhci_readl(host, SDHCI_RESPONSE_0);
+
+	if (data) {
+		ret = dove_sdhci_wait_for_done(host, SDHCI_INT_XFER_COMPLETE);
+		if (ret) {
+			dev_err(host->mci.hw_dev, "error while transfering data for command %d\n",
+				cmd->cmdidx);
+			dev_err(host->mci.hw_dev, "state = %04x %04x, interrupt = %04x %04x\n",
+				dove_sdhci_readw(host, SDHCI_PRESENT_STATE0),
+				dove_sdhci_readw(host, SDHCI_PRESENT_STATE1),
+				dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS),
+				dove_sdhci_readw(host, SDHCI_INT_ERROR_STATUS));
+			goto cmd_error;
+		}
+	}
+
+cmd_error:
+	dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
+	return ret;
+}
+
+static u16 dove_sdhci_get_clock_divider(struct dove_sdhci *host, u32 reqclk)
+{
+	u16 div;
+
+	for (div = 1; div < SDHCI_SPEC_200_MAX_CLK_DIVIDER; div *= 2)
+		if ((host->mci.f_max / div) <= reqclk)
+			break;
+	div /= 2;
+
+	return div;
+}
+
+static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
+{
+	u16 val;
+	u64 start;
+	struct dove_sdhci *host = priv_from_mci_host(mci);
+
+	debug("%s: clock = %u, bus-width = %d, timing = %02x\n", __func__, ios->clock, ios->bus_width, ios->timing);
+
+	/* disable on zero clock */
+	if (!ios->clock)
+		return;
+
+	/* enable bus power */
+	val = SDHCI_BUS_VOLTAGE_330;
+	dove_sdhci_writeb(host, SDHCI_POWER_CONTROL, val | SDHCI_BUS_POWER_EN);
+	udelay(400);
+
+	/* set bus width */
+	val = dove_sdhci_readb(host, SDHCI_HOST_CONTROL) &
+		~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_8:
+		val |= SDHCI_DATA_WIDTH_8BIT;
+		break;
+	case MMC_BUS_WIDTH_4:
+		val |= SDHCI_DATA_WIDTH_4BIT;
+		break;
+	}
+
+	if (ios->clock > 26000000)
+		val |= SDHCI_HIGHSPEED_EN;
+	else
+		val &= ~SDHCI_HIGHSPEED_EN;
+
+	dove_sdhci_writeb(host, SDHCI_HOST_CONTROL, val);
+
+	/* set bus clock */
+	dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, 0);
+	val = dove_sdhci_get_clock_divider(host, ios->clock);
+	val = SDHCI_INTCLOCK_EN | SDHCI_FREQ_SEL(val);
+	dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, val);
+
+	/* wait for internal clock stable */
+	start = get_time_ns();
+	while (!(dove_sdhci_readw(host, SDHCI_CLOCK_CONTROL) &
+			SDHCI_INTCLOCK_STABLE)) {
+		if (is_timeout(start, 20 * MSECOND)) {
+			dev_err(host->mci.hw_dev, "SDHCI clock stable timeout\n");
+			return;
+		}
+	}
+
+	/* enable bus clock */
+	dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, val | SDHCI_SDCLOCK_EN);
+}
+
+static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
+{
+	u64 start;
+	struct dove_sdhci *host = priv_from_mci_host(mci);
+
+	/* reset sdhci controller */
+	dove_sdhci_writeb(host, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL);
+
+	/* wait for reset completion */
+	start = get_time_ns();
+	while (1) {
+		if ((dove_sdhci_readb(host, SDHCI_SOFTWARE_RESET) &
+				SDHCI_RESET_ALL) == 0)
+			break;
+		if (is_timeout(start, 100 * MSECOND)) {
+			dev_err(dev, "SDHCI reset timeout\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
+	dove_sdhci_writel(host, SDHCI_INT_ENABLE, ~0);
+	dove_sdhci_writel(host, SDHCI_SIGNAL_ENABLE, ~0);
+
+	return 0;
+}
+
+static void dove_sdhci_set_mci_caps(struct dove_sdhci *host)
+{
+	u16 caps[2];
+
+	caps[0] = dove_sdhci_readw(host, SDHCI_CAPABILITIES);
+	caps[1] = dove_sdhci_readw(host, SDHCI_CAPABILITIES_1);
+
+	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_180)
+		host->mci.voltages |= MMC_VDD_165_195;
+	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_300)
+		host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
+	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_330)
+		host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	if (caps[1] & SDHCI_HOSTCAP_HIGHSPEED)
+		host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ |
+					MMC_CAP_MMC_HIGHSPEED |
+					MMC_CAP_SD_HIGHSPEED);
+
+	/* parse board supported bus width capabilities */
+	mci_of_parse(&host->mci);
+
+	/* limit bus widths to controller capabilities */
+	if ((caps[1] & SDHCI_HOSTCAP_8BIT) == 0)
+		host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA;
+}
+
+static int dove_sdhci_detect(struct device_d *dev)
+{
+	struct dove_sdhci *host = dev->priv;
+	return mci_detect_card(&host->mci);
+}
+
+static int dove_sdhci_probe(struct device_d *dev)
+{
+	struct dove_sdhci *host;
+	int ret;
+
+	host = xzalloc(sizeof(*host));
+	host->base = dev_request_mem_region(dev, 0);
+	host->mci.hw_dev = dev;
+	host->mci.send_cmd = dove_sdhci_mci_send_cmd;
+	host->mci.set_ios = dove_sdhci_mci_set_ios;
+	host->mci.init = dove_sdhci_mci_init;
+	host->mci.f_max = 50000000;
+	host->mci.f_min = host->mci.f_max / 256;
+	dev->priv = host;
+	dev->detect = dove_sdhci_detect;
+
+	dove_sdhci_set_mci_caps(host);
+
+	ret = mci_register(&host->mci);
+	if (ret)
+		free(host);
+	return ret;
+}
+
+static struct of_device_id dove_sdhci_dt_ids[] = {
+	{ .compatible = "marvell,dove-sdhci", },
+	{ }
+};
+
+static struct driver_d dove_sdhci_driver = {
+	.name = "dove-sdhci",
+	.probe = dove_sdhci_probe,
+	.of_compatible = DRV_OF_COMPAT(dove_sdhci_dt_ids),
+};
+device_platform_driver(dove_sdhci_driver);
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [RFC 0/2] mci: Dove SDHCI driver
  2013-07-05 21:22 [RFC 0/2] mci: Dove SDHCI driver Sebastian Hesselbarth
  2013-07-05 21:22 ` [RFC 1/2] mci: add more defines to sdhci include Sebastian Hesselbarth
  2013-07-05 21:22 ` [RFC 2/2] mci: add Marvell Dove SDHCI driver Sebastian Hesselbarth
@ 2013-07-09 17:38 ` Sascha Hauer
  2013-07-10 22:51   ` Sebastian Hesselbarth
  2 siblings, 1 reply; 8+ messages in thread
From: Sascha Hauer @ 2013-07-09 17:38 UTC (permalink / raw)
  To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox

On Fri, Jul 05, 2013 at 11:22:17PM +0200, Sebastian Hesselbarth wrote:
> This RFC presents a working SDHCI driver for the IP found on Marvell
> Dove SoCs.
> 
> @Sascha: We talked about refactoring common SDHCI code and I just want
> to show what I came up with for Dove. After thinking about existing barebox
> SDHCI, I had the impression that I should reimplement Dove SDHCI with writel
> as it is already made in other SDHCI drivers.

Yes, common register accessors would make it possible to share code.
Maybe we can start with some sdhc_write[bwl]/read[bwl] functions which
are static inline wrappers around regular writel/readl. This would make
it possible to add an indirection there should we have to.

> 
> I will be not checking mails regularily nor working on Barebox for the next
> two weeks, so feel free to simply ignore the RFC. But I thought it will be
> a good way to discuss your plans for common SDHCI code.

I think the driver looks mostly good. It should be a good base to factor
out common code in the future.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [RFC 0/2] mci: Dove SDHCI driver
  2013-07-09 17:38 ` [RFC 0/2] mci: " Sascha Hauer
@ 2013-07-10 22:51   ` Sebastian Hesselbarth
  0 siblings, 0 replies; 8+ messages in thread
From: Sebastian Hesselbarth @ 2013-07-10 22:51 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Thomas Petazzoni, barebox

On 07/09/2013 07:38 PM, Sascha Hauer wrote:
> On Fri, Jul 05, 2013 at 11:22:17PM +0200, Sebastian Hesselbarth wrote:
>> This RFC presents a working SDHCI driver for the IP found on Marvell
>> Dove SoCs.
>>
>> @Sascha: We talked about refactoring common SDHCI code and I just want
>> to show what I came up with for Dove. After thinking about existing barebox
>> SDHCI, I had the impression that I should reimplement Dove SDHCI with writel
>> as it is already made in other SDHCI drivers.
>
> Yes, common register accessors would make it possible to share code.
> Maybe we can start with some sdhc_write[bwl]/read[bwl] functions which
> are static inline wrappers around regular writel/readl. This would make
> it possible to add an indirection there should we have to.

Sascha,

a quick look at the SDHCI spec showed that the "native" word width is
16b. At least Dove allows you to read registers at any width, but there
may be other controllers with limited word width capabilities. Anyway,
I guess we should try to have the common code and the defines use those
16b reg width.

>> I will be not checking mails regularily nor working on Barebox for the next
>> two weeks, so feel free to simply ignore the RFC. But I thought it will be
>> a good way to discuss your plans for common SDHCI code.
>
> I think the driver looks mostly good. It should be a good base to factor
> out common code in the future.

Ok, when I get back to this, I will prepare a real patch for it.

Sebastian


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [RFC 2/2] mci: add Marvell Dove SDHCI driver
  2013-07-05 21:22 ` [RFC 2/2] mci: add Marvell Dove SDHCI driver Sebastian Hesselbarth
@ 2015-02-17 23:43   ` Michael Grzeschik
  2015-02-18 19:34     ` Sebastian Hesselbarth
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Grzeschik @ 2015-02-17 23:43 UTC (permalink / raw)
  To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox

On Fri, Jul 05, 2013 at 11:22:19PM +0200, Sebastian Hesselbarth wrote:
> This adds a driver for the SDHCI controller found on Marvell Dove SoCs.
> Despite a missing pinctrl driver, corresponding MPP config has to be
> set on a per board basis.
> 
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
> Cc: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Cc: barebox@lists.infradead.org
> ---
>  drivers/mci/Kconfig      |    7 +
>  drivers/mci/Makefile     |    1 +
>  drivers/mci/dove-sdhci.c |  365 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 373 insertions(+)
>  create mode 100644 drivers/mci/dove-sdhci.c
> 
> diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
> index 7aff7df..554ce9e 100644
> --- a/drivers/mci/Kconfig
> +++ b/drivers/mci/Kconfig
> @@ -52,6 +52,13 @@ config MCI_BCM2835
>  	bool "MCI support for BCM2835"
>  	depends on ARCH_BCM2835
>  
> +config MCI_DOVE
> +	bool "Marvell Dove SDHCI"
> +	depends on ARCH_DOVE
> +	help
> +	  Enable this entry to add support to read and write SD cards on a
> +	  Marvell Dove SoC based system.
> +
>  config MCI_IMX
>  	bool "i.MX"
>  	depends on ARCH_IMX27 || ARCH_IMX31
> diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
> index df06a08..59e39cc 100644
> --- a/drivers/mci/Makefile
> +++ b/drivers/mci/Makefile
> @@ -1,6 +1,7 @@
>  obj-$(CONFIG_MCI)		+= mci-core.o
>  obj-$(CONFIG_MCI_ATMEL)		+= atmel_mci.o
>  obj-$(CONFIG_MCI_BCM2835)	+= mci-bcm2835.o
> +obj-$(CONFIG_MCI_DOVE)		+= dove-sdhci.o
>  obj-$(CONFIG_MCI_IMX)		+= imx.o
>  obj-$(CONFIG_MCI_IMX_ESDHC)	+= imx-esdhc.o
>  obj-$(CONFIG_MCI_MXS)		+= mxs.o
> diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
> new file mode 100644
> index 0000000..91ef8b0
> --- /dev/null
> +++ b/drivers/mci/dove-sdhci.c
> @@ -0,0 +1,365 @@
> +/*
> + * Marvell Dove SDHCI MCI driver
> + *
> + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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.
> + *
> + */
> +
> +#include <clock.h>
> +#include <common.h>
> +#include <init.h>
> +#include <io.h>
> +#include <malloc.h>
> +#include <mci.h>
> +#include <linux/err.h>
> +
> +#include "sdhci.h"
> +
> +struct dove_sdhci {
> +	struct mci_host mci;
> +	void __iomem *base;
> +};
> +
> +#define priv_from_mci_host(h)	\
> +	container_of(h, struct dove_sdhci, mci);
> +
> +static inline void dove_sdhci_writel(struct dove_sdhci *p, int reg, u32 val)
> +{
> +	writel(val, p->base + reg);
> +}
> +
> +static inline void dove_sdhci_writew(struct dove_sdhci *p, int reg, u16 val)
> +{
> +	writew(val, p->base + reg);
> +}
> +
> +static inline void dove_sdhci_writeb(struct dove_sdhci *p, int reg, u8 val)
> +{
> +	writeb(val, p->base + reg);
> +}
> +
> +static inline u32 dove_sdhci_readl(struct dove_sdhci *p, int reg)
> +{
> +	return readl(p->base + reg);
> +}
> +
> +static inline u16 dove_sdhci_readw(struct dove_sdhci *p, int reg)
> +{
> +	return readw(p->base + reg);
> +}
> +
> +static inline u8 dove_sdhci_readb(struct dove_sdhci *p, int reg)
> +{
> +	return readb(p->base + reg);
> +}
> +
> +static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask)
> +{
> +	u16 status;
> +	u64 start;
> +
> +	start = get_time_ns();
> +	while (1) {
> +		status = dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS);
> +		if (status & SDHCI_INT_ERROR)
> +			return -EPERM;
> +		if (status & mask)
> +			break;
> +		if (is_timeout(start, 100 * MSECOND)) {
> +			dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for done\n");
> +			return -ETIMEDOUT;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
> +				struct mci_data *data)
> +{
> +	u16 val;
> +	u64 start;
> +	int ret;
> +	struct dove_sdhci *host = priv_from_mci_host(mci);
> +
> +	dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
> +
> +	/* Do not wait for CMD_INHIBIT_DAT on stop commands */
> +	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
> +		val = SDHCI_CMD_INHIBIT_CMD;
> +	else
> +		val = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
> +
> +	/* Wait for bus idle */
> +	start = get_time_ns();
> +	while (1) {
> +		if (!(dove_sdhci_readw(host, SDHCI_PRESENT_STATE0) & val))
> +			break;
> +		if (is_timeout(start, 10 * MSECOND)) {

I had to set something higher than 10 milliseconds to make this driver
work with solidrun cubox. Otherwise it was always running into the
timeout.

Regards,
Michael

> +			dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for idle\n");
> +			return -ETIMEDOUT;
> +		}
> +	}
> +
> +	/* setup transfer data */
> +	if (data) {
> +		if (data->flags & MMC_DATA_READ)
> +			dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, (u32)data->dest);
> +		else
> +			dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, (u32)data->src);
> +		dove_sdhci_writew(host, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K |
> +				SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
> +		dove_sdhci_writew(host, SDHCI_BLOCK_COUNT, data->blocks);
> +		dove_sdhci_writeb(host, SDHCI_TIMEOUT_CONTROL, 0xe);
> +	}
> +
> +	/* setup transfer mode */
> +	val = 0;
> +	if (data) {
> +		val |= SDHCI_DMA_EN | SDHCI_BLOCK_COUNT_EN;
> +		if (data->blocks > 1)
> +			val |= SDHCI_MULTIPLE_BLOCKS;
> +		if (data->flags & MMC_DATA_READ)
> +			val |= SDHCI_DATA_TO_HOST;
> +	}
> +	dove_sdhci_writew(host, SDHCI_TRANSFER_MODE, val);
> +
> +	dove_sdhci_writel(host, SDHCI_ARGUMENT, cmd->cmdarg);
> +
> +	if (!(cmd->resp_type & MMC_RSP_PRESENT))
> +		val = SDHCI_RESP_NONE;
> +	else if (cmd->resp_type & MMC_RSP_136)
> +		val = SDHCI_RESP_TYPE_136;
> +	else if (cmd->resp_type & MMC_RSP_BUSY)
> +		val = SDHCI_RESP_TYPE_48_BUSY;
> +	else
> +		val = SDHCI_RESP_TYPE_48;
> +
> +	if (cmd->resp_type & MMC_RSP_CRC)
> +		val |= SDHCI_CMD_CRC_CHECK_EN;
> +	if (cmd->resp_type & MMC_RSP_OPCODE)
> +		val |= SDHCI_CMD_INDEX_CHECK_EN;
> +	if (data)
> +		val |= SDHCI_DATA_PRESENT;
> +	val |= SDHCI_CMD_INDEX(cmd->cmdidx);
> +
> +	dove_sdhci_writew(host, SDHCI_COMMAND, val);
> +
> +	ret = dove_sdhci_wait_for_done(host, SDHCI_INT_CMD_COMPLETE);
> +	if (ret) {
> +		dev_err(host->mci.hw_dev, "error on command %d\n", cmd->cmdidx);
> +		dev_err(host->mci.hw_dev, "state = %04x %04x, interrupt = %04x %04x\n",
> +			dove_sdhci_readw(host, SDHCI_PRESENT_STATE0),
> +			dove_sdhci_readw(host, SDHCI_PRESENT_STATE1),
> +			dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS),
> +			dove_sdhci_readw(host, SDHCI_INT_ERROR_STATUS));
> +		goto cmd_error;
> +	}
> +
> +	/* CRC is stripped so we need to do some shifting. */
> +	if (cmd->resp_type & MMC_RSP_136) {
> +		int i;
> +		for (i = 0; i < 4; i++) {
> +			cmd->response[i] = dove_sdhci_readl(host,
> +					SDHCI_RESPONSE_0 + 4*(3-i)) << 8;
> +			if (i != 3)
> +				cmd->response[i] |= dove_sdhci_readb(host,
> +					SDHCI_RESPONSE_0 + 4*(3-i) - 1);
> +		}
> +	} else
> +		cmd->response[0] = dove_sdhci_readl(host, SDHCI_RESPONSE_0);
> +
> +	if (data) {
> +		ret = dove_sdhci_wait_for_done(host, SDHCI_INT_XFER_COMPLETE);
> +		if (ret) {
> +			dev_err(host->mci.hw_dev, "error while transfering data for command %d\n",
> +				cmd->cmdidx);
> +			dev_err(host->mci.hw_dev, "state = %04x %04x, interrupt = %04x %04x\n",
> +				dove_sdhci_readw(host, SDHCI_PRESENT_STATE0),
> +				dove_sdhci_readw(host, SDHCI_PRESENT_STATE1),
> +				dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS),
> +				dove_sdhci_readw(host, SDHCI_INT_ERROR_STATUS));
> +			goto cmd_error;
> +		}
> +	}
> +
> +cmd_error:
> +	dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
> +	return ret;
> +}
> +
> +static u16 dove_sdhci_get_clock_divider(struct dove_sdhci *host, u32 reqclk)
> +{
> +	u16 div;
> +
> +	for (div = 1; div < SDHCI_SPEC_200_MAX_CLK_DIVIDER; div *= 2)
> +		if ((host->mci.f_max / div) <= reqclk)
> +			break;
> +	div /= 2;
> +
> +	return div;
> +}
> +
> +static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
> +{
> +	u16 val;
> +	u64 start;
> +	struct dove_sdhci *host = priv_from_mci_host(mci);
> +
> +	debug("%s: clock = %u, bus-width = %d, timing = %02x\n", __func__, ios->clock, ios->bus_width, ios->timing);
> +
> +	/* disable on zero clock */
> +	if (!ios->clock)
> +		return;
> +
> +	/* enable bus power */
> +	val = SDHCI_BUS_VOLTAGE_330;
> +	dove_sdhci_writeb(host, SDHCI_POWER_CONTROL, val | SDHCI_BUS_POWER_EN);
> +	udelay(400);
> +
> +	/* set bus width */
> +	val = dove_sdhci_readb(host, SDHCI_HOST_CONTROL) &
> +		~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
> +	switch (ios->bus_width) {
> +	case MMC_BUS_WIDTH_8:
> +		val |= SDHCI_DATA_WIDTH_8BIT;
> +		break;
> +	case MMC_BUS_WIDTH_4:
> +		val |= SDHCI_DATA_WIDTH_4BIT;
> +		break;
> +	}
> +
> +	if (ios->clock > 26000000)
> +		val |= SDHCI_HIGHSPEED_EN;
> +	else
> +		val &= ~SDHCI_HIGHSPEED_EN;
> +
> +	dove_sdhci_writeb(host, SDHCI_HOST_CONTROL, val);
> +
> +	/* set bus clock */
> +	dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, 0);
> +	val = dove_sdhci_get_clock_divider(host, ios->clock);
> +	val = SDHCI_INTCLOCK_EN | SDHCI_FREQ_SEL(val);
> +	dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, val);
> +
> +	/* wait for internal clock stable */
> +	start = get_time_ns();
> +	while (!(dove_sdhci_readw(host, SDHCI_CLOCK_CONTROL) &
> +			SDHCI_INTCLOCK_STABLE)) {
> +		if (is_timeout(start, 20 * MSECOND)) {
> +			dev_err(host->mci.hw_dev, "SDHCI clock stable timeout\n");
> +			return;
> +		}
> +	}
> +
> +	/* enable bus clock */
> +	dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, val | SDHCI_SDCLOCK_EN);
> +}
> +
> +static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
> +{
> +	u64 start;
> +	struct dove_sdhci *host = priv_from_mci_host(mci);
> +
> +	/* reset sdhci controller */
> +	dove_sdhci_writeb(host, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL);
> +
> +	/* wait for reset completion */
> +	start = get_time_ns();
> +	while (1) {
> +		if ((dove_sdhci_readb(host, SDHCI_SOFTWARE_RESET) &
> +				SDHCI_RESET_ALL) == 0)
> +			break;
> +		if (is_timeout(start, 100 * MSECOND)) {
> +			dev_err(dev, "SDHCI reset timeout\n");
> +			return -ETIMEDOUT;
> +		}
> +	}
> +
> +	dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
> +	dove_sdhci_writel(host, SDHCI_INT_ENABLE, ~0);
> +	dove_sdhci_writel(host, SDHCI_SIGNAL_ENABLE, ~0);
> +
> +	return 0;
> +}
> +
> +static void dove_sdhci_set_mci_caps(struct dove_sdhci *host)
> +{
> +	u16 caps[2];
> +
> +	caps[0] = dove_sdhci_readw(host, SDHCI_CAPABILITIES);
> +	caps[1] = dove_sdhci_readw(host, SDHCI_CAPABILITIES_1);
> +
> +	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_180)
> +		host->mci.voltages |= MMC_VDD_165_195;
> +	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_300)
> +		host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
> +	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_330)
> +		host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
> +
> +	if (caps[1] & SDHCI_HOSTCAP_HIGHSPEED)
> +		host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ |
> +					MMC_CAP_MMC_HIGHSPEED |
> +					MMC_CAP_SD_HIGHSPEED);
> +
> +	/* parse board supported bus width capabilities */
> +	mci_of_parse(&host->mci);
> +
> +	/* limit bus widths to controller capabilities */
> +	if ((caps[1] & SDHCI_HOSTCAP_8BIT) == 0)
> +		host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA;
> +}
> +
> +static int dove_sdhci_detect(struct device_d *dev)
> +{
> +	struct dove_sdhci *host = dev->priv;
> +	return mci_detect_card(&host->mci);
> +}
> +
> +static int dove_sdhci_probe(struct device_d *dev)
> +{
> +	struct dove_sdhci *host;
> +	int ret;
> +
> +	host = xzalloc(sizeof(*host));
> +	host->base = dev_request_mem_region(dev, 0);
> +	host->mci.hw_dev = dev;
> +	host->mci.send_cmd = dove_sdhci_mci_send_cmd;
> +	host->mci.set_ios = dove_sdhci_mci_set_ios;
> +	host->mci.init = dove_sdhci_mci_init;
> +	host->mci.f_max = 50000000;
> +	host->mci.f_min = host->mci.f_max / 256;
> +	dev->priv = host;
> +	dev->detect = dove_sdhci_detect;
> +
> +	dove_sdhci_set_mci_caps(host);
> +
> +	ret = mci_register(&host->mci);
> +	if (ret)
> +		free(host);
> +	return ret;
> +}
> +
> +static struct of_device_id dove_sdhci_dt_ids[] = {
> +	{ .compatible = "marvell,dove-sdhci", },
> +	{ }
> +};
> +
> +static struct driver_d dove_sdhci_driver = {
> +	.name = "dove-sdhci",
> +	.probe = dove_sdhci_probe,
> +	.of_compatible = DRV_OF_COMPAT(dove_sdhci_dt_ids),
> +};
> +device_platform_driver(dove_sdhci_driver);
> -- 
> 1.7.10.4
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [RFC 2/2] mci: add Marvell Dove SDHCI driver
  2015-02-17 23:43   ` Michael Grzeschik
@ 2015-02-18 19:34     ` Sebastian Hesselbarth
  2015-02-19 11:59       ` Michael Grzeschik
  0 siblings, 1 reply; 8+ messages in thread
From: Sebastian Hesselbarth @ 2015-02-18 19:34 UTC (permalink / raw)
  To: Michael Grzeschik; +Cc: Thomas Petazzoni, barebox

On 18.02.2015 00:43, Michael Grzeschik wrote:
> On Fri, Jul 05, 2013 at 11:22:19PM +0200, Sebastian Hesselbarth wrote:

Nice! It just bumped up the RFC from 1.5yrs back to top in my barebox
mail folder ;)

>> This adds a driver for the SDHCI controller found on Marvell Dove SoCs.
>> Despite a missing pinctrl driver, corresponding MPP config has to be
>> set on a per board basis.
[...]
>> diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
>> new file mode 100644
>> index 0000000..91ef8b0
>> --- /dev/null
>> +++ b/drivers/mci/dove-sdhci.c
[...]
>> +static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
>> +				struct mci_data *data)
>> +{
>> +	u16 val;
>> +	u64 start;
>> +	int ret;
>> +	struct dove_sdhci *host = priv_from_mci_host(mci);
>> +
>> +	dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
>> +
>> +	/* Do not wait for CMD_INHIBIT_DAT on stop commands */
>> +	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
>> +		val = SDHCI_CMD_INHIBIT_CMD;
>> +	else
>> +		val = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
>> +
>> +	/* Wait for bus idle */
>> +	start = get_time_ns();
>> +	while (1) {
>> +		if (!(dove_sdhci_readw(host, SDHCI_PRESENT_STATE0) & val))
>> +			break;
>> +		if (is_timeout(start, 10 * MSECOND)) {
>
> I had to set something higher than 10 milliseconds to make this driver
> work with solidrun cubox. Otherwise it was always running into the
> timeout.

Can you tell to what value you had to increase the timeout?

I have no problem increasing the timeout, we shouldn't run into
any of them anyway at this point.

Sebastian

>> +			dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for idle\n");
>> +			return -ETIMEDOUT;
>> +		}
>> +	}
[...]

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [RFC 2/2] mci: add Marvell Dove SDHCI driver
  2015-02-18 19:34     ` Sebastian Hesselbarth
@ 2015-02-19 11:59       ` Michael Grzeschik
  0 siblings, 0 replies; 8+ messages in thread
From: Michael Grzeschik @ 2015-02-19 11:59 UTC (permalink / raw)
  To: Sebastian Hesselbarth; +Cc: Thomas Petazzoni, barebox

On Wed, Feb 18, 2015 at 08:34:45PM +0100, Sebastian Hesselbarth wrote:
> On 18.02.2015 00:43, Michael Grzeschik wrote:
> >On Fri, Jul 05, 2013 at 11:22:19PM +0200, Sebastian Hesselbarth wrote:
> 
> Nice! It just bumped up the RFC from 1.5yrs back to top in my barebox
> mail folder ;)

:)

> >>This adds a driver for the SDHCI controller found on Marvell Dove SoCs.
> >>Despite a missing pinctrl driver, corresponding MPP config has to be
> >>set on a per board basis.
> [...]
> >>diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
> >>new file mode 100644
> >>index 0000000..91ef8b0
> >>--- /dev/null
> >>+++ b/drivers/mci/dove-sdhci.c
> [...]
> >>+static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
> >>+				struct mci_data *data)
> >>+{
> >>+	u16 val;
> >>+	u64 start;
> >>+	int ret;
> >>+	struct dove_sdhci *host = priv_from_mci_host(mci);
> >>+
> >>+	dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0);
> >>+
> >>+	/* Do not wait for CMD_INHIBIT_DAT on stop commands */
> >>+	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
> >>+		val = SDHCI_CMD_INHIBIT_CMD;
> >>+	else
> >>+		val = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
> >>+
> >>+	/* Wait for bus idle */
> >>+	start = get_time_ns();
> >>+	while (1) {
> >>+		if (!(dove_sdhci_readw(host, SDHCI_PRESENT_STATE0) & val))
> >>+			break;
> >>+		if (is_timeout(start, 10 * MSECOND)) {
> >
> >I had to set something higher than 10 milliseconds to make this driver
> >work with solidrun cubox. Otherwise it was always running into the
> >timeout.
> 
> Can you tell to what value you had to increase the timeout?
> 
> I have no problem increasing the timeout, we shouldn't run into
> any of them anyway at this point.

I checked this code again without my changes. Just to do some
approximation how small this timeout could get.

This time I have been using another SD-Card.

With that card it was even working without changing the timeout.
But when I started to copy data from the card to ram (which I did not
check so far), it was barking the following error:

dove-sdhci f1092000.sdio-host: SDHCI timeout while waiting for done
dove-sdhci f1092000.sdio-host: error while transfering data for command 18
dove-sdhci f1092000.sdio-host: state = 0206 01ef, interrupt = 0009 0000

This came from the function dove_sdhci_wait_for_done which also has
timeout issues. I had no luck with changing this timeout barrier. It was
giving this error even with an timeout of one second.

I see in the kernel that the dove-sdhci is using the quirk
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL which probably needs some
investigation.

Thanks,
Michael

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2015-02-19 11:59 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-05 21:22 [RFC 0/2] mci: Dove SDHCI driver Sebastian Hesselbarth
2013-07-05 21:22 ` [RFC 1/2] mci: add more defines to sdhci include Sebastian Hesselbarth
2013-07-05 21:22 ` [RFC 2/2] mci: add Marvell Dove SDHCI driver Sebastian Hesselbarth
2015-02-17 23:43   ` Michael Grzeschik
2015-02-18 19:34     ` Sebastian Hesselbarth
2015-02-19 11:59       ` Michael Grzeschik
2013-07-09 17:38 ` [RFC 0/2] mci: " Sascha Hauer
2013-07-10 22:51   ` Sebastian Hesselbarth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox