blob: 00d151f4d121875a4ef6b2dbd40ab1c57e4c8f61 [file] [log] [blame]
Thomas Bogendoerferc066a322006-12-28 18:22:32 +01001/*
2 * PCI Tower specific code
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
9 */
10
11#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/pci.h>
14#include <linux/serial_8250.h>
15
16#include <asm/mc146818-time.h>
17#include <asm/sni.h>
18#include <asm/time.h>
19#include <asm/irq_cpu.h>
20
21
22#define PORT(_base,_irq) \
23 { \
24 .iobase = _base, \
25 .irq = _irq, \
26 .uartclk = 1843200, \
27 .iotype = UPIO_PORT, \
28 .flags = UPF_BOOT_AUTOCONF, \
29 }
30
31static struct plat_serial8250_port pcit_data[] = {
32 PORT(0x3f8, 0),
33 PORT(0x2f8, 3),
34 { },
35};
36
37static struct platform_device pcit_serial8250_device = {
38 .name = "serial8250",
39 .id = PLAT8250_DEV_PLATFORM,
40 .dev = {
41 .platform_data = pcit_data,
42 },
43};
44
45static struct plat_serial8250_port pcit_cplus_data[] = {
Thomas Bogendoerferbea77172007-04-08 13:34:57 +020046 PORT(0x3f8, 0),
Thomas Bogendoerferc066a322006-12-28 18:22:32 +010047 PORT(0x2f8, 3),
48 PORT(0x3e8, 4),
49 PORT(0x2e8, 3),
50 { },
51};
52
53static struct platform_device pcit_cplus_serial8250_device = {
54 .name = "serial8250",
55 .id = PLAT8250_DEV_PLATFORM,
56 .dev = {
57 .platform_data = pcit_cplus_data,
58 },
59};
60
61static struct resource sni_io_resource = {
Thomas Bogendoerferbea77172007-04-08 13:34:57 +020062 .start = 0x00000000UL,
Thomas Bogendoerferc066a322006-12-28 18:22:32 +010063 .end = 0x03bfffffUL,
Thomas Bogendoerferbea77172007-04-08 13:34:57 +020064 .name = "PCIT IO",
Thomas Bogendoerferc066a322006-12-28 18:22:32 +010065 .flags = IORESOURCE_IO,
66};
67
68static struct resource pcit_io_resources[] = {
69 {
70 .start = 0x00,
71 .end = 0x1f,
72 .name = "dma1",
73 .flags = IORESOURCE_BUSY
74 }, {
75 .start = 0x40,
76 .end = 0x5f,
77 .name = "timer",
78 .flags = IORESOURCE_BUSY
79 }, {
80 .start = 0x60,
81 .end = 0x6f,
82 .name = "keyboard",
83 .flags = IORESOURCE_BUSY
84 }, {
85 .start = 0x80,
86 .end = 0x8f,
87 .name = "dma page reg",
88 .flags = IORESOURCE_BUSY
89 }, {
90 .start = 0xc0,
91 .end = 0xdf,
92 .name = "dma2",
93 .flags = IORESOURCE_BUSY
94 }, {
Thomas Bogendoerferbea77172007-04-08 13:34:57 +020095 .start = 0xcf8,
96 .end = 0xcfb,
97 .name = "PCI config addr",
98 .flags = IORESOURCE_BUSY
99 }, {
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100100 .start = 0xcfc,
101 .end = 0xcff,
102 .name = "PCI config data",
103 .flags = IORESOURCE_BUSY
104 }
105};
106
107static struct resource sni_mem_resource = {
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200108 .start = 0x18000000UL,
109 .end = 0x1fbfffffUL,
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100110 .name = "PCIT PCI MEM",
111 .flags = IORESOURCE_MEM
112};
113
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100114static void __init sni_pcit_resource_init(void)
115{
116 int i;
117
118 /* request I/O space for devices used on all i[345]86 PCs */
119 for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++)
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200120 request_resource(&sni_io_resource, pcit_io_resources + i);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100121}
122
123
124extern struct pci_ops sni_pcit_ops;
125
126static struct pci_controller sni_pcit_controller = {
127 .pci_ops = &sni_pcit_ops,
128 .mem_resource = &sni_mem_resource,
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200129 .mem_offset = 0x00000000UL,
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100130 .io_resource = &sni_io_resource,
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200131 .io_offset = 0x00000000UL,
132 .io_map_base = SNI_PORT_BASE
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100133};
134
135static void enable_pcit_irq(unsigned int irq)
136{
137 u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
138
139 *(volatile u32 *)SNI_PCIT_INT_REG |= mask;
140}
141
142void disable_pcit_irq(unsigned int irq)
143{
144 u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
145
146 *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask;
147}
148
149void end_pcit_irq(unsigned int irq)
150{
151 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
152 enable_pcit_irq(irq);
153}
154
155static struct irq_chip pcit_irq_type = {
156 .typename = "PCIT",
157 .ack = disable_pcit_irq,
158 .mask = disable_pcit_irq,
159 .mask_ack = disable_pcit_irq,
160 .unmask = enable_pcit_irq,
161 .end = end_pcit_irq,
162};
163
164static void pcit_hwint1(void)
165{
166 u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
167 int irq;
168
169 clear_c0_status(IE_IRQ1);
170 irq = ffs((pending >> 16) & 0x7f);
171
172 if (likely(irq > 0))
173 do_IRQ (irq + SNI_PCIT_INT_START - 1);
174 set_c0_status (IE_IRQ1);
175}
176
177static void pcit_hwint0(void)
178{
179 u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
180 int irq;
181
182 clear_c0_status(IE_IRQ0);
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200183 irq = ffs((pending >> 16) & 0x3f);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100184
185 if (likely(irq > 0))
186 do_IRQ (irq + SNI_PCIT_INT_START - 1);
187 set_c0_status (IE_IRQ0);
188}
189
190static void sni_pcit_hwint(void)
191{
Thiemo Seufer119537c2007-03-19 00:13:37 +0000192 u32 pending = read_c0_cause() & read_c0_status();
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100193
194 if (pending & C_IRQ1)
195 pcit_hwint1();
196 else if (pending & C_IRQ2)
Thomas Bogendoerferf13cc012007-02-23 21:39:38 +0100197 do_IRQ (MIPS_CPU_IRQ_BASE + 4);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100198 else if (pending & C_IRQ3)
Thomas Bogendoerferf13cc012007-02-23 21:39:38 +0100199 do_IRQ (MIPS_CPU_IRQ_BASE + 5);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100200 else if (pending & C_IRQ5)
Thomas Bogendoerferf13cc012007-02-23 21:39:38 +0100201 do_IRQ (MIPS_CPU_IRQ_BASE + 7);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100202}
203
204static void sni_pcit_hwint_cplus(void)
205{
Thiemo Seufer119537c2007-03-19 00:13:37 +0000206 u32 pending = read_c0_cause() & read_c0_status();
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100207
208 if (pending & C_IRQ0)
209 pcit_hwint0();
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200210 else if (pending & C_IRQ1)
211 do_IRQ (MIPS_CPU_IRQ_BASE + 3);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100212 else if (pending & C_IRQ2)
Thomas Bogendoerferf13cc012007-02-23 21:39:38 +0100213 do_IRQ (MIPS_CPU_IRQ_BASE + 4);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100214 else if (pending & C_IRQ3)
Thomas Bogendoerferf13cc012007-02-23 21:39:38 +0100215 do_IRQ (MIPS_CPU_IRQ_BASE + 5);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100216 else if (pending & C_IRQ5)
Thomas Bogendoerferf13cc012007-02-23 21:39:38 +0100217 do_IRQ (MIPS_CPU_IRQ_BASE + 7);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100218}
219
220void __init sni_pcit_irq_init(void)
221{
222 int i;
223
224 mips_cpu_irq_init();
225 for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
226 set_irq_chip(i, &pcit_irq_type);
227 *(volatile u32 *)SNI_PCIT_INT_REG = 0;
228 sni_hwint = sni_pcit_hwint;
229 change_c0_status(ST0_IM, IE_IRQ1);
230 setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq);
231}
232
233void __init sni_pcit_cplus_irq_init(void)
234{
235 int i;
236
237 mips_cpu_irq_init();
238 for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
239 set_irq_chip(i, &pcit_irq_type);
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200240 *(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000;
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100241 sni_hwint = sni_pcit_hwint_cplus;
242 change_c0_status(ST0_IM, IE_IRQ0);
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200243 setup_irq (MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq);
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100244}
245
246void sni_pcit_init(void)
247{
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100248 rtc_mips_get_time = mc146818_get_cmos_time;
249 rtc_mips_set_time = mc146818_set_rtc_mmss;
250 board_time_init = sni_cpu_time_init;
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200251 ioport_resource.end = sni_io_resource.end;
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100252#ifdef CONFIG_PCI
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200253 PCIBIOS_MIN_IO = 0x9000;
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100254 register_pci_controller(&sni_pcit_controller);
255#endif
Thomas Bogendoerferbea77172007-04-08 13:34:57 +0200256 sni_pcit_resource_init();
Thomas Bogendoerferc066a322006-12-28 18:22:32 +0100257}
258
259static int __init snirm_pcit_setup_devinit(void)
260{
261 switch (sni_brd_type) {
262 case SNI_BRD_PCI_TOWER:
263 platform_device_register(&pcit_serial8250_device);
264 break;
265
266 case SNI_BRD_PCI_TOWER_CPLUS:
267 platform_device_register(&pcit_cplus_serial8250_device);
268 break;
269 }
270 return 0;
271}
272
273device_initcall(snirm_pcit_setup_devinit);