linux/arch/arm/mach-ixp2000/pci.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-ixp2000/pci.c
   3 *
   4 * PCI routines for IXDP2400/IXDP2800 boards
   5 *
   6 * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
   7 * Maintained by: Deepak Saxena <dsaxena@plexity.net>
   8 *
   9 * Copyright 2002 Intel Corp.
  10 * Copyright (C) 2003-2004 MontaVista Software, Inc.
  11 *
  12 *  This program is free software; you can redistribute  it and/or modify it
  13 *  under  the terms of  the GNU General  Public License as published by the
  14 *  Free Software Foundation;  either version 2 of the  License, or (at your
  15 *  option) any later version.
  16 */
  17
  18#include <linux/sched.h>
  19#include <linux/kernel.h>
  20#include <linux/pci.h>
  21#include <linux/interrupt.h>
  22#include <linux/mm.h>
  23#include <linux/init.h>
  24#include <linux/ioport.h>
  25#include <linux/slab.h>
  26#include <linux/delay.h>
  27#include <linux/io.h>
  28
  29#include <asm/irq.h>
  30#include <asm/system.h>
  31#include <mach/hardware.h>
  32
  33#include <asm/mach/pci.h>
  34
  35static volatile int pci_master_aborts = 0;
  36
  37static int clear_master_aborts(void);
  38
  39u32 *
  40ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
  41{
  42        u32 *paddress;
  43
  44        if (PCI_SLOT(devfn) > 7)
  45                return 0;
  46
  47        /* Must be dword aligned */
  48        where &= ~3;
  49
  50        /*
  51         * For top bus, generate type 0, else type 1
  52         */
  53        if (!bus_nr) {
  54                /* only bits[23:16] are used for IDSEL */
  55                paddress = (u32 *) (IXP2000_PCI_CFG0_VIRT_BASE
  56                                    | (1 << (PCI_SLOT(devfn) + 16))
  57                                    | (PCI_FUNC(devfn) << 8) | where);
  58        } else {
  59                paddress = (u32 *) (IXP2000_PCI_CFG1_VIRT_BASE 
  60                                    | (bus_nr << 16)
  61                                    | (PCI_SLOT(devfn) << 11)
  62                                    | (PCI_FUNC(devfn) << 8) | where);
  63        }
  64
  65        return paddress;
  66}
  67
  68/*
  69 * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
  70 * 0 and 3 are not valid indexes...
  71 */
  72static u32 bytemask[] = {
  73        /*0*/   0,
  74        /*1*/   0xff,
  75        /*2*/   0xffff,
  76        /*3*/   0,
  77        /*4*/   0xffffffff,
  78};
  79
  80
  81int ixp2000_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where,
  82                                int size, u32 *value)
  83{
  84        u32 n;
  85        u32 *addr;
  86
  87        n = where % 4;
  88
  89        addr = ixp2000_pci_config_addr(bus->number, devfn, where);
  90        if (!addr)
  91                return PCIBIOS_DEVICE_NOT_FOUND;
  92
  93        pci_master_aborts = 0;
  94        *value = (*addr >> (8*n)) & bytemask[size];
  95        if (pci_master_aborts) {
  96                pci_master_aborts = 0;
  97                *value = 0xffffffff;
  98                return PCIBIOS_DEVICE_NOT_FOUND;
  99        }
 100
 101        return PCIBIOS_SUCCESSFUL;
 102}
 103
 104/*
 105 * We don't do error checks by calling clear_master_aborts() b/c the
 106 * assumption is that the caller did a read first to make sure a device
 107 * exists.
 108 */
 109int ixp2000_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where,
 110                                int size, u32 value)
 111{
 112        u32 mask;
 113        u32 *addr;
 114        u32 temp;
 115
 116        mask = ~(bytemask[size] << ((where % 0x4) * 8));
 117        addr = ixp2000_pci_config_addr(bus->number, devfn, where);
 118        if (!addr)
 119                return PCIBIOS_DEVICE_NOT_FOUND;
 120        temp = (u32) (value) << ((where % 0x4) * 8);
 121        *addr = (*addr & mask) | temp;
 122
 123        clear_master_aborts();
 124
 125        return PCIBIOS_SUCCESSFUL;
 126}
 127
 128
 129static struct pci_ops ixp2000_pci_ops = {
 130        .read   = ixp2000_pci_read_config,
 131        .write  = ixp2000_pci_write_config
 132};
 133
 134struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
 135{
 136        return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata);
 137}
 138
 139
 140int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 141{
 142
 143        volatile u32 temp;
 144        unsigned long flags;
 145
 146        pci_master_aborts = 1;
 147
 148        local_irq_save(flags);
 149        temp = *(IXP2000_PCI_CONTROL);
 150        if (temp & ((1 << 8) | (1 << 5))) {
 151                ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
 152        }
 153
 154        temp = *(IXP2000_PCI_CMDSTAT);
 155        if (temp & (1 << 29)) {
 156                while (temp & (1 << 29)) {      
 157                        ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
 158                        temp = *(IXP2000_PCI_CMDSTAT);
 159                }
 160        }
 161        local_irq_restore(flags);
 162
 163        /*
 164         * If it was an imprecise abort, then we need to correct the
 165         * return address to be _after_ the instruction.
 166         */
 167        if (fsr & (1 << 10))
 168                regs->ARM_pc += 4;
 169
 170        return 0;
 171}
 172
 173int
 174clear_master_aborts(void)
 175{
 176        volatile u32 temp;
 177        unsigned long flags;
 178
 179        local_irq_save(flags);
 180        temp = *(IXP2000_PCI_CONTROL);
 181        if (temp & ((1 << 8) | (1 << 5))) {
 182                ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
 183        }
 184
 185        temp = *(IXP2000_PCI_CMDSTAT);
 186        if (temp & (1 << 29)) {
 187                while (temp & (1 << 29)) {
 188                        ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
 189                        temp = *(IXP2000_PCI_CMDSTAT);
 190                }
 191        }
 192        local_irq_restore(flags);
 193
 194        return 0;
 195}
 196
 197void __init
 198ixp2000_pci_preinit(void)
 199{
 200#ifndef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
 201        /*
 202         * Configure the PCI unit to properly byteswap I/O transactions,
 203         * and verify that it worked.
 204         */
 205        ixp2000_reg_write(IXP2000_PCI_CONTROL,
 206                          (*IXP2000_PCI_CONTROL | PCI_CONTROL_IEE));
 207
 208        if ((*IXP2000_PCI_CONTROL & PCI_CONTROL_IEE) == 0)
 209                panic("IXP2000: PCI I/O is broken on this ixp model, and "
 210                        "the needed workaround has not been configured in");
 211#endif
 212
 213        hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS,
 214                                "PCI config cycle to non-existent device");
 215}
 216
 217
 218/*
 219 * IXP2000 systems often have large resource requirements, so we just
 220 * use our own resource space.
 221 */
 222static struct resource ixp2000_pci_mem_space = {
 223        .start  = 0xe0000000,
 224        .end    = 0xffffffff,
 225        .flags  = IORESOURCE_MEM,
 226        .name   = "PCI Mem Space"
 227};
 228
 229static struct resource ixp2000_pci_io_space = {
 230        .start  = 0x00010000,
 231        .end    = 0x0001ffff,
 232        .flags  = IORESOURCE_IO,
 233        .name   = "PCI I/O Space"
 234};
 235
 236int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
 237{
 238        if (nr >= 1)
 239                return 0;
 240
 241        sys->resource[0] = &ixp2000_pci_io_space;
 242        sys->resource[1] = &ixp2000_pci_mem_space;
 243        sys->resource[2] = NULL;
 244
 245        return 1;
 246}
 247
 248
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.