Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
trini committed Apr 26, 2024
2 parents 689f524 + 1776213 commit 174ac98
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 31 deletions.
18 changes: 18 additions & 0 deletions drivers/mmc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,24 @@ config SPL_MMC_SDHCI_ADMA
This enables support for the ADMA (Advanced DMA) defined
in the SD Host Controller Standard Specification Version 3.00 in SPL.

config MMC_SDHCI_ADMA_FORCE_32BIT
bool "Force 32 bit mode for ADMA on 64 bit platforms"
help
This forces SDHCI ADMA to be built for 32 bit descriptors, even
on a 64 bit platform where they would otherwise be assumed to
be 64 bits. This is necessary for certain hardware platforms
that are 64-bit but include only 32-bit support within the selected
SD host controller IP.

config MMC_SDHCI_ADMA_64BIT
bool "Use SHDCI ADMA with 64 bit descriptors"
depends on !MMC_SDHCI_ADMA_FORCE_32BIT
default y if DMA_ADDR_T_64BIT
help
This selects 64 bit descriptors for SDHCI ADMA. It is enabled by
default on 64 bit systems, but can be disabled if one of these
systems includes 32-bit ADMA.

config FIXED_SDHCI_ALIGNED_BUFFER
hex "SDRAM address for fixed buffer"
depends on SPL && MVEBU_SPL_BOOT_DEVICE_MMC
Expand Down
10 changes: 10 additions & 0 deletions drivers/mmc/arm_pl180_mmci.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ static int do_data_transfer(struct mmc *dev,
u32 blksz = 0;
u32 data_ctrl = 0;
u32 data_len = (u32) (data->blocks * data->blocksize);
assert(data_len < U16_MAX); /* should be ensured by arm_pl180_get_b_max */

if (!host->version2) {
blksz = (ffs(data->blocksize) - 1);
Expand Down Expand Up @@ -356,6 +357,14 @@ static int host_set_ios(struct mmc *dev)
return 0;
}

static int arm_pl180_get_b_max(struct udevice *dev, void *dst, lbaint_t blkcnt)
{
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct mmc *mmc = upriv->mmc;

return U16_MAX / mmc->read_bl_len;
}

static void arm_pl180_mmc_init(struct pl180_mmc_host *host)
{
u32 sdi_u32;
Expand Down Expand Up @@ -470,6 +479,7 @@ static const struct dm_mmc_ops arm_pl180_dm_mmc_ops = {
.send_cmd = dm_host_request,
.set_ios = dm_host_set_ios,
.get_cd = dm_mmc_getcd,
.get_b_max = arm_pl180_get_b_max,
};

static int arm_pl180_mmc_of_to_plat(struct udevice *dev)
Expand Down
2 changes: 1 addition & 1 deletion drivers/mmc/fsl_esdhc.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ static void esdhc_setup_dma(struct fsl_esdhc_priv *priv, struct mmc_data *data)
priv->adma_desc_table) {
debug("Using ADMA2\n");
/* prefer ADMA2 if it is available */
sdhci_prepare_adma_table(priv->adma_desc_table, data,
sdhci_prepare_adma_table(NULL, priv->adma_desc_table, data,
priv->dma_addr);

adma_addr = virt_to_phys(priv->adma_desc_table);
Expand Down
7 changes: 5 additions & 2 deletions drivers/mmc/mmc-uclass.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,14 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
if (dev_read_bool(dev, "mmc-hs200-1_2v"))
cfg->host_caps |= MMC_CAP(MMC_HS_200);
if (dev_read_bool(dev, "mmc-hs400-1_8v"))
cfg->host_caps |= MMC_CAP(MMC_HS_400);
cfg->host_caps |= MMC_CAP(MMC_HS_400) | MMC_CAP(MMC_HS_200);
if (dev_read_bool(dev, "mmc-hs400-1_2v"))
cfg->host_caps |= MMC_CAP(MMC_HS_400);
cfg->host_caps |= MMC_CAP(MMC_HS_400) | MMC_CAP(MMC_HS_200);
if (dev_read_bool(dev, "mmc-hs400-enhanced-strobe"))
cfg->host_caps |= MMC_CAP(MMC_HS_400_ES);
if (dev_read_bool(dev, "no-mmc-hs400"))
cfg->host_caps &= ~(MMC_CAP(MMC_HS_400) |
MMC_CAP(MMC_HS_400_ES));

if (dev_read_bool(dev, "non-removable")) {
cfg->host_caps |= MMC_CAP_NONREMOVABLE;
Expand Down
43 changes: 29 additions & 14 deletions drivers/mmc/sdhci-adma.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,41 @@
#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)
void sdhci_adma_write_desc(struct sdhci_host *host, void **next_desc,
dma_addr_t addr, int len, bool end)
{
struct sdhci_adma_desc *desc = *next_desc;
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->len = len & 0xffff;
desc->reserved = 0;
desc->addr_lo = lower_32_bits(addr);
#ifdef CONFIG_DMA_ADDR_T_64BIT
#ifdef CONFIG_MMC_SDHCI_ADMA_64BIT
desc->addr_hi = upper_32_bits(addr);
#endif

*next_desc += ADMA_DESC_LEN;
}

static inline void __sdhci_adma_write_desc(struct sdhci_host *host,
void **desc, dma_addr_t addr,
int len, bool end)
{
if (host && host->ops && host->ops->adma_write_desc)
host->ops->adma_write_desc(host, desc, addr, len, end);
else
sdhci_adma_write_desc(host, desc, addr, len, end);
}

/**
* sdhci_prepare_adma_table() - Populate the ADMA table
*
* @host: Pointer to the sdhci_host
* @table: Pointer to the ADMA table
* @data: Pointer to MMC data
* @addr: DMA address to write to or read from
Expand All @@ -39,25 +53,26 @@ static void sdhci_adma_desc(struct sdhci_adma_desc *desc,
* 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)
void sdhci_prepare_adma_table(struct sdhci_host *host,
struct sdhci_adma_desc *table,
struct mmc_data *data, dma_addr_t start_addr)
{
dma_addr_t addr = start_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;
void *next_desc = table;
int i = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN);

while (--i) {
sdhci_adma_desc(desc, addr, ADMA_MAX_LEN, false);
__sdhci_adma_write_desc(host, &next_desc, addr,
ADMA_MAX_LEN, false);
addr += ADMA_MAX_LEN;
trans_bytes -= ADMA_MAX_LEN;
desc++;
}

sdhci_adma_desc(desc, addr, trans_bytes, true);
__sdhci_adma_write_desc(host, &next_desc, addr, trans_bytes, true);

flush_cache((dma_addr_t)table,
ROUND(desc_count * sizeof(struct sdhci_adma_desc),
flush_cache((phys_addr_t)table,
ROUND(next_desc - (void *)table,
ARCH_DMA_MINALIGN));
}

Expand Down
26 changes: 18 additions & 8 deletions drivers/mmc/sdhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *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,
sdhci_prepare_adma_table(host, host->adma_desc_table, data,
host->start_addr);

sdhci_writel(host, lower_32_bits(host->adma_addr),
Expand Down Expand Up @@ -897,14 +897,15 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
__func__);
return -EINVAL;
}
host->adma_desc_table = sdhci_adma_init();
host->adma_addr = (dma_addr_t)host->adma_desc_table;
if (!host->adma_desc_table) {
host->adma_desc_table = sdhci_adma_init();
host->adma_addr = virt_to_phys(host->adma_desc_table);
}

#ifdef CONFIG_DMA_ADDR_T_64BIT
host->flags |= USE_ADMA64;
#else
host->flags |= USE_ADMA;
#endif
if (IS_ENABLED(CONFIG_MMC_SDHCI_ADMA_64BIT))
host->flags |= USE_ADMA64;
else
host->flags |= USE_ADMA;
#endif
if (host->quirks & SDHCI_QUIRK_REG32_RW)
host->version =
Expand All @@ -929,6 +930,15 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
debug("%s, caps_1: 0x%x\n", __func__, caps_1);
host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
SDHCI_CLOCK_MUL_SHIFT;

/*
* In case the value in Clock Multiplier is 0, then programmable
* clock mode is not supported, otherwise the actual clock
* multiplier is one more than the value of Clock Multiplier
* in the Capabilities Register.
*/
if (host->clk_mul)
host->clk_mul += 1;
}

if (host->max_clk == 0) {
Expand Down
21 changes: 15 additions & 6 deletions include/sdhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <mmc.h>
#include <asm/gpio.h>
Expand Down Expand Up @@ -291,16 +292,21 @@ struct sdhci_ops {
* Return: 0 if successful, -ve on error
*/
int (*set_enhanced_strobe)(struct sdhci_host *host);

#ifdef CONFIG_MMC_SDHCI_ADMA_HELPERS
void (*adma_write_desc)(struct sdhci_host *host, void **desc,
dma_addr_t addr, int len, bool end);
#endif
};

#define ADMA_MAX_LEN 65532
#ifdef CONFIG_DMA_ADDR_T_64BIT
#ifdef CONFIG_MMC_SDHCI_ADMA_64BIT
#define ADMA_DESC_LEN 16
#else
#define ADMA_DESC_LEN 8
#endif
#define ADMA_TABLE_NO_ENTRIES (CONFIG_SYS_MMC_MAX_BLK_COUNT * \
MMC_MAX_BLOCK_LEN) / ADMA_MAX_LEN
#define ADMA_TABLE_NO_ENTRIES DIV_ROUND_UP(CONFIG_SYS_MMC_MAX_BLK_COUNT * \
MMC_MAX_BLOCK_LEN, ADMA_MAX_LEN)

#define ADMA_TABLE_SZ (ADMA_TABLE_NO_ENTRIES * ADMA_DESC_LEN)

Expand All @@ -319,7 +325,7 @@ struct sdhci_adma_desc {
u8 reserved;
u16 len;
u32 addr_lo;
#ifdef CONFIG_DMA_ADDR_T_64BIT
#ifdef CONFIG_MMC_SDHCI_ADMA_64BIT
u32 addr_hi;
#endif
} __packed;
Expand Down Expand Up @@ -526,8 +532,11 @@ extern const struct dm_mmc_ops sdhci_ops;
#else
#endif

void sdhci_adma_write_desc(struct sdhci_host *host, void **next_desc,
dma_addr_t addr, int len, bool end);
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);
void sdhci_prepare_adma_table(struct sdhci_host *host,
struct sdhci_adma_desc *table,
struct mmc_data *data, dma_addr_t start_addr);

#endif /* __SDHCI_HW_H */

0 comments on commit 174ac98

Please sign in to comment.