mmc: sdhci: move the ADMA2 table handling into own module

There are other (non-SDHCI) controllers which supports ADMA2 descriptor
tables, namely the Freescale eSDHC. Instead of copying the code, move it
into an own module.

Signed-off-by: Michael Walle <michael@walle.cc>
This commit is contained in:
Michael Walle 2020-09-23 12:42:51 +02:00 committed by Peng Fan
parent 7e48a028a4
commit 4d6a773b1c
5 changed files with 92 additions and 58 deletions

View File

@ -46,6 +46,9 @@ config SPL_DM_MMC
if MMC if MMC
config MMC_SDHCI_ADMA_HELPERS
bool
config MMC_SPI config MMC_SPI
bool "Support for SPI-based MMC controller" bool "Support for SPI-based MMC controller"
depends on DM_MMC && DM_SPI depends on DM_MMC && DM_SPI
@ -445,6 +448,7 @@ config MMC_SDHCI_SDMA
config MMC_SDHCI_ADMA config MMC_SDHCI_ADMA
bool "Support SDHCI ADMA2" bool "Support SDHCI ADMA2"
depends on MMC_SDHCI depends on MMC_SDHCI
select MMC_SDHCI_ADMA_HELPERS
help help
This enables support for the ADMA (Advanced DMA) defined This enables support for the ADMA (Advanced DMA) defined
in the SD Host Controller Standard Specification Version 3.00 in the SD Host Controller Standard Specification Version 3.00
@ -452,6 +456,7 @@ config MMC_SDHCI_ADMA
config SPL_MMC_SDHCI_ADMA config SPL_MMC_SDHCI_ADMA
bool "Support SDHCI ADMA2 in SPL" bool "Support SDHCI ADMA2 in SPL"
depends on MMC_SDHCI depends on MMC_SDHCI
select MMC_SDHCI_ADMA_HELPERS
help help
This enables support for the ADMA (Advanced DMA) defined This enables support for the ADMA (Advanced DMA) defined
in the SD Host Controller Standard Specification Version 3.00 in SPL. in the SD Host Controller Standard Specification Version 3.00 in SPL.

View File

@ -6,6 +6,7 @@
obj-y += mmc.o obj-y += mmc.o
obj-$(CONFIG_$(SPL_)DM_MMC) += mmc-uclass.o obj-$(CONFIG_$(SPL_)DM_MMC) += mmc-uclass.o
obj-$(CONFIG_$(SPL_)MMC_WRITE) += mmc_write.o obj-$(CONFIG_$(SPL_)MMC_WRITE) += mmc_write.o
obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o
ifndef CONFIG_$(SPL_)BLK ifndef CONFIG_$(SPL_)BLK
obj-y += mmc_legacy.o obj-y += mmc_legacy.o

73
drivers/mmc/sdhci-adma.c Normal file
View File

@ -0,0 +1,73 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* SDHCI ADMA2 helper functions.
*/
#include <common.h>
#include <cpu_func.h>
#include <sdhci.h>
#include <malloc.h>
#include <asm/cache.h>
static void sdhci_adma_desc(struct sdhci_adma_desc *desc,
dma_addr_t addr, u16 len, bool end)
{
u8 attr;
attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
if (end)
attr |= ADMA_DESC_ATTR_END;
desc->attr = attr;
desc->len = len;
desc->reserved = 0;
desc->addr_lo = lower_32_bits(addr);
#ifdef CONFIG_DMA_ADDR_T_64BIT
desc->addr_hi = upper_32_bits(addr);
#endif
}
/**
* sdhci_prepare_adma_table() - Populate the ADMA table
*
* @table: Pointer to the ADMA table
* @data: Pointer to MMC data
* @addr: DMA address to write to or read from
*
* Fill the ADMA table according to the MMC data to read from or write to the
* given DMA address.
* Please note, that the table size depends on CONFIG_SYS_MMC_MAX_BLK_COUNT and
* we don't have to check for overflow.
*/
void sdhci_prepare_adma_table(struct sdhci_adma_desc *table,
struct mmc_data *data, dma_addr_t addr)
{
uint trans_bytes = data->blocksize * data->blocks;
uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN);
struct sdhci_adma_desc *desc = table;
int i = desc_count;
while (--i) {
sdhci_adma_desc(desc, addr, ADMA_MAX_LEN, false);
addr += ADMA_MAX_LEN;
trans_bytes -= ADMA_MAX_LEN;
desc++;
}
sdhci_adma_desc(desc, addr, trans_bytes, true);
flush_cache((dma_addr_t)table,
ROUND(desc_count * sizeof(struct sdhci_adma_desc),
ARCH_DMA_MINALIGN));
}
/**
* sdhci_adma_init() - initialize the ADMA descriptor table
*
* @return pointer to the allocated descriptor table or NULL in case of an
* error.
*/
struct sdhci_adma_desc *sdhci_adma_init(void)
{
return memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ);
}

View File

