Merge branch 'upstream-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/linvil...
[linux-2.6] / arch / mips / sni / rm200.c
1 /*
2  * RM200 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/platform_device.h>
14 #include <linux/serial_8250.h>
15
16 #include <asm/sni.h>
17 #include <asm/time.h>
18 #include <asm/ds1216.h>
19 #include <asm/irq_cpu.h>
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 rm200_data[] = {
31         PORT(0x3f8, 4),
32         PORT(0x2f8, 3),
33         { },
34 };
35
36 static struct platform_device rm200_serial8250_device = {
37         .name                   = "serial8250",
38         .id                     = PLAT8250_DEV_PLATFORM,
39         .dev                    = {
40                 .platform_data  = rm200_data,
41         },
42 };
43
44 static struct resource snirm_82596_rm200_rsrc[] = {
45         {
46                 .start = 0xb8000000,
47                 .end   = 0xb80fffff,
48                 .flags = IORESOURCE_MEM
49         },
50         {
51                 .start = 0xbb000000,
52                 .end   = 0xbb000004,
53                 .flags = IORESOURCE_MEM
54         },
55         {
56                 .start = 0xbff00000,
57                 .end   = 0xbff00020,
58                 .flags = IORESOURCE_MEM
59         },
60         {
61                 .start = 27,
62                 .end   = 27,
63                 .flags = IORESOURCE_IRQ
64         },
65         {
66                 .flags = 0x00
67         }
68 };
69
70 static struct platform_device snirm_82596_rm200_pdev = {
71         .name           = "snirm_82596",
72         .num_resources  = ARRAY_SIZE(snirm_82596_rm200_rsrc),
73         .resource       = snirm_82596_rm200_rsrc
74 };
75
76 static struct resource snirm_53c710_rm200_rsrc[] = {
77         {
78                 .start = 0xb9000000,
79                 .end   = 0xb90fffff,
80                 .flags = IORESOURCE_MEM
81         },
82         {
83                 .start = 26,
84                 .end   = 26,
85                 .flags = IORESOURCE_IRQ
86         }
87 };
88
89 static struct platform_device snirm_53c710_rm200_pdev = {
90         .name           = "snirm_53c710",
91         .num_resources  = ARRAY_SIZE(snirm_53c710_rm200_rsrc),
92         .resource       = snirm_53c710_rm200_rsrc
93 };
94
95 static int __init snirm_setup_devinit(void)
96 {
97         if (sni_brd_type == SNI_BRD_RM200) {
98                 platform_device_register(&rm200_serial8250_device);
99                 platform_device_register(&snirm_82596_rm200_pdev);
100                 platform_device_register(&snirm_53c710_rm200_pdev);
101         }
102         return 0;
103 }
104
105 device_initcall(snirm_setup_devinit);
106
107
108 #define SNI_RM200_INT_STAT_REG  0xbc000000
109 #define SNI_RM200_INT_ENA_REG   0xbc080000
110
111 #define SNI_RM200_INT_START  24
112 #define SNI_RM200_INT_END    28
113
114 static void enable_rm200_irq(unsigned int irq)
115 {
116         unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
117
118         *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask;
119 }
120
121 void disable_rm200_irq(unsigned int irq)
122 {
123         unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
124
125         *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask;
126 }
127
128 void end_rm200_irq(unsigned int irq)
129 {
130         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
131                 enable_rm200_irq(irq);
132 }
133
134 static struct irq_chip rm200_irq_type = {
135         .typename = "RM200",
136         .ack = disable_rm200_irq,
137         .mask = disable_rm200_irq,
138         .mask_ack = disable_rm200_irq,
139         .unmask = enable_rm200_irq,
140         .end = end_rm200_irq,
141 };
142
143 static void sni_rm200_hwint(void)
144 {
145         u32 pending = read_c0_cause() & read_c0_status();
146         u8 mask;
147         u8 stat;
148         int irq;
149
150         if (pending & C_IRQ5)
151                 do_IRQ (MIPS_CPU_IRQ_BASE + 7);
152         else if (pending & C_IRQ0) {
153                 clear_c0_status (IE_IRQ0);
154                 mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f;
155                 stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14;
156                 irq = ffs(stat & mask & 0x1f);
157
158                 if (likely(irq > 0))
159                         do_IRQ (irq + SNI_RM200_INT_START - 1);
160                 set_c0_status (IE_IRQ0);
161         }
162 }
163
164 void __init sni_rm200_irq_init(void)
165 {
166         int i;
167
168         * (volatile u8 *)SNI_RM200_INT_ENA_REG = 0x1f;
169
170         mips_cpu_irq_init();
171         /* Actually we've got more interrupts to handle ...  */
172         for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++)
173                 set_irq_chip(i, &rm200_irq_type);
174         sni_hwint = sni_rm200_hwint;
175         change_c0_status(ST0_IM, IE_IRQ0);
176         setup_irq (SNI_RM200_INT_START + 0, &sni_isa_irq);
177 }
178
179 void sni_rm200_init(void)
180 {
181         set_io_port_base(SNI_PORT_BASE + 0x02000000);
182         ioport_resource.end += 0x02000000;
183         ds1216_base = (volatile unsigned char *) SNI_DS1216_RM200_BASE;
184         rtc_mips_get_time = ds1216_get_cmos_time;
185         board_time_init = sni_cpu_time_init;
186 }