linux-bk/arch/mips/pci/ops-au1000.c
<<
>>
Prefs
   1/*
   2 * BRIEF MODULE DESCRIPTION
   3 *      Alchemy/AMD Au1x00 pci support.
   4 *
   5 * Copyright 2001,2002,2003 MontaVista Software Inc.
   6 * Author: MontaVista Software, Inc.
   7 *              ppopov@mvista.com or source@mvista.com
   8 *
   9 *  Support for all devices (greater than 16) added by David Gathright.
  10 *
  11 *  This program is free software; you can redistribute  it and/or modify it
  12 *  under  the terms of  the GNU General  Public License as published by the
  13 *  Free Software Foundation;  either version 2 of the  License, or (at your
  14 *  option) any later version.
  15 *
  16 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
  17 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
  18 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  19 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
  20 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
  22 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  23 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
  24 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26 *
  27 *  You should have received a copy of the  GNU General Public License along
  28 *  with this program; if not, write  to the Free Software Foundation, Inc.,
  29 *  675 Mass Ave, Cambridge, MA 02139, USA.
  30 */
  31#include <linux/config.h>
  32#include <linux/types.h>
  33#include <linux/pci.h>
  34#include <linux/kernel.h>
  35#include <linux/init.h>
  36#include <linux/vmalloc.h>
  37
  38#include <asm/mach-au1x00/au1000.h>
  39
  40#undef DEBUG
  41#ifdef DEBUG
  42#define DBG(x...) printk(x)
  43#else
  44#define DBG(x...)
  45#endif
  46
  47#define PCI_ACCESS_READ  0
  48#define PCI_ACCESS_WRITE 1
  49
  50
  51int (*board_pci_idsel)(unsigned int devsel, int assert);
  52
  53/* CP0 hazard avoidance. */
  54#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
  55                                     "nop; nop; nop; nop;\t" \
  56                                     ".set reorder\n\t")
  57
  58void mod_wired_entry(int entry, unsigned long entrylo0,
  59                unsigned long entrylo1, unsigned long entryhi,
  60                unsigned long pagemask)
  61{
  62        unsigned long old_pagemask;
  63        unsigned long old_ctx;
  64
  65        /* Save old context and create impossible VPN2 value */
  66        old_ctx = read_c0_entryhi() & 0xff;
  67        old_pagemask = read_c0_pagemask();
  68        write_c0_index(entry);
  69        BARRIER;
  70        write_c0_pagemask(pagemask);
  71        write_c0_entryhi(entryhi);
  72        write_c0_entrylo0(entrylo0);
  73        write_c0_entrylo1(entrylo1);
  74        BARRIER;
  75        tlb_write_indexed();
  76        BARRIER;
  77        write_c0_entryhi(old_ctx);
  78        BARRIER;
  79        write_c0_pagemask(old_pagemask);
  80}
  81
  82struct vm_struct *pci_cfg_vm;
  83static int pci_cfg_wired_entry;
  84static int first_cfg = 1;
  85unsigned long last_entryLo0, last_entryLo1;
  86
  87static int config_access(unsigned char access_type, struct pci_bus *bus,
  88                         unsigned int dev_fn, unsigned char where,
  89                         u32 * data)
  90{
  91#if defined( CONFIG_SOC_AU1500 ) || defined( CONFIG_SOC_AU1550 )
  92        unsigned int device = PCI_SLOT(dev_fn);
  93        unsigned int function = PCI_FUNC(dev_fn);
  94        unsigned long offset, status;
  95        unsigned long cfg_base;
  96        unsigned long flags;
  97        int error = PCIBIOS_SUCCESSFUL;
  98        unsigned long entryLo0, entryLo1;
  99
 100        if (device > 19) {
 101                *data = 0xffffffff;
 102                return -1;
 103        }
 104
 105        local_irq_save(flags);
 106        au_writel(((0x2000 << 16) | (au_readl(Au1500_PCI_STATCMD) & 0xffff)),
 107                        Au1500_PCI_STATCMD);
 108        au_sync_udelay(1);
 109
 110        /*
 111         * We can't ioremap the entire pci config space because it's
 112         * too large. Nor can we call ioremap dynamically because some
 113         * device drivers use the pci config routines from within
 114         * interrupt handlers and that becomes a problem in get_vm_area().
 115         * We use one wired tlb to handle all config accesses for all
 116         * busses. To improve performance, if the current device
 117         * is the same as the last device accessed, we don't touch the
 118         * tlb.
 119         */
 120        if (first_cfg) {
 121                /* reserve a wired entry for pci config accesses */
 122                first_cfg = 0;
 123                pci_cfg_vm = get_vm_area(0x2000, 0);
 124                if (!pci_cfg_vm)
 125                        panic (KERN_ERR "PCI unable to get vm area\n");
 126                pci_cfg_wired_entry = read_c0_wired();
 127                add_wired_entry(0, 0, (unsigned long)pci_cfg_vm->addr, PM_4K);
 128                last_entryLo0  = last_entryLo1 = 0xffffffff;
 129        }
 130
 131        /* Since the Au1xxx doesn't do the idsel timing exactly to spec,
 132         * many board vendors implement their own off-chip idsel, so call
 133         * it now.  If it doesn't succeed, may as well bail out at this point.
 134         */
 135        if (board_pci_idsel) {
 136                if (board_pci_idsel(device, 1) == 0) {
 137                        *data = 0xffffffff;
 138                        local_irq_restore(flags);
 139                        return -1;
 140                }
 141        }
 142
 143        /* setup the config window */
 144        if (bus->number == 0) {
 145                cfg_base = ((1<<device)<<11);
 146        } else {
 147                cfg_base = 0x80000000 | (bus->number<<16) | (device<<11);
 148        }
 149
 150        /* setup the lower bits of the 36 bit address */
 151        offset = (function << 8) | (where & ~0x3);
 152        /* pick up any address that falls below the page mask */
 153        offset |= cfg_base & ~PAGE_MASK;
 154
 155        /* page boundary */
 156        cfg_base = cfg_base & PAGE_MASK;
 157
 158        entryLo0 = (6 << 26)  | (cfg_base >> 6) | (2 << 3) | 7;
 159        entryLo1 = (6 << 26)  | (cfg_base >> 6) | (0x1000 >> 6) | (2 << 3) | 7;
 160
 161        if ((entryLo0 != last_entryLo0) || (entryLo1 != last_entryLo1)) {
 162                mod_wired_entry(pci_cfg_wired_entry, entryLo0, entryLo1,
 163                                (unsigned long)pci_cfg_vm->addr, PM_4K);
 164                last_entryLo0 = entryLo0;
 165                last_entryLo1 = entryLo1;
 166        }
 167
 168        if (access_type == PCI_ACCESS_WRITE) {
 169                au_writel(*data, (int)(pci_cfg_vm->addr + offset));
 170        } else {
 171                *data = au_readl((int)(pci_cfg_vm->addr + offset));
 172        }
 173        au_sync_udelay(2);
 174
 175        DBG("cfg_access %d bus->number %d dev %d at %x *data %x conf %x\n",
 176                        access_type, bus->number, device, where, *data, offset);
 177
 178        /* check master abort */
 179        status = au_readl(Au1500_PCI_STATCMD);
 180
 181        if (status & (1<<29)) {
 182                *data = 0xffffffff;
 183                error = -1;
 184                DBG("Au1x Master Abort\n");
 185        } else if ((status >> 28) & 0xf) {
 186                DBG("PCI ERR detected: status %x\n", status);
 187                *data = 0xffffffff;
 188                error = -1;
 189        }
 190
 191        /* Take away the idsel.
 192        */
 193        if (board_pci_idsel) {
 194                (void)board_pci_idsel(device, 0);
 195        }
 196
 197        local_irq_restore(flags);
 198        return error;
 199#endif
 200}
 201
 202static int read_config_byte(struct pci_bus *bus, unsigned int devfn,
 203                            int where, u8 * val)
 204{
 205        u32 data;
 206        int ret;
 207
 208        ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
 209        if (where & 1)
 210                data >>= 8;
 211        if (where & 2)
 212                data >>= 16;
 213        *val = data & 0xff;
 214        return ret;
 215}
 216
 217
 218static int read_config_word(struct pci_bus *bus, unsigned int devfn,
 219                            int where, u16 * val)
 220{
 221        u32 data;
 222        int ret;
 223
 224        ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
 225        if (where & 2)
 226                data >>= 16;
 227        *val = data & 0xffff;
 228        return ret;
 229}
 230
 231static int read_config_dword(struct pci_bus *bus, unsigned int devfn,
 232                             int where, u32 * val)
 233{
 234        int ret;
 235
 236        ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val);
 237        return ret;
 238}
 239
 240static int
 241write_config_byte(struct pci_bus *bus, unsigned int devfn, int where,
 242                  u8 val)
 243{
 244        u32 data = 0;
 245
 246        if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
 247                return -1;
 248
 249        data = (data & ~(0xff << ((where & 3) << 3))) |
 250            (val << ((where & 3) << 3));
 251
 252        if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
 253                return -1;
 254
 255        return PCIBIOS_SUCCESSFUL;
 256}
 257
 258static int
 259write_config_word(struct pci_bus *bus, unsigned int devfn, int where,
 260                  u16 val)
 261{
 262        u32 data = 0;
 263
 264        if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
 265                return -1;
 266
 267        data = (data & ~(0xffff << ((where & 3) << 3))) |
 268            (val << ((where & 3) << 3));
 269
 270        if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
 271                return -1;
 272
 273
 274        return PCIBIOS_SUCCESSFUL;
 275}
 276
 277static int
 278write_config_dword(struct pci_bus *bus, unsigned int devfn, int where,
 279                   u32 val)
 280{
 281        if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val))
 282                return -1;
 283
 284        return PCIBIOS_SUCCESSFUL;
 285}
 286
 287static int config_read(struct pci_bus *bus, unsigned int devfn,
 288                       int where, int size, u32 * val)
 289{
 290        switch (size) {
 291        case 1:
 292                return read_config_byte(bus, devfn, where, (u8 *) val);
 293        case 2:
 294                return read_config_word(bus, devfn, where, (u16 *) val);
 295        default:
 296                return read_config_dword(bus, devfn, where, val);
 297        }
 298}
 299
 300static int config_write(struct pci_bus *bus, unsigned int devfn,
 301                        int where, int size, u32 val)
 302{
 303        switch (size) {
 304        case 1:
 305                return write_config_byte(bus, devfn, where, (u8) val);
 306        case 2:
 307                return write_config_word(bus, devfn, where, (u16) val);
 308        default:
 309                return write_config_dword(bus, devfn, where, val);
 310        }
 311}
 312
 313
 314struct pci_ops au1x_pci_ops = {
 315        config_read,
 316        config_write
 317};
 318
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.