| Ralf Baechle | 23fbee9 | 2005-07-25 22:45:45 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  * Define the pci_ops for the Toshiba rbtx4938 | 
 | 3 |  * Copyright (C) 2000-2001 Toshiba Corporation | 
 | 4 |  * | 
 | 5 |  * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the | 
 | 6 |  * terms of the GNU General Public License version 2. This program is | 
 | 7 |  * licensed "as is" without any warranty of any kind, whether express | 
 | 8 |  * or implied. | 
 | 9 |  * | 
 | 10 |  * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com) | 
 | 11 |  */ | 
 | 12 | #include <linux/types.h> | 
 | 13 | #include <linux/pci.h> | 
 | 14 | #include <linux/kernel.h> | 
 | 15 | #include <linux/init.h> | 
 | 16 |  | 
 | 17 | #include <asm/addrspace.h> | 
 | 18 | #include <asm/tx4938/rbtx4938.h> | 
 | 19 |  | 
 | 20 | /* initialize in setup */ | 
 | 21 | struct resource pci_io_resource = { | 
 | 22 | 	.name	= "pci IO space", | 
 | 23 | 	.start	= 0, | 
 | 24 | 	.end	= 0, | 
 | 25 | 	.flags	= IORESOURCE_IO | 
 | 26 | }; | 
 | 27 |  | 
 | 28 | /* initialize in setup */ | 
 | 29 | struct resource pci_mem_resource = { | 
 | 30 | 	.name	= "pci memory space", | 
 | 31 | 	.start	= 0, | 
 | 32 | 	.end	= 0, | 
 | 33 | 	.flags	= IORESOURCE_MEM | 
 | 34 | }; | 
 | 35 |  | 
 | 36 | struct resource tx4938_pcic1_pci_io_resource = { | 
 | 37 |        	.name	= "PCI1 IO", | 
 | 38 |        	.start	= 0, | 
 | 39 |        	.end	= 0, | 
 | 40 |        	.flags	= IORESOURCE_IO | 
 | 41 | }; | 
 | 42 | struct resource tx4938_pcic1_pci_mem_resource = { | 
 | 43 |        	.name	= "PCI1 mem", | 
 | 44 |        	.start	= 0, | 
 | 45 |        	.end	= 0, | 
 | 46 |        	.flags	= IORESOURCE_MEM | 
 | 47 | }; | 
 | 48 |  | 
 | 49 | static int mkaddr(int bus, int dev_fn, int where, int *flagsp) | 
 | 50 | { | 
 | 51 | 	if (bus > 0) { | 
 | 52 | 		/* Type 1 configuration */ | 
 | 53 | 		tx4938_pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) | | 
 | 54 | 		    ((dev_fn & 0xff) << 0x08) | (where & 0xfc) | 1; | 
 | 55 | 	} else { | 
 | 56 | 		if (dev_fn >= PCI_DEVFN(TX4938_PCIC_MAX_DEVNU, 0)) | 
 | 57 | 			return -1; | 
 | 58 |  | 
 | 59 | 		/* Type 0 configuration */ | 
 | 60 | 		tx4938_pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) | | 
 | 61 | 		    ((dev_fn & 0xff) << 0x08) | (where & 0xfc); | 
 | 62 | 	} | 
 | 63 | 	/* clear M_ABORT and Disable M_ABORT Int. */ | 
 | 64 | 	tx4938_pcicptr->pcistatus = | 
 | 65 | 	    (tx4938_pcicptr->pcistatus & 0x0000ffff) | | 
 | 66 | 	    (PCI_STATUS_REC_MASTER_ABORT << 16); | 
 | 67 | 	tx4938_pcicptr->pcimask &= ~PCI_STATUS_REC_MASTER_ABORT; | 
 | 68 |  | 
 | 69 | 	return 0; | 
 | 70 | } | 
 | 71 |  | 
 | 72 | static int check_abort(int flags) | 
 | 73 | { | 
 | 74 | 	int code = PCIBIOS_SUCCESSFUL; | 
 | 75 | 	/* wait write cycle completion before checking error status */ | 
 | 76 | 	while (tx4938_pcicptr->pcicstatus & TX4938_PCIC_PCICSTATUS_IWB) | 
 | 77 | 				; | 
 | 78 | 	if (tx4938_pcicptr->pcistatus & (PCI_STATUS_REC_MASTER_ABORT << 16)) { | 
 | 79 | 		tx4938_pcicptr->pcistatus = | 
 | 80 | 		    (tx4938_pcicptr-> | 
 | 81 | 		     pcistatus & 0x0000ffff) | (PCI_STATUS_REC_MASTER_ABORT | 
 | 82 | 						<< 16); | 
 | 83 | 		tx4938_pcicptr->pcimask |= PCI_STATUS_REC_MASTER_ABORT; | 
 | 84 | 		code = PCIBIOS_DEVICE_NOT_FOUND; | 
 | 85 | 	} | 
 | 86 | 	return code; | 
 | 87 | } | 
 | 88 |  | 
 | 89 | static int tx4938_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, | 
 | 90 | 					int where, int size, u32 * val) | 
 | 91 | { | 
 | 92 | 	int flags, retval, dev, busno, func; | 
 | 93 |  | 
 | 94 | 	dev = PCI_SLOT(devfn); | 
 | 95 | 	func = PCI_FUNC(devfn); | 
 | 96 |  | 
 | 97 | 	/* check if the bus is top-level */ | 
 | 98 | 	if (bus->parent != NULL) | 
 | 99 | 		busno = bus->number; | 
 | 100 | 	else { | 
 | 101 | 		busno = 0; | 
 | 102 | 	} | 
 | 103 |  | 
 | 104 | 	if (mkaddr(busno, devfn, where, &flags)) | 
 | 105 | 		return -1; | 
 | 106 |  | 
 | 107 | 	switch (size) { | 
 | 108 | 	case 1: | 
 | 109 | 		*val = *(volatile u8 *) ((ulong) & tx4938_pcicptr->g2pcfgdata | | 
 | 110 | #ifdef __BIG_ENDIAN | 
 | 111 | 			      ((where & 3) ^ 3)); | 
 | 112 | #else | 
 | 113 | 			      (where & 3)); | 
 | 114 | #endif | 
 | 115 | 		break; | 
 | 116 | 	case 2: | 
 | 117 | 		*val = *(volatile u16 *) ((ulong) & tx4938_pcicptr->g2pcfgdata | | 
 | 118 | #ifdef __BIG_ENDIAN | 
 | 119 | 				((where & 3) ^ 2)); | 
 | 120 | #else | 
 | 121 | 				(where & 3)); | 
 | 122 | #endif | 
 | 123 | 		break; | 
 | 124 | 	case 4: | 
 | 125 | 		*val = tx4938_pcicptr->g2pcfgdata; | 
 | 126 | 		break; | 
 | 127 | 	} | 
 | 128 |  | 
 | 129 | 	retval = check_abort(flags); | 
 | 130 | 	if (retval == PCIBIOS_DEVICE_NOT_FOUND) | 
 | 131 | 		*val = 0xffffffff; | 
 | 132 |  | 
 | 133 | 	return retval; | 
 | 134 | } | 
 | 135 |  | 
 | 136 | static int tx4938_pcibios_write_config(struct pci_bus *bus, unsigned int devfn, int where, | 
 | 137 | 						int size, u32 val) | 
 | 138 | { | 
 | 139 | 	int flags, dev, busno, func; | 
 | 140 |  | 
 | 141 | 	busno = bus->number; | 
 | 142 | 	dev = PCI_SLOT(devfn); | 
 | 143 | 	func = PCI_FUNC(devfn); | 
 | 144 |  | 
 | 145 | 	/* check if the bus is top-level */ | 
 | 146 | 	if (bus->parent != NULL) { | 
 | 147 | 		busno = bus->number; | 
 | 148 | 	} else { | 
 | 149 | 		busno = 0; | 
 | 150 | 	} | 
 | 151 |  | 
 | 152 | 	if (mkaddr(busno, devfn, where, &flags)) | 
 | 153 | 		return -1; | 
 | 154 |  | 
 | 155 | 	switch (size) { | 
 | 156 | 	case 1: | 
 | 157 | 		*(volatile u8 *) ((ulong) & tx4938_pcicptr->g2pcfgdata | | 
 | 158 | #ifdef __BIG_ENDIAN | 
 | 159 | 			  ((where & 3) ^ 3)) = val; | 
 | 160 | #else | 
 | 161 | 			  (where & 3)) = val; | 
 | 162 | #endif | 
 | 163 | 		break; | 
 | 164 | 	case 2: | 
 | 165 | 		*(volatile u16 *) ((ulong) & tx4938_pcicptr->g2pcfgdata | | 
 | 166 | #ifdef __BIG_ENDIAN | 
 | 167 | 			((where & 0x3) ^ 0x2)) = val; | 
 | 168 | #else | 
 | 169 | 			(where & 3)) = val; | 
 | 170 | #endif | 
 | 171 | 		break; | 
 | 172 | 	case 4: | 
 | 173 | 		tx4938_pcicptr->g2pcfgdata = val; | 
 | 174 | 		break; | 
 | 175 | 	} | 
 | 176 |  | 
 | 177 | 	return check_abort(flags); | 
 | 178 | } | 
 | 179 |  | 
 | 180 | struct pci_ops tx4938_pci_ops = { | 
 | 181 | 	tx4938_pcibios_read_config, | 
 | 182 | 	tx4938_pcibios_write_config | 
 | 183 | }; | 
 | 184 |  | 
 | 185 | struct pci_controller tx4938_pci_controller[] = { | 
 | 186 | 	/* h/w only supports devices 0x00 to 0x14 */ | 
 | 187 | 	{ | 
 | 188 | 		.pci_ops        = &tx4938_pci_ops, | 
 | 189 | 		.io_resource    = &pci_io_resource, | 
 | 190 | 		.mem_resource   = &pci_mem_resource, | 
 | 191 | 	}, | 
 | 192 | 	/* h/w only supports devices 0x00 to 0x14 */ | 
 | 193 | 	{ | 
 | 194 | 		.pci_ops        = &tx4938_pci_ops, | 
 | 195 | 		.io_resource    = &tx4938_pcic1_pci_io_resource, | 
 | 196 | 		.mem_resource   = &tx4938_pcic1_pci_mem_resource, | 
 | 197 |         } | 
 | 198 | }; |