linux/arch/sh/boards/mpc1211/pci.c
<<
>>
Prefs
   1/*
   2 *      Low-Level PCI Support for the MPC-1211(CTP/PCI/MPC-SH02)
   3 *
   4 *  (c) 2002-2003 Saito.K & Jeanne
   5 *
   6 *  Dustin McIntire (dustin@sensoria.com)
   7 *      Derived from arch/i386/kernel/pci-*.c which bore the message:
   8 *      (c) 1999--2000 Martin Mares <mj@ucw.cz>
   9 *      
  10 *  May be copied or modified under the terms of the GNU General Public
  11 *  License.  See linux/COPYING for more information.
  12 *
  13 */
  14#include <linux/types.h>
  15#include <linux/kernel.h>
  16#include <linux/init.h>
  17#include <linux/delay.h>
  18#include <linux/pci.h>
  19#include <linux/sched.h>
  20#include <linux/ioport.h>
  21#include <linux/errno.h>
  22#include <linux/irq.h>
  23#include <linux/interrupt.h>
  24
  25#include <asm/machvec.h>
  26#include <asm/io.h>
  27#include <asm/mpc1211/pci.h>
  28
  29static struct resource mpcpci_io_resource = {
  30        "MPCPCI IO",
  31        0x00000000,
  32        0xffffffff,
  33        IORESOURCE_IO
  34};
  35
  36static struct resource mpcpci_mem_resource = {
  37        "MPCPCI mem",
  38        0x00000000,
  39        0xffffffff,
  40        IORESOURCE_MEM
  41};
  42
  43static struct pci_ops pci_direct_conf1;
  44struct pci_channel board_pci_channels[] = {
  45        {&pci_direct_conf1, &mpcpci_io_resource, &mpcpci_mem_resource, 0, 256},
  46        {NULL, NULL, NULL, 0, 0},
  47};
  48
  49/*
  50 * Direct access to PCI hardware...
  51 */
  52
  53
  54#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
  55
  56/*
  57 * Functions for accessing PCI configuration space with type 1 accesses
  58 */
  59static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
  60{
  61        u32 word;
  62        unsigned long flags;
  63
  64        /* 
  65         * PCIPDR may only be accessed as 32 bit words, 
  66         * so we must do byte alignment by hand 
  67         */
  68        local_irq_save(flags);
  69        writel(CONFIG_CMD(bus,devfn,where), PCIPAR);
  70        word = readl(PCIPDR);
  71        local_irq_restore(flags);
  72
  73        switch (size) {
  74        case 1:
  75                switch (where & 0x3) {
  76                case 3:
  77                        *value = (u8)(word >> 24);
  78                        break;
  79                case 2:
  80                        *value = (u8)(word >> 16);
  81                        break;
  82                case 1:
  83                        *value = (u8)(word >> 8);
  84                        break;
  85                default:
  86                        *value = (u8)word;
  87                        break;
  88                }
  89                break;
  90        case 2:
  91                switch (where & 0x3) {
  92                case 3:
  93                        *value = (u16)(word >> 24);
  94                        local_irq_save(flags);
  95                        writel(CONFIG_CMD(bus,devfn,(where+1)), PCIPAR);
  96                        word = readl(PCIPDR);
  97                        local_irq_restore(flags);
  98                        *value |= ((word & 0xff) << 8);
  99                        break;
 100                case 2:
 101                        *value = (u16)(word >> 16);
 102                        break;
 103                case 1:
 104                        *value = (u16)(word >> 8);
 105                        break;
 106                default:
 107                        *value = (u16)word;
 108                        break;
 109                }
 110                break;
 111        case 4:
 112                *value = word;
 113                break;
 114        }
 115        PCIDBG(4,"pci_conf1_read@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),*value); 
 116        return PCIBIOS_SUCCESSFUL;    
 117}
 118
 119/* 
 120 * Since MPC-1211 only does 32bit access we'll have to do a read,mask,write operation.  
 121 * We'll allow an odd byte offset, though it should be illegal.
 122 */ 
 123static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
 124{
 125        u32 word,mask = 0;
 126        unsigned long flags;
 127        u32 shift = (where & 3) * 8;
 128
 129        if(size == 1) {
 130                mask = ((1 << 8) - 1) << shift;  // create the byte mask
 131        } else if(size == 2){
 132                if(shift == 24)
 133                        return PCIBIOS_BAD_REGISTER_NUMBER;           
 134                mask = ((1 << 16) - 1) << shift;  // create the word mask
 135        }
 136        local_irq_save(flags);
 137        writel(CONFIG_CMD(bus,devfn,where), PCIPAR);
 138        if(size == 4){
 139                writel(value, PCIPDR);
 140                local_irq_restore(flags);
 141                PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),value);
 142                return PCIBIOS_SUCCESSFUL;
 143        }
 144        word = readl(PCIPDR);
 145        word &= ~mask;
 146        word |= ((value << shift) & mask);
 147        writel(word, PCIPDR);
 148        local_irq_restore(flags);
 149        PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),word);
 150        return PCIBIOS_SUCCESSFUL;
 151}
 152
 153#undef CONFIG_CMD
 154
 155static struct pci_ops pci_direct_conf1 = {
 156        .read =         pci_conf1_read,
 157        .write =        pci_conf1_write,
 158};
 159
 160static void __devinit quirk_ali_ide_ports(struct pci_dev *dev)
 161{
 162        dev->resource[0].start = 0x1f0;
 163        dev->resource[0].end   = 0x1f7;
 164        dev->resource[0].flags = IORESOURCE_IO;
 165        dev->resource[1].start = 0x3f6;
 166        dev->resource[1].end   = 0x3f6;
 167        dev->resource[1].flags = IORESOURCE_IO;
 168        dev->resource[2].start = 0x170;
 169        dev->resource[2].end   = 0x177;
 170        dev->resource[2].flags = IORESOURCE_IO;
 171        dev->resource[3].start = 0x376;
 172        dev->resource[3].end   = 0x376;
 173        dev->resource[3].flags = IORESOURCE_IO;
 174        dev->resource[4].start = 0xf000;
 175        dev->resource[4].end   = 0xf00f;
 176        dev->resource[4].flags = IORESOURCE_IO;
 177}
 178DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports);
 179
 180char * __devinit pcibios_setup(char *str)
 181{
 182        return str;
 183}
 184
 185/*
 186 *  Called after each bus is probed, but before its children
 187 *  are examined.
 188 */
 189
 190void __devinit pcibios_fixup_bus(struct pci_bus *b)
 191{
 192        pci_read_bridge_bases(b);
 193}
 194
 195/* 
 196 *      IRQ functions 
 197 */
 198static inline u8 bridge_swizzle(u8 pin, u8 slot)
 199{
 200        return (((pin-1) + slot) % 4) + 1;
 201}
 202
 203static inline u8 bridge_swizzle_pci_1(u8 pin, u8 slot)
 204{
 205        return (((pin-1) - slot) & 3) + 1;
 206}
 207
 208static u8 __init mpc1211_swizzle(struct pci_dev *dev, u8 *pinp)
 209{
 210        unsigned long flags;
 211        u8 pin = *pinp;
 212        u32 word;
 213
 214        for ( ; dev->bus->self; dev = dev->bus->self) {
 215                if (!pin)
 216                        continue;
 217
 218                if (dev->bus->number == 1) {
 219                        local_irq_save(flags);
 220                        writel(0x80000000 | 0x2c, PCIPAR);
 221                        word = readl(PCIPDR);
 222                        local_irq_restore(flags);
 223                        word >>= 16;
 224
 225                        if (word == 0x0001)
 226                                pin = bridge_swizzle_pci_1(pin, PCI_SLOT(dev->devfn));
 227                        else
 228                                pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
 229                } else
 230                        pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
 231        }
 232
 233        *pinp = pin;
 234
 235        return PCI_SLOT(dev->devfn);
 236}
 237
 238static int __init map_mpc1211_irq(struct pci_dev *dev, u8 slot, u8 pin)
 239{
 240        int irq = -1;
 241
 242        /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
 243        if (dev->bus->number == 0) {
 244                switch (slot) {
 245                case 13:   irq =  9; break;   /* USB */
 246                case 22:   irq = 10; break;   /* LAN */
 247                default:   irq =  0; break;
 248                }
 249        } else {
 250                switch (pin) {
 251                case 0:   irq =  0; break;
 252                case 1:   irq =  7; break;
 253                case 2:   irq =  9; break;
 254                case 3:   irq = 10; break;
 255                case 4:   irq = 11; break;
 256                }
 257        }
 258
 259        if( irq < 0 ) {
 260                PCIDBG(3, "PCI: Error mapping IRQ on device %s\n", pci_name(dev));
 261                return irq;
 262        }
 263        
 264        PCIDBG(2, "Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
 265
 266        return irq;
 267}
 268
 269void __init pcibios_fixup_irqs(void)
 270{
 271        pci_fixup_irqs(mpc1211_swizzle, map_mpc1211_irq);
 272}
 273
 274void pcibios_align_resource(void *data, struct resource *res,
 275                            resource_size_t size, resource_size_t align)
 276{
 277        resource_size_t start = res->start;
 278
 279        if (res->flags & IORESOURCE_IO) {
 280                if (start >= 0x10000UL) {
 281                        if ((start & 0xffffUL) < 0x4000UL) {
 282                                start = (start & 0xffff0000UL) + 0x4000UL;
 283                        } else if ((start & 0xffffUL) >= 0xf000UL) {
 284                                start = (start & 0xffff0000UL) + 0x10000UL;
 285                        }
 286                        res->start = start;
 287                } else {
 288                        if (start & 0x300) {
 289                                start = (start + 0x3ff) & ~0x3ff;
 290                                res->start = start;
 291                        }
 292                }
 293        }
 294}
 295
 296
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.