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$
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
77199886Snwhitehornstatic void	cpu_6xx_setup(int cpuid, uint16_t vers);
78199886Snwhitehornstatic void	cpu_970_setup(int cpuid, uint16_t vers);
79236097Srajstatic void	cpu_booke_setup(int cpuid, uint16_t vers);
80199886Snwhitehorn
81215157Snwhitehornint powerpc_pow_enabled;
82247454Sdavidevoid (*cpu_idle_hook)(sbintime_t) = NULL;
83247454Sdavidestatic void	cpu_idle_60x(sbintime_t);
84247454Sdavidestatic void	cpu_idle_booke(sbintime_t);
85215157Snwhitehorn
86110386Sbennostruct cputab {
87110386Sbenno	const char	*name;
88110386Sbenno	uint16_t	version;
89110386Sbenno	uint16_t	revfmt;
90199886Snwhitehorn	int		features;	/* Do not include PPC_FEATURE_32 or
91199886Snwhitehorn					 * PPC_FEATURE_HAS_MMU */
92199886Snwhitehorn	void		(*cpu_setup)(int cpuid, uint16_t vers);
93110386Sbenno};
94110386Sbenno#define	REVFMT_MAJMIN	1	/* %u.%u */
95110386Sbenno#define	REVFMT_HEX	2	/* 0x%04x */
96110386Sbenno#define	REVFMT_DEC	3	/* %u */
97110386Sbennostatic const struct cputab models[] = {
98199886Snwhitehorn        { "Motorola PowerPC 601",	MPC601,		REVFMT_DEC,
99199886Snwhitehorn	   PPC_FEATURE_HAS_FPU | PPC_FEATURE_UNIFIED_CACHE, cpu_6xx_setup },
100199886Snwhitehorn        { "Motorola PowerPC 602",	MPC602,		REVFMT_DEC,
101199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
102199886Snwhitehorn        { "Motorola PowerPC 603",	MPC603,		REVFMT_MAJMIN,
103199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
104199886Snwhitehorn        { "Motorola PowerPC 603e",	MPC603e,	REVFMT_MAJMIN,
105199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
106199886Snwhitehorn        { "Motorola PowerPC 603ev",	MPC603ev,	REVFMT_MAJMIN,
107199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
108199886Snwhitehorn        { "Motorola PowerPC 604",	MPC604,		REVFMT_MAJMIN,
109199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
110199886Snwhitehorn        { "Motorola PowerPC 604ev",	MPC604ev,	REVFMT_MAJMIN,
111199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
112199886Snwhitehorn        { "Motorola PowerPC 620",	MPC620,		REVFMT_HEX,
113199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
114199886Snwhitehorn        { "Motorola PowerPC 750",	MPC750,		REVFMT_MAJMIN,
115199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
116199886Snwhitehorn        { "IBM PowerPC 750FX",		IBM750FX,	REVFMT_MAJMIN,
117199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
118199886Snwhitehorn        { "IBM PowerPC 970",		IBM970,		REVFMT_MAJMIN,
119199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
120199886Snwhitehorn	   cpu_970_setup },
121199886Snwhitehorn        { "IBM PowerPC 970FX",		IBM970FX,	REVFMT_MAJMIN,
122199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
123199886Snwhitehorn	   cpu_970_setup },
124199886Snwhitehorn        { "IBM PowerPC 970GX",		IBM970GX,	REVFMT_MAJMIN,
125199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
126199886Snwhitehorn	   cpu_970_setup },
127199886Snwhitehorn        { "IBM PowerPC 970MP",		IBM970MP,	REVFMT_MAJMIN,
128199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
129199886Snwhitehorn	   cpu_970_setup },
130255418Snwhitehorn        { "IBM POWER4",		IBMPOWER4,	REVFMT_MAJMIN,
131255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
132255418Snwhitehorn        { "IBM POWER4+",	IBMPOWER4PLUS,	REVFMT_MAJMIN,
133255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
134255418Snwhitehorn        { "IBM POWER5",		IBMPOWER5,	REVFMT_MAJMIN,
135255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
136255418Snwhitehorn        { "IBM POWER5+",	IBMPOWER5PLUS,	REVFMT_MAJMIN,
137255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
138255418Snwhitehorn        { "IBM POWER6",		IBMPOWER6,	REVFMT_MAJMIN,
139255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
140255418Snwhitehorn	   NULL },
141255418Snwhitehorn        { "IBM POWER7",		IBMPOWER7,	REVFMT_MAJMIN,
142255418Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
143255418Snwhitehorn	   NULL },
144255640Snwhitehorn        { "IBM POWER7+",	IBMPOWER7PLUS,	REVFMT_MAJMIN,
145255640Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
146255640Snwhitehorn	   NULL },
147255640Snwhitehorn        { "IBM POWER8",		IBMPOWER8,	REVFMT_MAJMIN,
148255640Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
149255640Snwhitehorn	   NULL },
150199886Snwhitehorn        { "Motorola PowerPC 7400",	MPC7400,	REVFMT_MAJMIN,
151199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
152199886Snwhitehorn        { "Motorola PowerPC 7410",	MPC7410,	REVFMT_MAJMIN,
153199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
154199886Snwhitehorn        { "Motorola PowerPC 7450",	MPC7450,	REVFMT_MAJMIN,
155199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
156199886Snwhitehorn        { "Motorola PowerPC 7455",	MPC7455,	REVFMT_MAJMIN,
157199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
158199886Snwhitehorn        { "Motorola PowerPC 7457",	MPC7457,	REVFMT_MAJMIN,
159199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
160199886Snwhitehorn        { "Motorola PowerPC 7447A",	MPC7447A,	REVFMT_MAJMIN,
161199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
162199886Snwhitehorn        { "Motorola PowerPC 7448",	MPC7448,	REVFMT_MAJMIN,
163199886Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
164199886Snwhitehorn        { "Motorola PowerPC 8240",	MPC8240,	REVFMT_MAJMIN,
165199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
166199886Snwhitehorn        { "Motorola PowerPC 8245",	MPC8245,	REVFMT_MAJMIN,
167199886Snwhitehorn	   PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
168199886Snwhitehorn        { "Freescale e500v1 core",	FSL_E500v1,	REVFMT_MAJMIN,
169236097Sraj	   0, cpu_booke_setup },
170199886Snwhitehorn        { "Freescale e500v2 core",	FSL_E500v2,	REVFMT_MAJMIN,
171236097Sraj	   0, cpu_booke_setup },
172236097Sraj	{ "Freescale e500mc core",	FSL_E500mc,	REVFMT_MAJMIN,
173236097Sraj	   0, cpu_booke_setup },
174236097Sraj	{ "Freescale e5500 core",	FSL_E5500,	REVFMT_MAJMIN,
175236097Sraj	   0, cpu_booke_setup },
176215182Snwhitehorn        { "IBM Cell Broadband Engine",	IBMCELLBE,	REVFMT_MAJMIN,
177215182Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
178215182Snwhitehorn	   NULL},
179199886Snwhitehorn        { "Unknown PowerPC CPU",	0,		REVFMT_HEX, 0, NULL },
180110386Sbenno};
181110386Sbenno
182199886Snwhitehornstatic void	cpu_6xx_print_cacheinfo(u_int, uint16_t);
183199886Snwhitehornstatic int	cpu_feature_bit(SYSCTL_HANDLER_ARGS);
184199886Snwhitehorn
185166011Smarcelstatic char model[64];
186166011SmarcelSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, "");
187166011Smarcel
188199886Snwhitehornint cpu_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU;
189199886SnwhitehornSYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLTYPE_INT | CTLFLAG_RD,
190199886Snwhitehorn    &cpu_features, sizeof(cpu_features), "IX", "PowerPC CPU features");
191110386Sbenno
192199886Snwhitehorn/* Provide some user-friendly aliases for bits in cpu_features */
193199886SnwhitehornSYSCTL_PROC(_hw, OID_AUTO, floatingpoint, CTLTYPE_INT | CTLFLAG_RD,
194199886Snwhitehorn    0, PPC_FEATURE_HAS_FPU, cpu_feature_bit, "I",
195199886Snwhitehorn    "Floating point instructions executed in hardware");
196199886SnwhitehornSYSCTL_PROC(_hw, OID_AUTO, altivec, CTLTYPE_INT | CTLFLAG_RD,
197199886Snwhitehorn    0, PPC_FEATURE_HAS_ALTIVEC, cpu_feature_bit, "I", "CPU supports Altivec");
198198445Snwhitehorn
199110386Sbennovoid
200110386Sbennocpu_setup(u_int cpuid)
201110386Sbenno{
202198445Snwhitehorn	u_int		pvr, maj, min;
203110386Sbenno	uint16_t	vers, rev, revfmt;
204199886Snwhitehorn	uint64_t	cps;
205110386Sbenno	const struct	cputab *cp;
206110386Sbenno	const char	*name;
207110386Sbenno
208110386Sbenno	pvr = mfpvr();
209110386Sbenno	vers = pvr >> 16;
210110386Sbenno	rev = pvr;
211110386Sbenno	switch (vers) {
212176534Sraj		case MPC7410:
213176534Sraj			min = (pvr >> 0) & 0xff;
214176534Sraj			maj = min <= 4 ? 1 : 2;
215176534Sraj			break;
216176534Sraj		case FSL_E500v1:
217176534Sraj		case FSL_E500v2:
218236097Sraj		case FSL_E500mc:
219236097Sraj		case FSL_E5500:
220176534Sraj			maj = (pvr >>  4) & 0xf;
221176534Sraj			min = (pvr >>  0) & 0xf;
222176534Sraj			break;
223176534Sraj		default:
224176534Sraj			maj = (pvr >>  8) & 0xf;
225176534Sraj			min = (pvr >>  0) & 0xf;
226110386Sbenno	}
227110386Sbenno
228166812Smarcel	for (cp = models; cp->version != 0; cp++) {
229110386Sbenno		if (cp->version == vers)
230110386Sbenno			break;
231110386Sbenno	}
232110386Sbenno
233110386Sbenno	revfmt = cp->revfmt;
234110386Sbenno	name = cp->name;
235110386Sbenno	if (rev == MPC750 && pvr == 15) {
236110386Sbenno		name = "Motorola MPC755";
237110386Sbenno		revfmt = REVFMT_HEX;
238110386Sbenno	}
239166011Smarcel	strncpy(model, name, sizeof(model) - 1);
240110386Sbenno
241110386Sbenno	printf("cpu%d: %s revision ", cpuid, name);
242110386Sbenno
243110386Sbenno	switch (revfmt) {
244176534Sraj		case REVFMT_MAJMIN:
245176534Sraj			printf("%u.%u", maj, min);
246176534Sraj			break;
247176534Sraj		case REVFMT_HEX:
248176534Sraj			printf("0x%04x", rev);
249176534Sraj			break;
250176534Sraj		case REVFMT_DEC:
251176534Sraj			printf("%u", rev);
252176534Sraj			break;
253110386Sbenno	}
254110386Sbenno
255199886Snwhitehorn	if (cpu_est_clockrate(0, &cps) == 0)
256209975Snwhitehorn		printf(", %jd.%02jd MHz", cps / 1000000, (cps / 10000) % 100);
257199886Snwhitehorn	printf("\n");
258199886Snwhitehorn
259199886Snwhitehorn	cpu_features |= cp->features;
260199886Snwhitehorn	printf("cpu%d: Features %b\n", cpuid, cpu_features,
261199886Snwhitehorn	    PPC_FEATURE_BITMASK);
262199886Snwhitehorn
263110386Sbenno	/*
264198445Snwhitehorn	 * Configure CPU
265110386Sbenno	 */
266199886Snwhitehorn	if (cp->cpu_setup != NULL)
267199886Snwhitehorn		cp->cpu_setup(cpuid, vers);
268110386Sbenno}
269110386Sbenno
270193156Snwhitehorn/* Get current clock frequency for the given cpu id. */
271193156Snwhitehornint
272193156Snwhitehorncpu_est_clockrate(int cpu_id, uint64_t *cps)
273193156Snwhitehorn{
274193156Snwhitehorn	uint16_t	vers;
275194374Snwhitehorn	register_t	msr;
276193156Snwhitehorn
277193156Snwhitehorn	vers = mfpvr() >> 16;
278194374Snwhitehorn	msr = mfmsr();
279194374Snwhitehorn	mtmsr(msr & ~PSL_EE);
280193156Snwhitehorn
281193156Snwhitehorn	switch (vers) {
282193156Snwhitehorn		case MPC7450:
283193156Snwhitehorn		case MPC7455:
284193156Snwhitehorn		case MPC7457:
285193156Snwhitehorn		case MPC750:
286193156Snwhitehorn		case IBM750FX:
287193156Snwhitehorn		case MPC7400:
288193156Snwhitehorn		case MPC7410:
289193156Snwhitehorn		case MPC7447A:
290193156Snwhitehorn		case MPC7448:
291193156Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_FC);
292193156Snwhitehorn			mtspr(SPR_PMC1, 0);
293193156Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_PMC1SEL(PMCN_CYCLES));
294194374Snwhitehorn			DELAY(1000);
295194374Snwhitehorn			*cps = (mfspr(SPR_PMC1) * 1000) + 4999;
296194374Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_FC);
297194374Snwhitehorn
298194374Snwhitehorn			mtmsr(msr);
299193156Snwhitehorn			return (0);
300194374Snwhitehorn		case IBM970:
301194374Snwhitehorn		case IBM970FX:
302194374Snwhitehorn		case IBM970MP:
303194374Snwhitehorn			isync();
304194374Snwhitehorn			mtspr(SPR_970MMCR0, SPR_MMCR0_FC);
305194374Snwhitehorn			isync();
306194374Snwhitehorn			mtspr(SPR_970MMCR1, 0);
307194374Snwhitehorn			mtspr(SPR_970MMCRA, 0);
308194374Snwhitehorn			mtspr(SPR_970PMC1, 0);
309194374Snwhitehorn			mtspr(SPR_970MMCR0,
310194374Snwhitehorn			    SPR_970MMCR0_PMC1SEL(PMC970N_CYCLES));
311194374Snwhitehorn			isync();
312194374Snwhitehorn			DELAY(1000);
313194374Snwhitehorn			powerpc_sync();
314194374Snwhitehorn			mtspr(SPR_970MMCR0, SPR_MMCR0_FC);
315194374Snwhitehorn			*cps = (mfspr(SPR_970PMC1) * 1000) + 4999;
316194374Snwhitehorn
317194374Snwhitehorn			mtmsr(msr);
318194374Snwhitehorn			return (0);
319193156Snwhitehorn	}
320194374Snwhitehorn
321193156Snwhitehorn	return (ENXIO);
322110386Sbenno}
323110386Sbenno
324110386Sbennovoid
325198445Snwhitehorncpu_6xx_setup(int cpuid, uint16_t vers)
326110386Sbenno{
327198445Snwhitehorn	register_t hid0, pvr;
328198445Snwhitehorn	const char *bitmask;
329110386Sbenno
330198445Snwhitehorn	hid0 = mfspr(SPR_HID0);
331198445Snwhitehorn	pvr = mfpvr();
332110386Sbenno
333198445Snwhitehorn	/*
334198445Snwhitehorn	 * Configure power-saving mode.
335198445Snwhitehorn	 */
336198445Snwhitehorn	switch (vers) {
337198445Snwhitehorn		case MPC603:
338198445Snwhitehorn		case MPC603e:
339198445Snwhitehorn		case MPC603ev:
340198445Snwhitehorn		case MPC604ev:
341198445Snwhitehorn		case MPC750:
342198445Snwhitehorn		case IBM750FX:
343198445Snwhitehorn		case MPC7400:
344198445Snwhitehorn		case MPC7410:
345198445Snwhitehorn		case MPC8240:
346198445Snwhitehorn		case MPC8245:
347198445Snwhitehorn			/* Select DOZE mode. */
348198445Snwhitehorn			hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
349198445Snwhitehorn			hid0 |= HID0_DOZE | HID0_DPM;
350198445Snwhitehorn			powerpc_pow_enabled = 1;
351198445Snwhitehorn			break;
352198445Snwhitehorn
353198445Snwhitehorn		case MPC7448:
354198445Snwhitehorn		case MPC7447A:
355198445Snwhitehorn		case MPC7457:
356198445Snwhitehorn		case MPC7455:
357198445Snwhitehorn		case MPC7450:
358198445Snwhitehorn			/* Enable the 7450 branch caches */
359198445Snwhitehorn			hid0 |= HID0_SGE | HID0_BTIC;
360198445Snwhitehorn			hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT;
361198445Snwhitehorn			/* Disable BTIC on 7450 Rev 2.0 or earlier and on 7457 */
362198445Snwhitehorn			if (((pvr >> 16) == MPC7450 && (pvr & 0xFFFF) <= 0x0200)
363198445Snwhitehorn					|| (pvr >> 16) == MPC7457)
364198445Snwhitehorn				hid0 &= ~HID0_BTIC;
365198445Snwhitehorn			/* Select NAP mode. */
366198445Snwhitehorn			hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
367198445Snwhitehorn			hid0 |= HID0_NAP | HID0_DPM;
368198445Snwhitehorn			powerpc_pow_enabled = 1;
369198445Snwhitehorn			break;
370198445Snwhitehorn
371198445Snwhitehorn		default:
372198445Snwhitehorn			/* No power-saving mode is available. */ ;
373198445Snwhitehorn	}
374198445Snwhitehorn
375198445Snwhitehorn	switch (vers) {
376198445Snwhitehorn		case IBM750FX:
377198445Snwhitehorn		case MPC750:
378198445Snwhitehorn			hid0 &= ~HID0_DBP;		/* XXX correct? */
379198445Snwhitehorn			hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT;
380198445Snwhitehorn			break;
381198445Snwhitehorn
382198445Snwhitehorn		case MPC7400:
383198445Snwhitehorn		case MPC7410:
384198445Snwhitehorn			hid0 &= ~HID0_SPD;
385198445Snwhitehorn			hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT;
386198445Snwhitehorn			hid0 |= HID0_EIEC;
387198445Snwhitehorn			break;
388198445Snwhitehorn
389198445Snwhitehorn	}
390198445Snwhitehorn
391198445Snwhitehorn	mtspr(SPR_HID0, hid0);
392198445Snwhitehorn
393198445Snwhitehorn	if (bootverbose)
394198445Snwhitehorn		cpu_6xx_print_cacheinfo(cpuid, vers);
395198445Snwhitehorn
396198445Snwhitehorn	switch (vers) {
397198445Snwhitehorn		case MPC7447A:
398198445Snwhitehorn		case MPC7448:
399198445Snwhitehorn		case MPC7450:
400198445Snwhitehorn		case MPC7455:
401198445Snwhitehorn		case MPC7457:
402198445Snwhitehorn			bitmask = HID0_7450_BITMASK;
403198445Snwhitehorn			break;
404198445Snwhitehorn		default:
405198445Snwhitehorn			bitmask = HID0_BITMASK;
406198445Snwhitehorn			break;
407198445Snwhitehorn	}
408198445Snwhitehorn
409199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask);
410215157Snwhitehorn
411215157Snwhitehorn	if (cpu_idle_hook == NULL)
412215157Snwhitehorn		cpu_idle_hook = cpu_idle_60x;
413198445Snwhitehorn}
414198445Snwhitehorn
415198445Snwhitehorn
416198445Snwhitehornstatic void
417198445Snwhitehorncpu_6xx_print_cacheinfo(u_int cpuid, uint16_t vers)
418198445Snwhitehorn{
419198445Snwhitehorn	register_t hid;
420198445Snwhitehorn
421183029Smarcel	hid = mfspr(SPR_HID0);
422183029Smarcel	printf("cpu%u: ", cpuid);
423183029Smarcel	printf("L1 I-cache %sabled, ", (hid & HID0_ICE) ? "en" : "dis");
424183029Smarcel	printf("L1 D-cache %sabled\n", (hid & HID0_DCE) ? "en" : "dis");
425110386Sbenno
426183029Smarcel	printf("cpu%u: ", cpuid);
427198378Snwhitehorn  	if (mfspr(SPR_L2CR) & L2CR_L2E) {
428183029Smarcel		switch (vers) {
429183029Smarcel		case MPC7450:
430183029Smarcel		case MPC7455:
431183029Smarcel		case MPC7457:
432183029Smarcel			printf("256KB L2 cache, ");
433198378Snwhitehorn			if (mfspr(SPR_L3CR) & L3CR_L3E)
434183029Smarcel				printf("%cMB L3 backside cache",
435198378Snwhitehorn				    mfspr(SPR_L3CR) & L3CR_L3SIZ ? '2' : '1');
436183029Smarcel			else
437183029Smarcel				printf("L3 cache disabled");
438110386Sbenno			printf("\n");
439183029Smarcel			break;
440183029Smarcel		case IBM750FX:
441110386Sbenno			printf("512KB L2 cache\n");
442183029Smarcel			break;
443110386Sbenno		default:
444198378Snwhitehorn			switch (mfspr(SPR_L2CR) & L2CR_L2SIZ) {
445183029Smarcel			case L2SIZ_256K:
446183029Smarcel				printf("256KB ");
447183029Smarcel				break;
448183029Smarcel			case L2SIZ_512K:
449183029Smarcel				printf("512KB ");
450183029Smarcel				break;
451183029Smarcel			case L2SIZ_1M:
452183029Smarcel				printf("1MB ");
453183029Smarcel				break;
454183029Smarcel			}
455198378Snwhitehorn			printf("write-%s", (mfspr(SPR_L2CR) & L2CR_L2WT)
456183029Smarcel			    ? "through" : "back");
457198378Snwhitehorn			if (mfspr(SPR_L2CR) & L2CR_L2PE)
458183029Smarcel				printf(", with parity");
459183029Smarcel			printf(" backside cache\n");
460110386Sbenno			break;
461110386Sbenno		}
462110386Sbenno	} else
463183029Smarcel		printf("L2 cache disabled\n");
464110386Sbenno}
465198445Snwhitehorn
466198445Snwhitehornstatic void
467236097Srajcpu_booke_setup(int cpuid, uint16_t vers)
468198445Snwhitehorn{
469236141Sraj#ifdef BOOKE_E500
470198445Snwhitehorn	register_t hid0;
471198445Snwhitehorn
472198445Snwhitehorn	hid0 = mfspr(SPR_HID0);
473205527Smarcel
474205527Smarcel	/* Programe power-management mode. */
475205527Smarcel	hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
476205527Smarcel	hid0 |= HID0_DOZE;
477205527Smarcel
478205527Smarcel	mtspr(SPR_HID0, hid0);
479205527Smarcel
480199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, HID0_E500_BITMASK);
481236141Sraj#endif
482215157Snwhitehorn
483215157Snwhitehorn	if (cpu_idle_hook == NULL)
484236097Sraj		cpu_idle_hook = cpu_idle_booke;
485198445Snwhitehorn}
486198445Snwhitehorn
487198445Snwhitehornstatic void
488198445Snwhitehorncpu_970_setup(int cpuid, uint16_t vers)
489198445Snwhitehorn{
490199886Snwhitehorn#ifdef AIM
491198445Snwhitehorn	uint32_t hid0_hi, hid0_lo;
492198445Snwhitehorn
493198445Snwhitehorn	__asm __volatile ("mfspr %0,%2; clrldi %1,%0,32; srdi %0,%0,32;"
494198445Snwhitehorn	    : "=r" (hid0_hi), "=r" (hid0_lo) : "K" (SPR_HID0));
495198445Snwhitehorn
496198445Snwhitehorn	/* Configure power-saving mode */
497204127Snwhitehorn	switch (vers) {
498204127Snwhitehorn	case IBM970MP:
499215101Snwhitehorn		hid0_hi |= (HID0_DEEPNAP | HID0_NAP | HID0_DPM);
500215101Snwhitehorn		hid0_hi &= ~HID0_DOZE;
501204127Snwhitehorn		break;
502204127Snwhitehorn	default:
503204127Snwhitehorn		hid0_hi |= (HID0_NAP | HID0_DPM);
504204127Snwhitehorn		hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP);
505204127Snwhitehorn		break;
506204127Snwhitehorn	}
507198445Snwhitehorn	powerpc_pow_enabled = 1;
508198445Snwhitehorn
509198445Snwhitehorn	__asm __volatile (" \
510198445Snwhitehorn		sync; isync;					\
511198445Snwhitehorn		sldi	%0,%0,32; or %0,%0,%1;			\
512198445Snwhitehorn		mtspr	%2, %0;					\
513198445Snwhitehorn		mfspr   %0, %2; mfspr   %0, %2; mfspr   %0, %2; \
514198445Snwhitehorn		mfspr   %0, %2; mfspr   %0, %2; mfspr   %0, %2; \
515198445Snwhitehorn		sync; isync"
516198445Snwhitehorn	    :: "r" (hid0_hi), "r"(hid0_lo), "K" (SPR_HID0));
517198445Snwhitehorn
518198445Snwhitehorn	__asm __volatile ("mfspr %0,%1; srdi %0,%0,32;"
519198445Snwhitehorn	    : "=r" (hid0_hi) : "K" (SPR_HID0));
520199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK);
521199886Snwhitehorn#endif
522215157Snwhitehorn
523215157Snwhitehorn	cpu_idle_hook = cpu_idle_60x;
524198445Snwhitehorn}
525199886Snwhitehorn
526199886Snwhitehornstatic int
527199886Snwhitehorncpu_feature_bit(SYSCTL_HANDLER_ARGS)
528199886Snwhitehorn{
529199886Snwhitehorn	int result;
530199886Snwhitehorn
531199886Snwhitehorn	result = (cpu_features & arg2) ? 1 : 0;
532199886Snwhitehorn
533199886Snwhitehorn	return (sysctl_handle_int(oidp, &result, 0, req));
534199886Snwhitehorn}
535199886Snwhitehorn
536215157Snwhitehornvoid
537215157Snwhitehorncpu_idle(int busy)
538215157Snwhitehorn{
539247454Sdavide	sbintime_t sbt = -1;
540215157Snwhitehorn
541215157Snwhitehorn#ifdef INVARIANTS
542215157Snwhitehorn	if ((mfmsr() & PSL_EE) != PSL_EE) {
543215157Snwhitehorn		struct thread *td = curthread;
544215157Snwhitehorn		printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr);
545215157Snwhitehorn		panic("ints disabled in idleproc!");
546215157Snwhitehorn	}
547215157Snwhitehorn#endif
548215157Snwhitehorn
549215157Snwhitehorn	CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
550215157Snwhitehorn	    busy, curcpu);
551236097Sraj
552215157Snwhitehorn	if (cpu_idle_hook != NULL) {
553215157Snwhitehorn		if (!busy) {
554215157Snwhitehorn			critical_enter();
555247454Sdavide			sbt = cpu_idleclock();
556215157Snwhitehorn		}
557247454Sdavide		cpu_idle_hook(sbt);
558215157Snwhitehorn		if (!busy) {
559215157Snwhitehorn			cpu_activeclock();
560215157Snwhitehorn			critical_exit();
561215157Snwhitehorn		}
562215157Snwhitehorn	}
563236097Sraj
564215157Snwhitehorn	CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
565215157Snwhitehorn	    busy, curcpu);
566215157Snwhitehorn}
567215157Snwhitehorn
568215157Snwhitehornint
569215157Snwhitehorncpu_idle_wakeup(int cpu)
570215157Snwhitehorn{
571215157Snwhitehorn	return (0);
572215157Snwhitehorn}
573215157Snwhitehorn
574215157Snwhitehornstatic void
575247454Sdavidecpu_idle_60x(sbintime_t sbt)
576215157Snwhitehorn{
577215157Snwhitehorn	register_t msr;
578215157Snwhitehorn	uint16_t vers;
579215157Snwhitehorn
580215157Snwhitehorn	if (!powerpc_pow_enabled)
581215157Snwhitehorn		return;
582215157Snwhitehorn
583215157Snwhitehorn	msr = mfmsr();
584215157Snwhitehorn	vers = mfpvr() >> 16;
585215157Snwhitehorn
586215157Snwhitehorn#ifdef AIM
587215157Snwhitehorn	switch (vers) {
588215157Snwhitehorn	case IBM970:
589215157Snwhitehorn	case IBM970FX:
590215157Snwhitehorn	case IBM970MP:
591215157Snwhitehorn	case MPC7447A:
592215157Snwhitehorn	case MPC7448:
593215157Snwhitehorn	case MPC7450:
594215157Snwhitehorn	case MPC7455:
595215157Snwhitehorn	case MPC7457:
596215157Snwhitehorn		__asm __volatile("\
597215157Snwhitehorn			    dssall; sync; mtmsr %0; isync"
598215157Snwhitehorn			    :: "r"(msr | PSL_POW));
599215157Snwhitehorn		break;
600215157Snwhitehorn	default:
601215157Snwhitehorn		powerpc_sync();
602215157Snwhitehorn		mtmsr(msr | PSL_POW);
603215157Snwhitehorn		isync();
604215157Snwhitehorn		break;
605215157Snwhitehorn	}
606215157Snwhitehorn#endif
607215157Snwhitehorn}
608215157Snwhitehorn
609215157Snwhitehornstatic void
610247454Sdavidecpu_idle_booke(sbintime_t sbt)
611215157Snwhitehorn{
612215157Snwhitehorn	register_t msr;
613215157Snwhitehorn
614215157Snwhitehorn	msr = mfmsr();
615215157Snwhitehorn
616215157Snwhitehorn#ifdef E500
617215157Snwhitehorn	/* Freescale E500 core RM section 6.4.1. */
618215157Snwhitehorn	__asm __volatile("msync; mtmsr %0; isync" ::
619215157Snwhitehorn	    "r" (msr | PSL_WE));
620215157Snwhitehorn#endif
621215157Snwhitehorn}
622215157Snwhitehorn
623