linux/arch/sh/drivers/pci/ops-sh7786.c
<<
>>
Prefs
   1/*
   2 * Generic SH7786 PCI-Express operations.
   3 *
   4 *  Copyright (C) 2009  Paul Mundt
   5 *
   6 * This file is subject to the terms and conditions of the GNU General Public
   7 * License v2. See the file "COPYING" in the main directory of this archive
   8 * for more details.
   9 */
  10#include <linux/kernel.h>
  11#include <linux/init.h>
  12#include <linux/pci.h>
  13#include <linux/io.h>
  14#include <linux/spinlock.h>
  15#include "pcie-sh7786.h"
  16
  17enum {
  18        PCI_ACCESS_READ,
  19        PCI_ACCESS_WRITE,
  20};
  21
  22static DEFINE_SPINLOCK(sh7786_pcie_lock);
  23
  24static int sh7786_pcie_config_access(unsigned char access_type,
  25                struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
  26{
  27        struct pci_channel *chan = bus->sysdata;
  28        int dev, func;
  29
  30        dev = PCI_SLOT(devfn);
  31        func = PCI_FUNC(devfn);
  32
  33        if (bus->number > 255 || dev > 31 || func > 7)
  34                return PCIBIOS_FUNC_NOT_SUPPORTED;
  35        if (devfn)
  36                return PCIBIOS_DEVICE_NOT_FOUND;
  37
  38        /* Set the PIO address */
  39        pci_write_reg(chan, (bus->number << 24) | (dev << 19) |
  40                                (func << 16) | (where & ~3), SH4A_PCIEPAR);
  41
  42        /* Enable the configuration access */
  43        pci_write_reg(chan, (1 << 31), SH4A_PCIEPCTLR);
  44
  45        if (access_type == PCI_ACCESS_READ)
  46                *data = pci_read_reg(chan, SH4A_PCIEPDR);
  47        else
  48                pci_write_reg(chan, *data, SH4A_PCIEPDR);
  49
  50        /* Check for master and target aborts */
  51        if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
  52                return PCIBIOS_DEVICE_NOT_FOUND;
  53
  54        return PCIBIOS_SUCCESSFUL;
  55}
  56
  57static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
  58                            int where, int size, u32 *val)
  59{
  60        unsigned long flags;
  61        int ret;
  62        u32 data;
  63
  64        if ((size == 2) && (where & 1))
  65                return PCIBIOS_BAD_REGISTER_NUMBER;
  66        else if ((size == 4) && (where & 3))
  67                return PCIBIOS_BAD_REGISTER_NUMBER;
  68
  69        spin_lock_irqsave(&sh7786_pcie_lock, flags);
  70        ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
  71                                        devfn, where, &data);
  72        if (ret != PCIBIOS_SUCCESSFUL)
  73                goto out;
  74
  75        if (size == 1)
  76                *val = (data >> ((where & 3) << 3)) & 0xff;
  77        else if (size == 2)
  78                *val = (data >> ((where & 2) << 3)) & 0xffff;
  79        else
  80                *val = data;
  81
  82        dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x "
  83                "where=0x%04x size=%d val=0x%08lx\n", bus->number,
  84                devfn, where, size, (unsigned long)*val);
  85
  86out:
  87        spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
  88        return ret;
  89}
  90
  91static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
  92                             int where, int size, u32 val)
  93{
  94        unsigned long flags;
  95        int shift, ret;
  96        u32 data;
  97
  98        if ((size == 2) && (where & 1))
  99                return PCIBIOS_BAD_REGISTER_NUMBER;
 100        else if ((size == 4) && (where & 3))
 101                return PCIBIOS_BAD_REGISTER_NUMBER;
 102
 103        spin_lock_irqsave(&sh7786_pcie_lock, flags);
 104        ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
 105                                        devfn, where, &data);
 106        if (ret != PCIBIOS_SUCCESSFUL)
 107                goto out;
 108
 109        dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x "
 110                "where=0x%04x size=%d val=%08lx\n", bus->number,
 111                devfn, where, size, (unsigned long)val);
 112
 113        if (size == 1) {
 114                shift = (where & 3) << 3;
 115                data &= ~(0xff << shift);
 116                data |= ((val & 0xff) << shift);
 117        } else if (size == 2) {
 118                shift = (where & 2) << 3;
 119                data &= ~(0xffff << shift);
 120                data |= ((val & 0xffff) << shift);
 121        } else
 122                data = val;
 123
 124        ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus,
 125                                        devfn, where, &data);
 126out:
 127        spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
 128        return ret;
 129}
 130
 131struct pci_ops sh7786_pci_ops = {
 132        .read   = sh7786_pcie_read,
 133        .write  = sh7786_pcie_write,
 134};
 135