linux/arch/arm/mach-ixp23xx/pci.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-ixp23xx/pci.c
   3 *
   4 * PCI routines for IXP23XX based systems
   5 *
   6 * Copyright (c) 2005 MontaVista Software, Inc.
   7 *
   8 * based on original code:
   9 *
  10 * Author: Naeem Afzal <naeem.m.afzal@intel.com>
  11 * Copyright 2002-2005 Intel Corp.
  12 *
  13 * This program is free software; you can redistribute it and/or modify it
  14 * under the terms of the GNU General Public License as published by the
  15 * Free Software Foundation; either version 2 of the License, or (at your
  16 * option) any later version.
  17 */
  18
  19#include <linux/sched.h>
  20#include <linux/kernel.h>
  21#include <linux/pci.h>
  22#include <linux/interrupt.h>
  23#include <linux/mm.h>
  24#include <linux/init.h>
  25#include <linux/ioport.h>
  26#include <linux/delay.h>
  27#include <linux/io.h>
  28
  29#include <asm/irq.h>
  30#include <asm/sizes.h>
  31#include <asm/system.h>
  32#include <asm/mach/pci.h>
  33#include <mach/hardware.h>
  34
  35extern int (*external_fault) (unsigned long, struct pt_regs *);
  36
  37static volatile int pci_master_aborts = 0;
  38
  39#ifdef DEBUG
  40#define DBG(x...)       printk(x)
  41#else
  42#define DBG(x...)
  43#endif
  44
  45int clear_master_aborts(void);
  46
  47static u32
  48*ixp23xx_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
  49{
  50        u32 *paddress;
  51
  52        /*
  53         * Must be dword aligned
  54         */
  55        where &= ~3;
  56
  57        /*
  58         * For top bus, generate type 0, else type 1
  59         */
  60        if (!bus_nr) {
  61                if (PCI_SLOT(devfn) >= 8)
  62                        return 0;
  63
  64                paddress = (u32 *) (IXP23XX_PCI_CFG0_VIRT
  65                                    | (1 << (PCI_SLOT(devfn) + 16))
  66                                    | (PCI_FUNC(devfn) << 8) | where);
  67        } else {
  68                paddress = (u32 *) (IXP23XX_PCI_CFG1_VIRT
  69                                    | (bus_nr << 16)
  70                                    | (PCI_SLOT(devfn) << 11)
  71                                    | (PCI_FUNC(devfn) << 8) | where);
  72        }
  73
  74        return paddress;
  75}
  76
  77/*
  78 * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
  79 * 0 and 3 are not valid indexes...
  80 */
  81static u32 bytemask[] = {
  82        /*0*/   0,
  83        /*1*/   0xff,
  84        /*2*/   0xffff,
  85        /*3*/   0,
  86        /*4*/   0xffffffff,
  87};
  88
  89static int ixp23xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
  90                                int where, int size, u32 *value)
  91{
  92        u32 n;
  93        u32 *addr;
  94
  95        n = where % 4;
  96
  97        DBG("In config_read(%d) %d from dev %d:%d:%d\n", size, where,
  98                bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
  99
 100        addr = ixp23xx_pci_config_addr(bus->number, devfn, where);
 101        if (!addr)
 102                return PCIBIOS_DEVICE_NOT_FOUND;
 103
 104        pci_master_aborts = 0;
 105        *value = (*addr >> (8*n)) & bytemask[size];
 106        if (pci_master_aborts) {
 107                        pci_master_aborts = 0;
 108                        *value = 0xffffffff;
 109                        return PCIBIOS_DEVICE_NOT_FOUND;
 110                }
 111
 112        return PCIBIOS_SUCCESSFUL;
 113}
 114
 115/*
 116 * We don't do error checking on the address for writes.
 117 * It's assumed that the user checked for the device existing first
 118 * by doing a read first.
 119 */
 120static int ixp23xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
 121                                        int where, int size, u32 value)
 122{
 123        u32 mask;
 124        u32 *addr;
 125        u32 temp;
 126
 127        mask = ~(bytemask[size] << ((where % 0x4) * 8));
 128        addr = ixp23xx_pci_config_addr(bus->number, devfn, where);
 129        if (!addr)
 130                return PCIBIOS_DEVICE_NOT_FOUND;
 131        temp = (u32) (value) << ((where % 0x4) * 8);
 132        *addr = (*addr & mask) | temp;
 133
 134        clear_master_aborts();
 135
 136        return PCIBIOS_SUCCESSFUL;
 137}
 138
 139struct pci_ops ixp23xx_pci_ops = {
 140        .read   = ixp23xx_pci_read_config,
 141        .write  = ixp23xx_pci_write_config,
 142};
 143
 144struct pci_bus *ixp23xx_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
 145{
 146        return pci_scan_root_bus(NULL, sysdata->busnr, &ixp23xx_pci_ops,
 147                                 sysdata, &sysdata->resources);
 148}
 149
 150int ixp23xx_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 151{
 152        volatile unsigned long temp;
 153        unsigned long flags;
 154
 155        pci_master_aborts = 1;
 156
 157        local_irq_save(flags);
 158        temp = *IXP23XX_PCI_CONTROL;
 159
 160        /*
 161         * master abort and cmd tgt err
 162         */
 163        if (temp & ((1 << 8) | (1 << 5)))
 164                *IXP23XX_PCI_CONTROL = temp;
 165
 166        temp = *IXP23XX_PCI_CMDSTAT;
 167
 168        if (temp & (1 << 29))
 169                *IXP23XX_PCI_CMDSTAT = temp;
 170        local_irq_restore(flags);
 171
 172        /*
 173         * If it was an imprecise abort, then we need to correct the
 174         * return address to be _after_ the instruction.
 175         */
 176        if (fsr & (1 << 10))
 177                regs->ARM_pc += 4;
 178
 179        return 0;
 180}
 181
 182int clear_master_aborts(void)
 183{
 184        volatile u32 temp;
 185
 186        temp = *IXP23XX_PCI_CONTROL;
 187
 188        /*
 189         * master abort and cmd tgt err
 190         */
 191        if (temp & ((1 << 8) | (1 << 5)))
 192                *IXP23XX_PCI_CONTROL = temp;
 193
 194        temp = *IXP23XX_PCI_CMDSTAT;
 195
 196        if (temp & (1 << 29))
 197                *IXP23XX_PCI_CMDSTAT = temp;
 198
 199        return 0;
 200}
 201
 202static void __init ixp23xx_pci_common_init(void)
 203{
 204#ifdef __ARMEB__
 205        *IXP23XX_PCI_CONTROL |= 0x20000;        /* set I/O swapping */
 206#endif
 207        /*
 208         * ADDR_31 needs to be clear for PCI memory access to CPP memory
 209         */
 210        *IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_ADDR_31;
 211        *IXP23XX_CPP2XSI_CURR_XFER_REG3 |= IXP23XX_CPP2XSI_PSH_OFF;
 212
 213        /*
 214         * Select correct memory for PCI inbound transactions
 215         */
 216        if (ixp23xx_cpp_boot()) {
 217                *IXP23XX_PCI_CPP_ADDR_BITS &= ~(1 << 1);
 218        } else {
 219                *IXP23XX_PCI_CPP_ADDR_BITS |= (1 << 1);
 220
 221                /*
 222                 * Enable coherency on A2 silicon.
 223                 */
 224                if (arch_is_coherent())
 225                        *IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_COH_OFF;
 226        }
 227}
 228
 229void __init ixp23xx_pci_preinit(void)
 230{
 231        pcibios_min_io = 0;
 232        pcibios_min_mem = 0xe0000000;
 233
 234        pci_set_flags(0);
 235
 236        ixp23xx_pci_common_init();
 237
 238        hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS, 0,
 239                        "PCI config cycle to non-existent device");
 240
 241        *IXP23XX_PCI_ADDR_EXT = 0x0000e000;
 242}
 243
 244/*
 245 * Prevent PCI layer from seeing the inbound host-bridge resources
 246 */
 247static void __devinit pci_fixup_ixp23xx(struct pci_dev *dev)
 248{
 249        int i;
 250
 251        dev->class &= 0xff;
 252        dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
 253        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 254                dev->resource[i].start = 0;
 255                dev->resource[i].end   = 0;
 256                dev->resource[i].flags = 0;
 257        }
 258}
 259DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9002, pci_fixup_ixp23xx);
 260
 261/*
 262 * IXP2300 systems often have large resource requirements, so we just
 263 * use our own resource space.
 264 */
 265static struct resource ixp23xx_pci_mem_space = {
 266        .start  = IXP23XX_PCI_MEM_START,
 267        .end    = IXP23XX_PCI_MEM_START + IXP23XX_PCI_MEM_SIZE - 1,
 268        .flags  = IORESOURCE_MEM,
 269        .name   = "PCI Mem Space"
 270};
 271
 272static struct resource ixp23xx_pci_io_space = {
 273        .start  = 0x00000100,
 274        .end    = 0x01ffffff,
 275        .flags  = IORESOURCE_IO,
 276        .name   = "PCI I/O Space"
 277};
 278
 279int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys)
 280{
 281        if (nr >= 1)
 282                return 0;
 283
 284        pci_add_resource(&sys->resources, &ixp23xx_pci_io_space);
 285        pci_add_resource(&sys->resources, &ixp23xx_pci_mem_space);
 286
 287        return 1;
 288}
 289
 290void __init ixp23xx_pci_slave_init(void)
 291{
 292        ixp23xx_pci_common_init();
 293}
 294