Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
[pandora-kernel.git] / arch / mips / sni / pcit.c
1 /*
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/sni.h>
17 #include <asm/time.h>
18 #include <asm/irq_cpu.h>
19
20
21 #define PORT(_base,_irq)                                \
22         {                                               \
23                 .iobase         = _base,                \
24                 .irq            = _irq,                 \
25                 .uartclk        = 1843200,              \
26                 .iotype         = UPIO_PORT,            \
27                 .flags          = UPF_BOOT_AUTOCONF,    \
28         }
29
30 static struct plat_serial8250_port pcit_data[] = {
31         PORT(0x3f8, 0),
32         PORT(0x2f8, 3),
33         { },
34 };
35
36 static struct platform_device pcit_serial8250_device = {
37         .name                   = "serial8250",
38         .id                     = PLAT8250_DEV_PLATFORM,
39         .dev                    = {
40                 .platform_data  = pcit_data,
41         },
42 };
43
44 static struct plat_serial8250_port pcit_cplus_data[] = {
45         PORT(0x3f8, 0),
46         PORT(0x2f8, 3),
47         PORT(0x3e8, 4),
48         PORT(0x2e8, 3),
49         { },
50 };
51
52 static struct platform_device pcit_cplus_serial8250_device = {
53         .name                   = "serial8250",
54         .id                     = PLAT8250_DEV_PLATFORM,
55         .dev                    = {
56                 .platform_data  = pcit_cplus_data,
57         },
58 };
59
60 static struct resource pcit_cmos_rsrc[] = {
61         {
62                 .start = 0x70,
63                 .end   = 0x71,
64                 .flags = IORESOURCE_IO
65         },
66         {
67                 .start = 8,
68                 .end   = 8,
69                 .flags = IORESOURCE_IRQ
70         }
71 };
72
73 static struct platform_device pcit_cmos_device = {
74         .name           = "rtc_cmos",
75         .num_resources  = ARRAY_SIZE(pcit_cmos_rsrc),
76         .resource       = pcit_cmos_rsrc
77 };
78
79 static struct platform_device pcit_pcspeaker_pdev = {
80         .name           = "pcspkr",
81         .id             = -1,
82 };
83
84 static struct resource sni_io_resource = {
85         .start  = 0x00000000UL,
86         .end    = 0x03bfffffUL,
87         .name   = "PCIT IO",
88         .flags  = IORESOURCE_IO,
89 };
90
91 static struct resource pcit_io_resources[] = {
92         {
93                 .start  = 0x00,
94                 .end    = 0x1f,
95                 .name   = "dma1",
96                 .flags  = IORESOURCE_BUSY
97         }, {
98                 .start  =  0x40,
99                 .end    = 0x5f,
100                 .name   = "timer",
101                 .flags  = IORESOURCE_BUSY
102         }, {
103                 .start  =  0x60,
104                 .end    = 0x6f,
105                 .name   = "keyboard",
106                 .flags  = IORESOURCE_BUSY
107         }, {
108                 .start  =  0x80,
109                 .end    = 0x8f,
110                 .name   = "dma page reg",
111                 .flags  = IORESOURCE_BUSY
112         }, {
113                 .start  =  0xc0,
114                 .end    = 0xdf,
115                 .name   = "dma2",
116                 .flags  = IORESOURCE_BUSY
117         }, {
118                 .start  =  0xcf8,
119                 .end    = 0xcfb,
120                 .name   = "PCI config addr",
121                 .flags  = IORESOURCE_BUSY
122         }, {
123                 .start  =  0xcfc,
124                 .end    = 0xcff,
125                 .name   = "PCI config data",
126                 .flags  = IORESOURCE_BUSY
127         }
128 };
129
130 static struct resource sni_mem_resource = {
131         .start  = 0x18000000UL,
132         .end    = 0x1fbfffffUL,
133         .name   = "PCIT PCI MEM",
134         .flags  = IORESOURCE_MEM
135 };
136
137 static void __init sni_pcit_resource_init(void)
138 {
139         int i;
140
141         /* request I/O space for devices used on all i[345]86 PCs */
142         for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++)
143                 request_resource(&sni_io_resource, pcit_io_resources + i);
144 }
145
146
147 extern struct pci_ops sni_pcit_ops;
148
149 static struct pci_controller sni_pcit_controller = {
150         .pci_ops        = &sni_pcit_ops,
151         .mem_resource   = &sni_mem_resource,
152         .mem_offset     = 0x00000000UL,
153         .io_resource    = &sni_io_resource,
154         .io_offset      = 0x00000000UL,
155         .io_map_base    = SNI_PORT_BASE
156 };
157
158 static void enable_pcit_irq(unsigned int irq)
159 {
160         u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
161
162         *(volatile u32 *)SNI_PCIT_INT_REG |= mask;
163 }
164
165 void disable_pcit_irq(unsigned int irq)
166 {
167         u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
168
169         *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask;
170 }
171
172 void end_pcit_irq(unsigned int irq)
173 {
174         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
175                 enable_pcit_irq(irq);
176 }
177
178 static struct irq_chip pcit_irq_type = {
179         .name = "PCIT",
180         .ack = disable_pcit_irq,
181         .mask = disable_pcit_irq,
182         .mask_ack = disable_pcit_irq,
183         .unmask = enable_pcit_irq,
184         .end = end_pcit_irq,
185 };
186
187 static void pcit_hwint1(void)
188 {
189         u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
190         int irq;
191
192         clear_c0_status(IE_IRQ1);
193         irq = ffs((pending >> 16) & 0x7f);
194
195         if (likely(irq > 0))
196                 do_IRQ(irq + SNI_PCIT_INT_START - 1);
197         set_c0_status(IE_IRQ1);
198 }
199
200 static void pcit_hwint0(void)
201 {
202         u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
203         int irq;
204
205         clear_c0_status(IE_IRQ0);
206         irq = ffs((pending >> 16) & 0x3f);
207
208         if (likely(irq > 0))
209                 do_IRQ(irq + SNI_PCIT_INT_START - 1);
210         set_c0_status(IE_IRQ0);
211 }
212
213 static void sni_pcit_hwint(void)
214 {
215         u32 pending = read_c0_cause() & read_c0_status();
216
217         if (pending & C_IRQ1)
218                 pcit_hwint1();
219         else if (pending & C_IRQ2)
220                 do_IRQ(MIPS_CPU_IRQ_BASE + 4);
221         else if (pending & C_IRQ3)
222                 do_IRQ(MIPS_CPU_IRQ_BASE + 5);
223         else if (pending & C_IRQ5)
224                 do_IRQ(MIPS_CPU_IRQ_BASE + 7);
225 }
226
227 static void sni_pcit_hwint_cplus(void)
228 {
229         u32 pending = read_c0_cause() & read_c0_status();
230
231         if (pending & C_IRQ0)
232                 pcit_hwint0();
233         else if (pending & C_IRQ1)
234                 do_IRQ(MIPS_CPU_IRQ_BASE + 3);
235         else if (pending & C_IRQ2)
236                 do_IRQ(MIPS_CPU_IRQ_BASE + 4);
237         else if (pending & C_IRQ3)
238                 do_IRQ(MIPS_CPU_IRQ_BASE + 5);
239         else if (pending & C_IRQ5)
240                 do_IRQ(MIPS_CPU_IRQ_BASE + 7);
241 }
242
243 void __init sni_pcit_irq_init(void)
244 {
245         int i;
246
247         mips_cpu_irq_init();
248         for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
249                 set_irq_chip_and_handler(i, &pcit_irq_type, handle_level_irq);
250         *(volatile u32 *)SNI_PCIT_INT_REG = 0;
251         sni_hwint = sni_pcit_hwint;
252         change_c0_status(ST0_IM, IE_IRQ1);
253         setup_irq(SNI_PCIT_INT_START + 6, &sni_isa_irq);
254 }
255
256 void __init sni_pcit_cplus_irq_init(void)
257 {
258         int i;
259
260         mips_cpu_irq_init();
261         for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
262                 set_irq_chip_and_handler(i, &pcit_irq_type, handle_level_irq);
263         *(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000;
264         sni_hwint = sni_pcit_hwint_cplus;
265         change_c0_status(ST0_IM, IE_IRQ0);
266         setup_irq(MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq);
267 }
268
269 void __init sni_pcit_init(void)
270 {
271         ioport_resource.end = sni_io_resource.end;
272 #ifdef CONFIG_PCI
273         PCIBIOS_MIN_IO = 0x9000;
274         register_pci_controller(&sni_pcit_controller);
275 #endif
276         sni_pcit_resource_init();
277 }
278
279 static int __init snirm_pcit_setup_devinit(void)
280 {
281         switch (sni_brd_type) {
282         case SNI_BRD_PCI_TOWER:
283                 platform_device_register(&pcit_serial8250_device);
284                 platform_device_register(&pcit_cmos_device);
285                 platform_device_register(&pcit_pcspeaker_pdev);
286                 break;
287
288         case SNI_BRD_PCI_TOWER_CPLUS:
289                 platform_device_register(&pcit_cplus_serial8250_device);
290                 platform_device_register(&pcit_cmos_device);
291                 platform_device_register(&pcit_pcspeaker_pdev);
292                 break;
293         }
294         return 0;
295 }
296
297 device_initcall(snirm_pcit_setup_devinit);