platform_powermac.c revision 198378
1192067Snwhitehorn/*-
2192067Snwhitehorn * Copyright (c) 2008 Marcel Moolenaar
3192067Snwhitehorn * Copyright (c) 2009 Nathan Whitehorn
4192067Snwhitehorn * All rights reserved.
5192067Snwhitehorn *
6192067Snwhitehorn * Redistribution and use in source and binary forms, with or without
7192067Snwhitehorn * modification, are permitted provided that the following conditions
8192067Snwhitehorn * are met:
9192067Snwhitehorn *
10192067Snwhitehorn * 1. Redistributions of source code must retain the above copyright
11192067Snwhitehorn *    notice, this list of conditions and the following disclaimer.
12192067Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
13192067Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
14192067Snwhitehorn *    documentation and/or other materials provided with the distribution.
15192067Snwhitehorn *
16192067Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17192067Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18192067Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19192067Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20192067Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21192067Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22192067Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23192067Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24192067Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25192067Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26192067Snwhitehorn */
27192067Snwhitehorn
28192067Snwhitehorn#include <sys/cdefs.h>
29192067Snwhitehorn__FBSDID("$FreeBSD: head/sys/powerpc/aim/platform_chrp.c 198378 2009-10-23 03:17:02Z nwhitehorn $");
30192067Snwhitehorn
31192067Snwhitehorn#include <sys/param.h>
32192067Snwhitehorn#include <sys/systm.h>
33192067Snwhitehorn#include <sys/kernel.h>
34192067Snwhitehorn#include <sys/bus.h>
35192067Snwhitehorn#include <sys/pcpu.h>
36192067Snwhitehorn#include <sys/proc.h>
37192067Snwhitehorn#include <sys/smp.h>
38198212Snwhitehorn#include <vm/vm.h>
39198212Snwhitehorn#include <vm/pmap.h>
40192067Snwhitehorn
41192067Snwhitehorn#include <machine/bus.h>
42192067Snwhitehorn#include <machine/cpu.h>
43192067Snwhitehorn#include <machine/hid.h>
44192067Snwhitehorn#include <machine/platformvar.h>
45198212Snwhitehorn#include <machine/pmap.h>
46192067Snwhitehorn#include <machine/smp.h>
47192067Snwhitehorn#include <machine/spr.h>
48192067Snwhitehorn
49192067Snwhitehorn#include <dev/ofw/openfirm.h>
50192067Snwhitehorn#include <machine/ofw_machdep.h>
51192067Snwhitehorn
52192067Snwhitehorn#include "platform_if.h"
53192067Snwhitehorn
54192067Snwhitehorn#ifdef SMP
55192067Snwhitehornextern void *ap_pcpu;
56192067Snwhitehorn#endif
57192067Snwhitehorn
58192067Snwhitehornstatic int chrp_probe(platform_t);
59192067Snwhitehornvoid chrp_mem_regions(platform_t, struct mem_region **phys, int *physsz,
60192067Snwhitehorn    struct mem_region **avail, int *availsz);
61192067Snwhitehornstatic u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref);
62192067Snwhitehornstatic int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref);
63192067Snwhitehornstatic int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref);
64192067Snwhitehornstatic int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref);
65192067Snwhitehornstatic int chrp_smp_start_cpu(platform_t, struct pcpu *cpu);
66192067Snwhitehorn
67192067Snwhitehornstatic platform_method_t chrp_methods[] = {
68192067Snwhitehorn	PLATFORMMETHOD(platform_probe, 		chrp_probe),
69192067Snwhitehorn	PLATFORMMETHOD(platform_mem_regions,	chrp_mem_regions),
70192067Snwhitehorn	PLATFORMMETHOD(platform_timebase_freq,	chrp_timebase_freq),
71192067Snwhitehorn
72192067Snwhitehorn	PLATFORMMETHOD(platform_smp_first_cpu,	chrp_smp_first_cpu),
73192067Snwhitehorn	PLATFORMMETHOD(platform_smp_next_cpu,	chrp_smp_next_cpu),
74192067Snwhitehorn	PLATFORMMETHOD(platform_smp_get_bsp,	chrp_smp_get_bsp),
75192067Snwhitehorn	PLATFORMMETHOD(platform_smp_start_cpu,	chrp_smp_start_cpu),
76192067Snwhitehorn
77192067Snwhitehorn	{ 0, 0 }
78192067Snwhitehorn};
79192067Snwhitehorn
80192067Snwhitehornstatic platform_def_t chrp_platform = {
81192067Snwhitehorn	"chrp",
82192067Snwhitehorn	chrp_methods,
83192067Snwhitehorn	0
84192067Snwhitehorn};
85192067Snwhitehorn
86192067SnwhitehornPLATFORM_DEF(chrp_platform);
87192067Snwhitehorn
88192067Snwhitehornstatic int
89192067Snwhitehornchrp_probe(platform_t plat)
90192067Snwhitehorn{
91192067Snwhitehorn	if (OF_finddevice("/memory") != -1)
92192067Snwhitehorn		return (BUS_PROBE_GENERIC);
93192067Snwhitehorn
94192067Snwhitehorn	return (ENXIO);
95192067Snwhitehorn}
96192067Snwhitehorn
97192067Snwhitehornvoid
98192067Snwhitehornchrp_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
99192067Snwhitehorn    struct mem_region **avail, int *availsz)
100192067Snwhitehorn{
101192067Snwhitehorn	ofw_mem_regions(phys,physsz,avail,availsz);
102192067Snwhitehorn}
103192067Snwhitehorn
104192067Snwhitehornstatic u_long
105192067Snwhitehornchrp_timebase_freq(platform_t plat, struct cpuref *cpuref)
106192067Snwhitehorn{
107192067Snwhitehorn	phandle_t phandle;
108193909Sgrehan	long ticks = -1;
109192067Snwhitehorn
110192067Snwhitehorn	phandle = cpuref->cr_hwref;
111192067Snwhitehorn
112192067Snwhitehorn	OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks));
113192067Snwhitehorn
114192067Snwhitehorn	if (ticks <= 0)
115192067Snwhitehorn		panic("Unable to determine timebase frequency!");
116192067Snwhitehorn
117192067Snwhitehorn	return (ticks);
118192067Snwhitehorn}
119192067Snwhitehorn
120192067Snwhitehorn
121192067Snwhitehornstatic int
122192067Snwhitehornchrp_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu)
123192067Snwhitehorn{
124192067Snwhitehorn	int cpuid, res;
125192067Snwhitehorn
126192067Snwhitehorn	cpuref->cr_hwref = cpu;
127192067Snwhitehorn	res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
128192067Snwhitehorn
129193909Sgrehan	/*
130193909Sgrehan	 * psim doesn't have a reg property, so assume 0 as for the
131193909Sgrehan	 * uniprocessor case in the CHRP spec.
132193909Sgrehan	 */
133193909Sgrehan	if (res < 0) {
134193909Sgrehan		cpuid = 0;
135193909Sgrehan	}
136193909Sgrehan
137192067Snwhitehorn	cpuref->cr_cpuid = cpuid & 0xff;
138192067Snwhitehorn	return (0);
139192067Snwhitehorn}
140192067Snwhitehorn
141192067Snwhitehornstatic int
142192067Snwhitehornchrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
143192067Snwhitehorn{
144192067Snwhitehorn	char buf[8];
145192067Snwhitehorn	phandle_t cpu, dev, root;
146192067Snwhitehorn	int res;
147192067Snwhitehorn
148192067Snwhitehorn	root = OF_peer(0);
149192067Snwhitehorn
150192067Snwhitehorn	dev = OF_child(root);
151192067Snwhitehorn	while (dev != 0) {
152192067Snwhitehorn		res = OF_getprop(dev, "name", buf, sizeof(buf));
153192067Snwhitehorn		if (res > 0 && strcmp(buf, "cpus") == 0)
154192067Snwhitehorn			break;
155192067Snwhitehorn		dev = OF_peer(dev);
156192067Snwhitehorn	}
157193909Sgrehan	if (dev == 0) {
158193909Sgrehan		/*
159193909Sgrehan		 * psim doesn't have a name property on the /cpus node,
160193909Sgrehan		 * but it can be found directly
161193909Sgrehan		 */
162193909Sgrehan		dev = OF_finddevice("/cpus");
163193909Sgrehan		if (dev == 0)
164193909Sgrehan			return (ENOENT);
165193909Sgrehan	}
166192067Snwhitehorn
167192067Snwhitehorn	cpu = OF_child(dev);
168193909Sgrehan
169192067Snwhitehorn	while (cpu != 0) {
170192067Snwhitehorn		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
171192067Snwhitehorn		if (res > 0 && strcmp(buf, "cpu") == 0)
172192067Snwhitehorn			break;
173192067Snwhitehorn		cpu = OF_peer(cpu);
174192067Snwhitehorn	}
175192067Snwhitehorn	if (cpu == 0)
176192067Snwhitehorn		return (ENOENT);
177192067Snwhitehorn
178192067Snwhitehorn	return (chrp_smp_fill_cpuref(cpuref, cpu));
179192067Snwhitehorn}
180192067Snwhitehorn
181192067Snwhitehornstatic int
182192067Snwhitehornchrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
183192067Snwhitehorn{
184192067Snwhitehorn	char buf[8];
185192067Snwhitehorn	phandle_t cpu;
186192067Snwhitehorn	int res;
187192067Snwhitehorn
188192067Snwhitehorn	cpu = OF_peer(cpuref->cr_hwref);
189192067Snwhitehorn	while (cpu != 0) {
190192067Snwhitehorn		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
191192067Snwhitehorn		if (res > 0 && strcmp(buf, "cpu") == 0)
192192067Snwhitehorn			break;
193192067Snwhitehorn		cpu = OF_peer(cpu);
194192067Snwhitehorn	}
195192067Snwhitehorn	if (cpu == 0)
196192067Snwhitehorn		return (ENOENT);
197192067Snwhitehorn
198192067Snwhitehorn	return (chrp_smp_fill_cpuref(cpuref, cpu));
199192067Snwhitehorn}
200192067Snwhitehorn
201192067Snwhitehornstatic int
202192067Snwhitehornchrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
203192067Snwhitehorn{
204192067Snwhitehorn	ihandle_t inst;
205192067Snwhitehorn	phandle_t bsp, chosen;
206192067Snwhitehorn	int res;
207192067Snwhitehorn
208192067Snwhitehorn	chosen = OF_finddevice("/chosen");
209192067Snwhitehorn	if (chosen == 0)
210192067Snwhitehorn		return (ENXIO);
211192067Snwhitehorn
212192067Snwhitehorn	res = OF_getprop(chosen, "cpu", &inst, sizeof(inst));
213192067Snwhitehorn	if (res < 0)
214192067Snwhitehorn		return (ENXIO);
215192067Snwhitehorn
216192067Snwhitehorn	bsp = OF_instance_to_package(inst);
217192067Snwhitehorn	return (chrp_smp_fill_cpuref(cpuref, bsp));
218192067Snwhitehorn}
219192067Snwhitehorn
220192067Snwhitehornstatic int
221192067Snwhitehornchrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
222192067Snwhitehorn{
223192067Snwhitehorn#ifdef SMP
224192067Snwhitehorn	phandle_t cpu;
225192067Snwhitehorn	volatile uint8_t *rstvec;
226198212Snwhitehorn	static volatile uint8_t *rstvec_virtbase = NULL;
227192067Snwhitehorn	int res, reset, timeout;
228192067Snwhitehorn
229192067Snwhitehorn	cpu = pc->pc_hwref;
230192067Snwhitehorn	res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset));
231192067Snwhitehorn	if (res < 0)
232192067Snwhitehorn		return (ENXIO);
233192067Snwhitehorn
234192067Snwhitehorn	ap_pcpu = pc;
235192067Snwhitehorn
236198212Snwhitehorn	if (rstvec_virtbase == NULL)
237198212Snwhitehorn		rstvec_virtbase = pmap_mapdev(0x80000000, PAGE_SIZE);
238192067Snwhitehorn
239198212Snwhitehorn	rstvec = rstvec_virtbase + reset;
240198212Snwhitehorn
241192067Snwhitehorn	*rstvec = 4;
242198378Snwhitehorn	(void)(*rstvec);
243192067Snwhitehorn	powerpc_sync();
244192067Snwhitehorn	DELAY(1);
245192067Snwhitehorn	*rstvec = 0;
246198378Snwhitehorn	(void)(*rstvec);
247192067Snwhitehorn	powerpc_sync();
248192067Snwhitehorn
249198378Snwhitehorn	timeout = 10000;
250192067Snwhitehorn	while (!pc->pc_awake && timeout--)
251192067Snwhitehorn		DELAY(100);
252192067Snwhitehorn
253192067Snwhitehorn	return ((pc->pc_awake) ? 0 : EBUSY);
254192067Snwhitehorn#else
255192067Snwhitehorn	/* No SMP support */
256192067Snwhitehorn	return (ENXIO);
257192067Snwhitehorn#endif
258192067Snwhitehorn}
259192067Snwhitehorn
260