xref: /openbmc/linux/arch/csky/mm/dma-mapping.c (revision 4af9027d3f4061992c0b065102a0a666b72f073b)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3 
4 #include <linux/cache.h>
5 #include <linux/dma-mapping.h>
6 #include <linux/dma-contiguous.h>
7 #include <linux/dma-noncoherent.h>
8 #include <linux/genalloc.h>
9 #include <linux/highmem.h>
10 #include <linux/io.h>
11 #include <linux/mm.h>
12 #include <linux/scatterlist.h>
13 #include <linux/types.h>
14 #include <linux/version.h>
15 #include <asm/cache.h>
16 
17 static int __init atomic_pool_init(void)
18 {
19 	return dma_atomic_pool_init(GFP_KERNEL, pgprot_noncached(PAGE_KERNEL));
20 }
21 postcore_initcall(atomic_pool_init);
22 
23 static inline void cache_op(phys_addr_t paddr, size_t size,
24 			    void (*fn)(unsigned long start, unsigned long end))
25 {
26 	struct page *page    = phys_to_page(paddr);
27 	void *start          = __va(page_to_phys(page));
28 	unsigned long offset = offset_in_page(paddr);
29 	size_t left          = size;
30 
31 	do {
32 		size_t len = left;
33 
34 		if (offset + len > PAGE_SIZE)
35 			len = PAGE_SIZE - offset;
36 
37 		if (PageHighMem(page)) {
38 			start = kmap_atomic(page);
39 
40 			fn((unsigned long)start + offset,
41 					(unsigned long)start + offset + len);
42 
43 			kunmap_atomic(start);
44 		} else {
45 			fn((unsigned long)start + offset,
46 					(unsigned long)start + offset + len);
47 		}
48 		offset = 0;
49 
50 		page++;
51 		start += PAGE_SIZE;
52 		left -= len;
53 	} while (left);
54 }
55 
56 static void dma_wbinv_set_zero_range(unsigned long start, unsigned long end)
57 {
58 	memset((void *)start, 0, end - start);
59 	dma_wbinv_range(start, end);
60 }
61 
62 void arch_dma_prep_coherent(struct page *page, size_t size)
63 {
64 	cache_op(page_to_phys(page), size, dma_wbinv_set_zero_range);
65 }
66 
67 void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
68 			      size_t size, enum dma_data_direction dir)
69 {
70 	switch (dir) {
71 	case DMA_TO_DEVICE:
72 		cache_op(paddr, size, dma_wb_range);
73 		break;
74 	case DMA_FROM_DEVICE:
75 	case DMA_BIDIRECTIONAL:
76 		cache_op(paddr, size, dma_wbinv_range);
77 		break;
78 	default:
79 		BUG();
80 	}
81 }
82 
83 void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
84 			   size_t size, enum dma_data_direction dir)
85 {
86 	switch (dir) {
87 	case DMA_TO_DEVICE:
88 		cache_op(paddr, size, dma_wb_range);
89 		break;
90 	case DMA_FROM_DEVICE:
91 	case DMA_BIDIRECTIONAL:
92 		cache_op(paddr, size, dma_wbinv_range);
93 		break;
94 	default:
95 		BUG();
96 	}
97 }
98