mp_cpudep.c revision 215197
1218887Sdim/*-
2218887Sdim * Copyright (c) 2008 Marcel Moolenaar
3218887Sdim * All rights reserved.
4218887Sdim *
5218887Sdim * Redistribution and use in source and binary forms, with or without
6218887Sdim * modification, are permitted provided that the following conditions
7218887Sdim * are met:
8218887Sdim *
9218887Sdim * 1. Redistributions of source code must retain the above copyright
10218887Sdim *    notice, this list of conditions and the following disclaimer.
11218887Sdim * 2. Redistributions in binary form must reproduce the above copyright
12218887Sdim *    notice, this list of conditions and the following disclaimer in the
13218887Sdim *    documentation and/or other materials provided with the distribution.
14218887Sdim *
15218887Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16218887Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17218887Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18218887Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19218887Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20218887Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21218887Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22218887Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23218887Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24218887Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25218887Sdim */
26218887Sdim
27218887Sdim#include <sys/cdefs.h>
28218887Sdim__FBSDID("$FreeBSD: head/sys/powerpc/aim/mp_cpudep.c 215197 2010-11-12 20:26:34Z nwhitehorn $");
29218887Sdim
30218887Sdim#include <sys/param.h>
31218887Sdim#include <sys/systm.h>
32218887Sdim#include <sys/kernel.h>
33218887Sdim#include <sys/bus.h>
34218887Sdim#include <sys/pcpu.h>
35218887Sdim#include <sys/proc.h>
36218887Sdim#include <sys/smp.h>
37218887Sdim
38218887Sdim#include <machine/bus.h>
39218887Sdim#include <machine/cpu.h>
40218887Sdim#include <machine/hid.h>
41218887Sdim#include <machine/intr_machdep.h>
42218887Sdim#include <machine/pcb.h>
43218887Sdim#include <machine/psl.h>
44218887Sdim#include <machine/smp.h>
45218887Sdim#include <machine/spr.h>
46218887Sdim#include <machine/trap_aim.h>
47218887Sdim
48218887Sdim#include <dev/ofw/openfirm.h>
49218887Sdim#include <machine/ofw_machdep.h>
50218887Sdim
51218887Sdimvoid *ap_pcpu;
52218887Sdim
53218887Sdimstatic register_t bsp_state[8] __aligned(8);
54218887Sdim
55218887Sdimstatic void cpudep_save_config(void *dummy);
56218887SdimSYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL);
57218887Sdim
58218887Sdimvoid
59218887Sdimcpudep_ap_early_bootstrap(void)
60218887Sdim{
61218887Sdim	register_t reg;
62218887Sdim
63218887Sdim	__asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu));
64218887Sdim	powerpc_sync();
65218887Sdim
66218887Sdim	switch (mfpvr() >> 16) {
67218887Sdim	case IBM970:
68218887Sdim	case IBM970FX:
69218887Sdim	case IBM970MP:
70218887Sdim		/* Restore HID4 and HID5, which are necessary for the MMU */
71218887Sdim
72218887Sdim		__asm __volatile("ld %0, 16(%2); sync; isync;	\
73218887Sdim		    mtspr %1, %0; sync; isync;"
74218887Sdim		    : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state));
75218887Sdim		__asm __volatile("ld %0, 24(%2); sync; isync;	\
76218887Sdim		    mtspr %1, %0; sync; isync;"
77218887Sdim		    : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state));
78218887Sdim		powerpc_sync();
79218887Sdim		break;
80218887Sdim	}
81218887Sdim}
82218887Sdim
83218887Sdimuintptr_t
84218887Sdimcpudep_ap_bootstrap(void)
85218887Sdim{
86218887Sdim	register_t msr, sp;
87218887Sdim
88218887Sdim	msr = PSL_KERNSET & ~PSL_EE;
89218887Sdim	mtmsr(msr);
90218887Sdim	isync();
91218887Sdim
92218887Sdim	pcpup->pc_curthread = pcpup->pc_idlethread;
93218887Sdim	pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
94218887Sdim	sp = pcpup->pc_curpcb->pcb_sp;
95218887Sdim
96218887Sdim	return (sp);
97218887Sdim}
98218887Sdim
99218887Sdimstatic register_t
100218887Sdimmpc74xx_l2_enable(register_t l2cr_config)
101218887Sdim{
102218887Sdim	register_t ccr, bit;
103218887Sdim	uint16_t	vers;
104218887Sdim
105218887Sdim	vers = mfpvr() >> 16;
106218887Sdim	switch (vers) {
107218887Sdim	case MPC7400:
108218887Sdim	case MPC7410:
109218887Sdim		bit = L2CR_L2IP;
110218887Sdim		break;
111218887Sdim	default:
112218887Sdim		bit = L2CR_L2I;
113218887Sdim		break;
114218887Sdim	}
115218887Sdim
116218887Sdim	ccr = mfspr(SPR_L2CR);
117218887Sdim	if (ccr & L2CR_L2E)
118218887Sdim		return (ccr);
119218887Sdim
120218887Sdim	/* Configure L2 cache. */
121218887Sdim	ccr = l2cr_config & ~L2CR_L2E;
122218887Sdim	mtspr(SPR_L2CR, ccr | L2CR_L2I);
123218887Sdim	do {
124218887Sdim		ccr = mfspr(SPR_L2CR);
125218887Sdim	} while (ccr & bit);
126218887Sdim	powerpc_sync();
127218887Sdim	mtspr(SPR_L2CR, l2cr_config);
128218887Sdim	powerpc_sync();
129218887Sdim
130218887Sdim	return (l2cr_config);
131218887Sdim}
132218887Sdim
133218887Sdimstatic register_t
134218887Sdimmpc745x_l3_enable(register_t l3cr_config)
135218887Sdim{
136218887Sdim	register_t ccr;
137218887Sdim
138218887Sdim	ccr = mfspr(SPR_L3CR);
139218887Sdim	if (ccr & L3CR_L3E)
140218887Sdim		return (ccr);
141218887Sdim
142218887Sdim	/* Configure L3 cache. */
143218887Sdim	ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN);
144218887Sdim	mtspr(SPR_L3CR, ccr);
145218887Sdim	ccr |= 0x4000000;       /* Magic, but documented. */
146218887Sdim	mtspr(SPR_L3CR, ccr);
147218887Sdim	ccr |= L3CR_L3CLKEN;
148218887Sdim	mtspr(SPR_L3CR, ccr);
149218887Sdim	mtspr(SPR_L3CR, ccr | L3CR_L3I);
150218887Sdim	while (mfspr(SPR_L3CR) & L3CR_L3I)
151218887Sdim		;
152218887Sdim	mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN);
153218887Sdim	powerpc_sync();
154218887Sdim	DELAY(100);
155218887Sdim	mtspr(SPR_L3CR, ccr);
156218887Sdim	powerpc_sync();
157218887Sdim	DELAY(100);
158218887Sdim	ccr |= L3CR_L3E;
159218887Sdim	mtspr(SPR_L3CR, ccr);
160218887Sdim	powerpc_sync();
161218887Sdim
162218887Sdim	return(ccr);
163218887Sdim}
164218887Sdim
165218887Sdimstatic register_t
166218887Sdimmpc74xx_l1d_enable(void)
167218887Sdim{
168218887Sdim	register_t hid;
169218887Sdim
170221345Sdim	hid = mfspr(SPR_HID0);
171218887Sdim	if (hid & HID0_DCE)
172218887Sdim		return (hid);
173218887Sdim
174218887Sdim	/* Enable L1 D-cache */
175218887Sdim	hid |= HID0_DCE;
176218887Sdim	powerpc_sync();
177218887Sdim	mtspr(SPR_HID0, hid | HID0_DCFI);
178218887Sdim	powerpc_sync();
179218887Sdim
180218887Sdim	return (hid);
181218887Sdim}
182218887Sdim
183218887Sdimstatic register_t
184218887Sdimmpc74xx_l1i_enable(void)
185218887Sdim{
186218887Sdim	register_t hid;
187218887Sdim
188218887Sdim	hid = mfspr(SPR_HID0);
189218887Sdim	if (hid & HID0_ICE)
190218887Sdim		return (hid);
191218887Sdim
192218887Sdim	/* Enable L1 I-cache */
193218887Sdim	hid |= HID0_ICE;
194218887Sdim	isync();
195218887Sdim	mtspr(SPR_HID0, hid | HID0_ICFI);
196218887Sdim	isync();
197218887Sdim
198218887Sdim	return (hid);
199218887Sdim}
200218887Sdim
201218887Sdimstatic void
202218887Sdimcpudep_save_config(void *dummy)
203218887Sdim{
204218887Sdim	uint16_t	vers;
205218887Sdim
206218887Sdim	vers = mfpvr() >> 16;
207218887Sdim
208218887Sdim	switch(vers) {
209218887Sdim	case IBM970:
210218887Sdim	case IBM970FX:
211218887Sdim	case IBM970MP:
212218887Sdim		#ifdef __powerpc64__
213218887Sdim		bsp_state[0] = mfspr(SPR_HID0);
214218887Sdim		bsp_state[1] = mfspr(SPR_HID1);
215218887Sdim		bsp_state[2] = mfspr(SPR_HID4);
216218887Sdim		bsp_state[3] = mfspr(SPR_HID5);
217218887Sdim		#else
218218887Sdim		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
219218887Sdim		    : "=r" (bsp_state[0]),"=r" (bsp_state[1]) : "K" (SPR_HID0));
220218887Sdim		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
221218887Sdim		    : "=r" (bsp_state[2]),"=r" (bsp_state[3]) : "K" (SPR_HID1));
222218887Sdim		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
223218887Sdim		    : "=r" (bsp_state[4]),"=r" (bsp_state[5]) : "K" (SPR_HID4));
224218887Sdim		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
225218887Sdim		    : "=r" (bsp_state[6]),"=r" (bsp_state[7]) : "K" (SPR_HID5));
226218887Sdim		#endif
227218887Sdim
228218887Sdim		powerpc_sync();
229218887Sdim
230218887Sdim		break;
231218887Sdim	case IBMCELLBE:
232218887Sdim		#ifdef NOTYET /* Causes problems if in instruction stream on 970 */
233218887Sdim		if (mfmsr() & PSL_HV) {
234218887Sdim			bsp_state[0] = mfspr(SPR_HID0);
235218887Sdim			bsp_state[1] = mfspr(SPR_HID1);
236218887Sdim			bsp_state[2] = mfspr(SPR_HID4);
237218887Sdim			bsp_state[3] = mfspr(SPR_HID6);
238218887Sdim
239218887Sdim			bsp_state[4] = mfspr(SPR_CELL_TSCR);
240218887Sdim		}
241218887Sdim		#endif
242218887Sdim
243218887Sdim		bsp_state[5] = mfspr(SPR_CELL_TSRL);
244218887Sdim
245218887Sdim		break;
246218887Sdim	case MPC7450:
247218887Sdim	case MPC7455:
248218887Sdim	case MPC7457:
249218887Sdim		/* Only MPC745x CPUs have an L3 cache. */
250218887Sdim		bsp_state[3] = mfspr(SPR_L3CR);
251218887Sdim
252218887Sdim		/* Fallthrough */
253218887Sdim	case MPC7400:
254218887Sdim	case MPC7410:
255218887Sdim	case MPC7447A:
256218887Sdim	case MPC7448:
257218887Sdim		bsp_state[2] = mfspr(SPR_L2CR);
258218887Sdim		bsp_state[1] = mfspr(SPR_HID1);
259218887Sdim		bsp_state[0] = mfspr(SPR_HID0);
260218887Sdim		break;
261218887Sdim	}
262218887Sdim}
263218887Sdim
264218887Sdimvoid
265218887Sdimcpudep_ap_setup()
266218887Sdim{
267218887Sdim	register_t	reg;
268218887Sdim	uint16_t	vers;
269218887Sdim
270218887Sdim	vers = mfpvr() >> 16;
271218887Sdim
272218887Sdim	switch(vers) {
273218887Sdim	case IBM970:
274218887Sdim	case IBM970FX:
275218887Sdim	case IBM970MP:
276218887Sdim		/* Set HIOR to 0 */
277218887Sdim		__asm __volatile("mtspr 311,%0" :: "r"(0));
278218887Sdim		powerpc_sync();
279218887Sdim
280218887Sdim		/*
281218887Sdim		 * The 970 has strange rules about how to update HID registers.
282218887Sdim		 * See Table 2-3, 970MP manual
283218887Sdim		 */
284218887Sdim
285218887Sdim		__asm __volatile("mtasr %0; sync" :: "r"(0));
286218887Sdim		__asm __volatile(" \
287218887Sdim			ld	%0,0(%2);				\
288218887Sdim			sync; isync;					\
289218887Sdim			mtspr	%1, %0;					\
290218887Sdim			mfspr	%0, %1;	mfspr	%0, %1;	mfspr	%0, %1;	\
291218887Sdim			mfspr	%0, %1;	mfspr	%0, %1;	mfspr	%0, %1; \
292218887Sdim			sync; isync"
293218887Sdim		    : "=r"(reg) : "K"(SPR_HID0), "r"(bsp_state));
294218887Sdim		__asm __volatile("ld %0, 8(%2); sync; isync;	\
295218887Sdim		    mtspr %1, %0; mtspr %1, %0; sync; isync"
296218887Sdim		    : "=r"(reg) : "K"(SPR_HID1), "r"(bsp_state));
297218887Sdim		__asm __volatile("ld %0, 16(%2); sync; isync;	\
298218887Sdim		    mtspr %1, %0; sync; isync;"
299218887Sdim		    : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state));
300218887Sdim		__asm __volatile("ld %0, 24(%2); sync; isync;	\
301218887Sdim		    mtspr %1, %0; sync; isync;"
302218887Sdim		    : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state));
303218887Sdim
304218887Sdim		powerpc_sync();
305218887Sdim		break;
306218887Sdim	case IBMCELLBE:
307218887Sdim		#ifdef NOTYET /* Causes problems if in instruction stream on 970 */
308218887Sdim		if (mfmsr() & PSL_HV) {
309218887Sdim			mtspr(SPR_HID0, bsp_state[0]);
310218887Sdim			mtspr(SPR_HID1, bsp_state[1]);
311218887Sdim			mtspr(SPR_HID4, bsp_state[2]);
312218887Sdim			mtspr(SPR_HID6, bsp_state[3]);
313218887Sdim
314218887Sdim			mtspr(SPR_CELL_TSCR, bsp_state[4]);
315218887Sdim		}
316218887Sdim		#endif
317218887Sdim
318218887Sdim		mtspr(SPR_CELL_TSRL, bsp_state[5]);
319218887Sdim
320218887Sdim		break;
321218887Sdim	case MPC7450:
322218887Sdim	case MPC7455:
323218887Sdim	case MPC7457:
324218887Sdim		/* Only MPC745x CPUs have an L3 cache. */
325218887Sdim		reg = mpc745x_l3_enable(bsp_state[3]);
326218887Sdim
327218887Sdim		/* Fallthrough */
328218887Sdim	case MPC7400:
329218887Sdim	case MPC7410:
330218887Sdim	case MPC7447A:
331218887Sdim	case MPC7448:
332218887Sdim		/* XXX: Program the CPU ID into PIR */
333218887Sdim		__asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid)));
334218887Sdim
335218887Sdim		powerpc_sync();
336218887Sdim		isync();
337218887Sdim
338218887Sdim		mtspr(SPR_HID0, bsp_state[0]); isync();
339218887Sdim		mtspr(SPR_HID1, bsp_state[1]); isync();
340218887Sdim
341218887Sdim		reg = mpc74xx_l2_enable(bsp_state[2]);
342218887Sdim		reg = mpc74xx_l1d_enable();
343218887Sdim		reg = mpc74xx_l1i_enable();
344218887Sdim
345218887Sdim		break;
346218887Sdim	default:
347218887Sdim		printf("WARNING: Unknown CPU type. Cache performace may be "
348218887Sdim		    "suboptimal.\n");
349218887Sdim		break;
350218887Sdim	}
351218887Sdim}
352218887Sdim
353218887Sdim