DMA memory cannot cross specific boundary for some SDHCI controller, such as DesignWare SDHCI controller. Add DMA memory boundary dt property and workaround the limitation. Signed-off-by: Jun Nie <jun.nie@xxxxxxxxxx> --- drivers/mmc/host/sdhci.c | 20 +++++++++++++++++++- drivers/mmc/host/sdhci.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index d8a6c1c91448..56c53fbadd9d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -763,9 +763,25 @@ static void sdhci_adma_table_pre(struct sdhci_host *host, BUG_ON(len > 65536); /* tran, valid */ - if (len) + if (len) { + unsigned int boundary = host->dma_mem_boundary; + /* + * work around for buffer across mem boundary, split + * the buffer. + */ + if (boundary && + ((addr & (boundary - 1)) + len) > boundary) { + offset = boundary - (addr & (boundary - 1)); + __sdhci_adma_write_desc(host, &desc, + addr, offset, + ADMA2_TRAN_VALID); + addr += offset; + len -= offset; + } + __sdhci_adma_write_desc(host, &desc, addr, len, ADMA2_TRAN_VALID); + } /* * If this triggers then we have a calculation bug @@ -3634,6 +3650,8 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver, "sdhci-caps-mask", &dt_caps_mask); of_property_read_u64(mmc_dev(host->mmc)->of_node, "sdhci-caps", &dt_caps); + of_property_read_u32(mmc_dev(host->mmc)->of_node, + "sdhci-dma-mem-boundary", &host->dma_mem_boundary); if (of_property_read_u32(mmc_dev(host->mmc)->of_node, "sdhci-ctrl-hs400", &host->sdhci_ctrl_hs400)) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index cac4d819f62c..954ac08c4fb0 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -608,6 +608,7 @@ struct sdhci_host { /* SDHCI_CTRL_HS400 value */ u32 sdhci_ctrl_hs400; + u32 dma_mem_boundary; unsigned long private[0] ____cacheline_aligned; }; -- 2.17.1