1/* 2 * 3 * BRIEF MODULE DESCRIPTION 4 * 5 * 2.6 port, Embedded Alley Solutions, Inc 6 * 7 * Based on: 8 * Author: source@mvista.com 9 * 10 * This program is free software; you can distribute it and/or modify it 11 * under the terms of the GNU General Public License (Version 2) as 12 * published by the Free Software Foundation. 13 * 14 * This program is distributed in the hope it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 * for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write to the Free Software Foundation, Inc., 21 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 22 */ 23#include <linux/types.h> 24#include <linux/pci.h> 25#include <linux/kernel.h> 26#include <linux/init.h> 27#include <linux/vmalloc.h> 28#include <linux/delay.h> 29 30#include <asm/mach-pnx8550/pci.h> 31#include <asm/mach-pnx8550/glb.h> 32 33static inline void clear_status(void) 34{ 35 unsigned long pci_stat; 36 37 pci_stat = inl(PCI_BASE | PCI_GPPM_STATUS); 38 outl(pci_stat, PCI_BASE | PCI_GPPM_ICLR); 39} 40 41static inline unsigned int 42calc_cfg_addr(struct pci_bus *bus, unsigned int devfn, int where) 43{ 44 unsigned int addr; 45 46 addr = ((bus->number > 0) ? (((bus->number & 0xff) << PCI_CFG_BUS_SHIFT) | 1) : 0); 47 addr |= ((devfn & 0xff) << PCI_CFG_FUNC_SHIFT) | (where & 0xfc); 48 49 return addr; 50} 51 52static int 53config_access(unsigned int pci_cmd, struct pci_bus *bus, unsigned int devfn, int where, unsigned int pci_mode, unsigned int *val) 54{ 55 unsigned int flags; 56 unsigned long loops = 0; 57 unsigned long ioaddr = calc_cfg_addr(bus, devfn, where); 58 59 local_irq_save(flags); 60 /*Clear pending interrupt status */ 61 if (inl(PCI_BASE | PCI_GPPM_STATUS)) { 62 clear_status(); 63 while (!(inl(PCI_BASE | PCI_GPPM_STATUS) == 0)) ; 64 } 65 66 outl(ioaddr, PCI_BASE | PCI_GPPM_ADDR); 67 68 if ((pci_cmd == PCI_CMD_IOW) || (pci_cmd == PCI_CMD_CONFIG_WRITE)) 69 outl(*val, PCI_BASE | PCI_GPPM_WDAT); 70 71 outl(INIT_PCI_CYCLE | pci_cmd | (pci_mode & PCI_BYTE_ENABLE_MASK), 72 PCI_BASE | PCI_GPPM_CTRL); 73 74 loops = 75 ((loops_per_jiffy * 76 PCI_IO_JIFFIES_TIMEOUT) >> (PCI_IO_JIFFIES_SHIFT)); 77 while (1) { 78 if (inl(PCI_BASE | PCI_GPPM_STATUS) & GPPM_DONE) { 79 if ((pci_cmd == PCI_CMD_IOR) || 80 (pci_cmd == PCI_CMD_CONFIG_READ)) 81 *val = inl(PCI_BASE | PCI_GPPM_RDAT); 82 clear_status(); 83 local_irq_restore(flags); 84 return PCIBIOS_SUCCESSFUL; 85 } else if (inl(PCI_BASE | PCI_GPPM_STATUS) & GPPM_R_MABORT) { 86 break; 87 } 88 89 loops--; 90 if (loops == 0) { 91 printk("%s : Arbiter Locked.\n", __func__); 92 } 93 } 94 95 clear_status(); 96 if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_IOW)) { 97 printk("%s timeout (GPPM_CTRL=%X) ioaddr %lX pci_cmd %X\n", 98 __func__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr, 99 pci_cmd); 100 } 101 102 if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_CONFIG_READ)) 103 *val = 0xffffffff; 104 local_irq_restore(flags); 105 return PCIBIOS_DEVICE_NOT_FOUND; 106} 107 108/* 109 * We can't address 8 and 16 bit words directly. Instead we have to 110 * read/write a 32bit word and mask/modify the data we actually want. 111 */ 112static int 113read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val) 114{ 115 unsigned int data = 0; 116 int err; 117 118 if (bus == NULL) 119 return -1; 120 121 err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, ~(1 << (where & 3)), &data); 122 switch (where & 0x03) { 123 case 0: 124 *val = (unsigned char)(data & 0x000000ff); 125 break; 126 case 1: 127 *val = (unsigned char)((data & 0x0000ff00) >> 8); 128 break; 129 case 2: 130 *val = (unsigned char)((data & 0x00ff0000) >> 16); 131 break; 132 case 3: 133 *val = (unsigned char)((data & 0xff000000) >> 24); 134 break; 135 } 136 137 return err; 138} 139 140static int 141read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val) 142{ 143 unsigned int data = 0; 144 int err; 145 146 if (bus == NULL) 147 return -1; 148 149 if (where & 0x01) 150 return PCIBIOS_BAD_REGISTER_NUMBER; 151 152 err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, ~(3 << (where & 3)), &data); 153 switch (where & 0x02) { 154 case 0: 155 *val = (unsigned short)(data & 0x0000ffff); 156 break; 157 case 2: 158 *val = (unsigned short)((data & 0xffff0000) >> 16); 159 break; 160 } 161 162 return err; 163} 164 165static int 166read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val) 167{ 168 int err; 169 if (bus == NULL) 170 return -1; 171 172 if (where & 0x03) 173 return PCIBIOS_BAD_REGISTER_NUMBER; 174 175 err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, 0, val); 176 177 return err; 178} 179 180static int 181write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val) 182{ 183 unsigned int data = (unsigned int)val; 184 int err; 185 186 if (bus == NULL) 187 return -1; 188 189 switch (where & 0x03) { 190 case 1: 191 data = (data << 8); 192 break; 193 case 2: 194 data = (data << 16); 195 break; 196 case 3: 197 data = (data << 24); 198 break; 199 default: 200 break; 201 } 202 203 err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, ~(1 << (where & 3)), &data); 204 205 return err; 206} 207 208static int 209write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val) 210{ 211 unsigned int data = (unsigned int)val; 212 int err; 213 214 if (bus == NULL) 215 return -1; 216 217 if (where & 0x01) 218 return PCIBIOS_BAD_REGISTER_NUMBER; 219 220 switch (where & 0x02) { 221 case 2: 222 data = (data << 16); 223 break; 224 default: 225 break; 226 } 227 err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, ~(3 << (where & 3)), &data); 228 229 return err; 230} 231 232static int 233write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val) 234{ 235 int err; 236 if (bus == NULL) 237 return -1; 238 239 if (where & 0x03) 240 return PCIBIOS_BAD_REGISTER_NUMBER; 241 242 err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, 0, &val); 243 244 return err; 245} 246 247static int config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) 248{ 249 switch (size) { 250 case 1: { 251 u8 _val; 252 int rc = read_config_byte(bus, devfn, where, &_val); 253 *val = _val; 254 return rc; 255 } 256 case 2: { 257 u16 _val; 258 int rc = read_config_word(bus, devfn, where, &_val); 259 *val = _val; 260 return rc; 261 } 262 default: 263 return read_config_dword(bus, devfn, where, val); 264 } 265} 266 267static int config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) 268{ 269 switch (size) { 270 case 1: 271 return write_config_byte(bus, devfn, where, (u8) val); 272 case 2: 273 return write_config_word(bus, devfn, where, (u16) val); 274 default: 275 return write_config_dword(bus, devfn, where, val); 276 } 277} 278 279struct pci_ops pnx8550_pci_ops = { 280 config_read, 281 config_write 282}; 283