#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <sdhci.h>
DECLARE_GLOBAL_DATA_PTR;
char reserved1[8]; /* reserved */
uint fevt; /* Force event register */
uint admaes; /* ADMA error status register */
- uint adsaddr; /* ADMA system address register */
- char reserved2[160];
+ uint adsaddrl; /* ADMA system address low register */
+ uint adsaddrh; /* ADMA system address high register */
+ char reserved2[156];
uint hostver; /* Host controller version register */
char reserved3[4]; /* reserved */
uint dmaerraddr; /* DMA error address register */
struct mmc *mmc;
#endif
struct udevice *dev;
+ struct sdhci_adma_desc *adma_desc_table;
dma_addr_t dma_addr;
};
{
uint trans_bytes = data->blocksize * data->blocks;
struct fsl_esdhc *regs = priv->esdhc_regs;
+ phys_addr_t adma_addr;
void *buf;
if (data->flags & MMC_DATA_WRITE)
priv->dma_addr = dma_map_single(buf, trans_bytes,
mmc_get_dma_dir(data));
- if (upper_32_bits(priv->dma_addr))
- printf("Cannot use 64 bit addresses with SDMA\n");
- esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr));
+
+ if (IS_ENABLED(CONFIG_FSL_ESDHC_SUPPORT_ADMA2) &&
+ priv->adma_desc_table) {
+ debug("Using ADMA2\n");
+ /* prefer ADMA2 if it is available */
+ sdhci_prepare_adma_table(priv->adma_desc_table, data,
+ priv->dma_addr);
+
+ adma_addr = virt_to_phys(priv->adma_desc_table);
+ esdhc_write32(®s->adsaddrl, lower_32_bits(adma_addr));
+ if (IS_ENABLED(CONFIG_DMA_ADDR_T_64BIT))
+ esdhc_write32(®s->adsaddrh, upper_32_bits(adma_addr));
+ esdhc_clrsetbits32(®s->proctl, PROCTL_DMAS_MASK,
+ PROCTL_DMAS_ADMA2);
+ } else {
+ debug("Using SDMA\n");
+ if (upper_32_bits(priv->dma_addr))
+ printf("Cannot use 64 bit addresses with SDMA\n");
+ esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr));
+ esdhc_clrsetbits32(®s->proctl, PROCTL_DMAS_MASK,
+ PROCTL_DMAS_SDMA);
+ }
+
esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize);
}
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct fsl_esdhc_plat *plat = dev_get_platdata(dev);
struct fsl_esdhc_priv *priv = dev_get_priv(dev);
+ u32 caps, hostver;
fdt_addr_t addr;
struct mmc *mmc;
int ret;
#endif
priv->dev = dev;
+ if (IS_ENABLED(CONFIG_FSL_ESDHC_SUPPORT_ADMA2)) {
+ /*
+ * Only newer eSDHC controllers can do ADMA2 if the ADMA flag
+ * is set in the host capabilities register.
+ */
+ caps = esdhc_read32(&priv->esdhc_regs->hostcapblt);
+ hostver = esdhc_read32(&priv->esdhc_regs->hostver);
+ if (caps & HOSTCAPBLT_DMAS &&
+ HOSTVER_VENDOR(hostver) > VENDOR_V_22) {
+ priv->adma_desc_table = sdhci_adma_init();
+ if (!priv->adma_desc_table)
+ debug("Could not allocate ADMA tables, falling back to SDMA\n");
+ }
+ }
+
if (gd->arch.sdhc_per_clk) {
priv->sdhc_clk = gd->arch.sdhc_per_clk;
priv->is_sdhc_per_clk = true;
#define PROCTL_DTW_4 0x00000002
#define PROCTL_DTW_8 0x00000004
#define PROCTL_D3CD 0x00000008
+#define PROCTL_DMAS_MASK 0x00000300
+#define PROCTL_DMAS_SDMA 0x00000000
+#define PROCTL_DMAS_ADMA1 0x00000100
+#define PROCTL_DMAS_ADMA2 0x00000300
#define PROCTL_VOLT_SEL 0x00000400
#define CMDARG 0x0002e008
#define MAX_TUNING_LOOP 40
+#define HOSTVER_VENDOR(x) (((x) >> 8) & 0xff)
+#define VENDOR_V_10 0x00
+#define VENDOR_V_20 0x10
+#define VENDOR_V_21 0x11
+#define VENDOR_V_22 0x12
+#define VENDOR_V_23 0x13
+#define VENDOR_V_30 0x20
+#define VENDOR_V_31 0x21
+#define VENDOR_V_32 0x22
+
struct fsl_esdhc_cfg {
phys_addr_t esdhc_base;
u32 sdhc_clk;