1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * SNI specific PCI support for RM200/RM300. 7 * 8 * Copyright (C) 1997 - 2000, 2003 Ralf Baechle <ralf@linux-mips.org> 9 */ 10 #include <linux/kernel.h> 11 #include <linux/pci.h> 12 #include <linux/types.h> 13 #include <asm/sni.h> 14 15 /* 16 * It seems that on the RM200 only lower 3 bits of the 5 bit PCI device 17 * address are decoded. We therefore manually have to reject attempts at 18 * reading outside this range. Being on the paranoid side we only do this 19 * test for bus 0 and hope forwarding and decoding work properly for any 20 * subordinated busses. 21 * 22 * ASIC PCI only supports type 1 config cycles. 23 */ 24 static int set_config_address(unsigned int busno, unsigned int devfn, int reg) 25 { 26 if ((devfn > 255) || (reg > 255)) 27 return PCIBIOS_BAD_REGISTER_NUMBER; 28 29 if (busno == 0 && devfn >= PCI_DEVFN(8, 0)) 30 return PCIBIOS_DEVICE_NOT_FOUND; 31 32 *(volatile u32 *)PCIMT_CONFIG_ADDRESS = 33 ((busno & 0xff) << 16) | 34 ((devfn & 0xff) << 8) | 35 (reg & 0xfc); 36 37 return PCIBIOS_SUCCESSFUL; 38 } 39 40 static int pcimt_read(struct pci_bus *bus, unsigned int devfn, int reg, 41 int size, u32 * val) 42 { 43 int res; 44 45 if ((res = set_config_address(bus->number, devfn, reg))) 46 return res; 47 48 switch (size) { 49 case 1: 50 *val = *(volatile u8 *) (PCIMT_CONFIG_DATA + (reg & 3)); 51 break; 52 case 2: 53 *val = *(volatile u16 *) (PCIMT_CONFIG_DATA + (reg & 2)); 54 break; 55 case 4: 56 *val = *(volatile u32 *) PCIMT_CONFIG_DATA; 57 break; 58 } 59 60 return 0; 61 } 62 63 static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg, 64 int size, u32 val) 65 { 66 int res; 67 68 if ((res = set_config_address(bus->number, devfn, reg))) 69 return res; 70 71 switch (size) { 72 case 1: 73 *(volatile u8 *) (PCIMT_CONFIG_DATA + (reg & 3)) = val; 74 break; 75 case 2: 76 *(volatile u16 *) (PCIMT_CONFIG_DATA + (reg & 2)) = val; 77 break; 78 case 4: 79 *(volatile u32 *) PCIMT_CONFIG_DATA = val; 80 break; 81 } 82 83 return 0; 84 } 85 86 struct pci_ops sni_pci_ops = { 87 .read = pcimt_read, 88 .write = pcimt_write, 89 }; 90