2  * Copyright (C) 1999, 2000, 2004, 2005  MIPS Technologies, Inc.
 
   4  *    Authors: Carsten Langgaard <carstenl@mips.com>
 
   5  *             Maciej W. Rozycki <macro@mips.com>
 
   6  * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
 
   8  *  This program is free software; you can distribute it and/or modify it
 
   9  *  under the terms of the GNU General Public License (Version 2) as
 
  10  *  published by the Free Software Foundation.
 
  12  *  This program is distributed in the hope it will be useful, but WITHOUT
 
  13  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
  14  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
  17  *  You should have received a copy of the GNU General Public License along
 
  18  *  with this program; if not, write to the Free Software Foundation, Inc.,
 
  19  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 
  21  * MIPS boards specific PCI support.
 
  24 #include <linux/types.h>
 
  25 #include <linux/pci.h>
 
  26 #include <linux/kernel.h>
 
  27 #include <linux/init.h>
 
  29 #include <asm/mips-boards/msc01_pci.h>
 
  31 #define PCI_ACCESS_READ  0
 
  32 #define PCI_ACCESS_WRITE 1
 
  35  *  PCI configuration cycle AD bus definition
 
  38 #define PCI_CFG_TYPE0_REG_SHF           0
 
  39 #define PCI_CFG_TYPE0_FUNC_SHF          8
 
  42 #define PCI_CFG_TYPE1_REG_SHF           0
 
  43 #define PCI_CFG_TYPE1_FUNC_SHF          8
 
  44 #define PCI_CFG_TYPE1_DEV_SHF           11
 
  45 #define PCI_CFG_TYPE1_BUS_SHF           16
 
  47 static int msc_pcibios_config_access(unsigned char access_type,
 
  48         struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
 
  50         unsigned char busnum = bus->number;
 
  53         /* Clear status register bits. */
 
  54         MSC_WRITE(MSC01_PCI_INTSTAT,
 
  55                   (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT));
 
  57         MSC_WRITE(MSC01_PCI_CFGADDR,
 
  58                   ((busnum << MSC01_PCI_CFGADDR_BNUM_SHF) |
 
  59                    (PCI_SLOT(devfn) << MSC01_PCI_CFGADDR_DNUM_SHF) |
 
  60                    (PCI_FUNC(devfn) << MSC01_PCI_CFGADDR_FNUM_SHF) |
 
  61                    ((where / 4) << MSC01_PCI_CFGADDR_RNUM_SHF)));
 
  64         if (access_type == PCI_ACCESS_WRITE)
 
  65                 MSC_WRITE(MSC01_PCI_CFGDATA, *data);
 
  67                 MSC_READ(MSC01_PCI_CFGDATA, *data);
 
  69         /* Detect Master/Target abort */
 
  70         MSC_READ(MSC01_PCI_INTSTAT, intr);
 
  71         if (intr & (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT)) {
 
  75                 MSC_WRITE(MSC01_PCI_INTSTAT,
 
  76                           (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT));
 
  86  * We can't address 8 and 16 bit words directly.  Instead we have to
 
  87  * read/write a 32bit word and mask/modify the data we actually want.
 
  89 static int msc_pcibios_read(struct pci_bus *bus, unsigned int devfn,
 
  90                              int where, int size, u32 * val)
 
  94         if ((size == 2) && (where & 1))
 
  95                 return PCIBIOS_BAD_REGISTER_NUMBER;
 
  96         else if ((size == 4) && (where & 3))
 
  97                 return PCIBIOS_BAD_REGISTER_NUMBER;
 
  99         if (msc_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
 
 104                 *val = (data >> ((where & 3) << 3)) & 0xff;
 
 106                 *val = (data >> ((where & 3) << 3)) & 0xffff;
 
 110         return PCIBIOS_SUCCESSFUL;
 
 113 static int msc_pcibios_write(struct pci_bus *bus, unsigned int devfn,
 
 114                               int where, int size, u32 val)
 
 118         if ((size == 2) && (where & 1))
 
 119                 return PCIBIOS_BAD_REGISTER_NUMBER;
 
 120         else if ((size == 4) && (where & 3))
 
 121                 return PCIBIOS_BAD_REGISTER_NUMBER;
 
 126                 if (msc_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
 
 131                         data = (data & ~(0xff << ((where & 3) << 3))) |
 
 132                                 (val << ((where & 3) << 3));
 
 134                         data = (data & ~(0xffff << ((where & 3) << 3))) |
 
 135                                 (val << ((where & 3) << 3));
 
 138         if (msc_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
 
 142         return PCIBIOS_SUCCESSFUL;
 
 145 struct pci_ops msc_pci_ops = {
 
 146         .read = msc_pcibios_read,
 
 147         .write = msc_pcibios_write