linux/arch/mips/pci/ops-sni.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * SNI specific PCI support for RM200/RM300.
   7 *
   8 * Copyright (C) 1997 - 2000, 2003 Ralf Baechle <ralf@linux-mips.org>
   9 */
  10#include <linux/kernel.h>
  11#include <linux/pci.h>
  12#include <linux/types.h>
  13#include <asm/sni.h>
  14
  15/*
  16 * It seems that on the RM200 only lower 3 bits of the 5 bit PCI device
  17 * address are decoded.  We therefore manually have to reject attempts at
  18 * reading outside this range.  Being on the paranoid side we only do this
  19 * test for bus 0 and hope forwarding and decoding work properly for any
  20 * subordinated busses.
  21 *
  22 * ASIC PCI only supports type 1 config cycles.
  23 */
  24static int set_config_address(unsigned int busno, unsigned int devfn, int reg)
  25{
  26        if ((devfn > 255) || (reg > 255))
  27                return PCIBIOS_BAD_REGISTER_NUMBER;
  28
  29        if (busno == 0 && devfn >= PCI_DEVFN(8, 0))
  30                return PCIBIOS_DEVICE_NOT_FOUND;
  31
  32        *(volatile u32 *)PCIMT_CONFIG_ADDRESS =
  33                 ((busno    & 0xff) << 16) |
  34                 ((devfn    & 0xff) <<  8) |
  35                  (reg      & 0xfc);
  36
  37        return PCIBIOS_SUCCESSFUL;
  38}
  39
  40static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg,
  41                      int size, u32 * val)
  42{
  43        int res;
  44
  45        if ((res = set_config_address(bus->number, devfn, reg)))
  46                return res;
  47
  48        switch (size) {
  49        case 1:
  50                *val = inb(PCIMT_CONFIG_DATA + (reg & 3));
  51                break;
  52        case 2:
  53                *val = inw(PCIMT_CONFIG_DATA + (reg & 2));
  54                break;
  55        case 4:
  56                *val = inl(PCIMT_CONFIG_DATA);
  57                break;
  58        }
  59
  60        return 0;
  61}
  62
  63static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg,
  64                       int size, u32 val)
  65{
  66        int res;
  67
  68        if ((res = set_config_address(bus->number, devfn, reg)))
  69                return res;
  70
  71        switch (size) {
  72        case 1:
  73                outb(val, PCIMT_CONFIG_DATA + (reg & 3));
  74                break;
  75        case 2:
  76                outw(val, PCIMT_CONFIG_DATA + (reg & 2));
  77                break;
  78        case 4:
  79                outl(val, PCIMT_CONFIG_DATA);
  80                break;
  81        }
  82
  83        return 0;
  84}
  85
  86struct pci_ops sni_pcimt_ops = {
  87        .read = pcimt_read,
  88        .write = pcimt_write,
  89};
  90
  91static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg)
  92{
  93        if ((devfn > 255) || (reg > 255) || (busno > 255))
  94                return PCIBIOS_BAD_REGISTER_NUMBER;
  95
  96        outl((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8);
  97        return PCIBIOS_SUCCESSFUL;
  98}
  99
 100static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg,
 101                      int size, u32 * val)
 102{
 103        int res;
 104
 105        /*
 106         * on bus 0 we need to check, whether there is a device answering
 107         * for the devfn by doing a config write and checking the result. If
 108         * we don't do it, we will get a data bus error
 109         */
 110        if (bus->number == 0) {
 111                pcit_set_config_address(0, 0, 0x68);
 112                outl(inl(0xcfc) | 0xc0000000, 0xcfc);
 113                if ((res = pcit_set_config_address(0, devfn, 0)))
 114                        return res;
 115                outl(0xffffffff, 0xcfc);
 116                pcit_set_config_address(0, 0, 0x68);
 117                if (inl(0xcfc) & 0x100000)
 118                        return PCIBIOS_DEVICE_NOT_FOUND;
 119        }
 120        if ((res = pcit_set_config_address(bus->number, devfn, reg)))
 121                return res;
 122
 123        switch (size) {
 124        case 1:
 125                *val = inb(PCIMT_CONFIG_DATA + (reg & 3));
 126                break;
 127        case 2:
 128                *val = inw(PCIMT_CONFIG_DATA + (reg & 2));
 129                break;
 130        case 4:
 131                *val = inl(PCIMT_CONFIG_DATA);
 132                break;
 133        }
 134        return 0;
 135}
 136
 137static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg,
 138                       int size, u32 val)
 139{
 140        int res;
 141
 142        if ((res = pcit_set_config_address(bus->number, devfn, reg)))
 143                return res;
 144
 145        switch (size) {
 146        case 1:
 147                outb(val, PCIMT_CONFIG_DATA + (reg & 3));
 148                break;
 149        case 2:
 150                outw(val, PCIMT_CONFIG_DATA + (reg & 2));
 151                break;
 152        case 4:
 153                outl(val, PCIMT_CONFIG_DATA);
 154                break;
 155        }
 156
 157        return 0;
 158}
 159
 160
 161struct pci_ops sni_pcit_ops = {
 162        .read = pcit_read,
 163        .write = pcit_write,
 164};
 165