18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IO workarounds for PCI on Celleb/Cell platform 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) Copyright 2006-2007 TOSHIBA CORPORATION 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#undef DEBUG 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/ppc-pci.h> 168c2ecf20Sopenharmony_ci#include <asm/pci-bridge.h> 178c2ecf20Sopenharmony_ci#include <asm/io-workarounds.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define SPIDER_PCI_DISABLE_PREFETCH 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct spiderpci_iowa_private { 228c2ecf20Sopenharmony_ci void __iomem *regs; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void spiderpci_io_flush(struct iowa_bus *bus) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct spiderpci_iowa_private *priv; 288c2ecf20Sopenharmony_ci u32 val; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci priv = bus->private; 318c2ecf20Sopenharmony_ci val = in_be32(priv->regs + SPIDER_PCI_DUMMY_READ); 328c2ecf20Sopenharmony_ci iosync(); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define SPIDER_PCI_MMIO_READ(name, ret) \ 368c2ecf20Sopenharmony_cistatic ret spiderpci_##name(const PCI_IO_ADDR addr) \ 378c2ecf20Sopenharmony_ci{ \ 388c2ecf20Sopenharmony_ci ret val = __do_##name(addr); \ 398c2ecf20Sopenharmony_ci spiderpci_io_flush(iowa_mem_find_bus(addr)); \ 408c2ecf20Sopenharmony_ci return val; \ 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define SPIDER_PCI_MMIO_READ_STR(name) \ 448c2ecf20Sopenharmony_cistatic void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, \ 458c2ecf20Sopenharmony_ci unsigned long count) \ 468c2ecf20Sopenharmony_ci{ \ 478c2ecf20Sopenharmony_ci __do_##name(addr, buf, count); \ 488c2ecf20Sopenharmony_ci spiderpci_io_flush(iowa_mem_find_bus(addr)); \ 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ(readb, u8) 528c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ(readw, u16) 538c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ(readl, u32) 548c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ(readq, u64) 558c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ(readw_be, u16) 568c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ(readl_be, u32) 578c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ(readq_be, u64) 588c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ_STR(readsb) 598c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ_STR(readsw) 608c2ecf20Sopenharmony_ciSPIDER_PCI_MMIO_READ_STR(readsl) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src, 638c2ecf20Sopenharmony_ci unsigned long n) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci __do_memcpy_fromio(dest, src, n); 668c2ecf20Sopenharmony_ci spiderpci_io_flush(iowa_mem_find_bus(src)); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int __init spiderpci_pci_setup_chip(struct pci_controller *phb, 708c2ecf20Sopenharmony_ci void __iomem *regs) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci void *dummy_page_va; 738c2ecf20Sopenharmony_ci dma_addr_t dummy_page_da; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#ifdef SPIDER_PCI_DISABLE_PREFETCH 768c2ecf20Sopenharmony_ci u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT); 778c2ecf20Sopenharmony_ci pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val); 788c2ecf20Sopenharmony_ci out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8); 798c2ecf20Sopenharmony_ci#endif /* SPIDER_PCI_DISABLE_PREFETCH */ 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* setup dummy read */ 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * On CellBlade, we can't know that which XDR memory is used by 848c2ecf20Sopenharmony_ci * kmalloc() to allocate dummy_page_va. 858c2ecf20Sopenharmony_ci * In order to imporve the performance, the XDR which is used to 868c2ecf20Sopenharmony_ci * allocate dummy_page_va is the nearest the spider-pci. 878c2ecf20Sopenharmony_ci * We have to select the CBE which is the nearest the spider-pci 888c2ecf20Sopenharmony_ci * to allocate memory from the best XDR, but I don't know that 898c2ecf20Sopenharmony_ci * how to do. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * Celleb does not have this problem, because it has only one XDR. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); 948c2ecf20Sopenharmony_ci if (!dummy_page_va) { 958c2ecf20Sopenharmony_ci pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n"); 968c2ecf20Sopenharmony_ci return -1; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci dummy_page_da = dma_map_single(phb->parent, dummy_page_va, 1008c2ecf20Sopenharmony_ci PAGE_SIZE, DMA_FROM_DEVICE); 1018c2ecf20Sopenharmony_ci if (dma_mapping_error(phb->parent, dummy_page_da)) { 1028c2ecf20Sopenharmony_ci pr_err("SPIDER-IOWA:Map dummy page filed.\n"); 1038c2ecf20Sopenharmony_ci kfree(dummy_page_va); 1048c2ecf20Sopenharmony_ci return -1; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciint __init spiderpci_iowa_init(struct iowa_bus *bus, void *data) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci void __iomem *regs = NULL; 1158c2ecf20Sopenharmony_ci struct spiderpci_iowa_private *priv; 1168c2ecf20Sopenharmony_ci struct device_node *np = bus->phb->dn; 1178c2ecf20Sopenharmony_ci struct resource r; 1188c2ecf20Sopenharmony_ci unsigned long offset = (unsigned long)data; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%pOF)\n", 1218c2ecf20Sopenharmony_ci np); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1248c2ecf20Sopenharmony_ci if (!priv) { 1258c2ecf20Sopenharmony_ci pr_err("SPIDERPCI-IOWA:" 1268c2ecf20Sopenharmony_ci "Can't allocate struct spiderpci_iowa_private"); 1278c2ecf20Sopenharmony_ci return -1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 0, &r)) { 1318c2ecf20Sopenharmony_ci pr_err("SPIDERPCI-IOWA:Can't get resource.\n"); 1328c2ecf20Sopenharmony_ci goto error; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE); 1368c2ecf20Sopenharmony_ci if (!regs) { 1378c2ecf20Sopenharmony_ci pr_err("SPIDERPCI-IOWA:ioremap failed.\n"); 1388c2ecf20Sopenharmony_ci goto error; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci priv->regs = regs; 1418c2ecf20Sopenharmony_ci bus->private = priv; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (spiderpci_pci_setup_chip(bus->phb, regs)) 1448c2ecf20Sopenharmony_ci goto error; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cierror: 1498c2ecf20Sopenharmony_ci kfree(priv); 1508c2ecf20Sopenharmony_ci bus->private = NULL; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (regs) 1538c2ecf20Sopenharmony_ci iounmap(regs); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return -1; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistruct ppc_pci_io spiderpci_ops = { 1598c2ecf20Sopenharmony_ci .readb = spiderpci_readb, 1608c2ecf20Sopenharmony_ci .readw = spiderpci_readw, 1618c2ecf20Sopenharmony_ci .readl = spiderpci_readl, 1628c2ecf20Sopenharmony_ci .readq = spiderpci_readq, 1638c2ecf20Sopenharmony_ci .readw_be = spiderpci_readw_be, 1648c2ecf20Sopenharmony_ci .readl_be = spiderpci_readl_be, 1658c2ecf20Sopenharmony_ci .readq_be = spiderpci_readq_be, 1668c2ecf20Sopenharmony_ci .readsb = spiderpci_readsb, 1678c2ecf20Sopenharmony_ci .readsw = spiderpci_readsw, 1688c2ecf20Sopenharmony_ci .readsl = spiderpci_readsl, 1698c2ecf20Sopenharmony_ci .memcpy_fromio = spiderpci_memcpy_fromio, 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci 172