*/
#include <common.h>
+#include <cpu_func.h>
#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <mmc.h>
#include <sdhci.h>
#include <dm.h>
-
-#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
-void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER;
-#else
-void *aligned_buffer;
-#endif
+#include <linux/dma-mapping.h>
static void sdhci_reset(struct sdhci_host *host, u8 mask)
{
}
#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
-static void sdhci_adma_desc(struct sdhci_host *host, char *buf, u16 len,
- bool end)
+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->attr = attr;
desc->len = len;
desc->reserved = 0;
- desc->addr_lo = (dma_addr_t)buf;
+ desc->addr_lo = lower_32_bits(dma_addr);
#ifdef CONFIG_DMA_ADDR_T_64BIT
- desc->addr_hi = (u64)buf >> 32;
+ desc->addr_hi = upper_32_bits(dma_addr);
#endif
}
uint trans_bytes = data->blocksize * data->blocks;
uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN);
int i = desc_count;
- char *buf;
+ dma_addr_t dma_addr = host->start_addr;
host->desc_slot = 0;
- if (data->flags & MMC_DATA_READ)
- buf = data->dest;
- else
- buf = (char *)data->src;
-
while (--i) {
- sdhci_adma_desc(host, buf, ADMA_MAX_LEN, false);
- buf += ADMA_MAX_LEN;
+ sdhci_adma_desc(host, dma_addr, ADMA_MAX_LEN, false);
+ dma_addr += ADMA_MAX_LEN;
trans_bytes -= ADMA_MAX_LEN;
}
- sdhci_adma_desc(host, buf, trans_bytes, true);
+ 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),
int *is_aligned, int trans_bytes)
{
unsigned char ctrl;
+ void *buf;
if (data->flags == MMC_DATA_READ)
- host->start_addr = (dma_addr_t)data->dest;
+ buf = data->dest;
else
- host->start_addr = (dma_addr_t)data->src;
+ buf = (void *)data->src;
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
ctrl |= SDHCI_CTRL_ADMA32;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- if (host->flags & USE_SDMA) {
- if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
- (host->start_addr & 0x7) != 0x0) {
- *is_aligned = 0;
- host->start_addr = (unsigned long)aligned_buffer;
- if (data->flags != MMC_DATA_READ)
- memcpy(aligned_buffer, data->src, trans_bytes);
- }
-
-#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
- /*
- * Always use this bounce-buffer when
- * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined
- */
+ if (host->flags & USE_SDMA &&
+ (host->force_align_buffer ||
+ (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR &&
+ ((unsigned long)buf & 0x7) != 0x0))) {
*is_aligned = 0;
- host->start_addr = (unsigned long)aligned_buffer;
if (data->flags != MMC_DATA_READ)
- memcpy(aligned_buffer, data->src, trans_bytes);
-#endif
- sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS);
+ memcpy(host->align_buffer, buf, trans_bytes);
+ buf = host->align_buffer;
+ }
+
+ host->start_addr = dma_map_single(buf, trans_bytes,
+ mmc_get_dma_dir(data));
+ if (host->flags & USE_SDMA) {
+ sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS);
} else if (host->flags & (USE_ADMA | USE_ADMA64)) {
sdhci_prepare_adma_table(host, data);
- sdhci_writel(host, (u32)host->adma_addr, SDHCI_ADMA_ADDRESS);
+ sdhci_writel(host, lower_32_bits(host->adma_addr),
+ SDHCI_ADMA_ADDRESS);
if (host->flags & USE_ADMA64)
- sdhci_writel(host, (u64)host->adma_addr >> 32,
+ sdhci_writel(host, upper_32_bits(host->adma_addr),
SDHCI_ADMA_ADDRESS_HI);
}
-
- flush_cache(host->start_addr, ROUND(trans_bytes, ARCH_DMA_MINALIGN));
}
#else
static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
return -ETIMEDOUT;
}
} while (!(stat & SDHCI_INT_DATA_END));
+
+ dma_unmap_single(host->start_addr, data->blocks * data->blocksize,
+ mmc_get_dma_dir(data));
+
return 0;
}
if (!ret) {
if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
!is_aligned && (data->flags == MMC_DATA_READ))
- memcpy(data->dest, aligned_buffer, trans_bytes);
+ memcpy(data->dest, host->align_buffer, trans_bytes);
return 0;
}
void sdhci_set_uhs_timing(struct sdhci_host *host)
{
- struct mmc *mmc = (struct mmc *)host->mmc;
+ struct mmc *mmc = host->mmc;
u32 reg;
reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
sdhci_reset(host, SDHCI_RESET_ALL);
- if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) {
- aligned_buffer = memalign(8, 512*1024);
- if (!aligned_buffer) {
+#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
+ host->align_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER;
+ /*
+ * Always use this bounce-buffer when CONFIG_FIXED_SDHCI_ALIGNED_BUFFER
+ * is defined.
+ */
+ host->force_align_buffer = true;
+#else
+ if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) {
+ host->align_buffer = memalign(8, 512 * 1024);
+ if (!host->align_buffer) {
printf("%s: Aligned buffer alloc failed!!!\n",
__func__);
return -ENOMEM;
}
}
+#endif
sdhci_set_power(host, fls(mmc->cfg->voltages) - 1);
return sdhci_init(mmc);
}
+static int sdhci_deferred_probe(struct udevice *dev)
+{
+ int err;
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+ struct sdhci_host *host = mmc->priv;
+
+ if (host->ops && host->ops->deferred_probe) {
+ err = host->ops->deferred_probe(host);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
static int sdhci_get_cd(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
.send_cmd = sdhci_send_command,
.set_ios = sdhci_set_ios,
.get_cd = sdhci_get_cd,
+ .deferred_probe = sdhci_deferred_probe,
#ifdef MMC_SUPPORTS_TUNING
.execute_tuning = sdhci_execute_tuning,
#endif
__func__);
return -EINVAL;
}
- host->adma_desc_table = (struct sdhci_adma_desc *)
- memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ);
+ host->adma_desc_table = memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ);
host->adma_addr = (dma_addr_t)host->adma_desc_table;
#ifdef CONFIG_DMA_ADDR_T_64BIT
cfg->host_caps &= ~MMC_MODE_HS_52MHz;
}
- if (!(cfg->voltages & MMC_VDD_165_195) ||
- (host->quirks & SDHCI_QUIRK_NO_1_8_V))
+ if (!(cfg->voltages & MMC_VDD_165_195))
caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);