108dbd0f8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 265c3d7c5SRichard Kuo /* 365c3d7c5SRichard Kuo * DMA implementation for Hexagon 465c3d7c5SRichard Kuo * 55e115054SRichard Kuo * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. 665c3d7c5SRichard Kuo */ 765c3d7c5SRichard Kuo 8e0a9317dSChristoph Hellwig #include <linux/dma-noncoherent.h> 957c8a661SMike Rapoport #include <linux/memblock.h> 1065c3d7c5SRichard Kuo #include <linux/genalloc.h> 116bbbc30cSRichard Kuo #include <linux/module.h> 125e115054SRichard Kuo #include <asm/page.h> 1365c3d7c5SRichard Kuo 1465c3d7c5SRichard Kuo static struct gen_pool *coherent_pool; 1565c3d7c5SRichard Kuo 1665c3d7c5SRichard Kuo 1765c3d7c5SRichard Kuo /* Allocates from a pool of uncached memory that was reserved at boot time */ 1865c3d7c5SRichard Kuo 19e0a9317dSChristoph Hellwig void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_addr, 20e0a9317dSChristoph Hellwig gfp_t flag, unsigned long attrs) 2165c3d7c5SRichard Kuo { 2265c3d7c5SRichard Kuo void *ret; 2365c3d7c5SRichard Kuo 245e115054SRichard Kuo /* 255e115054SRichard Kuo * Our max_low_pfn should have been backed off by 16MB in 265e115054SRichard Kuo * mm/init.c to create DMA coherent space. Use that as the VA 275e115054SRichard Kuo * for the pool. 285e115054SRichard Kuo */ 295e115054SRichard Kuo 3065c3d7c5SRichard Kuo if (coherent_pool == NULL) { 3165c3d7c5SRichard Kuo coherent_pool = gen_pool_create(PAGE_SHIFT, -1); 3265c3d7c5SRichard Kuo 3365c3d7c5SRichard Kuo if (coherent_pool == NULL) 3465c3d7c5SRichard Kuo panic("Can't create %s() memory pool!", __func__); 3565c3d7c5SRichard Kuo else 3665c3d7c5SRichard Kuo gen_pool_add(coherent_pool, 37200f351eSRandy Dunlap (unsigned long)pfn_to_virt(max_low_pfn), 3865c3d7c5SRichard Kuo hexagon_coherent_pool_size, -1); 3965c3d7c5SRichard Kuo } 4065c3d7c5SRichard Kuo 4165c3d7c5SRichard Kuo ret = (void *) gen_pool_alloc(coherent_pool, size); 4265c3d7c5SRichard Kuo 4365c3d7c5SRichard Kuo if (ret) { 4465c3d7c5SRichard Kuo memset(ret, 0, size); 455e115054SRichard Kuo *dma_addr = (dma_addr_t) virt_to_phys(ret); 4665c3d7c5SRichard Kuo } else 4765c3d7c5SRichard Kuo *dma_addr = ~0; 4865c3d7c5SRichard Kuo 4965c3d7c5SRichard Kuo return ret; 5065c3d7c5SRichard Kuo } 5165c3d7c5SRichard Kuo 52e0a9317dSChristoph Hellwig void arch_dma_free(struct device *dev, size_t size, void *vaddr, 5300085f1eSKrzysztof Kozlowski dma_addr_t dma_addr, unsigned long attrs) 5465c3d7c5SRichard Kuo { 5565c3d7c5SRichard Kuo gen_pool_free(coherent_pool, (unsigned long) vaddr, size); 5665c3d7c5SRichard Kuo } 5765c3d7c5SRichard Kuo 58e0a9317dSChristoph Hellwig void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, 59e0a9317dSChristoph Hellwig size_t size, enum dma_data_direction dir) 6065c3d7c5SRichard Kuo { 61e0a9317dSChristoph Hellwig void *addr = phys_to_virt(paddr); 6265c3d7c5SRichard Kuo 6365c3d7c5SRichard Kuo switch (dir) { 6465c3d7c5SRichard Kuo case DMA_TO_DEVICE: 6565c3d7c5SRichard Kuo hexagon_clean_dcache_range((unsigned long) addr, 6665c3d7c5SRichard Kuo (unsigned long) addr + size); 6765c3d7c5SRichard Kuo break; 6865c3d7c5SRichard Kuo case DMA_FROM_DEVICE: 6965c3d7c5SRichard Kuo hexagon_inv_dcache_range((unsigned long) addr, 7065c3d7c5SRichard Kuo (unsigned long) addr + size); 7165c3d7c5SRichard Kuo break; 7265c3d7c5SRichard Kuo case DMA_BIDIRECTIONAL: 7365c3d7c5SRichard Kuo flush_dcache_range((unsigned long) addr, 7465c3d7c5SRichard Kuo (unsigned long) addr + size); 7565c3d7c5SRichard Kuo break; 7665c3d7c5SRichard Kuo default: 7765c3d7c5SRichard Kuo BUG(); 7865c3d7c5SRichard Kuo } 7965c3d7c5SRichard Kuo } 80