platform_powermac.c revision 192067
1/*-
2 * Copyright (c) 2008 Marcel Moolenaar
3 * Copyright (c) 2009 Nathan Whitehorn
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/powerpc/aim/platform_chrp.c 192067 2009-05-14 00:34:26Z nwhitehorn $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/bus.h>
35#include <sys/pcpu.h>
36#include <sys/proc.h>
37#include <sys/smp.h>
38
39#include <machine/bus.h>
40#include <machine/cpu.h>
41#include <machine/hid.h>
42#include <machine/platformvar.h>
43#include <machine/smp.h>
44#include <machine/spr.h>
45
46#include <dev/ofw/openfirm.h>
47#include <machine/ofw_machdep.h>
48
49#include "platform_if.h"
50
51#ifdef SMP
52extern void *ap_pcpu;
53#endif
54
55static int chrp_probe(platform_t);
56void chrp_mem_regions(platform_t, struct mem_region **phys, int *physsz,
57    struct mem_region **avail, int *availsz);
58static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref);
59static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref);
60static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref);
61static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref);
62static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu);
63
64static platform_method_t chrp_methods[] = {
65	PLATFORMMETHOD(platform_probe, 		chrp_probe),
66	PLATFORMMETHOD(platform_mem_regions,	chrp_mem_regions),
67	PLATFORMMETHOD(platform_timebase_freq,	chrp_timebase_freq),
68
69	PLATFORMMETHOD(platform_smp_first_cpu,	chrp_smp_first_cpu),
70	PLATFORMMETHOD(platform_smp_next_cpu,	chrp_smp_next_cpu),
71	PLATFORMMETHOD(platform_smp_get_bsp,	chrp_smp_get_bsp),
72	PLATFORMMETHOD(platform_smp_start_cpu,	chrp_smp_start_cpu),
73
74	{ 0, 0 }
75};
76
77static platform_def_t chrp_platform = {
78	"chrp",
79	chrp_methods,
80	0
81};
82
83PLATFORM_DEF(chrp_platform);
84
85static int
86chrp_probe(platform_t plat)
87{
88	if (OF_finddevice("/memory") != -1)
89		return (BUS_PROBE_GENERIC);
90
91	return (ENXIO);
92}
93
94void
95chrp_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
96    struct mem_region **avail, int *availsz)
97{
98	ofw_mem_regions(phys,physsz,avail,availsz);
99}
100
101static u_long
102chrp_timebase_freq(platform_t plat, struct cpuref *cpuref)
103{
104	phandle_t phandle;
105	u_long ticks = -1;
106
107	phandle = cpuref->cr_hwref;
108
109	OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks));
110
111	if (ticks <= 0)
112		panic("Unable to determine timebase frequency!");
113
114	return (ticks);
115}
116
117
118static int
119chrp_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu)
120{
121	int cpuid, res;
122
123	cpuref->cr_hwref = cpu;
124	res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
125	if (res < 0)
126		return (ENOENT);
127
128	cpuref->cr_cpuid = cpuid & 0xff;
129	return (0);
130}
131
132static int
133chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
134{
135	char buf[8];
136	phandle_t cpu, dev, root;
137	int res;
138
139	root = OF_peer(0);
140
141	dev = OF_child(root);
142	while (dev != 0) {
143		res = OF_getprop(dev, "name", buf, sizeof(buf));
144		if (res > 0 && strcmp(buf, "cpus") == 0)
145			break;
146		dev = OF_peer(dev);
147	}
148	if (dev == 0)
149		return (ENOENT);
150
151	cpu = OF_child(dev);
152	while (cpu != 0) {
153		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
154		if (res > 0 && strcmp(buf, "cpu") == 0)
155			break;
156		cpu = OF_peer(cpu);
157	}
158	if (cpu == 0)
159		return (ENOENT);
160
161	return (chrp_smp_fill_cpuref(cpuref, cpu));
162}
163
164static int
165chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
166{
167	char buf[8];
168	phandle_t cpu;
169	int res;
170
171	cpu = OF_peer(cpuref->cr_hwref);
172	while (cpu != 0) {
173		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
174		if (res > 0 && strcmp(buf, "cpu") == 0)
175			break;
176		cpu = OF_peer(cpu);
177	}
178	if (cpu == 0)
179		return (ENOENT);
180
181	return (chrp_smp_fill_cpuref(cpuref, cpu));
182}
183
184static int
185chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
186{
187	ihandle_t inst;
188	phandle_t bsp, chosen;
189	int res;
190
191	chosen = OF_finddevice("/chosen");
192	if (chosen == 0)
193		return (ENXIO);
194
195	res = OF_getprop(chosen, "cpu", &inst, sizeof(inst));
196	if (res < 0)
197		return (ENXIO);
198
199	bsp = OF_instance_to_package(inst);
200	return (chrp_smp_fill_cpuref(cpuref, bsp));
201}
202
203static int
204chrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
205{
206#ifdef SMP
207	phandle_t cpu;
208	volatile uint8_t *rstvec;
209	int res, reset, timeout;
210
211	cpu = pc->pc_hwref;
212	res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset));
213	if (res < 0)
214		return (ENXIO);
215
216	ap_pcpu = pc;
217
218	rstvec = (uint8_t *)(0x80000000 + reset);
219
220	*rstvec = 4;
221	powerpc_sync();
222	DELAY(1);
223	*rstvec = 0;
224	powerpc_sync();
225
226	timeout = 1000;
227	while (!pc->pc_awake && timeout--)
228		DELAY(100);
229
230	return ((pc->pc_awake) ? 0 : EBUSY);
231#else
232	/* No SMP support */
233	return (ENXIO);
234#endif
235}
236
237