mp_cpudep.c revision 209114
1/*-
2 * Copyright (c) 2008 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/powerpc/aim/mp_cpudep.c 209114 2010-06-12 21:14:22Z nwhitehorn $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kernel.h>
33#include <sys/bus.h>
34#include <sys/pcpu.h>
35#include <sys/proc.h>
36#include <sys/smp.h>
37
38#include <machine/bus.h>
39#include <machine/cpu.h>
40#include <machine/hid.h>
41#include <machine/intr_machdep.h>
42#include <machine/pcb.h>
43#include <machine/psl.h>
44#include <machine/smp.h>
45#include <machine/spr.h>
46#include <machine/trap_aim.h>
47
48#include <dev/ofw/openfirm.h>
49#include <machine/ofw_machdep.h>
50
51void *ap_pcpu;
52
53static register_t bsp_state[8] __aligned(8);
54
55static void cpudep_save_config(void *dummy);
56SYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL);
57
58uintptr_t
59cpudep_ap_bootstrap(void)
60{
61	register_t msr, sp;
62
63	msr = PSL_KERNSET & ~PSL_EE;
64	mtmsr(msr);
65	isync();
66
67	__asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu));
68	powerpc_sync();
69
70	pcpup->pc_curthread = pcpup->pc_idlethread;
71	pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
72	sp = pcpup->pc_curpcb->pcb_sp;
73
74	return (sp);
75}
76
77static register_t
78mpc74xx_l2_enable(register_t l2cr_config)
79{
80	register_t ccr, bit;
81	uint16_t	vers;
82
83	vers = mfpvr() >> 16;
84	switch (vers) {
85	case MPC7400:
86	case MPC7410:
87		bit = L2CR_L2IP;
88		break;
89	default:
90		bit = L2CR_L2I;
91		break;
92	}
93
94	ccr = mfspr(SPR_L2CR);
95	if (ccr & L2CR_L2E)
96		return (ccr);
97
98	/* Configure L2 cache. */
99	ccr = l2cr_config & ~L2CR_L2E;
100	mtspr(SPR_L2CR, ccr | L2CR_L2I);
101	do {
102		ccr = mfspr(SPR_L2CR);
103	} while (ccr & bit);
104	powerpc_sync();
105	mtspr(SPR_L2CR, l2cr_config);
106	powerpc_sync();
107
108	return (l2cr_config);
109}
110
111static register_t
112mpc745x_l3_enable(register_t l3cr_config)
113{
114	register_t ccr;
115
116	ccr = mfspr(SPR_L3CR);
117	if (ccr & L3CR_L3E)
118		return (ccr);
119
120	/* Configure L3 cache. */
121	ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN);
122	mtspr(SPR_L3CR, ccr);
123	ccr |= 0x4000000;       /* Magic, but documented. */
124	mtspr(SPR_L3CR, ccr);
125	ccr |= L3CR_L3CLKEN;
126	mtspr(SPR_L3CR, ccr);
127	mtspr(SPR_L3CR, ccr | L3CR_L3I);
128	while (mfspr(SPR_L3CR) & L3CR_L3I)
129		;
130	mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN);
131	powerpc_sync();
132	DELAY(100);
133	mtspr(SPR_L3CR, ccr);
134	powerpc_sync();
135	DELAY(100);
136	ccr |= L3CR_L3E;
137	mtspr(SPR_L3CR, ccr);
138	powerpc_sync();
139
140	return(ccr);
141}
142
143static register_t
144mpc74xx_l1d_enable(void)
145{
146	register_t hid;
147
148	hid = mfspr(SPR_HID0);
149	if (hid & HID0_DCE)
150		return (hid);
151
152	/* Enable L1 D-cache */
153	hid |= HID0_DCE;
154	powerpc_sync();
155	mtspr(SPR_HID0, hid | HID0_DCFI);
156	powerpc_sync();
157
158	return (hid);
159}
160
161static register_t
162mpc74xx_l1i_enable(void)
163{
164	register_t hid;
165
166	hid = mfspr(SPR_HID0);
167	if (hid & HID0_ICE)
168		return (hid);
169
170	/* Enable L1 I-cache */
171	hid |= HID0_ICE;
172	isync();
173	mtspr(SPR_HID0, hid | HID0_ICFI);
174	isync();
175
176	return (hid);
177}
178
179static void
180cpudep_save_config(void *dummy)
181{
182	uint16_t	vers;
183
184	vers = mfpvr() >> 16;
185
186	switch(vers) {
187	case IBM970:
188	case IBM970FX:
189	case IBM970MP:
190		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
191		    : "=r" (bsp_state[0]),"=r" (bsp_state[1]) : "K" (SPR_HID0));
192		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
193		    : "=r" (bsp_state[2]),"=r" (bsp_state[3]) : "K" (SPR_HID1));
194		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
195		    : "=r" (bsp_state[4]),"=r" (bsp_state[5]) : "K" (SPR_HID4));
196		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
197		    : "=r" (bsp_state[6]),"=r" (bsp_state[7]) : "K" (SPR_HID5));
198
199		powerpc_sync();
200
201		break;
202	case MPC7450:
203	case MPC7455:
204	case MPC7457:
205		/* Only MPC745x CPUs have an L3 cache. */
206		bsp_state[3] = mfspr(SPR_L3CR);
207
208		/* Fallthrough */
209	case MPC7400:
210	case MPC7410:
211	case MPC7447A:
212	case MPC7448:
213		bsp_state[2] = mfspr(SPR_L2CR);
214		bsp_state[1] = mfspr(SPR_HID1);
215		bsp_state[0] = mfspr(SPR_HID0);
216		break;
217	}
218}
219
220void
221cpudep_ap_setup()
222{
223	register_t	reg;
224	uint16_t	vers;
225
226	vers = mfpvr() >> 16;
227
228	switch(vers) {
229	case IBM970:
230	case IBM970FX:
231	case IBM970MP:
232		/* Set HIOR to 0 */
233		__asm __volatile("mtspr 311,%0" :: "r"(0));
234		powerpc_sync();
235
236		/*
237		 * The 970 has strange rules about how to update HID registers.
238		 * See Table 2-3, 970MP manual
239		 */
240
241		__asm __volatile("mtasr %0; sync" :: "r"(0));
242		__asm __volatile(" \
243			ld	%0,0(%2);				\
244			sync; isync;					\
245			mtspr	%1, %0;					\
246			mfspr	%0, %1;	mfspr	%0, %1;	mfspr	%0, %1;	\
247			mfspr	%0, %1;	mfspr	%0, %1;	mfspr	%0, %1; \
248			sync; isync"
249		    : "=r"(reg) : "K"(SPR_HID0), "r"(bsp_state));
250		__asm __volatile("ld %0, 8(%2); sync; isync;	\
251		    mtspr %1, %0; mtspr %1, %0; sync; isync"
252		    : "=r"(reg) : "K"(SPR_HID1), "r"(bsp_state));
253		__asm __volatile("ld %0, 16(%2); sync; isync;	\
254		    mtspr %1, %0; sync; isync;"
255		    : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state));
256		__asm __volatile("ld %0, 24(%2); sync; isync;	\
257		    mtspr %1, %0; sync; isync;"
258		    : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state));
259
260		powerpc_sync();
261		break;
262	case MPC7450:
263	case MPC7455:
264	case MPC7457:
265		/* Only MPC745x CPUs have an L3 cache. */
266		reg = mpc745x_l3_enable(bsp_state[3]);
267
268		/* Fallthrough */
269	case MPC7400:
270	case MPC7410:
271	case MPC7447A:
272	case MPC7448:
273		/* XXX: Program the CPU ID into PIR */
274		__asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid)));
275
276		powerpc_sync();
277		isync();
278
279		mtspr(SPR_HID0, bsp_state[0]); isync();
280		mtspr(SPR_HID1, bsp_state[1]); isync();
281
282		reg = mpc74xx_l2_enable(bsp_state[2]);
283		reg = mpc74xx_l1d_enable();
284		reg = mpc74xx_l1i_enable();
285
286		break;
287	default:
288		printf("WARNING: Unknown CPU type. Cache performace may be "
289		    "suboptimal.\n");
290		break;
291	}
292}
293
294