mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/3] MMC: SDHCI: Add and use common DMA helpers
@ 2021-06-10 14:47 Sascha Hauer
  2021-06-10 14:47 ` [PATCH 1/3] mci: sdhci: Add DMA transfer helpers Sascha Hauer
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Sascha Hauer @ 2021-06-10 14:47 UTC (permalink / raw)
  To: Barebox List

So far the SDHCI common code can only do PIO data transfers. This series
pimps that up to allow DMA data transfers. The imx-esdhc driver is
converted to use these new helpers and also the new Rockchip SDHCI
support which I resend here converted to use the helpers.

Sascha

Sascha Hauer (3):
  mci: sdhci: Add DMA transfer helpers
  mci: Add support for Rockchip variant of the dwcmshc
  mci: imx-esdhc: Use common DMA helpers

 drivers/mci/Kconfig                  |   7 +
 drivers/mci/Makefile                 |   1 +
 drivers/mci/arasan-sdhci.c           |   2 +-
 drivers/mci/atmel-sdhci-common.c     |   2 +-
 drivers/mci/imx-esdhc-common.c       |  88 ++-----
 drivers/mci/mci-bcm2835.c            |   2 +-
 drivers/mci/rockchip-dwcmshc-sdhci.c | 377 +++++++++++++++++++++++++++
 drivers/mci/sdhci.c                  | 118 ++++++++-
 drivers/mci/sdhci.h                  |  10 +-
 9 files changed, 538 insertions(+), 69 deletions(-)
 create mode 100644 drivers/mci/rockchip-dwcmshc-sdhci.c

-- 
2.29.2


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


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

* [PATCH 1/3] mci: sdhci: Add DMA transfer helpers
  2021-06-10 14:47 [PATCH 0/3] MMC: SDHCI: Add and use common DMA helpers Sascha Hauer
@ 2021-06-10 14:47 ` Sascha Hauer
  2021-06-10 14:47 ` [PATCH 2/3] mci: Add support for Rockchip variant of the dwcmshc Sascha Hauer
  2021-06-10 14:47 ` [PATCH 3/3] mci: imx-esdhc: Use common DMA helpers Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2021-06-10 14:47 UTC (permalink / raw)
  To: Barebox List

The SDHCI helpers only use PIO mode so far. This patch implements SDMA
mode helpers. The helpers with _pio suffix explicitly do PIO while the
DMA helpers have a _dma suffix and first try to do DMA, but fall back
to PIO when DMA is not possible.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c       |   2 +-
 drivers/mci/atmel-sdhci-common.c |   2 +-
 drivers/mci/imx-esdhc-common.c   |   2 +-
 drivers/mci/mci-bcm2835.c        |   2 +-
 drivers/mci/sdhci.c              | 118 ++++++++++++++++++++++++++++++-
 drivers/mci/sdhci.h              |  10 ++-
 6 files changed, 130 insertions(+), 6 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index dd5ad9d69b..04fce62bf4 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -213,7 +213,7 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
 	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, mask);
 
 	if (data)
