* [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