linux/arch/mips/mti-malta/malta-pci.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 1999, 2000, 2004, 2005  MIPS Technologies, Inc.
   3 *      All rights reserved.
   4 *      Authors: Carsten Langgaard <carstenl@mips.com>
   5 *               Maciej W. Rozycki <macro@mips.com>
   6 *
   7 * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
   8 *
   9 *  This program is free software; you can distribute it and/or modify it
  10 *  under the terms of the GNU General Public License (Version 2) as
  11 *  published by the Free Software Foundation.
  12 *
  13 *  This program is distributed in the hope it will be useful, but WITHOUT
  14 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16 *  for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License along
  19 *  with this program; if not, write to the Free Software Foundation, Inc.,
  20 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  21 *
  22 * MIPS boards specific PCI support.
  23 */
  24#include <linux/types.h>
  25#include <linux/pci.h>
  26#include <linux/kernel.h>
  27#include <linux/init.h>
  28
  29#include <asm/gt64120.h>
  30#include <asm/gcmpregs.h>
  31#include <asm/mips-boards/generic.h>
  32#include <asm/mips-boards/bonito64.h>
  33#include <asm/mips-boards/msc01_pci.h>
  34
  35static struct resource bonito64_mem_resource = {
  36        .name   = "Bonito PCI MEM",
  37        .flags  = IORESOURCE_MEM,
  38};
  39
  40static struct resource bonito64_io_resource = {
  41        .name   = "Bonito PCI I/O",
  42        .start  = 0x00000000UL,
  43        .end    = 0x000fffffUL,
  44        .flags  = IORESOURCE_IO,
  45};
  46
  47static struct resource gt64120_mem_resource = {
  48        .name   = "GT-64120 PCI MEM",
  49        .flags  = IORESOURCE_MEM,
  50};
  51
  52static struct resource gt64120_io_resource = {
  53        .name   = "GT-64120 PCI I/O",
  54        .flags  = IORESOURCE_IO,
  55};
  56
  57static struct resource msc_mem_resource = {
  58        .name   = "MSC PCI MEM",
  59        .flags  = IORESOURCE_MEM,
  60};
  61
  62static struct resource msc_io_resource = {
  63        .name   = "MSC PCI I/O",
  64        .flags  = IORESOURCE_IO,
  65};
  66
  67extern struct pci_ops bonito64_pci_ops;
  68extern struct pci_ops gt64xxx_pci0_ops;
  69extern struct pci_ops msc_pci_ops;
  70
  71static struct pci_controller bonito64_controller = {
  72        .pci_ops        = &bonito64_pci_ops,
  73        .io_resource    = &bonito64_io_resource,
  74        .mem_resource   = &bonito64_mem_resource,
  75        .io_offset      = 0x00000000UL,
  76};
  77
  78static struct pci_controller gt64120_controller = {
  79        .pci_ops        = &gt64xxx_pci0_ops,
  80        .io_resource    = &gt64120_io_resource,
  81        .mem_resource   = &gt64120_mem_resource,
  82};
  83
  84static struct pci_controller msc_controller = {
  85        .pci_ops        = &msc_pci_ops,
  86        .io_resource    = &msc_io_resource,
  87        .mem_resource   = &msc_mem_resource,
  88};
  89
  90void __init mips_pcibios_init(void)
  91{
  92        struct pci_controller *controller;
  93        resource_size_t start, end, map, start1, end1, map1, map2, map3, mask;
  94
  95        switch (mips_revision_sconid) {
  96        case MIPS_REVISION_SCON_GT64120:
  97                /*
  98                 * Due to a bug in the Galileo system controller, we need
  99                 * to setup the PCI BAR for the Galileo internal registers.
 100                 * This should be done in the bios/bootprom and will be
 101                 * fixed in a later revision of YAMON (the MIPS boards
 102                 * boot prom).
 103                 */
 104                GT_WRITE(GT_PCI0_CFGADDR_OFS,
 105                         (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
 106                         (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */
 107                         (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/
 108                         ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/
 109                         GT_PCI0_CFGADDR_CONFIGEN_BIT);
 110
 111                /* Perform the write */
 112                GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE));
 113
 114                /* Set up resource ranges from the controller's registers.  */
 115                start = GT_READ(GT_PCI0M0LD_OFS);
 116                end = GT_READ(GT_PCI0M0HD_OFS);
 117                map = GT_READ(GT_PCI0M0REMAP_OFS);
 118                end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
 119                start1 = GT_READ(GT_PCI0M1LD_OFS);
 120                end1 = GT_READ(GT_PCI0M1HD_OFS);
 121                map1 = GT_READ(GT_PCI0M1REMAP_OFS);
 122                end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK);
 123                /* Cannot support multiple windows, use the wider.  */
 124                if (end1 - start1 > end - start) {
 125                        start = start1;
 126                        end = end1;
 127                        map = map1;
 128                }
 129                mask = ~(start ^ end);
 130                /* We don't support remapping with a discontiguous mask.  */
 131                BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
 132                       mask != ~((mask & -mask) - 1));
 133                gt64120_mem_resource.start = start;
 134                gt64120_mem_resource.end = end;
 135                gt64120_controller.mem_offset = (start & mask) - (map & mask);
 136                /* Addresses are 36-bit, so do shifts in the destinations.  */
 137                gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF;
 138                gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF;
 139                gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
 140                gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF;
 141
 142                start = GT_READ(GT_PCI0IOLD_OFS);
 143                end = GT_READ(GT_PCI0IOHD_OFS);
 144                map = GT_READ(GT_PCI0IOREMAP_OFS);
 145                end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
 146                mask = ~(start ^ end);
 147                /* We don't support remapping with a discontiguous mask.  */
 148                BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
 149                       mask != ~((mask & -mask) - 1));
 150                gt64120_io_resource.start = map & mask;
 151                gt64120_io_resource.end = (map & mask) | ~mask;
 152                gt64120_controller.io_offset = 0;
 153                /* Addresses are 36-bit, so do shifts in the destinations.  */
 154                gt64120_io_resource.start <<= GT_PCI_DCRM_SHF;
 155                gt64120_io_resource.end <<= GT_PCI_DCRM_SHF;
 156                gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
 157
 158                controller = &gt64120_controller;
 159                break;
 160
 161        case MIPS_REVISION_SCON_BONITO:
 162                /* Set up resource ranges from the controller's registers.  */
 163                map = BONITO_PCIMAP;
 164                map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >>
 165                       BONITO_PCIMAP_PCIMAP_LO0_SHIFT;
 166                map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >>
 167                       BONITO_PCIMAP_PCIMAP_LO1_SHIFT;
 168                map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >>
 169                       BONITO_PCIMAP_PCIMAP_LO2_SHIFT;
 170                /* Combine as many adjacent windows as possible.  */
 171                map = map1;
 172                start = BONITO_PCILO0_BASE;
 173                end = 1;
 174                if (map3 == map2 + 1) {
 175                        map = map2;
 176                        start = BONITO_PCILO1_BASE;
 177                        end++;
 178                }
 179                if (map2 == map1 + 1) {
 180                        map = map1;
 181                        start = BONITO_PCILO0_BASE;
 182                        end++;
 183                }
 184                bonito64_mem_resource.start = start;
 185                bonito64_mem_resource.end = start +
 186                                            BONITO_PCIMAP_WINBASE(end) - 1;
 187                bonito64_controller.mem_offset = start -
 188                                                 BONITO_PCIMAP_WINBASE(map);
 189
 190                controller = &bonito64_controller;
 191                break;
 192
 193        case MIPS_REVISION_SCON_SOCIT:
 194        case MIPS_REVISION_SCON_ROCIT:
 195        case MIPS_REVISION_SCON_SOCITSC:
 196        case MIPS_REVISION_SCON_SOCITSCP:
 197                /* Set up resource ranges from the controller's registers.  */
 198                MSC_READ(MSC01_PCI_SC2PMBASL, start);
 199                MSC_READ(MSC01_PCI_SC2PMMSKL, mask);
 200                MSC_READ(MSC01_PCI_SC2PMMAPL, map);
 201                msc_mem_resource.start = start & mask;
 202                msc_mem_resource.end = (start & mask) | ~mask;
 203                msc_controller.mem_offset = (start & mask) - (map & mask);
 204#ifdef CONFIG_MIPS_CMP
 205                if (gcmp_niocu())
 206                        gcmp_setregion(0, start, mask,
 207                                GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
 208#endif
 209                MSC_READ(MSC01_PCI_SC2PIOBASL, start);
 210                MSC_READ(MSC01_PCI_SC2PIOMSKL, mask);
 211                MSC_READ(MSC01_PCI_SC2PIOMAPL, map);
 212                msc_io_resource.start = map & mask;
 213                msc_io_resource.end = (map & mask) | ~mask;
 214                msc_controller.io_offset = 0;
 215                ioport_resource.end = ~mask;
 216#ifdef CONFIG_MIPS_CMP
 217                if (gcmp_niocu())
 218                        gcmp_setregion(1, start, mask,
 219                                GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
 220#endif
 221                /* If ranges overlap I/O takes precedence.  */
 222                start = start & mask;
 223                end = start | ~mask;
 224                if ((start >= msc_mem_resource.start &&
 225                     start <= msc_mem_resource.end) ||
 226                    (end >= msc_mem_resource.start &&
 227                     end <= msc_mem_resource.end)) {
 228                        /* Use the larger space.  */
 229                        start = max(start, msc_mem_resource.start);
 230                        end = min(end, msc_mem_resource.end);
 231                        if (start - msc_mem_resource.start >=
 232                            msc_mem_resource.end - end)
 233                                msc_mem_resource.end = start - 1;
 234                        else
 235                                msc_mem_resource.start = end + 1;
 236                }
 237
 238                controller = &msc_controller;
 239                break;
 240        default:
 241                return;
 242        }
 243
 244        if (controller->io_resource->start < 0x00001000UL)      /* FIXME */
 245                controller->io_resource->start = 0x00001000UL;
 246
 247        iomem_resource.end &= 0xfffffffffULL;                   /* 64 GB */
 248        ioport_resource.end = controller->io_resource->end;
 249
 250        register_pci_controller(controller);
 251}
 252
 253/* Enable PCI 2.1 compatibility in PIIX4 */
 254static void __init quirk_dlcsetup(struct pci_dev *dev)
 255{
 256        u8 odlc, ndlc;
 257        (void) pci_read_config_byte(dev, 0x82, &odlc);
 258        /* Enable passive releases and delayed transaction */
 259        ndlc = odlc | 7;
 260        (void) pci_write_config_byte(dev, 0x82, ndlc);
 261}
 262
 263DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
 264        quirk_dlcsetup);
 265