linux/arch/mips/pci/ops-tx3927.c
<<
>>
Prefs
   1/*
   2 * Copyright 2001 MontaVista Software Inc.
   3 * Author: MontaVista Software, Inc.
   4 *              ahennessy@mvista.com
   5 *
   6 * Copyright (C) 2000-2001 Toshiba Corporation
   7 * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
   8 *
   9 * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c
  10 *
  11 *     Define the pci_ops for TX3927.
  12 *
  13 * Much of the code is derived from the original DDB5074 port by
  14 * Geert Uytterhoeven <geert@linux-m68k.org>
  15 *
  16 *  This program is free software; you can redistribute  it and/or modify it
  17 *  under  the terms of  the GNU General  Public License as published by the
  18 *  Free Software Foundation;  either version 2 of the  License, or (at your
  19 *  option) any later version.
  20 *
  21 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
  22 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
  23 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  24 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
  25 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  26 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
  27 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  28 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
  29 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  30 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31 *
  32 *  You should have received a copy of the  GNU General Public License along
  33 *  with this program; if not, write  to the Free Software Foundation, Inc.,
  34 *  675 Mass Ave, Cambridge, MA 02139, USA.
  35 */
  36#include <linux/types.h>
  37#include <linux/pci.h>
  38#include <linux/kernel.h>
  39#include <linux/init.h>
  40#include <linux/interrupt.h>
  41#include <linux/irq.h>
  42
  43#include <asm/addrspace.h>
  44#include <asm/txx9irq.h>
  45#include <asm/txx9/pci.h>
  46#include <asm/txx9/tx3927.h>
  47
  48static int mkaddr(struct pci_bus *bus, unsigned char devfn, unsigned char where)
  49{
  50        if (bus->parent == NULL &&
  51            devfn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0))
  52                return -1;
  53        tx3927_pcicptr->ica =
  54                ((bus->number & 0xff) << 0x10) |
  55                ((devfn & 0xff) << 0x08) |
  56                (where & 0xfc) | (bus->parent ? 1 : 0);
  57
  58        /* clear M_ABORT and Disable M_ABORT Int. */
  59        tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
  60        tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT;
  61        return 0;
  62}
  63
  64static inline int check_abort(void)
  65{
  66        if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) {
  67                tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
  68                tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT;
  69                /* flush write buffer */
  70                iob();
  71                return PCIBIOS_DEVICE_NOT_FOUND;
  72        }
  73        return PCIBIOS_SUCCESSFUL;
  74}
  75
  76static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn,
  77        int where, int size, u32 * val)
  78{
  79        if (mkaddr(bus, devfn, where)) {
  80                *val = 0xffffffff;
  81                return PCIBIOS_DEVICE_NOT_FOUND;
  82        }
  83
  84        switch (size) {
  85        case 1:
  86                *val = *(volatile u8 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3));
  87                break;
  88
  89        case 2:
  90                *val = le16_to_cpu(*(volatile u16 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3)));
  91                break;
  92
  93        case 4:
  94                *val = le32_to_cpu(tx3927_pcicptr->icd);
  95                break;
  96        }
  97
  98        return check_abort();
  99}
 100
 101static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn,
 102        int where, int size, u32 val)
 103{
 104        if (mkaddr(bus, devfn, where))
 105                return PCIBIOS_DEVICE_NOT_FOUND;
 106
 107        switch (size) {
 108        case 1:
 109                *(volatile u8 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3)) = val;
 110                break;
 111
 112        case 2:
 113                *(volatile u16 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 2)) =
 114            cpu_to_le16(val);
 115                break;
 116
 117        case 4:
 118                tx3927_pcicptr->icd = cpu_to_le32(val);
 119        }
 120
 121        return check_abort();
 122}
 123
 124static struct pci_ops tx3927_pci_ops = {
 125        .read = tx3927_pci_read_config,
 126        .write = tx3927_pci_write_config,
 127};
 128
 129void __init tx3927_pcic_setup(struct pci_controller *channel,
 130                              unsigned long sdram_size, int extarb)
 131{
 132        unsigned long flags;
 133        unsigned long io_base =
 134                channel->io_resource->start + mips_io_port_base - IO_BASE;
 135        unsigned long io_size =
 136                channel->io_resource->end - channel->io_resource->start;
 137        unsigned long io_pciaddr =
 138                channel->io_resource->start - channel->io_offset;
 139        unsigned long mem_base =
 140                channel->mem_resource->start;
 141        unsigned long mem_size =
 142                channel->mem_resource->end - channel->mem_resource->start;
 143        unsigned long mem_pciaddr =
 144                channel->mem_resource->start - channel->mem_offset;
 145
 146        printk(KERN_INFO "TX3927 PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:%s",
 147               tx3927_pcicptr->did, tx3927_pcicptr->vid,
 148               tx3927_pcicptr->rid,
 149               extarb ? "External" : "Internal");
 150        channel->pci_ops = &tx3927_pci_ops;
 151
 152        local_irq_save(flags);
 153        /* Disable External PCI Config. Access */
 154        tx3927_pcicptr->lbc = TX3927_PCIC_LBC_EPCAD;
 155#ifdef __BIG_ENDIAN
 156        tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_IBSE |
 157                TX3927_PCIC_LBC_TIBSE |
 158                TX3927_PCIC_LBC_TMFBSE | TX3927_PCIC_LBC_MSDSE;
 159#endif
 160        /* LB->PCI mappings */
 161        tx3927_pcicptr->iomas = ~(io_size - 1);
 162        tx3927_pcicptr->ilbioma = io_base;
 163        tx3927_pcicptr->ipbioma = io_pciaddr;
 164        tx3927_pcicptr->mmas = ~(mem_size - 1);
 165        tx3927_pcicptr->ilbmma = mem_base;
 166        tx3927_pcicptr->ipbmma = mem_pciaddr;
 167        /* PCI->LB mappings */
 168        tx3927_pcicptr->iobas = 0xffffffff;
 169        tx3927_pcicptr->ioba = 0;
 170        tx3927_pcicptr->tlbioma = 0;
 171        tx3927_pcicptr->mbas = ~(sdram_size - 1);
 172        tx3927_pcicptr->mba = 0;
 173        tx3927_pcicptr->tlbmma = 0;
 174        /* Enable Direct mapping Address Space Decoder */
 175        tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_ILMDE | TX3927_PCIC_LBC_ILIDE;
 176
 177        /* Clear All Local Bus Status */
 178        tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL;
 179        /* Enable All Local Bus Interrupts */
 180        tx3927_pcicptr->lbim = TX3927_PCIC_LBIM_ALL;
 181        /* Clear All PCI Status Error */
 182        tx3927_pcicptr->pcistat = TX3927_PCIC_PCISTATIM_ALL;
 183        /* Enable All PCI Status Error Interrupts */
 184        tx3927_pcicptr->pcistatim = TX3927_PCIC_PCISTATIM_ALL;
 185
 186        /* PCIC Int => IRC IRQ10 */
 187        tx3927_pcicptr->il = TX3927_IR_PCI;
 188        /* Target Control (per errata) */
 189        tx3927_pcicptr->tc = TX3927_PCIC_TC_OF8E | TX3927_PCIC_TC_IF8E;
 190
 191        /* Enable Bus Arbiter */
 192        if (!extarb)
 193                tx3927_pcicptr->pbapmc = TX3927_PCIC_PBAPMC_PBAEN;
 194
 195        tx3927_pcicptr->pcicmd = PCI_COMMAND_MASTER |
 196                PCI_COMMAND_MEMORY |
 197                PCI_COMMAND_IO |
 198                PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
 199        local_irq_restore(flags);
 200}
 201
 202static irqreturn_t tx3927_pcierr_interrupt(int irq, void *dev_id)
 203{
 204        struct pt_regs *regs = get_irq_regs();
 205
 206        if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) {
 207                printk(KERN_WARNING "PCI error interrupt at 0x%08lx.\n",
 208                       regs->cp0_epc);
 209                printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n",
 210                       tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat);
 211        }
 212        if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) {
 213                /* clear all pci errors */
 214                tx3927_pcicptr->pcistat |= TX3927_PCIC_PCISTATIM_ALL;
 215                tx3927_pcicptr->istat = TX3927_PCIC_IIM_ALL;
 216                tx3927_pcicptr->tstat = TX3927_PCIC_TIM_ALL;
 217                tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL;
 218                return IRQ_HANDLED;
 219        }
 220        console_verbose();
 221        panic("PCI error.");
 222}
 223
 224void __init tx3927_setup_pcierr_irq(void)
 225{
 226        if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI,
 227                        tx3927_pcierr_interrupt,
 228                        0, "PCI error",
 229                        (void *)TX3927_PCIC_REG))
 230                printk(KERN_WARNING "Failed to request irq for PCIERR\n");
 231}
 232