diff options
author | Tom Rini <trini@konsulko.com> | 2024-04-26 07:39:18 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-04-26 07:39:18 -0600 |
commit | 174ac987655c888017c82df1883c0c2ea0dc2495 (patch) | |
tree | ab6377136e11b9a43bb70e9e2f54c939bbb3d241 | |
parent | 689f52491d4722bd70eda3256c6e75654ecf00ed (diff) | |
parent | 1776213dadef4b578f98bcf18beb152f8975a8bf (diff) | |
download | u-boot-WIP/26Apr2024.zip u-boot-WIP/26Apr2024.tar.gz u-boot-WIP/26Apr2024.tar.bz2 |
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-mmcWIP/26Apr2024
-rw-r--r-- | drivers/mmc/Kconfig | 18 | ||||
-rw-r--r-- | drivers/mmc/arm_pl180_mmci.c | 10 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc.c | 2 | ||||
-rw-r--r-- | drivers/mmc/mmc-uclass.c | 7 | ||||
-rw-r--r-- | drivers/mmc/sdhci-adma.c | 43 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 26 | ||||
-rw-r--r-- | include/sdhci.h | 21 |
7 files changed, 96 insertions, 31 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 06e32e7..5496348 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -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 diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 2666b65..cecc7ad 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -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); @@ -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; @@ -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) diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index d44dfa5..595d88b 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -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); diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 1e03901..24170c5 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -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; diff --git a/drivers/mmc/sdhci-adma.c b/drivers/mmc/sdhci-adma.c index 8213223..283ba95 100644 --- a/drivers/mmc/sdhci-adma.c +++ b/drivers/mmc/sdhci-adma.c @@ -9,9 +9,10 @@ #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; @@ -19,17 +20,30 @@ static void sdhci_adma_desc(struct sdhci_adma_desc *desc, 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 @@ -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)); } diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 0178ed8..af654ea 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -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), @@ -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 = @@ -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) { diff --git a/include/sdhci.h b/include/sdhci.h index a1b74e3..78ef0d1 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -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> @@ -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) @@ -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; @@ -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 */ |