ia64/linux-2.6.18-xen.hg

annotate arch/mips/pci/ops-pnx8550.c @ 0:831230e53067

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