Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh64-2.6
[pandora-kernel.git] / 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/irq_cpu.h>
19
20 #define PORT(_base,_irq)                                \
21         {                                               \
22                 .iobase         = _base,                \
23                 .irq            = _irq,                 \
24                 .uartclk        = 1843200,              \
25                 .iotype         = UPIO_PORT,            \
26                 .flags          = UPF_BOOT_AUTOCONF,    \
27         }
28
29 static struct plat_serial8250_port rm200_data[] = {
30         PORT(0x3f8, 4),
31         PORT(0x2f8, 3),
32         { },
33 };
34
35 static struct platform_device rm200_serial8250_device = {
36         .name                   = "serial8250",
37         .id                     = PLAT8250_DEV_PLATFORM,
38         .dev                    = {
39                 .platform_data  = rm200_data,
40         },
41 };
42
43 static struct resource rm200_ds1216_rsrc[] = {
44         {
45                 .start = 0x1cd41ffc,
46                 .end   = 0x1cd41fff,
47                 .flags = IORESOURCE_MEM
48         }
49 };
50
51 static struct platform_device rm200_ds1216_device = {
52         .name           = "rtc-ds1216",
53         .num_resources  = ARRAY_SIZE(rm200_ds1216_rsrc),
54         .resource       = rm200_ds1216_rsrc
55 };
56
57 static struct resource snirm_82596_rm200_rsrc[] = {
58         {
59                 .start = 0x18000000,
60                 .end   = 0x180fffff,
61                 .flags = IORESOURCE_MEM
62         },
63         {
64                 .start = 0x1b000000,
65                 .end   = 0x1b000004,
66                 .flags = IORESOURCE_MEM
67         },
68         {
69                 .start = 0x1ff00000,
70                 .end   = 0x1ff00020,
71                 .flags = IORESOURCE_MEM
72         },
73         {
74                 .start = 27,
75                 .end   = 27,
76                 .flags = IORESOURCE_IRQ
77         },
78         {
79                 .flags = 0x00
80         }
81 };
82
83 static struct platform_device snirm_82596_rm200_pdev = {
84         .name           = "snirm_82596",
85         .num_resources  = ARRAY_SIZE(snirm_82596_rm200_rsrc),
86         .resource       = snirm_82596_rm200_rsrc
87 };
88
89 static struct resource snirm_53c710_rm200_rsrc[] = {
90         {
91                 .start = 0x19000000,
92                 .end   = 0x190fffff,
93                 .flags = IORESOURCE_MEM
94         },
95         {
96                 .start = 26,
97                 .end   = 26,
98                 .flags = IORESOURCE_IRQ
99         }
100 };
101
102 static struct platform_device snirm_53c710_rm200_pdev = {
103         .name           = "snirm_53c710",
104         .num_resources  = ARRAY_SIZE(snirm_53c710_rm200_rsrc),
105         .resource       = snirm_53c710_rm200_rsrc
106 };
107
108 static int __init snirm_setup_devinit(void)
109 {
110         if (sni_brd_type == SNI_BRD_RM200) {
111                 platform_device_register(&rm200_serial8250_device);
112                 platform_device_register(&rm200_ds1216_device);
113                 platform_device_register(&snirm_82596_rm200_pdev);
114                 platform_device_register(&snirm_53c710_rm200_pdev);
115         }
116         return 0;
117 }
118
119 device_initcall(snirm_setup_devinit);
120
121
122 #define SNI_RM200_INT_STAT_REG  0xbc000000
123 #define SNI_RM200_INT_ENA_REG   0xbc080000
124
125 #define SNI_RM200_INT_START  24
126 #define SNI_RM200_INT_END    28
127
128 static void enable_rm200_irq(unsigned int irq)
129 {
130         unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
131
132         *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask;
133 }
134
135 void disable_rm200_irq(unsigned int irq)
136 {
137         unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
138
139         *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask;
140 }
141
142 void end_rm200_irq(unsigned int irq)
143 {
144         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
145                 enable_rm200_irq(irq);
146 }
147
148 static struct irq_chip rm200_irq_type = {
149         .typename = "RM200",
150         .ack = disable_rm200_irq,
151         .mask = disable_rm200_irq,
152         .mask_ack = disable_rm200_irq,
153         .unmask = enable_rm200_irq,
154         .end = end_rm200_irq,
155 };
156
157 static void sni_rm200_hwint(void)
158 {
159         u32 pending = read_c0_cause() & read_c0_status();
160         u8 mask;
161         u8 stat;
162         int irq;
163
164         if (pending & C_IRQ5)
165                 do_IRQ(MIPS_CPU_IRQ_BASE + 7);
166         else if (pending & C_IRQ0) {
167                 clear_c0_status(IE_IRQ0);
168                 mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f;
169                 stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14;
170                 irq = ffs(stat & mask & 0x1f);
171
172                 if (likely(irq > 0))
173                         do_IRQ(irq + SNI_RM200_INT_START - 1);
174                 set_c0_status(IE_IRQ0);
175         }
176 }
177
178 void __init sni_rm200_irq_init(void)
179 {
180         int i;
181
182         * (volatile u8 *)SNI_RM200_INT_ENA_REG = 0x1f;
183
184         mips_cpu_irq_init();
185         /* Actually we've got more interrupts to handle ...  */
186         for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++)
187                 set_irq_chip(i, &rm200_irq_type);
188         sni_hwint = sni_rm200_hwint;
189         change_c0_status(ST0_IM, IE_IRQ0);
190         setup_irq(SNI_RM200_INT_START + 0, &sni_isa_irq);
191 }
192
193 void __init sni_rm200_init(void)
194 {
195         set_io_port_base(SNI_PORT_BASE + 0x02000000);
196         ioport_resource.end += 0x02000000;
197 }