diff options
author | Ley Foon Tan <leyfoon.tan@starfivetech.com> | 2022-11-25 10:21:06 +0300 |
---|---|---|
committer | Ley Foon Tan <leyfoon.tan@starfivetech.com> | 2023-12-04 06:00:13 +0300 |
commit | bc6f67fe5309e8032f0c03ad7c494de6da2f5334 (patch) | |
tree | cd05621dcc43ba1d981e640fff1c4f6c2cd2cd54 | |
parent | f9e9e8f8144aacea6e4ebcdd29262901f19a91fc (diff) | |
download | linux-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.socs | 1 | ||||
-rw-r--r-- | arch/riscv/mm/dma-noncoherent.c | 55 |
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) |