linux/arch/sh/drivers/pci/pci-sh7751.c
<<
>>
Prefs
   1/*
   2 * Low-Level PCI Support for the SH7751
   3 *
   4 *  Copyright (C) 2003 - 2009  Paul Mundt
   5 *  Copyright (C) 2001  Dustin McIntire
   6 *
   7 *  With cleanup by Paul van Gool <pvangool@mimotech.com>, 2003.
   8 *
   9 * This file is subject to the terms and conditions of the GNU General Public
  10 * License.  See the file "COPYING" in the main directory of this archive
  11 * for more details.
  12 */
  13#include <linux/init.h>
  14#include <linux/pci.h>
  15#include <linux/types.h>
  16#include <linux/errno.h>
  17#include <linux/io.h>
  18#include "pci-sh4.h"
  19#include <asm/addrspace.h>
  20#include <asm/sizes.h>
  21
  22static int __init __area_sdram_check(struct pci_channel *chan,
  23                                     unsigned int area)
  24{
  25        unsigned long word;
  26
  27        word = __raw_readl(SH7751_BCR1);
  28        /* check BCR for SDRAM in area */
  29        if (((word >> area) & 1) == 0) {
  30                printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%lx\n",
  31                       area, word);
  32                return 0;
  33        }
  34        pci_write_reg(chan, word, SH4_PCIBCR1);
  35
  36        word = __raw_readw(SH7751_BCR2);
  37        /* check BCR2 for 32bit SDRAM interface*/
  38        if (((word >> (area << 1)) & 0x3) != 0x3) {
  39                printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%lx\n",
  40                       area, word);
  41                return 0;
  42        }
  43        pci_write_reg(chan, word, SH4_PCIBCR2);
  44
  45        return 1;
  46}
  47
  48static struct resource sh7751_pci_resources[] = {
  49        {
  50                .name   = "SH7751_IO",
  51                .start  = 0x1000,
  52                .end    = SZ_4M - 1,
  53                .flags  = IORESOURCE_IO
  54        }, {
  55                .name   = "SH7751_mem",
  56                .start  = SH7751_PCI_MEMORY_BASE,
  57                .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
  58                .flags  = IORESOURCE_MEM
  59        },
  60};
  61
  62static struct pci_channel sh7751_pci_controller = {
  63        .pci_ops        = &sh4_pci_ops,
  64        .resources      = sh7751_pci_resources,
  65        .nr_resources   = ARRAY_SIZE(sh7751_pci_resources),
  66        .mem_offset     = 0x00000000,
  67        .io_offset      = 0x00000000,
  68        .io_map_base    = SH7751_PCI_IO_BASE,
  69};
  70
  71static struct sh4_pci_address_map sh7751_pci_map = {
  72        .window0        = {
  73                .base   = SH7751_CS3_BASE_ADDR,
  74                .size   = 0x04000000,
  75        },
  76};
  77
  78static int __init sh7751_pci_init(void)
  79{
  80        struct pci_channel *chan = &sh7751_pci_controller;
  81        unsigned int id;
  82        u32 word, reg;
  83
  84        printk(KERN_NOTICE "PCI: Starting initialization.\n");
  85
  86        chan->reg_base = 0xfe200000;
  87
  88        /* check for SH7751/SH7751R hardware */
  89        id = pci_read_reg(chan, SH7751_PCICONF0);
  90        if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
  91            id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
  92                pr_debug("PCI: This is not an SH7751(R) (%x)\n", id);
  93                return -ENODEV;
  94        }
  95
  96        /* Set the BCR's to enable PCI access */
  97        reg = __raw_readl(SH7751_BCR1);
  98        reg |= 0x80000;
  99        __raw_writel(reg, SH7751_BCR1);
 100
 101        /* Turn the clocks back on (not done in reset)*/
 102        pci_write_reg(chan, 0, SH4_PCICLKR);
 103        /* Clear Powerdown IRQ's (not done in reset) */
 104        word = SH4_PCIPINT_D3 | SH4_PCIPINT_D0;
 105        pci_write_reg(chan, word, SH4_PCIPINT);
 106
 107        /* set the command/status bits to:
 108         * Wait Cycle Control + Parity Enable + Bus Master +
 109         * Mem space enable
 110         */
 111        word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
 112               SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
 113        pci_write_reg(chan, word, SH7751_PCICONF1);
 114
 115        /* define this host as the host bridge */
 116        word = PCI_BASE_CLASS_BRIDGE << 24;
 117        pci_write_reg(chan, word, SH7751_PCICONF2);
 118
 119        /* Set IO and Mem windows to local address
 120         * Make PCI and local address the same for easy 1 to 1 mapping
 121         */
 122        word = sh7751_pci_map.window0.size - 1;
 123        pci_write_reg(chan, word, SH4_PCILSR0);
 124        /* Set the values on window 0 PCI config registers */
 125        word = P2SEGADDR(sh7751_pci_map.window0.base);
 126        pci_write_reg(chan, word, SH4_PCILAR0);
 127        pci_write_reg(chan, word, SH7751_PCICONF5);
 128
 129        /* Set the local 16MB PCI memory space window to
 130         * the lowest PCI mapped address
 131         */
 132        word = chan->resources[1].start & SH4_PCIMBR_MASK;
 133        pr_debug("PCI: Setting upper bits of Memory window to 0x%x\n", word);
 134        pci_write_reg(chan, word , SH4_PCIMBR);
 135
 136        /* Make sure the MSB's of IO window are set to access PCI space
 137         * correctly */
 138        word = chan->resources[0].start & SH4_PCIIOBR_MASK;
 139        pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word);
 140        pci_write_reg(chan, word, SH4_PCIIOBR);
 141
 142        /* Set PCI WCRx, BCRx's, copy from BSC locations */
 143
 144        /* check BCR for SDRAM in specified area */
 145        switch (sh7751_pci_map.window0.base) {
 146        case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(chan, 0); break;
 147        case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(chan, 1); break;
 148        case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(chan, 2); break;
 149        case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(chan, 3); break;
 150        case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(chan, 4); break;
 151        case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(chan, 5); break;
 152        case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(chan, 6); break;
 153        }
 154
 155        if (!word)
 156                return -1;
 157
 158        /* configure the wait control registers */
 159        word = __raw_readl(SH7751_WCR1);
 160        pci_write_reg(chan, word, SH4_PCIWCR1);
 161        word = __raw_readl(SH7751_WCR2);
 162        pci_write_reg(chan, word, SH4_PCIWCR2);
 163        word = __raw_readl(SH7751_WCR3);
 164        pci_write_reg(chan, word, SH4_PCIWCR3);
 165        word = __raw_readl(SH7751_MCR);
 166        pci_write_reg(chan, word, SH4_PCIMCR);
 167
 168        /* NOTE: I'm ignoring the PCI error IRQs for now..
 169         * TODO: add support for the internal error interrupts and
 170         * DMA interrupts...
 171         */
 172
 173        pci_fixup_pcic(chan);
 174
 175        /* SH7751 init done, set central function init complete */
 176        /* use round robin mode to stop a device starving/overruning */
 177        word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM;
 178        pci_write_reg(chan, word, SH4_PCICR);
 179
 180        return register_pci_controller(chan);
 181}
 182arch_initcall(sh7751_pci_init);
 183