linux/arch/ppc/syslib/mpc52xx_pci.c
<<
>>
Prefs
   1/*
   2 * PCI code for the Freescale MPC52xx embedded CPU.
   3 *
   4 *
   5 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
   6 *
   7 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
   8 *
   9 * This file is licensed under the terms of the GNU General Public License
  10 * version 2. This program is licensed "as is" without any warranty of any
  11 * kind, whether express or implied.
  12 */
  13
  14
  15#include <asm/pci.h>
  16
  17#include <asm/mpc52xx.h>
  18#include "mpc52xx_pci.h"
  19
  20#include <asm/delay.h>
  21#include <asm/machdep.h>
  22
  23
  24/* This macro is defined to activate the workaround for the bug
  25   435 of the MPC5200 (L25R). With it activated, we don't do any
  26   32 bits configuration access during type-1 cycles */
  27#define MPC5200_BUG_435_WORKAROUND
  28
  29
  30static int
  31mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
  32                                int offset, int len, u32 *val)
  33{
  34        struct pci_controller *hose = bus->sysdata;
  35        u32 value;
  36
  37        if (ppc_md.pci_exclude_device)
  38                if (ppc_md.pci_exclude_device(bus->number, devfn))
  39                        return PCIBIOS_DEVICE_NOT_FOUND;
  40
  41        out_be32(hose->cfg_addr,
  42                (1 << 31) |
  43                ((bus->number - hose->bus_offset) << 16) |
  44                (devfn << 8) |
  45                (offset & 0xfc));
  46        mb();
  47
  48#ifdef MPC5200_BUG_435_WORKAROUND
  49        if (bus->number != hose->bus_offset) {
  50                switch (len) {
  51                        case 1:
  52                                value = in_8(((u8 __iomem *)hose->cfg_data) + (offset & 3));
  53                                break;
  54                        case 2:
  55                                value = in_le16(((u16 __iomem *)hose->cfg_data) + ((offset>>1) & 1));
  56                                break;
  57
  58                        default:
  59                                value = in_le16((u16 __iomem *)hose->cfg_data) |
  60                                        (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
  61                                break;
  62                }
  63        }
  64        else
  65#endif
  66        {
  67                value = in_le32(hose->cfg_data);
  68
  69                if (len != 4) {
  70                        value >>= ((offset & 0x3) << 3);
  71                        value &= 0xffffffff >> (32 - (len << 3));
  72                }
  73        }
  74
  75        *val = value;
  76
  77        out_be32(hose->cfg_addr, 0);
  78        mb();
  79
  80        return PCIBIOS_SUCCESSFUL;
  81}
  82
  83static int
  84mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
  85                                int offset, int len, u32 val)
  86{
  87        struct pci_controller *hose = bus->sysdata;
  88        u32 value, mask;
  89
  90        if (ppc_md.pci_exclude_device)
  91                if (ppc_md.pci_exclude_device(bus->number, devfn))
  92                        return PCIBIOS_DEVICE_NOT_FOUND;
  93
  94        out_be32(hose->cfg_addr,
  95                (1 << 31) |
  96                ((bus->number - hose->bus_offset) << 16) |
  97                (devfn << 8) |
  98                (offset & 0xfc));
  99        mb();
 100
 101#ifdef MPC5200_BUG_435_WORKAROUND
 102        if (bus->number != hose->bus_offset) {
 103                switch (len) {
 104                        case 1:
 105                                out_8(((u8 __iomem *)hose->cfg_data) +
 106                                        (offset & 3), val);
 107                                break;
 108                        case 2:
 109                                out_le16(((u16 __iomem *)hose->cfg_data) +
 110                                        ((offset>>1) & 1), val);
 111                                break;
 112
 113                        default:
 114                                out_le16((u16 __iomem *)hose->cfg_data,
 115                                        (u16)val);
 116                                out_le16(((u16 __iomem *)hose->cfg_data) + 1,
 117                                        (u16)(val>>16));
 118                                break;
 119                }
 120        }
 121        else
 122#endif
 123        {
 124                if (len != 4) {
 125                        value = in_le32(hose->cfg_data);
 126
 127                        offset = (offset & 0x3) << 3;
 128                        mask = (0xffffffff >> (32 - (len << 3)));
 129                        mask <<= offset;
 130
 131                        value &= ~mask;
 132                        val = value | ((val << offset) & mask);
 133                }
 134
 135                out_le32(hose->cfg_data, val);
 136        }
 137        mb();
 138
 139        out_be32(hose->cfg_addr, 0);
 140        mb();
 141
 142        return PCIBIOS_SUCCESSFUL;
 143}
 144
 145static struct pci_ops mpc52xx_pci_ops = {
 146        .read  = mpc52xx_pci_read_config,
 147        .write = mpc52xx_pci_write_config
 148};
 149
 150
 151static void __init
 152mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs)
 153{
 154        u32 tmp;
 155
 156        /* Setup control regs */
 157        tmp = in_be32(&pci_regs->scr);
 158        tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
 159        out_be32(&pci_regs->scr, tmp);
 160
 161        /* Setup windows */
 162        out_be32(&pci_regs->iw0btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
 163                MPC52xx_PCI_MEM_START + MPC52xx_PCI_MEM_OFFSET,
 164                MPC52xx_PCI_MEM_START,
 165                MPC52xx_PCI_MEM_SIZE ));
 166
 167        out_be32(&pci_regs->iw1btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
 168                MPC52xx_PCI_MMIO_START + MPC52xx_PCI_MEM_OFFSET,
 169                MPC52xx_PCI_MMIO_START,
 170                MPC52xx_PCI_MMIO_SIZE ));
 171
 172        out_be32(&pci_regs->iw2btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
 173                MPC52xx_PCI_IO_BASE,
 174                MPC52xx_PCI_IO_START,
 175                MPC52xx_PCI_IO_SIZE ));
 176
 177        out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(
 178                ( MPC52xx_PCI_IWCR_ENABLE |             /* iw0btar */
 179                  MPC52xx_PCI_IWCR_READ_MULTI |
 180                  MPC52xx_PCI_IWCR_MEM ),
 181                ( MPC52xx_PCI_IWCR_ENABLE |             /* iw1btar */
 182                  MPC52xx_PCI_IWCR_READ |
 183                  MPC52xx_PCI_IWCR_MEM ),
 184                ( MPC52xx_PCI_IWCR_ENABLE |             /* iw2btar */
 185                  MPC52xx_PCI_IWCR_IO )
 186        ));
 187
 188
 189        out_be32(&pci_regs->tbatr0,
 190                MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
 191        out_be32(&pci_regs->tbatr1,
 192                MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
 193
 194        out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
 195
 196        /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
 197        /* Not necessary and can be a bad thing if for example the bootloader
 198           is displaying a splash screen or ... Just left here for
 199           documentation purpose if anyone need it */
 200        tmp = in_be32(&pci_regs->gscr);
 201#if 0
 202        out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
 203        udelay(50);
 204#endif
 205        out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
 206}
 207
 208static void
 209mpc52xx_pci_fixup_resources(struct pci_dev *dev)
 210{
 211        int i;
 212
 213        /* We don't rely on boot loader for PCI and resets all
 214           devices */
 215        for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 216                struct resource *res = &dev->resource[i];
 217                if (res->end > res->start) {    /* Only valid resources */
 218                        res->end -= res->start;
 219                        res->start = 0;
 220                        res->flags |= IORESOURCE_UNSET;
 221                }
 222        }
 223
 224        /* The PCI Host bridge of MPC52xx has a prefetch memory resource
 225           fixed to 1Gb. Doesn't fit in the resource system so we remove it */
 226        if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
 227             (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
 228              || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
 229                struct resource *res = &dev->resource[1];
 230                res->start = res->end = res->flags = 0;
 231        }
 232}
 233
 234void __init
 235mpc52xx_find_bridges(void)
 236{
 237        struct mpc52xx_pci __iomem *pci_regs;
 238        struct pci_controller *hose;
 239
 240        pci_assign_all_buses = 1;
 241
 242        pci_regs = ioremap(MPC52xx_PA(MPC52xx_PCI_OFFSET), MPC52xx_PCI_SIZE);
 243        if (!pci_regs)
 244                return;
 245
 246        hose = pcibios_alloc_controller();
 247        if (!hose) {
 248                iounmap(pci_regs);
 249                return;
 250        }
 251
 252        ppc_md.pci_swizzle = common_swizzle;
 253        ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
 254
 255        hose->first_busno = 0;
 256        hose->last_busno = 0xff;
 257        hose->bus_offset = 0;
 258        hose->ops = &mpc52xx_pci_ops;
 259
 260        mpc52xx_pci_setup(pci_regs);
 261
 262        hose->pci_mem_offset = MPC52xx_PCI_MEM_OFFSET;
 263
 264        hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE);
 265        isa_io_base = (unsigned long) hose->io_base_virt;
 266
 267        hose->cfg_addr = &pci_regs->car;
 268        hose->cfg_data = hose->io_base_virt;
 269
 270        /* Setup resources */
 271        pci_init_resource(&hose->mem_resources[0],
 272                        MPC52xx_PCI_MEM_START,
 273                        MPC52xx_PCI_MEM_STOP,
 274                        IORESOURCE_MEM|IORESOURCE_PREFETCH,
 275                        "PCI prefetchable memory");
 276
 277        pci_init_resource(&hose->mem_resources[1],
 278                        MPC52xx_PCI_MMIO_START,
 279                        MPC52xx_PCI_MMIO_STOP,
 280                        IORESOURCE_MEM,
 281                        "PCI memory");
 282
 283        pci_init_resource(&hose->io_resource,
 284                        MPC52xx_PCI_IO_START,
 285                        MPC52xx_PCI_IO_STOP,
 286                        IORESOURCE_IO,
 287                        "PCI I/O");
 288
 289}
 290
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.