xref: /OK3568_Linux_fs/kernel/arch/mips/sni/a20r.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * A20R specific code
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This file is subject to the terms and conditions of the GNU General Public
5*4882a593Smuzhiyun  * License.  See the file "COPYING" in the main directory of this archive
6*4882a593Smuzhiyun  * for more details.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/irq.h>
14*4882a593Smuzhiyun #include <linux/platform_device.h>
15*4882a593Smuzhiyun #include <linux/serial_8250.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <asm/sni.h>
18*4882a593Smuzhiyun #include <asm/time.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define PORT(_base,_irq)				\
21*4882a593Smuzhiyun 	{						\
22*4882a593Smuzhiyun 		.iobase		= _base,		\
23*4882a593Smuzhiyun 		.irq		= _irq,			\
24*4882a593Smuzhiyun 		.uartclk	= 1843200,		\
25*4882a593Smuzhiyun 		.iotype		= UPIO_PORT,		\
26*4882a593Smuzhiyun 		.flags		= UPF_BOOT_AUTOCONF,	\
27*4882a593Smuzhiyun 	}
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun static struct plat_serial8250_port a20r_data[] = {
30*4882a593Smuzhiyun 	PORT(0x3f8, 4),
31*4882a593Smuzhiyun 	PORT(0x2f8, 3),
32*4882a593Smuzhiyun 	{ },
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static struct platform_device a20r_serial8250_device = {
36*4882a593Smuzhiyun 	.name			= "serial8250",
37*4882a593Smuzhiyun 	.id			= PLAT8250_DEV_PLATFORM,
38*4882a593Smuzhiyun 	.dev			= {
39*4882a593Smuzhiyun 		.platform_data	= a20r_data,
40*4882a593Smuzhiyun 	},
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static struct resource a20r_ds1216_rsrc[] = {
44*4882a593Smuzhiyun 	{
45*4882a593Smuzhiyun 		.start = 0x1c081ffc,
46*4882a593Smuzhiyun 		.end   = 0x1c081fff,
47*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM
48*4882a593Smuzhiyun 	}
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun static struct platform_device a20r_ds1216_device = {
52*4882a593Smuzhiyun 	.name		= "rtc-ds1216",
53*4882a593Smuzhiyun 	.num_resources	= ARRAY_SIZE(a20r_ds1216_rsrc),
54*4882a593Smuzhiyun 	.resource	= a20r_ds1216_rsrc
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun static struct resource snirm_82596_rsrc[] = {
58*4882a593Smuzhiyun 	{
59*4882a593Smuzhiyun 		.start = 0x18000000,
60*4882a593Smuzhiyun 		.end   = 0x18000004,
61*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM
62*4882a593Smuzhiyun 	},
63*4882a593Smuzhiyun 	{
64*4882a593Smuzhiyun 		.start = 0x18010000,
65*4882a593Smuzhiyun 		.end   = 0x18010004,
66*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM
67*4882a593Smuzhiyun 	},
68*4882a593Smuzhiyun 	{
69*4882a593Smuzhiyun 		.start = 0x1ff00000,
70*4882a593Smuzhiyun 		.end   = 0x1ff00020,
71*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM
72*4882a593Smuzhiyun 	},
73*4882a593Smuzhiyun 	{
74*4882a593Smuzhiyun 		.start = 22,
75*4882a593Smuzhiyun 		.end   = 22,
76*4882a593Smuzhiyun 		.flags = IORESOURCE_IRQ
77*4882a593Smuzhiyun 	},
78*4882a593Smuzhiyun 	{
79*4882a593Smuzhiyun 		.flags = 0x01		     /* 16bit mpu port access */
80*4882a593Smuzhiyun 	}
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun static struct platform_device snirm_82596_pdev = {
84*4882a593Smuzhiyun 	.name		= "snirm_82596",
85*4882a593Smuzhiyun 	.num_resources	= ARRAY_SIZE(snirm_82596_rsrc),
86*4882a593Smuzhiyun 	.resource	= snirm_82596_rsrc
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static struct resource snirm_53c710_rsrc[] = {
90*4882a593Smuzhiyun 	{
91*4882a593Smuzhiyun 		.start = 0x19000000,
92*4882a593Smuzhiyun 		.end   = 0x190fffff,
93*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM
94*4882a593Smuzhiyun 	},
95*4882a593Smuzhiyun 	{
96*4882a593Smuzhiyun 		.start = 19,
97*4882a593Smuzhiyun 		.end   = 19,
98*4882a593Smuzhiyun 		.flags = IORESOURCE_IRQ
99*4882a593Smuzhiyun 	}
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun static struct platform_device snirm_53c710_pdev = {
103*4882a593Smuzhiyun 	.name		= "snirm_53c710",
104*4882a593Smuzhiyun 	.num_resources	= ARRAY_SIZE(snirm_53c710_rsrc),
105*4882a593Smuzhiyun 	.resource	= snirm_53c710_rsrc
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun static struct resource sc26xx_rsrc[] = {
109*4882a593Smuzhiyun 	{
110*4882a593Smuzhiyun 		.start = 0x1c070000,
111*4882a593Smuzhiyun 		.end   = 0x1c0700ff,
112*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM
113*4882a593Smuzhiyun 	},
114*4882a593Smuzhiyun 	{
115*4882a593Smuzhiyun 		.start = 20,
116*4882a593Smuzhiyun 		.end   = 20,
117*4882a593Smuzhiyun 		.flags = IORESOURCE_IRQ
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun };
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun #include <linux/platform_data/serial-sccnxp.h>
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun static struct sccnxp_pdata sccnxp_data = {
124*4882a593Smuzhiyun 	.reg_shift	= 2,
125*4882a593Smuzhiyun 	.mctrl_cfg[0]	= MCTRL_SIG(DTR_OP, LINE_OP7) |
126*4882a593Smuzhiyun 			  MCTRL_SIG(RTS_OP, LINE_OP3) |
127*4882a593Smuzhiyun 			  MCTRL_SIG(DSR_IP, LINE_IP5) |
128*4882a593Smuzhiyun 			  MCTRL_SIG(DCD_IP, LINE_IP6),
129*4882a593Smuzhiyun 	.mctrl_cfg[1]	= MCTRL_SIG(DTR_OP, LINE_OP2) |
130*4882a593Smuzhiyun 			  MCTRL_SIG(RTS_OP, LINE_OP1) |
131*4882a593Smuzhiyun 			  MCTRL_SIG(DSR_IP, LINE_IP0) |
132*4882a593Smuzhiyun 			  MCTRL_SIG(CTS_IP, LINE_IP1) |
133*4882a593Smuzhiyun 			  MCTRL_SIG(DCD_IP, LINE_IP2) |
134*4882a593Smuzhiyun 			  MCTRL_SIG(RNG_IP, LINE_IP3),
135*4882a593Smuzhiyun };
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun static struct platform_device sc26xx_pdev = {
138*4882a593Smuzhiyun 	.name		= "sc2681",
139*4882a593Smuzhiyun 	.resource	= sc26xx_rsrc,
140*4882a593Smuzhiyun 	.num_resources	= ARRAY_SIZE(sc26xx_rsrc),
141*4882a593Smuzhiyun 	.dev	= {
142*4882a593Smuzhiyun 		.platform_data	= &sccnxp_data,
143*4882a593Smuzhiyun 	},
144*4882a593Smuzhiyun };
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun  * Trigger chipset to update CPU's CAUSE IP field
148*4882a593Smuzhiyun  */
a20r_update_cause_ip(void)149*4882a593Smuzhiyun static u32 a20r_update_cause_ip(void)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	u32 status = read_c0_status();
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	write_c0_status(status | 0x00010000);
154*4882a593Smuzhiyun 	asm volatile(
155*4882a593Smuzhiyun 	"	.set	push			\n"
156*4882a593Smuzhiyun 	"	.set	noat			\n"
157*4882a593Smuzhiyun 	"	.set	noreorder		\n"
158*4882a593Smuzhiyun 	"	lw	$1, 0(%0)		\n"
159*4882a593Smuzhiyun 	"	sb	$0, 0(%1)		\n"
160*4882a593Smuzhiyun 	"	sync				\n"
161*4882a593Smuzhiyun 	"	lb	%1, 0(%1)		\n"
162*4882a593Smuzhiyun 	"	b	1f			\n"
163*4882a593Smuzhiyun 	"	ori	%1, $1, 2		\n"
164*4882a593Smuzhiyun 	"	.align	8			\n"
165*4882a593Smuzhiyun 	"1:					\n"
166*4882a593Smuzhiyun 	"	nop				\n"
167*4882a593Smuzhiyun 	"	sw	%1, 0(%0)		\n"
168*4882a593Smuzhiyun 	"	sync				\n"
169*4882a593Smuzhiyun 	"	li	%1, 0x20		\n"
170*4882a593Smuzhiyun 	"2:					\n"
171*4882a593Smuzhiyun 	"	nop				\n"
172*4882a593Smuzhiyun 	"	bnez	%1,2b			\n"
173*4882a593Smuzhiyun 	"	addiu	%1, -1			\n"
174*4882a593Smuzhiyun 	"	sw	$1, 0(%0)		\n"
175*4882a593Smuzhiyun 	"	sync				\n"
176*4882a593Smuzhiyun 		".set	pop			\n"
177*4882a593Smuzhiyun 	:
178*4882a593Smuzhiyun 	: "Jr" (PCIMT_UCONF), "Jr" (0xbc000000));
179*4882a593Smuzhiyun 	write_c0_status(status);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	return status;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
unmask_a20r_irq(struct irq_data * d)184*4882a593Smuzhiyun static inline void unmask_a20r_irq(struct irq_data *d)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	set_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE));
187*4882a593Smuzhiyun 	irq_enable_hazard();
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
mask_a20r_irq(struct irq_data * d)190*4882a593Smuzhiyun static inline void mask_a20r_irq(struct irq_data *d)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	clear_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE));
193*4882a593Smuzhiyun 	irq_disable_hazard();
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun static struct irq_chip a20r_irq_type = {
197*4882a593Smuzhiyun 	.name		= "A20R",
198*4882a593Smuzhiyun 	.irq_mask	= mask_a20r_irq,
199*4882a593Smuzhiyun 	.irq_unmask	= unmask_a20r_irq,
200*4882a593Smuzhiyun };
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun /*
203*4882a593Smuzhiyun  * hwint 0 receive all interrupts
204*4882a593Smuzhiyun  */
a20r_hwint(void)205*4882a593Smuzhiyun static void a20r_hwint(void)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	u32 cause, status;
208*4882a593Smuzhiyun 	int irq;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	clear_c0_status(IE_IRQ0);
211*4882a593Smuzhiyun 	status = a20r_update_cause_ip();
212*4882a593Smuzhiyun 	cause = read_c0_cause();
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	irq = ffs(((cause & status) >> 8) & 0xf8);
215*4882a593Smuzhiyun 	if (likely(irq > 0))
216*4882a593Smuzhiyun 		do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	a20r_update_cause_ip();
219*4882a593Smuzhiyun 	set_c0_status(IE_IRQ0);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
sni_a20r_irq_init(void)222*4882a593Smuzhiyun void __init sni_a20r_irq_init(void)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	int i;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++)
227*4882a593Smuzhiyun 		irq_set_chip_and_handler(i, &a20r_irq_type, handle_level_irq);
228*4882a593Smuzhiyun 	sni_hwint = a20r_hwint;
229*4882a593Smuzhiyun 	change_c0_status(ST0_IM, IE_IRQ0);
230*4882a593Smuzhiyun 	if (request_irq(SNI_A20R_IRQ_BASE + 3, sni_isa_irq_handler,
231*4882a593Smuzhiyun 			IRQF_SHARED, "ISA", sni_isa_irq_handler))
232*4882a593Smuzhiyun 		pr_err("Failed to register ISA interrupt\n");
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
sni_a20r_init(void)235*4882a593Smuzhiyun void sni_a20r_init(void)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	/* FIXME, remove if not needed */
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
snirm_a20r_setup_devinit(void)240*4882a593Smuzhiyun static int __init snirm_a20r_setup_devinit(void)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	switch (sni_brd_type) {
243*4882a593Smuzhiyun 	case SNI_BRD_TOWER_OASIC:
244*4882a593Smuzhiyun 	case SNI_BRD_MINITOWER:
245*4882a593Smuzhiyun 		platform_device_register(&snirm_82596_pdev);
246*4882a593Smuzhiyun 		platform_device_register(&snirm_53c710_pdev);
247*4882a593Smuzhiyun 		platform_device_register(&sc26xx_pdev);
248*4882a593Smuzhiyun 		platform_device_register(&a20r_serial8250_device);
249*4882a593Smuzhiyun 		platform_device_register(&a20r_ds1216_device);
250*4882a593Smuzhiyun 		sni_eisa_root_init();
251*4882a593Smuzhiyun 		break;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 	return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun device_initcall(snirm_a20r_setup_devinit);
257