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
30static struct plat_serial8250_port rm200_data[] = {
31	PORT(0x3f8, 4),
32	PORT(0x2f8, 3),
33	{ },
34};
35
36static struct platform_device rm200_serial8250_device = {
37	.name			= "serial8250",
38	.id			= PLAT8250_DEV_PLATFORM,
39	.dev			= {
40		.platform_data	= rm200_data,
41	},
42};
43
44static 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
70static 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
76static 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
89static 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
95static 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
105device_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
114static 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
121void 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
128void end_rm200_irq(unsigned int irq)
129{
130	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
131		enable_rm200_irq(irq);
132}
133
134static 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
143static 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
164void __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
179void 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}
187