-		ret = sdhci_transfer_data(&host->sdhci, data);
+		ret = sdhci_transfer_data_pio(&host->sdhci, data);
 
 error:
 	if (ret) {
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index 9d78c59e95..eff2a993db 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -166,7 +166,7 @@ int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd,
 	sdhci_write32(sdhci, SDHCI_INT_STATUS, mask);
 
 	if (data)
-		sdhci_transfer_data(sdhci, data);
+		sdhci_transfer_data_pio(sdhci, data);
 
 	udelay(1000);
 
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index 7980278801..a85459d29c 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -109,7 +109,7 @@ static int esdhc_do_data(struct fsl_esdhc_host *host, struct mci_data *data,
 	u32 irqstat;
 
 	if (esdhc_use_pio_mode())
-		return sdhci_transfer_data(&host->sdhci, data);
+		return sdhci_transfer_data_pio(&host->sdhci, data);
 
 	do {
 		irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
diff --git a/drivers/mci/mci-bcm2835.c b/drivers/mci/mci-bcm2835.c
index 91027857be..0450f899c6 100644
--- a/drivers/mci/mci-bcm2835.c
+++ b/drivers/mci/mci-bcm2835.c
@@ -172,7 +172,7 @@ static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd,
 	}
 
 	if (!ret && data)
-		ret = sdhci_transfer_data(&host->sdhci, data);
+		ret = sdhci_transfer_data_pio(&host->sdhci, data);
 
 	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, 0xFFFFFFFF);
 	if (ret) {
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 0783f6d420..aca4a5a6f9 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -4,6 +4,7 @@
 #include <driver.h>
 #include <mci.h>
 #include <io.h>
+#include <dma.h>
 #include <linux/bitfield.h>
 
 #include "sdhci.h"
@@ -123,12 +124,112 @@ void sdhci_set_bus_width(struct sdhci *host, int width)
 
 #endif
 
-int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data)
+void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data)
+{
+	if (!data)
+		return;
+
+	sdhci_write16(sdhci, SDHCI_BLOCK_SIZE, sdhci->sdma_boundary |
+		    SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
+	sdhci_write16(sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+}
+
+void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data,
+			  dma_addr_t *dma)
+{
+	struct device_d *dev = sdhci->mci->hw_dev;
+	int nbytes;
+
+	if (!data)
+		return;
+
+	sdhci_setup_data_pio(sdhci, data);
+
+	if (!dma)
+		return;
+
+	nbytes = data->blocks * data->blocksize;
+
+	if (data->flags & MMC_DATA_READ)
+		*dma = dma_map_single(dev, (void *)data->src, nbytes,
+				      DMA_FROM_DEVICE);
+	else
+		*dma = dma_map_single(dev, data->dest, nbytes,
+				      DMA_TO_DEVICE);
+
+	if (dma_mapping_error(dev, *dma)) {
+		*dma = SDHCI_NO_DMA;
+		return;
+	}
+
+	sdhci_write32(sdhci, SDHCI_DMA_ADDRESS, *dma);
+}
+
+int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
+			    dma_addr_t dma)
+{
+	struct device_d *dev = sdhci->mci->hw_dev;
+	int nbytes;
+	u32 irqstat;
+	int ret;
+
+	if (!data)
+		return 0;
+
+	nbytes = data->blocks * data->blocksize;
+
+	do {
+		irqstat = sdhci_read32(sdhci, SDHCI_INT_STATUS);
+
+		if (irqstat & SDHCI_INT_DATA_END_BIT) {
+			ret = -EIO;
+			goto out;
+		}
+
+		if (irqstat & SDHCI_INT_DATA_CRC) {
+			ret = -EBADMSG;
+			goto out;
+		}
+
+		if (irqstat & SDHCI_INT_DATA_TIMEOUT) {
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+
+		if (irqstat & SDHCI_INT_DMA) {
+			u32 addr = sdhci_read32(sdhci, SDHCI_DMA_ADDRESS);
+
+			/*
+			 * DMA engine has stopped on buffer boundary. Acknowledge
+			 * the interrupt and kick the DMA engine again.
+			 */
+			sdhci_write32(sdhci, SDHCI_INT_STATUS, SDHCI_INT_DMA);
+			sdhci_write32(sdhci, SDHCI_DMA_ADDRESS, addr);
+		}
+
+		if (irqstat & SDHCI_INT_XFER_COMPLETE)
+			break;
+	} while (1);
+
+	ret = 0;
+out:
+	if (data->flags & MMC_DATA_READ)
+		dma_unmap_single(dev, dma, nbytes, DMA_FROM_DEVICE);
+	else
+		dma_unmap_single(dev, dma, nbytes, DMA_TO_DEVICE);
+
+	return 0;
+}
+
+int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data)
 {
 	unsigned int block = 0;
 	u32 stat, prs;
 	uint64_t start = get_time_ns();
 
+	if (!data)
+		return 0;
+
 	do {
 		stat = sdhci_read32(sdhci, SDHCI_INT_STATUS);
 		if (stat & SDHCI_INT_ERROR)
@@ -161,6 +262,19 @@ int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data)
 	return 0;
 }
 
