aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sni
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/sni')
-rw-r--r--arch/mips/sni/Makefile2
-rw-r--r--arch/mips/sni/a20r.c227
-rw-r--r--arch/mips/sni/ds1216.c81
-rw-r--r--arch/mips/sni/irq.c188
-rw-r--r--arch/mips/sni/pcimt.c390
-rw-r--r--arch/mips/sni/pcit.c351
-rw-r--r--arch/mips/sni/reset.c9
-rw-r--r--arch/mips/sni/rm200.c186
-rw-r--r--arch/mips/sni/setup.c242
-rw-r--r--arch/mips/sni/sniprom.c129
-rw-r--r--arch/mips/sni/time.c148
11 files changed, 1578 insertions, 375 deletions
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index a5eb0adb87c7..e30809a92151 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the SNI specific part of the kernel 2# Makefile for the SNI specific part of the kernel
3# 3#
4 4
5obj-y += irq.o pcimt_scache.o reset.o setup.o 5obj-y += irq.o reset.o setup.o ds1216.o a20r.o rm200.o pcimt.o pcit.o time.o
6obj-$(CONFIG_CPU_BIG_ENDIAN) += sniprom.o 6obj-$(CONFIG_CPU_BIG_ENDIAN) += sniprom.o
7 7
8EXTRA_AFLAGS := $(CFLAGS) 8EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c
new file mode 100644
index 000000000000..31ab80f1befa
--- /dev/null
+++ b/arch/mips/sni/a20r.c
@@ -0,0 +1,227 @@
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#include <asm/ds1216.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
29static struct plat_serial8250_port a20r_data[] = {
30 PORT(0x3f8, 4),
31 PORT(0x2f8, 3),
32 { },
33};
34
35static struct platform_device a20r_serial8250_device = {
36 .name = "serial8250",
37 .id = PLAT8250_DEV_PLATFORM,
38 .dev = {
39 .platform_data = a20r_data,
40 },
41};
42
43static struct resource snirm_82596_rsrc[] = {
44 {
45 .start = 0xb8000000,
46 .end = 0xb8000004,
47 .flags = IORESOURCE_MEM
48 },
49 {
50 .start = 0xb8010000,
51 .end = 0xb8010004,
52 .flags = IORESOURCE_MEM
53 },
54 {
55 .start = 0xbff00000,
56 .end = 0xbff00020,
57 .flags = IORESOURCE_MEM
58 },
59 {
60 .start = 22,
61 .end = 22,
62 .flags = IORESOURCE_IRQ
63 },
64 {
65 .flags = 0x01 /* 16bit mpu port access */
66 }
67};
68
69static struct platform_device snirm_82596_pdev = {
70 .name = "snirm_82596",
71 .num_resources = ARRAY_SIZE(snirm_82596_rsrc),
72 .resource = snirm_82596_rsrc
73};
74
75static struct resource snirm_53c710_rsrc[] = {
76 {
77 .start = 0xb9000000,
78 .end = 0xb90fffff,
79 .flags = IORESOURCE_MEM
80 },
81 {
82 .start = 19,
83 .end = 19,
84 .flags = IORESOURCE_IRQ
85 }
86};
87
88static struct platform_device snirm_53c710_pdev = {
89 .name = "snirm_53c710",
90 .num_resources = ARRAY_SIZE(snirm_53c710_rsrc),
91 .resource = snirm_53c710_rsrc
92};
93
94static struct resource sc26xx_rsrc[] = {
95 {
96 .start = 0xbc070000,
97 .end = 0xbc0700ff,
98 .flags = IORESOURCE_MEM
99 },
100 {
101 .start = 20,
102 .end = 20,
103 .flags = IORESOURCE_IRQ
104 }
105};
106
107static struct platform_device sc26xx_pdev = {
108 .name = "SC26xx",
109 .num_resources = ARRAY_SIZE(sc26xx_rsrc),
110 .resource = sc26xx_rsrc
111};
112
113static u32 a20r_ack_hwint(void)
114{
115 u32 status = read_c0_status();
116
117 write_c0_status (status | 0x00010000);
118 asm volatile(
119 " .set push \n"
120 " .set noat \n"
121 " .set noreorder \n"
122 " lw $1, 0(%0) \n"
123 " sb $0, 0(%1) \n"
124 " sync \n"
125 " lb %1, 0(%1) \n"
126 " b 1f \n"
127 " ori %1, $1, 2 \n"
128 " .align 8 \n"
129 "1: \n"
130 " nop \n"
131 " sw %1, 0(%0) \n"
132 " sync \n"
133 " li %1, 0x20 \n"
134 "2: \n"
135 " nop \n"
136 " bnez %1,2b \n"
137 " addiu %1, -1 \n"
138 " sw $1, 0(%0) \n"
139 " sync \n"
140 ".set pop \n"
141 :
142 : "Jr" (PCIMT_UCONF), "Jr" (0xbc000000));
143 write_c0_status(status);
144
145 return status;
146}
147
148static inline void unmask_a20r_irq(unsigned int irq)
149{
150 set_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
151 irq_enable_hazard();
152}
153
154static inline void mask_a20r_irq(unsigned int irq)
155{
156 clear_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
157 irq_disable_hazard();
158}
159
160static void end_a20r_irq(unsigned int irq)
161{
162 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
163 a20r_ack_hwint();
164 unmask_a20r_irq(irq);
165 }
166}
167
168static struct irq_chip a20r_irq_type = {
169 .typename = "A20R",
170 .ack = mask_a20r_irq,
171 .mask = mask_a20r_irq,
172 .mask_ack = mask_a20r_irq,
173 .unmask = unmask_a20r_irq,
174 .end = end_a20r_irq,
175};
176
177/*
178 * hwint 0 receive all interrupts
179 */
180static void a20r_hwint(void)
181{
182 u32 cause, status;
183 int irq;
184
185 clear_c0_status (IE_IRQ0);
186 status = a20r_ack_hwint();
187 cause = read_c0_cause();
188
189 irq = ffs(((cause & status) >> 8) & 0xf8);
190 if (likely(irq > 0))
191 do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
192 set_c0_status(IE_IRQ0);
193}
194
195void __init sni_a20r_irq_init(void)
196{
197 int i;
198
199 for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++)
200 set_irq_chip(i, &a20r_irq_type);
201 sni_hwint = a20r_hwint;
202 change_c0_status(ST0_IM, IE_IRQ0);
203 setup_irq (SNI_A20R_IRQ_BASE + 3, &sni_isa_irq);
204}
205
206void sni_a20r_init(void)
207{
208 ds1216_base = (volatile unsigned char *) SNI_DS1216_A20R_BASE;
209 rtc_mips_get_time = ds1216_get_cmos_time;
210}
211
212static int __init snirm_a20r_setup_devinit(void)
213{
214 switch (sni_brd_type) {
215 case SNI_BRD_TOWER_OASIC:
216 case SNI_BRD_MINITOWER:
217 platform_device_register(&snirm_82596_pdev);
218 platform_device_register(&snirm_53c710_pdev);
219 platform_device_register(&sc26xx_pdev);
220 platform_device_register(&a20r_serial8250_device);
221 break;
222 }
223
224 return 0;
225}
226
227device_initcall(snirm_a20r_setup_devinit);
diff --git a/arch/mips/sni/ds1216.c b/arch/mips/sni/ds1216.c
new file mode 100644
index 000000000000..1d92732c14f1
--- /dev/null
+++ b/arch/mips/sni/ds1216.c
@@ -0,0 +1,81 @@
1
2#include <linux/bcd.h>
3#include <linux/time.h>
4
5#include <asm/ds1216.h>
6
7volatile unsigned char *ds1216_base;
8
9/*
10 * Read the 64 bit we'd like to have - It a series
11 * of 64 bits showing up in the LSB of the base register.
12 *
13 */
14static unsigned char *ds1216_read(void)
15{
16 static unsigned char rdbuf[8];
17 unsigned char c;
18 int i, j;
19
20 for (i = 0; i < 8; i++) {
21 c = 0x0;
22 for (j = 0; j < 8; j++) {
23 c |= (*ds1216_base & 0x1) << j;
24 }
25 rdbuf[i] = c;
26 }
27
28 return rdbuf;
29}
30
31static void ds1216_switch_ds_to_clock(void)
32{
33 unsigned char magic[] = {
34 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
35 };
36 int i,j,c;
37
38 /* Reset magic pointer */
39 c = *ds1216_base;
40
41 /* Write 64 bit magic to DS1216 */
42 for (i = 0; i < 8; i++) {
43 c = magic[i];
44 for (j = 0; j < 8; j++) {
45 *ds1216_base = c;
46 c = c >> 1;
47 }
48 }
49}
50
51unsigned long ds1216_get_cmos_time(void)
52{
53 unsigned char *rdbuf;
54 unsigned int year, month, date, hour, min, sec;
55
56 ds1216_switch_ds_to_clock();
57 rdbuf = ds1216_read();
58
59 sec = BCD2BIN(DS1216_SEC(rdbuf));
60 min = BCD2BIN(DS1216_MIN(rdbuf));
61 hour = BCD2BIN(DS1216_HOUR(rdbuf));
62 date = BCD2BIN(DS1216_DATE(rdbuf));
63 month = BCD2BIN(DS1216_MONTH(rdbuf));
64 year = BCD2BIN(DS1216_YEAR(rdbuf));
65
66 if (DS1216_1224(rdbuf) && DS1216_AMPM(rdbuf))
67 hour+=12;
68
69 if (year < 70)
70 year += 2000;
71 else
72 year += 1900;
73
74 return mktime(year, month, date, hour, min, sec);
75}
76
77int ds1216_set_rtc_mmss(unsigned long nowtime)
78{
79 printk("ds1216_set_rtc_mmss called but not implemented\n");
80 return -1;
81}
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index 039e8e540508..ad5fc471a004 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -5,6 +5,7 @@
5 * 5 *
6 * Copyright (C) 1992 Linus Torvalds 6 * Copyright (C) 1992 Linus Torvalds
7 * Copyright (C) 1994 - 2000 Ralf Baechle 7 * Copyright (C) 1994 - 2000 Ralf Baechle
8 * Copyright (C) 2006 Thomas Bogendoerfer
8 */ 9 */
9#include <linux/delay.h> 10#include <linux/delay.h>
10#include <linux/init.h> 11#include <linux/init.h>
@@ -15,152 +16,34 @@
15#include <asm/i8259.h> 16#include <asm/i8259.h>
16#include <asm/io.h> 17#include <asm/io.h>
17#include <asm/sni.h> 18#include <asm/sni.h>
19#include <asm/irq.h>
20#include <asm/irq_cpu.h>
18 21
19static void enable_pciasic_irq(unsigned int irq) 22void (*sni_hwint)(void);
20{
21 unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
22
23 *(volatile u8 *) PCIMT_IRQSEL |= mask;
24}
25
26void disable_pciasic_irq(unsigned int irq)
27{
28 unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2));
29
30 *(volatile u8 *) PCIMT_IRQSEL &= mask;
31}
32 23
33static void end_pciasic_irq(unsigned int irq) 24asmlinkage void plat_irq_dispatch(void)
34{
35 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
36 enable_pciasic_irq(irq);
37}
38
39static struct irq_chip pciasic_irq_type = {
40 .name = "ASIC-PCI",
41 .ack = disable_pciasic_irq,
42 .mask = disable_pciasic_irq,
43 .mask_ack = disable_pciasic_irq,
44 .unmask = enable_pciasic_irq,
45 .end = end_pciasic_irq,
46};
47
48/*
49 * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
50 * button interrupts. Later ...
51 */
52static void pciasic_hwint0(void)
53{
54 panic("Received int0 but no handler yet ...");
55}
56
57/* This interrupt was used for the com1 console on the first prototypes. */
58static void pciasic_hwint2(void)
59{
60 /* I think this shouldn't happen on production machines. */
61 panic("hwint2 and no handler yet");
62}
63
64/* hwint5 is the r4k count / compare interrupt */
65static void pciasic_hwint5(void)
66{
67 panic("hwint5 and no handler yet");
68}
69
70static unsigned int ls1bit8(unsigned int x)
71{
72 int b = 7, s;
73
74 s = 4; if ((x & 0x0f) == 0) s = 0; b -= s; x <<= s;
75 s = 2; if ((x & 0x30) == 0) s = 0; b -= s; x <<= s;
76 s = 1; if ((x & 0x40) == 0) s = 0; b -= s;
77
78 return b;
79}
80
81/*
82 * hwint 1 deals with EISA and SCSI interrupts,
83 *
84 * The EISA_INT bit in CSITPEND is high active, all others are low active.
85 */
86static void pciasic_hwint1(void)
87{ 25{
88 u8 pend = *(volatile char *)PCIMT_CSITPEND; 26 sni_hwint();
89 unsigned long flags;
90
91 if (pend & IT_EISA) {
92 int irq;
93 /*
94 * Note: ASIC PCI's builtin interrupt achknowledge feature is
95 * broken. Using it may result in loss of some or all i8259
96 * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
97 */
98 irq = i8259_irq();
99 if (unlikely(irq < 0))
100 return;
101
102 do_IRQ(irq);
103 }
104
105 if (!(pend & IT_SCSI)) {
106 flags = read_c0_status();
107 clear_c0_status(ST0_IM);
108 do_IRQ(PCIMT_IRQ_SCSI);
109 write_c0_status(flags);
110 }
111} 27}
112 28
113/* 29/* ISA irq handler */
114 * hwint 3 should deal with the PCI A - D interrupts, 30static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
115 */
116static void pciasic_hwint3(void)
117{ 31{
118 u8 pend = *(volatile char *)PCIMT_CSITPEND;
119 int irq; 32 int irq;
120 33
121 pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); 34 irq = i8259_irq();
122 clear_c0_status(IE_IRQ3); 35 if (unlikely(irq < 0))
123 irq = PCIMT_IRQ_INT2 + ls1bit8(pend); 36 return IRQ_NONE;
124 do_IRQ(irq);
125 set_c0_status(IE_IRQ3);
126}
127 37
128/* 38 do_IRQ(irq);
129 * hwint 4 is used for only the onboard PCnet 32. 39 return IRQ_HANDLED;
130 */
131static void pciasic_hwint4(void)
132{
133 clear_c0_status(IE_IRQ4);
134 do_IRQ(PCIMT_IRQ_ETHERNET);
135 set_c0_status(IE_IRQ4);
136}
137
138asmlinkage void plat_irq_dispatch(void)
139{
140 unsigned int pending = read_c0_status() & read_c0_cause();
141 static unsigned char led_cache;
142
143 *(volatile unsigned char *) PCIMT_CSLED = ++led_cache;
144
145 if (pending & 0x0800)
146 pciasic_hwint1();
147 else if (pending & 0x4000)
148 pciasic_hwint4();
149 else if (pending & 0x2000)
150 pciasic_hwint3();
151 else if (pending & 0x1000)
152 pciasic_hwint2();
153 else if (pending & 0x8000)
154 pciasic_hwint5();
155 else if (pending & 0x0400)
156 pciasic_hwint0();
157} 40}
158 41
159void __init init_pciasic(void) 42struct irqaction sni_isa_irq = {
160{ 43 .handler = sni_isa_irq_handler,
161 * (volatile u8 *) PCIMT_IRQSEL = 44 .name = "ISA",
162 IT_EISA | IT_INTA | IT_INTB | IT_INTC | IT_INTD; 45 .flags = SA_SHIRQ
163} 46};
164 47
165/* 48/*
166 * On systems with i8259-style interrupt controllers we assume for 49 * On systems with i8259-style interrupt controllers we assume for
@@ -169,14 +52,31 @@ void __init init_pciasic(void)
169 */ 52 */
170void __init arch_init_irq(void) 53void __init arch_init_irq(void)
171{ 54{
172 int i;
173
174 init_i8259_irqs(); /* Integrated i8259 */ 55 init_i8259_irqs(); /* Integrated i8259 */
175 init_pciasic(); 56 switch (sni_brd_type) {
176 57 case SNI_BRD_10:
177 /* Actually we've got more interrupts to handle ... */ 58 case SNI_BRD_10NEW:
178 for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_ETHERNET; i++) 59 case SNI_BRD_TOWER_OASIC:
179 set_irq_chip(i, &pciasic_irq_type); 60 case SNI_BRD_MINITOWER:
180 61 sni_a20r_irq_init();
181 change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4); 62 break;
63
64 case SNI_BRD_PCI_TOWER:
65 sni_pcit_irq_init();
66 break;
67
68 case SNI_BRD_PCI_TOWER_CPLUS:
69 sni_pcit_cplus_irq_init();
70 break;
71
72 case SNI_BRD_RM200:
73 sni_rm200_irq_init();
74 break;
75
76 case SNI_BRD_PCI_MTOWER:
77 case SNI_BRD_PCI_DESKTOP:
78 case SNI_BRD_PCI_MTOWER_CPLUS:
79 sni_pcimt_irq_init();
80 break;
81 }
182} 82}
diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c
new file mode 100644
index 000000000000..6c0dad7cbf4e
--- /dev/null
+++ b/arch/mips/sni/pcimt.c
@@ -0,0 +1,390 @@
1/*
2 * PCIMT 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) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org)
9 * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
10 */
11
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/pci.h>
15#include <linux/serial_8250.h>
16
17#include <asm/mc146818-time.h>
18#include <asm/sni.h>
19#include <asm/time.h>
20#include <asm/i8259.h>
21#include <asm/irq_cpu.h>
22
23#define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF)
24#define invspace (*(volatile unsigned int *)PCIMT_INVSPACE)
25
26static void __init sni_pcimt_sc_init(void)
27{
28 unsigned int scsiz, sc_size;
29
30 scsiz = cacheconf & 7;
31 if (scsiz == 0) {
32 printk("Second level cache is deactived.\n");
33 return;
34 }
35 if (scsiz >= 6) {
36 printk("Invalid second level cache size configured, "
37 "deactivating second level cache.\n");
38 cacheconf = 0;
39 return;
40 }
41
42 sc_size = 128 << scsiz;
43 printk("%dkb second level cache detected, deactivating.\n", sc_size);
44 cacheconf = 0;
45}
46
47
48/*
49 * A bit more gossip about the iron we're running on ...
50 */
51static inline void sni_pcimt_detect(void)
52{
53 char boardtype[80];
54 unsigned char csmsr;
55 char *p = boardtype;
56 unsigned int asic;
57
58 csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
59
60 p += sprintf(p, "%s PCI", (csmsr & 0x80) ? "RM200" : "RM300");
61 if ((csmsr & 0x80) == 0)
62 p += sprintf(p, ", board revision %s",
63 (csmsr & 0x20) ? "D" : "C");
64 asic = csmsr & 0x80;
65 asic = (csmsr & 0x08) ? asic : !asic;
66 p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1");
67 printk("%s.\n", boardtype);
68}
69
70#define PORT(_base,_irq) \
71 { \
72 .iobase = _base, \
73 .irq = _irq, \
74 .uartclk = 1843200, \
75 .iotype = UPIO_PORT, \
76 .flags = UPF_BOOT_AUTOCONF, \
77 }
78
79static struct plat_serial8250_port pcimt_data[] = {
80 PORT(0x3f8, 4),
81 PORT(0x2f8, 3),
82 { },
83};
84
85static struct platform_device pcimt_serial8250_device = {
86 .name = "serial8250",
87 .id = PLAT8250_DEV_PLATFORM,
88 .dev = {
89 .platform_data = pcimt_data,
90 },
91};
92
93static struct resource sni_io_resource = {
94 .start = 0x00001000UL,
95 .end = 0x03bfffffUL,
96 .name = "PCIMT IO MEM",
97 .flags = IORESOURCE_IO,
98};
99
100static struct resource pcimt_io_resources[] = {
101 {
102 .start = 0x00,
103 .end = 0x1f,
104 .name = "dma1",
105 .flags = IORESOURCE_BUSY
106 }, {
107 .start = 0x40,
108 .end = 0x5f,
109 .name = "timer",
110 .flags = IORESOURCE_BUSY
111 }, {
112 .start = 0x60,
113 .end = 0x6f,
114 .name = "keyboard",
115 .flags = IORESOURCE_BUSY
116 }, {
117 .start = 0x80,
118 .end = 0x8f,
119 .name = "dma page reg",
120 .flags = IORESOURCE_BUSY
121 }, {
122 .start = 0xc0,
123 .end = 0xdf,
124 .name = "dma2",
125 .flags = IORESOURCE_BUSY
126 }, {
127 .start = 0xcfc,
128 .end = 0xcff,
129 .name = "PCI config data",
130 .flags = IORESOURCE_BUSY
131 }
132};
133
134static struct resource sni_mem_resource = {
135 .start = 0x10000000UL,
136 .end = 0xffffffffUL,
137 .name = "PCIMT PCI MEM",
138 .flags = IORESOURCE_MEM
139};
140
141/*
142 * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used
143 * for other purposes. Be paranoid and allocate all of the before the PCI
144 * code gets a chance to to map anything else there ...
145 *
146 * This leaves the following areas available:
147 *
148 * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory
149 * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory
150 * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory
151 * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory
152 * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory
153 */
154static struct resource pcimt_mem_resources[] = {
155 {
156 .start = 0x100a0000,
157 .end = 0x100bffff,
158 .name = "Video RAM area",
159 .flags = IORESOURCE_BUSY
160 }, {
161 .start = 0x100c0000,
162 .end = 0x100fffff,
163 .name = "ISA Reserved",
164 .flags = IORESOURCE_BUSY
165 }, {
166 .start = 0x14000000,
167 .end = 0x17bfffff,
168 .name = "PCI IO",
169 .flags = IORESOURCE_BUSY
170 }, {
171 .start = 0x17c00000,
172 .end = 0x17ffffff,
173 .name = "Cache Replacement Area",
174 .flags = IORESOURCE_BUSY
175 }, {
176 .start = 0x1a000000,
177 .end = 0x1a000003,
178 .name = "PCI INT Acknowledge",
179 .flags = IORESOURCE_BUSY
180 }, {
181 .start = 0x1fc00000,
182 .end = 0x1fc7ffff,
183 .name = "Boot PROM",
184 .flags = IORESOURCE_BUSY
185 }, {
186 .start = 0x1fc80000,
187 .end = 0x1fcfffff,
188 .name = "Diag PROM",
189 .flags = IORESOURCE_BUSY
190 }, {
191 .start = 0x1fd00000,
192 .end = 0x1fdfffff,
193 .name = "X-Bus",
194 .flags = IORESOURCE_BUSY
195 }, {
196 .start = 0x1fe00000,
197 .end = 0x1fefffff,
198 .name = "BIOS map",
199 .flags = IORESOURCE_BUSY
200 }, {
201 .start = 0x1ff00000,
202 .end = 0x1ff7ffff,
203 .name = "NVRAM / EEPROM",
204 .flags = IORESOURCE_BUSY
205 }, {
206 .start = 0x1fff0000,
207 .end = 0x1fffefff,
208 .name = "ASIC PCI",
209 .flags = IORESOURCE_BUSY
210 }, {
211 .start = 0x1ffff000,
212 .end = 0x1fffffff,
213 .name = "MP Agent",
214 .flags = IORESOURCE_BUSY
215 }, {
216 .start = 0x20000000,
217 .end = 0x9fffffff,
218 .name = "Main Memory",
219 .flags = IORESOURCE_BUSY
220 }
221};
222
223static void __init sni_pcimt_resource_init(void)
224{
225 int i;
226
227 /* request I/O space for devices used on all i[345]86 PCs */
228 for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++)
229 request_resource(&ioport_resource, pcimt_io_resources + i);
230
231 /* request mem space for pcimt-specific devices */
232 for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++)
233 request_resource(&sni_mem_resource, pcimt_mem_resources + i);
234
235 ioport_resource.end = sni_io_resource.end;
236}
237
238extern struct pci_ops sni_pcimt_ops;
239
240static struct pci_controller sni_controller = {
241 .pci_ops = &sni_pcimt_ops,
242 .mem_resource = &sni_mem_resource,
243 .mem_offset = 0x10000000UL,
244 .io_resource = &sni_io_resource,
245 .io_offset = 0x00000000UL
246};
247
248static void enable_pcimt_irq(unsigned int irq)
249{
250 unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
251
252 *(volatile u8 *) PCIMT_IRQSEL |= mask;
253}
254
255void disable_pcimt_irq(unsigned int irq)
256{
257 unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2));
258
259 *(volatile u8 *) PCIMT_IRQSEL &= mask;
260}
261
262static void end_pcimt_irq(unsigned int irq)
263{
264 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
265 enable_pcimt_irq(irq);
266}
267
268static struct irq_chip pcimt_irq_type = {
269 .typename = "PCIMT",
270 .ack = disable_pcimt_irq,
271 .mask = disable_pcimt_irq,
272 .mask_ack = disable_pcimt_irq,
273 .unmask = enable_pcimt_irq,
274 .end = end_pcimt_irq,
275};
276
277/*
278 * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
279 * button interrupts. Later ...
280 */
281static void pcimt_hwint0(void)
282{
283 panic("Received int0 but no handler yet ...");
284}
285
286/*
287 * hwint 1 deals with EISA and SCSI interrupts,
288 *
289 * The EISA_INT bit in CSITPEND is high active, all others are low active.
290 */
291static void pcimt_hwint1(void)
292{
293 u8 pend = *(volatile char *)PCIMT_CSITPEND;
294 unsigned long flags;
295
296 if (pend & IT_EISA) {
297 int irq;
298 /*
299 * Note: ASIC PCI's builtin interrupt achknowledge feature is
300 * broken. Using it may result in loss of some or all i8259
301 * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
302 */
303 irq = i8259_irq();
304 if (unlikely(irq < 0))
305 return;
306
307 do_IRQ(irq);
308 }
309
310 if (!(pend & IT_SCSI)) {
311 flags = read_c0_status();
312 clear_c0_status(ST0_IM);
313 do_IRQ(PCIMT_IRQ_SCSI);
314 write_c0_status(flags);
315 }
316}
317
318/*
319 * hwint 3 should deal with the PCI A - D interrupts,
320 */
321static void pcimt_hwint3(void)
322{
323 u8 pend = *(volatile char *)PCIMT_CSITPEND;
324 int irq;
325
326 pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
327 pend ^= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
328 clear_c0_status(IE_IRQ3);
329 irq = PCIMT_IRQ_INT2 + ffs(pend) - 1;
330 do_IRQ(irq);
331 set_c0_status(IE_IRQ3);
332}
333
334static void sni_pcimt_hwint(void)
335{
336 u32 pending = (read_c0_cause() & read_c0_status());
337
338 if (pending & C_IRQ5)
339 do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7);
340 else if (pending & C_IRQ4)
341 do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 6);
342 else if (pending & C_IRQ3)
343 pcimt_hwint3();
344 else if (pending & C_IRQ1)
345 pcimt_hwint1();
346 else if (pending & C_IRQ0) {
347 pcimt_hwint0();
348 }
349}
350
351void __init sni_pcimt_irq_init(void)
352{
353 int i;
354
355 *(volatile u8 *) PCIMT_IRQSEL = IT_ETH | IT_EISA;
356 mips_cpu_irq_init();
357 /* Actually we've got more interrupts to handle ... */
358 for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_SCSI; i++)
359 set_irq_chip(i, &pcimt_irq_type);
360 sni_hwint = sni_pcimt_hwint;
361 change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ3);
362}
363
364void sni_pcimt_init(void)
365{
366 sni_pcimt_resource_init();
367 sni_pcimt_detect();
368 sni_pcimt_sc_init();
369 rtc_mips_get_time = mc146818_get_cmos_time;
370 rtc_mips_set_time = mc146818_set_rtc_mmss;
371 board_time_init = sni_cpu_time_init;
372#ifdef CONFIG_PCI
373 register_pci_controller(&sni_controller);
374#endif
375}
376
377static int __init snirm_pcimt_setup_devinit(void)
378{
379 switch (sni_brd_type) {
380 case SNI_BRD_PCI_MTOWER:
381 case SNI_BRD_PCI_DESKTOP:
382 case SNI_BRD_PCI_MTOWER_CPLUS:
383 platform_device_register(&pcimt_serial8250_device);
384 break;
385 }
386
387 return 0;
388}
389
390device_initcall(snirm_pcimt_setup_devinit);
diff --git a/arch/mips/sni/pcit.c b/arch/mips/sni/pcit.c
new file mode 100644
index 000000000000..3921096023c3
--- /dev/null
+++ b/arch/mips/sni/pcit.c
@@ -0,0 +1,351 @@
1/*
2 * PCI Tower 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/pci.h>
14#include <linux/serial_8250.h>
15
16#include <asm/mc146818-time.h>
17#include <asm/sni.h>
18#include <asm/time.h>
19#include <asm/irq_cpu.h>
20
21
22#define PORT(_base,_irq) \
23 { \
24 .iobase = _base, \
25 .irq = _irq, \
26 .uartclk = 1843200, \
27 .iotype = UPIO_PORT, \
28 .flags = UPF_BOOT_AUTOCONF, \
29 }
30
31static struct plat_serial8250_port pcit_data[] = {
32 PORT(0x3f8, 0),
33 PORT(0x2f8, 3),
34 { },
35};
36
37static struct platform_device pcit_serial8250_device = {
38 .name = "serial8250",
39 .id = PLAT8250_DEV_PLATFORM,
40 .dev = {
41 .platform_data = pcit_data,
42 },
43};
44
45static struct plat_serial8250_port pcit_cplus_data[] = {
46 PORT(0x3f8, 4),
47 PORT(0x2f8, 3),
48 PORT(0x3e8, 4),
49 PORT(0x2e8, 3),
50 { },
51};
52
53static struct platform_device pcit_cplus_serial8250_device = {
54 .name = "serial8250",
55 .id = PLAT8250_DEV_PLATFORM,
56 .dev = {
57 .platform_data = pcit_cplus_data,
58 },
59};
60
61static struct resource sni_io_resource = {
62 .start = 0x00001000UL,
63 .end = 0x03bfffffUL,
64 .name = "PCIT IO MEM",
65 .flags = IORESOURCE_IO,
66};
67
68static struct resource pcit_io_resources[] = {
69 {
70 .start = 0x00,
71 .end = 0x1f,
72 .name = "dma1",
73 .flags = IORESOURCE_BUSY
74 }, {
75 .start = 0x40,
76 .end = 0x5f,
77 .name = "timer",
78 .flags = IORESOURCE_BUSY
79 }, {
80 .start = 0x60,
81 .end = 0x6f,
82 .name = "keyboard",
83 .flags = IORESOURCE_BUSY
84 }, {
85 .start = 0x80,
86 .end = 0x8f,
87 .name = "dma page reg",
88 .flags = IORESOURCE_BUSY
89 }, {
90 .start = 0xc0,
91 .end = 0xdf,
92 .name = "dma2",
93 .flags = IORESOURCE_BUSY
94 }, {
95 .start = 0xcfc,
96 .end = 0xcff,
97 .name = "PCI config data",
98 .flags = IORESOURCE_BUSY
99 }
100};
101
102static struct resource sni_mem_resource = {
103 .start = 0x10000000UL,
104 .end = 0xffffffffUL,
105 .name = "PCIT PCI MEM",
106 .flags = IORESOURCE_MEM
107};
108
109/*
110 * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used
111 * for other purposes. Be paranoid and allocate all of the before the PCI
112 * code gets a chance to to map anything else there ...
113 *
114 * This leaves the following areas available:
115 *
116 * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory
117 * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory
118 * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory
119 * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory
120 * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory
121 */
122static struct resource pcit_mem_resources[] = {
123 {
124 .start = 0x14000000,
125 .end = 0x17bfffff,
126 .name = "PCI IO",
127 .flags = IORESOURCE_BUSY
128 }, {
129 .start = 0x17c00000,
130 .end = 0x17ffffff,
131 .name = "Cache Replacement Area",
132 .flags = IORESOURCE_BUSY
133 }, {
134 .start = 0x180a0000,
135 .end = 0x180bffff,
136 .name = "Video RAM area",
137 .flags = IORESOURCE_BUSY
138 }, {
139 .start = 0x180c0000,
140 .end = 0x180fffff,
141 .name = "ISA Reserved",
142 .flags = IORESOURCE_BUSY
143 }, {
144 .start = 0x19000000,
145 .end = 0x1fbfffff,
146 .name = "PCI MEM",
147 .flags = IORESOURCE_BUSY
148 }, {
149 .start = 0x1fc00000,
150 .end = 0x1fc7ffff,
151 .name = "Boot PROM",
152 .flags = IORESOURCE_BUSY
153 }, {
154 .start = 0x1fc80000,
155 .end = 0x1fcfffff,
156 .name = "Diag PROM",
157 .flags = IORESOURCE_BUSY
158 }, {
159 .start = 0x1fd00000,
160 .end = 0x1fdfffff,
161 .name = "X-Bus",
162 .flags = IORESOURCE_BUSY
163 }, {
164 .start = 0x1fe00000,
165 .end = 0x1fefffff,
166 .name = "BIOS map",
167 .flags = IORESOURCE_BUSY
168 }, {
169 .start = 0x1ff00000,
170 .end = 0x1ff7ffff,
171 .name = "NVRAM / EEPROM",
172 .flags = IORESOURCE_BUSY
173 }, {
174 .start = 0x1fff0000,
175 .end = 0x1fffefff,
176 .name = "MAUI ASIC",
177 .flags = IORESOURCE_BUSY
178 }, {
179 .start = 0x1ffff000,
180 .end = 0x1fffffff,
181 .name = "MP Agent",
182 .flags = IORESOURCE_BUSY
183 }, {
184 .start = 0x20000000,
185 .end = 0x9fffffff,
186 .name = "Main Memory",
187 .flags = IORESOURCE_BUSY
188 }
189};
190
191static void __init sni_pcit_resource_init(void)
192{
193 int i;
194
195 /* request I/O space for devices used on all i[345]86 PCs */
196 for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++)
197 request_resource(&ioport_resource, pcit_io_resources + i);
198
199 /* request mem space for pcimt-specific devices */
200 for (i = 0; i < ARRAY_SIZE(pcit_mem_resources); i++)
201 request_resource(&sni_mem_resource, pcit_mem_resources + i);
202
203 ioport_resource.end = sni_io_resource.end;
204}
205
206
207extern struct pci_ops sni_pcit_ops;
208
209static struct pci_controller sni_pcit_controller = {
210 .pci_ops = &sni_pcit_ops,
211 .mem_resource = &sni_mem_resource,
212 .mem_offset = 0x10000000UL,
213 .io_resource = &sni_io_resource,
214 .io_offset = 0x00000000UL
215};
216
217static void enable_pcit_irq(unsigned int irq)
218{
219 u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
220
221 *(volatile u32 *)SNI_PCIT_INT_REG |= mask;
222}
223
224void disable_pcit_irq(unsigned int irq)
225{
226 u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
227
228 *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask;
229}
230
231void end_pcit_irq(unsigned int irq)
232{
233 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
234 enable_pcit_irq(irq);
235}
236
237static struct irq_chip pcit_irq_type = {
238 .typename = "PCIT",
239 .ack = disable_pcit_irq,
240 .mask = disable_pcit_irq,
241 .mask_ack = disable_pcit_irq,
242 .unmask = enable_pcit_irq,
243 .end = end_pcit_irq,
244};
245
246static void pcit_hwint1(void)
247{
248 u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
249 int irq;
250
251 clear_c0_status(IE_IRQ1);
252 irq = ffs((pending >> 16) & 0x7f);
253
254 if (likely(irq > 0))
255 do_IRQ (irq + SNI_PCIT_INT_START - 1);
256 set_c0_status (IE_IRQ1);
257}
258
259static void pcit_hwint0(void)
260{
261 u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
262 int irq;
263
264 clear_c0_status(IE_IRQ0);
265 irq = ffs((pending >> 16) & 0x7f);
266
267 if (likely(irq > 0))
268 do_IRQ (irq + SNI_PCIT_INT_START - 1);
269 set_c0_status (IE_IRQ0);
270}
271
272static void sni_pcit_hwint(void)
273{
274 u32 pending = (read_c0_cause() & read_c0_status());
275
276 if (pending & C_IRQ1)
277 pcit_hwint1();
278 else if (pending & C_IRQ2)
279 do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 4);
280 else if (pending & C_IRQ3)
281 do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 5);
282 else if (pending & C_IRQ5)
283 do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7);
284}
285
286static void sni_pcit_hwint_cplus(void)
287{
288 u32 pending = (read_c0_cause() & read_c0_status());
289
290 if (pending & C_IRQ0)
291 pcit_hwint0();
292 else if (pending & C_IRQ2)
293 do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 4);
294 else if (pending & C_IRQ3)
295 do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 5);
296 else if (pending & C_IRQ5)
297 do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7);
298}
299
300void __init sni_pcit_irq_init(void)
301{
302 int i;
303
304 mips_cpu_irq_init();
305 for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
306 set_irq_chip(i, &pcit_irq_type);
307 *(volatile u32 *)SNI_PCIT_INT_REG = 0;
308 sni_hwint = sni_pcit_hwint;
309 change_c0_status(ST0_IM, IE_IRQ1);
310 setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq);
311}
312
313void __init sni_pcit_cplus_irq_init(void)
314{
315 int i;
316
317 mips_cpu_irq_init();
318 for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
319 set_irq_chip(i, &pcit_irq_type);
320 *(volatile u32 *)SNI_PCIT_INT_REG = 0;
321 sni_hwint = sni_pcit_hwint_cplus;
322 change_c0_status(ST0_IM, IE_IRQ0);
323 setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq);
324}
325
326void sni_pcit_init(void)
327{
328 sni_pcit_resource_init();
329 rtc_mips_get_time = mc146818_get_cmos_time;
330 rtc_mips_set_time = mc146818_set_rtc_mmss;
331 board_time_init = sni_cpu_time_init;
332#ifdef CONFIG_PCI
333 register_pci_controller(&sni_pcit_controller);
334#endif
335}
336
337static int __init snirm_pcit_setup_devinit(void)
338{
339 switch (sni_brd_type) {
340 case SNI_BRD_PCI_TOWER:
341 platform_device_register(&pcit_serial8250_device);
342 break;
343
344 case SNI_BRD_PCI_TOWER_CPLUS:
345 platform_device_register(&pcit_cplus_serial8250_device);
346 break;
347 }
348 return 0;
349}
350
351device_initcall(snirm_pcit_setup_devinit);
diff --git a/arch/mips/sni/reset.c b/arch/mips/sni/reset.c
index be85bec002e1..2eada8aea682 100644
--- a/arch/mips/sni/reset.c
+++ b/arch/mips/sni/reset.c
@@ -13,12 +13,11 @@
13 * controller to pulse the reset-line low. We try that for a while, 13 * controller to pulse the reset-line low. We try that for a while,
14 * and if it doesn't work, we do some other stupid things. 14 * and if it doesn't work, we do some other stupid things.
15 */ 15 */
16static inline void 16static inline void kb_wait(void)
17kb_wait(void)
18{ 17{
19 int i; 18 int i;
20 19
21 for (i=0; i<0x10000; i++) 20 for (i = 0; i < 0x10000; i++)
22 if ((inb_p(0x64) & 0x02) == 0) 21 if ((inb_p(0x64) & 0x02) == 0)
23 break; 22 break;
24} 23}
@@ -32,9 +31,9 @@ void sni_machine_restart(char *command)
32 We can do that easier ... */ 31 We can do that easier ... */
33 local_irq_disable(); 32 local_irq_disable();
34 for (;;) { 33 for (;;) {
35 for (i=0; i<100; i++) { 34 for (i = 0; i < 100; i++) {
36 kb_wait(); 35 kb_wait();
37 for(j = 0; j < 100000 ; j++) 36 for (j = 0; j < 100000 ; j++)
38 /* nothing */; 37 /* nothing */;
39 outb_p(0xfe,0x64); /* pulse reset low */ 38 outb_p(0xfe,0x64); /* pulse reset low */
40 } 39 }
diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c
new file mode 100644
index 000000000000..517dc698c083
--- /dev/null
+++ b/arch/mips/sni/rm200.c
@@ -0,0 +1,186 @@
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 (SNI_MIPS_IRQ_CPU_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}
diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c
index afeb7f13e5b5..68d7cf609b4f 100644
--- a/arch/mips/sni/setup.c
+++ b/arch/mips/sni/setup.c
@@ -6,16 +6,10 @@
6 * for more details. 6 * for more details.
7 * 7 *
8 * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org) 8 * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org)
9 * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
9 */ 10 */
10#include <linux/eisa.h> 11#include <linux/eisa.h>
11#include <linux/hdreg.h>
12#include <linux/ioport.h>
13#include <linux/sched.h>
14#include <linux/init.h> 12#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/mc146818rtc.h>
17#include <linux/pm.h>
18#include <linux/pci.h>
19#include <linux/console.h> 13#include <linux/console.h>
20#include <linux/fb.h> 14#include <linux/fb.h>
21#include <linux/screen_info.h> 15#include <linux/screen_info.h>
@@ -25,52 +19,16 @@
25#include <asm/sgialib.h> 19#include <asm/sgialib.h>
26#endif 20#endif
27 21
28#include <asm/bcache.h>
29#include <asm/bootinfo.h>
30#include <asm/io.h> 22#include <asm/io.h>
31#include <asm/irq.h>
32#include <asm/mc146818-time.h>
33#include <asm/processor.h>
34#include <asm/reboot.h> 23#include <asm/reboot.h>
35#include <asm/sni.h> 24#include <asm/sni.h>
36#include <asm/time.h> 25
37#include <asm/traps.h> 26unsigned int sni_brd_type;
38 27
39extern void sni_machine_restart(char *command); 28extern void sni_machine_restart(char *command);
40extern void sni_machine_halt(void); 29extern void sni_machine_halt(void);
41extern void sni_machine_power_off(void); 30extern void sni_machine_power_off(void);
42 31
43void __init plat_timer_setup(struct irqaction *irq)
44{
45 /* set the clock to 100 Hz */
46 outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
47 outb_p(LATCH & 0xff , 0x40); /* LSB */
48 outb(LATCH >> 8 , 0x40); /* MSB */
49 setup_irq(0, irq);
50}
51
52/*
53 * A bit more gossip about the iron we're running on ...
54 */
55static inline void sni_pcimt_detect(void)
56{
57 char boardtype[80];
58 unsigned char csmsr;
59 char *p = boardtype;
60 unsigned int asic;
61
62 csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
63
64 p += sprintf(p, "%s PCI", (csmsr & 0x80) ? "RM200" : "RM300");
65 if ((csmsr & 0x80) == 0)
66 p += sprintf(p, ", board revision %s",
67 (csmsr & 0x20) ? "D" : "C");
68 asic = csmsr & 0x80;
69 asic = (csmsr & 0x08) ? asic : !asic;
70 p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1");
71 printk("%s.\n", boardtype);
72}
73
74static void __init sni_display_setup(void) 32static void __init sni_display_setup(void)
75{ 33{
76#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_ARC) 34#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_ARC)
@@ -90,175 +48,11 @@ static void __init sni_display_setup(void)
90#endif 48#endif
91} 49}
92 50
93static struct resource sni_io_resource = {
94 .start = 0x00001000UL,
95 .end = 0x03bfffffUL,
96 .name = "PCIMT IO MEM",
97 .flags = IORESOURCE_IO,
98};
99
100static struct resource pcimt_io_resources[] = {
101 {
102 .start = 0x00,
103 .end = 0x1f,
104 .name = "dma1",
105 .flags = IORESOURCE_BUSY
106 }, {
107 .start = 0x40,
108 .end = 0x5f,
109 .name = "timer",
110 .flags = IORESOURCE_BUSY
111 }, {
112 .start = 0x60,
113 .end = 0x6f,
114 .name = "keyboard",
115 .flags = IORESOURCE_BUSY
116 }, {
117 .start = 0x80,
118 .end = 0x8f,
119 .name = "dma page reg",
120 .flags = IORESOURCE_BUSY
121 }, {
122 .start = 0xc0,
123 .end = 0xdf,
124 .name = "dma2",
125 .flags = IORESOURCE_BUSY
126 }, {
127 .start = 0xcfc,
128 .end = 0xcff,
129 .name = "PCI config data",
130 .flags = IORESOURCE_BUSY
131 }
132};
133
134static struct resource sni_mem_resource = {
135 .start = 0x10000000UL,
136 .end = 0xffffffffUL,
137 .name = "PCIMT PCI MEM",
138 .flags = IORESOURCE_MEM
139};
140
141/*
142 * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used
143 * for other purposes. Be paranoid and allocate all of the before the PCI
144 * code gets a chance to to map anything else there ...
145 *
146 * This leaves the following areas available:
147 *
148 * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory
149 * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory
150 * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory
151 * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory
152 * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory
153 */
154static struct resource pcimt_mem_resources[] = {
155 {
156 .start = 0x100a0000,
157 .end = 0x100bffff,
158 .name = "Video RAM area",
159 .flags = IORESOURCE_BUSY
160 }, {
161 .start = 0x100c0000,
162 .end = 0x100fffff,
163 .name = "ISA Reserved",
164 .flags = IORESOURCE_BUSY
165 }, {
166 .start = 0x14000000,
167 .end = 0x17bfffff,
168 .name = "PCI IO",
169 .flags = IORESOURCE_BUSY
170 }, {
171 .start = 0x17c00000,
172 .end = 0x17ffffff,
173 .name = "Cache Replacement Area",
174 .flags = IORESOURCE_BUSY
175 }, {
176 .start = 0x1a000000,
177 .end = 0x1a000003,
178 .name = "PCI INT Acknowledge",
179 .flags = IORESOURCE_BUSY
180 }, {
181 .start = 0x1fc00000,
182 .end = 0x1fc7ffff,
183 .name = "Boot PROM",
184 .flags = IORESOURCE_BUSY
185 }, {
186 .start = 0x1fc80000,
187 .end = 0x1fcfffff,
188 .name = "Diag PROM",
189 .flags = IORESOURCE_BUSY
190 }, {
191 .start = 0x1fd00000,
192 .end = 0x1fdfffff,
193 .name = "X-Bus",
194 .flags = IORESOURCE_BUSY
195 }, {
196 .start = 0x1fe00000,
197 .end = 0x1fefffff,
198 .name = "BIOS map",
199 .flags = IORESOURCE_BUSY
200 }, {
201 .start = 0x1ff00000,
202 .end = 0x1ff7ffff,
203 .name = "NVRAM / EEPROM",
204 .flags = IORESOURCE_BUSY
205 }, {
206 .start = 0x1fff0000,
207 .end = 0x1fffefff,
208 .name = "ASIC PCI",
209 .flags = IORESOURCE_BUSY
210 }, {
211 .start = 0x1ffff000,
212 .end = 0x1fffffff,
213 .name = "MP Agent",
214 .flags = IORESOURCE_BUSY
215 }, {
216 .start = 0x20000000,
217 .end = 0x9fffffff,
218 .name = "Main Memory",
219 .flags = IORESOURCE_BUSY
220 }
221};
222
223static void __init sni_resource_init(void)
224{
225 int i;
226
227 /* request I/O space for devices used on all i[345]86 PCs */
228 for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++)
229 request_resource(&ioport_resource, pcimt_io_resources + i);
230
231 /* request mem space for pcimt-specific devices */
232 for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++)
233 request_resource(&sni_mem_resource, pcimt_mem_resources + i);
234
235 ioport_resource.end = sni_io_resource.end;
236}
237
238extern struct pci_ops sni_pci_ops;
239
240static struct pci_controller sni_controller = {
241 .pci_ops = &sni_pci_ops,
242 .mem_resource = &sni_mem_resource,
243 .mem_offset = 0x10000000UL,
244 .io_resource = &sni_io_resource,
245 .io_offset = 0x00000000UL
246};
247
248static inline void sni_pcimt_time_init(void)
249{
250 rtc_mips_get_time = mc146818_get_cmos_time;
251 rtc_mips_set_time = mc146818_set_rtc_mmss;
252}
253 51
254void __init plat_mem_setup(void) 52void __init plat_mem_setup(void)
255{ 53{
256 sni_pcimt_detect();
257 sni_pcimt_sc_init();
258 sni_pcimt_time_init();
259
260 set_io_port_base(SNI_PORT_BASE); 54 set_io_port_base(SNI_PORT_BASE);
261 ioport_resource.end = sni_io_resource.end; 55// ioport_resource.end = sni_io_resource.end;
262 56
263 /* 57 /*
264 * Setup (E)ISA I/O memory access stuff 58 * Setup (E)ISA I/O memory access stuff
@@ -268,15 +62,33 @@ void __init plat_mem_setup(void)
268 EISA_bus = 1; 62 EISA_bus = 1;
269#endif 63#endif
270 64
271 sni_resource_init(); 65 switch (sni_brd_type) {
66 case SNI_BRD_10:
67 case SNI_BRD_10NEW:
68 case SNI_BRD_TOWER_OASIC:
69 case SNI_BRD_MINITOWER:
70 sni_a20r_init();
71 break;
72
73 case SNI_BRD_PCI_TOWER:
74 case SNI_BRD_PCI_TOWER_CPLUS:
75 sni_pcit_init();
76 break;
77
78 case SNI_BRD_RM200:
79 sni_rm200_init();
80 break;
81
82 case SNI_BRD_PCI_MTOWER:
83 case SNI_BRD_PCI_DESKTOP:
84 case SNI_BRD_PCI_MTOWER_CPLUS:
85 sni_pcimt_init();
86 break;
87 }
272 88
273 _machine_restart = sni_machine_restart; 89 _machine_restart = sni_machine_restart;
274 _machine_halt = sni_machine_halt; 90 _machine_halt = sni_machine_halt;
275 pm_power_off = sni_machine_power_off; 91 pm_power_off = sni_machine_power_off;
276 92
277 sni_display_setup(); 93 sni_display_setup();
278
279#ifdef CONFIG_PCI
280 register_pci_controller(&sni_controller);
281#endif
282} 94}
diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c
index 1213d166f22e..6a44bbf0b732 100644
--- a/arch/mips/sni/sniprom.c
+++ b/arch/mips/sni/sniprom.c
@@ -12,6 +12,7 @@
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/string.h> 14#include <linux/string.h>
15#include <linux/console.h>
15 16
16#include <asm/addrspace.h> 17#include <asm/addrspace.h>
17#include <asm/sni.h> 18#include <asm/sni.h>
@@ -31,7 +32,7 @@
31#define PROM_ENTRY(x) (PROM_VEC + (x)) 32#define PROM_ENTRY(x) (PROM_VEC + (x))
32 33
33 34
34#undef DEBUG 35#define DEBUG
35#ifdef DEBUG 36#ifdef DEBUG
36#define DBG_PRINTF(x...) prom_printf(x) 37#define DBG_PRINTF(x...) prom_printf(x)
37#else 38#else
@@ -93,14 +94,14 @@ static void sni_idprom_dump(void)
93{ 94{
94 int i; 95 int i;
95 96
96 prom_printf("SNI IDProm dump (first 128byte):\n"); 97 prom_printf("SNI IDProm dump:\n");
97 for(i=0;i<128;i++) { 98 for (i = 0; i < 256; i++) {
98 if (i%16 == 0) 99 if (i%16 == 0)
99 prom_printf("%04x ", i); 100 prom_printf("%04x ", i);
100 101
101 prom_printf("%02x ", *(unsigned char *) (SNI_IDPROM_BASE+i)); 102 prom_printf("%02x ", *(unsigned char *) (SNI_IDPROM_BASE + i));
102 103
103 if (i%16 == 15) 104 if (i % 16 == 15)
104 prom_printf("\n"); 105 prom_printf("\n");
105 } 106 }
106} 107}
@@ -118,7 +119,7 @@ static void sni_mem_init(void )
118 } memconf[8]; 119 } memconf[8];
119 120
120 /* MemSIZE from prom in 16MByte chunks */ 121 /* MemSIZE from prom in 16MByte chunks */
121 memsize=*((unsigned char *) SNI_IDPROM_MEMSIZE) * 16; 122 memsize = *((unsigned char *) SNI_IDPROM_MEMSIZE) * 16;
122 123
123 DBG_PRINTF("IDProm memsize: %lu MByte\n", memsize); 124 DBG_PRINTF("IDProm memsize: %lu MByte\n", memsize);
124 125
@@ -126,26 +127,134 @@ static void sni_mem_init(void )
126 __prom_get_memconf(&memconf); 127 __prom_get_memconf(&memconf);
127 128
128 DBG_PRINTF("prom_get_mem_conf memory configuration:\n"); 129 DBG_PRINTF("prom_get_mem_conf memory configuration:\n");
129 for(i=0;i<8 && memconf[i].size;i++) { 130 for (i = 0;i < 8 && memconf[i].size; i++) {
130 prom_printf("Bank%d: %08x @ %08x\n", i, 131 if (sni_brd_type == SNI_BRD_PCI_TOWER ||
132 sni_brd_type == SNI_BRD_PCI_TOWER_CPLUS) {
133 if (memconf[i].base >= 0x20000000 &&
134 memconf[i].base < 0x30000000) {
135 memconf[i].base -= 0x20000000;
136 }
137 }
138 DBG_PRINTF("Bank%d: %08x @ %08x\n", i,
131 memconf[i].size, memconf[i].base); 139 memconf[i].size, memconf[i].base);
132 add_memory_region(memconf[i].base, memconf[i].size, BOOT_MEM_RAM); 140 add_memory_region(memconf[i].base, memconf[i].size, BOOT_MEM_RAM);
133 } 141 }
134} 142}
135 143
144static void __init sni_console_setup(void)
145{
146 char *ctype;
147 char *cdev;
148 char *baud;
149 int port;
150 static char options[8];
151
152 cdev = prom_getenv ("console_dev");
153 if (strncmp (cdev, "tty", 3) == 0) {
154 ctype = prom_getenv ("console");
155 switch (*ctype) {
156 default:
157 case 'l':
158 port = 0;
159 baud = prom_getenv("lbaud");
160 break;
161 case 'r':
162 port = 1;
163 baud = prom_getenv("rbaud");
164 break;
165 }
166 if (baud)
167 strcpy(options, baud);
168 add_preferred_console("ttyS", port, baud ? options : NULL);
169 }
170}
171
136void __init prom_init(void) 172void __init prom_init(void)
137{ 173{
138 int argc = fw_arg0; 174 int argc = fw_arg0;
139 char **argv = (void *)fw_arg1; 175 char **argv = (void *)fw_arg1;
140 unsigned int sni_brd_type = *(unsigned char *) SNI_IDPROM_BRDTYPE;
141 int i; 176 int i;
177 int cputype;
142 178
143 DBG_PRINTF("Found SNI brdtype %02x\n", sni_brd_type); 179 sni_brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE;
180 cputype = *(unsigned char *)SNI_IDPROM_CPUTYPE;
181 switch (sni_brd_type) {
182 case SNI_BRD_TOWER_OASIC:
183 switch (cputype) {
184 case SNI_CPU_M8030:
185 systype = "RM400-330";
186 break;
187 case SNI_CPU_M8031:
188 systype = "RM400-430";
189 break;
190 case SNI_CPU_M8037:
191 systype = "RM400-530";
192 break;
193 case SNI_CPU_M8034:
194 systype = "RM400-730";
195 break;
196 default:
197 systype = "RM400-xxx";
198 break;
199 }
200 break;
201 case SNI_BRD_MINITOWER:
202 switch (cputype) {
203 case SNI_CPU_M8021:
204 case SNI_CPU_M8043:
205 systype = "RM400-120";
206 break;
207 case SNI_CPU_M8040:
208 systype = "RM400-220";
209 break;
210 case SNI_CPU_M8053:
211 systype = "RM400-225";
212 break;
213 case SNI_CPU_M8050:
214 systype = "RM400-420";
215 break;
216 default:
217 systype = "RM400-xxx";
218 break;
219 }
220 break;
221 case SNI_BRD_PCI_TOWER:
222 systype = "RM400-Cxx";
223 break;
224 case SNI_BRD_RM200:
225 systype = "RM200-xxx";
226 break;
227 case SNI_BRD_PCI_MTOWER:
228 systype = "RM300-Cxx";
229 break;
230 case SNI_BRD_PCI_DESKTOP:
231 switch (read_c0_prid() & 0xff00) {
232 case PRID_IMP_R4600:
233 case PRID_IMP_R4700:
234 systype = "RM200-C20";
235 break;
236 case PRID_IMP_R5000:
237 systype = "RM200-C40";
238 break;
239 default:
240 systype = "RM200-Cxx";
241 break;
242 }
243 break;
244 case SNI_BRD_PCI_TOWER_CPLUS:
245 systype = "RM400-Exx";
246 break;
247 case SNI_BRD_PCI_MTOWER_CPLUS:
248 systype = "RM300-Exx";
249 break;
250 }
251 DBG_PRINTF("Found SNI brdtype %02x name %s\n", sni_brd_type,systype);
144 252
145#ifdef DEBUG 253#ifdef DEBUG
146 sni_idprom_dump(); 254 sni_idprom_dump();
147#endif 255#endif
148 sni_mem_init(); 256 sni_mem_init();
257 sni_console_setup();
149 258
150 /* copy prom cmdline parameters to kernel cmdline */ 259 /* copy prom cmdline parameters to kernel cmdline */
151 for (i = 1; i < argc; i++) { 260 for (i = 1; i < argc; i++) {
diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c
new file mode 100644
index 000000000000..20028fc7757e
--- /dev/null
+++ b/arch/mips/sni/time.c
@@ -0,0 +1,148 @@
1#include <linux/types.h>
2#include <linux/interrupt.h>
3#include <linux/time.h>
4
5#include <asm/sni.h>
6#include <asm/time.h>
7
8#define SNI_CLOCK_TICK_RATE 3686400
9#define SNI_COUNTER2_DIV 64
10#define SNI_COUNTER0_DIV ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ)
11
12static void sni_a20r_timer_ack(void)
13{
14 *(volatile u8 *)A20R_PT_TIM0_ACK = 0x0; wmb();
15}
16
17/*
18 * a20r platform uses 2 counters to divide the input frequency.
19 * Counter 2 output is connected to Counter 0 & 1 input.
20 */
21static void __init sni_a20r_timer_setup(struct irqaction *irq)
22{
23 *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; wmb();
24 *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = (SNI_COUNTER0_DIV) & 0xff; wmb();
25 *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = (SNI_COUNTER0_DIV >> 8) & 0xff; wmb();
26
27 *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; wmb();
28 *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = (SNI_COUNTER2_DIV) & 0xff; wmb();
29 *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = (SNI_COUNTER2_DIV >> 8) & 0xff; wmb();
30
31 setup_irq(SNI_A20R_IRQ_TIMER, irq);
32 mips_timer_ack = sni_a20r_timer_ack;
33}
34
35#define SNI_8254_TICK_RATE 1193182UL
36
37#define SNI_8254_TCSAMP_COUNTER ((SNI_8254_TICK_RATE / HZ) + 255)
38
39static __init unsigned long dosample(void)
40{
41 u32 ct0, ct1;
42 volatile u8 msb, lsb;
43
44 /* Start the counter. */
45 outb_p (0x34, 0x43);
46 outb_p(SNI_8254_TCSAMP_COUNTER & 0xff, 0x40);
47 outb (SNI_8254_TCSAMP_COUNTER >> 8, 0x40);
48
49 /* Get initial counter invariant */
50 ct0 = read_c0_count();
51
52 /* Latch and spin until top byte of counter0 is zero */
53 do {
54 outb (0x00, 0x43);
55 lsb = inb (0x40);
56 msb = inb (0x40);
57 ct1 = read_c0_count();
58 } while (msb);
59
60 /* Stop the counter. */
61 outb (0x38, 0x43);
62 /*
63 * Return the difference, this is how far the r4k counter increments
64 * for every 1/HZ seconds. We round off the nearest 1 MHz of master
65 * clock (= 1000000 / HZ / 2).
66 */
67 /*return (ct1 - ct0 + (500000/HZ/2)) / (500000/HZ) * (500000/HZ);*/
68 return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
69}
70
71/*
72 * Here we need to calibrate the cycle counter to at least be close.
73 */
74__init void sni_cpu_time_init(void)
75{
76 unsigned long r4k_ticks[3];
77 unsigned long r4k_tick;
78
79 /*
80 * Figure out the r4k offset, the algorithm is very simple and works in
81 * _all_ cases as long as the 8254 counter register itself works ok (as
82 * an interrupt driving timer it does not because of bug, this is why
83 * we are using the onchip r4k counter/compare register to serve this
84 * purpose, but for r4k_offset calculation it will work ok for us).
85 * There are other very complicated ways of performing this calculation
86 * but this one works just fine so I am not going to futz around. ;-)
87 */
88 printk(KERN_INFO "Calibrating system timer... ");
89 dosample(); /* Prime cache. */
90 dosample(); /* Prime cache. */
91 /* Zero is NOT an option. */
92 do {
93 r4k_ticks[0] = dosample();
94 } while (!r4k_ticks[0]);
95 do {
96 r4k_ticks[1] = dosample();
97 } while (!r4k_ticks[1]);
98
99 if (r4k_ticks[0] != r4k_ticks[1]) {
100 printk("warning: timer counts differ, retrying... ");
101 r4k_ticks[2] = dosample();
102 if (r4k_ticks[2] == r4k_ticks[0]
103 || r4k_ticks[2] == r4k_ticks[1])
104 r4k_tick = r4k_ticks[2];
105 else {
106 printk("disagreement, using average... ");
107 r4k_tick = (r4k_ticks[0] + r4k_ticks[1]
108 + r4k_ticks[2]) / 3;
109 }
110 } else
111 r4k_tick = r4k_ticks[0];
112
113 printk("%d [%d.%04d MHz CPU]\n", (int) r4k_tick,
114 (int) (r4k_tick / (500000 / HZ)),
115 (int) (r4k_tick % (500000 / HZ)));
116
117 mips_hpt_frequency = r4k_tick * HZ;
118}
119
120/*
121 * R4k counter based timer interrupt. Works on RM200-225 and possibly
122 * others but not on RM400
123 */
124static void __init sni_cpu_timer_setup(struct irqaction *irq)
125{
126 setup_irq(SNI_MIPS_IRQ_CPU_TIMER, irq);
127}
128
129void __init plat_timer_setup(struct irqaction *irq)
130{
131 switch (sni_brd_type) {
132 case SNI_BRD_10:
133 case SNI_BRD_10NEW:
134 case SNI_BRD_TOWER_OASIC:
135 case SNI_BRD_MINITOWER:
136 sni_a20r_timer_setup (irq);
137 break;
138
139 case SNI_BRD_PCI_TOWER:
140 case SNI_BRD_RM200:
141 case SNI_BRD_PCI_MTOWER:
142 case SNI_BRD_PCI_DESKTOP:
143 case SNI_BRD_PCI_TOWER_CPLUS:
144 case SNI_BRD_PCI_MTOWER_CPLUS:
145 sni_cpu_timer_setup (irq);
146 break;
147 }
148}