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