1110386Sbenno/*-
2110386Sbenno * Copyright (c) 2001 Matt Thomas.
3110386Sbenno * Copyright (c) 2001 Tsubai Masanari.
4110386Sbenno * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc.
5110386Sbenno * All rights reserved.
6110386Sbenno *
7110386Sbenno * Redistribution and use in source and binary forms, with or without
8110386Sbenno * modification, are permitted provided that the following conditions
9110386Sbenno * are met:
10110386Sbenno * 1. Redistributions of source code must retain the above copyright
11110386Sbenno *    notice, this list of conditions and the following disclaimer.
12110386Sbenno * 2. Redistributions in binary form must reproduce the above copyright
13110386Sbenno *    notice, this list of conditions and the following disclaimer in the
14110386Sbenno *    documentation and/or other materials provided with the distribution.
15110386Sbenno * 3. All advertising materials mentioning features or use of this software
16110386Sbenno *    must display the following acknowledgement:
17110386Sbenno *	This product includes software developed by
18110386Sbenno *	Internet Research Institute, Inc.
19110386Sbenno * 4. The name of the author may not be used to endorse or promote products
20110386Sbenno *    derived from this software without specific prior written permission.
21110386Sbenno *
22110386Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23110386Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24110386Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25110386Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26110386Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27110386Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28110386Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29110386Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30110386Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31110386Sbenno * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32110386Sbenno */
33139825Simp/*-
34110386Sbenno * Copyright (C) 2003 Benno Rice.
35110386Sbenno * All rights reserved.
36110386Sbenno *
37110386Sbenno * Redistribution and use in source and binary forms, with or without
38110386Sbenno * modification, are permitted provided that the following conditions
39110386Sbenno * are met:
40110386Sbenno * 1. Redistributions of source code must retain the above copyright
41110386Sbenno *    notice, this list of conditions and the following disclaimer.
42110386Sbenno * 2. Redistributions in binary form must reproduce the above copyright
43110386Sbenno *    notice, this list of conditions and the following disclaimer in the
44110386Sbenno *    documentation and/or other materials provided with the distribution.
45110386Sbenno *
46110386Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
47110386Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48110386Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49110386Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50110386Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51110386Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52110386Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53110386Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54110386Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55110386Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56110386Sbenno *
57110386Sbenno * from $NetBSD: cpu_subr.c,v 1.1 2003/02/03 17:10:09 matt Exp $
58110386Sbenno * $FreeBSD: releng/10.3/sys/powerpc/powerpc/cpu.c 273736 2014-10-27 14:38:00Z hselasky $
59110386Sbenno */
60110386Sbenno
61110386Sbenno#include <sys/param.h>
62110386Sbenno#include <sys/systm.h>
63110386Sbenno#include <sys/bus.h>
64110386Sbenno#include <sys/conf.h>
65193156Snwhitehorn#include <sys/cpu.h>
66110386Sbenno#include <sys/kernel.h>
67215157Snwhitehorn#include <sys/proc.h>
68166011Smarcel#include <sys/sysctl.h>
69110386Sbenno
70110386Sbenno#include <machine/bus.h>
71199886Snwhitehorn#include <machine/cpu.h>
72110386Sbenno#include <machine/hid.h>
73110386Sbenno#include <machine/md_var.h>
74198378Snwhitehorn#include <machine/smp.h>
75110386Sbenno#include <machine/spr.h>
76110386Sbenno
77259256Sandreast#include <dev/ofw/openfirm.h>
78259256Sandreast
79199886Snwhitehornstatic void	cpu_6xx_setup(int cpuid, uint16_t vers);
80199886Snwhitehornstatic void	cpu_970_setup(int cpuid, uint16_t vers);
81236097Srajstatic void	cpu_booke_setup(int cpuid, uint16_t vers);
82199886Snwhitehorn
83215157Snwhitehornint powerpc_pow_enabled;
84247454Sdavidevoid (*cpu_idle_hook)(sbintime_t) = NULL;
85247454Sdavidestatic void	cpu_idle_60x(sbintime_t);
86247454Sdavidestatic void	cpu_idle_booke(sbintime_t);
87215157Snwhitehorn
88110386Sbennostruct cputab {
89110386Sbenno	const char	*name;
90110386Sbenno	uint16_t	version;
91110386Sbenno	uint16_t	revfmt;
92199886Snwhitehorn	int		features;	/* Do not include PPC_FEATURE_32 or
93199886Snwhitehorn					 * PPC_FEATURE_HAS_MMU */
94199886Snwhitehorn	void		(*cpu_setup)(int cpuid, uint16_t vers);
95110386Sbenno};
96110386Sbenno#define	REVFMT_MAJMIN	1	/* %u.%u */
97110386Sbenno#define	REVFMT_HEX	2	/* 0x%04x */
98110386Sbenno#define	REVFMT_DEC	3	/* %u */
99110386Sbennostatic const struct cputab models[] = {
100199886Snwhitehorn        { "Motorola PowerPC 601",	MPC601,		REVFMT_DEC,
101199886Snwhitehorn	   PPC_FEATURE_HAS_FPU | PPC_FEATURE_UNIFIED_CACHE, cpu_6xx_setup },
102199886Snwhitehorn        { "Motorola PowerPC 602",	MPC602,		REVFMT_DEC,
103199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
104199886Snwhitehorn        { "Motorola PowerPC 603",	MPC603,		REVFMT_MAJMIN,
105199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
106199886Snwhitehorn        { "Motorola PowerPC 603e",	MPC603e,	REVFMT_MAJMIN,
107199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
108199886Snwhitehorn        { "Motorola PowerPC 603ev",	MPC603ev,	REVFMT_MAJMIN,
109199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
110199886Snwhitehorn        { "Motorola PowerPC 604",	MPC604,		REVFMT_MAJMIN,
111199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
112199886Snwhitehorn        { "Motorola PowerPC 604ev",	MPC604ev,	REVFMT_MAJMIN,
113199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
114199886Snwhitehorn        { "Motorola PowerPC 620",	MPC620,		REVFMT_HEX,
115199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
116199886Snwhitehorn        { "Motorola PowerPC 750",	MPC750,		REVFMT_MAJMIN,
117199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
118199886Snwhitehorn        { "IBM PowerPC 750FX",		IBM750FX,	REVFMT_MAJMIN,
119199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
120199886Snwhitehorn        { "IBM PowerPC 970",		IBM970,		REVFMT_MAJMIN,
121199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
122199886Snwhitehorn	   cpu_970_setup },
123199886Snwhitehorn        { "IBM PowerPC 970FX",		IBM970FX,	REVFMT_MAJMIN,
124199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
125199886Snwhitehorn	   cpu_970_setup },
126199886Snwhitehorn        { "IBM PowerPC 970GX",		IBM970GX,	REVFMT_MAJMIN,
127199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
128199886Snwhitehorn	   cpu_970_setup },
129199886Snwhitehorn        { "IBM PowerPC 970MP",		IBM970MP,	REVFMT_MAJMIN,
130199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
131199886Snwhitehorn	   cpu_970_setup },
132255418Snwhitehorn        { "IBM POWER4",		IBMPOWER4,	REVFMT_MAJMIN,
133255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
134255418Snwhitehorn        { "IBM POWER4+",	IBMPOWER4PLUS,	REVFMT_MAJMIN,
135255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
136255418Snwhitehorn        { "IBM POWER5",		IBMPOWER5,	REVFMT_MAJMIN,
137255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
138255418Snwhitehorn        { "IBM POWER5+",	IBMPOWER5PLUS,	REVFMT_MAJMIN,
139255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
140255418Snwhitehorn        { "IBM POWER6",		IBMPOWER6,	REVFMT_MAJMIN,
141255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
142255418Snwhitehorn	   NULL },
143255418Snwhitehorn        { "IBM POWER7",		IBMPOWER7,	REVFMT_MAJMIN,
144255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
145255418Snwhitehorn	   NULL },
146255640Snwhitehorn        { "IBM POWER7+",	IBMPOWER7PLUS,	REVFMT_MAJMIN,
147255640Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
148255640Snwhitehorn	   NULL },
149255640Snwhitehorn        { "IBM POWER8",		IBMPOWER8,	REVFMT_MAJMIN,
150255640Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
151255640Snwhitehorn	   NULL },
152199886Snwhitehorn        { "Motorola PowerPC 7400",	MPC7400,	REVFMT_MAJMIN,
153199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
154199886Snwhitehorn        { "Motorola PowerPC 7410",	MPC7410,	REVFMT_MAJMIN,
155199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
156199886Snwhitehorn        { "Motorola PowerPC 7450",	MPC7450,	REVFMT_MAJMIN,
157199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
158199886Snwhitehorn        { "Motorola PowerPC 7455",	MPC7455,	REVFMT_MAJMIN,
159199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
160199886Snwhitehorn        { "Motorola PowerPC 7457",	MPC7457,	REVFMT_MAJMIN,
161199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
162199886Snwhitehorn        { "Motorola PowerPC 7447A",	MPC7447A,	REVFMT_MAJMIN,
163199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
164199886Snwhitehorn        { "Motorola PowerPC 7448",	MPC7448,	REVFMT_MAJMIN,
165199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
166199886Snwhitehorn        { "Motorola PowerPC 8240",	MPC8240,	REVFMT_MAJMIN,
167199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
168199886Snwhitehorn        { "Motorola PowerPC 8245",	MPC8245,	REVFMT_MAJMIN,
169199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
170199886Snwhitehorn        { "Freescale e500v1 core",	FSL_E500v1,	REVFMT_MAJMIN,
171236097Sraj	   0, cpu_booke_setup },
172199886Snwhitehorn        { "Freescale e500v2 core",	FSL_E500v2,	REVFMT_MAJMIN,
173236097Sraj	   0, cpu_booke_setup },
174236097Sraj	{ "Freescale e500mc core",	FSL_E500mc,	REVFMT_MAJMIN,
175236097Sraj	   0, cpu_booke_setup },
176236097Sraj	{ "Freescale e5500 core",	FSL_E5500,	REVFMT_MAJMIN,
177236097Sraj	   0, cpu_booke_setup },
178215182Snwhitehorn        { "IBM Cell Broadband Engine",	IBMCELLBE,	REVFMT_MAJMIN,
179215182Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
180215182Snwhitehorn	   NULL},
181199886Snwhitehorn        { "Unknown PowerPC CPU",	0,		REVFMT_HEX, 0, NULL },
182110386Sbenno};
183110386Sbenno
184199886Snwhitehornstatic void	cpu_6xx_print_cacheinfo(u_int, uint16_t);
185199886Snwhitehornstatic int	cpu_feature_bit(SYSCTL_HANDLER_ARGS);
186199886Snwhitehorn
187166011Smarcelstatic char model[64];
188166011SmarcelSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, "");
189166011Smarcel
190199886Snwhitehornint cpu_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU;
191273736ShselaskySYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLFLAG_RD,
192199886Snwhitehorn    &cpu_features, sizeof(cpu_features), "IX", "PowerPC CPU features");
193110386Sbenno
194199886Snwhitehorn/* Provide some user-friendly aliases for bits in cpu_features */
195199886SnwhitehornSYSCTL_PROC(_hw, OID_AUTO, floatingpoint, CTLTYPE_INT | CTLFLAG_RD,
196199886Snwhitehorn    0, PPC_FEATURE_HAS_FPU, cpu_feature_bit, "I",
197199886Snwhitehorn    "Floating point instructions executed in hardware");
198199886SnwhitehornSYSCTL_PROC(_hw, OID_AUTO, altivec, CTLTYPE_INT | CTLFLAG_RD,
199199886Snwhitehorn    0, PPC_FEATURE_HAS_ALTIVEC, cpu_feature_bit, "I", "CPU supports Altivec");
200198445Snwhitehorn
201110386Sbennovoid
202110386Sbennocpu_setup(u_int cpuid)
203110386Sbenno{
204198445Snwhitehorn	u_int		pvr, maj, min;
205110386Sbenno	uint16_t	vers, rev, revfmt;
206199886Snwhitehorn	uint64_t	cps;
207110386Sbenno	const struct	cputab *cp;
208110386Sbenno	const char	*name;
209110386Sbenno
210110386Sbenno	pvr = mfpvr();
211110386Sbenno	vers = pvr >> 16;
212110386Sbenno	rev = pvr;
213110386Sbenno	switch (vers) {
214176534Sraj		case MPC7410:
215176534Sraj			min = (pvr >> 0) & 0xff;
216176534Sraj			maj = min <= 4 ? 1 : 2;
217176534Sraj			break;
218176534Sraj		case FSL_E500v1:
219176534Sraj		case FSL_E500v2:
220236097Sraj		case FSL_E500mc:
221236097Sraj		case FSL_E5500:
222176534Sraj			maj = (pvr >>  4) & 0xf;
223176534Sraj			min = (pvr >>  0) & 0xf;
224176534Sraj			break;
225176534Sraj		default:
226176534Sraj			maj = (pvr >>  8) & 0xf;
227176534Sraj			min = (pvr >>  0) & 0xf;
228110386Sbenno	}
229110386Sbenno
230166812Smarcel	for (cp = models; cp->version != 0; cp++) {
231110386Sbenno		if (cp->version == vers)
232110386Sbenno			break;
233110386Sbenno	}
234110386Sbenno
235110386Sbenno	revfmt = cp->revfmt;
236110386Sbenno	name = cp->name;
237110386Sbenno	if (rev == MPC750 && pvr == 15) {
238110386Sbenno		name = "Motorola MPC755";
239110386Sbenno		revfmt = REVFMT_HEX;
240110386Sbenno	}
241166011Smarcel	strncpy(model, name, sizeof(model) - 1);
242110386Sbenno
243110386Sbenno	printf("cpu%d: %s revision ", cpuid, name);
244110386Sbenno
245110386Sbenno	switch (revfmt) {
246176534Sraj		case REVFMT_MAJMIN:
247176534Sraj			printf("%u.%u", maj, min);
248176534Sraj			break;
249176534Sraj		case REVFMT_HEX:
250176534Sraj			printf("0x%04x", rev);
251176534Sraj			break;
252176534Sraj		case REVFMT_DEC:
253176534Sraj			printf("%u", rev);
254176534Sraj			break;
255110386Sbenno	}
256110386Sbenno
257199886Snwhitehorn	if (cpu_est_clockrate(0, &cps) == 0)
258209975Snwhitehorn		printf(", %jd.%02jd MHz", cps / 1000000, (cps / 10000) % 100);
259199886Snwhitehorn	printf("\n");
260199886Snwhitehorn
261199886Snwhitehorn	cpu_features |= cp->features;
262199886Snwhitehorn	printf("cpu%d: Features %b\n", cpuid, cpu_features,
263199886Snwhitehorn	    PPC_FEATURE_BITMASK);
264199886Snwhitehorn
265110386Sbenno	/*
266198445Snwhitehorn	 * Configure CPU
267110386Sbenno	 */
268199886Snwhitehorn	if (cp->cpu_setup != NULL)
269199886Snwhitehorn		cp->cpu_setup(cpuid, vers);
270110386Sbenno}
271110386Sbenno
272193156Snwhitehorn/* Get current clock frequency for the given cpu id. */
273193156Snwhitehornint
274193156Snwhitehorncpu_est_clockrate(int cpu_id, uint64_t *cps)
275193156Snwhitehorn{
276193156Snwhitehorn	uint16_t	vers;
277194374Snwhitehorn	register_t	msr;
278259256Sandreast	phandle_t	cpu, dev, root;
279259256Sandreast	int		res  = 0;
280259256Sandreast	char		buf[8];
281193156Snwhitehorn
282193156Snwhitehorn	vers = mfpvr() >> 16;
283194374Snwhitehorn	msr = mfmsr();
284194374Snwhitehorn	mtmsr(msr & ~PSL_EE);
285193156Snwhitehorn
286193156Snwhitehorn	switch (vers) {
287193156Snwhitehorn		case MPC7450:
288193156Snwhitehorn		case MPC7455:
289193156Snwhitehorn		case MPC7457:
290193156Snwhitehorn		case MPC750:
291193156Snwhitehorn		case IBM750FX:
292193156Snwhitehorn		case MPC7400:
293193156Snwhitehorn		case MPC7410:
294193156Snwhitehorn		case MPC7447A:
295193156Snwhitehorn		case MPC7448:
296193156Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_FC);
297193156Snwhitehorn			mtspr(SPR_PMC1, 0);
298193156Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_PMC1SEL(PMCN_CYCLES));
299194374Snwhitehorn			DELAY(1000);
300194374Snwhitehorn			*cps = (mfspr(SPR_PMC1) * 1000) + 4999;
301194374Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_FC);
302194374Snwhitehorn
303194374Snwhitehorn			mtmsr(msr);
304193156Snwhitehorn			return (0);
305194374Snwhitehorn		case IBM970:
306194374Snwhitehorn		case IBM970FX:
307194374Snwhitehorn		case IBM970MP:
308194374Snwhitehorn			isync();
309194374Snwhitehorn			mtspr(SPR_970MMCR0, SPR_MMCR0_FC);
310194374Snwhitehorn			isync();
311194374Snwhitehorn			mtspr(SPR_970MMCR1, 0);
312194374Snwhitehorn			mtspr(SPR_970MMCRA, 0);
313194374Snwhitehorn			mtspr(SPR_970PMC1, 0);
314194374Snwhitehorn			mtspr(SPR_970MMCR0,
315194374Snwhitehorn			    SPR_970MMCR0_PMC1SEL(PMC970N_CYCLES));
316194374Snwhitehorn			isync();
317194374Snwhitehorn			DELAY(1000);
318194374Snwhitehorn			powerpc_sync();
319194374Snwhitehorn			mtspr(SPR_970MMCR0, SPR_MMCR0_FC);
320194374Snwhitehorn			*cps = (mfspr(SPR_970PMC1) * 1000) + 4999;
321194374Snwhitehorn
322194374Snwhitehorn			mtmsr(msr);
323194374Snwhitehorn			return (0);
324259256Sandreast
325259256Sandreast		default:
326259256Sandreast			root = OF_peer(0);
327259256Sandreast			if (root == 0)
328259256Sandreast				return (ENXIO);
329259256Sandreast
330259256Sandreast			dev = OF_child(root);
331259256Sandreast			while (dev != 0) {
332259256Sandreast				res = OF_getprop(dev, "name", buf, sizeof(buf));
333259256Sandreast				if (res > 0 && strcmp(buf, "cpus") == 0)
334259256Sandreast					break;
335259256Sandreast				dev = OF_peer(dev);
336259256Sandreast			}
337259256Sandreast			cpu = OF_child(dev);
338259256Sandreast			while (cpu != 0) {
339259256Sandreast				res = OF_getprop(cpu, "device_type", buf,
340259256Sandreast						sizeof(buf));
341259256Sandreast				if (res > 0 && strcmp(buf, "cpu") == 0)
342259256Sandreast					break;
343259256Sandreast				cpu = OF_peer(cpu);
344259256Sandreast			}
345259256Sandreast			if (cpu == 0)
346259256Sandreast				return (ENOENT);
347259256Sandreast			if (OF_getprop(cpu, "ibm,extended-clock-frequency",
348259256Sandreast			    cps, sizeof(*cps)) >= 0) {
349259256Sandreast				return (0);
350259256Sandreast			} else if (OF_getprop(cpu, "clock-frequency", cps,
351259256Sandreast			    sizeof(cell_t)) >= 0) {
352259256Sandreast				*cps >>= 32;
353259256Sandreast				return (0);
354259256Sandreast			} else {
355259256Sandreast				return (ENOENT);
356259256Sandreast			}
357193156Snwhitehorn	}
358110386Sbenno}
359110386Sbenno
360110386Sbennovoid
361198445Snwhitehorncpu_6xx_setup(int cpuid, uint16_t vers)
362110386Sbenno{
363198445Snwhitehorn	register_t hid0, pvr;
364198445Snwhitehorn	const char *bitmask;
365110386Sbenno
366198445Snwhitehorn	hid0 = mfspr(SPR_HID0);
367198445Snwhitehorn	pvr = mfpvr();
368110386Sbenno
369198445Snwhitehorn	/*
370198445Snwhitehorn	 * Configure power-saving mode.
371198445Snwhitehorn	 */
372198445Snwhitehorn	switch (vers) {
373198445Snwhitehorn		case MPC603:
374198445Snwhitehorn		case MPC603e:
375198445Snwhitehorn		case MPC603ev:
376198445Snwhitehorn		case MPC604ev:
377198445Snwhitehorn		case MPC750:
378198445Snwhitehorn		case IBM750FX:
379198445Snwhitehorn		case MPC7400:
380198445Snwhitehorn		case MPC7410:
381198445Snwhitehorn		case MPC8240:
382198445Snwhitehorn		case MPC8245:
383198445Snwhitehorn			/* Select DOZE mode. */
384198445Snwhitehorn			hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
385198445Snwhitehorn			hid0 |= HID0_DOZE | HID0_DPM;
386198445Snwhitehorn			powerpc_pow_enabled = 1;
387198445Snwhitehorn			break;
388198445Snwhitehorn
389198445Snwhitehorn		case MPC7448:
390198445Snwhitehorn		case MPC7447A:
391198445Snwhitehorn		case MPC7457:
392198445Snwhitehorn		case MPC7455:
393198445Snwhitehorn		case MPC7450:
394198445Snwhitehorn			/* Enable the 7450 branch caches */
395198445Snwhitehorn			hid0 |= HID0_SGE | HID0_BTIC;
396198445Snwhitehorn			hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT;
397198445Snwhitehorn			/* Disable BTIC on 7450 Rev 2.0 or earlier and on 7457 */
398198445Snwhitehorn			if (((pvr >> 16) == MPC7450 && (pvr & 0xFFFF) <= 0x0200)
399198445Snwhitehorn					|| (pvr >> 16) == MPC7457)
400198445Snwhitehorn				hid0 &= ~HID0_BTIC;
401198445Snwhitehorn			/* Select NAP mode. */
402198445Snwhitehorn			hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
403198445Snwhitehorn			hid0 |= HID0_NAP | HID0_DPM;
404198445Snwhitehorn			powerpc_pow_enabled = 1;
405198445Snwhitehorn			break;
406198445Snwhitehorn
407198445Snwhitehorn		default:
408198445Snwhitehorn			/* No power-saving mode is available. */ ;
409198445Snwhitehorn	}
410198445Snwhitehorn
411198445Snwhitehorn	switch (vers) {
412198445Snwhitehorn		case IBM750FX:
413198445Snwhitehorn		case MPC750:
414198445Snwhitehorn			hid0 &= ~HID0_DBP;		/* XXX correct? */
415198445Snwhitehorn			hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT;
416198445Snwhitehorn			break;
417198445Snwhitehorn
418198445Snwhitehorn		case MPC7400:
419198445Snwhitehorn		case MPC7410:
420198445Snwhitehorn			hid0 &= ~HID0_SPD;
421198445Snwhitehorn			hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT;
422198445Snwhitehorn			hid0 |= HID0_EIEC;
423198445Snwhitehorn			break;
424198445Snwhitehorn
425198445Snwhitehorn	}
426198445Snwhitehorn
427198445Snwhitehorn	mtspr(SPR_HID0, hid0);
428198445Snwhitehorn
429198445Snwhitehorn	if (bootverbose)
430198445Snwhitehorn		cpu_6xx_print_cacheinfo(cpuid, vers);
431198445Snwhitehorn
432198445Snwhitehorn	switch (vers) {
433198445Snwhitehorn		case MPC7447A:
434198445Snwhitehorn		case MPC7448:
435198445Snwhitehorn		case MPC7450:
436198445Snwhitehorn		case MPC7455:
437198445Snwhitehorn		case MPC7457:
438198445Snwhitehorn			bitmask = HID0_7450_BITMASK;
439198445Snwhitehorn			break;
440198445Snwhitehorn		default:
441198445Snwhitehorn			bitmask = HID0_BITMASK;
442198445Snwhitehorn			break;
443198445Snwhitehorn	}
444198445Snwhitehorn
445199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask);
446215157Snwhitehorn
447215157Snwhitehorn	if (cpu_idle_hook == NULL)
448215157Snwhitehorn		cpu_idle_hook = cpu_idle_60x;
449198445Snwhitehorn}
450198445Snwhitehorn
451198445Snwhitehorn
452198445Snwhitehornstatic void
453198445Snwhitehorncpu_6xx_print_cacheinfo(u_int cpuid, uint16_t vers)
454198445Snwhitehorn{
455198445Snwhitehorn	register_t hid;
456198445Snwhitehorn
457183029Smarcel	hid = mfspr(SPR_HID0);
458183029Smarcel	printf("cpu%u: ", cpuid);
459183029Smarcel	printf("L1 I-cache %sabled, ", (hid & HID0_ICE) ? "en" : "dis");
460183029Smarcel	printf("L1 D-cache %sabled\n", (hid & HID0_DCE) ? "en" : "dis");
461110386Sbenno
462183029Smarcel	printf("cpu%u: ", cpuid);
463198378Snwhitehorn  	if (mfspr(SPR_L2CR) & L2CR_L2E) {
464183029Smarcel		switch (vers) {
465183029Smarcel		case MPC7450:
466183029Smarcel		case MPC7455:
467183029Smarcel		case MPC7457:
468183029Smarcel			printf("256KB L2 cache, ");
469198378Snwhitehorn			if (mfspr(SPR_L3CR) & L3CR_L3E)
470183029Smarcel				printf("%cMB L3 backside cache",
471198378Snwhitehorn				    mfspr(SPR_L3CR) & L3CR_L3SIZ ? '2' : '1');
472183029Smarcel			else
473183029Smarcel				printf("L3 cache disabled");
474110386Sbenno			printf("\n");
475183029Smarcel			break;
476183029Smarcel		case IBM750FX:
477110386Sbenno			printf("512KB L2 cache\n");
478183029Smarcel			break;
479110386Sbenno		default:
480198378Snwhitehorn			switch (mfspr(SPR_L2CR) & L2CR_L2SIZ) {
481183029Smarcel			case L2SIZ_256K:
482183029Smarcel				printf("256KB ");
483183029Smarcel				break;
484183029Smarcel			case L2SIZ_512K:
485183029Smarcel				printf("512KB ");
486183029Smarcel				break;
487183029Smarcel			case L2SIZ_1M:
488183029Smarcel				printf("1MB ");
489183029Smarcel				break;
490183029Smarcel			}
491198378Snwhitehorn			printf("write-%s", (mfspr(SPR_L2CR) & L2CR_L2WT)
492183029Smarcel			    ? "through" : "back");
493198378Snwhitehorn			if (mfspr(SPR_L2CR) & L2CR_L2PE)
494183029Smarcel				printf(", with parity");
495183029Smarcel			printf(" backside cache\n");
496110386Sbenno			break;
497110386Sbenno		}
498110386Sbenno	} else
499183029Smarcel		printf("L2 cache disabled\n");
500110386Sbenno}
501198445Snwhitehorn
502198445Snwhitehornstatic void
503236097Srajcpu_booke_setup(int cpuid, uint16_t vers)
504198445Snwhitehorn{
505236141Sraj#ifdef BOOKE_E500
506198445Snwhitehorn	register_t hid0;
507198445Snwhitehorn
508198445Snwhitehorn	hid0 = mfspr(SPR_HID0);
509205527Smarcel
510205527Smarcel	/* Programe power-management mode. */
511205527Smarcel	hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
512205527Smarcel	hid0 |= HID0_DOZE;
513205527Smarcel
514205527Smarcel	mtspr(SPR_HID0, hid0);
515205527Smarcel
516199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, HID0_E500_BITMASK);
517236141Sraj#endif
518215157Snwhitehorn
519215157Snwhitehorn	if (cpu_idle_hook == NULL)
520236097Sraj		cpu_idle_hook = cpu_idle_booke;
521198445Snwhitehorn}
522198445Snwhitehorn
523198445Snwhitehornstatic void
524198445Snwhitehorncpu_970_setup(int cpuid, uint16_t vers)
525198445Snwhitehorn{
526199886Snwhitehorn#ifdef AIM
527198445Snwhitehorn	uint32_t hid0_hi, hid0_lo;
528198445Snwhitehorn
529198445Snwhitehorn	__asm __volatile ("mfspr %0,%2; clrldi %1,%0,32; srdi %0,%0,32;"
530198445Snwhitehorn	    : "=r" (hid0_hi), "=r" (hid0_lo) : "K" (SPR_HID0));
531198445Snwhitehorn
532198445Snwhitehorn	/* Configure power-saving mode */
533204127Snwhitehorn	switch (vers) {
534204127Snwhitehorn	case IBM970MP:
535215101Snwhitehorn		hid0_hi |= (HID0_DEEPNAP | HID0_NAP | HID0_DPM);
536215101Snwhitehorn		hid0_hi &= ~HID0_DOZE;
537204127Snwhitehorn		break;
538204127Snwhitehorn	default:
539204127Snwhitehorn		hid0_hi |= (HID0_NAP | HID0_DPM);
540204127Snwhitehorn		hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP);
541204127Snwhitehorn		break;
542204127Snwhitehorn	}
543198445Snwhitehorn	powerpc_pow_enabled = 1;
544198445Snwhitehorn
545198445Snwhitehorn	__asm __volatile (" \
546198445Snwhitehorn		sync; isync;					\
547198445Snwhitehorn		sldi	%0,%0,32; or %0,%0,%1;			\
548198445Snwhitehorn		mtspr	%2, %0;					\
549198445Snwhitehorn		mfspr   %0, %2; mfspr   %0, %2; mfspr   %0, %2; \
550198445Snwhitehorn		mfspr   %0, %2; mfspr   %0, %2; mfspr   %0, %2; \
551198445Snwhitehorn		sync; isync"
552198445Snwhitehorn	    :: "r" (hid0_hi), "r"(hid0_lo), "K" (SPR_HID0));
553198445Snwhitehorn
554198445Snwhitehorn	__asm __volatile ("mfspr %0,%1; srdi %0,%0,32;"
555198445Snwhitehorn	    : "=r" (hid0_hi) : "K" (SPR_HID0));
556199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK);
557199886Snwhitehorn#endif
558215157Snwhitehorn
559215157Snwhitehorn	cpu_idle_hook = cpu_idle_60x;
560198445Snwhitehorn}
561199886Snwhitehorn
562199886Snwhitehornstatic int
563199886Snwhitehorncpu_feature_bit(SYSCTL_HANDLER_ARGS)
564199886Snwhitehorn{
565199886Snwhitehorn	int result;
566199886Snwhitehorn
567199886Snwhitehorn	result = (cpu_features & arg2) ? 1 : 0;
568199886Snwhitehorn
569199886Snwhitehorn	return (sysctl_handle_int(oidp, &result, 0, req));
570199886Snwhitehorn}
571199886Snwhitehorn
572215157Snwhitehornvoid
573215157Snwhitehorncpu_idle(int busy)
574215157Snwhitehorn{
575247454Sdavide	sbintime_t sbt = -1;
576215157Snwhitehorn
577215157Snwhitehorn#ifdef INVARIANTS
578215157Snwhitehorn	if ((mfmsr() & PSL_EE) != PSL_EE) {
579215157Snwhitehorn		struct thread *td = curthread;
580215157Snwhitehorn		printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr);
581215157Snwhitehorn		panic("ints disabled in idleproc!");
582215157Snwhitehorn	}
583215157Snwhitehorn#endif
584215157Snwhitehorn
585215157Snwhitehorn	CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
586215157Snwhitehorn	    busy, curcpu);
587236097Sraj
588215157Snwhitehorn	if (cpu_idle_hook != NULL) {
589215157Snwhitehorn		if (!busy) {
590215157Snwhitehorn			critical_enter();
591247454Sdavide			sbt = cpu_idleclock();
592215157Snwhitehorn		}
593247454Sdavide		cpu_idle_hook(sbt);
594215157Snwhitehorn		if (!busy) {
595215157Snwhitehorn			cpu_activeclock();
596215157Snwhitehorn			critical_exit();
597215157Snwhitehorn		}
598215157Snwhitehorn	}
599236097Sraj
600215157Snwhitehorn	CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
601215157Snwhitehorn	    busy, curcpu);
602215157Snwhitehorn}
603215157Snwhitehorn
604215157Snwhitehornint
605215157Snwhitehorncpu_idle_wakeup(int cpu)
606215157Snwhitehorn{
607215157Snwhitehorn	return (0);
608215157Snwhitehorn}
609215157Snwhitehorn
610215157Snwhitehornstatic void
611247454Sdavidecpu_idle_60x(sbintime_t sbt)
612215157Snwhitehorn{
613215157Snwhitehorn	register_t msr;
614215157Snwhitehorn	uint16_t vers;
615215157Snwhitehorn
616215157Snwhitehorn	if (!powerpc_pow_enabled)
617215157Snwhitehorn		return;
618215157Snwhitehorn
619215157Snwhitehorn	msr = mfmsr();
620215157Snwhitehorn	vers = mfpvr() >> 16;
621215157Snwhitehorn
622215157Snwhitehorn#ifdef AIM
623215157Snwhitehorn	switch (vers) {
624215157Snwhitehorn	case IBM970:
625215157Snwhitehorn	case IBM970FX:
626215157Snwhitehorn	case IBM970MP:
627215157Snwhitehorn	case MPC7447A:
628215157Snwhitehorn	case MPC7448:
629215157Snwhitehorn	case MPC7450:
630215157Snwhitehorn	case MPC7455:
631215157Snwhitehorn	case MPC7457:
632215157Snwhitehorn		__asm __volatile("\
633215157Snwhitehorn			    dssall; sync; mtmsr %0; isync"
634215157Snwhitehorn			    :: "r"(msr | PSL_POW));
635215157Snwhitehorn		break;
636215157Snwhitehorn	default:
637215157Snwhitehorn		powerpc_sync();
638215157Snwhitehorn		mtmsr(msr | PSL_POW);
639215157Snwhitehorn		isync();
640215157Snwhitehorn		break;
641215157Snwhitehorn	}
642215157Snwhitehorn#endif
643215157Snwhitehorn}
644215157Snwhitehorn
645215157Snwhitehornstatic void
646247454Sdavidecpu_idle_booke(sbintime_t sbt)
647215157Snwhitehorn{
648215157Snwhitehorn	register_t msr;
649215157Snwhitehorn
650215157Snwhitehorn	msr = mfmsr();
651215157Snwhitehorn
652215157Snwhitehorn#ifdef E500
653215157Snwhitehorn	/* Freescale E500 core RM section 6.4.1. */
654215157Snwhitehorn	__asm __volatile("msync; mtmsr %0; isync" ::
655215157Snwhitehorn	    "r" (msr | PSL_WE));
656215157Snwhitehorn#endif
657215157Snwhitehorn}
658215157Snwhitehorn
659