xref: /OK3568_Linux_fs/kernel/arch/c6x/mm/dma-coherent.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Port on Texas Instruments TMS320C6x architecture
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
6*4882a593Smuzhiyun  *  Author: Aurelien Jacquiot <aurelien.jacquiot@ti.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *  DMA uncached mapping support.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  *  Using code pulled from ARM
11*4882a593Smuzhiyun  *  Copyright (C) 2000-2004 Russell King
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/bitmap.h>
15*4882a593Smuzhiyun #include <linux/bitops.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/interrupt.h>
18*4882a593Smuzhiyun #include <linux/dma-map-ops.h>
19*4882a593Smuzhiyun #include <linux/memblock.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include <asm/cacheflush.h>
22*4882a593Smuzhiyun #include <asm/page.h>
23*4882a593Smuzhiyun #include <asm/setup.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /*
26*4882a593Smuzhiyun  * DMA coherent memory management, can be redefined using the memdma=
27*4882a593Smuzhiyun  * kernel command line
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /* none by default */
31*4882a593Smuzhiyun static phys_addr_t dma_base;
32*4882a593Smuzhiyun static u32 dma_size;
33*4882a593Smuzhiyun static u32 dma_pages;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static unsigned long *dma_bitmap;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* bitmap lock */
38*4882a593Smuzhiyun static DEFINE_SPINLOCK(dma_lock);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /*
41*4882a593Smuzhiyun  * Return a DMA coherent and contiguous memory chunk from the DMA memory
42*4882a593Smuzhiyun  */
__alloc_dma_pages(int order)43*4882a593Smuzhiyun static inline u32 __alloc_dma_pages(int order)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	unsigned long flags;
46*4882a593Smuzhiyun 	u32 pos;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	spin_lock_irqsave(&dma_lock, flags);
49*4882a593Smuzhiyun 	pos = bitmap_find_free_region(dma_bitmap, dma_pages, order);
50*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dma_lock, flags);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	return dma_base + (pos << PAGE_SHIFT);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
__free_dma_pages(u32 addr,int order)55*4882a593Smuzhiyun static void __free_dma_pages(u32 addr, int order)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	unsigned long flags;
58*4882a593Smuzhiyun 	u32 pos = (addr - dma_base) >> PAGE_SHIFT;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	if (addr < dma_base || (pos + (1 << order)) >= dma_pages) {
61*4882a593Smuzhiyun 		printk(KERN_ERR "%s: freeing outside range.\n", __func__);
62*4882a593Smuzhiyun 		BUG();
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	spin_lock_irqsave(&dma_lock, flags);
66*4882a593Smuzhiyun 	bitmap_release_region(dma_bitmap, pos, order);
67*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dma_lock, flags);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun  * Allocate DMA coherent memory space and return both the kernel
72*4882a593Smuzhiyun  * virtual and DMA address for that space.
73*4882a593Smuzhiyun  */
arch_dma_alloc(struct device * dev,size_t size,dma_addr_t * handle,gfp_t gfp,unsigned long attrs)74*4882a593Smuzhiyun void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
75*4882a593Smuzhiyun 		gfp_t gfp, unsigned long attrs)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	void *ret;
78*4882a593Smuzhiyun 	u32 paddr;
79*4882a593Smuzhiyun 	int order;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	if (!dma_size || !size)
82*4882a593Smuzhiyun 		return NULL;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	paddr = __alloc_dma_pages(order);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if (handle)
89*4882a593Smuzhiyun 		*handle = paddr;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (!paddr)
92*4882a593Smuzhiyun 		return NULL;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	ret = phys_to_virt(paddr);
95*4882a593Smuzhiyun 	memset(ret, 0, 1 << order);
96*4882a593Smuzhiyun 	return ret;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /*
100*4882a593Smuzhiyun  * Free DMA coherent memory as defined by the above mapping.
101*4882a593Smuzhiyun  */
arch_dma_free(struct device * dev,size_t size,void * vaddr,dma_addr_t dma_handle,unsigned long attrs)102*4882a593Smuzhiyun void arch_dma_free(struct device *dev, size_t size, void *vaddr,
103*4882a593Smuzhiyun 		dma_addr_t dma_handle, unsigned long attrs)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	int order;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	if (!dma_size || !size)
108*4882a593Smuzhiyun 		return;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	__free_dma_pages(virt_to_phys(vaddr), order);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun /*
116*4882a593Smuzhiyun  * Initialise the coherent DMA memory allocator using the given uncached region.
117*4882a593Smuzhiyun  */
coherent_mem_init(phys_addr_t start,u32 size)118*4882a593Smuzhiyun void __init coherent_mem_init(phys_addr_t start, u32 size)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	if (!size)
121*4882a593Smuzhiyun 		return;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	printk(KERN_INFO
124*4882a593Smuzhiyun 	       "Coherent memory (DMA) region start=0x%x size=0x%x\n",
125*4882a593Smuzhiyun 	       start, size);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	dma_base = start;
128*4882a593Smuzhiyun 	dma_size = size;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	/* allocate bitmap */
131*4882a593Smuzhiyun 	dma_pages = dma_size >> PAGE_SHIFT;
132*4882a593Smuzhiyun 	if (dma_size & (PAGE_SIZE - 1))
133*4882a593Smuzhiyun 		++dma_pages;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	dma_bitmap = memblock_alloc(BITS_TO_LONGS(dma_pages) * sizeof(long),
136*4882a593Smuzhiyun 				    sizeof(long));
137*4882a593Smuzhiyun 	if (!dma_bitmap)
138*4882a593Smuzhiyun 		panic("%s: Failed to allocate %zu bytes align=0x%zx\n",
139*4882a593Smuzhiyun 		      __func__, BITS_TO_LONGS(dma_pages) * sizeof(long),
140*4882a593Smuzhiyun 		      sizeof(long));
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
c6x_dma_sync(phys_addr_t paddr,size_t size,enum dma_data_direction dir)143*4882a593Smuzhiyun static void c6x_dma_sync(phys_addr_t paddr, size_t size,
144*4882a593Smuzhiyun 		enum dma_data_direction dir)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	BUG_ON(!valid_dma_direction(dir));
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	switch (dir) {
149*4882a593Smuzhiyun 	case DMA_FROM_DEVICE:
150*4882a593Smuzhiyun 		L2_cache_block_invalidate(paddr, paddr + size);
151*4882a593Smuzhiyun 		break;
152*4882a593Smuzhiyun 	case DMA_TO_DEVICE:
153*4882a593Smuzhiyun 		L2_cache_block_writeback(paddr, paddr + size);
154*4882a593Smuzhiyun 		break;
155*4882a593Smuzhiyun 	case DMA_BIDIRECTIONAL:
156*4882a593Smuzhiyun 		L2_cache_block_writeback_invalidate(paddr, paddr + size);
157*4882a593Smuzhiyun 		break;
158*4882a593Smuzhiyun 	default:
159*4882a593Smuzhiyun 		break;
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
arch_sync_dma_for_device(phys_addr_t paddr,size_t size,enum dma_data_direction dir)163*4882a593Smuzhiyun void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
164*4882a593Smuzhiyun 		enum dma_data_direction dir)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	return c6x_dma_sync(paddr, size, dir);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
arch_sync_dma_for_cpu(phys_addr_t paddr,size_t size,enum dma_data_direction dir)169*4882a593Smuzhiyun void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
170*4882a593Smuzhiyun 		enum dma_data_direction dir)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	return c6x_dma_sync(paddr, size, dir);
173*4882a593Smuzhiyun }
174