1c066a32aSThomas Bogendoerfer /*
2c066a32aSThomas Bogendoerfer * PCIMT specific code
3c066a32aSThomas Bogendoerfer *
4c066a32aSThomas Bogendoerfer * This file is subject to the terms and conditions of the GNU General Public
5c066a32aSThomas Bogendoerfer * License. See the file "COPYING" in the main directory of this archive
6c066a32aSThomas Bogendoerfer * for more details.
7c066a32aSThomas Bogendoerfer *
8c066a32aSThomas Bogendoerfer * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org)
90c2bf745SThomas Bogendoerfer * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
10c066a32aSThomas Bogendoerfer */
11c066a32aSThomas Bogendoerfer
12c066a32aSThomas Bogendoerfer #include <linux/init.h>
13c066a32aSThomas Bogendoerfer #include <linux/interrupt.h>
14ca4d3e67SDavid Howells #include <linux/irq.h>
15c066a32aSThomas Bogendoerfer #include <linux/pci.h>
16c066a32aSThomas Bogendoerfer #include <linux/serial_8250.h>
17c066a32aSThomas Bogendoerfer
18c066a32aSThomas Bogendoerfer #include <asm/sni.h>
19c066a32aSThomas Bogendoerfer #include <asm/time.h>
20c066a32aSThomas Bogendoerfer #include <asm/i8259.h>
21c066a32aSThomas Bogendoerfer #include <asm/irq_cpu.h>
22c066a32aSThomas Bogendoerfer
23c066a32aSThomas Bogendoerfer #define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF)
24c066a32aSThomas Bogendoerfer #define invspace (*(volatile unsigned int *)PCIMT_INVSPACE)
25c066a32aSThomas Bogendoerfer
sni_pcimt_sc_init(void)26c066a32aSThomas Bogendoerfer static void __init sni_pcimt_sc_init(void)
27c066a32aSThomas Bogendoerfer {
28c066a32aSThomas Bogendoerfer unsigned int scsiz, sc_size;
29c066a32aSThomas Bogendoerfer
30c066a32aSThomas Bogendoerfer scsiz = cacheconf & 7;
31c066a32aSThomas Bogendoerfer if (scsiz == 0) {
326997991aSMasanari Iida printk("Second level cache is deactivated.\n");
33c066a32aSThomas Bogendoerfer return;
34c066a32aSThomas Bogendoerfer }
35c066a32aSThomas Bogendoerfer if (scsiz >= 6) {
36c066a32aSThomas Bogendoerfer printk("Invalid second level cache size configured, "
37c066a32aSThomas Bogendoerfer "deactivating second level cache.\n");
38c066a32aSThomas Bogendoerfer cacheconf = 0;
39c066a32aSThomas Bogendoerfer return;
40c066a32aSThomas Bogendoerfer }
41c066a32aSThomas Bogendoerfer
42c066a32aSThomas Bogendoerfer sc_size = 128 << scsiz;
43c066a32aSThomas Bogendoerfer printk("%dkb second level cache detected, deactivating.\n", sc_size);
44c066a32aSThomas Bogendoerfer cacheconf = 0;
45c066a32aSThomas Bogendoerfer }
46c066a32aSThomas Bogendoerfer
47c066a32aSThomas Bogendoerfer
48c066a32aSThomas Bogendoerfer /*
49c066a32aSThomas Bogendoerfer * A bit more gossip about the iron we're running on ...
50c066a32aSThomas Bogendoerfer */
sni_pcimt_detect(void)51c066a32aSThomas Bogendoerfer static inline void sni_pcimt_detect(void)
52c066a32aSThomas Bogendoerfer {
53c066a32aSThomas Bogendoerfer char boardtype[80];
54c066a32aSThomas Bogendoerfer unsigned char csmsr;
55c066a32aSThomas Bogendoerfer char *p = boardtype;
56c066a32aSThomas Bogendoerfer unsigned int asic;
57c066a32aSThomas Bogendoerfer
58c066a32aSThomas Bogendoerfer csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
59c066a32aSThomas Bogendoerfer
60c066a32aSThomas Bogendoerfer p += sprintf(p, "%s PCI", (csmsr & 0x80) ? "RM200" : "RM300");
61c066a32aSThomas Bogendoerfer if ((csmsr & 0x80) == 0)
62c066a32aSThomas Bogendoerfer p += sprintf(p, ", board revision %s",
63c066a32aSThomas Bogendoerfer (csmsr & 0x20) ? "D" : "C");
64c066a32aSThomas Bogendoerfer asic = csmsr & 0x80;
65c066a32aSThomas Bogendoerfer asic = (csmsr & 0x08) ? asic : !asic;
66c066a32aSThomas Bogendoerfer p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1");
67c066a32aSThomas Bogendoerfer printk("%s.\n", boardtype);
68c066a32aSThomas Bogendoerfer }
69c066a32aSThomas Bogendoerfer
70c066a32aSThomas Bogendoerfer #define PORT(_base,_irq) \
71c066a32aSThomas Bogendoerfer { \
72c066a32aSThomas Bogendoerfer .iobase = _base, \
73c066a32aSThomas Bogendoerfer .irq = _irq, \
74c066a32aSThomas Bogendoerfer .uartclk = 1843200, \
75c066a32aSThomas Bogendoerfer .iotype = UPIO_PORT, \
76c066a32aSThomas Bogendoerfer .flags = UPF_BOOT_AUTOCONF, \
77c066a32aSThomas Bogendoerfer }
78c066a32aSThomas Bogendoerfer
79c066a32aSThomas Bogendoerfer static struct plat_serial8250_port pcimt_data[] = {
80c066a32aSThomas Bogendoerfer PORT(0x3f8, 4),
81c066a32aSThomas Bogendoerfer PORT(0x2f8, 3),
82c066a32aSThomas Bogendoerfer { },
83c066a32aSThomas Bogendoerfer };
84c066a32aSThomas Bogendoerfer
85c066a32aSThomas Bogendoerfer static struct platform_device pcimt_serial8250_device = {
86c066a32aSThomas Bogendoerfer .name = "serial8250",
87c066a32aSThomas Bogendoerfer .id = PLAT8250_DEV_PLATFORM,
88c066a32aSThomas Bogendoerfer .dev = {
89c066a32aSThomas Bogendoerfer .platform_data = pcimt_data,
90c066a32aSThomas Bogendoerfer },
91c066a32aSThomas Bogendoerfer };
92c066a32aSThomas Bogendoerfer
9306cf5583SThomas Bogendoerfer static struct resource pcimt_cmos_rsrc[] = {
9406cf5583SThomas Bogendoerfer {
9506cf5583SThomas Bogendoerfer .start = 0x70,
9606cf5583SThomas Bogendoerfer .end = 0x71,
9706cf5583SThomas Bogendoerfer .flags = IORESOURCE_IO
9806cf5583SThomas Bogendoerfer },
9906cf5583SThomas Bogendoerfer {
10006cf5583SThomas Bogendoerfer .start = 8,
10106cf5583SThomas Bogendoerfer .end = 8,
10206cf5583SThomas Bogendoerfer .flags = IORESOURCE_IRQ
10306cf5583SThomas Bogendoerfer }
10406cf5583SThomas Bogendoerfer };
10506cf5583SThomas Bogendoerfer
10606cf5583SThomas Bogendoerfer static struct platform_device pcimt_cmos_device = {
10706cf5583SThomas Bogendoerfer .name = "rtc_cmos",
10806cf5583SThomas Bogendoerfer .num_resources = ARRAY_SIZE(pcimt_cmos_rsrc),
10906cf5583SThomas Bogendoerfer .resource = pcimt_cmos_rsrc
11006cf5583SThomas Bogendoerfer };
11106cf5583SThomas Bogendoerfer
11206cf5583SThomas Bogendoerfer
113c066a32aSThomas Bogendoerfer static struct resource sni_io_resource = {
114bea77175SThomas Bogendoerfer .start = 0x00000000UL,
115c066a32aSThomas Bogendoerfer .end = 0x03bfffffUL,
116c066a32aSThomas Bogendoerfer .name = "PCIMT IO MEM",
117c066a32aSThomas Bogendoerfer .flags = IORESOURCE_IO,
118c066a32aSThomas Bogendoerfer };
119c066a32aSThomas Bogendoerfer
120c066a32aSThomas Bogendoerfer static struct resource pcimt_io_resources[] = {
121c066a32aSThomas Bogendoerfer {
122c066a32aSThomas Bogendoerfer .start = 0x00,
123c066a32aSThomas Bogendoerfer .end = 0x1f,
124c066a32aSThomas Bogendoerfer .name = "dma1",
125c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY
126c066a32aSThomas Bogendoerfer }, {
127c066a32aSThomas Bogendoerfer .start = 0x40,
128c066a32aSThomas Bogendoerfer .end = 0x5f,
129c066a32aSThomas Bogendoerfer .name = "timer",
130c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY
131c066a32aSThomas Bogendoerfer }, {
132c066a32aSThomas Bogendoerfer .start = 0x60,
133c066a32aSThomas Bogendoerfer .end = 0x6f,
134c066a32aSThomas Bogendoerfer .name = "keyboard",
135c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY
136c066a32aSThomas Bogendoerfer }, {
137c066a32aSThomas Bogendoerfer .start = 0x80,
138c066a32aSThomas Bogendoerfer .end = 0x8f,
139c066a32aSThomas Bogendoerfer .name = "dma page reg",
140c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY
141c066a32aSThomas Bogendoerfer }, {
142c066a32aSThomas Bogendoerfer .start = 0xc0,
143c066a32aSThomas Bogendoerfer .end = 0xdf,
144c066a32aSThomas Bogendoerfer .name = "dma2",
145c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY
146c066a32aSThomas Bogendoerfer }, {
147c066a32aSThomas Bogendoerfer .start = 0xcfc,
148c066a32aSThomas Bogendoerfer .end = 0xcff,
149c066a32aSThomas Bogendoerfer .name = "PCI config data",
150c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY
151c066a32aSThomas Bogendoerfer }
152c066a32aSThomas Bogendoerfer };
153c066a32aSThomas Bogendoerfer
1540c2bf745SThomas Bogendoerfer static struct resource pcimt_mem_resources[] = {
1550c2bf745SThomas Bogendoerfer {
1560c2bf745SThomas Bogendoerfer /*
1570c2bf745SThomas Bogendoerfer * this region should only be 4 bytes long,
1580c2bf745SThomas Bogendoerfer * but it's 16MB on all RM300C I've checked
1590c2bf745SThomas Bogendoerfer */
1600c2bf745SThomas Bogendoerfer .start = 0x1a000000,
1610c2bf745SThomas Bogendoerfer .end = 0x1affffff,
1620c2bf745SThomas Bogendoerfer .name = "PCI INT ACK",
1630c2bf745SThomas Bogendoerfer .flags = IORESOURCE_BUSY
1640c2bf745SThomas Bogendoerfer }
1650c2bf745SThomas Bogendoerfer };
1660c2bf745SThomas Bogendoerfer
167c066a32aSThomas Bogendoerfer static struct resource sni_mem_resource = {
168bea77175SThomas Bogendoerfer .start = 0x18000000UL,
169bea77175SThomas Bogendoerfer .end = 0x1fbfffffUL,
170c066a32aSThomas Bogendoerfer .name = "PCIMT PCI MEM",
171c066a32aSThomas Bogendoerfer .flags = IORESOURCE_MEM
172c066a32aSThomas Bogendoerfer };
173c066a32aSThomas Bogendoerfer
sni_pcimt_resource_init(void)174c066a32aSThomas Bogendoerfer static void __init sni_pcimt_resource_init(void)
175c066a32aSThomas Bogendoerfer {
176c066a32aSThomas Bogendoerfer int i;
177c066a32aSThomas Bogendoerfer
178c066a32aSThomas Bogendoerfer /* request I/O space for devices used on all i[345]86 PCs */
179c066a32aSThomas Bogendoerfer for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++)
180bea77175SThomas Bogendoerfer request_resource(&sni_io_resource, pcimt_io_resources + i);
1810c2bf745SThomas Bogendoerfer /* request MEM space for devices used on all i[345]86 PCs */
1820c2bf745SThomas Bogendoerfer for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++)
1830c2bf745SThomas Bogendoerfer request_resource(&sni_mem_resource, pcimt_mem_resources + i);
184c066a32aSThomas Bogendoerfer }
185c066a32aSThomas Bogendoerfer
186c066a32aSThomas Bogendoerfer extern struct pci_ops sni_pcimt_ops;
187c066a32aSThomas Bogendoerfer
188*5bd80765SMarkos Chandras #ifdef CONFIG_PCI
189c066a32aSThomas Bogendoerfer static struct pci_controller sni_controller = {
190c066a32aSThomas Bogendoerfer .pci_ops = &sni_pcimt_ops,
191c066a32aSThomas Bogendoerfer .mem_resource = &sni_mem_resource,
192bea77175SThomas Bogendoerfer .mem_offset = 0x00000000UL,
193c066a32aSThomas Bogendoerfer .io_resource = &sni_io_resource,
194bea77175SThomas Bogendoerfer .io_offset = 0x00000000UL,
195bea77175SThomas Bogendoerfer .io_map_base = SNI_PORT_BASE
196c066a32aSThomas Bogendoerfer };
197*5bd80765SMarkos Chandras #endif
198c066a32aSThomas Bogendoerfer
enable_pcimt_irq(struct irq_data * d)1990b888c7fSThomas Gleixner static void enable_pcimt_irq(struct irq_data *d)
200c066a32aSThomas Bogendoerfer {
2010b888c7fSThomas Gleixner unsigned int mask = 1 << (d->irq - PCIMT_IRQ_INT2);
202c066a32aSThomas Bogendoerfer
203c066a32aSThomas Bogendoerfer *(volatile u8 *) PCIMT_IRQSEL |= mask;
204c066a32aSThomas Bogendoerfer }
205c066a32aSThomas Bogendoerfer
disable_pcimt_irq(struct irq_data * d)2060b888c7fSThomas Gleixner void disable_pcimt_irq(struct irq_data *d)
207c066a32aSThomas Bogendoerfer {
2080b888c7fSThomas Gleixner unsigned int mask = ~(1 << (d->irq - PCIMT_IRQ_INT2));
209c066a32aSThomas Bogendoerfer
210c066a32aSThomas Bogendoerfer *(volatile u8 *) PCIMT_IRQSEL &= mask;
211c066a32aSThomas Bogendoerfer }
212c066a32aSThomas Bogendoerfer
213c066a32aSThomas Bogendoerfer static struct irq_chip pcimt_irq_type = {
2148922f79eSThomas Gleixner .name = "PCIMT",
2150b888c7fSThomas Gleixner .irq_mask = disable_pcimt_irq,
2160b888c7fSThomas Gleixner .irq_unmask = enable_pcimt_irq,
217c066a32aSThomas Bogendoerfer };
218c066a32aSThomas Bogendoerfer
219c066a32aSThomas Bogendoerfer /*
220c066a32aSThomas Bogendoerfer * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
221c066a32aSThomas Bogendoerfer * button interrupts. Later ...
222c066a32aSThomas Bogendoerfer */
pcimt_hwint0(void)223c066a32aSThomas Bogendoerfer static void pcimt_hwint0(void)
224c066a32aSThomas Bogendoerfer {
225c066a32aSThomas Bogendoerfer panic("Received int0 but no handler yet ...");
226c066a32aSThomas Bogendoerfer }
227c066a32aSThomas Bogendoerfer
228c066a32aSThomas Bogendoerfer /*
229c066a32aSThomas Bogendoerfer * hwint 1 deals with EISA and SCSI interrupts,
230c066a32aSThomas Bogendoerfer *
231c066a32aSThomas Bogendoerfer * The EISA_INT bit in CSITPEND is high active, all others are low active.
232c066a32aSThomas Bogendoerfer */
pcimt_hwint1(void)233c066a32aSThomas Bogendoerfer static void pcimt_hwint1(void)
234c066a32aSThomas Bogendoerfer {
235c066a32aSThomas Bogendoerfer u8 pend = *(volatile char *)PCIMT_CSITPEND;
236c066a32aSThomas Bogendoerfer unsigned long flags;
237c066a32aSThomas Bogendoerfer
238c066a32aSThomas Bogendoerfer if (pend & IT_EISA) {
239c066a32aSThomas Bogendoerfer int irq;
240c066a32aSThomas Bogendoerfer /*
241eae5fdc3SMaciej W. Rozycki * Note: ASIC PCI's builtin interrupt acknowledge feature is
242c066a32aSThomas Bogendoerfer * broken. Using it may result in loss of some or all i8259
2433a4fa0a2SRobert P. J. Day * interrupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
244c066a32aSThomas Bogendoerfer */
245c066a32aSThomas Bogendoerfer irq = i8259_irq();
246c066a32aSThomas Bogendoerfer if (unlikely(irq < 0))
247c066a32aSThomas Bogendoerfer return;
248c066a32aSThomas Bogendoerfer
249c066a32aSThomas Bogendoerfer do_IRQ(irq);
250c066a32aSThomas Bogendoerfer }
251c066a32aSThomas Bogendoerfer
252c066a32aSThomas Bogendoerfer if (!(pend & IT_SCSI)) {
253c066a32aSThomas Bogendoerfer flags = read_c0_status();
254c066a32aSThomas Bogendoerfer clear_c0_status(ST0_IM);
255c066a32aSThomas Bogendoerfer do_IRQ(PCIMT_IRQ_SCSI);
256c066a32aSThomas Bogendoerfer write_c0_status(flags);
257c066a32aSThomas Bogendoerfer }
258c066a32aSThomas Bogendoerfer }
259c066a32aSThomas Bogendoerfer
260c066a32aSThomas Bogendoerfer /*
261c066a32aSThomas Bogendoerfer * hwint 3 should deal with the PCI A - D interrupts,
262c066a32aSThomas Bogendoerfer */
pcimt_hwint3(void)263c066a32aSThomas Bogendoerfer static void pcimt_hwint3(void)
264c066a32aSThomas Bogendoerfer {
265c066a32aSThomas Bogendoerfer u8 pend = *(volatile char *)PCIMT_CSITPEND;
266c066a32aSThomas Bogendoerfer int irq;
267c066a32aSThomas Bogendoerfer
268c066a32aSThomas Bogendoerfer pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
269c066a32aSThomas Bogendoerfer pend ^= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
270c066a32aSThomas Bogendoerfer clear_c0_status(IE_IRQ3);
271c066a32aSThomas Bogendoerfer irq = PCIMT_IRQ_INT2 + ffs(pend) - 1;
272c066a32aSThomas Bogendoerfer do_IRQ(irq);
273c066a32aSThomas Bogendoerfer set_c0_status(IE_IRQ3);
274c066a32aSThomas Bogendoerfer }
275c066a32aSThomas Bogendoerfer
sni_pcimt_hwint(void)276c066a32aSThomas Bogendoerfer static void sni_pcimt_hwint(void)
277c066a32aSThomas Bogendoerfer {
278119537c0SThiemo Seufer u32 pending = read_c0_cause() & read_c0_status();
279c066a32aSThomas Bogendoerfer
280c066a32aSThomas Bogendoerfer if (pending & C_IRQ5)
281f13cc01dSThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 7);
282c066a32aSThomas Bogendoerfer else if (pending & C_IRQ4)
283f13cc01dSThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 6);
284c066a32aSThomas Bogendoerfer else if (pending & C_IRQ3)
285c066a32aSThomas Bogendoerfer pcimt_hwint3();
286c066a32aSThomas Bogendoerfer else if (pending & C_IRQ1)
287c066a32aSThomas Bogendoerfer pcimt_hwint1();
288c066a32aSThomas Bogendoerfer else if (pending & C_IRQ0) {
289c066a32aSThomas Bogendoerfer pcimt_hwint0();
290c066a32aSThomas Bogendoerfer }
291c066a32aSThomas Bogendoerfer }
292c066a32aSThomas Bogendoerfer
sni_pcimt_irq_init(void)293c066a32aSThomas Bogendoerfer void __init sni_pcimt_irq_init(void)
294c066a32aSThomas Bogendoerfer {
295c066a32aSThomas Bogendoerfer int i;
296c066a32aSThomas Bogendoerfer
297c066a32aSThomas Bogendoerfer *(volatile u8 *) PCIMT_IRQSEL = IT_ETH | IT_EISA;
298c066a32aSThomas Bogendoerfer mips_cpu_irq_init();
299c066a32aSThomas Bogendoerfer /* Actually we've got more interrupts to handle ... */
300c066a32aSThomas Bogendoerfer for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_SCSI; i++)
301e4ec7989SThomas Gleixner irq_set_chip_and_handler(i, &pcimt_irq_type, handle_level_irq);
302c066a32aSThomas Bogendoerfer sni_hwint = sni_pcimt_hwint;
303c066a32aSThomas Bogendoerfer change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ3);
304c066a32aSThomas Bogendoerfer }
305c066a32aSThomas Bogendoerfer
sni_pcimt_init(void)30606cf5583SThomas Bogendoerfer void __init sni_pcimt_init(void)
307c066a32aSThomas Bogendoerfer {
308c066a32aSThomas Bogendoerfer sni_pcimt_detect();
309c066a32aSThomas Bogendoerfer sni_pcimt_sc_init();
310bea77175SThomas Bogendoerfer ioport_resource.end = sni_io_resource.end;
311c066a32aSThomas Bogendoerfer #ifdef CONFIG_PCI
312bea77175SThomas Bogendoerfer PCIBIOS_MIN_IO = 0x9000;
313c066a32aSThomas Bogendoerfer register_pci_controller(&sni_controller);
314c066a32aSThomas Bogendoerfer #endif
315bea77175SThomas Bogendoerfer sni_pcimt_resource_init();
316c066a32aSThomas Bogendoerfer }
317c066a32aSThomas Bogendoerfer
snirm_pcimt_setup_devinit(void)318c066a32aSThomas Bogendoerfer static int __init snirm_pcimt_setup_devinit(void)
319c066a32aSThomas Bogendoerfer {
320c066a32aSThomas Bogendoerfer switch (sni_brd_type) {
321c066a32aSThomas Bogendoerfer case SNI_BRD_PCI_MTOWER:
322c066a32aSThomas Bogendoerfer case SNI_BRD_PCI_DESKTOP:
323c066a32aSThomas Bogendoerfer case SNI_BRD_PCI_MTOWER_CPLUS:
324c066a32aSThomas Bogendoerfer platform_device_register(&pcimt_serial8250_device);
32506cf5583SThomas Bogendoerfer platform_device_register(&pcimt_cmos_device);
326c066a32aSThomas Bogendoerfer break;
327c066a32aSThomas Bogendoerfer }
328c066a32aSThomas Bogendoerfer
329c066a32aSThomas Bogendoerfer return 0;
330c066a32aSThomas Bogendoerfer }
331c066a32aSThomas Bogendoerfer
332c066a32aSThomas Bogendoerfer device_initcall(snirm_pcimt_setup_devinit);
333