18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> 88c2ecf20Sopenharmony_ci * Copyright (C) 2005 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com> 98c2ecf20Sopenharmony_ci * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. 108c2ecf20Sopenharmony_ci * IP32 changes by Ilya. 118c2ecf20Sopenharmony_ci * Copyright (C) 2010 Cavium Networks, Inc. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/dma-direct.h> 148c2ecf20Sopenharmony_ci#include <linux/memblock.h> 158c2ecf20Sopenharmony_ci#include <linux/swiotlb.h> 168c2ecf20Sopenharmony_ci#include <linux/types.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/mm.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/octeon/octeon.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 258c2ecf20Sopenharmony_ci#include <linux/pci.h> 268c2ecf20Sopenharmony_ci#include <asm/octeon/pci-octeon.h> 278c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-npi-defs.h> 288c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-pci-defs.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct octeon_dma_map_ops { 318c2ecf20Sopenharmony_ci dma_addr_t (*phys_to_dma)(struct device *dev, phys_addr_t paddr); 328c2ecf20Sopenharmony_ci phys_addr_t (*dma_to_phys)(struct device *dev, dma_addr_t daddr); 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic dma_addr_t octeon_hole_phys_to_dma(phys_addr_t paddr) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci if (paddr >= CVMX_PCIE_BAR1_PHYS_BASE && paddr < (CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_PHYS_SIZE)) 388c2ecf20Sopenharmony_ci return paddr - CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_RC_BASE; 398c2ecf20Sopenharmony_ci else 408c2ecf20Sopenharmony_ci return paddr; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic phys_addr_t octeon_hole_dma_to_phys(dma_addr_t daddr) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (daddr >= CVMX_PCIE_BAR1_RC_BASE) 468c2ecf20Sopenharmony_ci return daddr + CVMX_PCIE_BAR1_PHYS_BASE - CVMX_PCIE_BAR1_RC_BASE; 478c2ecf20Sopenharmony_ci else 488c2ecf20Sopenharmony_ci return daddr; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic dma_addr_t octeon_gen1_phys_to_dma(struct device *dev, phys_addr_t paddr) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci if (paddr >= 0x410000000ull && paddr < 0x420000000ull) 548c2ecf20Sopenharmony_ci paddr -= 0x400000000ull; 558c2ecf20Sopenharmony_ci return octeon_hole_phys_to_dma(paddr); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic phys_addr_t octeon_gen1_dma_to_phys(struct device *dev, dma_addr_t daddr) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci daddr = octeon_hole_dma_to_phys(daddr); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (daddr >= 0x10000000ull && daddr < 0x20000000ull) 638c2ecf20Sopenharmony_ci daddr += 0x400000000ull; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return daddr; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const struct octeon_dma_map_ops octeon_gen1_ops = { 698c2ecf20Sopenharmony_ci .phys_to_dma = octeon_gen1_phys_to_dma, 708c2ecf20Sopenharmony_ci .dma_to_phys = octeon_gen1_dma_to_phys, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic dma_addr_t octeon_gen2_phys_to_dma(struct device *dev, phys_addr_t paddr) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci return octeon_hole_phys_to_dma(paddr); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic phys_addr_t octeon_gen2_dma_to_phys(struct device *dev, dma_addr_t daddr) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci return octeon_hole_dma_to_phys(daddr); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic const struct octeon_dma_map_ops octeon_gen2_ops = { 848c2ecf20Sopenharmony_ci .phys_to_dma = octeon_gen2_phys_to_dma, 858c2ecf20Sopenharmony_ci .dma_to_phys = octeon_gen2_dma_to_phys, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic dma_addr_t octeon_big_phys_to_dma(struct device *dev, phys_addr_t paddr) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci if (paddr >= 0x410000000ull && paddr < 0x420000000ull) 918c2ecf20Sopenharmony_ci paddr -= 0x400000000ull; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* Anything in the BAR1 hole or above goes via BAR2 */ 948c2ecf20Sopenharmony_ci if (paddr >= 0xf0000000ull) 958c2ecf20Sopenharmony_ci paddr = OCTEON_BAR2_PCI_ADDRESS + paddr; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return paddr; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic phys_addr_t octeon_big_dma_to_phys(struct device *dev, dma_addr_t daddr) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci if (daddr >= OCTEON_BAR2_PCI_ADDRESS) 1038c2ecf20Sopenharmony_ci daddr -= OCTEON_BAR2_PCI_ADDRESS; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (daddr >= 0x10000000ull && daddr < 0x20000000ull) 1068c2ecf20Sopenharmony_ci daddr += 0x400000000ull; 1078c2ecf20Sopenharmony_ci return daddr; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic const struct octeon_dma_map_ops octeon_big_ops = { 1118c2ecf20Sopenharmony_ci .phys_to_dma = octeon_big_phys_to_dma, 1128c2ecf20Sopenharmony_ci .dma_to_phys = octeon_big_dma_to_phys, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic dma_addr_t octeon_small_phys_to_dma(struct device *dev, 1168c2ecf20Sopenharmony_ci phys_addr_t paddr) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (paddr >= 0x410000000ull && paddr < 0x420000000ull) 1198c2ecf20Sopenharmony_ci paddr -= 0x400000000ull; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Anything not in the BAR1 range goes via BAR2 */ 1228c2ecf20Sopenharmony_ci if (paddr >= octeon_bar1_pci_phys && paddr < octeon_bar1_pci_phys + 0x8000000ull) 1238c2ecf20Sopenharmony_ci paddr = paddr - octeon_bar1_pci_phys; 1248c2ecf20Sopenharmony_ci else 1258c2ecf20Sopenharmony_ci paddr = OCTEON_BAR2_PCI_ADDRESS + paddr; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return paddr; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic phys_addr_t octeon_small_dma_to_phys(struct device *dev, 1318c2ecf20Sopenharmony_ci dma_addr_t daddr) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci if (daddr >= OCTEON_BAR2_PCI_ADDRESS) 1348c2ecf20Sopenharmony_ci daddr -= OCTEON_BAR2_PCI_ADDRESS; 1358c2ecf20Sopenharmony_ci else 1368c2ecf20Sopenharmony_ci daddr += octeon_bar1_pci_phys; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (daddr >= 0x10000000ull && daddr < 0x20000000ull) 1398c2ecf20Sopenharmony_ci daddr += 0x400000000ull; 1408c2ecf20Sopenharmony_ci return daddr; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic const struct octeon_dma_map_ops octeon_small_ops = { 1448c2ecf20Sopenharmony_ci .phys_to_dma = octeon_small_phys_to_dma, 1458c2ecf20Sopenharmony_ci .dma_to_phys = octeon_small_dma_to_phys, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic const struct octeon_dma_map_ops *octeon_pci_dma_ops; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_civoid __init octeon_pci_dma_init(void) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci switch (octeon_dma_bar_type) { 1538c2ecf20Sopenharmony_ci case OCTEON_DMA_BAR_TYPE_PCIE: 1548c2ecf20Sopenharmony_ci octeon_pci_dma_ops = &octeon_gen1_ops; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case OCTEON_DMA_BAR_TYPE_PCIE2: 1578c2ecf20Sopenharmony_ci octeon_pci_dma_ops = &octeon_gen2_ops; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case OCTEON_DMA_BAR_TYPE_BIG: 1608c2ecf20Sopenharmony_ci octeon_pci_dma_ops = &octeon_big_ops; 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci case OCTEON_DMA_BAR_TYPE_SMALL: 1638c2ecf20Sopenharmony_ci octeon_pci_dma_ops = &octeon_small_ops; 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci default: 1668c2ecf20Sopenharmony_ci BUG(); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cidma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 1748c2ecf20Sopenharmony_ci if (dev && dev_is_pci(dev)) 1758c2ecf20Sopenharmony_ci return octeon_pci_dma_ops->phys_to_dma(dev, paddr); 1768c2ecf20Sopenharmony_ci#endif 1778c2ecf20Sopenharmony_ci return paddr; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ciphys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 1838c2ecf20Sopenharmony_ci if (dev && dev_is_pci(dev)) 1848c2ecf20Sopenharmony_ci return octeon_pci_dma_ops->dma_to_phys(dev, daddr); 1858c2ecf20Sopenharmony_ci#endif 1868c2ecf20Sopenharmony_ci return daddr; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cichar *octeon_swiotlb; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_civoid __init plat_swiotlb_setup(void) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci phys_addr_t start, end; 1948c2ecf20Sopenharmony_ci phys_addr_t max_addr; 1958c2ecf20Sopenharmony_ci phys_addr_t addr_size; 1968c2ecf20Sopenharmony_ci size_t swiotlbsize; 1978c2ecf20Sopenharmony_ci unsigned long swiotlb_nslabs; 1988c2ecf20Sopenharmony_ci u64 i; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci max_addr = 0; 2018c2ecf20Sopenharmony_ci addr_size = 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci for_each_mem_range(i, &start, &end) { 2048c2ecf20Sopenharmony_ci /* These addresses map low for PCI. */ 2058c2ecf20Sopenharmony_ci if (start > 0x410000000ull && !OCTEON_IS_OCTEON2()) 2068c2ecf20Sopenharmony_ci continue; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci addr_size += (end - start); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (max_addr < end) 2118c2ecf20Sopenharmony_ci max_addr = end; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci swiotlbsize = PAGE_SIZE; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * For OCTEON_DMA_BAR_TYPE_SMALL, size the iotlb at 1/4 memory 2198c2ecf20Sopenharmony_ci * size to a maximum of 64MB 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN31XX) 2228c2ecf20Sopenharmony_ci || OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2)) { 2238c2ecf20Sopenharmony_ci swiotlbsize = addr_size / 4; 2248c2ecf20Sopenharmony_ci if (swiotlbsize > 64 * (1<<20)) 2258c2ecf20Sopenharmony_ci swiotlbsize = 64 * (1<<20); 2268c2ecf20Sopenharmony_ci } else if (max_addr > 0xf0000000ul) { 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * Otherwise only allocate a big iotlb if there is 2298c2ecf20Sopenharmony_ci * memory past the BAR1 hole. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_ci swiotlbsize = 64 * (1<<20); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci#endif 2348c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_OHCI_HCD_PLATFORM 2358c2ecf20Sopenharmony_ci /* OCTEON II ohci is only 32-bit. */ 2368c2ecf20Sopenharmony_ci if (OCTEON_IS_OCTEON2() && max_addr >= 0x100000000ul) 2378c2ecf20Sopenharmony_ci swiotlbsize = 64 * (1<<20); 2388c2ecf20Sopenharmony_ci#endif 2398c2ecf20Sopenharmony_ci swiotlb_nslabs = swiotlbsize >> IO_TLB_SHIFT; 2408c2ecf20Sopenharmony_ci swiotlb_nslabs = ALIGN(swiotlb_nslabs, IO_TLB_SEGSIZE); 2418c2ecf20Sopenharmony_ci swiotlbsize = swiotlb_nslabs << IO_TLB_SHIFT; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci octeon_swiotlb = memblock_alloc_low(swiotlbsize, PAGE_SIZE); 2448c2ecf20Sopenharmony_ci if (!octeon_swiotlb) 2458c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %zu bytes align=%lx\n", 2468c2ecf20Sopenharmony_ci __func__, swiotlbsize, PAGE_SIZE); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (swiotlb_init_with_tbl(octeon_swiotlb, swiotlb_nslabs, 1) == -ENOMEM) 2498c2ecf20Sopenharmony_ci panic("Cannot allocate SWIOTLB buffer"); 2508c2ecf20Sopenharmony_ci} 251