+int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma)
+{
+	struct device_d *dev = sdhci->mci->hw_dev;
+
+	if (!data)
+		return 0;
+
+	if (dma_mapping_error(dev, dma))
+		return sdhci_transfer_data_pio(sdhci, data);
+	else
+		return sdhci_transfer_data_dma(sdhci, data, dma);
+}
+
 int sdhci_reset(struct sdhci *sdhci, u8 mask)
 {
 	u8 val;
@@ -428,5 +542,7 @@ int sdhci_setup_host(struct sdhci *host)
 	if (host->caps & SDHCI_CAN_DO_HISPD)
 		mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
+	host->sdma_boundary = SDHCI_DMA_BOUNDARY_512K;
+
 	return 0;
 }
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 0cdd558565..351940a511 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -2,6 +2,7 @@
 #define __MCI_SDHCI_H
 
 #include <pbl.h>
+#include <dma.h>
 #include <linux/iopoll.h>
 
 #define SDHCI_DMA_ADDRESS					0x00
@@ -201,6 +202,7 @@ struct sdhci {
 	u32 caps;	/* CAPABILITY_0 */
 	u32 caps1;	/* CAPABILITY_1 */
 	bool read_caps;	/* Capability flags have been read */
+	u32 sdma_boundary;
 
 	struct mci_host	*mci;
 };
@@ -253,11 +255,17 @@ static inline void sdhci_write8(struct sdhci *host, int reg, u32 val)
 		writeb(val, host->base + reg);
 }
 
+#define SDHCI_NO_DMA DMA_ERROR_CODE
 void sdhci_read_response(struct sdhci *host, struct mci_cmd *cmd);
 void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
 			     struct mci_data *data, bool dma, u32 *command,
 			     u32 *xfer);
-int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data);
+void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data);
+void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data, dma_addr_t *dma);
+int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma);
+int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data);
+int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
+			    dma_addr_t dma);
 int sdhci_reset(struct sdhci *sdhci, u8 mask);
 u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock,
 		   unsigned int *actual_clock, unsigned int input_clock);
-- 
2.29.2


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


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

