linux/arch/mips/pci/pci-bcm1480.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2001,2002,2005 Broadcom Corporation
   3 * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License
   7 * as published by the Free Software Foundation; either version 2
   8 * of the License, or (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18 */
  19
  20/*
  21 * BCM1x80/1x55-specific PCI support
  22 *
  23 * This module provides the glue between Linux's PCI subsystem
  24 * and the hardware.  We basically provide glue for accessing
  25 * configuration space, and set up the translation for I/O
  26 * space accesses.
  27 *
  28 * To access configuration space, we use ioremap.  In the 32-bit
  29 * kernel, this consumes either 4 or 8 page table pages, and 16MB of
  30 * kernel mapped memory.  Hopefully neither of these should be a huge
  31 * problem.
  32 *
  33 * XXX: AT THIS TIME, ONLY the NATIVE PCI-X INTERFACE IS SUPPORTED.
  34 */
  35#include <linux/types.h>
  36#include <linux/pci.h>
  37#include <linux/kernel.h>
  38#include <linux/init.h>
  39#include <linux/mm.h>
  40#include <linux/console.h>
  41#include <linux/tty.h>
  42
  43#include <asm/sibyte/bcm1480_regs.h>
  44#include <asm/sibyte/bcm1480_scd.h>
  45#include <asm/sibyte/board.h>
  46#include <asm/io.h>
  47
  48/*
  49 * Macros for calculating offsets into config space given a device
  50 * structure or dev/fun/reg
  51 */
  52#define CFGOFFSET(bus, devfn, where) (((bus)<<16)+((devfn)<<8)+(where))
  53#define CFGADDR(bus, devfn, where)   CFGOFFSET((bus)->number, (devfn), where)
  54
  55static void *cfg_space;
  56
  57#define PCI_BUS_ENABLED 1
  58#define PCI_DEVICE_MODE 2
  59
  60static int bcm1480_bus_status;
  61
  62#define PCI_BRIDGE_DEVICE  0
  63
  64/*
  65 * Read/write 32-bit values in config space.
  66 */
  67static inline u32 READCFG32(u32 addr)
  68{
  69        return *(u32 *)(cfg_space + (addr&~3));
  70}
  71
  72static inline void WRITECFG32(u32 addr, u32 data)
  73{
  74        *(u32 *)(cfg_space + (addr & ~3)) = data;
  75}
  76
  77int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
  78{
  79        if (pin == 0)
  80                return -1;
  81
  82        return K_BCM1480_INT_PCI_INTA - 1 + pin;
  83}
  84
  85/* Do platform specific device initialization at pci_enable_device() time */
  86int pcibios_plat_dev_init(struct pci_dev *dev)
  87{
  88        return 0;
  89}
  90
  91/*
  92 * Some checks before doing config cycles:
  93 * In PCI Device Mode, hide everything on bus 0 except the LDT host
  94 * bridge.  Otherwise, access is controlled by bridge MasterEn bits.
  95 */
  96static int bcm1480_pci_can_access(struct pci_bus *bus, int devfn)
  97{
  98        u32 devno;
  99
 100        if (!(bcm1480_bus_status & (PCI_BUS_ENABLED | PCI_DEVICE_MODE)))
 101                return 0;
 102
 103        if (bus->number == 0) {
 104                devno = PCI_SLOT(devfn);
 105                if (bcm1480_bus_status & PCI_DEVICE_MODE)
 106                        return 0;
 107                else
 108                        return 1;
 109        } else
 110                return 1;
 111}
 112
 113/*
 114 * Read/write access functions for various sizes of values
 115 * in config space.  Return all 1's for disallowed accesses
 116 * for a kludgy but adequate simulation of master aborts.
 117 */
 118
 119static int bcm1480_pcibios_read(struct pci_bus *bus, unsigned int devfn,
 120                                int where, int size, u32 * val)
 121{
 122        u32 data = 0;
 123
 124        if ((size == 2) && (where & 1))
 125                return PCIBIOS_BAD_REGISTER_NUMBER;
 126        else if ((size == 4) && (where & 3))
 127                return PCIBIOS_BAD_REGISTER_NUMBER;
 128
 129        if (bcm1480_pci_can_access(bus, devfn))
 130                data = READCFG32(CFGADDR(bus, devfn, where));
 131        else
 132                data = 0xFFFFFFFF;
 133
 134        if (size == 1)
 135                *val = (data >> ((where & 3) << 3)) & 0xff;
 136        else if (size == 2)
 137                *val = (data >> ((where & 3) << 3)) & 0xffff;
 138        else
 139                *val = data;
 140
 141        return PCIBIOS_SUCCESSFUL;
 142}
 143
 144static int bcm1480_pcibios_write(struct pci_bus *bus, unsigned int devfn,
 145                                int where, int size, u32 val)
 146{
 147        u32 cfgaddr = CFGADDR(bus, devfn, where);
 148        u32 data = 0;
 149
 150        if ((size == 2) && (where & 1))
 151                return PCIBIOS_BAD_REGISTER_NUMBER;
 152        else if ((size == 4) && (where & 3))
 153                return PCIBIOS_BAD_REGISTER_NUMBER;
 154
 155        if (!bcm1480_pci_can_access(bus, devfn))
 156                return PCIBIOS_BAD_REGISTER_NUMBER;
 157
 158        data = READCFG32(cfgaddr);
 159
 160        if (size == 1)
 161                data = (data & ~(0xff << ((where & 3) << 3))) |
 162                    (val << ((where & 3) << 3));
 163        else if (size == 2)
 164                data = (data & ~(0xffff << ((where & 3) << 3))) |
 165                    (val << ((where & 3) << 3));
 166        else
 167                data = val;
 168
 169        WRITECFG32(cfgaddr, data);
 170
 171        return PCIBIOS_SUCCESSFUL;
 172}
 173
 174struct pci_ops bcm1480_pci_ops = {
 175        bcm1480_pcibios_read,
 176        bcm1480_pcibios_write,
 177};
 178
 179static struct resource bcm1480_mem_resource = {
 180        .name   = "BCM1480 PCI MEM",
 181        .start  = A_BCM1480_PHYS_PCI_MEM_MATCH_BYTES,
 182        .end    = A_BCM1480_PHYS_PCI_MEM_MATCH_BYTES + 0xfffffffUL,
 183        .flags  = IORESOURCE_MEM,
 184};
 185
 186static struct resource bcm1480_io_resource = {
 187        .name   = "BCM1480 PCI I/O",
 188        .start  = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES,
 189        .end    = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES + 0x1ffffffUL,
 190        .flags  = IORESOURCE_IO,
 191};
 192
 193struct pci_controller bcm1480_controller = {
 194        .pci_ops        = &bcm1480_pci_ops,
 195        .mem_resource   = &bcm1480_mem_resource,
 196        .io_resource    = &bcm1480_io_resource,
 197        .io_offset      = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES,
 198};
 199
 200
 201static int __init bcm1480_pcibios_init(void)
 202{
 203        uint32_t cmdreg;
 204        uint64_t reg;
 205
 206        /* CFE will assign PCI resources */
 207        pci_probe_only = 1;
 208
 209        /* Avoid ISA compat ranges.  */
 210        PCIBIOS_MIN_IO = 0x00008000UL;
 211        PCIBIOS_MIN_MEM = 0x01000000UL;
 212
 213        /* Set I/O resource limits. - unlimited for now to accomodate HT */
 214        ioport_resource.end = 0xffffffffUL;
 215        iomem_resource.end = 0xffffffffUL;
 216
 217        cfg_space = ioremap(A_BCM1480_PHYS_PCI_CFG_MATCH_BITS, 16*1024*1024);
 218
 219        /*
 220         * See if the PCI bus has been configured by the firmware.
 221         */
 222        reg = __raw_readq(IOADDR(A_SCD_SYSTEM_CFG));
 223        if (!(reg & M_BCM1480_SYS_PCI_HOST)) {
 224                bcm1480_bus_status |= PCI_DEVICE_MODE;
 225        } else {
 226                cmdreg = READCFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0),
 227                                             PCI_COMMAND));
 228                if (!(cmdreg & PCI_COMMAND_MASTER)) {
 229                        printk
 230                            ("PCI: Skipping PCI probe.  Bus is not initialized.\n");
 231                        iounmap(cfg_space);
 232                        return 1; /* XXX */
 233                }
 234                bcm1480_bus_status |= PCI_BUS_ENABLED;
 235        }
 236
 237        /* turn on ExpMemEn */
 238        cmdreg = READCFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0), 0x40));
 239        WRITECFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0), 0x40),
 240                        cmdreg | 0x10);
 241        cmdreg = READCFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0), 0x40));
 242
 243        /*
 244         * Establish mappings in KSEG2 (kernel virtual) to PCI I/O
 245         * space.  Use "match bytes" policy to make everything look
 246         * little-endian.  So, you need to also set
 247         * CONFIG_SWAP_IO_SPACE, but this is the combination that
 248         * works correctly with most of Linux's drivers.
 249         * XXX ehs: Should this happen in PCI Device mode?
 250         */
 251
 252        bcm1480_controller.io_map_base = (unsigned long)
 253                ioremap(A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, 65536);
 254        bcm1480_controller.io_map_base -= bcm1480_controller.io_offset;
 255        set_io_port_base(bcm1480_controller.io_map_base);
 256
 257        register_pci_controller(&bcm1480_controller);
 258
 259#ifdef CONFIG_VGA_CONSOLE
 260        take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
 261#endif
 262        return 0;
 263}
 264
 265arch_initcall(bcm1480_pcibios_init);
 266