@ -69,57 +69,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
} }
} }
#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
static void sdhci_adma_desc(struct sdhci_host *host, dma_addr_t dma_addr,
u16 len, bool end)
{
struct sdhci_adma_desc *desc;
u8 attr;
desc = &host->adma_desc_table[host->desc_slot];
attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
if (!end)
host->desc_slot++;
else
attr |= ADMA_DESC_ATTR_END;
desc->attr = attr;
desc->len = len;
desc->reserved = 0;
desc->addr_lo = lower_32_bits(dma_addr);
#ifdef CONFIG_DMA_ADDR_T_64BIT
desc->addr_hi = upper_32_bits(dma_addr);
#endif
}
static void sdhci_prepare_adma_table(struct sdhci_host *host,
struct mmc_data *data)
{
uint trans_bytes = data->blocksize * data->blocks;
uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN);
int i = desc_count;
dma_addr_t dma_addr = host->start_addr;
host->desc_slot = 0;
while (--i) {
sdhci_adma_desc(host, dma_addr, ADMA_MAX_LEN, false);
dma_addr += ADMA_MAX_LEN;
trans_bytes -= ADMA_MAX_LEN;
}
sdhci_adma_desc(host, dma_addr, trans_bytes, true);
flush_cache((dma_addr_t)host->adma_desc_table,
ROUND(desc_count * sizeof(struct sdhci_adma_desc),
ARCH_DMA_MINALIGN));
}
#elif defined(CONFIG_MMC_SDHCI_SDMA)
static void sdhci_prepare_adma_table(struct sdhci_host *host,
struct mmc_data *data)
{}
#endif
#if (defined(CONFIG_MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)) #if (defined(CONFIG_MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA))
static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
int *is_aligned, int trans_bytes) int *is_aligned, int trans_bytes)
@ -156,8 +105,11 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
if (host->flags & USE_SDMA) { if (host->flags & USE_SDMA) {
sdhci_writel(host, phys_to_bus((ulong)host->start_addr), sdhci_writel(host, phys_to_bus((ulong)host->start_addr),
SDHCI_DMA_ADDRESS); SDHCI_DMA_ADDRESS);
} else if (host->flags & (USE_ADMA | USE_ADMA64)) { }
sdhci_prepare_adma_table(host, data); #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
else if (host->flags & (USE_ADMA | USE_ADMA64)) {
sdhci_prepare_adma_table(host->adma_desc_table, data,
host->start_addr);
sdhci_writel(host, lower_32_bits(host->adma_addr), sdhci_writel(host, lower_32_bits(host->adma_addr),
SDHCI_ADMA_ADDRESS); SDHCI_ADMA_ADDRESS);
@ -165,6 +117,7 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
sdhci_writel(host, upper_32_bits(host->adma_addr), sdhci_writel(host, upper_32_bits(host->adma_addr),
SDHCI_ADMA_ADDRESS_HI); SDHCI_ADMA_ADDRESS_HI);
} }
#endif
} }
#else #else
static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
@ -770,9 +723,9 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
__func__); __func__);
return -EINVAL; return -EINVAL;
} }
host->adma_desc_table = memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); host->adma_desc_table = sdhci_adma_init();
host->adma_addr = (dma_addr_t)host->adma_desc_table; host->adma_addr = (dma_addr_t)host->adma_desc_table;
#ifdef CONFIG_DMA_ADDR_T_64BIT #ifdef CONFIG_DMA_ADDR_T_64BIT
host->flags |= USE_ADMA64; host->flags |= USE_ADMA64;
#else #else

View File

@ -271,7 +271,6 @@ struct sdhci_ops {
int (*deferred_probe)(struct sdhci_host *host); int (*deferred_probe)(struct sdhci_host *host);
}; };
#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
#define ADMA_MAX_LEN 65532 #define ADMA_MAX_LEN 65532
#ifdef CONFIG_DMA_ADDR_T_64BIT #ifdef CONFIG_DMA_ADDR_T_64BIT
#define ADMA_DESC_LEN 16 #define ADMA_DESC_LEN 16
@ -302,7 +301,7 @@ struct sdhci_adma_desc {
u32 addr_hi; u32 addr_hi;
#endif #endif
} __packed; } __packed;
#endif
struct sdhci_host { struct sdhci_host {
const char *name; const char *name;
void *ioaddr; void *ioaddr;
@ -334,7 +333,6 @@ struct sdhci_host {
dma_addr_t adma_addr; dma_addr_t adma_addr;
#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
struct sdhci_adma_desc *adma_desc_table; struct sdhci_adma_desc *adma_desc_table;
uint desc_slot;
#endif #endif
}; };
@ -496,4 +494,8 @@ extern const struct dm_mmc_ops sdhci_ops;
#else #else
#endif #endif
struct sdhci_adma_desc *sdhci_adma_init(void);
void sdhci_prepare_adma_table(struct sdhci_adma_desc *table,
struct mmc_data *data, dma_addr_t addr);
#endif /* __SDHCI_HW_H */ #endif /* __SDHCI_HW_H */