[U-Boot] [PATCH 5/9] mmc: dw_mmc: add support for 64bit DMA
Marek Szyprowski
m.szyprowski at samsung.com
Wed Nov 7 15:03:08 UTC 2018
From: Lukasz Majewski <l.majewski at samsung.com>
DW-MMC module in Samsung Exynos5433 requires 64bit DMA descriptors. This
patch adds code for handling them.
Signed-off-by: Lukasz Majewski <l.majewski at samsung.com>
[extracted from old sources and adapted to mainline u-boot, minor fixes]
Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
---
drivers/mmc/dw_mmc.c | 53 ++++++++++++++++++++++++++++++-------
drivers/mmc/exynos_dw_mmc.c | 6 +++++
include/dwmmc.h | 25 +++++++++++++++++
3 files changed, 74 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 3c702b3ed8..f50eb29ac9 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -30,8 +30,8 @@ static int dwmci_wait_reset(struct dwmci_host *host, u32 value)
return 0;
}
-static void dwmci_set_idma_desc(struct dwmci_idmac *idmac,
- u32 desc0, u32 desc1, u32 desc2)
+static void dwmci_set_idma_desc_32bit(void *idmac,
+ u32 desc0, u32 desc1, u32 desc2)
{
struct dwmci_idmac *desc = idmac;
@@ -41,11 +41,27 @@ static void dwmci_set_idma_desc(struct dwmci_idmac *idmac,
desc->next_addr = (ulong)desc + sizeof(struct dwmci_idmac);
}
+static void dwmci_set_idma_desc_64bit(void *idmac,
+ u32 desc0, u32 desc1, u32 desc2)
+{
+ struct dwmci_idmac_64addr *desc = idmac;
+
+ desc->flags = desc0;
+ desc->_res1 = 0;
+ desc->cnt = desc1;
+ desc->_res2 = 0;
+ desc->addrl = desc2;
+ desc->addrh = 0;
+ desc->next_addrl = (ulong)desc + sizeof(struct dwmci_idmac_64addr);
+ desc->next_addrh = 0;
+}
+
static void dwmci_prepare_data(struct dwmci_host *host,
struct mmc_data *data,
- struct dwmci_idmac *cur_idmac,
+ struct dwmci_idmac_64addr *cur_idmac64,
void *bounce_buffer)
{
+ struct dwmci_idmac *cur_idmac = (struct dwmci_idmac *)cur_idmac64;
unsigned long ctrl;
unsigned int i = 0, flags, cnt, blk_cnt;
ulong data_start, data_end;
@@ -56,7 +72,12 @@ static void dwmci_prepare_data(struct dwmci_host *host,
dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
data_start = (ulong)cur_idmac;
- dwmci_writel(host, DWMCI_DBADDR, (ulong)cur_idmac);
+
+ if (host->dma_64bit_address) {
+ dwmci_writel(host, DWMCI_DBADDRU, 0);
+ dwmci_writel(host, DWMCI_DBADDRL, (ulong)cur_idmac64);
+ } else
+ dwmci_writel(host, DWMCI_DBADDR, (ulong)cur_idmac);
do {
flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ;
@@ -67,17 +88,27 @@ static void dwmci_prepare_data(struct dwmci_host *host,
} else
cnt = data->blocksize * 8;
- dwmci_set_idma_desc(cur_idmac, flags, cnt,
- (ulong)bounce_buffer + (i * PAGE_SIZE));
+ if (host->dma_64bit_address)
+ dwmci_set_idma_desc_64bit(cur_idmac64, flags, cnt,
+ (ulong)bounce_buffer +
+ (i * PAGE_SIZE));
+ else
+ dwmci_set_idma_desc_32bit(cur_idmac, flags, cnt,
+ (ulong)bounce_buffer +
+ (i * PAGE_SIZE));
if (blk_cnt <= 8)
break;
blk_cnt -= 8;
cur_idmac++;
+ cur_idmac64++;
i++;
} while(1);
- data_end = (ulong)cur_idmac;
+ if (host->dma_64bit_address)
+ data_end = (ulong)cur_idmac64;
+ else
+ data_end = (ulong)cur_idmac;
flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN);
ctrl = dwmci_readl(host, DWMCI_CTRL);
@@ -222,7 +253,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
{
#endif
struct dwmci_host *host = mmc->priv;
- ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac,
+ ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac_64addr, cur_idmac64,
data ? DIV_ROUND_UP(data->blocks, 8) : 0);
int ret = 0, flags = 0, i;
unsigned int timeout = 500;
@@ -256,7 +287,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
data->blocksize *
data->blocks, GEN_BB_READ);
}
- dwmci_prepare_data(host, data, cur_idmac,
+ dwmci_prepare_data(host, data, cur_idmac64,
bbstate.bounce_buffer);
}
}
@@ -474,7 +505,9 @@ static int dwmci_init(struct mmc *mmc)
dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF);
- dwmci_writel(host, DWMCI_IDINTEN, 0);
+ dwmci_writel(host, host->dma_64bit_address ?
+ DWMCI_IDINTEN64 : DWMCI_IDINTEN, 0);
+
dwmci_writel(host, DWMCI_BMOD, 1);
if (!host->fifoth_val) {
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 435ccac594..3e9d47538c 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -98,6 +98,7 @@ static void exynos_dwmci_board_init(struct dwmci_host *host)
static int exynos_dwmci_core_init(struct dwmci_host *host)
{
+ unsigned int addr_config;
unsigned int div;
unsigned long freq, sclk;
@@ -122,6 +123,11 @@ static int exynos_dwmci_core_init(struct dwmci_host *host)
host->clksel = exynos_dwmci_clksel;
host->get_mmc_clk = exynos_dwmci_get_clk;
+ addr_config = DWMCI_GET_ADDR_CONFIG(dwmci_readl(host, DWMCI_HCON));
+ if (addr_config == 1)
+ /* host supports IDMAC in 64-bit address mode */
+ host->dma_64bit_address = 1;
+
#ifndef CONFIG_DM_MMC
/* Add the mmc channel to be registered with mmc core */
if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) {
diff --git a/include/dwmmc.h b/include/dwmmc.h
index 0f9d51b557..14db03d7d4 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -48,6 +48,17 @@
#define DWMCI_DSCADDR 0x094
#define DWMCI_BUFADDR 0x098
#define DWMCI_DATA 0x200
+/*
+ * Registers to support idmac 64-bit address mode
+ */
+#define DWMCI_DBADDRL 0x088
+#define DWMCI_DBADDRU 0x08c
+#define DWMCI_IDSTS64 0x090
+#define DWMCI_IDINTEN64 0x094
+#define DWMCI_DSCADDRL 0x098
+#define DWMCI_DSCADDRU 0x09c
+#define DWMCI_BUFADDRL 0x0A0
+#define DWMCI_BUFADDRU 0x0A4
/* Interrupt Mask register */
#define DWMCI_INTMSK_ALL 0xffffffff
@@ -132,6 +143,7 @@
/* quirks */
#define DWMCI_QUIRK_DISABLE_SMU (1 << 0)
+#define DWMCI_GET_ADDR_CONFIG(x) (((x)>>27) & 0x1)
/**
* struct dwmci_host - Information about a designware MMC host
*
@@ -145,6 +157,7 @@
* @dev_id: Arbitrary device ID for use by controller
* @buswidth: Bus width in bits (8 or 4)
* @fifoth_val: Value for FIFOTH register (or 0 to leave unset)
+ * @dma_64bit_address: True only for devices supporting 64 bit DMA
* @mmc: Pointer to generic MMC structure for this device
* @priv: Private pointer for use by controller
*/
@@ -161,6 +174,7 @@ struct dwmci_host {
int dev_id;
int buswidth;
u32 fifoth_val;
+ int dma_64bit_address;
struct mmc *mmc;
void *priv;
@@ -196,6 +210,17 @@ struct dwmci_idmac {
u32 next_addr;
} __aligned(ARCH_DMA_MINALIGN);
+struct dwmci_idmac_64addr {
+ u32 flags;
+ u32 _res1;
+ u32 cnt;
+ u32 _res2;
+ u32 addrl;
+ u32 addrh;
+ u32 next_addrl;
+ u32 next_addrh;
+} __aligned(ARCH_DMA_MINALIGN);
+
static inline void dwmci_writel(struct dwmci_host *host, int reg, u32 val)
{
writel(val, host->ioaddr + reg);
--
2.17.1
More information about the U-Boot
mailing list