There is a limitation on AC5 SoC that Xenon SDHC can address only first 2GB of memory. Turning to the SDMA mode to use the bounce_buffer causes ext_csd recognition to fail on init. Using of swiotlb=force also does not help as it is allocated at the end of the memory. So it was decided to use reserved-memory as a bounce buffer in case if the board has more than 2G of memory, or turn on the PIO mode if such memory region does not exist in the device-tree. It was tested that this approach is 1.5 times faster than PIO. Signed-off-by: Vadym Kochan <vadym.kochan@xxxxxxxxxxx> --- drivers/mmc/host/sdhci-xenon.c | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index 08e838400b52..fbbd1a045002 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c @@ -14,8 +14,10 @@ #include <linux/acpi.h> #include <linux/delay.h> #include <linux/ktime.h> +#include <linux/mm.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_reserved_mem.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -486,6 +488,31 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host) xenon_disable_sdhc(host, sdhc_id); } +static int xenon_ac5_probe(struct sdhci_host *host) +{ + struct device *dev = mmc_dev(host->mmc); + struct sysinfo si; + int err; + + si_meminfo(&si); + + if ((si.totalram * si.mem_unit) > SZ_2G) { + struct device_node *dma_bounce_np; + + dma_bounce_np = of_parse_phandle(dev->of_node, + "marvell,ac5-sdhci-dma-bounce-pool", 0); + err = of_reserved_mem_device_init_by_idx(dev, dma_bounce_np, 0); + of_node_put(dma_bounce_np); + if (err) { + dev_warn(dev, "Disabling DMA because of 2GB DMA access limit and missing DMA bounce region\n"); + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; + host->quirks |= SDHCI_QUIRK_BROKEN_DMA; + } + } + + return 0; +} + static int xenon_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; @@ -531,6 +558,12 @@ static int xenon_probe(struct platform_device *pdev) if (err) goto err_clk; } + + if (of_device_is_compatible(dev->of_node, "marvell,ac5-sdhci")) { + err = xenon_ac5_probe(host); + if (err) + goto err_clk_axi; + } } err = mmc_of_parse(host->mmc); @@ -570,6 +603,7 @@ static int xenon_probe(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); xenon_sdhc_unprepare(host); err_clk_axi: + of_reserved_mem_device_release(&pdev->dev); clk_disable_unprepare(priv->axi_clk); err_clk: clk_disable_unprepare(pltfm_host->clk); @@ -591,6 +625,7 @@ static int xenon_remove(struct platform_device *pdev) sdhci_remove_host(host, 0); xenon_sdhc_unprepare(host); + of_reserved_mem_device_release(&pdev->dev); clk_disable_unprepare(priv->axi_clk); clk_disable_unprepare(pltfm_host->clk); @@ -682,6 +717,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = { { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807}, { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110}, { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700}, + { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AP806}, {} }; MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids); -- 2.17.1