162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IO workarounds for PCI on Celleb/Cell platform 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright 2006-2007 TOSHIBA CORPORATION 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#undef DEBUG 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/of_address.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <asm/ppc-pci.h> 1662306a36Sopenharmony_ci#include <asm/pci-bridge.h> 1762306a36Sopenharmony_ci#include <asm/io-workarounds.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define SPIDER_PCI_DISABLE_PREFETCH 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct spiderpci_iowa_private { 2262306a36Sopenharmony_ci void __iomem *regs; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic void spiderpci_io_flush(struct iowa_bus *bus) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct spiderpci_iowa_private *priv; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci priv = bus->private; 3062306a36Sopenharmony_ci in_be32(priv->regs + SPIDER_PCI_DUMMY_READ); 3162306a36Sopenharmony_ci iosync(); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define SPIDER_PCI_MMIO_READ(name, ret) \ 3562306a36Sopenharmony_cistatic ret spiderpci_##name(const PCI_IO_ADDR addr) \ 3662306a36Sopenharmony_ci{ \ 3762306a36Sopenharmony_ci ret val = __do_##name(addr); \ 3862306a36Sopenharmony_ci spiderpci_io_flush(iowa_mem_find_bus(addr)); \ 3962306a36Sopenharmony_ci return val; \ 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define SPIDER_PCI_MMIO_READ_STR(name) \ 4362306a36Sopenharmony_cistatic void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, \ 4462306a36Sopenharmony_ci unsigned long count) \ 4562306a36Sopenharmony_ci{ \ 4662306a36Sopenharmony_ci __do_##name(addr, buf, count); \ 4762306a36Sopenharmony_ci spiderpci_io_flush(iowa_mem_find_bus(addr)); \ 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ(readb, u8) 5162306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ(readw, u16) 5262306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ(readl, u32) 5362306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ(readq, u64) 5462306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ(readw_be, u16) 5562306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ(readl_be, u32) 5662306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ(readq_be, u64) 5762306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ_STR(readsb) 5862306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ_STR(readsw) 5962306a36Sopenharmony_ciSPIDER_PCI_MMIO_READ_STR(readsl) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src, 6262306a36Sopenharmony_ci unsigned long n) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci __do_memcpy_fromio(dest, src, n); 6562306a36Sopenharmony_ci spiderpci_io_flush(iowa_mem_find_bus(src)); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int __init spiderpci_pci_setup_chip(struct pci_controller *phb, 6962306a36Sopenharmony_ci void __iomem *regs) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci void *dummy_page_va; 7262306a36Sopenharmony_ci dma_addr_t dummy_page_da; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#ifdef SPIDER_PCI_DISABLE_PREFETCH 7562306a36Sopenharmony_ci u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT); 7662306a36Sopenharmony_ci pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val); 7762306a36Sopenharmony_ci out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8); 7862306a36Sopenharmony_ci#endif /* SPIDER_PCI_DISABLE_PREFETCH */ 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* setup dummy read */ 8162306a36Sopenharmony_ci /* 8262306a36Sopenharmony_ci * On CellBlade, we can't know that which XDR memory is used by 8362306a36Sopenharmony_ci * kmalloc() to allocate dummy_page_va. 8462306a36Sopenharmony_ci * In order to improve the performance, the XDR which is used to 8562306a36Sopenharmony_ci * allocate dummy_page_va is the nearest the spider-pci. 8662306a36Sopenharmony_ci * We have to select the CBE which is the nearest the spider-pci 8762306a36Sopenharmony_ci * to allocate memory from the best XDR, but I don't know that 8862306a36Sopenharmony_ci * how to do. 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * Celleb does not have this problem, because it has only one XDR. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); 9362306a36Sopenharmony_ci if (!dummy_page_va) { 9462306a36Sopenharmony_ci pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n"); 9562306a36Sopenharmony_ci return -1; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci dummy_page_da = dma_map_single(phb->parent, dummy_page_va, 9962306a36Sopenharmony_ci PAGE_SIZE, DMA_FROM_DEVICE); 10062306a36Sopenharmony_ci if (dma_mapping_error(phb->parent, dummy_page_da)) { 10162306a36Sopenharmony_ci pr_err("SPIDER-IOWA:Map dummy page filed.\n"); 10262306a36Sopenharmony_ci kfree(dummy_page_va); 10362306a36Sopenharmony_ci return -1; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciint __init spiderpci_iowa_init(struct iowa_bus *bus, void *data) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci void __iomem *regs = NULL; 11462306a36Sopenharmony_ci struct spiderpci_iowa_private *priv; 11562306a36Sopenharmony_ci struct device_node *np = bus->phb->dn; 11662306a36Sopenharmony_ci struct resource r; 11762306a36Sopenharmony_ci unsigned long offset = (unsigned long)data; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%pOF)\n", 12062306a36Sopenharmony_ci np); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 12362306a36Sopenharmony_ci if (!priv) { 12462306a36Sopenharmony_ci pr_err("SPIDERPCI-IOWA:" 12562306a36Sopenharmony_ci "Can't allocate struct spiderpci_iowa_private"); 12662306a36Sopenharmony_ci return -1; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (of_address_to_resource(np, 0, &r)) { 13062306a36Sopenharmony_ci pr_err("SPIDERPCI-IOWA:Can't get resource.\n"); 13162306a36Sopenharmony_ci goto error; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE); 13562306a36Sopenharmony_ci if (!regs) { 13662306a36Sopenharmony_ci pr_err("SPIDERPCI-IOWA:ioremap failed.\n"); 13762306a36Sopenharmony_ci goto error; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci priv->regs = regs; 14062306a36Sopenharmony_ci bus->private = priv; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (spiderpci_pci_setup_chip(bus->phb, regs)) 14362306a36Sopenharmony_ci goto error; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cierror: 14862306a36Sopenharmony_ci kfree(priv); 14962306a36Sopenharmony_ci bus->private = NULL; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (regs) 15262306a36Sopenharmony_ci iounmap(regs); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return -1; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct ppc_pci_io spiderpci_ops = { 15862306a36Sopenharmony_ci .readb = spiderpci_readb, 15962306a36Sopenharmony_ci .readw = spiderpci_readw, 16062306a36Sopenharmony_ci .readl = spiderpci_readl, 16162306a36Sopenharmony_ci .readq = spiderpci_readq, 16262306a36Sopenharmony_ci .readw_be = spiderpci_readw_be, 16362306a36Sopenharmony_ci .readl_be = spiderpci_readl_be, 16462306a36Sopenharmony_ci .readq_be = spiderpci_readq_be, 16562306a36Sopenharmony_ci .readsb = spiderpci_readsb, 16662306a36Sopenharmony_ci .readsw = spiderpci_readsw, 16762306a36Sopenharmony_ci .readsl = spiderpci_readsl, 16862306a36Sopenharmony_ci .memcpy_fromio = spiderpci_memcpy_fromio, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 171