xref: /freebsd/sys/powerpc/powermac/platform_powermac.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1b2a237beSNathan Whitehorn /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
371e3c308SPedro F. Giffuni  *
4b2a237beSNathan Whitehorn  * Copyright (c) 2008 Marcel Moolenaar
5b2a237beSNathan Whitehorn  * Copyright (c) 2009 Nathan Whitehorn
6b2a237beSNathan Whitehorn  * All rights reserved.
7b2a237beSNathan Whitehorn  *
8b2a237beSNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
9b2a237beSNathan Whitehorn  * modification, are permitted provided that the following conditions
10b2a237beSNathan Whitehorn  * are met:
11b2a237beSNathan Whitehorn  *
12b2a237beSNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
13b2a237beSNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
14b2a237beSNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
15b2a237beSNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
16b2a237beSNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
17b2a237beSNathan Whitehorn  *
18b2a237beSNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19b2a237beSNathan Whitehorn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20b2a237beSNathan Whitehorn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21b2a237beSNathan Whitehorn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22b2a237beSNathan Whitehorn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23b2a237beSNathan Whitehorn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24b2a237beSNathan Whitehorn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25b2a237beSNathan Whitehorn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26b2a237beSNathan Whitehorn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27b2a237beSNathan Whitehorn  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28b2a237beSNathan Whitehorn  */
29b2a237beSNathan Whitehorn 
30b2a237beSNathan Whitehorn #include <sys/param.h>
31b2a237beSNathan Whitehorn #include <sys/systm.h>
32b2a237beSNathan Whitehorn #include <sys/kernel.h>
33b2a237beSNathan Whitehorn #include <sys/bus.h>
34b2a237beSNathan Whitehorn #include <sys/pcpu.h>
35b2a237beSNathan Whitehorn #include <sys/proc.h>
36b2a237beSNathan Whitehorn #include <sys/smp.h>
37b2a237beSNathan Whitehorn #include <vm/vm.h>
38b2a237beSNathan Whitehorn #include <vm/pmap.h>
39b2a237beSNathan Whitehorn 
40e1c161e7SJustin Hibbits #include <machine/altivec.h>	/* For save_vec() */
41b2a237beSNathan Whitehorn #include <machine/bus.h>
42b2a237beSNathan Whitehorn #include <machine/cpu.h>
43e1c161e7SJustin Hibbits #include <machine/fpu.h>	/* For save_fpu() */
44b2a237beSNathan Whitehorn #include <machine/hid.h>
45b2a237beSNathan Whitehorn #include <machine/platformvar.h>
46e1c161e7SJustin Hibbits #include <machine/setjmp.h>
47b2a237beSNathan Whitehorn #include <machine/smp.h>
48b2a237beSNathan Whitehorn #include <machine/spr.h>
49b2a237beSNathan Whitehorn 
50b2a237beSNathan Whitehorn #include <dev/ofw/openfirm.h>
51b2a237beSNathan Whitehorn #include <machine/ofw_machdep.h>
52b2a237beSNathan Whitehorn 
53c583b025SBrandon Bergren #include <powerpc/powermac/platform_powermac.h>
54c583b025SBrandon Bergren 
55b2a237beSNathan Whitehorn #include "platform_if.h"
56b2a237beSNathan Whitehorn 
57c583b025SBrandon Bergren extern volatile void *ap_pcpu;
58c583b025SBrandon Bergren 
59c583b025SBrandon Bergren static void dummy_timebase(device_t, bool);
60c583b025SBrandon Bergren static device_t powermac_tb_dev;
61c583b025SBrandon Bergren static void (*freeze_timebase)(device_t, bool) = dummy_timebase;
62b2a237beSNathan Whitehorn 
63b2a237beSNathan Whitehorn static int powermac_probe(platform_t);
649f706727SNathan Whitehorn static int powermac_attach(platform_t);
65c1cb22d7SNathan Whitehorn void powermac_mem_regions(platform_t, struct mem_region *phys, int *physsz,
66c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz);
67b2a237beSNathan Whitehorn static u_long powermac_timebase_freq(platform_t, struct cpuref *cpuref);
68b2a237beSNathan Whitehorn static int powermac_smp_first_cpu(platform_t, struct cpuref *cpuref);
69b2a237beSNathan Whitehorn static int powermac_smp_next_cpu(platform_t, struct cpuref *cpuref);
70b2a237beSNathan Whitehorn static int powermac_smp_get_bsp(platform_t, struct cpuref *cpuref);
71b2a237beSNathan Whitehorn static int powermac_smp_start_cpu(platform_t, struct pcpu *cpu);
72de2dd83fSNathan Whitehorn static void powermac_smp_timebase_sync(platform_t, u_long tb, int ap);
73b2a237beSNathan Whitehorn static void powermac_reset(platform_t);
74b6d8f3b5SJustin Hibbits #ifndef __powerpc64__
75e1c161e7SJustin Hibbits static void powermac_sleep(platform_t);
76b6d8f3b5SJustin Hibbits #endif
77b2a237beSNathan Whitehorn 
78b2a237beSNathan Whitehorn static platform_method_t powermac_methods[] = {
79b2a237beSNathan Whitehorn 	PLATFORMMETHOD(platform_probe, 		powermac_probe),
809f706727SNathan Whitehorn 	PLATFORMMETHOD(platform_attach,		powermac_attach),
81b2a237beSNathan Whitehorn 	PLATFORMMETHOD(platform_mem_regions,	powermac_mem_regions),
82b2a237beSNathan Whitehorn 	PLATFORMMETHOD(platform_timebase_freq,	powermac_timebase_freq),
83b2a237beSNathan Whitehorn 
84b2a237beSNathan Whitehorn 	PLATFORMMETHOD(platform_smp_first_cpu,	powermac_smp_first_cpu),
85b2a237beSNathan Whitehorn 	PLATFORMMETHOD(platform_smp_next_cpu,	powermac_smp_next_cpu),
86b2a237beSNathan Whitehorn 	PLATFORMMETHOD(platform_smp_get_bsp,	powermac_smp_get_bsp),
87b2a237beSNathan Whitehorn 	PLATFORMMETHOD(platform_smp_start_cpu,	powermac_smp_start_cpu),
88de2dd83fSNathan Whitehorn 	PLATFORMMETHOD(platform_smp_timebase_sync, powermac_smp_timebase_sync),
89b2a237beSNathan Whitehorn 
90b2a237beSNathan Whitehorn 	PLATFORMMETHOD(platform_reset,		powermac_reset),
91b6d8f3b5SJustin Hibbits #ifndef __powerpc64__
92e1c161e7SJustin Hibbits 	PLATFORMMETHOD(platform_sleep,		powermac_sleep),
93b6d8f3b5SJustin Hibbits #endif
94b2a237beSNathan Whitehorn 
95eaba9848SRui Paulo 	PLATFORMMETHOD_END
96b2a237beSNathan Whitehorn };
97b2a237beSNathan Whitehorn 
98b2a237beSNathan Whitehorn static platform_def_t powermac_platform = {
99b2a237beSNathan Whitehorn 	"powermac",
100b2a237beSNathan Whitehorn 	powermac_methods,
101b2a237beSNathan Whitehorn 	0
102b2a237beSNathan Whitehorn };
103b2a237beSNathan Whitehorn 
104b2a237beSNathan Whitehorn PLATFORM_DEF(powermac_platform);
105b2a237beSNathan Whitehorn 
106b2a237beSNathan Whitehorn static int
powermac_probe(platform_t plat)107b2a237beSNathan Whitehorn powermac_probe(platform_t plat)
108b2a237beSNathan Whitehorn {
1095d46492dSNathan Whitehorn 	char compat[255];
1105d46492dSNathan Whitehorn 	ssize_t compatlen;
1115d46492dSNathan Whitehorn 	char *curstr;
1125d46492dSNathan Whitehorn 	phandle_t root;
1135d46492dSNathan Whitehorn 
1145d46492dSNathan Whitehorn 	root = OF_peer(0);
1155d46492dSNathan Whitehorn 	if (root == 0)
1165d46492dSNathan Whitehorn 		return (ENXIO);
1175d46492dSNathan Whitehorn 
1185d46492dSNathan Whitehorn 	compatlen = OF_getprop(root, "compatible", compat, sizeof(compat));
1195d46492dSNathan Whitehorn 
1205d46492dSNathan Whitehorn 	for (curstr = compat; curstr < compat + compatlen;
1215d46492dSNathan Whitehorn 	    curstr += strlen(curstr) + 1) {
1225d46492dSNathan Whitehorn 		if (strncmp(curstr, "MacRISC", 7) == 0)
1235d46492dSNathan Whitehorn 			return (BUS_PROBE_SPECIFIC);
1245d46492dSNathan Whitehorn 	}
125b2a237beSNathan Whitehorn 
126b2a237beSNathan Whitehorn 	return (ENXIO);
127b2a237beSNathan Whitehorn }
128b2a237beSNathan Whitehorn 
129b2a237beSNathan Whitehorn void
powermac_mem_regions(platform_t plat,struct mem_region * phys,int * physsz,struct mem_region * avail,int * availsz)130c1cb22d7SNathan Whitehorn powermac_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
131c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz)
132b2a237beSNathan Whitehorn {
133c1cb22d7SNathan Whitehorn 	phandle_t memory;
134c1cb22d7SNathan Whitehorn 	cell_t memoryprop[PHYS_AVAIL_SZ * 2];
135c1cb22d7SNathan Whitehorn 	ssize_t propsize, i, j;
136c1cb22d7SNathan Whitehorn 	int physacells = 1;
137c1cb22d7SNathan Whitehorn 
138c1cb22d7SNathan Whitehorn 	memory = OF_finddevice("/memory");
139276df218SNathan Whitehorn 	if (memory == -1)
140276df218SNathan Whitehorn 		memory = OF_finddevice("/memory@0");
141c1cb22d7SNathan Whitehorn 
142c1cb22d7SNathan Whitehorn 	/* "reg" has variable #address-cells, but #size-cells is always 1 */
143c1cb22d7SNathan Whitehorn 	OF_getprop(OF_parent(memory), "#address-cells", &physacells,
144c1cb22d7SNathan Whitehorn 	    sizeof(physacells));
145c1cb22d7SNathan Whitehorn 
146c1cb22d7SNathan Whitehorn 	propsize = OF_getprop(memory, "reg", memoryprop, sizeof(memoryprop));
147c1cb22d7SNathan Whitehorn 	propsize /= sizeof(cell_t);
148c1cb22d7SNathan Whitehorn 	for (i = 0, j = 0; i < propsize; i += physacells+1, j++) {
149c1cb22d7SNathan Whitehorn 		phys[j].mr_start = memoryprop[i];
150c1cb22d7SNathan Whitehorn 		if (physacells == 2) {
151c1cb22d7SNathan Whitehorn #ifndef __powerpc64__
152c1cb22d7SNathan Whitehorn 			/* On 32-bit PPC, ignore regions starting above 4 GB */
153c1cb22d7SNathan Whitehorn 			if (memoryprop[i] != 0) {
154c1cb22d7SNathan Whitehorn 				j--;
155c1cb22d7SNathan Whitehorn 				continue;
156c1cb22d7SNathan Whitehorn 			}
157c1cb22d7SNathan Whitehorn #else
158c1cb22d7SNathan Whitehorn 			phys[j].mr_start <<= 32;
159c1cb22d7SNathan Whitehorn #endif
160c1cb22d7SNathan Whitehorn 			phys[j].mr_start |= memoryprop[i+1];
161c1cb22d7SNathan Whitehorn 		}
162c1cb22d7SNathan Whitehorn 		phys[j].mr_size = memoryprop[i + physacells];
163c1cb22d7SNathan Whitehorn 	}
164c1cb22d7SNathan Whitehorn 	*physsz = j;
165c1cb22d7SNathan Whitehorn 
166c1cb22d7SNathan Whitehorn 	/* "available" always has #address-cells = 1 */
167c1cb22d7SNathan Whitehorn 	propsize = OF_getprop(memory, "available", memoryprop,
168c1cb22d7SNathan Whitehorn 	    sizeof(memoryprop));
169276df218SNathan Whitehorn 	if (propsize <= 0) {
170276df218SNathan Whitehorn 		for (i = 0; i < *physsz; i++) {
171276df218SNathan Whitehorn 			avail[i].mr_start = phys[i].mr_start;
172276df218SNathan Whitehorn 			avail[i].mr_size = phys[i].mr_size;
173276df218SNathan Whitehorn 		}
174276df218SNathan Whitehorn 
175276df218SNathan Whitehorn 		*availsz = *physsz;
176276df218SNathan Whitehorn 	} else {
177c1cb22d7SNathan Whitehorn 		propsize /= sizeof(cell_t);
178c1cb22d7SNathan Whitehorn 		for (i = 0, j = 0; i < propsize; i += 2, j++) {
179c1cb22d7SNathan Whitehorn 			avail[j].mr_start = memoryprop[i];
180c1cb22d7SNathan Whitehorn 			avail[j].mr_size = memoryprop[i + 1];
181c1cb22d7SNathan Whitehorn 		}
182c1cb22d7SNathan Whitehorn 
183c1cb22d7SNathan Whitehorn #ifdef __powerpc64__
184c1cb22d7SNathan Whitehorn 		/* Add in regions above 4 GB to the available list */
185c1cb22d7SNathan Whitehorn 		for (i = 0; i < *physsz; i++) {
186c1cb22d7SNathan Whitehorn 			if (phys[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
187c1cb22d7SNathan Whitehorn 				avail[j].mr_start = phys[i].mr_start;
188c1cb22d7SNathan Whitehorn 				avail[j].mr_size = phys[i].mr_size;
189c1cb22d7SNathan Whitehorn 				j++;
190c1cb22d7SNathan Whitehorn 			}
191c1cb22d7SNathan Whitehorn 		}
192c1cb22d7SNathan Whitehorn #endif
193c1cb22d7SNathan Whitehorn 		*availsz = j;
194b2a237beSNathan Whitehorn 	}
195276df218SNathan Whitehorn }
196b2a237beSNathan Whitehorn 
1979f706727SNathan Whitehorn static int
powermac_attach(platform_t plat)1989f706727SNathan Whitehorn powermac_attach(platform_t plat)
1999f706727SNathan Whitehorn {
2009f706727SNathan Whitehorn 	phandle_t rootnode;
2019f706727SNathan Whitehorn 	char model[32];
2029f706727SNathan Whitehorn 
2039f706727SNathan Whitehorn 	/*
2049f706727SNathan Whitehorn 	 * Quiesce Open Firmware on PowerMac11,2 and 12,1. It is
2059f706727SNathan Whitehorn 	 * necessary there to shut down a background thread doing fan
2069f706727SNathan Whitehorn 	 * management, and is harmful on other machines (it will make OF
2079f706727SNathan Whitehorn 	 * shut off power to various system components it had turned on).
2089f706727SNathan Whitehorn 	 *
2099f706727SNathan Whitehorn 	 * Note: we don't need to worry about which OF module we are
2109f706727SNathan Whitehorn 	 * using since this is called only from very early boot, within
2119f706727SNathan Whitehorn 	 * OF's boot context.
2129f706727SNathan Whitehorn 	 */
2139f706727SNathan Whitehorn 
2149f706727SNathan Whitehorn 	rootnode = OF_finddevice("/");
2159f706727SNathan Whitehorn 	if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) {
2169f706727SNathan Whitehorn 		if (strcmp(model, "PowerMac11,2") == 0 ||
2179f706727SNathan Whitehorn 		    strcmp(model, "PowerMac12,1") == 0) {
2189f706727SNathan Whitehorn 			ofw_quiesce();
2199f706727SNathan Whitehorn 		}
2209f706727SNathan Whitehorn 	}
2219f706727SNathan Whitehorn 
2229f706727SNathan Whitehorn 	return (0);
2239f706727SNathan Whitehorn }
2249f706727SNathan Whitehorn 
225b2a237beSNathan Whitehorn static u_long
powermac_timebase_freq(platform_t plat,struct cpuref * cpuref)226b2a237beSNathan Whitehorn powermac_timebase_freq(platform_t plat, struct cpuref *cpuref)
227b2a237beSNathan Whitehorn {
228b2a237beSNathan Whitehorn 	phandle_t phandle;
229b2a237beSNathan Whitehorn 	int32_t ticks = -1;
230b2a237beSNathan Whitehorn 
231b2a237beSNathan Whitehorn 	phandle = cpuref->cr_hwref;
232b2a237beSNathan Whitehorn 
233b2a237beSNathan Whitehorn 	OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks));
234b2a237beSNathan Whitehorn 
235b2a237beSNathan Whitehorn 	if (ticks <= 0)
236b2a237beSNathan Whitehorn 		panic("Unable to determine timebase frequency!");
237b2a237beSNathan Whitehorn 
238b2a237beSNathan Whitehorn 	return (ticks);
239b2a237beSNathan Whitehorn }
240b2a237beSNathan Whitehorn 
241b2a237beSNathan Whitehorn static int
powermac_smp_fill_cpuref(struct cpuref * cpuref,phandle_t cpu)242b2a237beSNathan Whitehorn powermac_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu)
243b2a237beSNathan Whitehorn {
244e17bec91SJustin Hibbits 	cell_t cpuid;
245e17bec91SJustin Hibbits 	int res;
246b2a237beSNathan Whitehorn 
247b2a237beSNathan Whitehorn 	cpuref->cr_hwref = cpu;
248b2a237beSNathan Whitehorn 	res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
249b2a237beSNathan Whitehorn 
250b2a237beSNathan Whitehorn 	/*
251b2a237beSNathan Whitehorn 	 * psim doesn't have a reg property, so assume 0 as for the
252b2a237beSNathan Whitehorn 	 * uniprocessor case in the CHRP spec.
253b2a237beSNathan Whitehorn 	 */
254b2a237beSNathan Whitehorn 	if (res < 0) {
255b2a237beSNathan Whitehorn 		cpuid = 0;
256b2a237beSNathan Whitehorn 	}
257b2a237beSNathan Whitehorn 
258b2a237beSNathan Whitehorn 	cpuref->cr_cpuid = cpuid & 0xff;
259b2a237beSNathan Whitehorn 	return (0);
260b2a237beSNathan Whitehorn }
261b2a237beSNathan Whitehorn 
262b2a237beSNathan Whitehorn static int
powermac_smp_first_cpu(platform_t plat,struct cpuref * cpuref)263b2a237beSNathan Whitehorn powermac_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
264b2a237beSNathan Whitehorn {
265b2a237beSNathan Whitehorn 	char buf[8];
266b2a237beSNathan Whitehorn 	phandle_t cpu, dev, root;
267b2a237beSNathan Whitehorn 	int res;
268b2a237beSNathan Whitehorn 
269b2a237beSNathan Whitehorn 	root = OF_peer(0);
270b2a237beSNathan Whitehorn 
271b2a237beSNathan Whitehorn 	dev = OF_child(root);
272b2a237beSNathan Whitehorn 	while (dev != 0) {
273b2a237beSNathan Whitehorn 		res = OF_getprop(dev, "name", buf, sizeof(buf));
274b2a237beSNathan Whitehorn 		if (res > 0 && strcmp(buf, "cpus") == 0)
275b2a237beSNathan Whitehorn 			break;
276b2a237beSNathan Whitehorn 		dev = OF_peer(dev);
277b2a237beSNathan Whitehorn 	}
278b2a237beSNathan Whitehorn 	if (dev == 0) {
279b2a237beSNathan Whitehorn 		/*
280b2a237beSNathan Whitehorn 		 * psim doesn't have a name property on the /cpus node,
281b2a237beSNathan Whitehorn 		 * but it can be found directly
282b2a237beSNathan Whitehorn 		 */
283b2a237beSNathan Whitehorn 		dev = OF_finddevice("/cpus");
28407042befSJayachandran C. 		if (dev == -1)
285b2a237beSNathan Whitehorn 			return (ENOENT);
286b2a237beSNathan Whitehorn 	}
287b2a237beSNathan Whitehorn 
288b2a237beSNathan Whitehorn 	cpu = OF_child(dev);
289b2a237beSNathan Whitehorn 
290b2a237beSNathan Whitehorn 	while (cpu != 0) {
291b2a237beSNathan Whitehorn 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
292b2a237beSNathan Whitehorn 		if (res > 0 && strcmp(buf, "cpu") == 0)
293b2a237beSNathan Whitehorn 			break;
294b2a237beSNathan Whitehorn 		cpu = OF_peer(cpu);
295b2a237beSNathan Whitehorn 	}
296b2a237beSNathan Whitehorn 	if (cpu == 0)
297b2a237beSNathan Whitehorn 		return (ENOENT);
298b2a237beSNathan Whitehorn 
299b2a237beSNathan Whitehorn 	return (powermac_smp_fill_cpuref(cpuref, cpu));
300b2a237beSNathan Whitehorn }
301b2a237beSNathan Whitehorn 
302b2a237beSNathan Whitehorn static int
powermac_smp_next_cpu(platform_t plat,struct cpuref * cpuref)303b2a237beSNathan Whitehorn powermac_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
304b2a237beSNathan Whitehorn {
305b2a237beSNathan Whitehorn 	char buf[8];
306b2a237beSNathan Whitehorn 	phandle_t cpu;
307b2a237beSNathan Whitehorn 	int res;
308b2a237beSNathan Whitehorn 
309b2a237beSNathan Whitehorn 	cpu = OF_peer(cpuref->cr_hwref);
310b2a237beSNathan Whitehorn 	while (cpu != 0) {
311b2a237beSNathan Whitehorn 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
312b2a237beSNathan Whitehorn 		if (res > 0 && strcmp(buf, "cpu") == 0)
313b2a237beSNathan Whitehorn 			break;
314b2a237beSNathan Whitehorn 		cpu = OF_peer(cpu);
315b2a237beSNathan Whitehorn 	}
316b2a237beSNathan Whitehorn 	if (cpu == 0)
317b2a237beSNathan Whitehorn 		return (ENOENT);
318b2a237beSNathan Whitehorn 
319b2a237beSNathan Whitehorn 	return (powermac_smp_fill_cpuref(cpuref, cpu));
320b2a237beSNathan Whitehorn }
321b2a237beSNathan Whitehorn 
322b2a237beSNathan Whitehorn static int
powermac_smp_get_bsp(platform_t plat,struct cpuref * cpuref)323b2a237beSNathan Whitehorn powermac_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
324b2a237beSNathan Whitehorn {
325b2a237beSNathan Whitehorn 	ihandle_t inst;
326b2a237beSNathan Whitehorn 	phandle_t bsp, chosen;
327b2a237beSNathan Whitehorn 	int res;
328b2a237beSNathan Whitehorn 
329b2a237beSNathan Whitehorn 	chosen = OF_finddevice("/chosen");
33007042befSJayachandran C. 	if (chosen == -1)
331b2a237beSNathan Whitehorn 		return (ENXIO);
332b2a237beSNathan Whitehorn 
333b2a237beSNathan Whitehorn 	res = OF_getprop(chosen, "cpu", &inst, sizeof(inst));
334b2a237beSNathan Whitehorn 	if (res < 0)
335b2a237beSNathan Whitehorn 		return (ENXIO);
336b2a237beSNathan Whitehorn 
337b2a237beSNathan Whitehorn 	bsp = OF_instance_to_package(inst);
338b2a237beSNathan Whitehorn 	return (powermac_smp_fill_cpuref(cpuref, bsp));
339b2a237beSNathan Whitehorn }
340b2a237beSNathan Whitehorn 
341b2a237beSNathan Whitehorn static int
powermac_smp_start_cpu(platform_t plat,struct pcpu * pc)342b2a237beSNathan Whitehorn powermac_smp_start_cpu(platform_t plat, struct pcpu *pc)
343b2a237beSNathan Whitehorn {
344b2a237beSNathan Whitehorn #ifdef SMP
345b2a237beSNathan Whitehorn 	phandle_t cpu;
346b2a237beSNathan Whitehorn 	volatile uint8_t *rstvec;
347b2a237beSNathan Whitehorn 	static volatile uint8_t *rstvec_virtbase = NULL;
348b2a237beSNathan Whitehorn 	int res, reset, timeout;
349b2a237beSNathan Whitehorn 
350b2a237beSNathan Whitehorn 	cpu = pc->pc_hwref;
351b2a237beSNathan Whitehorn 	res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset));
352b2a237beSNathan Whitehorn 	if (res < 0) {
353b2a237beSNathan Whitehorn 		reset = 0x58;
354b2a237beSNathan Whitehorn 
355b2a237beSNathan Whitehorn 		switch (pc->pc_cpuid) {
356b2a237beSNathan Whitehorn 		case 0:
357b2a237beSNathan Whitehorn 			reset += 0x03;
358b2a237beSNathan Whitehorn 			break;
359b2a237beSNathan Whitehorn 		case 1:
360b2a237beSNathan Whitehorn 			reset += 0x04;
361b2a237beSNathan Whitehorn 			break;
362b2a237beSNathan Whitehorn 		case 2:
363b2a237beSNathan Whitehorn 			reset += 0x0f;
364b2a237beSNathan Whitehorn 			break;
365b2a237beSNathan Whitehorn 		case 3:
366b2a237beSNathan Whitehorn 			reset += 0x10;
367b2a237beSNathan Whitehorn 			break;
368b2a237beSNathan Whitehorn 		default:
369b2a237beSNathan Whitehorn 			return (ENXIO);
370b2a237beSNathan Whitehorn 		}
371b2a237beSNathan Whitehorn 	}
372b2a237beSNathan Whitehorn 
373b2a237beSNathan Whitehorn 	ap_pcpu = pc;
374b2a237beSNathan Whitehorn 
375b2a237beSNathan Whitehorn 	if (rstvec_virtbase == NULL)
376b2a237beSNathan Whitehorn 		rstvec_virtbase = pmap_mapdev(0x80000000, PAGE_SIZE);
377b2a237beSNathan Whitehorn 
378b2a237beSNathan Whitehorn 	rstvec = rstvec_virtbase + reset;
379b2a237beSNathan Whitehorn 
380b2a237beSNathan Whitehorn 	*rstvec = 4;
381b2a237beSNathan Whitehorn 	powerpc_sync();
382b2a237beSNathan Whitehorn 	(void)(*rstvec);
383b2a237beSNathan Whitehorn 	powerpc_sync();
384b2a237beSNathan Whitehorn 	DELAY(1);
385b2a237beSNathan Whitehorn 	*rstvec = 0;
386b2a237beSNathan Whitehorn 	powerpc_sync();
387b2a237beSNathan Whitehorn 	(void)(*rstvec);
388b2a237beSNathan Whitehorn 	powerpc_sync();
389b2a237beSNathan Whitehorn 
390b2a237beSNathan Whitehorn 	timeout = 10000;
391b2a237beSNathan Whitehorn 	while (!pc->pc_awake && timeout--)
392b2a237beSNathan Whitehorn 		DELAY(100);
393b2a237beSNathan Whitehorn 
394b2a237beSNathan Whitehorn 	return ((pc->pc_awake) ? 0 : EBUSY);
395b2a237beSNathan Whitehorn #else
396b2a237beSNathan Whitehorn 	/* No SMP support */
397b2a237beSNathan Whitehorn 	return (ENXIO);
398b2a237beSNathan Whitehorn #endif
399b2a237beSNathan Whitehorn }
400b2a237beSNathan Whitehorn 
401c583b025SBrandon Bergren void
powermac_register_timebase(device_t dev,powermac_tb_disable_t cb)402c583b025SBrandon Bergren powermac_register_timebase(device_t dev, powermac_tb_disable_t cb)
403c583b025SBrandon Bergren {
404c583b025SBrandon Bergren 	powermac_tb_dev = dev;
405c583b025SBrandon Bergren 	freeze_timebase = cb;
406c583b025SBrandon Bergren }
407c583b025SBrandon Bergren 
408b2a237beSNathan Whitehorn static void
powermac_smp_timebase_sync(platform_t plat,u_long tb,int ap)409de2dd83fSNathan Whitehorn powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap)
410de2dd83fSNathan Whitehorn {
411c583b025SBrandon Bergren 	static volatile bool tb_ready;
412c583b025SBrandon Bergren 	static volatile int cpu_done;
413de2dd83fSNathan Whitehorn 
414c583b025SBrandon Bergren 	/*
415c583b025SBrandon Bergren 	 * XXX Temporary fallback for platforms we don't know how to freeze.
416c583b025SBrandon Bergren 	 *
417c583b025SBrandon Bergren 	 * This needs to be replaced with a cpu-to-cpu software sync
418c583b025SBrandon Bergren 	 * protocol, because this is not a consistent way to sync timebase.
419c583b025SBrandon Bergren 	 */
420de2dd83fSNathan Whitehorn 	mttb(tb);
421c583b025SBrandon Bergren 	if (freeze_timebase == dummy_timebase)
422c583b025SBrandon Bergren 		return;
423c583b025SBrandon Bergren 
424c583b025SBrandon Bergren 	if (ap) {
425c583b025SBrandon Bergren 		/* APs.  Hold off until we get a stable timebase. */
426c583b025SBrandon Bergren 		critical_enter();
427c583b025SBrandon Bergren 		while (!tb_ready)
428c583b025SBrandon Bergren 			atomic_thread_fence_seq_cst();
429c583b025SBrandon Bergren 		mttb(tb);
430c583b025SBrandon Bergren 		atomic_add_int(&cpu_done, 1);
431c583b025SBrandon Bergren 		while (cpu_done < mp_ncpus)
432c583b025SBrandon Bergren 			atomic_thread_fence_seq_cst();
433c583b025SBrandon Bergren 		critical_exit();
434c583b025SBrandon Bergren 	} else {
435c583b025SBrandon Bergren 		/* BSP */
436c583b025SBrandon Bergren 		critical_enter();
437c583b025SBrandon Bergren 		/* Ensure cpu_done is zeroed so we can resync at runtime */
438c583b025SBrandon Bergren 		atomic_set_int(&cpu_done, 0);
439c583b025SBrandon Bergren 		freeze_timebase(powermac_tb_dev, true);
440c583b025SBrandon Bergren 		tb_ready = true;
441c583b025SBrandon Bergren 		mttb(tb);
442c583b025SBrandon Bergren 		atomic_add_int(&cpu_done, 1);
443c583b025SBrandon Bergren 		while (cpu_done < mp_ncpus)
444c583b025SBrandon Bergren 			atomic_thread_fence_seq_cst();
445c583b025SBrandon Bergren 		freeze_timebase(powermac_tb_dev, false);
446c583b025SBrandon Bergren 		/* Reset tb_ready so we can resync at runtime */
447c583b025SBrandon Bergren 		tb_ready = false;
448c583b025SBrandon Bergren 		critical_exit();
449c583b025SBrandon Bergren 	}
450c583b025SBrandon Bergren }
451c583b025SBrandon Bergren 
452c583b025SBrandon Bergren /* Fallback freeze. In case no real handler is found in the device tree. */
453c583b025SBrandon Bergren static void
dummy_timebase(device_t dev,bool freeze)454c583b025SBrandon Bergren dummy_timebase(device_t dev, bool freeze)
455c583b025SBrandon Bergren {
456c583b025SBrandon Bergren 	/* Nothing to do here, move along. */
457de2dd83fSNathan Whitehorn }
458de2dd83fSNathan Whitehorn 
459de2dd83fSNathan Whitehorn static void
powermac_reset(platform_t platform)460b2a237beSNathan Whitehorn powermac_reset(platform_t platform)
461b2a237beSNathan Whitehorn {
462b2a237beSNathan Whitehorn 	OF_reboot();
463b2a237beSNathan Whitehorn }
464b2a237beSNathan Whitehorn 
465b6d8f3b5SJustin Hibbits #ifndef __powerpc64__
466e1c161e7SJustin Hibbits void
powermac_sleep(platform_t platform)467e1c161e7SJustin Hibbits powermac_sleep(platform_t platform)
468e1c161e7SJustin Hibbits {
469b6d8f3b5SJustin Hibbits 	/* Only supports MPC745x for now. */
470b6d8f3b5SJustin Hibbits 	if (!MPC745X_P(mfspr(SPR_PVR) >> 16)) {
471b6d8f3b5SJustin Hibbits 		printf("sleep only supported for G4 PowerMac hardware.\n");
472b6d8f3b5SJustin Hibbits 		return;
473b6d8f3b5SJustin Hibbits 	}
474e1c161e7SJustin Hibbits 
475e1c161e7SJustin Hibbits 	*(unsigned long *)0x80 = 0x100;
476b6d8f3b5SJustin Hibbits 	mpc745x_sleep();
477e1c161e7SJustin Hibbits }
478b6d8f3b5SJustin Hibbits #endif
479