* [PATCH 2/3] mci: Add support for Rockchip variant of the dwcmshc
  2021-06-10 14:47 [PATCH 0/3] MMC: SDHCI: Add and use common DMA helpers Sascha Hauer
  2021-06-10 14:47 ` [PATCH 1/3] mci: sdhci: Add DMA transfer helpers Sascha Hauer
@ 2021-06-10 14:47 ` Sascha Hauer
  2021-06-10 14:47 ` [PATCH 3/3] mci: imx-esdhc: Use common DMA helpers Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2021-06-10 14:47 UTC (permalink / raw)
  To: Barebox List

This adds support for a Rockchip derivation of the DWCMSHC controller
which itself is a SDHCI controller found on some Rockchip SoCs like the
RK3568.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Link: https://lore.barebox.org/20210607104411.23071-13-s.hauer@pengutronix.de
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/Kconfig                  |   7 +
 drivers/mci/Makefile                 |   1 +
 drivers/mci/rockchip-dwcmshc-sdhci.c | 377 +++++++++++++++++++++++++++
 3 files changed, 385 insertions(+)
 create mode 100644 drivers/mci/rockchip-dwcmshc-sdhci.c

diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 7d4e72138d..e1fcd41271 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -79,6 +79,13 @@ config MCI_MXS
 	  Enable this entry to add support to read and write SD cards on a
 	  i.MX23/i.MX28 based system.
 
+config MCI_ROCKCHIP_DWCMSHC
+	bool "MCI sdhc support for Rockchip SoCs"
+	select MCI_SDHCI
+	help
+	  Enable this entry to add support for a Rockchip derivation of the
+	  DWCMSHC controller found on some Rockchip SoCs like the RK3568.
+
 config MCI_S3C
 	bool "S3C"
 	depends on ARCH_S3C24xx
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index 60dc100c37..b113b1c732 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_MCI_MXS)		+= mxs.o
 obj-$(CONFIG_MCI_OMAP_HSMMC)	+= omap_hsmmc.o
 obj-$(CONFIG_MCI_PXA)		+= pxamci.o
 obj-$(CONFIG_MCI_S3C)		+= s3c.o
+obj-$(CONFIG_MCI_ROCKCHIP_DWCMSHC)	+= rockchip-dwcmshc-sdhci.o
 obj-$(CONFIG_MCI_TEGRA)		+= tegra-sdmmc.o
 obj-$(CONFIG_MCI_SPI)		+= mci_spi.o
 obj-$(CONFIG_MCI_DW)		+= dw_mmc.o
diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c
new file mode 100644
index 0000000000..164f662552
--- /dev/null
+++ b/drivers/mci/rockchip-dwcmshc-sdhci.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <clock.h>
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <mci.h>
+#include <dma.h>
+#include <linux/iopoll.h>
+
+#include "sdhci.h"
+
+/* DWCMSHC specific Mode Select value */
+#define DWCMSHC_CTRL_HS400		0x7
+
+#define DWCMSHC_VER_ID			0x500
+#define DWCMSHC_VER_TYPE		0x504
+#define DWCMSHC_HOST_CTRL3		0x508
+#define DWCMSHC_EMMC_CONTROL		0x52c
+#define DWCMSHC_EMMC_ATCTRL		0x540
+
+/* Rockchip specific Registers */
+#define DWCMSHC_EMMC_DLL_CTRL		0x800
+#define DWCMSHC_EMMC_DLL_RXCLK		0x804
+#define DWCMSHC_EMMC_DLL_TXCLK		0x808
+#define DWCMSHC_EMMC_DLL_STRBIN		0x80c
+#define DWCMSHC_EMMC_DLL_STATUS0	0x840
+#define DWCMSHC_EMMC_DLL_START		BIT(0)
+#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL	29
+#define DWCMSHC_EMMC_DLL_START_POINT	16
+#define DWCMSHC_EMMC_DLL_INC		8
+#define DWCMSHC_EMMC_DLL_DLYENA		BIT(27)
+#define DLL_TXCLK_TAPNUM_DEFAULT	0x8
+#define DLL_STRBIN_TAPNUM_DEFAULT	0x8
+#define DLL_TXCLK_TAPNUM_FROM_SW	BIT(24)
+#define DLL_STRBIN_TAPNUM_FROM_SW	BIT(24)
+#define DWCMSHC_EMMC_DLL_LOCKED		BIT(8)
+#define DWCMSHC_EMMC_DLL_TIMEOUT	BIT(9)
+#define DLL_RXCLK_NO_INVERTER		1
+#define DLL_RXCLK_INVERTER		0
+#define DWCMSHC_ENHANCED_STROBE		BIT(8)
+#define DLL_LOCK_WO_TMOUT(x) \
+	((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
+	(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
+
+#define SDHCI_DWCMSHC_INT_DATA_MASK		SDHCI_INT_XFER_COMPLETE | \
+						SDHCI_INT_DMA | \
+						SDHCI_INT_SPACE_AVAIL | \
+						SDHCI_INT_DATA_AVAIL | \
+						SDHCI_INT_DATA_TIMEOUT | \
+						SDHCI_INT_DATA_CRC | \
+						SDHCI_INT_DATA_END_BIT
+
+#define SDHCI_DWCMSHC_INT_CMD_MASK		SDHCI_INT_CMD_COMPLETE | \
+						SDHCI_INT_TIMEOUT | \
+						SDHCI_INT_CRC | \
+						SDHCI_INT_END_BIT | \
+						SDHCI_INT_INDEX
+
+enum {
+	CLK_CORE,
+	CLK_BUS,
+	CLK_AXI,
+	CLK_BLOCK,
+	CLK_TIMER,
+	CLK_MAX,
+};
+
+struct rk_sdhci_host {
+	struct mci_host		mci;
+	struct sdhci		sdhci;
+	struct clk_bulk_data	clks[CLK_MAX];
+};
+
+
+static inline
+struct rk_sdhci_host *to_rk_sdhci_host(struct mci_host *mci)
+{
+	return container_of(mci, struct rk_sdhci_host, mci);
+}
+
+static int rk_sdhci_card_present(struct mci_host *mci)
+{
+	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+
+	return !!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_CARD_DETECT);
+}
+
+static int rk_sdhci_reset(struct rk_sdhci_host *host, u8 mask)
+{
+	sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, mask);
+
+	/* wait for reset completion */
+	if (wait_on_timeout(100 * MSECOND,
+			!(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))){
+		dev_err(host->mci.hw_dev, "SDHCI reset timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int rk_sdhci_init(struct mci_host *mci, struct device_d *dev)
+{
+	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+	int ret;
+
+	ret = rk_sdhci_reset(host, SDHCI_RESET_ALL);
+	if (ret)
+		return ret;
+
+	sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL,
+			    SDHCI_BUS_VOLTAGE_330 | SDHCI_BUS_POWER_EN);
+	udelay(400);
+
+	sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
+			    SDHCI_DWCMSHC_INT_DATA_MASK |
+			    SDHCI_DWCMSHC_INT_CMD_MASK);
+	sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, 0x00);
+
+	/* Disable cmd conflict check */
+	sdhci_write32(&host->sdhci, DWCMSHC_HOST_CTRL3, 0x0);
+	/* Reset previous settings */
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_TXCLK, 0);
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_STRBIN, 0);
+
+	return 0;
+}
+
+static void rk_sdhci_set_clock(struct rk_sdhci_host *host, unsigned int clock)
+{
+	u32 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, extra;
+	int err;
+
+	host->mci.clock = 0;
+
+	/* DO NOT TOUCH THIS SETTING */
+	extra = DWCMSHC_EMMC_DLL_DLYENA |
+		DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_RXCLK, extra);
+
+	if (clock == 0)
+		return;
+
+	/* Rockchip platform only support 375KHz for identify mode */
+	if (clock <= 400000)
+		clock = 375000;
+
+	clk_set_rate(host->clks[CLK_CORE].clk, clock);
+
+	sdhci_set_clock(&host->sdhci, clock, clk_get_rate(host->clks[CLK_CORE].clk));
+
+	if (clock <= 400000)
+		return;
+
+	/* Reset DLL */
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, BIT(1));
+	udelay(1);
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, 0x0);
+
+	/* Init DLL settings */
+	extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
+		0x2 << DWCMSHC_EMMC_DLL_INC |
+		DWCMSHC_EMMC_DLL_START;
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, extra);
+	err = readl_poll_timeout(host->sdhci.base + DWCMSHC_EMMC_DLL_STATUS0,
+				 extra, DLL_LOCK_WO_TMOUT(extra),
+				 500 * USEC_PER_MSEC);
+	if (err) {
+		dev_err(host->mci.hw_dev, "DLL lock timeout!\n");
+		return;
+	}
+
+	/* Disable cmd conflict check */
+	extra = sdhci_read32(&host->sdhci, DWCMSHC_HOST_CTRL3);
+	extra &= ~BIT(0);
+	sdhci_write32(&host->sdhci, DWCMSHC_HOST_CTRL3, extra);
+
+	extra = 0x1 << 16 | /* tune clock stop en */
+		0x2 << 17 | /* pre-change delay */
+		0x3 << 19;  /* post-change delay */
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_ATCTRL, extra);
+
+	extra = DWCMSHC_EMMC_DLL_DLYENA |
+		DLL_TXCLK_TAPNUM_FROM_SW |
+		txclk_tapnum;
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_TXCLK, extra);
+
+	extra = DWCMSHC_EMMC_DLL_DLYENA |
+		DLL_STRBIN_TAPNUM_DEFAULT |
+		DLL_STRBIN_TAPNUM_FROM_SW;
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_STRBIN, extra);
+}
+
+static void rk_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
+{
+	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+	u16 val;
+
+	/* stop clock */
+	sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
+
+	if (ios->clock)
+		rk_sdhci_set_clock(host, ios->clock);
+
+	sdhci_set_bus_width(&host->sdhci, ios->bus_width);
+
+	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
+
+	if (ios->clock > 26000000)
+		val |= SDHCI_CTRL_HISPD;
+	else
+		val &= ~SDHCI_CTRL_HISPD;
+
+	sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
+}
+
+static int rk_sdhci_wait_for_done(struct rk_sdhci_host *host, u32 mask)
+{
+	u64 start = get_time_ns();
+	u16 stat;
+
+	do {
+		stat = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
+		if (stat & SDHCI_INT_ERROR) {
+			dev_err(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n",
+				sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
+			return -EPERM;
+		}
+
+		if (is_timeout(start, 1000 * MSECOND)) {
+			dev_err(host->mci.hw_dev,
+					"SDHCI timeout while waiting for done\n");
+			return -ETIMEDOUT;
+		}
+	} while ((stat & mask) != mask);
+
+	return 0;
+}
+
+static void print_error(struct rk_sdhci_host *host, int cmdidx)
+{
+	dev_err(host->mci.hw_dev,
+		"error while transfering data for command %d\n", cmdidx);
+	dev_err(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n",
+		sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE),
+		sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS));
+}
+
+static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
+				 struct mci_data *data)
+{
+	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+	u32 mask, command, xfer;
+	int ret;
+	dma_addr_t dma;
+
+	/* Wait for idle before next command */
+	mask = SDHCI_CMD_INHIBIT_CMD;
+	if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)
+		mask |= SDHCI_CMD_INHIBIT_DATA;
+
+	ret = wait_on_timeout(10 * MSECOND,
+			!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & mask));
+
+	if (ret) {
+		dev_err(host->mci.hw_dev,
+				"SDHCI timeout while waiting for idle\n");
+		return ret;
+	}
+
+	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+
+	sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe);
+
+	sdhci_setup_data_dma(&host->sdhci, data, &dma);
+
+	sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data,
+				dma == SDHCI_NO_DMA ? false : true,
+				&command, &xfer);
+
+	sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
+
+	sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
+	sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
+
+	ret = rk_sdhci_wait_for_done(host, SDHCI_INT_CMD_COMPLETE);
+	if (ret == -EPERM)
+		goto error;
+	else if (ret)
+		return ret;
+
+	sdhci_read_response(&host->sdhci, cmd);
+	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
+
+	ret = sdhci_transfer_data_dma(&host->sdhci, data, dma);
+
+error:
+	if (ret) {
+		print_error(host, cmd->cmdidx);
+		rk_sdhci_reset(host, BIT(1)); /* SDHCI_RESET_CMD */
+		rk_sdhci_reset(host, BIT(2)); /* SDHCI_RESET_DATA */
+	}
+
+	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+	return ret;
+}
+
+static int rk_sdhci_probe(struct device_d *dev)
+{
+	struct rk_sdhci_host *host;
+	struct resource *iores;
+	struct mci_host *mci;
+	int ret;
+
+	host = xzalloc(sizeof(*host));
+
+	mci = &host->mci;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	host->sdhci.base = IOMEM(iores->start);
+	host->sdhci.mci = mci;
+	mci->send_cmd = rk_sdhci_send_cmd;
+	mci->set_ios = rk_sdhci_set_ios;
+	mci->init = rk_sdhci_init;
+	mci->card_present = rk_sdhci_card_present;
+	mci->hw_dev = dev;
+
+	host->clks[CLK_CORE].id = "core";
+	host->clks[CLK_BUS].id = "bus";
+	host->clks[CLK_AXI].id = "axi";
+	host->clks[CLK_BLOCK].id = "block";
+	host->clks[CLK_TIMER].id = "timer";
+
+	ret = clk_bulk_get(host->mci.hw_dev, CLK_MAX, host->clks);
+	if (ret) {
+		dev_err(host->mci.hw_dev, "failed to get clocks: %s\n",
+			strerror(-ret));
+		return ret;
+	}
+
+	ret = clk_bulk_enable(CLK_MAX, host->clks);
+	if (ret) {
+		dev_err(host->mci.hw_dev, "failed to enable clocks: %s\n",
+			strerror(-ret));
+		return ret;
+	}
+
+	host->sdhci.max_clk = clk_get_rate(host->clks[CLK_CORE].clk);
+
+	mci_of_parse(&host->mci);
+
+	sdhci_setup_host(&host->sdhci);
+
+	dev->priv = host;
+
+	return mci_register(&host->mci);
+}
+
+static __maybe_unused struct of_device_id rk_sdhci_compatible[] = {
+	{
+		.compatible = "rockchip,rk3568-dwcmshc"
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct driver_d rk_sdhci_driver = {
+	.name = "rk3568-dwcmshc-sdhci",
+	.probe = rk_sdhci_probe,
+	.of_compatible = DRV_OF_COMPAT(rk_sdhci_compatible),
+};
+device_platform_driver(rk_sdhci_driver);
-- 
2.29.2


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


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

* [PATCH 3/3] mci: imx-esdhc: Use common DMA helpers
  2021-06-10 14:47 [PATCH 0/3] MMC: SDHCI: Add and use common DMA helpers Sascha Hauer
  2021-06-10 14:47 ` [PATCH 1/3] mci: sdhci: Add DMA transfer helpers Sascha Hauer
  2021-06-10 14:47 ` [PATCH 2/3] mci: Add support for Rockchip variant of the dwcmshc Sascha Hauer
@ 2021-06-10 14:47 ` Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2021-06-10 14:47 UTC (permalink / raw)
  To: Barebox List

