Path: blob/master/arch/powerpc/platforms/pasemi/pci.c
10818 views
/*1* Copyright (C) 2006 PA Semi, Inc2*3* Authors: Kip Walker, PA Semi4* Olof Johansson, PA Semi5*6* Maintained by: Olof Johansson <[email protected]>7*8* Based on arch/powerpc/platforms/maple/pci.c9*10* This program is free software; you can redistribute it and/or modify11* it under the terms of the GNU General Public License version 2 as12* published by the Free Software Foundation.13*14* This program is distributed in the hope that it will be useful,15* but WITHOUT ANY WARRANTY; without even the implied warranty of16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the17* GNU General Public License for more details.18*19* You should have received a copy of the GNU General Public License20* along with this program; if not, write to the Free Software21* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA22*/232425#include <linux/kernel.h>26#include <linux/pci.h>2728#include <asm/pci-bridge.h>29#include <asm/machdep.h>3031#include <asm/ppc-pci.h>3233#define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))3435static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset)36{37/* Device 0 Function 0 is special: It's config space spans function 1 as38* well, so allow larger offset. It's really a two-function device but the39* second function does not probe.40*/41if (bus == 0 && devfn == 0)42return offset < 8192;43else44return offset < 4096;45}4647static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,48u8 bus, u8 devfn, int offset)49{50return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset);51}5253static inline int is_root_port(int busno, int devfn)54{55return ((busno == 0) && (PCI_FUNC(devfn) < 4) &&56((PCI_SLOT(devfn) == 16) || (PCI_SLOT(devfn) == 17)));57}5859static inline int is_5945_reg(int reg)60{61return (((reg >= 0x18) && (reg < 0x34)) ||62((reg >= 0x158) && (reg < 0x178)));63}6465static int workaround_5945(struct pci_bus *bus, unsigned int devfn,66int offset, int len, u32 *val)67{68struct pci_controller *hose;69void volatile __iomem *addr, *dummy;70int byte;71u32 tmp;7273if (!is_root_port(bus->number, devfn) || !is_5945_reg(offset))74return 0;7576hose = pci_bus_to_host(bus);7778addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset & ~0x3);79byte = offset & 0x3;8081/* Workaround bug 5945: write 0 to a dummy register before reading,82* and write back what we read. We must read/write the full 32-bit83* contents so we need to shift and mask by hand.84*/85dummy = pa_pxp_cfg_addr(hose, bus->number, devfn, 0x10);86out_le32(dummy, 0);87tmp = in_le32(addr);88out_le32(addr, tmp);8990switch (len) {91case 1:92*val = (tmp >> (8*byte)) & 0xff;93break;94case 2:95if (byte == 0)96*val = tmp & 0xffff;97else98*val = (tmp >> 16) & 0xffff;99break;100default:101*val = tmp;102break;103}104105return 1;106}107108static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,109int offset, int len, u32 *val)110{111struct pci_controller *hose;112void volatile __iomem *addr;113114hose = pci_bus_to_host(bus);115if (!hose)116return PCIBIOS_DEVICE_NOT_FOUND;117118if (!pa_pxp_offset_valid(bus->number, devfn, offset))119return PCIBIOS_BAD_REGISTER_NUMBER;120121if (workaround_5945(bus, devfn, offset, len, val))122return PCIBIOS_SUCCESSFUL;123124addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);125126/*127* Note: the caller has already checked that offset is128* suitably aligned and that len is 1, 2 or 4.129*/130switch (len) {131case 1:132*val = in_8(addr);133break;134case 2:135*val = in_le16(addr);136break;137default:138*val = in_le32(addr);139break;140}141142return PCIBIOS_SUCCESSFUL;143}144145static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn,146int offset, int len, u32 val)147{148struct pci_controller *hose;149void volatile __iomem *addr;150151hose = pci_bus_to_host(bus);152if (!hose)153return PCIBIOS_DEVICE_NOT_FOUND;154155if (!pa_pxp_offset_valid(bus->number, devfn, offset))156return PCIBIOS_BAD_REGISTER_NUMBER;157158addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);159160/*161* Note: the caller has already checked that offset is162* suitably aligned and that len is 1, 2 or 4.163*/164switch (len) {165case 1:166out_8(addr, val);167break;168case 2:169out_le16(addr, val);170break;171default:172out_le32(addr, val);173break;174}175return PCIBIOS_SUCCESSFUL;176}177178static struct pci_ops pa_pxp_ops = {179.read = pa_pxp_read_config,180.write = pa_pxp_write_config,181};182183static void __init setup_pa_pxp(struct pci_controller *hose)184{185hose->ops = &pa_pxp_ops;186hose->cfg_data = ioremap(0xe0000000, 0x10000000);187}188189static int __init pas_add_bridge(struct device_node *dev)190{191struct pci_controller *hose;192193pr_debug("Adding PCI host bridge %s\n", dev->full_name);194195hose = pcibios_alloc_controller(dev);196if (!hose)197return -ENOMEM;198199hose->first_busno = 0;200hose->last_busno = 0xff;201202setup_pa_pxp(hose);203204printk(KERN_INFO "Found PA-PXP PCI host bridge.\n");205206/* Interpret the "ranges" property */207pci_process_bridge_OF_ranges(hose, dev, 1);208209return 0;210}211212void __init pas_pci_init(void)213{214struct device_node *np, *root;215216root = of_find_node_by_path("/");217if (!root) {218printk(KERN_CRIT "pas_pci_init: can't find root "219"of device tree\n");220return;221}222223for (np = NULL; (np = of_get_next_child(root, np)) != NULL;)224if (np->name && !strcmp(np->name, "pxp") && !pas_add_bridge(np))225of_node_get(np);226227of_node_put(root);228229/* Setup the linkage between OF nodes and PHBs */230pci_devs_phb_init();231232/* Use the common resource allocation mechanism */233pci_probe_only = 1;234}235236void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset)237{238struct pci_controller *hose;239240hose = pci_bus_to_host(dev->bus);241242return (void __iomem *)pa_pxp_cfg_addr(hose, dev->bus->number, dev->devfn, offset);243}244245246