*/
#include <common.h>
+#include <cpu_func.h>
#include <dm.h>
#include <errno.h>
+#include <log.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 <asm/cache.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <phys2bus.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, phys_to_bus((ulong)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,
start_addr &=
~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
- sdhci_writel(host, start_addr,
+ sdhci_writel(host, phys_to_bus((ulong)start_addr),
SDHCI_DMA_ADDRESS);
}
}
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);
#endif
u32 ctrl;
struct sdhci_host *host = mmc->priv;
+ bool no_hispd_bit = false;
if (host->ops && host->ops->set_control_reg)
host->ops->set_control_reg(host);
ctrl &= ~SDHCI_CTRL_4BITBUS;
}
- if (mmc->clock > 26000000)
- ctrl |= SDHCI_CTRL_HISPD;
- else
- ctrl &= ~SDHCI_CTRL_HISPD;
-
if ((host->quirks & SDHCI_QUIRK_NO_HISPD_BIT) ||
- (host->quirks & SDHCI_QUIRK_BROKEN_HISPD_MODE))
+ (host->quirks & SDHCI_QUIRK_BROKEN_HISPD_MODE)) {
ctrl &= ~SDHCI_CTRL_HISPD;
+ no_hispd_bit = true;
+ }
+
+ if (!no_hispd_bit) {
+ if (mmc->selected_mode == MMC_HS ||
+ mmc->selected_mode == SD_HS ||
+ mmc->selected_mode == MMC_DDR_52 ||
+ mmc->selected_mode == MMC_HS_200 ||
+ mmc->selected_mode == MMC_HS_400 ||
+ mmc->selected_mode == UHS_SDR25 ||
+ mmc->selected_mode == UHS_SDR50 ||
+ mmc->selected_mode == UHS_SDR104 ||
+ mmc->selected_mode == UHS_DDR50)
+ ctrl |= SDHCI_CTRL_HISPD;
+ else
+ ctrl &= ~SDHCI_CTRL_HISPD;
+ }
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
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);
}
-int sdhci_get_cd(struct udevice *dev)
+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);
struct sdhci_host *host = mmc->priv;
.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
"sdhci-caps-mask", 0);
dt_caps = dev_read_u64_default(host->mmc->dev,
"sdhci-caps", 0);
- caps = ~(u32)dt_caps_mask &
+ caps = ~lower_32_bits(dt_caps_mask) &
sdhci_readl(host, SDHCI_CAPABILITIES);
- caps |= (u32)dt_caps;
+ caps |= lower_32_bits(dt_caps);
#else
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
#endif
debug("%s, caps: 0x%x\n", __func__, caps);
#ifdef CONFIG_MMC_SDHCI_SDMA
- if (!(caps & SDHCI_CAN_DO_SDMA)) {
- printf("%s: Your controller doesn't support SDMA!!\n",
- __func__);
- return -EINVAL;
+ if ((caps & SDHCI_CAN_DO_SDMA)) {
+ host->flags |= USE_SDMA;
+ } else {
+ debug("%s: Your controller doesn't support SDMA!!\n",
+ __func__);
}
-
- host->flags |= USE_SDMA;
#endif
#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
if (!(caps & SDHCI_CAN_DO_ADMA2)) {
__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
/* Check whether the clock multiplier is supported or not */
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
#if CONFIG_IS_ENABLED(DM_MMC)
- caps_1 = ~(u32)(dt_caps_mask >> 32) &
+ caps_1 = ~upper_32_bits(dt_caps_mask) &
sdhci_readl(host, SDHCI_CAPABILITIES_1);
- caps_1 |= (u32)(dt_caps >> 32);
+ caps_1 |= upper_32_bits(dt_caps);
#else
caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
#endif
if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
cfg->voltages |= host->voltages;
- cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
+ if (caps & SDHCI_CAN_DO_HISPD)
+ cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
+
+ cfg->host_caps |= MMC_MODE_4BIT;
/* Since Host Controller Version3.0 */
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
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);