aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-10-26 07:45:56 -0400
committerPaul Mackerras <paulus@samba.org>2005-10-26 07:45:56 -0400
commitbbd0abda9cc689a54df509aae00000bbb2a1a7d1 (patch)
treed04e8f196f65f5598300485e654e5e90a6160aa6 /arch
parent303d72a0006c65bb8d16199c75a26338ce723811 (diff)
powerpc: Merge 32-bit CHRP support.
SMP still needs more work but UP gets as far as starting userspace at least. This uses the 64-bit-style code for spinning up the cpus. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/kernel/head_32.S9
-rw-r--r--arch/powerpc/kernel/prom_init.c54
-rw-r--r--arch/powerpc/kernel/setup_32.c4
-rw-r--r--arch/powerpc/platforms/Makefile1
-rw-r--r--arch/powerpc/platforms/chrp/Makefile3
-rw-r--r--arch/powerpc/platforms/chrp/pci.c310
-rw-r--r--arch/powerpc/platforms/chrp/pegasos_eth.c101
-rw-r--r--arch/powerpc/platforms/chrp/setup.c523
-rw-r--r--arch/powerpc/platforms/chrp/smp.c94
-rw-r--r--arch/powerpc/platforms/chrp/time.c188
-rw-r--r--arch/powerpc/platforms/powermac/pic.c4
12 files changed, 1256 insertions, 37 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 964ded4a757f..9589d621edc5 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -339,7 +339,7 @@ config U3_DART
339 default n 339 default n
340 340
341config MPIC 341config MPIC
342 depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE 342 depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE || PPC_CHRP
343 bool 343 bool
344 default y 344 default y
345 345
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index cd51fe585fcd..f8673f7b2b2d 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -207,7 +207,7 @@ turn_on_mmu:
207 .globl __secondary_hold 207 .globl __secondary_hold
208__secondary_hold: 208__secondary_hold:
209 /* tell the master we're here */ 209 /* tell the master we're here */
210 stw r3,4(0) 210 stw r3,__secondary_hold_acknowledge@l(0)
211#ifdef CONFIG_SMP 211#ifdef CONFIG_SMP
212100: lwz r4,0(0) 212100: lwz r4,0(0)
213 /* wait until we're told to start */ 213 /* wait until we're told to start */
@@ -220,6 +220,13 @@ __secondary_hold:
220 b . 220 b .
221#endif /* CONFIG_SMP */ 221#endif /* CONFIG_SMP */
222 222
223 .globl __secondary_hold_spinloop
224__secondary_hold_spinloop:
225 .long 0
226 .globl __secondary_hold_acknowledge
227__secondary_hold_acknowledge:
228 .long -1
229
223/* 230/*
224 * Exception entry code. This code runs with address translation 231 * Exception entry code. This code runs with address translation
225 * turned off, i.e. using physical addresses. 232 * turned off, i.e. using physical addresses.
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 18d266d8935d..debe9734636e 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -1155,9 +1155,18 @@ static void __init prom_initialize_tce_table(void)
1155 * 1155 *
1156 * -- Cort 1156 * -- Cort
1157 */ 1157 */
1158extern void __secondary_hold(void);
1159extern unsigned long __secondary_hold_spinloop;
1160extern unsigned long __secondary_hold_acknowledge;
1161
1162/*
1163 * We want to reference the copy of __secondary_hold_* in the
1164 * 0 - 0x100 address range
1165 */
1166#define LOW_ADDR(x) (((unsigned long) &(x)) & 0xff)
1167
1158static void __init prom_hold_cpus(void) 1168static void __init prom_hold_cpus(void)
1159{ 1169{
1160#ifdef CONFIG_PPC64
1161 unsigned long i; 1170 unsigned long i;
1162 unsigned int reg; 1171 unsigned int reg;
1163 phandle node; 1172 phandle node;
@@ -1166,20 +1175,18 @@ static void __init prom_hold_cpus(void)
1166 unsigned int interrupt_server[MAX_CPU_THREADS]; 1175 unsigned int interrupt_server[MAX_CPU_THREADS];
1167 unsigned int cpu_threads, hw_cpu_num; 1176 unsigned int cpu_threads, hw_cpu_num;
1168 int propsize; 1177 int propsize;
1169 extern void __secondary_hold(void); 1178 struct prom_t *_prom = &RELOC(prom);
1170 extern unsigned long __secondary_hold_spinloop;
1171 extern unsigned long __secondary_hold_acknowledge;
1172 unsigned long *spinloop 1179 unsigned long *spinloop
1173 = (void *) __pa(&__secondary_hold_spinloop); 1180 = (void *) LOW_ADDR(__secondary_hold_spinloop);
1174 unsigned long *acknowledge 1181 unsigned long *acknowledge
1175 = (void *) __pa(&__secondary_hold_acknowledge); 1182 = (void *) LOW_ADDR(__secondary_hold_acknowledge);
1176#ifdef CONFIG_PPC64 1183#ifdef CONFIG_PPC64
1184 /* __secondary_hold is actually a descriptor, not the text address */
1177 unsigned long secondary_hold 1185 unsigned long secondary_hold
1178 = __pa(*PTRRELOC((unsigned long *)__secondary_hold)); 1186 = __pa(*PTRRELOC((unsigned long *)__secondary_hold));
1179#else 1187#else
1180 unsigned long secondary_hold = __pa(&__secondary_hold); 1188 unsigned long secondary_hold = LOW_ADDR(__secondary_hold);
1181#endif 1189#endif
1182 struct prom_t *_prom = &RELOC(prom);
1183 1190
1184 prom_debug("prom_hold_cpus: start...\n"); 1191 prom_debug("prom_hold_cpus: start...\n");
1185 prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); 1192 prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop);
@@ -1197,9 +1204,8 @@ static void __init prom_hold_cpus(void)
1197 *spinloop = 0; 1204 *spinloop = 0;
1198 1205
1199#ifdef CONFIG_HMT 1206#ifdef CONFIG_HMT
1200 for (i = 0; i < NR_CPUS; i++) { 1207 for (i = 0; i < NR_CPUS; i++)
1201 RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; 1208 RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
1202 }
1203#endif 1209#endif
1204 /* look for cpus */ 1210 /* look for cpus */
1205 for (node = 0; prom_next_node(&node); ) { 1211 for (node = 0; prom_next_node(&node); ) {
@@ -1250,34 +1256,22 @@ static void __init prom_hold_cpus(void)
1250 call_prom("start-cpu", 3, 0, node, 1256 call_prom("start-cpu", 3, 0, node,
1251 secondary_hold, reg); 1257 secondary_hold, reg);
1252 1258
1253 for ( i = 0 ; (i < 100000000) && 1259 for (i = 0; (i < 100000000) &&
1254 (*acknowledge == ((unsigned long)-1)); i++ ) 1260 (*acknowledge == ((unsigned long)-1)); i++ )
1255 mb(); 1261 mb();
1256 1262
1257 if (*acknowledge == reg) { 1263 if (*acknowledge == reg)
1258 prom_printf("done\n"); 1264 prom_printf("done\n");
1259 /* We have to get every CPU out of OF, 1265 else
1260 * even if we never start it. */
1261 if (cpuid >= NR_CPUS)
1262 goto next;
1263 } else {
1264 prom_printf("failed: %x\n", *acknowledge); 1266 prom_printf("failed: %x\n", *acknowledge);
1265 }
1266 } 1267 }
1267#ifdef CONFIG_SMP 1268#ifdef CONFIG_SMP
1268 else 1269 else
1269 prom_printf("%x : boot cpu %x\n", cpuid, reg); 1270 prom_printf("%x : boot cpu %x\n", cpuid, reg);
1270#endif
1271next:
1272#ifdef CONFIG_SMP
1273 /* Init paca for secondary threads. They start later. */
1274 for (i=1; i < cpu_threads; i++) {
1275 cpuid++;
1276 if (cpuid >= NR_CPUS)
1277 continue;
1278 }
1279#endif /* CONFIG_SMP */ 1271#endif /* CONFIG_SMP */
1280 cpuid++; 1272
1273 /* Reserve cpu #s for secondary threads. They start later. */
1274 cpuid += cpu_threads;
1281 } 1275 }
1282#ifdef CONFIG_HMT 1276#ifdef CONFIG_HMT
1283 /* Only enable HMT on processors that provide support. */ 1277 /* Only enable HMT on processors that provide support. */
@@ -1311,7 +1305,6 @@ next:
1311 ") exceeded: ignoring extras\n"); 1305 ") exceeded: ignoring extras\n");
1312 1306
1313 prom_debug("prom_hold_cpus: end...\n"); 1307 prom_debug("prom_hold_cpus: end...\n");
1314#endif
1315} 1308}
1316 1309
1317 1310
@@ -1940,7 +1933,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
1940 unsigned long r6, unsigned long r7) 1933 unsigned long r6, unsigned long r7)
1941{ 1934{
1942 struct prom_t *_prom; 1935 struct prom_t *_prom;
1943 extern char _stext[];
1944 unsigned long hdr; 1936 unsigned long hdr;
1945 u32 getprop_rval; 1937 u32 getprop_rval;
1946 unsigned long offset = reloc_offset(); 1938 unsigned long offset = reloc_offset();
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 295d5c77f020..0cac112ca89d 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -56,6 +56,10 @@ extern void power4_idle(void);
56boot_infos_t *boot_infos; 56boot_infos_t *boot_infos;
57struct ide_machdep_calls ppc_ide_md; 57struct ide_machdep_calls ppc_ide_md;
58 58
59/* XXX should go elsewhere */
60int __irq_offset_value;
61EXPORT_SYMBOL(__irq_offset_value);
62
59/* Used with the BI_MEMSIZE bootinfo parameter to store the memory 63/* Used with the BI_MEMSIZE bootinfo parameter to store the memory
60 size value reported by the boot loader. */ 64 size value reported by the boot loader. */
61unsigned long boot_mem_size; 65unsigned long boot_mem_size;
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 509622da5408..01723d491b5d 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -5,6 +5,7 @@ ifeq ($(CONFIG_PPC64),y)
5obj-$(CONFIG_PPC_PMAC) += powermac/ 5obj-$(CONFIG_PPC_PMAC) += powermac/
6endif 6endif
7endif 7endif
8obj-$(CONFIG_PPC_CHRP) += chrp/
8obj-$(CONFIG_4xx) += 4xx/ 9obj-$(CONFIG_4xx) += 4xx/
9obj-$(CONFIG_85xx) += 85xx/ 10obj-$(CONFIG_85xx) += 85xx/
10obj-$(CONFIG_PPC_PSERIES) += pseries/ 11obj-$(CONFIG_PPC_PSERIES) += pseries/
diff --git a/arch/powerpc/platforms/chrp/Makefile b/arch/powerpc/platforms/chrp/Makefile
new file mode 100644
index 000000000000..1fde4e68414f
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/Makefile
@@ -0,0 +1,3 @@
1obj-y += setup.o time.o pegasos_eth.o
2obj-$(CONFIG_PCI) += pci.o
3obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c
new file mode 100644
index 000000000000..82c429d487f3
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/pci.c
@@ -0,0 +1,310 @@
1/*
2 * CHRP pci routines.
3 */
4
5#include <linux/config.h>
6#include <linux/kernel.h>
7#include <linux/pci.h>
8#include <linux/delay.h>
9#include <linux/string.h>
10#include <linux/init.h>
11#include <linux/ide.h>
12
13#include <asm/io.h>
14#include <asm/pgtable.h>
15#include <asm/irq.h>
16#include <asm/hydra.h>
17#include <asm/prom.h>
18#include <asm/gg2.h>
19#include <asm/machdep.h>
20#include <asm/sections.h>
21#include <asm/pci-bridge.h>
22#include <asm/open_pic.h>
23#include <asm/grackle.h>
24#include <asm/rtas.h>
25
26/* LongTrail */
27void __iomem *gg2_pci_config_base;
28
29/*
30 * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
31 * limit the bus number to 3 bits
32 */
33
34int gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off,
35 int len, u32 *val)
36{
37 volatile void __iomem *cfg_data;
38 struct pci_controller *hose = bus->sysdata;
39
40 if (bus->number > 7)
41 return PCIBIOS_DEVICE_NOT_FOUND;
42 /*
43 * Note: the caller has already checked that off is
44 * suitably aligned and that len is 1, 2 or 4.
45 */
46 cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off);
47 switch (len) {
48 case 1:
49 *val = in_8(cfg_data);
50 break;
51 case 2:
52 *val = in_le16(cfg_data);
53 break;
54 default:
55 *val = in_le32(cfg_data);
56 break;
57 }
58 return PCIBIOS_SUCCESSFUL;
59}
60
61int gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off,
62 int len, u32 val)
63{
64 volatile void __iomem *cfg_data;
65 struct pci_controller *hose = bus->sysdata;
66
67 if (bus->number > 7)
68 return PCIBIOS_DEVICE_NOT_FOUND;
69 /*
70 * Note: the caller has already checked that off is
71 * suitably aligned and that len is 1, 2 or 4.
72 */
73 cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off);
74 switch (len) {
75 case 1:
76 out_8(cfg_data, val);
77 break;
78 case 2:
79 out_le16(cfg_data, val);
80 break;
81 default:
82 out_le32(cfg_data, val);
83 break;
84 }
85 return PCIBIOS_SUCCESSFUL;
86}
87
88static struct pci_ops gg2_pci_ops =
89{
90 gg2_read_config,
91 gg2_write_config
92};
93
94/*
95 * Access functions for PCI config space using RTAS calls.
96 */
97int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
98 int len, u32 *val)
99{
100 struct pci_controller *hose = bus->sysdata;
101 unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
102 | (((bus->number - hose->first_busno) & 0xff) << 16)
103 | (hose->index << 24);
104 int ret = -1;
105 int rval;
106
107 rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len);
108 *val = ret;
109 return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;
110}
111
112int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
113 int len, u32 val)
114{
115 struct pci_controller *hose = bus->sysdata;
116 unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
117 | (((bus->number - hose->first_busno) & 0xff) << 16)
118 | (hose->index << 24);
119 int rval;
120
121 rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
122 addr, len, val);
123 return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;
124}
125
126static struct pci_ops rtas_pci_ops =
127{
128 rtas_read_config,
129 rtas_write_config
130};
131
132volatile struct Hydra __iomem *Hydra = NULL;
133
134int __init
135hydra_init(void)
136{
137 struct device_node *np;
138
139 np = find_devices("mac-io");
140 if (np == NULL || np->n_addrs == 0)
141 return 0;
142 Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
143 printk("Hydra Mac I/O at %lx\n", np->addrs[0].address);
144 printk("Hydra Feature_Control was %x",
145 in_le32(&Hydra->Feature_Control));
146 out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
147 HYDRA_FC_SCSI_CELL_EN |
148 HYDRA_FC_SCCA_ENABLE |
149 HYDRA_FC_SCCB_ENABLE |
150 HYDRA_FC_ARB_BYPASS |
151 HYDRA_FC_MPIC_ENABLE |
152 HYDRA_FC_SLOW_SCC_PCLK |
153 HYDRA_FC_MPIC_IS_MASTER));
154 printk(", now %x\n", in_le32(&Hydra->Feature_Control));
155 return 1;
156}
157
158void __init
159chrp_pcibios_fixup(void)
160{
161 struct pci_dev *dev = NULL;
162 struct device_node *np;
163
164 /* PCI interrupts are controlled by the OpenPIC */
165 for_each_pci_dev(dev) {
166 np = pci_device_to_OF_node(dev);
167 if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
168 dev->irq = np->intrs[0].line;
169 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
170 }
171}
172
173#define PRG_CL_RESET_VALID 0x00010000
174
175static void __init
176setup_python(struct pci_controller *hose, struct device_node *dev)
177{
178 u32 __iomem *reg;
179 u32 val;
180 unsigned long addr = dev->addrs[0].address;
181
182 setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010);
183
184 /* Clear the magic go-slow bit */
185 reg = ioremap(dev->addrs[0].address + 0xf6000, 0x40);
186 val = in_be32(&reg[12]);
187 if (val & PRG_CL_RESET_VALID) {
188 out_be32(&reg[12], val & ~PRG_CL_RESET_VALID);
189 in_be32(&reg[12]);
190 }
191 iounmap(reg);
192}
193
194/* Marvell Discovery II based Pegasos 2 */
195static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev)
196{
197 struct device_node *root = find_path_device("/");
198 struct device_node *rtas;
199
200 rtas = of_find_node_by_name (root, "rtas");
201 if (rtas) {
202 hose->ops = &rtas_pci_ops;
203 } else {
204 printk ("RTAS supporting Pegasos OF not found, please upgrade"
205 " your firmware\n");
206 }
207 pci_assign_all_buses = 1;
208}
209
210void __init
211chrp_find_bridges(void)
212{
213 struct device_node *dev;
214 int *bus_range;
215 int len, index = -1;
216 struct pci_controller *hose;
217 unsigned int *dma;
218 char *model, *machine;
219 int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
220 struct device_node *root = find_path_device("/");
221
222 /*
223 * The PCI host bridge nodes on some machines don't have
224 * properties to adequately identify them, so we have to
225 * look at what sort of machine this is as well.
226 */
227 machine = get_property(root, "model", NULL);
228 if (machine != NULL) {
229 is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
230 is_mot = strncmp(machine, "MOT", 3) == 0;
231 if (strncmp(machine, "Pegasos2", 8) == 0)
232 is_pegasos = 2;
233 else if (strncmp(machine, "Pegasos", 7) == 0)
234 is_pegasos = 1;
235 }
236 for (dev = root->child; dev != NULL; dev = dev->sibling) {
237 if (dev->type == NULL || strcmp(dev->type, "pci") != 0)
238 continue;
239 ++index;
240 /* The GG2 bridge on the LongTrail doesn't have an address */
241 if (dev->n_addrs < 1 && !is_longtrail) {
242 printk(KERN_WARNING "Can't use %s: no address\n",
243 dev->full_name);
244 continue;
245 }
246 bus_range = (int *) get_property(dev, "bus-range", &len);
247 if (bus_range == NULL || len < 2 * sizeof(int)) {
248 printk(KERN_WARNING "Can't get bus-range for %s\n",
249 dev->full_name);
250 continue;
251 }
252 if (bus_range[1] == bus_range[0])
253 printk(KERN_INFO "PCI bus %d", bus_range[0]);
254 else
255 printk(KERN_INFO "PCI buses %d..%d",
256 bus_range[0], bus_range[1]);
257 printk(" controlled by %s", dev->type);
258 if (dev->n_addrs > 0)
259 printk(" at %lx", dev->addrs[0].address);
260 printk("\n");
261
262 hose = pcibios_alloc_controller();
263 if (!hose) {
264 printk("Can't allocate PCI controller structure for %s\n",
265 dev->full_name);
266 continue;
267 }
268 hose->arch_data = dev;
269 hose->first_busno = bus_range[0];
270 hose->last_busno = bus_range[1];
271
272 model = get_property(dev, "model", NULL);
273 if (model == NULL)
274 model = "<none>";
275 if (device_is_compatible(dev, "IBM,python")) {
276 setup_python(hose, dev);
277 } else if (is_mot
278 || strncmp(model, "Motorola, Grackle", 17) == 0) {
279 setup_grackle(hose);
280 } else if (is_longtrail) {
281 void __iomem *p = ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
282 hose->ops = &gg2_pci_ops;
283 hose->cfg_data = p;
284 gg2_pci_config_base = p;
285 } else if (is_pegasos == 1) {
286 setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc);
287 } else if (is_pegasos == 2) {
288 setup_peg2(hose, dev);
289 } else {
290 printk("No methods for %s (model %s), using RTAS\n",
291 dev->full_name, model);
292 hose->ops = &rtas_pci_ops;
293 }
294
295 pci_process_bridge_OF_ranges(hose, dev, index == 0);
296
297 /* check the first bridge for a property that we can
298 use to set pci_dram_offset */
299 dma = (unsigned int *)
300 get_property(dev, "ibm,dma-ranges", &len);
301 if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
302 pci_dram_offset = dma[2] - dma[3];
303 printk("pci_dram_offset = %lx\n", pci_dram_offset);
304 }
305 }
306
307 /* Do not fixup interrupts from OF tree on pegasos */
308 if (is_pegasos == 0)
309 ppc_md.pcibios_fixup = chrp_pcibios_fixup;
310}
diff --git a/arch/powerpc/platforms/chrp/pegasos_eth.c b/arch/powerpc/platforms/chrp/pegasos_eth.c
new file mode 100644
index 000000000000..cad5bfa153b2
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/pegasos_eth.c
@@ -0,0 +1,101 @@
1/*
2 * arch/ppc/platforms/chrp_pegasos_eth.c
3 *
4 * Copyright (C) 2005 Sven Luther <sl@bplan-gmbh.de>
5 * Thanks to :
6 * Dale Farnsworth <dale@farnsworth.org>
7 * Mark A. Greer <mgreer@mvista.com>
8 * Nicolas DET <nd@bplan-gmbh.de>
9 * Benjamin Herrenschmidt <benh@kernel.crashing.org>
10 * And anyone else who helped me on this.
11 */
12
13#include <linux/types.h>
14#include <linux/init.h>
15#include <linux/ioport.h>
16#include <linux/device.h>
17#include <linux/mv643xx.h>
18#include <linux/pci.h>
19
20/* Pegasos 2 specific Marvell MV 64361 gigabit ethernet port setup */
21static struct resource mv643xx_eth_shared_resources[] = {
22 [0] = {
23 .name = "ethernet shared base",
24 .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
25 .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
26 MV643XX_ETH_SHARED_REGS_SIZE - 1,
27 .flags = IORESOURCE_MEM,
28 },
29};
30
31static struct platform_device mv643xx_eth_shared_device = {
32 .name = MV643XX_ETH_SHARED_NAME,
33 .id = 0,
34 .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources),
35 .resource = mv643xx_eth_shared_resources,
36};
37
38static struct resource mv643xx_eth0_resources[] = {
39 [0] = {
40 .name = "eth0 irq",
41 .start = 9,
42 .end = 9,
43 .flags = IORESOURCE_IRQ,
44 },
45};
46
47static struct mv643xx_eth_platform_data eth0_pd;
48
49static struct platform_device eth0_device = {
50 .name = MV643XX_ETH_NAME,
51 .id = 0,
52 .num_resources = ARRAY_SIZE(mv643xx_eth0_resources),
53 .resource = mv643xx_eth0_resources,
54 .dev = {
55 .platform_data = &eth0_pd,
56 },
57};
58
59static struct resource mv643xx_eth1_resources[] = {
60 [0] = {
61 .name = "eth1 irq",
62 .start = 9,
63 .end = 9,
64 .flags = IORESOURCE_IRQ,
65 },
66};
67
68static struct mv643xx_eth_platform_data eth1_pd;
69
70static struct platform_device eth1_device = {
71 .name = MV643XX_ETH_NAME,
72 .id = 1,
73 .num_resources = ARRAY_SIZE(mv643xx_eth1_resources),
74 .resource = mv643xx_eth1_resources,
75 .dev = {
76 .platform_data = &eth1_pd,
77 },
78};
79
80static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
81 &mv643xx_eth_shared_device,
82 &eth0_device,
83 &eth1_device,
84};
85
86
87int
88mv643xx_eth_add_pds(void)
89{
90 int ret = 0;
91 static struct pci_device_id pci_marvell_mv64360[] = {
92 { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) },
93 { }
94 };
95
96 if (pci_dev_present(pci_marvell_mv64360)) {
97 ret = platform_add_devices(mv643xx_eth_pd_devs, ARRAY_SIZE(mv643xx_eth_pd_devs));
98 }
99 return ret;
100}
101device_initcall(mv643xx_eth_add_pds);
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
new file mode 100644
index 000000000000..5145990e6a01
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -0,0 +1,523 @@
1/*
2 * arch/ppc/platforms/setup.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 * Adapted from 'alpha' version by Gary Thomas
6 * Modified by Cort Dougan (cort@cs.nmt.edu)
7 */
8
9/*
10 * bootup setup stuff..
11 */
12
13#include <linux/config.h>
14#include <linux/errno.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/mm.h>
18#include <linux/stddef.h>
19#include <linux/unistd.h>
20#include <linux/ptrace.h>
21#include <linux/slab.h>
22#include <linux/user.h>
23#include <linux/a.out.h>
24#include <linux/tty.h>
25#include <linux/major.h>
26#include <linux/interrupt.h>
27#include <linux/reboot.h>
28#include <linux/init.h>
29#include <linux/pci.h>
30#include <linux/version.h>
31#include <linux/adb.h>
32#include <linux/module.h>
33#include <linux/delay.h>
34#include <linux/ide.h>
35#include <linux/console.h>
36#include <linux/seq_file.h>
37#include <linux/root_dev.h>
38#include <linux/initrd.h>
39#include <linux/module.h>
40
41#include <asm/io.h>
42#include <asm/pgtable.h>
43#include <asm/prom.h>
44#include <asm/gg2.h>
45#include <asm/pci-bridge.h>
46#include <asm/dma.h>
47#include <asm/machdep.h>
48#include <asm/irq.h>
49#include <asm/hydra.h>
50#include <asm/sections.h>
51#include <asm/time.h>
52#include <asm/btext.h>
53#include <asm/i8259.h>
54#include <asm/mpic.h>
55#include <asm/rtas.h>
56#include <asm/xmon.h>
57
58void chrp_get_rtc_time(struct rtc_time *);
59int chrp_set_rtc_time(struct rtc_time *);
60void chrp_calibrate_decr(void);
61long chrp_time_init(void);
62
63void chrp_find_bridges(void);
64void chrp_event_scan(void);
65void rtas_indicator_progress(char *, unsigned short);
66void btext_progress(char *, unsigned short);
67
68int _chrp_type;
69EXPORT_SYMBOL(_chrp_type);
70
71struct mpic *chrp_mpic;
72
73/*
74 * XXX this should be in xmon.h, but putting it there means xmon.h
75 * has to include <linux/interrupt.h> (to get irqreturn_t), which
76 * causes all sorts of problems. -- paulus
77 */
78extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
79
80extern unsigned long loops_per_jiffy;
81
82#ifdef CONFIG_SMP
83extern struct smp_ops_t chrp_smp_ops;
84#endif
85
86static const char *gg2_memtypes[4] = {
87 "FPM", "SDRAM", "EDO", "BEDO"
88};
89static const char *gg2_cachesizes[4] = {
90 "256 KB", "512 KB", "1 MB", "Reserved"
91};
92static const char *gg2_cachetypes[4] = {
93 "Asynchronous", "Reserved", "Flow-Through Synchronous",
94 "Pipelined Synchronous"
95};
96static const char *gg2_cachemodes[4] = {
97 "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
98};
99
100void chrp_show_cpuinfo(struct seq_file *m)
101{
102 int i, sdramen;
103 unsigned int t;
104 struct device_node *root;
105 const char *model = "";
106
107 root = find_path_device("/");
108 if (root)
109 model = get_property(root, "model", NULL);
110 seq_printf(m, "machine\t\t: CHRP %s\n", model);
111
112 /* longtrail (goldengate) stuff */
113 if (!strncmp(model, "IBM,LongTrail", 13)) {
114 /* VLSI VAS96011/12 `Golden Gate 2' */
115 /* Memory banks */
116 sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL)
117 >>31) & 1;
118 for (i = 0; i < (sdramen ? 4 : 6); i++) {
119 t = in_le32(gg2_pci_config_base+
120 GG2_PCI_DRAM_BANK0+
121 i*4);
122 if (!(t & 1))
123 continue;
124 switch ((t>>8) & 0x1f) {
125 case 0x1f:
126 model = "4 MB";
127 break;
128 case 0x1e:
129 model = "8 MB";
130 break;
131 case 0x1c:
132 model = "16 MB";
133 break;
134 case 0x18:
135 model = "32 MB";
136 break;
137 case 0x10:
138 model = "64 MB";
139 break;
140 case 0x00:
141 model = "128 MB";
142 break;
143 default:
144 model = "Reserved";
145 break;
146 }
147 seq_printf(m, "memory bank %d\t: %s %s\n", i, model,
148 gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
149 }
150 /* L2 cache */
151 t = in_le32(gg2_pci_config_base+GG2_PCI_CC_CTRL);
152 seq_printf(m, "board l2\t: %s %s (%s)\n",
153 gg2_cachesizes[(t>>7) & 3],
154 gg2_cachetypes[(t>>2) & 3],
155 gg2_cachemodes[t & 3]);
156 }
157}
158
159/*
160 * Fixes for the National Semiconductor PC78308VUL SuperI/O
161 *
162 * Some versions of Open Firmware incorrectly initialize the IRQ settings
163 * for keyboard and mouse
164 */
165static inline void __init sio_write(u8 val, u8 index)
166{
167 outb(index, 0x15c);
168 outb(val, 0x15d);
169}
170
171static inline u8 __init sio_read(u8 index)
172{
173 outb(index, 0x15c);
174 return inb(0x15d);
175}
176
177static void __init sio_fixup_irq(const char *name, u8 device, u8 level,
178 u8 type)
179{
180 u8 level0, type0, active;
181
182 /* select logical device */
183 sio_write(device, 0x07);
184 active = sio_read(0x30);
185 level0 = sio_read(0x70);
186 type0 = sio_read(0x71);
187 if (level0 != level || type0 != type || !active) {
188 printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: "
189 "remapping to level %d, type %d, active\n",
190 name, level0, type0, !active ? "in" : "", level, type);
191 sio_write(0x01, 0x30);
192 sio_write(level, 0x70);
193 sio_write(type, 0x71);
194 }
195}
196
197static void __init sio_init(void)
198{
199 struct device_node *root;
200
201 if ((root = find_path_device("/")) &&
202 !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
203 /* logical device 0 (KBC/Keyboard) */
204 sio_fixup_irq("keyboard", 0, 1, 2);
205 /* select logical device 1 (KBC/Mouse) */
206 sio_fixup_irq("mouse", 1, 12, 2);
207 }
208}
209
210
211static void __init pegasos_set_l2cr(void)
212{
213 struct device_node *np;
214
215 /* On Pegasos, enable the l2 cache if needed, as the OF forgets it */
216 if (_chrp_type != _CHRP_Pegasos)
217 return;
218
219 /* Enable L2 cache if needed */
220 np = find_type_devices("cpu");
221 if (np != NULL) {
222 unsigned int *l2cr = (unsigned int *)
223 get_property (np, "l2cr", NULL);
224 if (l2cr == NULL) {
225 printk ("Pegasos l2cr : no cpu l2cr property found\n");
226 return;
227 }
228 if (!((*l2cr) & 0x80000000)) {
229 printk ("Pegasos l2cr : L2 cache was not active, "
230 "activating\n");
231 _set_L2CR(0);
232 _set_L2CR((*l2cr) | 0x80000000);
233 }
234 }
235}
236
237void __init chrp_setup_arch(void)
238{
239 struct device_node *root = find_path_device ("/");
240 char *machine = NULL;
241 struct device_node *device;
242 unsigned int *p = NULL;
243
244 /* init to some ~sane value until calibrate_delay() runs */
245 loops_per_jiffy = 50000000/HZ;
246
247 if (root)
248 machine = get_property(root, "model", NULL);
249 if (machine && strncmp(machine, "Pegasos", 7) == 0) {
250 _chrp_type = _CHRP_Pegasos;
251 } else if (machine && strncmp(machine, "IBM", 3) == 0) {
252 _chrp_type = _CHRP_IBM;
253 } else if (machine && strncmp(machine, "MOT", 3) == 0) {
254 _chrp_type = _CHRP_Motorola;
255 } else {
256 /* Let's assume it is an IBM chrp if all else fails */
257 _chrp_type = _CHRP_IBM;
258 }
259 printk("chrp type = %x\n", _chrp_type);
260
261 rtas_initialize();
262 if (rtas_token("display-character") >= 0)
263 ppc_md.progress = rtas_progress;
264
265#ifdef CONFIG_BOOTX_TEXT
266 if (ppc_md.progress == NULL && boot_text_mapped)
267 ppc_md.progress = btext_progress;
268#endif
269
270#ifdef CONFIG_BLK_DEV_INITRD
271 /* this is fine for chrp */
272 initrd_below_start_ok = 1;
273
274 if (initrd_start)
275 ROOT_DEV = Root_RAM0;
276 else
277#endif
278 ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */
279
280 /* On pegasos, enable the L2 cache if not already done by OF */
281 pegasos_set_l2cr();
282
283 /* Lookup PCI host bridges */
284 chrp_find_bridges();
285
286 /*
287 * Temporary fixes for PCI devices.
288 * -- Geert
289 */
290 hydra_init(); /* Mac I/O */
291
292 /*
293 * Fix the Super I/O configuration
294 */
295 sio_init();
296
297 /* Get the event scan rate for the rtas so we know how
298 * often it expects a heartbeat. -- Cort
299 */
300 device = find_devices("rtas");
301 if (device)
302 p = (unsigned int *) get_property
303 (device, "rtas-event-scan-rate", NULL);
304 if (p && *p) {
305 ppc_md.heartbeat = chrp_event_scan;
306 ppc_md.heartbeat_reset = HZ / (*p * 30) - 1;
307 ppc_md.heartbeat_count = 1;
308 printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
309 *p, ppc_md.heartbeat_reset);
310 }
311
312 pci_create_OF_bus_map();
313
314 /*
315 * Print the banner, then scroll down so boot progress
316 * can be printed. -- Cort
317 */
318 if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
319}
320
321void
322chrp_event_scan(void)
323{
324 unsigned char log[1024];
325 int ret = 0;
326
327 /* XXX: we should loop until the hardware says no more error logs -- Cort */
328 rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0,
329 __pa(log), 1024);
330 ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
331}
332
333/*
334 * Finds the open-pic node and sets up the mpic driver.
335 */
336static void __init chrp_find_openpic(void)
337{
338 struct device_node *np, *root;
339 int len, i, j, irq_count;
340 int isu_size, idu_size;
341 unsigned int *iranges, *opprop = NULL;
342 int oplen = 0;
343 unsigned long opaddr;
344 int na = 1;
345 unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
346
347 np = find_type_devices("open-pic");
348 if (np == NULL)
349 return;
350 root = find_path_device("/");
351 if (root) {
352 opprop = (unsigned int *) get_property
353 (root, "platform-open-pic", &oplen);
354 na = prom_n_addr_cells(root);
355 }
356 if (opprop && oplen >= na * sizeof(unsigned int)) {
357 opaddr = opprop[na-1]; /* assume 32-bit */
358 oplen /= na * sizeof(unsigned int);
359 } else {
360 if (np->n_addrs == 0)
361 return;
362 opaddr = np->addrs[0].address;
363 oplen = 0;
364 }
365
366 printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
367
368 irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */
369 prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS - 4);
370
371 iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
372 if (iranges == NULL)
373 len = 0; /* non-distributed mpic */
374 else
375 len /= 2 * sizeof(unsigned int);
376
377 /*
378 * The first pair of cells in interrupt-ranges refers to the
379 * IDU; subsequent pairs refer to the ISUs.
380 */
381 if (oplen < len) {
382 printk(KERN_ERR "Insufficient addresses for distributed"
383 " OpenPIC (%d < %d)\n", np->n_addrs, len);
384 len = oplen;
385 }
386
387 isu_size = 0;
388 idu_size = 0;
389 if (len > 0 && iranges[1] != 0) {
390 printk(KERN_INFO "OpenPIC irqs %d..%d in IDU\n",
391 iranges[0], iranges[0] + iranges[1] - 1);
392 idu_size = iranges[1];
393 }
394 if (len > 1)
395 isu_size = iranges[3];
396
397 chrp_mpic = mpic_alloc(opaddr, MPIC_PRIMARY,
398 isu_size, NUM_ISA_INTERRUPTS, irq_count,
399 NR_IRQS - 4, init_senses, irq_count,
400 " MPIC ");
401 if (chrp_mpic == NULL) {
402 printk(KERN_ERR "Failed to allocate MPIC structure\n");
403 return;
404 }
405
406 j = na - 1;
407 for (i = 1; i < len; ++i) {
408 iranges += 2;
409 j += na;
410 printk(KERN_INFO "OpenPIC irqs %d..%d in ISU at %x\n",
411 iranges[0], iranges[0] + iranges[1] - 1,
412 opprop[j]);
413 mpic_assign_isu(chrp_mpic, i - 1, opprop[j]);
414 }
415
416 mpic_init(chrp_mpic);
417 mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL);
418}
419
420#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
421static struct irqaction xmon_irqaction = {
422 .handler = xmon_irq,
423 .mask = CPU_MASK_NONE,
424 .name = "XMON break",
425};
426#endif
427
428void __init chrp_init_IRQ(void)
429{
430 struct device_node *np;
431 unsigned long chrp_int_ack = 0;
432#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
433 struct device_node *kbd;
434#endif
435
436 for (np = find_devices("pci"); np != NULL; np = np->next) {
437 unsigned int *addrp = (unsigned int *)
438 get_property(np, "8259-interrupt-acknowledge", NULL);
439
440 if (addrp == NULL)
441 continue;
442 chrp_int_ack = addrp[prom_n_addr_cells(np)-1];
443 break;
444 }
445 if (np == NULL)
446 printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n");
447
448 chrp_find_openpic();
449
450 i8259_init(chrp_int_ack, 0);
451
452 if (_chrp_type == _CHRP_Pegasos)
453 ppc_md.get_irq = i8259_irq;
454 else
455 ppc_md.get_irq = mpic_get_irq;
456
457#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
458 /* see if there is a keyboard in the device tree
459 with a parent of type "adb" */
460 for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
461 if (kbd->parent && kbd->parent->type
462 && strcmp(kbd->parent->type, "adb") == 0)
463 break;
464 if (kbd)
465 setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction);
466#endif
467}
468
469void __init
470chrp_init2(void)
471{
472 request_region(0x20,0x20,"pic1");
473 request_region(0xa0,0x20,"pic2");
474 request_region(0x00,0x20,"dma1");
475 request_region(0x40,0x20,"timer");
476 request_region(0x80,0x10,"dma page reg");
477 request_region(0xc0,0x20,"dma2");
478
479 if (ppc_md.progress)
480 ppc_md.progress(" Have fun! ", 0x7777);
481}
482
483void __init chrp_init(void)
484{
485 ISA_DMA_THRESHOLD = ~0L;
486 DMA_MODE_READ = 0x44;
487 DMA_MODE_WRITE = 0x48;
488 isa_io_base = CHRP_ISA_IO_BASE; /* default value */
489 ppc_do_canonicalize_irqs = 1;
490
491 /* Assume we have an 8259... */
492 __irq_offset_value = NUM_ISA_INTERRUPTS;
493
494 ppc_md.setup_arch = chrp_setup_arch;
495 ppc_md.show_cpuinfo = chrp_show_cpuinfo;
496
497 ppc_md.init_IRQ = chrp_init_IRQ;
498 ppc_md.init = chrp_init2;
499
500 ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
501
502 ppc_md.restart = rtas_restart;
503 ppc_md.power_off = rtas_power_off;
504 ppc_md.halt = rtas_halt;
505
506 ppc_md.time_init = chrp_time_init;
507 ppc_md.set_rtc_time = chrp_set_rtc_time;
508 ppc_md.get_rtc_time = chrp_get_rtc_time;
509 ppc_md.calibrate_decr = chrp_calibrate_decr;
510
511#ifdef CONFIG_SMP
512 smp_ops = &chrp_smp_ops;
513#endif /* CONFIG_SMP */
514}
515
516#ifdef CONFIG_BOOTX_TEXT
517void
518btext_progress(char *s, unsigned short hex)
519{
520 btext_drawstring(s);
521 btext_drawstring("\n");
522}
523#endif /* CONFIG_BOOTX_TEXT */
diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c
new file mode 100644
index 000000000000..bf68282670dd
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/smp.c
@@ -0,0 +1,94 @@
1/*
2 * Smp support for CHRP machines.
3 *
4 * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
5 * deal of code from the sparc and intel versions.
6 *
7 * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
8 *
9 */
10
11#include <linux/config.h>
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/smp.h>
15#include <linux/smp_lock.h>
16#include <linux/interrupt.h>
17#include <linux/kernel_stat.h>
18#include <linux/delay.h>
19#include <linux/init.h>
20#include <linux/spinlock.h>
21
22#include <asm/ptrace.h>
23#include <asm/atomic.h>
24#include <asm/irq.h>
25#include <asm/page.h>
26#include <asm/pgtable.h>
27#include <asm/sections.h>
28#include <asm/io.h>
29#include <asm/prom.h>
30#include <asm/smp.h>
31#include <asm/residual.h>
32#include <asm/time.h>
33#include <asm/open_pic.h>
34#include <asm/machdep.h>
35
36extern unsigned long smp_chrp_cpu_nr;
37
38static int __init smp_chrp_probe(void)
39{
40 if (smp_chrp_cpu_nr > 1)
41 openpic_request_IPIs();
42
43 return smp_chrp_cpu_nr;
44}
45
46static void __devinit smp_chrp_kick_cpu(int nr)
47{
48 *(unsigned long *)KERNELBASE = nr;
49 asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
50}
51
52static void __devinit smp_chrp_setup_cpu(int cpu_nr)
53{
54 if (OpenPIC_Addr)
55 do_openpic_setup_cpu();
56}
57
58static DEFINE_SPINLOCK(timebase_lock);
59static unsigned int timebase_upper = 0, timebase_lower = 0;
60
61void __devinit smp_chrp_give_timebase(void)
62{
63 spin_lock(&timebase_lock);
64 rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
65 timebase_upper = get_tbu();
66 timebase_lower = get_tbl();
67 spin_unlock(&timebase_lock);
68
69 while (timebase_upper || timebase_lower)
70 barrier();
71 rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
72}
73
74void __devinit smp_chrp_take_timebase(void)
75{
76 while (!(timebase_upper || timebase_lower))
77 barrier();
78 spin_lock(&timebase_lock);
79 set_tb(timebase_upper, timebase_lower);
80 timebase_upper = 0;
81 timebase_lower = 0;
82 spin_unlock(&timebase_lock);
83 printk("CPU %i taken timebase\n", smp_processor_id());
84}
85
86/* CHRP with openpic */
87struct smp_ops_t chrp_smp_ops = {
88 .message_pass = smp_openpic_message_pass,
89 .probe = smp_chrp_probe,
90 .kick_cpu = smp_chrp_kick_cpu,
91 .setup_cpu = smp_chrp_setup_cpu,
92 .give_timebase = smp_chrp_give_timebase,
93 .take_timebase = smp_chrp_take_timebase,
94};
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
new file mode 100644
index 000000000000..9e53535ddb82
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -0,0 +1,188 @@
1/*
2 * arch/ppc/platforms/chrp_time.c
3 *
4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
5 *
6 * Adapted for PowerPC (PReP) by Gary Thomas
7 * Modified by Cort Dougan (cort@cs.nmt.edu).
8 * Copied and modified from arch/i386/kernel/time.c
9 *
10 */
11#include <linux/errno.h>
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/param.h>
15#include <linux/string.h>
16#include <linux/mm.h>
17#include <linux/interrupt.h>
18#include <linux/time.h>
19#include <linux/timex.h>
20#include <linux/kernel_stat.h>
21#include <linux/mc146818rtc.h>
22#include <linux/init.h>
23#include <linux/bcd.h>
24
25#include <asm/io.h>
26#include <asm/nvram.h>
27#include <asm/prom.h>
28#include <asm/sections.h>
29#include <asm/time.h>
30
31extern spinlock_t rtc_lock;
32
33static int nvram_as1 = NVRAM_AS1;
34static int nvram_as0 = NVRAM_AS0;
35static int nvram_data = NVRAM_DATA;
36
37long __init chrp_time_init(void)
38{
39 struct device_node *rtcs;
40 int base;
41
42 rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
43 if (rtcs == NULL)
44 rtcs = find_compatible_devices("rtc", "ds1385-rtc");
45 if (rtcs == NULL || rtcs->addrs == NULL)
46 return 0;
47 base = rtcs->addrs[0].address;
48 nvram_as1 = 0;
49 nvram_as0 = base;
50 nvram_data = base + 1;
51
52 return 0;
53}
54
55int chrp_cmos_clock_read(int addr)
56{
57 if (nvram_as1 != 0)
58 outb(addr>>8, nvram_as1);
59 outb(addr, nvram_as0);
60 return (inb(nvram_data));
61}
62
63void chrp_cmos_clock_write(unsigned long val, int addr)
64{
65 if (nvram_as1 != 0)
66 outb(addr>>8, nvram_as1);
67 outb(addr, nvram_as0);
68 outb(val, nvram_data);
69 return;
70}
71
72/*
73 * Set the hardware clock. -- Cort
74 */
75int chrp_set_rtc_time(struct rtc_time *tmarg)
76{
77 unsigned char save_control, save_freq_select;
78 struct rtc_time tm = *tmarg;
79
80 spin_lock(&rtc_lock);
81
82 save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
83
84 chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
85
86 save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
87
88 chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
89
90 tm.tm_year -= 1900;
91 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
92 BIN_TO_BCD(tm.tm_sec);
93 BIN_TO_BCD(tm.tm_min);
94 BIN_TO_BCD(tm.tm_hour);
95 BIN_TO_BCD(tm.tm_mon);
96 BIN_TO_BCD(tm.tm_mday);
97 BIN_TO_BCD(tm.tm_year);
98 }
99 chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
100 chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
101 chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
102 chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
103 chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
104 chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
105
106 /* The following flags have to be released exactly in this order,
107 * otherwise the DS12887 (popular MC146818A clone with integrated
108 * battery and quartz) will not reset the oscillator and will not
109 * update precisely 500 ms later. You won't find this mentioned in
110 * the Dallas Semiconductor data sheets, but who believes data
111 * sheets anyway ... -- Markus Kuhn
112 */
113 chrp_cmos_clock_write(save_control, RTC_CONTROL);
114 chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
115
116 spin_unlock(&rtc_lock);
117 return 0;
118}
119
120void chrp_get_rtc_time(struct rtc_time *tm)
121{
122 unsigned int year, mon, day, hour, min, sec;
123 int uip, i;
124
125 /* The Linux interpretation of the CMOS clock register contents:
126 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
127 * RTC registers show the second which has precisely just started.
128 * Let's hope other operating systems interpret the RTC the same way.
129 */
130
131 /* Since the UIP flag is set for about 2.2 ms and the clock
132 * is typically written with a precision of 1 jiffy, trying
133 * to obtain a precision better than a few milliseconds is
134 * an illusion. Only consistency is interesting, this also
135 * allows to use the routine for /dev/rtc without a potential
136 * 1 second kernel busy loop triggered by any reader of /dev/rtc.
137 */
138
139 for ( i = 0; i<1000000; i++) {
140 uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
141 sec = chrp_cmos_clock_read(RTC_SECONDS);
142 min = chrp_cmos_clock_read(RTC_MINUTES);
143 hour = chrp_cmos_clock_read(RTC_HOURS);
144 day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
145 mon = chrp_cmos_clock_read(RTC_MONTH);
146 year = chrp_cmos_clock_read(RTC_YEAR);
147 uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
148 if ((uip & RTC_UIP)==0) break;
149 }
150
151 if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
152 BCD_TO_BIN(sec);
153 BCD_TO_BIN(min);
154 BCD_TO_BIN(hour);
155 BCD_TO_BIN(day);
156 BCD_TO_BIN(mon);
157 BCD_TO_BIN(year);
158 }
159 if ((year += 1900) < 1970)
160 year += 100;
161 tm->tm_sec = sec;
162 tm->tm_min = min;
163 tm->tm_hour = hour;
164 tm->tm_mday = day;
165 tm->tm_mon = mon;
166 tm->tm_year = year;
167}
168
169
170void __init chrp_calibrate_decr(void)
171{
172 struct device_node *cpu;
173 unsigned int freq, *fp;
174
175 /*
176 * The cpu node should have a timebase-frequency property
177 * to tell us the rate at which the decrementer counts.
178 */
179 freq = 16666000; /* hardcoded default */
180 cpu = find_type_devices("cpu");
181 if (cpu != 0) {
182 fp = (unsigned int *)
183 get_property(cpu, "timebase-frequency", NULL);
184 if (fp != 0)
185 freq = *fp;
186 }
187 ppc_tb_freq = freq;
188}
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 0eca17df239e..0037a8c8c81f 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -71,10 +71,6 @@ static u32 level_mask[4];
71 71
72static DEFINE_SPINLOCK(pmac_pic_lock); 72static DEFINE_SPINLOCK(pmac_pic_lock);
73 73
74/* XXX here for now, should move to arch/powerpc/kernel/irq.c */
75int ppc_do_canonicalize_irqs;
76EXPORT_SYMBOL(ppc_do_canonicalize_irqs);
77
78#define GATWICK_IRQ_POOL_SIZE 10 74#define GATWICK_IRQ_POOL_SIZE 10
79static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; 75static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
80 76