xref: /openbmc/linux/arch/mips/pci/ops-sni.c (revision e5451c8f8330e03ad3cfa16048b4daf961af434f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds  * for more details.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * SNI specific PCI support for RM200/RM300.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Copyright (C) 1997 - 2000, 2003 Ralf Baechle <ralf@linux-mips.org>
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/pci.h>
121da177e4SLinus Torvalds #include <linux/types.h>
131da177e4SLinus Torvalds #include <asm/sni.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds /*
161da177e4SLinus Torvalds  * It seems that on the RM200 only lower 3 bits of the 5 bit PCI device
171da177e4SLinus Torvalds  * address are decoded.	 We therefore manually have to reject attempts at
181da177e4SLinus Torvalds  * reading outside this range.	Being on the paranoid side we only do this
191da177e4SLinus Torvalds  * test for bus 0 and hope forwarding and decoding work properly for any
201da177e4SLinus Torvalds  * subordinated busses.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * ASIC PCI only supports type 1 config cycles.
231da177e4SLinus Torvalds  */
set_config_address(unsigned int busno,unsigned int devfn,int reg)241da177e4SLinus Torvalds static int set_config_address(unsigned int busno, unsigned int devfn, int reg)
251da177e4SLinus Torvalds {
261da177e4SLinus Torvalds 	if ((devfn > 255) || (reg > 255))
271da177e4SLinus Torvalds 		return PCIBIOS_BAD_REGISTER_NUMBER;
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds 	if (busno == 0 && devfn >= PCI_DEVFN(8, 0))
301da177e4SLinus Torvalds 		return PCIBIOS_DEVICE_NOT_FOUND;
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds 	*(volatile u32 *)PCIMT_CONFIG_ADDRESS =
331da177e4SLinus Torvalds 		 ((busno    & 0xff) << 16) |
341da177e4SLinus Torvalds 		 ((devfn    & 0xff) <<	8) |
351da177e4SLinus Torvalds 		  (reg	    & 0xfc);
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 	return PCIBIOS_SUCCESSFUL;
381da177e4SLinus Torvalds }
391da177e4SLinus Torvalds 
pcimt_read(struct pci_bus * bus,unsigned int devfn,int reg,int size,u32 * val)401da177e4SLinus Torvalds static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg,
411da177e4SLinus Torvalds 		      int size, u32 * val)
421da177e4SLinus Torvalds {
431da177e4SLinus Torvalds 	int res;
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 	if ((res = set_config_address(bus->number, devfn, reg)))
461da177e4SLinus Torvalds 		return res;
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 	switch (size) {
491da177e4SLinus Torvalds 	case 1:
504a0312fcSThomas Bogendoerfer 		*val = inb(PCIMT_CONFIG_DATA + (reg & 3));
511da177e4SLinus Torvalds 		break;
521da177e4SLinus Torvalds 	case 2:
534a0312fcSThomas Bogendoerfer 		*val = inw(PCIMT_CONFIG_DATA + (reg & 2));
541da177e4SLinus Torvalds 		break;
551da177e4SLinus Torvalds 	case 4:
564a0312fcSThomas Bogendoerfer 		*val = inl(PCIMT_CONFIG_DATA);
571da177e4SLinus Torvalds 		break;
581da177e4SLinus Torvalds 	}
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	return 0;
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds 
pcimt_write(struct pci_bus * bus,unsigned int devfn,int reg,int size,u32 val)631da177e4SLinus Torvalds static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg,
641da177e4SLinus Torvalds 		       int size, u32 val)
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds 	int res;
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	if ((res = set_config_address(bus->number, devfn, reg)))
691da177e4SLinus Torvalds 		return res;
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	switch (size) {
721da177e4SLinus Torvalds 	case 1:
734a0312fcSThomas Bogendoerfer 		outb(val, PCIMT_CONFIG_DATA + (reg & 3));
741da177e4SLinus Torvalds 		break;
751da177e4SLinus Torvalds 	case 2:
764a0312fcSThomas Bogendoerfer 		outw(val, PCIMT_CONFIG_DATA + (reg & 2));
771da177e4SLinus Torvalds 		break;
781da177e4SLinus Torvalds 	case 4:
794a0312fcSThomas Bogendoerfer 		outl(val, PCIMT_CONFIG_DATA);
801da177e4SLinus Torvalds 		break;
811da177e4SLinus Torvalds 	}
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds 	return 0;
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds 
86*c066a32aSThomas Bogendoerfer struct pci_ops sni_pcimt_ops = {
871da177e4SLinus Torvalds 	.read = pcimt_read,
881da177e4SLinus Torvalds 	.write = pcimt_write,
891da177e4SLinus Torvalds };
90*c066a32aSThomas Bogendoerfer 
pcit_set_config_address(unsigned int busno,unsigned int devfn,int reg)91*c066a32aSThomas Bogendoerfer static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg)
92*c066a32aSThomas Bogendoerfer {
93*c066a32aSThomas Bogendoerfer 	if ((devfn > 255) || (reg > 255) || (busno > 255))
94*c066a32aSThomas Bogendoerfer 		return PCIBIOS_BAD_REGISTER_NUMBER;
95*c066a32aSThomas Bogendoerfer 
96*c066a32aSThomas Bogendoerfer 	outl((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8);
97*c066a32aSThomas Bogendoerfer 	return PCIBIOS_SUCCESSFUL;
98*c066a32aSThomas Bogendoerfer }
99*c066a32aSThomas Bogendoerfer 
pcit_read(struct pci_bus * bus,unsigned int devfn,int reg,int size,u32 * val)100*c066a32aSThomas Bogendoerfer static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg,
101*c066a32aSThomas Bogendoerfer 		      int size, u32 * val)
102*c066a32aSThomas Bogendoerfer {
103*c066a32aSThomas Bogendoerfer 	int res;
104*c066a32aSThomas Bogendoerfer 
105*c066a32aSThomas Bogendoerfer 	/*
106*c066a32aSThomas Bogendoerfer 	 * on bus 0 we need to check, whether there is a device answering
107*c066a32aSThomas Bogendoerfer 	 * for the devfn by doing a config write and checking the result. If
108*c066a32aSThomas Bogendoerfer 	 * we don't do it, we will get a data bus error
109*c066a32aSThomas Bogendoerfer 	 */
110*c066a32aSThomas Bogendoerfer 	if (bus->number == 0) {
111*c066a32aSThomas Bogendoerfer 		pcit_set_config_address(0, 0, 0x68);
112*c066a32aSThomas Bogendoerfer 		outl(inl(0xcfc) | 0xc0000000, 0xcfc);
113*c066a32aSThomas Bogendoerfer 		if ((res = pcit_set_config_address(0, devfn, 0)))
114*c066a32aSThomas Bogendoerfer 			return res;
115*c066a32aSThomas Bogendoerfer 		outl(0xffffffff, 0xcfc);
116*c066a32aSThomas Bogendoerfer 		pcit_set_config_address(0, 0, 0x68);
117*c066a32aSThomas Bogendoerfer 		if (inl(0xcfc) & 0x100000)
118*c066a32aSThomas Bogendoerfer 			return PCIBIOS_DEVICE_NOT_FOUND;
119*c066a32aSThomas Bogendoerfer 	}
120*c066a32aSThomas Bogendoerfer 	if ((res = pcit_set_config_address(bus->number, devfn, reg)))
121*c066a32aSThomas Bogendoerfer 		return res;
122*c066a32aSThomas Bogendoerfer 
123*c066a32aSThomas Bogendoerfer 	switch (size) {
124*c066a32aSThomas Bogendoerfer 	case 1:
125*c066a32aSThomas Bogendoerfer 		*val = inb(PCIMT_CONFIG_DATA + (reg & 3));
126*c066a32aSThomas Bogendoerfer 		break;
127*c066a32aSThomas Bogendoerfer 	case 2:
128*c066a32aSThomas Bogendoerfer 		*val = inw(PCIMT_CONFIG_DATA + (reg & 2));
129*c066a32aSThomas Bogendoerfer 		break;
130*c066a32aSThomas Bogendoerfer 	case 4:
131*c066a32aSThomas Bogendoerfer 		*val = inl(PCIMT_CONFIG_DATA);
132*c066a32aSThomas Bogendoerfer 		break;
133*c066a32aSThomas Bogendoerfer 	}
134*c066a32aSThomas Bogendoerfer 	return 0;
135*c066a32aSThomas Bogendoerfer }
136*c066a32aSThomas Bogendoerfer 
pcit_write(struct pci_bus * bus,unsigned int devfn,int reg,int size,u32 val)137*c066a32aSThomas Bogendoerfer static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg,
138*c066a32aSThomas Bogendoerfer 		       int size, u32 val)
139*c066a32aSThomas Bogendoerfer {
140*c066a32aSThomas Bogendoerfer 	int res;
141*c066a32aSThomas Bogendoerfer 
142*c066a32aSThomas Bogendoerfer 	if ((res = pcit_set_config_address(bus->number, devfn, reg)))
143*c066a32aSThomas Bogendoerfer 		return res;
144*c066a32aSThomas Bogendoerfer 
145*c066a32aSThomas Bogendoerfer 	switch (size) {
146*c066a32aSThomas Bogendoerfer 	case 1:
147*c066a32aSThomas Bogendoerfer 		outb(val, PCIMT_CONFIG_DATA + (reg & 3));
148*c066a32aSThomas Bogendoerfer 		break;
149*c066a32aSThomas Bogendoerfer 	case 2:
150*c066a32aSThomas Bogendoerfer 		outw(val, PCIMT_CONFIG_DATA + (reg & 2));
151*c066a32aSThomas Bogendoerfer 		break;
152*c066a32aSThomas Bogendoerfer 	case 4:
153*c066a32aSThomas Bogendoerfer 		outl(val, PCIMT_CONFIG_DATA);
154*c066a32aSThomas Bogendoerfer 		break;
155*c066a32aSThomas Bogendoerfer 	}
156*c066a32aSThomas Bogendoerfer 
157*c066a32aSThomas Bogendoerfer 	return 0;
158*c066a32aSThomas Bogendoerfer }
159*c066a32aSThomas Bogendoerfer 
160*c066a32aSThomas Bogendoerfer 
161*c066a32aSThomas Bogendoerfer struct pci_ops sni_pcit_ops = {
162*c066a32aSThomas Bogendoerfer 	.read = pcit_read,
163*c066a32aSThomas Bogendoerfer 	.write = pcit_write,
164*c066a32aSThomas Bogendoerfer };
165