18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Port on Texas Instruments TMS320C6x architecture 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated 68c2ecf20Sopenharmony_ci * Author: Aurelien Jacquiot <aurelien.jacquiot@ti.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * DMA uncached mapping support. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Using code pulled from ARM 118c2ecf20Sopenharmony_ci * Copyright (C) 2000-2004 Russell King 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 158c2ecf20Sopenharmony_ci#include <linux/bitops.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h> 198c2ecf20Sopenharmony_ci#include <linux/memblock.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 228c2ecf20Sopenharmony_ci#include <asm/page.h> 238c2ecf20Sopenharmony_ci#include <asm/setup.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * DMA coherent memory management, can be redefined using the memdma= 278c2ecf20Sopenharmony_ci * kernel command line 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* none by default */ 318c2ecf20Sopenharmony_cistatic phys_addr_t dma_base; 328c2ecf20Sopenharmony_cistatic u32 dma_size; 338c2ecf20Sopenharmony_cistatic u32 dma_pages; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic unsigned long *dma_bitmap; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* bitmap lock */ 388c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(dma_lock); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * Return a DMA coherent and contiguous memory chunk from the DMA memory 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_cistatic inline u32 __alloc_dma_pages(int order) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci unsigned long flags; 468c2ecf20Sopenharmony_ci u32 pos; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci spin_lock_irqsave(&dma_lock, flags); 498c2ecf20Sopenharmony_ci pos = bitmap_find_free_region(dma_bitmap, dma_pages, order); 508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dma_lock, flags); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return dma_base + (pos << PAGE_SHIFT); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void __free_dma_pages(u32 addr, int order) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci unsigned long flags; 588c2ecf20Sopenharmony_ci u32 pos = (addr - dma_base) >> PAGE_SHIFT; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (addr < dma_base || (pos + (1 << order)) >= dma_pages) { 618c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: freeing outside range.\n", __func__); 628c2ecf20Sopenharmony_ci BUG(); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci spin_lock_irqsave(&dma_lock, flags); 668c2ecf20Sopenharmony_ci bitmap_release_region(dma_bitmap, pos, order); 678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dma_lock, flags); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * Allocate DMA coherent memory space and return both the kernel 728c2ecf20Sopenharmony_ci * virtual and DMA address for that space. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_civoid *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, 758c2ecf20Sopenharmony_ci gfp_t gfp, unsigned long attrs) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci void *ret; 788c2ecf20Sopenharmony_ci u32 paddr; 798c2ecf20Sopenharmony_ci int order; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (!dma_size || !size) 828c2ecf20Sopenharmony_ci return NULL; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci paddr = __alloc_dma_pages(order); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (handle) 898c2ecf20Sopenharmony_ci *handle = paddr; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!paddr) 928c2ecf20Sopenharmony_ci return NULL; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ret = phys_to_virt(paddr); 958c2ecf20Sopenharmony_ci memset(ret, 0, 1 << order); 968c2ecf20Sopenharmony_ci return ret; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * Free DMA coherent memory as defined by the above mapping. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_civoid arch_dma_free(struct device *dev, size_t size, void *vaddr, 1038c2ecf20Sopenharmony_ci dma_addr_t dma_handle, unsigned long attrs) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int order; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (!dma_size || !size) 1088c2ecf20Sopenharmony_ci return; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci __free_dma_pages(virt_to_phys(vaddr), order); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * Initialise the coherent DMA memory allocator using the given uncached region. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_civoid __init coherent_mem_init(phys_addr_t start, u32 size) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci if (!size) 1218c2ecf20Sopenharmony_ci return; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci printk(KERN_INFO 1248c2ecf20Sopenharmony_ci "Coherent memory (DMA) region start=0x%x size=0x%x\n", 1258c2ecf20Sopenharmony_ci start, size); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci dma_base = start; 1288c2ecf20Sopenharmony_ci dma_size = size; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* allocate bitmap */ 1318c2ecf20Sopenharmony_ci dma_pages = dma_size >> PAGE_SHIFT; 1328c2ecf20Sopenharmony_ci if (dma_size & (PAGE_SIZE - 1)) 1338c2ecf20Sopenharmony_ci ++dma_pages; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci dma_bitmap = memblock_alloc(BITS_TO_LONGS(dma_pages) * sizeof(long), 1368c2ecf20Sopenharmony_ci sizeof(long)); 1378c2ecf20Sopenharmony_ci if (!dma_bitmap) 1388c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %zu bytes align=0x%zx\n", 1398c2ecf20Sopenharmony_ci __func__, BITS_TO_LONGS(dma_pages) * sizeof(long), 1408c2ecf20Sopenharmony_ci sizeof(long)); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void c6x_dma_sync(phys_addr_t paddr, size_t size, 1448c2ecf20Sopenharmony_ci enum dma_data_direction dir) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci BUG_ON(!valid_dma_direction(dir)); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci switch (dir) { 1498c2ecf20Sopenharmony_ci case DMA_FROM_DEVICE: 1508c2ecf20Sopenharmony_ci L2_cache_block_invalidate(paddr, paddr + size); 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case DMA_TO_DEVICE: 1538c2ecf20Sopenharmony_ci L2_cache_block_writeback(paddr, paddr + size); 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case DMA_BIDIRECTIONAL: 1568c2ecf20Sopenharmony_ci L2_cache_block_writeback_invalidate(paddr, paddr + size); 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci default: 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_civoid arch_sync_dma_for_device(phys_addr_t paddr, size_t size, 1648c2ecf20Sopenharmony_ci enum dma_data_direction dir) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci return c6x_dma_sync(paddr, size, dir); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_civoid arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, 1708c2ecf20Sopenharmony_ci enum dma_data_direction dir) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci return c6x_dma_sync(paddr, size, dir); 1738c2ecf20Sopenharmony_ci} 174