116216333SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
27cfb62a2SIshizaki Kou /*
37cfb62a2SIshizaki Kou  * IO workarounds for PCI on Celleb/Cell platform
47cfb62a2SIshizaki Kou  *
57cfb62a2SIshizaki Kou  * (C) Copyright 2006-2007 TOSHIBA CORPORATION
67cfb62a2SIshizaki Kou  */
77cfb62a2SIshizaki Kou 
87cfb62a2SIshizaki Kou #undef DEBUG
97cfb62a2SIshizaki Kou 
107cfb62a2SIshizaki Kou #include <linux/kernel.h>
11*e6f6390aSChristophe Leroy #include <linux/of_address.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
137cfb62a2SIshizaki Kou #include <linux/io.h>
147cfb62a2SIshizaki Kou 
157cfb62a2SIshizaki Kou #include <asm/ppc-pci.h>
167cfb62a2SIshizaki Kou #include <asm/pci-bridge.h>
173cc30d07SMichael Ellerman #include <asm/io-workarounds.h>
187cfb62a2SIshizaki Kou 
197cfb62a2SIshizaki Kou #define SPIDER_PCI_DISABLE_PREFETCH
207cfb62a2SIshizaki Kou 
217cfb62a2SIshizaki Kou struct spiderpci_iowa_private {
227cfb62a2SIshizaki Kou 	void __iomem *regs;
237cfb62a2SIshizaki Kou };
247cfb62a2SIshizaki Kou 
spiderpci_io_flush(struct iowa_bus * bus)257cfb62a2SIshizaki Kou static void spiderpci_io_flush(struct iowa_bus *bus)
267cfb62a2SIshizaki Kou {
277cfb62a2SIshizaki Kou 	struct spiderpci_iowa_private *priv;
287cfb62a2SIshizaki Kou 
297cfb62a2SIshizaki Kou 	priv = bus->private;
30f377f7daSBaokun Li 	in_be32(priv->regs + SPIDER_PCI_DUMMY_READ);
317cfb62a2SIshizaki Kou 	iosync();
327cfb62a2SIshizaki Kou }
337cfb62a2SIshizaki Kou 
347cfb62a2SIshizaki Kou #define SPIDER_PCI_MMIO_READ(name, ret)					\
357cfb62a2SIshizaki Kou static ret spiderpci_##name(const PCI_IO_ADDR addr)			\
367cfb62a2SIshizaki Kou {									\
377cfb62a2SIshizaki Kou 	ret val = __do_##name(addr);					\
387cfb62a2SIshizaki Kou 	spiderpci_io_flush(iowa_mem_find_bus(addr));			\
397cfb62a2SIshizaki Kou 	return val;							\
407cfb62a2SIshizaki Kou }
417cfb62a2SIshizaki Kou 
427cfb62a2SIshizaki Kou #define SPIDER_PCI_MMIO_READ_STR(name)					\
437cfb62a2SIshizaki Kou static void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, 	\
447cfb62a2SIshizaki Kou 			     unsigned long count)			\
457cfb62a2SIshizaki Kou {									\
467cfb62a2SIshizaki Kou 	__do_##name(addr, buf, count);					\
477cfb62a2SIshizaki Kou 	spiderpci_io_flush(iowa_mem_find_bus(addr));			\
487cfb62a2SIshizaki Kou }
497cfb62a2SIshizaki Kou 
SPIDER_PCI_MMIO_READ(readb,u8)507cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ(readb, u8)
517cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ(readw, u16)
527cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ(readl, u32)
537cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ(readq, u64)
547cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ(readw_be, u16)
557cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ(readl_be, u32)
567cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ(readq_be, u64)
577cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ_STR(readsb)
587cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ_STR(readsw)
597cfb62a2SIshizaki Kou SPIDER_PCI_MMIO_READ_STR(readsl)
607cfb62a2SIshizaki Kou 
617cfb62a2SIshizaki Kou static void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src,
627cfb62a2SIshizaki Kou 				    unsigned long n)
637cfb62a2SIshizaki Kou {
647cfb62a2SIshizaki Kou 	__do_memcpy_fromio(dest, src, n);
657cfb62a2SIshizaki Kou 	spiderpci_io_flush(iowa_mem_find_bus(src));
667cfb62a2SIshizaki Kou }
677cfb62a2SIshizaki Kou 
spiderpci_pci_setup_chip(struct pci_controller * phb,void __iomem * regs)687cfb62a2SIshizaki Kou static int __init spiderpci_pci_setup_chip(struct pci_controller *phb,
697cfb62a2SIshizaki Kou 					   void __iomem *regs)
707cfb62a2SIshizaki Kou {
717cfb62a2SIshizaki Kou 	void *dummy_page_va;
727cfb62a2SIshizaki Kou 	dma_addr_t dummy_page_da;
737cfb62a2SIshizaki Kou 
747cfb62a2SIshizaki Kou #ifdef SPIDER_PCI_DISABLE_PREFETCH
757cfb62a2SIshizaki Kou 	u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT);
767cfb62a2SIshizaki Kou 	pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val);
777cfb62a2SIshizaki Kou 	out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);
787cfb62a2SIshizaki Kou #endif /* SPIDER_PCI_DISABLE_PREFETCH */
797cfb62a2SIshizaki Kou 
807cfb62a2SIshizaki Kou 	/* setup dummy read */
817cfb62a2SIshizaki Kou 	/*
827cfb62a2SIshizaki Kou 	 * On CellBlade, we can't know that which XDR memory is used by
837cfb62a2SIshizaki Kou 	 * kmalloc() to allocate dummy_page_va.
841fd02f66SJulia Lawall 	 * In order to improve the performance, the XDR which is used to
857cfb62a2SIshizaki Kou 	 * allocate dummy_page_va is the nearest the spider-pci.
867cfb62a2SIshizaki Kou 	 * We have to select the CBE which is the nearest the spider-pci
877cfb62a2SIshizaki Kou 	 * to allocate memory from the best XDR, but I don't know that
887cfb62a2SIshizaki Kou 	 * how to do.
897cfb62a2SIshizaki Kou 	 *
907cfb62a2SIshizaki Kou 	 * Celleb does not have this problem, because it has only one XDR.
917cfb62a2SIshizaki Kou 	 */
927cfb62a2SIshizaki Kou 	dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL);
937cfb62a2SIshizaki Kou 	if (!dummy_page_va) {
947cfb62a2SIshizaki Kou 		pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n");
957cfb62a2SIshizaki Kou 		return -1;
967cfb62a2SIshizaki Kou 	}
977cfb62a2SIshizaki Kou 
987cfb62a2SIshizaki Kou 	dummy_page_da = dma_map_single(phb->parent, dummy_page_va,
997cfb62a2SIshizaki Kou 				       PAGE_SIZE, DMA_FROM_DEVICE);
1008d8bb39bSFUJITA Tomonori 	if (dma_mapping_error(phb->parent, dummy_page_da)) {
1017cfb62a2SIshizaki Kou 		pr_err("SPIDER-IOWA:Map dummy page filed.\n");
1027cfb62a2SIshizaki Kou 		kfree(dummy_page_va);
1037cfb62a2SIshizaki Kou 		return -1;
1047cfb62a2SIshizaki Kou 	}
1057cfb62a2SIshizaki Kou 
1067cfb62a2SIshizaki Kou 	out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da);
1077cfb62a2SIshizaki Kou 
1087cfb62a2SIshizaki Kou 	return 0;
1097cfb62a2SIshizaki Kou }
1107cfb62a2SIshizaki Kou 
spiderpci_iowa_init(struct iowa_bus * bus,void * data)1117cfb62a2SIshizaki Kou int __init spiderpci_iowa_init(struct iowa_bus *bus, void *data)
1127cfb62a2SIshizaki Kou {
1137cfb62a2SIshizaki Kou 	void __iomem *regs = NULL;
1147cfb62a2SIshizaki Kou 	struct spiderpci_iowa_private *priv;
1157cfb62a2SIshizaki Kou 	struct device_node *np = bus->phb->dn;
1167cfb62a2SIshizaki Kou 	struct resource r;
1177cfb62a2SIshizaki Kou 	unsigned long offset = (unsigned long)data;
1187cfb62a2SIshizaki Kou 
119b7c670d6SRob Herring 	pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%pOF)\n",
120b7c670d6SRob Herring 		 np);
1217cfb62a2SIshizaki Kou 
122a0828cf5SMarkus Elfring 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1237cfb62a2SIshizaki Kou 	if (!priv) {
1247cfb62a2SIshizaki Kou 		pr_err("SPIDERPCI-IOWA:"
1257cfb62a2SIshizaki Kou 		       "Can't allocate struct spiderpci_iowa_private");
1267cfb62a2SIshizaki Kou 		return -1;
1277cfb62a2SIshizaki Kou 	}
1287cfb62a2SIshizaki Kou 
1297cfb62a2SIshizaki Kou 	if (of_address_to_resource(np, 0, &r)) {
1307cfb62a2SIshizaki Kou 		pr_err("SPIDERPCI-IOWA:Can't get resource.\n");
1317cfb62a2SIshizaki Kou 		goto error;
1327cfb62a2SIshizaki Kou 	}
1337cfb62a2SIshizaki Kou 
1347cfb62a2SIshizaki Kou 	regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE);
1357cfb62a2SIshizaki Kou 	if (!regs) {
1367cfb62a2SIshizaki Kou 		pr_err("SPIDERPCI-IOWA:ioremap failed.\n");
1377cfb62a2SIshizaki Kou 		goto error;
1387cfb62a2SIshizaki Kou 	}
1397cfb62a2SIshizaki Kou 	priv->regs = regs;
1407cfb62a2SIshizaki Kou 	bus->private = priv;
1417cfb62a2SIshizaki Kou 
1427cfb62a2SIshizaki Kou 	if (spiderpci_pci_setup_chip(bus->phb, regs))
1437cfb62a2SIshizaki Kou 		goto error;
1447cfb62a2SIshizaki Kou 
1457cfb62a2SIshizaki Kou 	return 0;
1467cfb62a2SIshizaki Kou 
1477cfb62a2SIshizaki Kou error:
1487cfb62a2SIshizaki Kou 	kfree(priv);
1497cfb62a2SIshizaki Kou 	bus->private = NULL;
1507cfb62a2SIshizaki Kou 
1517cfb62a2SIshizaki Kou 	if (regs)
1527cfb62a2SIshizaki Kou 		iounmap(regs);
1537cfb62a2SIshizaki Kou 
1547cfb62a2SIshizaki Kou 	return -1;
1557cfb62a2SIshizaki Kou }
1567cfb62a2SIshizaki Kou 
1577cfb62a2SIshizaki Kou struct ppc_pci_io spiderpci_ops = {
1587cfb62a2SIshizaki Kou 	.readb = spiderpci_readb,
1597cfb62a2SIshizaki Kou 	.readw = spiderpci_readw,
1607cfb62a2SIshizaki Kou 	.readl = spiderpci_readl,
1617cfb62a2SIshizaki Kou 	.readq = spiderpci_readq,
1627cfb62a2SIshizaki Kou 	.readw_be = spiderpci_readw_be,
1637cfb62a2SIshizaki Kou 	.readl_be = spiderpci_readl_be,
1647cfb62a2SIshizaki Kou 	.readq_be = spiderpci_readq_be,
1657cfb62a2SIshizaki Kou 	.readsb = spiderpci_readsb,
1667cfb62a2SIshizaki Kou 	.readsw = spiderpci_readsw,
1677cfb62a2SIshizaki Kou 	.readsl = spiderpci_readsl,
1687cfb62a2SIshizaki Kou 	.memcpy_fromio = spiderpci_memcpy_fromio,
1697cfb62a2SIshizaki Kou };
1707cfb62a2SIshizaki Kou 
171