Convert the driver to use the new common SDHCI DMA helpers.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/imx-esdhc-common.c | 88 ++++++++++------------------------
 1 file changed, 24 insertions(+), 64 deletions(-)

diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index a85459d29c..a0290275be 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -10,12 +10,6 @@
 
 #define PRSSTAT_DAT0  0x01000000
 
-struct fsl_esdhc_dma_transfer {
-	dma_addr_t dma;
-	unsigned int size;
-	enum dma_data_direction dir;
-};
-
 static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
 {
 	struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
@@ -58,71 +52,33 @@ static bool esdhc_use_pio_mode(void)
 {
 	return IN_PBL || IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO);
 }
+
 static int esdhc_setup_data(struct fsl_esdhc_host *host, struct mci_data *data,
-			    struct fsl_esdhc_dma_transfer *tr)
+			    dma_addr_t *dma)
 {
 	u32 wml_value;
-	void *ptr;
-
-	if (!esdhc_use_pio_mode()) {
-		wml_value = data->blocksize/4;
-
-		if (data->flags & MMC_DATA_READ) {
-			if (wml_value > 0x10)
-				wml_value = 0x10;
-
-			esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value);
-		} else {
-			if (wml_value > 0x80)
-				wml_value = 0x80;
 
-			esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK,
-						wml_value << 16);
-		}
-
-		tr->size = data->blocks * data->blocksize;
+	wml_value = data->blocksize / 4;
 
