diff options
Diffstat (limited to 'arch/mips/pci')
| -rw-r--r-- | arch/mips/pci/fixup-au1000.c | 43 | ||||
| -rw-r--r-- | arch/mips/pci/fixup-yosemite.c | 41 | ||||
| -rw-r--r-- | arch/mips/pci/ops-au1000.c | 308 | ||||
| -rw-r--r-- | arch/mips/pci/ops-titan-ht.c | 124 | ||||
| -rw-r--r-- | arch/mips/pci/ops-titan.c | 111 | ||||
| -rw-r--r-- | arch/mips/pci/pci-yosemite.c | 67 |
6 files changed, 694 insertions, 0 deletions
diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c new file mode 100644 index 00000000000..e2ddfc49237 --- /dev/null +++ b/arch/mips/pci/fixup-au1000.c | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * BRIEF MODULE DESCRIPTION | ||
| 3 | * Board specific PCI fixups. | ||
| 4 | * | ||
| 5 | * Copyright 2001-2003, 2008 MontaVista Software Inc. | ||
| 6 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
| 14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
| 15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
| 16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
| 19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
| 20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 23 | * | ||
| 24 | * You should have received a copy of the GNU General Public License along | ||
| 25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <linux/pci.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | |||
| 32 | extern char irq_tab_alchemy[][5]; | ||
| 33 | |||
| 34 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
| 35 | { | ||
| 36 | return irq_tab_alchemy[slot][pin]; | ||
| 37 | } | ||
| 38 | |||
| 39 | /* Do platform specific device initialization at pci_enable_device() time */ | ||
| 40 | int pcibios_plat_dev_init(struct pci_dev *dev) | ||
| 41 | { | ||
| 42 | return 0; | ||
| 43 | } | ||
diff --git a/arch/mips/pci/fixup-yosemite.c b/arch/mips/pci/fixup-yosemite.c new file mode 100644 index 00000000000..fdafb13a793 --- /dev/null +++ b/arch/mips/pci/fixup-yosemite.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2003 PMC-Sierra | ||
| 3 | * Author: Manish Lachwani (lachwani@pmc-sierra.com) | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License as published by the | ||
| 7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 8 | * option) any later version. | ||
| 9 | * | ||
| 10 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
| 11 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
| 12 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
| 13 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 14 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 15 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
| 16 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
| 17 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 18 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 19 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License along | ||
| 22 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 23 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 24 | */ | ||
| 25 | #include <linux/kernel.h> | ||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/pci.h> | ||
| 28 | |||
| 29 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
| 30 | { | ||
| 31 | if (pin == 0) | ||
| 32 | return -1; | ||
| 33 | |||
| 34 | return 3; /* Everything goes to one irq bit */ | ||
| 35 | } | ||
| 36 | |||
| 37 | /* Do platform specific device initialization at pci_enable_device() time */ | ||
| 38 | int pcibios_plat_dev_init(struct pci_dev *dev) | ||
| 39 | { | ||
| 40 | return 0; | ||
| 41 | } | ||
diff --git a/arch/mips/pci/ops-au1000.c b/arch/mips/pci/ops-au1000.c new file mode 100644 index 00000000000..9a57c5ab91d --- /dev/null +++ b/arch/mips/pci/ops-au1000.c | |||
| @@ -0,0 +1,308 @@ | |||
| 1 | /* | ||
| 2 | * BRIEF MODULE DESCRIPTION | ||
| 3 | * Alchemy/AMD Au1xx0 PCI support. | ||
| 4 | * | ||
| 5 | * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. | ||
| 6 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
| 7 | * | ||
| 8 | * Support for all devices (greater than 16) added by David Gathright. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the | ||
| 12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 13 | * option) any later version. | ||
| 14 | * | ||
| 15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
| 16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
| 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
| 18 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
| 21 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
| 22 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 25 | * | ||
| 26 | * You should have received a copy of the GNU General Public License along | ||
| 27 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <linux/types.h> | ||
| 32 | #include <linux/pci.h> | ||
| 33 | #include <linux/kernel.h> | ||
| 34 | #include <linux/init.h> | ||
| 35 | #include <linux/vmalloc.h> | ||
| 36 | |||
| 37 | #include <asm/mach-au1x00/au1000.h> | ||
| 38 | |||
| 39 | #undef DEBUG | ||
| 40 | #ifdef DEBUG | ||
| 41 | #define DBG(x...) printk(KERN_DEBUG x) | ||
| 42 | #else | ||
| 43 | #define DBG(x...) | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #define PCI_ACCESS_READ 0 | ||
| 47 | #define PCI_ACCESS_WRITE 1 | ||
| 48 | |||
| 49 | int (*board_pci_idsel)(unsigned int devsel, int assert); | ||
| 50 | |||
| 51 | void mod_wired_entry(int entry, unsigned long entrylo0, | ||
| 52 | unsigned long entrylo1, unsigned long entryhi, | ||
| 53 | unsigned long pagemask) | ||
| 54 | { | ||
| 55 | unsigned long old_pagemask; | ||
| 56 | unsigned long old_ctx; | ||
| 57 | |||
| 58 | /* Save old context and create impossible VPN2 value */ | ||
| 59 | old_ctx = read_c0_entryhi() & 0xff; | ||
| 60 | old_pagemask = read_c0_pagemask(); | ||
| 61 | write_c0_index(entry); | ||
| 62 | write_c0_pagemask(pagemask); | ||
| 63 | write_c0_entryhi(entryhi); | ||
| 64 | write_c0_entrylo0(entrylo0); | ||
| 65 | write_c0_entrylo1(entrylo1); | ||
| 66 | tlb_write_indexed(); | ||
| 67 | write_c0_entryhi(old_ctx); | ||
| 68 | write_c0_pagemask(old_pagemask); | ||
| 69 | } | ||
| 70 | |||
| 71 | static struct vm_struct *pci_cfg_vm; | ||
| 72 | static int pci_cfg_wired_entry; | ||
| 73 | static unsigned long last_entryLo0, last_entryLo1; | ||
| 74 | |||
| 75 | /* | ||
| 76 | * We can't ioremap the entire pci config space because it's too large. | ||
| 77 | * Nor can we call ioremap dynamically because some device drivers use | ||
| 78 | * the PCI config routines from within interrupt handlers and that | ||
| 79 | * becomes a problem in get_vm_area(). We use one wired TLB to handle | ||
| 80 | * all config accesses for all busses. | ||
| 81 | */ | ||
| 82 | void __init au1x_pci_cfg_init(void) | ||
| 83 | { | ||
| 84 | /* Reserve a wired entry for PCI config accesses */ | ||
| 85 | pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP); | ||
| 86 | if (!pci_cfg_vm) | ||
| 87 | panic(KERN_ERR "PCI unable to get vm area\n"); | ||
| 88 | pci_cfg_wired_entry = read_c0_wired(); | ||
| 89 | add_wired_entry(0, 0, (unsigned long)pci_cfg_vm->addr, PM_4K); | ||
| 90 | last_entryLo0 = last_entryLo1 = 0xffffffff; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int config_access(unsigned char access_type, struct pci_bus *bus, | ||
| 94 | unsigned int dev_fn, unsigned char where, u32 *data) | ||
| 95 | { | ||
| 96 | #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) | ||
| 97 | unsigned int device = PCI_SLOT(dev_fn); | ||
| 98 | unsigned int function = PCI_FUNC(dev_fn); | ||
| 99 | unsigned long offset, status; | ||
| 100 | unsigned long cfg_base; | ||
| 101 | unsigned long flags; | ||
| 102 | int error = PCIBIOS_SUCCESSFUL; | ||
| 103 | unsigned long entryLo0, entryLo1; | ||
| 104 | |||
| 105 | if (device > 19) { | ||
| 106 | *data = 0xffffffff; | ||
| 107 | return -1; | ||
| 108 | } | ||
| 109 | |||
| 110 | local_irq_save(flags); | ||
| 111 | au_writel(((0x2000 << 16) | (au_readl(Au1500_PCI_STATCMD) & 0xffff)), | ||
| 112 | Au1500_PCI_STATCMD); | ||
| 113 | au_sync_udelay(1); | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Allow board vendors to implement their own off-chip IDSEL. | ||
| 117 | * If it doesn't succeed, may as well bail out at this point. | ||
| 118 | */ | ||
| 119 | if (board_pci_idsel && board_pci_idsel(device, 1) == 0) { | ||
| 120 | *data = 0xffffffff; | ||
| 121 | local_irq_restore(flags); | ||
| 122 | return -1; | ||
| 123 | } | ||
| 124 | |||
| 125 | /* Setup the config window */ | ||
| 126 | if (bus->number == 0) | ||
| 127 | cfg_base = (1 << device) << 11; | ||
| 128 | else | ||
| 129 | cfg_base = 0x80000000 | (bus->number << 16) | (device << 11); | ||
| 130 | |||
| 131 | /* Setup the lower bits of the 36-bit address */ | ||
| 132 | offset = (function << 8) | (where & ~0x3); | ||
| 133 | /* Pick up any address that falls below the page mask */ | ||
| 134 | offset |= cfg_base & ~PAGE_MASK; | ||
| 135 | |||
| 136 | /* Page boundary */ | ||
| 137 | cfg_base = cfg_base & PAGE_MASK; | ||
| 138 | |||
| 139 | /* | ||
| 140 | * To improve performance, if the current device is the same as | ||
| 141 | * the last device accessed, we don't touch the TLB. | ||
| 142 | */ | ||
| 143 | entryLo0 = (6 << 26) | (cfg_base >> 6) | (2 << 3) | 7; | ||
| 144 | entryLo1 = (6 << 26) | (cfg_base >> 6) | (0x1000 >> 6) | (2 << 3) | 7; | ||
| 145 | if ((entryLo0 != last_entryLo0) || (entryLo1 != last_entryLo1)) { | ||
| 146 | mod_wired_entry(pci_cfg_wired_entry, entryLo0, entryLo1, | ||
| 147 | (unsigned long)pci_cfg_vm->addr, PM_4K); | ||
| 148 | last_entryLo0 = entryLo0; | ||
| 149 | last_entryLo1 = entryLo1; | ||
| 150 | } | ||
| 151 | |||
| 152 | if (access_type == PCI_ACCESS_WRITE) | ||
| 153 | au_writel(*data, (int)(pci_cfg_vm->addr + offset)); | ||
| 154 | else | ||
| 155 | *data = au_readl((int)(pci_cfg_vm->addr + offset)); | ||
| 156 | |||
| 157 | au_sync_udelay(2); | ||
| 158 | |||
| 159 | DBG("cfg_access %d bus->number %u dev %u at %x *data %x conf %lx\n", | ||
| 160 | access_type, bus->number, device, where, *data, offset); | ||
| 161 | |||
| 162 | /* Check master abort */ | ||
| 163 | status = au_readl(Au1500_PCI_STATCMD); | ||
| 164 | |||
| 165 | if (status & (1 << 29)) { | ||
| 166 | *data = 0xffffffff; | ||
| 167 | error = -1; | ||
| 168 | DBG("Au1x Master Abort\n"); | ||
| 169 | } else if ((status >> 28) & 0xf) { | ||
| 170 | DBG("PCI ERR detected: device %u, status %lx\n", | ||
| 171 | device, (status >> 28) & 0xf); | ||
| 172 | |||
| 173 | /* Clear errors */ | ||
| 174 | au_writel(status & 0xf000ffff, Au1500_PCI_STATCMD); | ||
| 175 | |||
| 176 | *data = 0xffffffff; | ||
| 177 | error = -1; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* Take away the IDSEL. */ | ||
| 181 | if (board_pci_idsel) | ||
| 182 | (void)board_pci_idsel(device, 0); | ||
| 183 | |||
| 184 | local_irq_restore(flags); | ||
| 185 | return error; | ||
| 186 | #endif | ||
| 187 | } | ||
| 188 | |||
| 189 | static int read_config_byte(struct pci_bus *bus, unsigned int devfn, | ||
| 190 | int where, u8 *val) | ||
| 191 | { | ||
| 192 | u32 data; | ||
| 193 | int ret; | ||
| 194 | |||
| 195 | ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); | ||
| 196 | if (where & 1) | ||
| 197 | data >>= 8; | ||
| 198 | if (where & 2) | ||
| 199 | data >>= 16; | ||
| 200 | *val = data & 0xff; | ||
| 201 | return ret; | ||
| 202 | } | ||
| 203 | |||
| 204 | static int read_config_word(struct pci_bus *bus, unsigned int devfn, | ||
| 205 | int where, u16 *val) | ||
| 206 | { | ||
| 207 | u32 data; | ||
| 208 | int ret; | ||
| 209 | |||
| 210 | ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); | ||
| 211 | if (where & 2) | ||
| 212 | data >>= 16; | ||
| 213 | *val = data & 0xffff; | ||
| 214 | return ret; | ||
| 215 | } | ||
| 216 | |||
| 217 | static int read_config_dword(struct pci_bus *bus, unsigned int devfn, | ||
| 218 | int where, u32 *val) | ||
| 219 | { | ||
| 220 | int ret; | ||
| 221 | |||
| 222 | ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val); | ||
| 223 | return ret; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int write_config_byte(struct pci_bus *bus, unsigned int devfn, | ||
| 227 | int where, u8 val) | ||
| 228 | { | ||
| 229 | u32 data = 0; | ||
| 230 | |||
| 231 | if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) | ||
| 232 | return -1; | ||
| 233 | |||
| 234 | data = (data & ~(0xff << ((where & 3) << 3))) | | ||
| 235 | (val << ((where & 3) << 3)); | ||
| 236 | |||
| 237 | if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) | ||
| 238 | return -1; | ||
| 239 | |||
| 240 | return PCIBIOS_SUCCESSFUL; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int write_config_word(struct pci_bus *bus, unsigned int devfn, | ||
| 244 | int where, u16 val) | ||
| 245 | { | ||
| 246 | u32 data = 0; | ||
| 247 | |||
| 248 | if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) | ||
| 249 | return -1; | ||
| 250 | |||
| 251 | data = (data & ~(0xffff << ((where & 3) << 3))) | | ||
| 252 | (val << ((where & 3) << 3)); | ||
| 253 | |||
| 254 | if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) | ||
| 255 | return -1; | ||
| 256 | |||
| 257 | return PCIBIOS_SUCCESSFUL; | ||
| 258 | } | ||
| 259 | |||
| 260 | static int write_config_dword(struct pci_bus *bus, unsigned int devfn, | ||
| 261 | int where, u32 val) | ||
| 262 | { | ||
| 263 | if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val)) | ||
| 264 | return -1; | ||
| 265 | |||
| 266 | return PCIBIOS_SUCCESSFUL; | ||
| 267 | } | ||
| 268 | |||
| 269 | static int config_read(struct pci_bus *bus, unsigned int devfn, | ||
| 270 | int where, int size, u32 *val) | ||
| 271 | { | ||
| 272 | switch (size) { | ||
| 273 | case 1: { | ||
| 274 | u8 _val; | ||
| 275 | int rc = read_config_byte(bus, devfn, where, &_val); | ||
| 276 | |||
| 277 | *val = _val; | ||
| 278 | return rc; | ||
| 279 | } | ||
| 280 | case 2: { | ||
| 281 | u16 _val; | ||
| 282 | int rc = read_config_word(bus, devfn, where, &_val); | ||
| 283 | |||
| 284 | *val = _val; | ||
| 285 | return rc; | ||
| 286 | } | ||
| 287 | default: | ||
| 288 | return read_config_dword(bus, devfn, where, val); | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | static int config_write(struct pci_bus *bus, unsigned int devfn, | ||
| 293 | int where, int size, u32 val) | ||
| 294 | { | ||
| 295 | switch (size) { | ||
| 296 | case 1: | ||
| 297 | return write_config_byte(bus, devfn, where, (u8) val); | ||
| 298 | case 2: | ||
| 299 | return write_config_word(bus, devfn, where, (u16) val); | ||
| 300 | default: | ||
| 301 | return write_config_dword(bus, devfn, where, val); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | struct pci_ops au1x_pci_ops = { | ||
| 306 | config_read, | ||
| 307 | config_write | ||
| 308 | }; | ||
diff --git a/arch/mips/pci/ops-titan-ht.c b/arch/mips/pci/ops-titan-ht.c new file mode 100644 index 00000000000..57d54adc9e2 --- /dev/null +++ b/arch/mips/pci/ops-titan-ht.c | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2003 PMC-Sierra | ||
| 3 | * Author: Manish Lachwani (lachwani@pmc-sierra.com) | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License as published by the | ||
| 7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 8 | * option) any later version. | ||
| 9 | * | ||
| 10 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
| 11 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
| 12 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
| 13 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 14 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 15 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
| 16 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
| 17 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 18 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 19 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License along | ||
| 22 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 23 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/types.h> | ||
| 27 | #include <linux/pci.h> | ||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/delay.h> | ||
| 30 | #include <asm/io.h> | ||
| 31 | |||
| 32 | #include <asm/titan_dep.h> | ||
| 33 | |||
| 34 | static int titan_ht_config_read_dword(struct pci_bus *bus, unsigned int devfn, | ||
| 35 | int offset, u32 *val) | ||
| 36 | { | ||
| 37 | volatile uint32_t address; | ||
| 38 | int busno; | ||
| 39 | |||
| 40 | busno = bus->number; | ||
| 41 | |||
| 42 | address = (busno << 16) | (devfn << 8) | (offset & 0xfc) | 0x80000000; | ||
| 43 | if (busno != 0) | ||
| 44 | address |= 1; | ||
| 45 | |||
| 46 | /* | ||
| 47 | * RM9000 HT Errata: Issue back to back HT config | ||
| 48 | * transcations. Issue a BIU sync before and | ||
| 49 | * after the HT cycle | ||
| 50 | */ | ||
| 51 | |||
| 52 | *(volatile int32_t *) 0xfb0000f0 |= 0x2; | ||
| 53 | |||
| 54 | udelay(30); | ||
| 55 | |||
| 56 | *(volatile int32_t *) 0xfb0006f8 = address; | ||
| 57 | *(val) = *(volatile int32_t *) 0xfb0006fc; | ||
| 58 | |||
| 59 | udelay(30); | ||
| 60 | |||
| 61 | * (volatile int32_t *) 0xfb0000f0 |= 0x2; | ||
| 62 | |||
| 63 | return PCIBIOS_SUCCESSFUL; | ||
| 64 | } | ||
| 65 | |||
| 66 | static int titan_ht_config_read(struct pci_bus *bus, unsigned int devfn, | ||
| 67 | int offset, int size, u32 *val) | ||
| 68 | { | ||
| 69 | uint32_t dword; | ||
| 70 | |||
| 71 | titan_ht_config_read_dword(bus, devfn, offset, &dword); | ||
| 72 | |||
| 73 | dword >>= ((offset & 3) << 3); | ||
| 74 | dword &= (0xffffffffU >> ((4 - size) << 8)); | ||
| 75 | |||
| 76 | return PCIBIOS_SUCCESSFUL; | ||
| 77 | } | ||
| 78 | |||
| 79 | static inline int titan_ht_config_write_dword(struct pci_bus *bus, | ||
| 80 | unsigned int devfn, int offset, u32 val) | ||
| 81 | { | ||
| 82 | volatile uint32_t address; | ||
| 83 | int busno; | ||
| 84 | |||
| 85 | busno = bus->number; | ||
| 86 | |||
| 87 | address = (busno << 16) | (devfn << 8) | (offset & 0xfc) | 0x80000000; | ||
| 88 | if (busno != 0) | ||
| 89 | address |= 1; | ||
| 90 | |||
| 91 | *(volatile int32_t *) 0xfb0000f0 |= 0x2; | ||
| 92 | |||
| 93 | udelay(30); | ||
| 94 | |||
| 95 | *(volatile int32_t *) 0xfb0006f8 = address; | ||
| 96 | *(volatile int32_t *) 0xfb0006fc = val; | ||
| 97 | |||
| 98 | udelay(30); | ||
| 99 | |||
| 100 | *(volatile int32_t *) 0xfb0000f0 |= 0x2; | ||
| 101 | |||
| 102 | return PCIBIOS_SUCCESSFUL; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int titan_ht_config_write(struct pci_bus *bus, unsigned int devfn, | ||
| 106 | int offset, int size, u32 val) | ||
| 107 | { | ||
| 108 | uint32_t val1, val2, mask; | ||
| 109 | |||
| 110 | titan_ht_config_read_dword(bus, devfn, offset, &val2); | ||
| 111 | |||
| 112 | val1 = val << ((offset & 3) << 3); | ||
| 113 | mask = ~(0xffffffffU >> ((4 - size) << 8)); | ||
| 114 | val2 &= ~(mask << ((offset & 3) << 8)); | ||
| 115 | |||
| 116 | titan_ht_config_write_dword(bus, devfn, offset, val1 | val2); | ||
| 117 | |||
| 118 | return PCIBIOS_SUCCESSFUL; | ||
| 119 | } | ||
| 120 | |||
| 121 | struct pci_ops titan_ht_pci_ops = { | ||
| 122 | .read = titan_ht_config_read, | ||
| 123 | .write = titan_ht_config_write, | ||
| 124 | }; | ||
diff --git a/arch/mips/pci/ops-titan.c b/arch/mips/pci/ops-titan.c new file mode 100644 index 00000000000..ebf8fc40e9b --- /dev/null +++ b/arch/mips/pci/ops-titan.c | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2003 PMC-Sierra | ||
| 3 | * Author: Manish Lachwani (lachwani@pmc-sierra.com) | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License as published by the | ||
| 7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 8 | * option) any later version. | ||
| 9 | * | ||
| 10 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
| 11 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
| 12 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
| 13 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 14 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 15 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
| 16 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
| 17 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 18 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 19 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License along | ||
| 22 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 23 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 24 | */ | ||
| 25 | #include <linux/types.h> | ||
| 26 | #include <linux/pci.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | |||
| 29 | #include <asm/pci.h> | ||
| 30 | #include <asm/io.h> | ||
| 31 | #include <asm/rm9k-ocd.h> | ||
| 32 | |||
| 33 | /* | ||
| 34 | * PCI specific defines | ||
| 35 | */ | ||
| 36 | #define TITAN_PCI_0_CONFIG_ADDRESS 0x780 | ||
| 37 | #define TITAN_PCI_0_CONFIG_DATA 0x784 | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Titan PCI Config Read Byte | ||
| 41 | */ | ||
| 42 | static int titan_read_config(struct pci_bus *bus, unsigned int devfn, int reg, | ||
| 43 | int size, u32 * val) | ||
| 44 | { | ||
| 45 | uint32_t address, tmp; | ||
| 46 | int dev, busno, func; | ||
| 47 | |||
| 48 | busno = bus->number; | ||
| 49 | dev = PCI_SLOT(devfn); | ||
| 50 | func = PCI_FUNC(devfn); | ||
| 51 | |||
| 52 | address = (busno << 16) | (dev << 11) | (func << 8) | | ||
| 53 | (reg & 0xfc) | 0x80000000; | ||
| 54 | |||
| 55 | |||
| 56 | /* start the configuration cycle */ | ||
| 57 | ocd_writel(address, TITAN_PCI_0_CONFIG_ADDRESS); | ||
| 58 | tmp = ocd_readl(TITAN_PCI_0_CONFIG_DATA) >> ((reg & 3) << 3); | ||
| 59 | |||
| 60 | switch (size) { | ||
| 61 | case 1: | ||
| 62 | tmp &= 0xff; | ||
| 63 | case 2: | ||
| 64 | tmp &= 0xffff; | ||
| 65 | } | ||
| 66 | *val = tmp; | ||
| 67 | |||
| 68 | return PCIBIOS_SUCCESSFUL; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int titan_write_config(struct pci_bus *bus, unsigned int devfn, int reg, | ||
| 72 | int size, u32 val) | ||
| 73 | { | ||
| 74 | uint32_t address; | ||
| 75 | int dev, busno, func; | ||
| 76 | |||
| 77 | busno = bus->number; | ||
| 78 | dev = PCI_SLOT(devfn); | ||
| 79 | func = PCI_FUNC(devfn); | ||
| 80 | |||
| 81 | address = (busno << 16) | (dev << 11) | (func << 8) | | ||
| 82 | (reg & 0xfc) | 0x80000000; | ||
| 83 | |||
| 84 | /* start the configuration cycle */ | ||
| 85 | ocd_writel(address, TITAN_PCI_0_CONFIG_ADDRESS); | ||
| 86 | |||
| 87 | /* write the data */ | ||
| 88 | switch (size) { | ||
| 89 | case 1: | ||
| 90 | ocd_writeb(val, TITAN_PCI_0_CONFIG_DATA + (~reg & 0x3)); | ||
| 91 | break; | ||
| 92 | |||
| 93 | case 2: | ||
| 94 | ocd_writew(val, TITAN_PCI_0_CONFIG_DATA + (~reg & 0x2)); | ||
| 95 | break; | ||
| 96 | |||
| 97 | case 4: | ||
| 98 | ocd_writel(val, TITAN_PCI_0_CONFIG_DATA); | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | |||
| 102 | return PCIBIOS_SUCCESSFUL; | ||
| 103 | } | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Titan PCI structure | ||
| 107 | */ | ||
| 108 | struct pci_ops titan_pci_ops = { | ||
| 109 | titan_read_config, | ||
| 110 | titan_write_config, | ||
| 111 | }; | ||
diff --git a/arch/mips/pci/pci-yosemite.c b/arch/mips/pci/pci-yosemite.c new file mode 100644 index 00000000000..cf5e1a25cb7 --- /dev/null +++ b/arch/mips/pci/pci-yosemite.c | |||
| @@ -0,0 +1,67 @@ | |||
| 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 | * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) | ||
| 7 | */ | ||
| 8 | #include <linux/init.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/types.h> | ||
| 11 | #include <linux/pci.h> | ||
| 12 | #include <asm/titan_dep.h> | ||
| 13 | |||
| 14 | extern struct pci_ops titan_pci_ops; | ||
| 15 | |||
| 16 | static struct resource py_mem_resource = { | ||
| 17 | .start = 0xe0000000UL, | ||
| 18 | .end = 0xe3ffffffUL, | ||
| 19 | .name = "Titan PCI MEM", | ||
| 20 | .flags = IORESOURCE_MEM | ||
| 21 | }; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * PMON really reserves 16MB of I/O port space but that's stupid, nothing | ||
| 25 | * needs that much since allocations are limited to 256 bytes per device | ||
| 26 | * anyway. So we just claim 64kB here. | ||
| 27 | */ | ||
| 28 | #define TITAN_IO_SIZE 0x0000ffffUL | ||
| 29 | #define TITAN_IO_BASE 0xe8000000UL | ||
| 30 | |||
| 31 | static struct resource py_io_resource = { | ||
| 32 | .start = 0x00001000UL, | ||
| 33 | .end = TITAN_IO_SIZE - 1, | ||
| 34 | .name = "Titan IO MEM", | ||
| 35 | .flags = IORESOURCE_IO, | ||
| 36 | }; | ||
| 37 | |||
| 38 | static struct pci_controller py_controller = { | ||
| 39 | .pci_ops = &titan_pci_ops, | ||
| 40 | .mem_resource = &py_mem_resource, | ||
| 41 | .mem_offset = 0x00000000UL, | ||
| 42 | .io_resource = &py_io_resource, | ||
| 43 | .io_offset = 0x00000000UL | ||
| 44 | }; | ||
| 45 | |||
| 46 | static char ioremap_failed[] __initdata = "Could not ioremap I/O port range"; | ||
| 47 | |||
| 48 | static int __init pmc_yosemite_setup(void) | ||
| 49 | { | ||
| 50 | unsigned long io_v_base; | ||
| 51 | |||
| 52 | io_v_base = (unsigned long) ioremap(TITAN_IO_BASE, TITAN_IO_SIZE); | ||
| 53 | if (!io_v_base) | ||
| 54 | panic(ioremap_failed); | ||
| 55 | |||
| 56 | set_io_port_base(io_v_base); | ||
| 57 | py_controller.io_map_base = io_v_base; | ||
| 58 | TITAN_WRITE(RM9000x2_OCD_LKM7, TITAN_READ(RM9000x2_OCD_LKM7) | 1); | ||
| 59 | |||
| 60 | ioport_resource.end = TITAN_IO_SIZE - 1; | ||
| 61 | |||
| 62 | register_pci_controller(&py_controller); | ||
| 63 | |||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | arch_initcall(pmc_yosemite_setup); | ||
