diff options
Diffstat (limited to 'arch/mips/pmc-sierra/yosemite/ht.c')
-rw-r--r-- | arch/mips/pmc-sierra/yosemite/ht.c | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/arch/mips/pmc-sierra/yosemite/ht.c b/arch/mips/pmc-sierra/yosemite/ht.c new file mode 100644 index 000000000000..dad228d3a220 --- /dev/null +++ b/arch/mips/pmc-sierra/yosemite/ht.c | |||
@@ -0,0 +1,454 @@ | |||
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/config.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/version.h> | ||
32 | #include <asm/pci.h> | ||
33 | #include <asm/io.h> | ||
34 | |||
35 | #include <linux/init.h> | ||
36 | #include <asm/titan_dep.h> | ||
37 | |||
38 | #ifdef CONFIG_HYPERTRANSPORT | ||
39 | |||
40 | |||
41 | /* | ||
42 | * This function check if the Hypertransport Link Initialization completed. If | ||
43 | * it did, then proceed further with scanning bus #2 | ||
44 | */ | ||
45 | static __inline__ int check_titan_htlink(void) | ||
46 | { | ||
47 | u32 val; | ||
48 | |||
49 | val = *(volatile uint32_t *)(RM9000x2_HTLINK_REG); | ||
50 | if (val & 0x00000020) | ||
51 | /* HT Link Initialization completed */ | ||
52 | return 1; | ||
53 | else | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int titan_ht_config_read_dword(struct pci_dev *device, | ||
58 | int offset, u32* val) | ||
59 | { | ||
60 | int dev, bus, func; | ||
61 | uint32_t address_reg, data_reg; | ||
62 | uint32_t address; | ||
63 | |||
64 | bus = device->bus->number; | ||
65 | dev = PCI_SLOT(device->devfn); | ||
66 | func = PCI_FUNC(device->devfn); | ||
67 | |||
68 | /* XXX Need to change the Bus # */ | ||
69 | if (bus > 2) | ||
70 | address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) | | ||
71 | 0x80000000 | 0x1; | ||
72 | else | ||
73 | address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000; | ||
74 | |||
75 | address_reg = RM9000x2_OCD_HTCFGA; | ||
76 | data_reg = RM9000x2_OCD_HTCFGD; | ||
77 | |||
78 | RM9K_WRITE(address_reg, address); | ||
79 | RM9K_READ(data_reg, val); | ||
80 | |||
81 | return PCIBIOS_SUCCESSFUL; | ||
82 | } | ||
83 | |||
84 | |||
85 | static int titan_ht_config_read_word(struct pci_dev *device, | ||
86 | int offset, u16* val) | ||
87 | { | ||
88 | int dev, bus, func; | ||
89 | uint32_t address_reg, data_reg; | ||
90 | uint32_t address; | ||
91 | |||
92 | bus = device->bus->number; | ||
93 | dev = PCI_SLOT(device->devfn); | ||
94 | func = PCI_FUNC(device->devfn); | ||
95 | |||
96 | /* XXX Need to change the Bus # */ | ||
97 | if (bus > 2) | ||
98 | address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) | | ||
99 | 0x80000000 | 0x1; | ||
100 | else | ||
101 | address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000; | ||
102 | |||
103 | address_reg = RM9000x2_OCD_HTCFGA; | ||
104 | data_reg = RM9000x2_OCD_HTCFGD; | ||
105 | |||
106 | if ((offset & 0x3) == 0) | ||
107 | offset = 0x2; | ||
108 | else | ||
109 | offset = 0x0; | ||
110 | |||
111 | RM9K_WRITE(address_reg, address); | ||
112 | RM9K_READ_16(data_reg + offset, val); | ||
113 | |||
114 | return PCIBIOS_SUCCESSFUL; | ||
115 | } | ||
116 | |||
117 | |||
118 | u32 longswap(unsigned long l) | ||
119 | { | ||
120 | unsigned char b1,b2,b3,b4; | ||
121 | |||
122 | b1 = l&255; | ||
123 | b2 = (l>>8)&255; | ||
124 | b3 = (l>>16)&255; | ||
125 | b4 = (l>>24)&255; | ||
126 | |||
127 | return ((b1<<24) + (b2<<16) + (b3<<8) + b4); | ||
128 | } | ||
129 | |||
130 | |||
131 | static int titan_ht_config_read_byte(struct pci_dev *device, | ||
132 | int offset, u8* val) | ||
133 | { | ||
134 | int dev, bus, func; | ||
135 | uint32_t address_reg, data_reg; | ||
136 | uint32_t address; | ||
137 | int offset1; | ||
138 | |||
139 | bus = device->bus->number; | ||
140 | dev = PCI_SLOT(device->devfn); | ||
141 | func = PCI_FUNC(device->devfn); | ||
142 | |||
143 | /* XXX Need to change the Bus # */ | ||
144 | if (bus > 2) | ||
145 | address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) | | ||
146 | 0x80000000 | 0x1; | ||
147 | else | ||
148 | address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000; | ||
149 | |||
150 | address_reg = RM9000x2_OCD_HTCFGA; | ||
151 | data_reg = RM9000x2_OCD_HTCFGD; | ||
152 | |||
153 | RM9K_WRITE(address_reg, address); | ||
154 | |||
155 | if ((offset & 0x3) == 0) { | ||
156 | offset1 = 0x3; | ||
157 | } | ||
158 | if ((offset & 0x3) == 1) { | ||
159 | offset1 = 0x2; | ||
160 | } | ||
161 | if ((offset & 0x3) == 2) { | ||
162 | offset1 = 0x1; | ||
163 | } | ||
164 | if ((offset & 0x3) == 3) { | ||
165 | offset1 = 0x0; | ||
166 | } | ||
167 | RM9K_READ_8(data_reg + offset1, val); | ||
168 | |||
169 | return PCIBIOS_SUCCESSFUL; | ||
170 | } | ||
171 | |||
172 | |||
173 | static int titan_ht_config_write_dword(struct pci_dev *device, | ||
174 | int offset, u8 val) | ||
175 | { | ||
176 | int dev, bus, func; | ||
177 | uint32_t address_reg, data_reg; | ||
178 | uint32_t address; | ||
179 | |||
180 | bus = device->bus->number; | ||
181 | dev = PCI_SLOT(device->devfn); | ||
182 | func = PCI_FUNC(device->devfn); | ||
183 | |||
184 | /* XXX Need to change the Bus # */ | ||
185 | if (bus > 2) | ||
186 | address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) | | ||
187 | 0x80000000 | 0x1; | ||
188 | else | ||
189 | address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000; | ||
190 | |||
191 | address_reg = RM9000x2_OCD_HTCFGA; | ||
192 | data_reg = RM9000x2_OCD_HTCFGD; | ||
193 | |||
194 | RM9K_WRITE(address_reg, address); | ||
195 | RM9K_WRITE(data_reg, val); | ||
196 | |||
197 | return PCIBIOS_SUCCESSFUL; | ||
198 | } | ||
199 | |||
200 | static int titan_ht_config_write_word(struct pci_dev *device, | ||
201 | int offset, u8 val) | ||
202 | { | ||
203 | int dev, bus, func; | ||
204 | uint32_t address_reg, data_reg; | ||
205 | uint32_t address; | ||
206 | |||
207 | bus = device->bus->number; | ||
208 | dev = PCI_SLOT(device->devfn); | ||
209 | func = PCI_FUNC(device->devfn); | ||
210 | |||
211 | /* XXX Need to change the Bus # */ | ||
212 | if (bus > 2) | ||
213 | address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) | | ||
214 | 0x80000000 | 0x1; | ||
215 | else | ||
216 | address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000; | ||
217 | |||
218 | address_reg = RM9000x2_OCD_HTCFGA; | ||
219 | data_reg = RM9000x2_OCD_HTCFGD; | ||
220 | |||
221 | if ((offset & 0x3) == 0) | ||
222 | offset = 0x2; | ||
223 | else | ||
224 | offset = 0x0; | ||
225 | |||
226 | RM9K_WRITE(address_reg, address); | ||
227 | RM9K_WRITE_16(data_reg + offset, val); | ||
228 | |||
229 | return PCIBIOS_SUCCESSFUL; | ||
230 | } | ||
231 | |||
232 | static int titan_ht_config_write_byte(struct pci_dev *device, | ||
233 | int offset, u8 val) | ||
234 | { | ||
235 | int dev, bus, func; | ||
236 | uint32_t address_reg, data_reg; | ||
237 | uint32_t address; | ||
238 | int offset1; | ||
239 | |||
240 | bus = device->bus->number; | ||
241 | dev = PCI_SLOT(device->devfn); | ||
242 | func = PCI_FUNC(device->devfn); | ||
243 | |||
244 | /* XXX Need to change the Bus # */ | ||
245 | if (bus > 2) | ||
246 | address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) | | ||
247 | 0x80000000 | 0x1; | ||
248 | else | ||
249 | address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000; | ||
250 | |||
251 | address_reg = RM9000x2_OCD_HTCFGA; | ||
252 | data_reg = RM9000x2_OCD_HTCFGD; | ||
253 | |||
254 | RM9K_WRITE(address_reg, address); | ||
255 | |||
256 | if ((offset & 0x3) == 0) { | ||
257 | offset1 = 0x3; | ||
258 | } | ||
259 | if ((offset & 0x3) == 1) { | ||
260 | offset1 = 0x2; | ||
261 | } | ||
262 | if ((offset & 0x3) == 2) { | ||
263 | offset1 = 0x1; | ||
264 | } | ||
265 | if ((offset & 0x3) == 3) { | ||
266 | offset1 = 0x0; | ||
267 | } | ||
268 | |||
269 | RM9K_WRITE_8(data_reg + offset1, val); | ||
270 | return PCIBIOS_SUCCESSFUL; | ||
271 | } | ||
272 | |||
273 | |||
274 | static void titan_pcibios_set_master(struct pci_dev *dev) | ||
275 | { | ||
276 | u16 cmd; | ||
277 | int bus = dev->bus->number; | ||
278 | |||
279 | if (check_titan_htlink()) | ||
280 | titan_ht_config_read_word(dev, PCI_COMMAND, &cmd); | ||
281 | |||
282 | cmd |= PCI_COMMAND_MASTER; | ||
283 | |||
284 | if (check_titan_htlink()) | ||
285 | titan_ht_config_write_word(dev, PCI_COMMAND, cmd); | ||
286 | } | ||
287 | |||
288 | |||
289 | int pcibios_enable_resources(struct pci_dev *dev) | ||
290 | { | ||
291 | u16 cmd, old_cmd; | ||
292 | u8 tmp1; | ||
293 | int idx; | ||
294 | struct resource *r; | ||
295 | int bus = dev->bus->number; | ||
296 | |||
297 | if (check_titan_htlink()) | ||
298 | titan_ht_config_read_word(dev, PCI_COMMAND, &cmd); | ||
299 | |||
300 | old_cmd = cmd; | ||
301 | for (idx = 0; idx < 6; idx++) { | ||
302 | r = &dev->resource[idx]; | ||
303 | if (!r->start && r->end) { | ||
304 | printk(KERN_ERR | ||
305 | "PCI: Device %s not available because of " | ||
306 | "resource collisions\n", pci_name(dev)); | ||
307 | return -EINVAL; | ||
308 | } | ||
309 | if (r->flags & IORESOURCE_IO) | ||
310 | cmd |= PCI_COMMAND_IO; | ||
311 | if (r->flags & IORESOURCE_MEM) | ||
312 | cmd |= PCI_COMMAND_MEMORY; | ||
313 | } | ||
314 | if (cmd != old_cmd) { | ||
315 | if (check_titan_htlink()) | ||
316 | titan_ht_config_write_word(dev, PCI_COMMAND, cmd); | ||
317 | } | ||
318 | |||
319 | if (check_titan_htlink()) | ||
320 | titan_ht_config_read_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1); | ||
321 | |||
322 | if (tmp1 != 8) { | ||
323 | printk(KERN_WARNING "PCI setting cache line size to 8 from " | ||
324 | "%d\n", tmp1); | ||
325 | } | ||
326 | |||
327 | if (check_titan_htlink()) | ||
328 | titan_ht_config_write_byte(dev, PCI_CACHE_LINE_SIZE, 8); | ||
329 | |||
330 | if (check_titan_htlink()) | ||
331 | titan_ht_config_read_byte(dev, PCI_LATENCY_TIMER, &tmp1); | ||
332 | |||
333 | if (tmp1 < 32 || tmp1 == 0xff) { | ||
334 | printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n", | ||
335 | tmp1); | ||
336 | } | ||
337 | |||
338 | if (check_titan_htlink()) | ||
339 | titan_ht_config_write_byte(dev, PCI_LATENCY_TIMER, 32); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | |||
345 | int pcibios_enable_device(struct pci_dev *dev, int mask) | ||
346 | { | ||
347 | return pcibios_enable_resources(dev); | ||
348 | } | ||
349 | |||
350 | |||
351 | |||
352 | void pcibios_update_resource(struct pci_dev *dev, struct resource *root, | ||
353 | struct resource *res, int resource) | ||
354 | { | ||
355 | u32 new, check; | ||
356 | int reg; | ||
357 | |||
358 | return; | ||
359 | |||
360 | new = res->start | (res->flags & PCI_REGION_FLAG_MASK); | ||
361 | if (resource < 6) { | ||
362 | reg = PCI_BASE_ADDRESS_0 + 4 * resource; | ||
363 | } else if (resource == PCI_ROM_RESOURCE) { | ||
364 | res->flags |= IORESOURCE_ROM_ENABLE; | ||
365 | reg = dev->rom_base_reg; | ||
366 | } else { | ||
367 | /* | ||
368 | * Somebody might have asked allocation of a non-standard | ||
369 | * resource | ||
370 | */ | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | pci_write_config_dword(dev, reg, new); | ||
375 | pci_read_config_dword(dev, reg, &check); | ||
376 | if ((new ^ check) & | ||
377 | ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : | ||
378 | PCI_BASE_ADDRESS_MEM_MASK)) { | ||
379 | printk(KERN_ERR "PCI: Error while updating region " | ||
380 | "%s/%d (%08x != %08x)\n", pci_name(dev), resource, | ||
381 | new, check); | ||
382 | } | ||
383 | } | ||
384 | |||
385 | |||
386 | void pcibios_align_resource(void *data, struct resource *res, | ||
387 | unsigned long size, unsigned long align) | ||
388 | { | ||
389 | struct pci_dev *dev = data; | ||
390 | |||
391 | if (res->flags & IORESOURCE_IO) { | ||
392 | unsigned long start = res->start; | ||
393 | |||
394 | /* We need to avoid collisions with `mirrored' VGA ports | ||
395 | and other strange ISA hardware, so we always want the | ||
396 | addresses kilobyte aligned. */ | ||
397 | if (size > 0x100) { | ||
398 | printk(KERN_ERR "PCI: I/O Region %s/%d too large" | ||
399 | " (%ld bytes)\n", pci_name(dev), | ||
400 | dev->resource - res, size); | ||
401 | } | ||
402 | |||
403 | start = (start + 1024 - 1) & ~(1024 - 1); | ||
404 | res->start = start; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | struct pci_ops titan_pci_ops = { | ||
409 | titan_ht_config_read_byte, | ||
410 | titan_ht_config_read_word, | ||
411 | titan_ht_config_read_dword, | ||
412 | titan_ht_config_write_byte, | ||
413 | titan_ht_config_write_word, | ||
414 | titan_ht_config_write_dword | ||
415 | }; | ||
416 | |||
417 | void __init pcibios_fixup_bus(struct pci_bus *c) | ||
418 | { | ||
419 | titan_ht_pcibios_fixup_bus(c); | ||
420 | } | ||
421 | |||
422 | void __init pcibios_init(void) | ||
423 | { | ||
424 | |||
425 | /* Reset PCI I/O and PCI MEM values */ | ||
426 | /* XXX Need to add the proper values here */ | ||
427 | ioport_resource.start = 0xe0000000; | ||
428 | ioport_resource.end = 0xe0000000 + 0x20000000 - 1; | ||
429 | iomem_resource.start = 0xc0000000; | ||
430 | iomem_resource.end = 0xc0000000 + 0x20000000 - 1; | ||
431 | |||
432 | /* XXX Need to add bus values */ | ||
433 | pci_scan_bus(2, &titan_pci_ops, NULL); | ||
434 | pci_scan_bus(3, &titan_pci_ops, NULL); | ||
435 | } | ||
436 | |||
437 | /* | ||
438 | * for parsing "pci=" kernel boot arguments. | ||
439 | */ | ||
440 | char *pcibios_setup(char *str) | ||
441 | { | ||
442 | printk(KERN_INFO "rr: pcibios_setup\n"); | ||
443 | /* Nothing to do for now. */ | ||
444 | |||
445 | return str; | ||
446 | } | ||
447 | |||
448 | unsigned __init int pcibios_assign_all_busses(void) | ||
449 | { | ||
450 | /* We want to use the PCI bus detection done by PMON */ | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | #endif /* CONFIG_HYPERTRANSPORT */ | ||