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

View File

@ -6,6 +6,7 @@
obj-y += mmc.o
obj-$(CONFIG_$(SPL_)DM_MMC) += mmc-uclass.o
obj-$(CONFIG_$(SPL_)MMC_WRITE) += mmc_write.o
obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o
ifndef CONFIG_$(SPL_)BLK
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))
static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
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) {
sdhci_writel(host, phys_to_bus((ulong)host->start_addr),
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_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_ADMA_ADDRESS_HI);
}
#endif
}
#else
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__);
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;
#ifdef CONFIG_DMA_ADDR_T_64BIT
host->flags |= USE_ADMA64;
#else

View File

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