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: stable/11/sys/powerpc/powerpc/cpu.c 310441 2016-12-23 03:14:05Z jhibbits $
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
77258722Sandreast#include <dev/ofw/openfirm.h>
78258722Sandreast
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 */
94293052Snwhitehorn	int		features2;
95199886Snwhitehorn	void		(*cpu_setup)(int cpuid, uint16_t vers);
96110386Sbenno};
97110386Sbenno#define	REVFMT_MAJMIN	1	/* %u.%u */
98110386Sbenno#define	REVFMT_HEX	2	/* 0x%04x */
99110386Sbenno#define	REVFMT_DEC	3	/* %u */
100110386Sbennostatic const struct cputab models[] = {
101199886Snwhitehorn        { "Motorola PowerPC 601",	MPC601,		REVFMT_DEC,
102293052Snwhitehorn	   PPC_FEATURE_HAS_FPU | PPC_FEATURE_UNIFIED_CACHE, 0, cpu_6xx_setup },
103199886Snwhitehorn        { "Motorola PowerPC 602",	MPC602,		REVFMT_DEC,
104293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
105199886Snwhitehorn        { "Motorola PowerPC 603",	MPC603,		REVFMT_MAJMIN,
106293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
107199886Snwhitehorn        { "Motorola PowerPC 603e",	MPC603e,	REVFMT_MAJMIN,
108293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
109199886Snwhitehorn        { "Motorola PowerPC 603ev",	MPC603ev,	REVFMT_MAJMIN,
110293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
111199886Snwhitehorn        { "Motorola PowerPC 604",	MPC604,		REVFMT_MAJMIN,
112293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
113199886Snwhitehorn        { "Motorola PowerPC 604ev",	MPC604ev,	REVFMT_MAJMIN,
114293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
115199886Snwhitehorn        { "Motorola PowerPC 620",	MPC620,		REVFMT_HEX,
116293052Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, 0, NULL },
117199886Snwhitehorn        { "Motorola PowerPC 750",	MPC750,		REVFMT_MAJMIN,
118293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
119199886Snwhitehorn        { "IBM PowerPC 750FX",		IBM750FX,	REVFMT_MAJMIN,
120293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
121199886Snwhitehorn        { "IBM PowerPC 970",		IBM970,		REVFMT_MAJMIN,
122199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
123293052Snwhitehorn	   0, cpu_970_setup },
124199886Snwhitehorn        { "IBM PowerPC 970FX",		IBM970FX,	REVFMT_MAJMIN,
125199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
126293052Snwhitehorn	   0, cpu_970_setup },
127199886Snwhitehorn        { "IBM PowerPC 970GX",		IBM970GX,	REVFMT_MAJMIN,
128199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
129293052Snwhitehorn	   0, cpu_970_setup },
130199886Snwhitehorn        { "IBM PowerPC 970MP",		IBM970MP,	REVFMT_MAJMIN,
131199886Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
132293052Snwhitehorn	   0, cpu_970_setup },
133255418Snwhitehorn        { "IBM POWER4",		IBMPOWER4,	REVFMT_MAJMIN,
134293052Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, 0, NULL },
135255418Snwhitehorn        { "IBM POWER4+",	IBMPOWER4PLUS,	REVFMT_MAJMIN,
136293052Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, 0, NULL },
137255418Snwhitehorn        { "IBM POWER5",		IBMPOWER5,	REVFMT_MAJMIN,
138293052Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_SMT, 0, NULL },
139255418Snwhitehorn        { "IBM POWER5+",	IBMPOWER5PLUS,	REVFMT_MAJMIN,
140293052Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_SMT, 0, NULL },
141255418Snwhitehorn        { "IBM POWER6",		IBMPOWER6,	REVFMT_MAJMIN,
142293052Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
143293052Snwhitehorn	   PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05, 0, NULL },
144255418Snwhitehorn        { "IBM POWER7",		IBMPOWER7,	REVFMT_MAJMIN,
145279189Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
146293052Snwhitehorn	   PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 |
147293052Snwhitehorn	   PPC_FEATURE_HAS_VSX, 0, NULL },
148255640Snwhitehorn        { "IBM POWER7+",	IBMPOWER7PLUS,	REVFMT_MAJMIN,
149279189Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
150293052Snwhitehorn	   PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 |
151293052Snwhitehorn	   PPC_FEATURE_HAS_VSX, 0, NULL },
152268320Snwhitehorn        { "IBM POWER8E",	IBMPOWER8E,	REVFMT_MAJMIN,
153279189Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
154293052Snwhitehorn	   PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 |
155293052Snwhitehorn	   PPC_FEATURE_HAS_VSX,
156293052Snwhitehorn	   PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_HAS_HTM |
157293052Snwhitehorn	   PPC_FEATURE2_HAS_VCRYPTO, NULL },
158255640Snwhitehorn        { "IBM POWER8",		IBMPOWER8,	REVFMT_MAJMIN,
159279189Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
160293052Snwhitehorn	   PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 |
161293052Snwhitehorn	   PPC_FEATURE_HAS_VSX,
162293052Snwhitehorn	   PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_HAS_HTM |
163293052Snwhitehorn	   PPC_FEATURE2_HAS_VCRYPTO, NULL },
164199886Snwhitehorn        { "Motorola PowerPC 7400",	MPC7400,	REVFMT_MAJMIN,
165293052Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
166199886Snwhitehorn        { "Motorola PowerPC 7410",	MPC7410,	REVFMT_MAJMIN,
167293052Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
168199886Snwhitehorn        { "Motorola PowerPC 7450",	MPC7450,	REVFMT_MAJMIN,
169293052Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
170199886Snwhitehorn        { "Motorola PowerPC 7455",	MPC7455,	REVFMT_MAJMIN,
171293052Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
172199886Snwhitehorn        { "Motorola PowerPC 7457",	MPC7457,	REVFMT_MAJMIN,
173293052Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
174199886Snwhitehorn        { "Motorola PowerPC 7447A",	MPC7447A,	REVFMT_MAJMIN,
175293052Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
176199886Snwhitehorn        { "Motorola PowerPC 7448",	MPC7448,	REVFMT_MAJMIN,
177293052Snwhitehorn	   PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
178199886Snwhitehorn        { "Motorola PowerPC 8240",	MPC8240,	REVFMT_MAJMIN,
179293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
180199886Snwhitehorn        { "Motorola PowerPC 8245",	MPC8245,	REVFMT_MAJMIN,
181293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
182199886Snwhitehorn        { "Freescale e500v1 core",	FSL_E500v1,	REVFMT_MAJMIN,
183293052Snwhitehorn	   PPC_FEATURE_BOOKE, 0, cpu_booke_setup },
184199886Snwhitehorn        { "Freescale e500v2 core",	FSL_E500v2,	REVFMT_MAJMIN,
185293052Snwhitehorn	   PPC_FEATURE_BOOKE, 0, cpu_booke_setup },
186236097Sraj	{ "Freescale e500mc core",	FSL_E500mc,	REVFMT_MAJMIN,
187293052Snwhitehorn	   PPC_FEATURE_BOOKE | PPC_FEATURE_HAS_FPU, 0, cpu_booke_setup },
188236097Sraj	{ "Freescale e5500 core",	FSL_E5500,	REVFMT_MAJMIN,
189293052Snwhitehorn	   PPC_FEATURE_BOOKE | PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, 0,
190293052Snwhitehorn	   cpu_booke_setup },
191292858Sjhibbits	{ "Freescale e6500 core",	FSL_E6500,	REVFMT_MAJMIN,
192293052Snwhitehorn	   PPC_FEATURE_BOOKE | PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC |
193293052Snwhitehorn	   PPC_FEATURE_HAS_FPU, 0, cpu_booke_setup },
194215182Snwhitehorn        { "IBM Cell Broadband Engine",	IBMCELLBE,	REVFMT_MAJMIN,
195293052Snwhitehorn	   PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
196293052Snwhitehorn	   PPC_FEATURE_SMT, 0, NULL},
197293052Snwhitehorn        { "Unknown PowerPC CPU",	0,		REVFMT_HEX, 0, 0, NULL },
198110386Sbenno};
199110386Sbenno
200199886Snwhitehornstatic void	cpu_6xx_print_cacheinfo(u_int, uint16_t);
201199886Snwhitehornstatic int	cpu_feature_bit(SYSCTL_HANDLER_ARGS);
202199886Snwhitehorn
203166011Smarcelstatic char model[64];
204166011SmarcelSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, "");
205166011Smarcel
206199886Snwhitehornint cpu_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU;
207293052Snwhitehornint cpu_features2 = 0;
208273377ShselaskySYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLFLAG_RD,
209199886Snwhitehorn    &cpu_features, sizeof(cpu_features), "IX", "PowerPC CPU features");
210293052SnwhitehornSYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features2, CTLFLAG_RD,
211293052Snwhitehorn    &cpu_features2, sizeof(cpu_features2), "IX", "PowerPC CPU features 2");
212110386Sbenno
213199886Snwhitehorn/* Provide some user-friendly aliases for bits in cpu_features */
214199886SnwhitehornSYSCTL_PROC(_hw, OID_AUTO, floatingpoint, CTLTYPE_INT | CTLFLAG_RD,
215199886Snwhitehorn    0, PPC_FEATURE_HAS_FPU, cpu_feature_bit, "I",
216199886Snwhitehorn    "Floating point instructions executed in hardware");
217199886SnwhitehornSYSCTL_PROC(_hw, OID_AUTO, altivec, CTLTYPE_INT | CTLFLAG_RD,
218199886Snwhitehorn    0, PPC_FEATURE_HAS_ALTIVEC, cpu_feature_bit, "I", "CPU supports Altivec");
219198445Snwhitehorn
220110386Sbennovoid
221110386Sbennocpu_setup(u_int cpuid)
222110386Sbenno{
223198445Snwhitehorn	u_int		pvr, maj, min;
224110386Sbenno	uint16_t	vers, rev, revfmt;
225199886Snwhitehorn	uint64_t	cps;
226110386Sbenno	const struct	cputab *cp;
227110386Sbenno	const char	*name;
228110386Sbenno
229110386Sbenno	pvr = mfpvr();
230110386Sbenno	vers = pvr >> 16;
231110386Sbenno	rev = pvr;
232110386Sbenno	switch (vers) {
233176534Sraj		case MPC7410:
234176534Sraj			min = (pvr >> 0) & 0xff;
235176534Sraj			maj = min <= 4 ? 1 : 2;
236176534Sraj			break;
237176534Sraj		case FSL_E500v1:
238176534Sraj		case FSL_E500v2:
239236097Sraj		case FSL_E500mc:
240236097Sraj		case FSL_E5500:
241176534Sraj			maj = (pvr >>  4) & 0xf;
242176534Sraj			min = (pvr >>  0) & 0xf;
243176534Sraj			break;
244176534Sraj		default:
245176534Sraj			maj = (pvr >>  8) & 0xf;
246176534Sraj			min = (pvr >>  0) & 0xf;
247110386Sbenno	}
248110386Sbenno
249166812Smarcel	for (cp = models; cp->version != 0; cp++) {
250110386Sbenno		if (cp->version == vers)
251110386Sbenno			break;
252110386Sbenno	}
253110386Sbenno
254110386Sbenno	revfmt = cp->revfmt;
255110386Sbenno	name = cp->name;
256110386Sbenno	if (rev == MPC750 && pvr == 15) {
257110386Sbenno		name = "Motorola MPC755";
258110386Sbenno		revfmt = REVFMT_HEX;
259110386Sbenno	}
260166011Smarcel	strncpy(model, name, sizeof(model) - 1);
261110386Sbenno
262110386Sbenno	printf("cpu%d: %s revision ", cpuid, name);
263110386Sbenno
264110386Sbenno	switch (revfmt) {
265176534Sraj		case REVFMT_MAJMIN:
266176534Sraj			printf("%u.%u", maj, min);
267176534Sraj			break;
268176534Sraj		case REVFMT_HEX:
269176534Sraj			printf("0x%04x", rev);
270176534Sraj			break;
271176534Sraj		case REVFMT_DEC:
272176534Sraj			printf("%u", rev);
273176534Sraj			break;
274110386Sbenno	}
275110386Sbenno
276199886Snwhitehorn	if (cpu_est_clockrate(0, &cps) == 0)
277209975Snwhitehorn		printf(", %jd.%02jd MHz", cps / 1000000, (cps / 10000) % 100);
278199886Snwhitehorn	printf("\n");
279199886Snwhitehorn
280199886Snwhitehorn	cpu_features |= cp->features;
281293052Snwhitehorn	cpu_features2 |= cp->features2;
282199886Snwhitehorn	printf("cpu%d: Features %b\n", cpuid, cpu_features,
283199886Snwhitehorn	    PPC_FEATURE_BITMASK);
284293052Snwhitehorn	if (cpu_features2 != 0)
285293052Snwhitehorn		printf("cpu%d: Features2 %b\n", cpuid, cpu_features2,
286293052Snwhitehorn		    PPC_FEATURE2_BITMASK);
287199886Snwhitehorn
288110386Sbenno	/*
289198445Snwhitehorn	 * Configure CPU
290110386Sbenno	 */
291199886Snwhitehorn	if (cp->cpu_setup != NULL)
292199886Snwhitehorn		cp->cpu_setup(cpuid, vers);
293110386Sbenno}
294110386Sbenno
295193156Snwhitehorn/* Get current clock frequency for the given cpu id. */
296193156Snwhitehornint
297193156Snwhitehorncpu_est_clockrate(int cpu_id, uint64_t *cps)
298193156Snwhitehorn{
299193156Snwhitehorn	uint16_t	vers;
300194374Snwhitehorn	register_t	msr;
301258722Sandreast	phandle_t	cpu, dev, root;
302258722Sandreast	int		res  = 0;
303258722Sandreast	char		buf[8];
304193156Snwhitehorn
305193156Snwhitehorn	vers = mfpvr() >> 16;
306194374Snwhitehorn	msr = mfmsr();
307194374Snwhitehorn	mtmsr(msr & ~PSL_EE);
308193156Snwhitehorn
309193156Snwhitehorn	switch (vers) {
310193156Snwhitehorn		case MPC7450:
311193156Snwhitehorn		case MPC7455:
312193156Snwhitehorn		case MPC7457:
313193156Snwhitehorn		case MPC750:
314193156Snwhitehorn		case IBM750FX:
315193156Snwhitehorn		case MPC7400:
316193156Snwhitehorn		case MPC7410:
317193156Snwhitehorn		case MPC7447A:
318193156Snwhitehorn		case MPC7448:
319193156Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_FC);
320193156Snwhitehorn			mtspr(SPR_PMC1, 0);
321193156Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_PMC1SEL(PMCN_CYCLES));
322194374Snwhitehorn			DELAY(1000);
323194374Snwhitehorn			*cps = (mfspr(SPR_PMC1) * 1000) + 4999;
324194374Snwhitehorn			mtspr(SPR_MMCR0, SPR_MMCR0_FC);
325194374Snwhitehorn
326194374Snwhitehorn			mtmsr(msr);
327193156Snwhitehorn			return (0);
328194374Snwhitehorn		case IBM970:
329194374Snwhitehorn		case IBM970FX:
330194374Snwhitehorn		case IBM970MP:
331194374Snwhitehorn			isync();
332194374Snwhitehorn			mtspr(SPR_970MMCR0, SPR_MMCR0_FC);
333194374Snwhitehorn			isync();
334194374Snwhitehorn			mtspr(SPR_970MMCR1, 0);
335194374Snwhitehorn			mtspr(SPR_970MMCRA, 0);
336194374Snwhitehorn			mtspr(SPR_970PMC1, 0);
337194374Snwhitehorn			mtspr(SPR_970MMCR0,
338194374Snwhitehorn			    SPR_970MMCR0_PMC1SEL(PMC970N_CYCLES));
339194374Snwhitehorn			isync();
340194374Snwhitehorn			DELAY(1000);
341194374Snwhitehorn			powerpc_sync();
342194374Snwhitehorn			mtspr(SPR_970MMCR0, SPR_MMCR0_FC);
343194374Snwhitehorn			*cps = (mfspr(SPR_970PMC1) * 1000) + 4999;
344194374Snwhitehorn
345194374Snwhitehorn			mtmsr(msr);
346194374Snwhitehorn			return (0);
347258722Sandreast
348258757Snwhitehorn		default:
349258722Sandreast			root = OF_peer(0);
350258757Snwhitehorn			if (root == 0)
351258757Snwhitehorn				return (ENXIO);
352258757Snwhitehorn
353258722Sandreast			dev = OF_child(root);
354258722Sandreast			while (dev != 0) {
355258722Sandreast				res = OF_getprop(dev, "name", buf, sizeof(buf));
356258722Sandreast				if (res > 0 && strcmp(buf, "cpus") == 0)
357258722Sandreast					break;
358258722Sandreast				dev = OF_peer(dev);
359258722Sandreast			}
360258722Sandreast			cpu = OF_child(dev);
361258722Sandreast			while (cpu != 0) {
362258722Sandreast				res = OF_getprop(cpu, "device_type", buf,
363258722Sandreast						sizeof(buf));
364258722Sandreast				if (res > 0 && strcmp(buf, "cpu") == 0)
365258722Sandreast					break;
366258722Sandreast				cpu = OF_peer(cpu);
367258722Sandreast			}
368258722Sandreast			if (cpu == 0)
369258722Sandreast				return (ENOENT);
370258757Snwhitehorn			if (OF_getprop(cpu, "ibm,extended-clock-frequency",
371258757Snwhitehorn			    cps, sizeof(*cps)) >= 0) {
372258757Snwhitehorn				return (0);
373258757Snwhitehorn			} else if (OF_getprop(cpu, "clock-frequency", cps,
374258757Snwhitehorn			    sizeof(cell_t)) >= 0) {
375258757Snwhitehorn				*cps >>= 32;
376258757Snwhitehorn				return (0);
377258757Snwhitehorn			} else {
378258757Snwhitehorn				return (ENOENT);
379258757Snwhitehorn			}
380193156Snwhitehorn	}
381110386Sbenno}
382110386Sbenno
383110386Sbennovoid
384198445Snwhitehorncpu_6xx_setup(int cpuid, uint16_t vers)
385110386Sbenno{
386198445Snwhitehorn	register_t hid0, pvr;
387198445Snwhitehorn	const char *bitmask;
388110386Sbenno
389198445Snwhitehorn	hid0 = mfspr(SPR_HID0);
390198445Snwhitehorn	pvr = mfpvr();
391110386Sbenno
392198445Snwhitehorn	/*
393198445Snwhitehorn	 * Configure power-saving mode.
394198445Snwhitehorn	 */
395198445Snwhitehorn	switch (vers) {
396198445Snwhitehorn		case MPC603:
397198445Snwhitehorn		case MPC603e:
398198445Snwhitehorn		case MPC603ev:
399198445Snwhitehorn		case MPC604ev:
400198445Snwhitehorn		case MPC750:
401198445Snwhitehorn		case IBM750FX:
402198445Snwhitehorn		case MPC7400:
403198445Snwhitehorn		case MPC7410:
404198445Snwhitehorn		case MPC8240:
405198445Snwhitehorn		case MPC8245:
406198445Snwhitehorn			/* Select DOZE mode. */
407198445Snwhitehorn			hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
408198445Snwhitehorn			hid0 |= HID0_DOZE | HID0_DPM;
409198445Snwhitehorn			powerpc_pow_enabled = 1;
410198445Snwhitehorn			break;
411198445Snwhitehorn
412198445Snwhitehorn		case MPC7448:
413198445Snwhitehorn		case MPC7447A:
414198445Snwhitehorn		case MPC7457:
415198445Snwhitehorn		case MPC7455:
416198445Snwhitehorn		case MPC7450:
417198445Snwhitehorn			/* Enable the 7450 branch caches */
418198445Snwhitehorn			hid0 |= HID0_SGE | HID0_BTIC;
419198445Snwhitehorn			hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT;
420198445Snwhitehorn			/* Disable BTIC on 7450 Rev 2.0 or earlier and on 7457 */
421198445Snwhitehorn			if (((pvr >> 16) == MPC7450 && (pvr & 0xFFFF) <= 0x0200)
422198445Snwhitehorn					|| (pvr >> 16) == MPC7457)
423198445Snwhitehorn				hid0 &= ~HID0_BTIC;
424198445Snwhitehorn			/* Select NAP mode. */
425198445Snwhitehorn			hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
426198445Snwhitehorn			hid0 |= HID0_NAP | HID0_DPM;
427198445Snwhitehorn			powerpc_pow_enabled = 1;
428198445Snwhitehorn			break;
429198445Snwhitehorn
430198445Snwhitehorn		default:
431198445Snwhitehorn			/* No power-saving mode is available. */ ;
432198445Snwhitehorn	}
433198445Snwhitehorn
434198445Snwhitehorn	switch (vers) {
435198445Snwhitehorn		case IBM750FX:
436198445Snwhitehorn		case MPC750:
437198445Snwhitehorn			hid0 &= ~HID0_DBP;		/* XXX correct? */
438198445Snwhitehorn			hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT;
439198445Snwhitehorn			break;
440198445Snwhitehorn
441198445Snwhitehorn		case MPC7400:
442198445Snwhitehorn		case MPC7410:
443198445Snwhitehorn			hid0 &= ~HID0_SPD;
444198445Snwhitehorn			hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT;
445198445Snwhitehorn			hid0 |= HID0_EIEC;
446198445Snwhitehorn			break;
447198445Snwhitehorn
448198445Snwhitehorn	}
449198445Snwhitehorn
450198445Snwhitehorn	mtspr(SPR_HID0, hid0);
451198445Snwhitehorn
452198445Snwhitehorn	if (bootverbose)
453198445Snwhitehorn		cpu_6xx_print_cacheinfo(cpuid, vers);
454198445Snwhitehorn
455198445Snwhitehorn	switch (vers) {
456198445Snwhitehorn		case MPC7447A:
457198445Snwhitehorn		case MPC7448:
458198445Snwhitehorn		case MPC7450:
459198445Snwhitehorn		case MPC7455:
460198445Snwhitehorn		case MPC7457:
461198445Snwhitehorn			bitmask = HID0_7450_BITMASK;
462198445Snwhitehorn			break;
463198445Snwhitehorn		default:
464198445Snwhitehorn			bitmask = HID0_BITMASK;
465198445Snwhitehorn			break;
466198445Snwhitehorn	}
467198445Snwhitehorn
468199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask);
469215157Snwhitehorn
470215157Snwhitehorn	if (cpu_idle_hook == NULL)
471215157Snwhitehorn		cpu_idle_hook = cpu_idle_60x;
472198445Snwhitehorn}
473198445Snwhitehorn
474198445Snwhitehorn
475198445Snwhitehornstatic void
476198445Snwhitehorncpu_6xx_print_cacheinfo(u_int cpuid, uint16_t vers)
477198445Snwhitehorn{
478198445Snwhitehorn	register_t hid;
479198445Snwhitehorn
480183029Smarcel	hid = mfspr(SPR_HID0);
481183029Smarcel	printf("cpu%u: ", cpuid);
482183029Smarcel	printf("L1 I-cache %sabled, ", (hid & HID0_ICE) ? "en" : "dis");
483183029Smarcel	printf("L1 D-cache %sabled\n", (hid & HID0_DCE) ? "en" : "dis");
484110386Sbenno
485183029Smarcel	printf("cpu%u: ", cpuid);
486198378Snwhitehorn  	if (mfspr(SPR_L2CR) & L2CR_L2E) {
487183029Smarcel		switch (vers) {
488183029Smarcel		case MPC7450:
489183029Smarcel		case MPC7455:
490183029Smarcel		case MPC7457:
491183029Smarcel			printf("256KB L2 cache, ");
492198378Snwhitehorn			if (mfspr(SPR_L3CR) & L3CR_L3E)
493183029Smarcel				printf("%cMB L3 backside cache",
494198378Snwhitehorn				    mfspr(SPR_L3CR) & L3CR_L3SIZ ? '2' : '1');
495183029Smarcel			else
496183029Smarcel				printf("L3 cache disabled");
497110386Sbenno			printf("\n");
498183029Smarcel			break;
499183029Smarcel		case IBM750FX:
500110386Sbenno			printf("512KB L2 cache\n");
501183029Smarcel			break;
502110386Sbenno		default:
503198378Snwhitehorn			switch (mfspr(SPR_L2CR) & L2CR_L2SIZ) {
504183029Smarcel			case L2SIZ_256K:
505183029Smarcel				printf("256KB ");
506183029Smarcel				break;
507183029Smarcel			case L2SIZ_512K:
508183029Smarcel				printf("512KB ");
509183029Smarcel				break;
510183029Smarcel			case L2SIZ_1M:
511183029Smarcel				printf("1MB ");
512183029Smarcel				break;
513183029Smarcel			}
514198378Snwhitehorn			printf("write-%s", (mfspr(SPR_L2CR) & L2CR_L2WT)
515183029Smarcel			    ? "through" : "back");
516198378Snwhitehorn			if (mfspr(SPR_L2CR) & L2CR_L2PE)
517183029Smarcel				printf(", with parity");
518183029Smarcel			printf(" backside cache\n");
519110386Sbenno			break;
520110386Sbenno		}
521110386Sbenno	} else
522183029Smarcel		printf("L2 cache disabled\n");
523110386Sbenno}
524198445Snwhitehorn
525198445Snwhitehornstatic void
526236097Srajcpu_booke_setup(int cpuid, uint16_t vers)
527198445Snwhitehorn{
528236141Sraj#ifdef BOOKE_E500
529198445Snwhitehorn	register_t hid0;
530198445Snwhitehorn
531198445Snwhitehorn	hid0 = mfspr(SPR_HID0);
532205527Smarcel
533205527Smarcel	/* Programe power-management mode. */
534205527Smarcel	hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
535205527Smarcel	hid0 |= HID0_DOZE;
536205527Smarcel
537205527Smarcel	mtspr(SPR_HID0, hid0);
538205527Smarcel
539199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, HID0_E500_BITMASK);
540236141Sraj#endif
541215157Snwhitehorn
542215157Snwhitehorn	if (cpu_idle_hook == NULL)
543236097Sraj		cpu_idle_hook = cpu_idle_booke;
544198445Snwhitehorn}
545198445Snwhitehorn
546198445Snwhitehornstatic void
547198445Snwhitehorncpu_970_setup(int cpuid, uint16_t vers)
548198445Snwhitehorn{
549199886Snwhitehorn#ifdef AIM
550198445Snwhitehorn	uint32_t hid0_hi, hid0_lo;
551198445Snwhitehorn
552198445Snwhitehorn	__asm __volatile ("mfspr %0,%2; clrldi %1,%0,32; srdi %0,%0,32;"
553198445Snwhitehorn	    : "=r" (hid0_hi), "=r" (hid0_lo) : "K" (SPR_HID0));
554198445Snwhitehorn
555198445Snwhitehorn	/* Configure power-saving mode */
556204127Snwhitehorn	switch (vers) {
557204127Snwhitehorn	case IBM970MP:
558215101Snwhitehorn		hid0_hi |= (HID0_DEEPNAP | HID0_NAP | HID0_DPM);
559215101Snwhitehorn		hid0_hi &= ~HID0_DOZE;
560204127Snwhitehorn		break;
561204127Snwhitehorn	default:
562204127Snwhitehorn		hid0_hi |= (HID0_NAP | HID0_DPM);
563204127Snwhitehorn		hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP);
564204127Snwhitehorn		break;
565204127Snwhitehorn	}
566198445Snwhitehorn	powerpc_pow_enabled = 1;
567198445Snwhitehorn
568198445Snwhitehorn	__asm __volatile (" \
569198445Snwhitehorn		sync; isync;					\
570198445Snwhitehorn		sldi	%0,%0,32; or %0,%0,%1;			\
571198445Snwhitehorn		mtspr	%2, %0;					\
572198445Snwhitehorn		mfspr   %0, %2; mfspr   %0, %2; mfspr   %0, %2; \
573198445Snwhitehorn		mfspr   %0, %2; mfspr   %0, %2; mfspr   %0, %2; \
574198445Snwhitehorn		sync; isync"
575198445Snwhitehorn	    :: "r" (hid0_hi), "r"(hid0_lo), "K" (SPR_HID0));
576198445Snwhitehorn
577198445Snwhitehorn	__asm __volatile ("mfspr %0,%1; srdi %0,%0,32;"
578198445Snwhitehorn	    : "=r" (hid0_hi) : "K" (SPR_HID0));
579199886Snwhitehorn	printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK);
580199886Snwhitehorn#endif
581215157Snwhitehorn
582215157Snwhitehorn	cpu_idle_hook = cpu_idle_60x;
583198445Snwhitehorn}
584199886Snwhitehorn
585199886Snwhitehornstatic int
586199886Snwhitehorncpu_feature_bit(SYSCTL_HANDLER_ARGS)
587199886Snwhitehorn{
588199886Snwhitehorn	int result;
589199886Snwhitehorn
590199886Snwhitehorn	result = (cpu_features & arg2) ? 1 : 0;
591199886Snwhitehorn
592199886Snwhitehorn	return (sysctl_handle_int(oidp, &result, 0, req));
593199886Snwhitehorn}
594199886Snwhitehorn
595215157Snwhitehornvoid
596215157Snwhitehorncpu_idle(int busy)
597215157Snwhitehorn{
598247454Sdavide	sbintime_t sbt = -1;
599215157Snwhitehorn
600215157Snwhitehorn#ifdef INVARIANTS
601215157Snwhitehorn	if ((mfmsr() & PSL_EE) != PSL_EE) {
602215157Snwhitehorn		struct thread *td = curthread;
603215157Snwhitehorn		printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr);
604215157Snwhitehorn		panic("ints disabled in idleproc!");
605215157Snwhitehorn	}
606215157Snwhitehorn#endif
607215157Snwhitehorn
608215157Snwhitehorn	CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
609215157Snwhitehorn	    busy, curcpu);
610236097Sraj
611215157Snwhitehorn	if (cpu_idle_hook != NULL) {
612215157Snwhitehorn		if (!busy) {
613215157Snwhitehorn			critical_enter();
614247454Sdavide			sbt = cpu_idleclock();
615215157Snwhitehorn		}
616247454Sdavide		cpu_idle_hook(sbt);
617215157Snwhitehorn		if (!busy) {
618215157Snwhitehorn			cpu_activeclock();
619215157Snwhitehorn			critical_exit();
620215157Snwhitehorn		}
621215157Snwhitehorn	}
622236097Sraj
623215157Snwhitehorn	CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
624215157Snwhitehorn	    busy, curcpu);
625215157Snwhitehorn}
626215157Snwhitehorn
627215157Snwhitehornstatic void
628247454Sdavidecpu_idle_60x(sbintime_t sbt)
629215157Snwhitehorn{
630215157Snwhitehorn	register_t msr;
631215157Snwhitehorn	uint16_t vers;
632215157Snwhitehorn
633215157Snwhitehorn	if (!powerpc_pow_enabled)
634215157Snwhitehorn		return;
635215157Snwhitehorn
636215157Snwhitehorn	msr = mfmsr();
637215157Snwhitehorn	vers = mfpvr() >> 16;
638215157Snwhitehorn
639215157Snwhitehorn#ifdef AIM
640215157Snwhitehorn	switch (vers) {
641215157Snwhitehorn	case IBM970:
642215157Snwhitehorn	case IBM970FX:
643215157Snwhitehorn	case IBM970MP:
644215157Snwhitehorn	case MPC7447A:
645215157Snwhitehorn	case MPC7448:
646215157Snwhitehorn	case MPC7450:
647215157Snwhitehorn	case MPC7455:
648215157Snwhitehorn	case MPC7457:
649215157Snwhitehorn		__asm __volatile("\
650215157Snwhitehorn			    dssall; sync; mtmsr %0; isync"
651215157Snwhitehorn			    :: "r"(msr | PSL_POW));
652215157Snwhitehorn		break;
653215157Snwhitehorn	default:
654215157Snwhitehorn		powerpc_sync();
655215157Snwhitehorn		mtmsr(msr | PSL_POW);
656215157Snwhitehorn		isync();
657215157Snwhitehorn		break;
658215157Snwhitehorn	}
659215157Snwhitehorn#endif
660215157Snwhitehorn}
661215157Snwhitehorn
662215157Snwhitehornstatic void
663247454Sdavidecpu_idle_booke(sbintime_t sbt)
664215157Snwhitehorn{
665215157Snwhitehorn
666310441Sjhibbits#ifdef BOOKE_E500
667293030Sjhibbits	platform_cpu_idle(PCPU_GET(cpuid));
668215157Snwhitehorn#endif
669215157Snwhitehorn}
670215157Snwhitehorn
671