ops-gt64xxx_pci0.c 4.07 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2 3 4 5
 * Copyright (C) 1999, 2000, 2004  MIPS Technologies, Inc.
 *	All rights reserved.
 *	Authors: Carsten Langgaard <carstenl@mips.com>
 *		 Maciej W. Rozycki <macro@mips.com>
Linus Torvalds's avatar
Linus Torvalds committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 *  This program is free software; you can distribute it and/or modify it
 *  under the terms of the GNU General Public License (Version 2) as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope it will be useful, but WITHOUT
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 *  for more details.
 *
 *  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.,
 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 */
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>

#include <asm/gt64120.h>

Ralf Baechle's avatar
Ralf Baechle committed
26
#define PCI_ACCESS_READ	 0
Linus Torvalds's avatar
Linus Torvalds committed
27 28 29 30 31 32
#define PCI_ACCESS_WRITE 1

/*
 *  PCI configuration cycle AD bus definition
 */
/* Type 0 */
Ralf Baechle's avatar
Ralf Baechle committed
33 34
#define PCI_CFG_TYPE0_REG_SHF		0
#define PCI_CFG_TYPE0_FUNC_SHF		8
Linus Torvalds's avatar
Linus Torvalds committed
35 36

/* Type 1 */
Ralf Baechle's avatar
Ralf Baechle committed
37 38 39 40
#define PCI_CFG_TYPE1_REG_SHF		0
#define PCI_CFG_TYPE1_FUNC_SHF		8
#define PCI_CFG_TYPE1_DEV_SHF		11
#define PCI_CFG_TYPE1_BUS_SHF		16
Linus Torvalds's avatar
Linus Torvalds committed
41

42 43
static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type,
		struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
Linus Torvalds's avatar
Linus Torvalds committed
44 45 46 47 48 49 50 51 52
{
	unsigned char busnum = bus->number;
	u32 intr;

	if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0)))
		return -1;	/* Because of a bug in the galileo (for slot 31). */

	/* Clear cause register bits */
	GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
Ralf Baechle's avatar
Ralf Baechle committed
53
				     GT_INTRCAUSE_TARABORT0_BIT));
Linus Torvalds's avatar
Linus Torvalds committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

	/* Setup address */
	GT_WRITE(GT_PCI0_CFGADDR_OFS,
		 (busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) |
		 (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
		 ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
		 GT_PCI0_CFGADDR_CONFIGEN_BIT);

	if (access_type == PCI_ACCESS_WRITE) {
		if (busnum == 0 && PCI_SLOT(devfn) == 0) {
			/*
			 * The Galileo system controller is acting
			 * differently than other devices.
			 */
			GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
		} else
			__GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
	} else {
		if (busnum == 0 && PCI_SLOT(devfn) == 0) {
			/*
			 * The Galileo system controller is acting
			 * differently than other devices.
			 */
			*data = GT_READ(GT_PCI0_CFGDATA_OFS);
		} else
			*data = __GT_READ(GT_PCI0_CFGDATA_OFS);
	}

	/* Check for master or target abort */
	intr = GT_READ(GT_INTRCAUSE_OFS);

	if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
		/* Error occurred */

		/* Clear bits */
		GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
Ralf Baechle's avatar
Ralf Baechle committed
90
					     GT_INTRCAUSE_TARABORT0_BIT));
Linus Torvalds's avatar
Linus Torvalds committed
91 92 93 94 95 96 97 98 99 100 101 102

		return -1;
	}

	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.
 */
103 104
static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn,
		int where, int size, u32 * val)
Linus Torvalds's avatar
Linus Torvalds committed
105 106 107
{
	u32 data = 0;

108
	if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
Ralf Baechle's avatar
Ralf Baechle committed
109
					       where, &data))
Linus Torvalds's avatar
Linus Torvalds committed
110 111 112 113 114 115 116 117 118 119 120 121
		return PCIBIOS_DEVICE_NOT_FOUND;

	if (size == 1)
		*val = (data >> ((where & 3) << 3)) & 0xff;
	else if (size == 2)
		*val = (data >> ((where & 3) << 3)) & 0xffff;
	else
		*val = data;

	return PCIBIOS_SUCCESSFUL;
}

122 123
static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn,
		int where, int size, u32 val)
Linus Torvalds's avatar
Linus Torvalds committed
124 125 126 127 128 129
{
	u32 data = 0;

	if (size == 4)
		data = val;
	else {
130
		if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus,
Ralf Baechle's avatar
Ralf Baechle committed
131
						       devfn, where, &data))
Linus Torvalds's avatar
Linus Torvalds committed
132 133 134 135 136 137 138 139 140 141
			return PCIBIOS_DEVICE_NOT_FOUND;

		if (size == 1)
			data = (data & ~(0xff << ((where & 3) << 3))) |
				(val << ((where & 3) << 3));
		else if (size == 2)
			data = (data & ~(0xffff << ((where & 3) << 3))) |
				(val << ((where & 3) << 3));
	}

142
	if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn,
Ralf Baechle's avatar
Ralf Baechle committed
143
					       where, &data))
Linus Torvalds's avatar
Linus Torvalds committed
144 145 146 147 148
		return PCIBIOS_DEVICE_NOT_FOUND;

	return PCIBIOS_SUCCESSFUL;
}

149 150 151
struct pci_ops gt64xxx_pci0_ops = {
	.read	= gt64xxx_pci0_pcibios_read,
	.write	= gt64xxx_pci0_pcibios_write
Linus Torvalds's avatar
Linus Torvalds committed
152
};