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