Merge branch 'task_killable' of git://git.kernel.org/pub/scm/linux/kernel/git/willy...
[linux-2.6] / arch / mips / sni / a20r.c
1 /*
2  * A20R 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
19 #define PORT(_base,_irq)                                \
20         {                                               \
21                 .iobase         = _base,                \
22                 .irq            = _irq,                 \
23                 .uartclk        = 1843200,              \
24                 .iotype         = UPIO_PORT,            \
25                 .flags          = UPF_BOOT_AUTOCONF,    \
26         }
27
28 static struct plat_serial8250_port a20r_data[] = {
29         PORT(0x3f8, 4),
30         PORT(0x2f8, 3),
31         { },
32 };
33
34 static struct platform_device a20r_serial8250_device = {
35         .name                   = "serial8250",
36         .id                     = PLAT8250_DEV_PLATFORM,
37         .dev                    = {
38                 .platform_data  = a20r_data,
39         },
40 };
41
42 static struct resource a20r_ds1216_rsrc[] = {
43         {
44                 .start = 0x1c081ffc,
45                 .end   = 0x1c081fff,
46                 .flags = IORESOURCE_MEM
47         }
48 };
49
50 static struct platform_device a20r_ds1216_device = {
51         .name           = "rtc-ds1216",
52         .num_resources  = ARRAY_SIZE(a20r_ds1216_rsrc),
53         .resource       = a20r_ds1216_rsrc
54 };
55
56 static struct resource snirm_82596_rsrc[] = {
57         {
58                 .start = 0x18000000,
59                 .end   = 0x18000004,
60                 .flags = IORESOURCE_MEM
61         },
62         {
63                 .start = 0x18010000,
64                 .end   = 0x18010004,
65                 .flags = IORESOURCE_MEM
66         },
67         {
68                 .start = 0x1ff00000,
69                 .end   = 0x1ff00020,
70                 .flags = IORESOURCE_MEM
71         },
72         {
73                 .start = 22,
74                 .end   = 22,
75                 .flags = IORESOURCE_IRQ
76         },
77         {
78                 .flags = 0x01                /* 16bit mpu port access */
79         }
80 };
81
82 static struct platform_device snirm_82596_pdev = {
83         .name           = "snirm_82596",
84         .num_resources  = ARRAY_SIZE(snirm_82596_rsrc),
85         .resource       = snirm_82596_rsrc
86 };
87
88 static struct resource snirm_53c710_rsrc[] = {
89         {
90                 .start = 0x19000000,
91                 .end   = 0x190fffff,
92                 .flags = IORESOURCE_MEM
93         },
94         {
95                 .start = 19,
96                 .end   = 19,
97                 .flags = IORESOURCE_IRQ
98         }
99 };
100
101 static struct platform_device snirm_53c710_pdev = {
102         .name           = "snirm_53c710",
103         .num_resources  = ARRAY_SIZE(snirm_53c710_rsrc),
104         .resource       = snirm_53c710_rsrc
105 };
106
107 static struct resource sc26xx_rsrc[] = {
108         {
109                 .start = 0x1c070000,
110                 .end   = 0x1c0700ff,
111                 .flags = IORESOURCE_MEM
112         },
113         {
114                 .start = 20,
115                 .end   = 20,
116                 .flags = IORESOURCE_IRQ
117         }
118 };
119
120 static unsigned int sc26xx_data[2] = {
121         /* DTR   |   RTS    |   DSR    |   CTS     |   DCD     |   RI    */
122         (8 << 0) | (4 << 4) | (6 << 8) | (0 << 12) | (6 << 16) | (0 << 20),
123         (3 << 0) | (2 << 4) | (1 << 8) | (2 << 12) | (3 << 16) | (4 << 20)
124 };
125
126 static struct platform_device sc26xx_pdev = {
127         .name           = "SC26xx",
128         .num_resources  = ARRAY_SIZE(sc26xx_rsrc),
129         .resource       = sc26xx_rsrc,
130         .dev                    = {
131                 .platform_data  = sc26xx_data,
132         }
133 };
134
135 static u32 a20r_ack_hwint(void)
136 {
137         u32 status = read_c0_status();
138
139         write_c0_status(status | 0x00010000);
140         asm volatile(
141         "       .set    push                    \n"
142         "       .set    noat                    \n"
143         "       .set    noreorder               \n"
144         "       lw      $1, 0(%0)               \n"
145         "       sb      $0, 0(%1)               \n"
146         "       sync                            \n"
147         "       lb      %1, 0(%1)               \n"
148         "       b       1f                      \n"
149         "       ori     %1, $1, 2               \n"
150         "       .align  8                       \n"
151         "1:                                     \n"
152         "       nop                             \n"
153         "       sw      %1, 0(%0)               \n"
154         "       sync                            \n"
155         "       li      %1, 0x20                \n"
156         "2:                                     \n"
157         "       nop                             \n"
158         "       bnez    %1,2b                   \n"
159         "       addiu   %1, -1                  \n"
160         "       sw      $1, 0(%0)               \n"
161         "       sync                            \n"
162                 ".set   pop                     \n"
163         :
164         : "Jr" (PCIMT_UCONF), "Jr" (0xbc000000));
165         write_c0_status(status);
166
167         return status;
168 }
169
170 static inline void unmask_a20r_irq(unsigned int irq)
171 {
172         set_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
173         irq_enable_hazard();
174 }
175
176 static inline void mask_a20r_irq(unsigned int irq)
177 {
178         clear_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
179         irq_disable_hazard();
180 }
181
182 static void end_a20r_irq(unsigned int irq)
183 {
184         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
185                 a20r_ack_hwint();
186                 unmask_a20r_irq(irq);
187         }
188 }
189
190 static struct irq_chip a20r_irq_type = {
191         .typename       = "A20R",
192         .ack            = mask_a20r_irq,
193         .mask           = mask_a20r_irq,
194         .mask_ack       = mask_a20r_irq,
195         .unmask         = unmask_a20r_irq,
196         .end            = end_a20r_irq,
197 };
198
199 /*
200  * hwint 0 receive all interrupts
201  */
202 static void a20r_hwint(void)
203 {
204         u32 cause, status;
205         int irq;
206
207         clear_c0_status(IE_IRQ0);
208         status = a20r_ack_hwint();
209         cause = read_c0_cause();
210
211         irq = ffs(((cause & status) >> 8) & 0xf8);
212         if (likely(irq > 0))
213                 do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
214         set_c0_status(IE_IRQ0);
215 }
216
217 void __init sni_a20r_irq_init(void)
218 {
219         int i;
220
221         for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++)
222                 set_irq_chip(i, &a20r_irq_type);
223         sni_hwint = a20r_hwint;
224         change_c0_status(ST0_IM, IE_IRQ0);
225         setup_irq(SNI_A20R_IRQ_BASE + 3, &sni_isa_irq);
226 }
227
228 void sni_a20r_init(void)
229 {
230         /* FIXME, remove if not needed */
231 }
232
233 static int __init snirm_a20r_setup_devinit(void)
234 {
235         switch (sni_brd_type) {
236         case SNI_BRD_TOWER_OASIC:
237         case SNI_BRD_MINITOWER:
238                 platform_device_register(&snirm_82596_pdev);
239                 platform_device_register(&snirm_53c710_pdev);
240                 platform_device_register(&sc26xx_pdev);
241                 platform_device_register(&a20r_serial8250_device);
242                 platform_device_register(&a20r_ds1216_device);
243                 sni_eisa_root_init();
244                 break;
245         }
246         return 0;
247 }
248
249 device_initcall(snirm_a20r_setup_devinit);