-		if (data->flags & MMC_DATA_WRITE) {
-			ptr = (void *)data->src;
-			tr->dir = DMA_TO_DEVICE;
-		} else {
-			ptr = data->dest;
-			tr->dir = DMA_FROM_DEVICE;
-		}
+	if (data->flags & MMC_DATA_READ) {
+		if (wml_value > 0x10)
+			wml_value = 0x10;
 
-		tr->dma = dma_map_single(host->dev, ptr, tr->size, tr->dir);
-		if (dma_mapping_error(host->dev, tr->dma))
-			return -EFAULT;
+		esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value);
+	} else {
+		if (wml_value > 0x80)
+			wml_value = 0x80;
 
-
-		sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, tr->dma);
+		esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK,
+					wml_value << 16);
 	}
 
-	sdhci_write32(&host->sdhci, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | data->blocksize);
-
-	return 0;
-}
-
-static int esdhc_do_data(struct fsl_esdhc_host *host, struct mci_data *data,
-		  struct fsl_esdhc_dma_transfer *tr)
-{
-	u32 irqstat;
+	host->sdhci.sdma_boundary = 0;
 
 	if (esdhc_use_pio_mode())
-		return sdhci_transfer_data_pio(&host->sdhci, data);
-
-	do {
-		irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
-
-		if (irqstat & DATA_ERR)
-			return -EIO;
-
-		if (irqstat & SDHCI_INT_DATA_TIMEOUT)
-			return -ETIMEDOUT;
-	} while (!(irqstat & SDHCI_INT_XFER_COMPLETE) &&
-		(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_DATA_LINE_ACTIVE));
-
-	dma_unmap_single(host->dev, tr->dma, tr->size, tr->dir);
+		sdhci_setup_data_pio(&host->sdhci, data);
+	else
+		sdhci_setup_data_dma(&host->sdhci, data, dma);
 
 	return 0;
 }
