diff options
author | Thomas Bogendoerfer <tsbogend@alpha.franken.de> | 2006-12-28 12:22:32 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-02-18 16:31:37 -0500 |
commit | c066a32a890c50ce59e91f8cea8eb5fd8d5821b9 (patch) | |
tree | d129af235d11d44c649f0743bc38535c3a229e41 /arch/mips | |
parent | 5759906ca9e5201c3fd40d61c861ec1e441d3a24 (diff) |
[MIPS] Support for several more SNI RM models.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/Kconfig | 5 | ||||
-rw-r--r-- | arch/mips/pci/fixup-sni.c | 66 | ||||
-rw-r--r-- | arch/mips/pci/ops-sni.c | 77 | ||||
-rw-r--r-- | arch/mips/sni/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/sni/a20r.c | 227 | ||||
-rw-r--r-- | arch/mips/sni/ds1216.c | 81 | ||||
-rw-r--r-- | arch/mips/sni/irq.c | 188 | ||||
-rw-r--r-- | arch/mips/sni/pcimt.c | 390 | ||||
-rw-r--r-- | arch/mips/sni/pcit.c | 351 | ||||
-rw-r--r-- | arch/mips/sni/reset.c | 9 | ||||
-rw-r--r-- | arch/mips/sni/rm200.c | 186 | ||||
-rw-r--r-- | arch/mips/sni/setup.c | 242 | ||||
-rw-r--r-- | arch/mips/sni/sniprom.c | 129 | ||||
-rw-r--r-- | arch/mips/sni/time.c | 148 |
14 files changed, 1719 insertions, 382 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a92ce6bd7cf1..46fa5ca9f5ac 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -726,15 +726,16 @@ config SNI_RM | |||
726 | select BOOT_ELF32 | 726 | select BOOT_ELF32 |
727 | select DMA_NONCOHERENT | 727 | select DMA_NONCOHERENT |
728 | select GENERIC_ISA_DMA | 728 | select GENERIC_ISA_DMA |
729 | select HAVE_STD_PC_SERIAL_PORT | ||
730 | select HW_HAS_EISA | 729 | select HW_HAS_EISA |
731 | select HW_HAS_PCI | 730 | select HW_HAS_PCI |
731 | select IRQ_CPU | ||
732 | select I8253 | 732 | select I8253 |
733 | select I8259 | 733 | select I8259 |
734 | select ISA | 734 | select ISA |
735 | select SWAP_IO_SPACE if CPU_BIG_ENDIAN | 735 | select SWAP_IO_SPACE if CPU_BIG_ENDIAN |
736 | select SYS_HAS_CPU_R4X00 | 736 | select SYS_HAS_CPU_R4X00 |
737 | select SYS_HAS_CPU_R5000 | 737 | select SYS_HAS_CPU_R5000 |
738 | select SYS_HAS_CPU_R10000 | ||
738 | select R5000_CPU_SCACHE | 739 | select R5000_CPU_SCACHE |
739 | select SYS_SUPPORTS_32BIT_KERNEL | 740 | select SYS_SUPPORTS_32BIT_KERNEL |
740 | select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL | 741 | select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL |
@@ -1066,7 +1067,7 @@ config BOOT_ELF32 | |||
1066 | 1067 | ||
1067 | config MIPS_L1_CACHE_SHIFT | 1068 | config MIPS_L1_CACHE_SHIFT |
1068 | int | 1069 | int |
1069 | default "4" if MACH_DECSTATION | 1070 | default "4" if MACH_DECSTATION || SNI_RM |
1070 | default "7" if SGI_IP27 | 1071 | default "7" if SGI_IP27 |
1071 | default "5" | 1072 | default "5" |
1072 | 1073 | ||
diff --git a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c index a176f2ca8656..0c9a4732d455 100644 --- a/arch/mips/pci/fixup-sni.c +++ b/arch/mips/pci/fixup-sni.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <asm/sni.h> | 15 | #include <asm/sni.h> |
16 | 16 | ||
17 | /* | 17 | /* |
18 | * Shortcuts ... | 18 | * PCIMT Shortcuts ... |
19 | */ | 19 | */ |
20 | #define SCSI PCIMT_IRQ_SCSI | 20 | #define SCSI PCIMT_IRQ_SCSI |
21 | #define ETH PCIMT_IRQ_ETHERNET | 21 | #define ETH PCIMT_IRQ_ETHERNET |
@@ -67,6 +67,50 @@ static char irq_tab_rm300d[8][5] __initdata = { | |||
67 | { 0, INTD, INTA, INTB, INTC }, /* Slot 4 */ | 67 | { 0, INTD, INTA, INTB, INTC }, /* Slot 4 */ |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static char irq_tab_rm300e[5][5] __initdata = { | ||
71 | /* INTA INTB INTC INTD */ | ||
72 | { 0, 0, 0, 0, 0 }, /* HOST bridge */ | ||
73 | { SCSI, SCSI, SCSI, SCSI, SCSI }, /* SCSI */ | ||
74 | { 0, INTC, INTD, INTA, INTB }, /* Bridge/i960 */ | ||
75 | { 0, INTD, INTA, INTB, INTC }, /* Slot 1 */ | ||
76 | { 0, INTA, INTB, INTC, INTD }, /* Slot 2 */ | ||
77 | }; | ||
78 | #undef SCSI | ||
79 | #undef ETH | ||
80 | #undef INTA | ||
81 | #undef INTB | ||
82 | #undef INTC | ||
83 | #undef INTD | ||
84 | |||
85 | |||
86 | /* | ||
87 | * PCIT Shortcuts ... | ||
88 | */ | ||
89 | #define SCSI0 PCIT_IRQ_SCSI0 | ||
90 | #define SCSI1 PCIT_IRQ_SCSI1 | ||
91 | #define ETH PCIT_IRQ_ETHERNET | ||
92 | #define INTA PCIT_IRQ_INTA | ||
93 | #define INTB PCIT_IRQ_INTB | ||
94 | #define INTC PCIT_IRQ_INTC | ||
95 | #define INTD PCIT_IRQ_INTD | ||
96 | |||
97 | static char irq_tab_pcit[13][5] __initdata = { | ||
98 | /* INTA INTB INTC INTD */ | ||
99 | { 0, 0, 0, 0, 0 }, /* HOST bridge */ | ||
100 | { SCSI0, SCSI0, SCSI0, SCSI0, SCSI0 }, /* SCSI */ | ||
101 | { SCSI1, SCSI1, SCSI1, SCSI1, SCSI1 }, /* SCSI */ | ||
102 | { ETH, ETH, ETH, ETH, ETH }, /* Ethernet */ | ||
103 | { 0, INTA, INTB, INTC, INTD }, /* PCI-PCI bridge */ | ||
104 | { 0, 0, 0, 0, 0 }, /* Unused */ | ||
105 | { 0, 0, 0, 0, 0 }, /* Unused */ | ||
106 | { 0, 0, 0, 0, 0 }, /* Unused */ | ||
107 | { 0, INTA, INTB, INTC, INTD }, /* Slot 1 */ | ||
108 | { 0, INTB, INTC, INTD, INTA }, /* Slot 2 */ | ||
109 | { 0, INTC, INTD, INTA, INTB }, /* Slot 3 */ | ||
110 | { 0, INTD, INTA, INTB, INTC }, /* Slot 4 */ | ||
111 | { 0, INTA, INTB, INTC, INTD }, /* Slot 5 */ | ||
112 | }; | ||
113 | |||
70 | static inline int is_rm300_revd(void) | 114 | static inline int is_rm300_revd(void) |
71 | { | 115 | { |
72 | unsigned char csmsr = *(volatile unsigned char *)PCIMT_CSMSR; | 116 | unsigned char csmsr = *(volatile unsigned char *)PCIMT_CSMSR; |
@@ -76,10 +120,24 @@ static inline int is_rm300_revd(void) | |||
76 | 120 | ||
77 | int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | 121 | int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) |
78 | { | 122 | { |
79 | if (is_rm300_revd()) | 123 | switch (sni_brd_type) { |
80 | return irq_tab_rm300d[slot][pin]; | 124 | case SNI_BRD_PCI_TOWER: |
125 | case SNI_BRD_PCI_TOWER_CPLUS: | ||
126 | return irq_tab_pcit[slot][pin]; | ||
127 | |||
128 | case SNI_BRD_PCI_MTOWER: | ||
129 | if (is_rm300_revd()) | ||
130 | return irq_tab_rm300d[slot][pin]; | ||
131 | /* fall through */ | ||
81 | 132 | ||
82 | return irq_tab_rm200[slot][pin]; | 133 | case SNI_BRD_PCI_DESKTOP: |
134 | return irq_tab_rm200[slot][pin]; | ||
135 | |||
136 | case SNI_BRD_PCI_MTOWER_CPLUS: | ||
137 | return irq_tab_rm300e[slot][pin]; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
83 | } | 141 | } |
84 | 142 | ||
85 | /* Do platform specific device initialization at pci_enable_device() time */ | 143 | /* Do platform specific device initialization at pci_enable_device() time */ |
diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c index 2b0ccd6d9dcd..fa2d2c60f797 100644 --- a/arch/mips/pci/ops-sni.c +++ b/arch/mips/pci/ops-sni.c | |||
@@ -83,7 +83,82 @@ static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg, | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | struct pci_ops sni_pci_ops = { | 86 | struct pci_ops sni_pcimt_ops = { |
87 | .read = pcimt_read, | 87 | .read = pcimt_read, |
88 | .write = pcimt_write, | 88 | .write = pcimt_write, |
89 | }; | 89 | }; |
90 | |||
91 | static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg) | ||
92 | { | ||
93 | if ((devfn > 255) || (reg > 255) || (busno > 255)) | ||
94 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
95 | |||
96 | outl ((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8); | ||
97 | return PCIBIOS_SUCCESSFUL; | ||
98 | } | ||
99 | |||
100 | static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg, | ||
101 | int size, u32 * val) | ||
102 | { | ||
103 | int res; | ||
104 | |||
105 | /* | ||
106 | * on bus 0 we need to check, whether there is a device answering | ||
107 | * for the devfn by doing a config write and checking the result. If | ||
108 | * we don't do it, we will get a data bus error | ||
109 | */ | ||
110 | if (bus->number == 0) { | ||
111 | pcit_set_config_address (0, 0, 0x68); | ||
112 | outl (inl (0xcfc) | 0xc0000000, 0xcfc); | ||
113 | if ((res = pcit_set_config_address(0, devfn, 0))) | ||
114 | return res; | ||
115 | outl (0xffffffff, 0xcfc); | ||
116 | pcit_set_config_address (0, 0, 0x68); | ||
117 | if (inl(0xcfc) & 0x100000) | ||
118 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
119 | } | ||
120 | if ((res = pcit_set_config_address(bus->number, devfn, reg))) | ||
121 | return res; | ||
122 | |||
123 | switch (size) { | ||
124 | case 1: | ||
125 | *val = inb(PCIMT_CONFIG_DATA + (reg & 3)); | ||
126 | break; | ||
127 | case 2: | ||
128 | *val = inw(PCIMT_CONFIG_DATA + (reg & 2)); | ||
129 | break; | ||
130 | case 4: | ||
131 | *val = inl(PCIMT_CONFIG_DATA); | ||
132 | break; | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg, | ||
138 | int size, u32 val) | ||
139 | { | ||
140 | int res; | ||
141 | |||
142 | if ((res = pcit_set_config_address(bus->number, devfn, reg))) | ||
143 | return res; | ||
144 | |||
145 | switch (size) { | ||
146 | case 1: | ||
147 | outb (val, PCIMT_CONFIG_DATA + (reg & 3)); | ||
148 | break; | ||
149 | case 2: | ||
150 | outw (val, PCIMT_CONFIG_DATA + (reg & 2)); | ||
151 | break; | ||
152 | case 4: | ||
153 | outl (val, PCIMT_CONFIG_DATA); | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | |||
161 | struct pci_ops sni_pcit_ops = { | ||
162 | .read = pcit_read, | ||
163 | .write = pcit_write, | ||
164 | }; | ||
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 | ||
5 | obj-y += irq.o pcimt_scache.o reset.o setup.o | 5 | obj-y += irq.o reset.o setup.o ds1216.o a20r.o rm200.o pcimt.o pcit.o time.o |
6 | obj-$(CONFIG_CPU_BIG_ENDIAN) += sniprom.o | 6 | obj-$(CONFIG_CPU_BIG_ENDIAN) += sniprom.o |
7 | 7 | ||
8 | EXTRA_AFLAGS := $(CFLAGS) | 8 | EXTRA_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 | |||
29 | static struct plat_serial8250_port a20r_data[] = { | ||
30 | PORT(0x3f8, 4), | ||
31 | PORT(0x2f8, 3), | ||
32 | { }, | ||
33 | }; | ||
34 | |||
35 | static struct platform_device a20r_serial8250_device = { | ||
36 | .name = "serial8250", | ||
37 | .id = PLAT8250_DEV_PLATFORM, | ||
38 | .dev = { | ||
39 | .platform_data = a20r_data, | ||
40 | }, | ||
41 | }; | ||
42 | |||
43 | static 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 | |||
69 | static 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 | |||
75 | static 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 | |||
88 | static 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 | |||
94 | static 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 | |||
107 | static struct platform_device sc26xx_pdev = { | ||
108 | .name = "SC26xx", | ||
109 | .num_resources = ARRAY_SIZE(sc26xx_rsrc), | ||
110 | .resource = sc26xx_rsrc | ||
111 | }; | ||
112 | |||
113 | static 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 | |||
148 | static 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 | |||
154 | static 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 | |||
160 | static 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 | |||
168 | static 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 | */ | ||
180 | static 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 | |||
195 | void __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 | |||
206 | void 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 | |||
212 | static 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 | |||
227 | device_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 | |||
7 | volatile 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 | */ | ||
14 | static 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 | |||
31 | static 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 | |||
51 | unsigned 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 | |||
77 | int 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 | ||
19 | static void enable_pciasic_irq(unsigned int irq) | 22 | void (*sni_hwint)(void); |
20 | { | ||
21 | unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2); | ||
22 | |||
23 | *(volatile u8 *) PCIMT_IRQSEL |= mask; | ||
24 | } | ||
25 | |||
26 | void 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 | ||
33 | static void end_pciasic_irq(unsigned int irq) | 24 | asmlinkage void plat_irq_dispatch(void) |
34 | { | ||
35 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
36 | enable_pciasic_irq(irq); | ||
37 | } | ||
38 | |||
39 | static 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 | */ | ||
52 | static 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. */ | ||
58 | static 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 */ | ||
65 | static void pciasic_hwint5(void) | ||
66 | { | ||
67 | panic("hwint5 and no handler yet"); | ||
68 | } | ||
69 | |||
70 | static 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 | */ | ||
86 | static 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, | 30 | static irqreturn_t sni_isa_irq_handler(int dummy, void *p) |
115 | */ | ||
116 | static 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 | */ | ||
131 | static 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 | |||
138 | asmlinkage 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 | ||
159 | void __init init_pciasic(void) | 42 | struct 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 | */ |
170 | void __init arch_init_irq(void) | 53 | void __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 | |||
26 | static 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 | */ | ||
51 | static 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 | |||
79 | static struct plat_serial8250_port pcimt_data[] = { | ||
80 | PORT(0x3f8, 4), | ||
81 | PORT(0x2f8, 3), | ||
82 | { }, | ||
83 | }; | ||
84 | |||
85 | static struct platform_device pcimt_serial8250_device = { | ||
86 | .name = "serial8250", | ||
87 | .id = PLAT8250_DEV_PLATFORM, | ||
88 | .dev = { | ||
89 | .platform_data = pcimt_data, | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | static struct resource sni_io_resource = { | ||
94 | .start = 0x00001000UL, | ||
95 | .end = 0x03bfffffUL, | ||
96 | .name = "PCIMT IO MEM", | ||
97 | .flags = IORESOURCE_IO, | ||
98 | }; | ||
99 | |||
100 | static 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 | |||
134 | static 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 | */ | ||
154 | static 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 | |||
223 | static 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 | |||
238 | extern struct pci_ops sni_pcimt_ops; | ||
239 | |||
240 | static 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 | |||
248 | static 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 | |||
255 | void 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 | |||
262 | static 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 | |||
268 | static 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 | */ | ||
281 | static 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 | */ | ||
291 | static 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 | */ | ||
321 | static 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 | |||
334 | static 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 | |||
351 | void __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 | |||
364 | void 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 | |||
377 | static 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 | |||
390 | device_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 | |||
31 | static struct plat_serial8250_port pcit_data[] = { | ||
32 | PORT(0x3f8, 0), | ||
33 | PORT(0x2f8, 3), | ||
34 | { }, | ||
35 | }; | ||
36 | |||
37 | static struct platform_device pcit_serial8250_device = { | ||
38 | .name = "serial8250", | ||
39 | .id = PLAT8250_DEV_PLATFORM, | ||
40 | .dev = { | ||
41 | .platform_data = pcit_data, | ||
42 | }, | ||
43 | }; | ||
44 | |||
45 | static 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 | |||
53 | static 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 | |||
61 | static struct resource sni_io_resource = { | ||
62 | .start = 0x00001000UL, | ||
63 | .end = 0x03bfffffUL, | ||
64 | .name = "PCIT IO MEM", | ||
65 | .flags = IORESOURCE_IO, | ||
66 | }; | ||
67 | |||
68 | static 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 | |||
102 | static 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 | */ | ||
122 | static 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 | |||
191 | static 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 | |||
207 | extern struct pci_ops sni_pcit_ops; | ||
208 | |||
209 | static 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 | |||
217 | static 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 | |||
224 | void 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 | |||
231 | void end_pcit_irq(unsigned int irq) | ||
232 | { | ||
233 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
234 | enable_pcit_irq(irq); | ||
235 | } | ||
236 | |||
237 | static 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 | |||
246 | static 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 | |||
259 | static 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 | |||
272 | static 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 | |||
286 | static 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 | |||
300 | void __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 | |||
313 | void __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 | |||
326 | void 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 | |||
337 | static 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 | |||
351 | device_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 | */ |
16 | static inline void | 16 | static inline void kb_wait(void) |
17 | kb_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 | |||
30 | static struct plat_serial8250_port rm200_data[] = { | ||
31 | PORT(0x3f8, 4), | ||
32 | PORT(0x2f8, 3), | ||
33 | { }, | ||
34 | }; | ||
35 | |||
36 | static struct platform_device rm200_serial8250_device = { | ||
37 | .name = "serial8250", | ||
38 | .id = PLAT8250_DEV_PLATFORM, | ||
39 | .dev = { | ||
40 | .platform_data = rm200_data, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static 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 | |||
70 | static 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 | |||
76 | static 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 | |||
89 | static 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 | |||
95 | static 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 | |||
105 | device_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 | |||
114 | static 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 | |||
121 | void 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 | |||
128 | void end_rm200_irq(unsigned int irq) | ||
129 | { | ||
130 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
131 | enable_rm200_irq(irq); | ||
132 | } | ||
133 | |||
134 | static 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 | |||
143 | static 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 | |||
164 | void __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 | |||
179 | void 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> | 26 | unsigned int sni_brd_type; |
38 | 27 | ||
39 | extern void sni_machine_restart(char *command); | 28 | extern void sni_machine_restart(char *command); |
40 | extern void sni_machine_halt(void); | 29 | extern void sni_machine_halt(void); |
41 | extern void sni_machine_power_off(void); | 30 | extern void sni_machine_power_off(void); |
42 | 31 | ||
43 | void __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 | */ | ||
55 | static 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 | |||
74 | static void __init sni_display_setup(void) | 32 | static 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 | ||
93 | static struct resource sni_io_resource = { | ||
94 | .start = 0x00001000UL, | ||
95 | .end = 0x03bfffffUL, | ||
96 | .name = "PCIMT IO MEM", | ||
97 | .flags = IORESOURCE_IO, | ||
98 | }; | ||
99 | |||
100 | static 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 | |||
134 | static 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 | */ | ||
154 | static 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 | |||
223 | static 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 | |||
238 | extern struct pci_ops sni_pci_ops; | ||
239 | |||
240 | static 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 | |||
248 | static 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 | ||
254 | void __init plat_mem_setup(void) | 52 | void __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 | ||
144 | static 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 | |||
136 | void __init prom_init(void) | 172 | void __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 | |||
12 | static 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 | */ | ||
21 | static 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 | |||
39 | static __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 | */ | ||
124 | static void __init sni_cpu_timer_setup(struct irqaction *irq) | ||
125 | { | ||
126 | setup_irq(SNI_MIPS_IRQ_CPU_TIMER, irq); | ||
127 | } | ||
128 | |||
129 | void __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 | } | ||