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