@@ -172,7 +128,7 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
 {
 	u32	xfertyp, mixctrl, command;
 	u32	irqstat;
-	struct fsl_esdhc_dma_transfer tr = { 0 };
+	dma_addr_t dma = SDHCI_NO_DMA;
 	int ret;
 
 	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, -1);
@@ -182,13 +138,13 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
 
 	/* Set up for a data transfer if we have one */
 	if (data) {
-		ret = esdhc_setup_data(host, data, &tr);
+		ret = esdhc_setup_data(host, data, &dma);
 		if (ret)
 			return ret;
 	}
 
 	sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data,
-				!esdhc_use_pio_mode(), &command, &xfertyp);
+				dma != SDHCI_NO_DMA, &command, &xfertyp);
 
 	if ((host->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) &&
 	    (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION))
@@ -245,7 +201,11 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
 
 	/* Wait until all of the blocks are transferred */
 	if (data) {
-		ret = esdhc_do_data(host, data, &tr);
+		if (esdhc_use_pio_mode())
+			ret = sdhci_transfer_data_pio(&host->sdhci, data);
+		else
+			ret = sdhci_transfer_data_dma(&host->sdhci, data, dma);
+
 		if (ret)
 			return ret;
 	}
-- 
2.29.2


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


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

end of thread, other threads:[~2021-06-10 14:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-10 14:47 [PATCH 0/3] MMC: SDHCI: Add and use common DMA helpers Sascha Hauer
2021-06-10 14:47 ` [PATCH 1/3] mci: sdhci: Add DMA transfer helpers Sascha Hauer
2021-06-10 14:47 ` [PATCH 2/3] mci: Add support for Rockchip variant of the dwcmshc Sascha Hauer
2021-06-10 14:47 ` [PATCH 3/3] mci: imx-esdhc: Use common DMA helpers Sascha Hauer

mail archive of the barebox mailing list

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://lore.barebox.org/barebox/0 barebox/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 barebox barebox/ https://lore.barebox.org/barebox \
		barebox@lists.infradead.org barebox@lists.infradead.org
	public-inbox-index barebox

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git