diff options
Diffstat (limited to 'arch/mips/pci/ops-it8172.c')
-rw-r--r-- | arch/mips/pci/ops-it8172.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/arch/mips/pci/ops-it8172.c b/arch/mips/pci/ops-it8172.c new file mode 100644 index 0000000..b7a8b9a --- /dev/null +++ b/arch/mips/pci/ops-it8172.c @@ -0,0 +1,215 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 system controller specific pci support. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_pci.h> + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static struct resource pci_mem_resource_1; + +static struct resource pci_io_resource = { + "io pci IO space", + 0x14018000, + 0x17FFFFFF, + IORESOURCE_IO +}; + +static struct resource pci_mem_resource_0 = { + "ext pci memory space 0/1", + 0x10101000, + 0x13FFFFFF, + IORESOURCE_MEM, + &pci_mem_resource_0, + NULL, + &pci_mem_resource_1 +}; + +static struct resource pci_mem_resource_1 = { + "ext pci memory space 2/3", + 0x1A000000, + 0x1FBFFFFF, + IORESOURCE_MEM, + &pci_mem_resource_0, + NULL, + NULL +}; + +extern struct pci_ops it8172_pci_ops; + +struct pci_controller it8172_controller = { + .pci_ops = &it8172_pci_ops, + .io_resource = &pci_io_resource, + .mem_resource = &pci_mem_resource_0, +}; + +static int it8172_pcibios_config_access(unsigned char access_type, + struct pci_bus *bus, + unsigned int devfn, int where, + u32 * data) +{ + /* + * config cycles are on 4 byte boundary only + */ + + /* Setup address */ + IT_WRITE(IT_CONFADDR, (bus->number << IT_BUSNUM_SHF) | + (devfn << IT_FUNCNUM_SHF) | (where & ~0x3)); + + if (access_type == PCI_ACCESS_WRITE) { + IT_WRITE(IT_CONFDATA, *data); + } else { + IT_READ(IT_CONFDATA, *data); + } + + /* + * Revisit: check for master or target abort. + */ + return 0; +} + + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + u32 data = 0; + + switch (size) { + case 1: + if (it8172_pcibios_config_access + (PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xff; + + return PCIBIOS_SUCCESSFUL; + + case 2: + + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access + (PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = (data >> ((where & 3) << 3)) & 0xffff; + DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n", + dev->bus->number, dev->devfn, where, *val); + + return PCIBIOS_SUCCESSFUL; + + case 4: + + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access + (PCI_ACCESS_READ, dev, where, &data)) + return -1; + + *val = data; + + return PCIBIOS_SUCCESSFUL; + } +} + + +static write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + u32 data = 0; + + switch (size) { + case 1: + if (it8172_pcibios_config_access + (PCI_ACCESS_READ, dev, where, &data)) + return -1; + + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (it8172_pcibios_config_access + (PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; + + case 2: + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access + (PCI_ACCESS_READ, dev, where, &data)) + eturn - 1; + + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + + if (it8172_pcibios_config_access + (PCI_ACCESS_WRITE, dev, where, &data)) + return -1; + + return PCIBIOS_SUCCESSFUL; + + case 4: + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (it8172_pcibios_config_access + (PCI_ACCESS_WRITE, dev, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; + } +} + +struct pci_ops it8172_pci_ops = { + .read = read_config, + .write = write_config, +}; |