Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright 2001 MontaVista Software Inc. | |
3 | * Author: MontaVista Software, Inc. | |
4 | * ahennessy@mvista.com | |
5 | * | |
6 | * Copyright (C) 2000-2001 Toshiba Corporation | |
7 | * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) | |
8 | * | |
9 | * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c | |
10 | * | |
89d63fe1 | 11 | * Define the pci_ops for TX3927. |
1da177e4 LT |
12 | * |
13 | * Much of the code is derived from the original DDB5074 port by | |
5e888e8f | 14 | * Geert Uytterhoeven <geert@linux-m68k.org> |
1da177e4 LT |
15 | * |
16 | * This program is free software; you can redistribute it and/or modify it | |
17 | * under the terms of the GNU General Public License as published by the | |
18 | * Free Software Foundation; either version 2 of the License, or (at your | |
19 | * option) any later version. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
23 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
24 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
27 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
28 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | * | |
32 | * You should have received a copy of the GNU General Public License along | |
33 | * with this program; if not, write to the Free Software Foundation, Inc., | |
34 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
35 | */ | |
36 | #include <linux/types.h> | |
37 | #include <linux/pci.h> | |
38 | #include <linux/kernel.h> | |
39 | #include <linux/init.h> | |
455cc256 | 40 | #include <linux/interrupt.h> |
ca4d3e67 | 41 | #include <linux/irq.h> |
1da177e4 LT |
42 | |
43 | #include <asm/addrspace.h> | |
455cc256 AN |
44 | #include <asm/txx9irq.h> |
45 | #include <asm/txx9/pci.h> | |
89d63fe1 | 46 | #include <asm/txx9/tx3927.h> |
1da177e4 | 47 | |
32d00d0f | 48 | static int mkaddr(struct pci_bus *bus, unsigned char devfn, unsigned char where) |
1da177e4 | 49 | { |
32d00d0f AN |
50 | if (bus->parent == NULL && |
51 | devfn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0)) | |
52 | return -1; | |
53 | tx3927_pcicptr->ica = | |
54 | ((bus->number & 0xff) << 0x10) | | |
55 | ((devfn & 0xff) << 0x08) | | |
56 | (where & 0xfc) | (bus->parent ? 1 : 0); | |
1da177e4 LT |
57 | |
58 | /* clear M_ABORT and Disable M_ABORT Int. */ | |
59 | tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; | |
60 | tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT; | |
32d00d0f | 61 | return 0; |
1da177e4 LT |
62 | } |
63 | ||
64 | static inline int check_abort(void) | |
65 | { | |
32d00d0f | 66 | if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) { |
1da177e4 LT |
67 | tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT; |
68 | tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT; | |
32d00d0f AN |
69 | /* flush write buffer */ |
70 | iob(); | |
1da177e4 | 71 | return PCIBIOS_DEVICE_NOT_FOUND; |
32d00d0f | 72 | } |
1da177e4 LT |
73 | return PCIBIOS_SUCCESSFUL; |
74 | } | |
75 | ||
89d63fe1 | 76 | static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn, |
1da177e4 LT |
77 | int where, int size, u32 * val) |
78 | { | |
32d00d0f AN |
79 | if (mkaddr(bus, devfn, where)) { |
80 | *val = 0xffffffff; | |
81 | return PCIBIOS_DEVICE_NOT_FOUND; | |
82 | } | |
1da177e4 LT |
83 | |
84 | switch (size) { | |
85 | case 1: | |
86 | *val = *(volatile u8 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3)); | |
87 | break; | |
88 | ||
89 | case 2: | |
90 | *val = le16_to_cpu(*(volatile u16 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3))); | |
91 | break; | |
92 | ||
93 | case 4: | |
94 | *val = le32_to_cpu(tx3927_pcicptr->icd); | |
95 | break; | |
96 | } | |
97 | ||
98 | return check_abort(); | |
99 | } | |
100 | ||
89d63fe1 | 101 | static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn, |
1da177e4 LT |
102 | int where, int size, u32 val) |
103 | { | |
32d00d0f AN |
104 | if (mkaddr(bus, devfn, where)) |
105 | return PCIBIOS_DEVICE_NOT_FOUND; | |
1da177e4 LT |
106 | |
107 | switch (size) { | |
108 | case 1: | |
109 | *(volatile u8 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 3)) = val; | |
110 | break; | |
111 | ||
112 | case 2: | |
09b696ef | 113 | *(volatile u16 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 2)) = |
1da177e4 LT |
114 | cpu_to_le16(val); |
115 | break; | |
116 | ||
117 | case 4: | |
118 | tx3927_pcicptr->icd = cpu_to_le32(val); | |
119 | } | |
120 | ||
1da177e4 LT |
121 | return check_abort(); |
122 | } | |
123 | ||
89d63fe1 AN |
124 | static struct pci_ops tx3927_pci_ops = { |
125 | .read = tx3927_pci_read_config, | |
126 | .write = tx3927_pci_write_config, | |
1da177e4 | 127 | }; |
89d63fe1 AN |
128 | |
129 | void __init tx3927_pcic_setup(struct pci_controller *channel, | |
130 | unsigned long sdram_size, int extarb) | |
131 | { | |
132 | unsigned long flags; | |
133 | unsigned long io_base = | |
134 | channel->io_resource->start + mips_io_port_base - IO_BASE; | |
135 | unsigned long io_size = | |
136 | channel->io_resource->end - channel->io_resource->start; | |
137 | unsigned long io_pciaddr = | |
138 | channel->io_resource->start - channel->io_offset; | |
139 | unsigned long mem_base = | |
140 | channel->mem_resource->start; | |
141 | unsigned long mem_size = | |
142 | channel->mem_resource->end - channel->mem_resource->start; | |
143 | unsigned long mem_pciaddr = | |
144 | channel->mem_resource->start - channel->mem_offset; | |
145 | ||
146 | printk(KERN_INFO "TX3927 PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:%s", | |
147 | tx3927_pcicptr->did, tx3927_pcicptr->vid, | |
148 | tx3927_pcicptr->rid, | |
149 | extarb ? "External" : "Internal"); | |
150 | channel->pci_ops = &tx3927_pci_ops; | |
151 | ||
152 | local_irq_save(flags); | |
153 | /* Disable External PCI Config. Access */ | |
154 | tx3927_pcicptr->lbc = TX3927_PCIC_LBC_EPCAD; | |
155 | #ifdef __BIG_ENDIAN | |
156 | tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_IBSE | | |
157 | TX3927_PCIC_LBC_TIBSE | | |
158 | TX3927_PCIC_LBC_TMFBSE | TX3927_PCIC_LBC_MSDSE; | |
159 | #endif | |
160 | /* LB->PCI mappings */ | |
161 | tx3927_pcicptr->iomas = ~(io_size - 1); | |
162 | tx3927_pcicptr->ilbioma = io_base; | |
163 | tx3927_pcicptr->ipbioma = io_pciaddr; | |
164 | tx3927_pcicptr->mmas = ~(mem_size - 1); | |
165 | tx3927_pcicptr->ilbmma = mem_base; | |
166 | tx3927_pcicptr->ipbmma = mem_pciaddr; | |
167 | /* PCI->LB mappings */ | |
168 | tx3927_pcicptr->iobas = 0xffffffff; | |
169 | tx3927_pcicptr->ioba = 0; | |
170 | tx3927_pcicptr->tlbioma = 0; | |
171 | tx3927_pcicptr->mbas = ~(sdram_size - 1); | |
172 | tx3927_pcicptr->mba = 0; | |
173 | tx3927_pcicptr->tlbmma = 0; | |
174 | /* Enable Direct mapping Address Space Decoder */ | |
175 | tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_ILMDE | TX3927_PCIC_LBC_ILIDE; | |
176 | ||
177 | /* Clear All Local Bus Status */ | |
178 | tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL; | |
179 | /* Enable All Local Bus Interrupts */ | |
180 | tx3927_pcicptr->lbim = TX3927_PCIC_LBIM_ALL; | |
181 | /* Clear All PCI Status Error */ | |
182 | tx3927_pcicptr->pcistat = TX3927_PCIC_PCISTATIM_ALL; | |
183 | /* Enable All PCI Status Error Interrupts */ | |
184 | tx3927_pcicptr->pcistatim = TX3927_PCIC_PCISTATIM_ALL; | |
185 | ||
186 | /* PCIC Int => IRC IRQ10 */ | |
187 | tx3927_pcicptr->il = TX3927_IR_PCI; | |
188 | /* Target Control (per errata) */ | |
189 | tx3927_pcicptr->tc = TX3927_PCIC_TC_OF8E | TX3927_PCIC_TC_IF8E; | |
190 | ||
191 | /* Enable Bus Arbiter */ | |
192 | if (!extarb) | |
193 | tx3927_pcicptr->pbapmc = TX3927_PCIC_PBAPMC_PBAEN; | |
194 | ||
195 | tx3927_pcicptr->pcicmd = PCI_COMMAND_MASTER | | |
196 | PCI_COMMAND_MEMORY | | |
197 | PCI_COMMAND_IO | | |
198 | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; | |
199 | local_irq_restore(flags); | |
200 | } | |
455cc256 AN |
201 | |
202 | static irqreturn_t tx3927_pcierr_interrupt(int irq, void *dev_id) | |
203 | { | |
204 | struct pt_regs *regs = get_irq_regs(); | |
205 | ||
206 | if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) { | |
207 | printk(KERN_WARNING "PCI error interrupt at 0x%08lx.\n", | |
208 | regs->cp0_epc); | |
209 | printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", | |
210 | tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat); | |
211 | } | |
212 | if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) { | |
213 | /* clear all pci errors */ | |
214 | tx3927_pcicptr->pcistat |= TX3927_PCIC_PCISTATIM_ALL; | |
215 | tx3927_pcicptr->istat = TX3927_PCIC_IIM_ALL; | |
216 | tx3927_pcicptr->tstat = TX3927_PCIC_TIM_ALL; | |
217 | tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL; | |
218 | return IRQ_HANDLED; | |
219 | } | |
220 | console_verbose(); | |
221 | panic("PCI error."); | |
222 | } | |
223 | ||
224 | void __init tx3927_setup_pcierr_irq(void) | |
225 | { | |
226 | if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI, | |
227 | tx3927_pcierr_interrupt, | |
8b5690f8 | 228 | 0, "PCI error", |
455cc256 AN |
229 | (void *)TX3927_PCIC_REG)) |
230 | printk(KERN_WARNING "Failed to request irq for PCIERR\n"); | |
231 | } |