summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLey Foon Tan <leyfoon.tan@starfivetech.com>2022-11-25 10:21:06 +0300
committerLey Foon Tan <leyfoon.tan@starfivetech.com>2023-12-04 06:00:13 +0300
commitbc6f67fe5309e8032f0c03ad7c494de6da2f5334 (patch)
treecd05621dcc43ba1d981e640fff1c4f6c2cd2cd54
parentf9e9e8f8144aacea6e4ebcdd29262901f19a91fc (diff)
downloadlinux-bc6f67fe5309e8032f0c03ad7c494de6da2f5334.tar.xz
riscv: starfive: Add DMA non-coherent support
Enable arch_*dma* implementation. Signed-off-by: Ley Foon Tan <leyfoon.tan@linux.starfivetech.com>
-rw-r--r--arch/riscv/Kconfig.socs1
-rw-r--r--arch/riscv/mm/dma-noncoherent.c55
2 files changed, 56 insertions, 0 deletions
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index d569eff6cace..199be54abdec 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -28,6 +28,7 @@ config SOC_STARFIVE
config SOC_STARFIVE_DUBHE
bool "StarFive Dubhe SoC"
+ select RISCV_DMA_NONCOHERENT
select SERIAL_SIFIVE if TTY
select SERIAL_SIFIVE_CONSOLE if TTY
select SIFIVE_PLIC
diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c
index e07e53aea537..81ee62da18a5 100644
--- a/arch/riscv/mm/dma-noncoherent.c
+++ b/arch/riscv/mm/dma-noncoherent.c
@@ -7,12 +7,66 @@
#include <linux/dma-direct.h>
#include <linux/dma-map-ops.h>
+#include <linux/io.h>
#include <linux/mm.h>
#include <asm/cacheflush.h>
+#include <asm/sbi.h>
#include <soc/sifive/sifive_ccache.h>
static bool noncoherent_supported;
+#ifdef CONFIG_SOC_STARFIVE_DUBHE
+
+#define DUBHE_UNCACHED_OFFSET 0x400000000
+
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, enum dma_data_direction dir)
+{
+ sbi_cache_flush(paddr, size);
+}
+
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, enum dma_data_direction dir)
+{
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ sbi_cache_flush(paddr, size);
+ break;
+ case DMA_FROM_DEVICE:
+ sbi_cache_invalidate(paddr, size);
+ break;
+ case DMA_TO_DEVICE:
+ break;
+ default:
+ BUG();
+ }
+}
+
+void arch_dma_prep_coherent(struct page *page, size_t size)
+{
+ void *flush_addr = page_address(page);
+
+ sbi_cache_flush(__pa(flush_addr), size);
+}
+
+void arch_dma_clear_uncached(void *addr, size_t size)
+{
+ memunmap(addr);
+}
+
+void *arch_dma_set_uncached(void *addr, size_t size)
+{
+ phys_addr_t phys_addr = __pa(addr) + DUBHE_UNCACHED_OFFSET;
+ void *mem_base = NULL;
+
+ mem_base = memremap(phys_addr, size, MEMREMAP_WT);
+ if (!mem_base) {
+ pr_err("%s memremap failed for addr %px\n", __func__, addr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return mem_base;
+}
+
+#else
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
enum dma_data_direction dir)
{
@@ -88,6 +142,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
ALT_CMO_OP(flush, flush_addr, size, riscv_cbom_block_size);
}
+#endif
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *iommu, bool coherent)