145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21e76875eSOlof Johansson /*
31e76875eSOlof Johansson * Copyright (C) 2006 PA Semi, Inc
41e76875eSOlof Johansson *
51e76875eSOlof Johansson * Authors: Kip Walker, PA Semi
61e76875eSOlof Johansson * Olof Johansson, PA Semi
71e76875eSOlof Johansson *
81e76875eSOlof Johansson * Maintained by: Olof Johansson <olof@lixom.net>
91e76875eSOlof Johansson *
101e76875eSOlof Johansson * Based on arch/powerpc/platforms/maple/pci.c
111e76875eSOlof Johansson */
121e76875eSOlof Johansson
131e76875eSOlof Johansson
141e76875eSOlof Johansson #include <linux/kernel.h>
15e6f6390aSChristophe Leroy #include <linux/of_address.h>
161e76875eSOlof Johansson #include <linux/pci.h>
171e76875eSOlof Johansson
181e76875eSOlof Johansson #include <asm/pci-bridge.h>
1951f4cc20SDarren Stevens #include <asm/isa-bridge.h>
201e76875eSOlof Johansson #include <asm/machdep.h>
211e76875eSOlof Johansson
221e76875eSOlof Johansson #include <asm/ppc-pci.h>
231e76875eSOlof Johansson
24d28a0d94SDaniel Axtens #include "pasemi.h"
25d28a0d94SDaniel Axtens
261e76875eSOlof Johansson #define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
271e76875eSOlof Johansson
pa_pxp_offset_valid(u8 bus,u8 devfn,int offset)28df7e70a2SOlof Johansson static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset)
29df7e70a2SOlof Johansson {
30df7e70a2SOlof Johansson /* Device 0 Function 0 is special: It's config space spans function 1 as
31df7e70a2SOlof Johansson * well, so allow larger offset. It's really a two-function device but the
32df7e70a2SOlof Johansson * second function does not probe.
33df7e70a2SOlof Johansson */
34df7e70a2SOlof Johansson if (bus == 0 && devfn == 0)
35df7e70a2SOlof Johansson return offset < 8192;
36df7e70a2SOlof Johansson else
37df7e70a2SOlof Johansson return offset < 4096;
38df7e70a2SOlof Johansson }
391e76875eSOlof Johansson
pa_pxp_cfg_addr(struct pci_controller * hose,u8 bus,u8 devfn,int offset)407c84ace9SAl Viro static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,
411e76875eSOlof Johansson u8 bus, u8 devfn, int offset)
421e76875eSOlof Johansson {
437c84ace9SAl Viro return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset);
441e76875eSOlof Johansson }
451e76875eSOlof Johansson
is_root_port(int busno,int devfn)464d442331SOlof Johansson static inline int is_root_port(int busno, int devfn)
474d442331SOlof Johansson {
484d442331SOlof Johansson return ((busno == 0) && (PCI_FUNC(devfn) < 4) &&
494d442331SOlof Johansson ((PCI_SLOT(devfn) == 16) || (PCI_SLOT(devfn) == 17)));
504d442331SOlof Johansson }
514d442331SOlof Johansson
is_5945_reg(int reg)524d442331SOlof Johansson static inline int is_5945_reg(int reg)
534d442331SOlof Johansson {
544d442331SOlof Johansson return (((reg >= 0x18) && (reg < 0x34)) ||
554d442331SOlof Johansson ((reg >= 0x158) && (reg < 0x178)));
564d442331SOlof Johansson }
574d442331SOlof Johansson
workaround_5945(struct pci_bus * bus,unsigned int devfn,int offset,int len,u32 * val)584d442331SOlof Johansson static int workaround_5945(struct pci_bus *bus, unsigned int devfn,
594d442331SOlof Johansson int offset, int len, u32 *val)
604d442331SOlof Johansson {
614d442331SOlof Johansson struct pci_controller *hose;
624d442331SOlof Johansson void volatile __iomem *addr, *dummy;
634d442331SOlof Johansson int byte;
644d442331SOlof Johansson u32 tmp;
654d442331SOlof Johansson
664d442331SOlof Johansson if (!is_root_port(bus->number, devfn) || !is_5945_reg(offset))
674d442331SOlof Johansson return 0;
684d442331SOlof Johansson
694d442331SOlof Johansson hose = pci_bus_to_host(bus);
704d442331SOlof Johansson
714d442331SOlof Johansson addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset & ~0x3);
724d442331SOlof Johansson byte = offset & 0x3;
734d442331SOlof Johansson
744d442331SOlof Johansson /* Workaround bug 5945: write 0 to a dummy register before reading,
754d442331SOlof Johansson * and write back what we read. We must read/write the full 32-bit
764d442331SOlof Johansson * contents so we need to shift and mask by hand.
774d442331SOlof Johansson */
784d442331SOlof Johansson dummy = pa_pxp_cfg_addr(hose, bus->number, devfn, 0x10);
794d442331SOlof Johansson out_le32(dummy, 0);
804d442331SOlof Johansson tmp = in_le32(addr);
814d442331SOlof Johansson out_le32(addr, tmp);
824d442331SOlof Johansson
834d442331SOlof Johansson switch (len) {
844d442331SOlof Johansson case 1:
854d442331SOlof Johansson *val = (tmp >> (8*byte)) & 0xff;
864d442331SOlof Johansson break;
874d442331SOlof Johansson case 2:
884d442331SOlof Johansson if (byte == 0)
894d442331SOlof Johansson *val = tmp & 0xffff;
904d442331SOlof Johansson else
914d442331SOlof Johansson *val = (tmp >> 16) & 0xffff;
924d442331SOlof Johansson break;
934d442331SOlof Johansson default:
944d442331SOlof Johansson *val = tmp;
954d442331SOlof Johansson break;
964d442331SOlof Johansson }
974d442331SOlof Johansson
984d442331SOlof Johansson return 1;
994d442331SOlof Johansson }
1004d442331SOlof Johansson
10168f211a4SDarren Stevens #ifdef CONFIG_PPC_PASEMI_NEMO
10268f211a4SDarren Stevens #define PXP_ERR_CFG_REG 0x4
10368f211a4SDarren Stevens #define PXP_IGNORE_PCIE_ERRORS 0x800
10468f211a4SDarren Stevens #define SB600_BUS 5
10568f211a4SDarren Stevens
sb600_set_flag(int bus)10668f211a4SDarren Stevens static void sb600_set_flag(int bus)
10768f211a4SDarren Stevens {
10868f211a4SDarren Stevens static void __iomem *iob_mapbase = NULL;
10968f211a4SDarren Stevens struct resource res;
11068f211a4SDarren Stevens struct device_node *dn;
11168f211a4SDarren Stevens int err;
11268f211a4SDarren Stevens
11368f211a4SDarren Stevens if (iob_mapbase == NULL) {
11468f211a4SDarren Stevens dn = of_find_compatible_node(NULL, "isa", "pasemi,1682m-iob");
11568f211a4SDarren Stevens if (!dn) {
11668f211a4SDarren Stevens pr_crit("NEMO SB600 missing iob node\n");
11768f211a4SDarren Stevens return;
11868f211a4SDarren Stevens }
11968f211a4SDarren Stevens
12068f211a4SDarren Stevens err = of_address_to_resource(dn, 0, &res);
12168f211a4SDarren Stevens of_node_put(dn);
12268f211a4SDarren Stevens
12368f211a4SDarren Stevens if (err) {
12468f211a4SDarren Stevens pr_crit("NEMO SB600 missing resource\n");
12568f211a4SDarren Stevens return;
12668f211a4SDarren Stevens }
12768f211a4SDarren Stevens
12868f211a4SDarren Stevens pr_info("NEMO SB600 IOB base %08llx\n",res.start);
12968f211a4SDarren Stevens
13068f211a4SDarren Stevens iob_mapbase = ioremap(res.start + 0x100, 0x94);
13168f211a4SDarren Stevens }
13268f211a4SDarren Stevens
13368f211a4SDarren Stevens if (iob_mapbase != NULL) {
13468f211a4SDarren Stevens if (bus == SB600_BUS) {
13568f211a4SDarren Stevens /*
13668f211a4SDarren Stevens * This is the SB600's bus, tell the PCI-e root port
13768f211a4SDarren Stevens * to allow non-zero devices to enumerate.
13868f211a4SDarren Stevens */
13968f211a4SDarren Stevens out_le32(iob_mapbase + PXP_ERR_CFG_REG, in_le32(iob_mapbase + PXP_ERR_CFG_REG) | PXP_IGNORE_PCIE_ERRORS);
14068f211a4SDarren Stevens } else {
14168f211a4SDarren Stevens /*
14268f211a4SDarren Stevens * Only scan device 0 on other busses
14368f211a4SDarren Stevens */
14468f211a4SDarren Stevens out_le32(iob_mapbase + PXP_ERR_CFG_REG, in_le32(iob_mapbase + PXP_ERR_CFG_REG) & ~PXP_IGNORE_PCIE_ERRORS);
14568f211a4SDarren Stevens }
14668f211a4SDarren Stevens }
14768f211a4SDarren Stevens }
14868f211a4SDarren Stevens
14968f211a4SDarren Stevens #else
15068f211a4SDarren Stevens
sb600_set_flag(int bus)15168f211a4SDarren Stevens static void sb600_set_flag(int bus)
15268f211a4SDarren Stevens {
15368f211a4SDarren Stevens }
15468f211a4SDarren Stevens #endif
15568f211a4SDarren Stevens
pa_pxp_read_config(struct pci_bus * bus,unsigned int devfn,int offset,int len,u32 * val)1561e76875eSOlof Johansson static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
1571e76875eSOlof Johansson int offset, int len, u32 *val)
1581e76875eSOlof Johansson {
1591e76875eSOlof Johansson struct pci_controller *hose;
1607c84ace9SAl Viro void volatile __iomem *addr;
1611e76875eSOlof Johansson
1621e76875eSOlof Johansson hose = pci_bus_to_host(bus);
1631e76875eSOlof Johansson if (!hose)
1641e76875eSOlof Johansson return PCIBIOS_DEVICE_NOT_FOUND;
1651e76875eSOlof Johansson
166df7e70a2SOlof Johansson if (!pa_pxp_offset_valid(bus->number, devfn, offset))
1671e76875eSOlof Johansson return PCIBIOS_BAD_REGISTER_NUMBER;
1681e76875eSOlof Johansson
1694d442331SOlof Johansson if (workaround_5945(bus, devfn, offset, len, val))
1704d442331SOlof Johansson return PCIBIOS_SUCCESSFUL;
1714d442331SOlof Johansson
1721e76875eSOlof Johansson addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
1731e76875eSOlof Johansson
17451f4cc20SDarren Stevens sb600_set_flag(bus->number);
17551f4cc20SDarren Stevens
1761e76875eSOlof Johansson /*
1771e76875eSOlof Johansson * Note: the caller has already checked that offset is
1781e76875eSOlof Johansson * suitably aligned and that len is 1, 2 or 4.
1791e76875eSOlof Johansson */
1801e76875eSOlof Johansson switch (len) {
1811e76875eSOlof Johansson case 1:
1827c84ace9SAl Viro *val = in_8(addr);
1831e76875eSOlof Johansson break;
1841e76875eSOlof Johansson case 2:
1857c84ace9SAl Viro *val = in_le16(addr);
1861e76875eSOlof Johansson break;
1871e76875eSOlof Johansson default:
1887c84ace9SAl Viro *val = in_le32(addr);
1891e76875eSOlof Johansson break;
1901e76875eSOlof Johansson }
1911e76875eSOlof Johansson
1921e76875eSOlof Johansson return PCIBIOS_SUCCESSFUL;
1931e76875eSOlof Johansson }
1941e76875eSOlof Johansson
pa_pxp_write_config(struct pci_bus * bus,unsigned int devfn,int offset,int len,u32 val)1951e76875eSOlof Johansson static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn,
1961e76875eSOlof Johansson int offset, int len, u32 val)
1971e76875eSOlof Johansson {
1981e76875eSOlof Johansson struct pci_controller *hose;
1997c84ace9SAl Viro void volatile __iomem *addr;
2001e76875eSOlof Johansson
2011e76875eSOlof Johansson hose = pci_bus_to_host(bus);
2021e76875eSOlof Johansson if (!hose)
2031e76875eSOlof Johansson return PCIBIOS_DEVICE_NOT_FOUND;
2041e76875eSOlof Johansson
205df7e70a2SOlof Johansson if (!pa_pxp_offset_valid(bus->number, devfn, offset))
2061e76875eSOlof Johansson return PCIBIOS_BAD_REGISTER_NUMBER;
2071e76875eSOlof Johansson
2081e76875eSOlof Johansson addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
2091e76875eSOlof Johansson
21051f4cc20SDarren Stevens sb600_set_flag(bus->number);
21151f4cc20SDarren Stevens
2121e76875eSOlof Johansson /*
2131e76875eSOlof Johansson * Note: the caller has already checked that offset is
2141e76875eSOlof Johansson * suitably aligned and that len is 1, 2 or 4.
2151e76875eSOlof Johansson */
2161e76875eSOlof Johansson switch (len) {
2171e76875eSOlof Johansson case 1:
2187c84ace9SAl Viro out_8(addr, val);
2191e76875eSOlof Johansson break;
2201e76875eSOlof Johansson case 2:
2217c84ace9SAl Viro out_le16(addr, val);
2221e76875eSOlof Johansson break;
2231e76875eSOlof Johansson default:
2247c84ace9SAl Viro out_le32(addr, val);
2251e76875eSOlof Johansson break;
2261e76875eSOlof Johansson }
2271e76875eSOlof Johansson return PCIBIOS_SUCCESSFUL;
2281e76875eSOlof Johansson }
2291e76875eSOlof Johansson
2301e76875eSOlof Johansson static struct pci_ops pa_pxp_ops = {
2311bb8c621SNathan Lynch .read = pa_pxp_read_config,
2321bb8c621SNathan Lynch .write = pa_pxp_write_config,
2331e76875eSOlof Johansson };
2341e76875eSOlof Johansson
setup_pa_pxp(struct pci_controller * hose)2351e76875eSOlof Johansson static void __init setup_pa_pxp(struct pci_controller *hose)
2361e76875eSOlof Johansson {
2371e76875eSOlof Johansson hose->ops = &pa_pxp_ops;
2381e76875eSOlof Johansson hose->cfg_data = ioremap(0xe0000000, 0x10000000);
2391e76875eSOlof Johansson }
2401e76875eSOlof Johansson
pas_add_bridge(struct device_node * dev)24109b55f76SArnd Bergmann static int __init pas_add_bridge(struct device_node *dev)
2421e76875eSOlof Johansson {
2431e76875eSOlof Johansson struct pci_controller *hose;
2441e76875eSOlof Johansson
245b7c670d6SRob Herring pr_debug("Adding PCI host bridge %pOF\n", dev);
2461e76875eSOlof Johansson
2471e76875eSOlof Johansson hose = pcibios_alloc_controller(dev);
2481e76875eSOlof Johansson if (!hose)
2491e76875eSOlof Johansson return -ENOMEM;
2501e76875eSOlof Johansson
2511e76875eSOlof Johansson hose->first_busno = 0;
2521e76875eSOlof Johansson hose->last_busno = 0xff;
253d28a0d94SDaniel Axtens hose->controller_ops = pasemi_pci_controller_ops;
2541e76875eSOlof Johansson
2551e76875eSOlof Johansson setup_pa_pxp(hose);
2561e76875eSOlof Johansson
257e13606d7SDarren Stevens pr_info("Found PA-PXP PCI host bridge.\n");
2581e76875eSOlof Johansson
2591e76875eSOlof Johansson /* Interpret the "ranges" property */
2601e76875eSOlof Johansson pci_process_bridge_OF_ranges(hose, dev, 1);
2611e76875eSOlof Johansson
26251f4cc20SDarren Stevens /*
26351f4cc20SDarren Stevens * Scan for an isa bridge. This is needed to find the SB600 on the nemo
26451f4cc20SDarren Stevens * and does nothing on machines without one.
26551f4cc20SDarren Stevens */
26651f4cc20SDarren Stevens isa_bridge_find_early(hose);
26751f4cc20SDarren Stevens
2681e76875eSOlof Johansson return 0;
2691e76875eSOlof Johansson }
2701e76875eSOlof Johansson
pas_pci_init(void)2711e76875eSOlof Johansson void __init pas_pci_init(void)
2721e76875eSOlof Johansson {
273*2a066ae1SChristophe Leroy struct device_node *root = of_find_node_by_path("/");
274c28c2d4aSMichael Ellerman struct device_node *np;
275250a9350SDarren Stevens int res;
2761e76875eSOlof Johansson
277eff06ef0SOlof Johansson pci_set_flags(PCI_SCAN_ALL_PCIE_DEVS);
278eff06ef0SOlof Johansson
279*2a066ae1SChristophe Leroy np = of_find_compatible_node(root, NULL, "pasemi,rootbus");
280250a9350SDarren Stevens if (np) {
281250a9350SDarren Stevens res = pas_add_bridge(np);
282250a9350SDarren Stevens of_node_put(np);
283250a9350SDarren Stevens }
284*2a066ae1SChristophe Leroy of_node_put(root);
2851e76875eSOlof Johansson }
28668c8404cSOlof Johansson
pasemi_pci_getcfgaddr(struct pci_dev * dev,int offset)287e37e06afSNick Child void __iomem *__init pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset)
28868c8404cSOlof Johansson {
28968c8404cSOlof Johansson struct pci_controller *hose;
29068c8404cSOlof Johansson
2914d442331SOlof Johansson hose = pci_bus_to_host(dev->bus);
29268c8404cSOlof Johansson
2934d442331SOlof Johansson return (void __iomem *)pa_pxp_cfg_addr(hose, dev->bus->number, dev->devfn, offset);
29468c8404cSOlof Johansson }
295d28a0d94SDaniel Axtens
296d28a0d94SDaniel Axtens struct pci_controller_ops pasemi_pci_controller_ops;
297