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