1178628Smarcel/*-
2178628Smarcel * Copyright (c) 2008 Marcel Moolenaar
3178628Smarcel * All rights reserved.
4178628Smarcel *
5178628Smarcel * Redistribution and use in source and binary forms, with or without
6178628Smarcel * modification, are permitted provided that the following conditions
7178628Smarcel * are met:
8178628Smarcel *
9178628Smarcel * 1. Redistributions of source code must retain the above copyright
10178628Smarcel *    notice, this list of conditions and the following disclaimer.
11178628Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12178628Smarcel *    notice, this list of conditions and the following disclaimer in the
13178628Smarcel *    documentation and/or other materials provided with the distribution.
14178628Smarcel *
15178628Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16178628Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17178628Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18178628Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19178628Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20178628Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21178628Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22178628Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23178628Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24178628Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25178628Smarcel */
26178628Smarcel
27178628Smarcel#include <sys/cdefs.h>
28178628Smarcel__FBSDID("$FreeBSD$");
29178628Smarcel
30178628Smarcel#include <sys/param.h>
31178628Smarcel#include <sys/systm.h>
32178628Smarcel#include <sys/kernel.h>
33178628Smarcel#include <sys/bus.h>
34178628Smarcel#include <sys/pcpu.h>
35178628Smarcel#include <sys/proc.h>
36178628Smarcel#include <sys/smp.h>
37178628Smarcel
38178628Smarcel#include <machine/bus.h>
39178628Smarcel#include <machine/cpu.h>
40178628Smarcel#include <machine/hid.h>
41178628Smarcel#include <machine/intr_machdep.h>
42178628Smarcel#include <machine/pcb.h>
43178628Smarcel#include <machine/psl.h>
44178628Smarcel#include <machine/smp.h>
45178628Smarcel#include <machine/spr.h>
46265974Sian#include <machine/trap.h>
47178628Smarcel
48178628Smarcel#include <dev/ofw/openfirm.h>
49178628Smarcel#include <machine/ofw_machdep.h>
50178628Smarcel
51178628Smarcelvoid *ap_pcpu;
52178628Smarcel
53198427Snwhitehornstatic register_t bsp_state[8] __aligned(8);
54198378Snwhitehorn
55198378Snwhitehornstatic void cpudep_save_config(void *dummy);
56198378SnwhitehornSYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL);
57198378Snwhitehorn
58209975Snwhitehornvoid
59209975Snwhitehorncpudep_ap_early_bootstrap(void)
60209975Snwhitehorn{
61209975Snwhitehorn	register_t reg;
62209975Snwhitehorn
63209975Snwhitehorn	__asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu));
64209975Snwhitehorn	powerpc_sync();
65209975Snwhitehorn
66209975Snwhitehorn	switch (mfpvr() >> 16) {
67209975Snwhitehorn	case IBM970:
68209975Snwhitehorn	case IBM970FX:
69209975Snwhitehorn	case IBM970MP:
70209975Snwhitehorn		/* Restore HID4 and HID5, which are necessary for the MMU */
71209975Snwhitehorn
72209975Snwhitehorn		__asm __volatile("ld %0, 16(%2); sync; isync;	\
73209975Snwhitehorn		    mtspr %1, %0; sync; isync;"
74209975Snwhitehorn		    : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state));
75209975Snwhitehorn		__asm __volatile("ld %0, 24(%2); sync; isync;	\
76209975Snwhitehorn		    mtspr %1, %0; sync; isync;"
77209975Snwhitehorn		    : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state));
78209975Snwhitehorn		powerpc_sync();
79209975Snwhitehorn		break;
80209975Snwhitehorn	}
81209975Snwhitehorn}
82209975Snwhitehorn
83198378Snwhitehornuintptr_t
84198378Snwhitehorncpudep_ap_bootstrap(void)
85198378Snwhitehorn{
86198378Snwhitehorn	register_t msr, sp;
87198378Snwhitehorn
88198378Snwhitehorn	msr = PSL_KERNSET & ~PSL_EE;
89198378Snwhitehorn	mtmsr(msr);
90198378Snwhitehorn
91227628Snwhitehorn	pcpup->pc_curthread = pcpup->pc_idlethread;
92227628Snwhitehorn#ifdef __powerpc64__
93227628Snwhitehorn	__asm __volatile("mr 13,%0" :: "r"(pcpup->pc_curthread));
94227628Snwhitehorn#else
95227628Snwhitehorn	__asm __volatile("mr 2,%0" :: "r"(pcpup->pc_curthread));
96227628Snwhitehorn#endif
97198378Snwhitehorn	pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
98198378Snwhitehorn	sp = pcpup->pc_curpcb->pcb_sp;
99198378Snwhitehorn
100198378Snwhitehorn	return (sp);
101198378Snwhitehorn}
102198378Snwhitehorn
103183090Smarcelstatic register_t
104209114Snwhitehornmpc74xx_l2_enable(register_t l2cr_config)
105183090Smarcel{
106209114Snwhitehorn	register_t ccr, bit;
107209114Snwhitehorn	uint16_t	vers;
108183090Smarcel
109209114Snwhitehorn	vers = mfpvr() >> 16;
110209114Snwhitehorn	switch (vers) {
111209114Snwhitehorn	case MPC7400:
112209114Snwhitehorn	case MPC7410:
113209114Snwhitehorn		bit = L2CR_L2IP;
114209114Snwhitehorn		break;
115209114Snwhitehorn	default:
116209114Snwhitehorn		bit = L2CR_L2I;
117209114Snwhitehorn		break;
118209114Snwhitehorn	}
119209114Snwhitehorn
120183090Smarcel	ccr = mfspr(SPR_L2CR);
121183090Smarcel	if (ccr & L2CR_L2E)
122183090Smarcel		return (ccr);
123183090Smarcel
124183090Smarcel	/* Configure L2 cache. */
125183090Smarcel	ccr = l2cr_config & ~L2CR_L2E;
126183090Smarcel	mtspr(SPR_L2CR, ccr | L2CR_L2I);
127183090Smarcel	do {
128183090Smarcel		ccr = mfspr(SPR_L2CR);
129209114Snwhitehorn	} while (ccr & bit);
130183090Smarcel	powerpc_sync();
131183090Smarcel	mtspr(SPR_L2CR, l2cr_config);
132183090Smarcel	powerpc_sync();
133183090Smarcel
134183090Smarcel	return (l2cr_config);
135183090Smarcel}
136183090Smarcel
137183090Smarcelstatic register_t
138198378Snwhitehornmpc745x_l3_enable(register_t l3cr_config)
139183090Smarcel{
140183090Smarcel	register_t ccr;
141183090Smarcel
142183090Smarcel	ccr = mfspr(SPR_L3CR);
143183090Smarcel	if (ccr & L3CR_L3E)
144183090Smarcel		return (ccr);
145183090Smarcel
146183090Smarcel	/* Configure L3 cache. */
147183090Smarcel	ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN);
148183090Smarcel	mtspr(SPR_L3CR, ccr);
149183090Smarcel	ccr |= 0x4000000;       /* Magic, but documented. */
150183090Smarcel	mtspr(SPR_L3CR, ccr);
151183090Smarcel	ccr |= L3CR_L3CLKEN;
152183090Smarcel	mtspr(SPR_L3CR, ccr);
153183090Smarcel	mtspr(SPR_L3CR, ccr | L3CR_L3I);
154183090Smarcel	while (mfspr(SPR_L3CR) & L3CR_L3I)
155183090Smarcel		;
156183090Smarcel	mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN);
157183090Smarcel	powerpc_sync();
158183090Smarcel	DELAY(100);
159183090Smarcel	mtspr(SPR_L3CR, ccr);
160183090Smarcel	powerpc_sync();
161183090Smarcel	DELAY(100);
162183090Smarcel	ccr |= L3CR_L3E;
163183090Smarcel	mtspr(SPR_L3CR, ccr);
164183090Smarcel	powerpc_sync();
165183090Smarcel
166183090Smarcel	return(ccr);
167183090Smarcel}
168183090Smarcel
169183090Smarcelstatic register_t
170209114Snwhitehornmpc74xx_l1d_enable(void)
171183090Smarcel{
172183090Smarcel	register_t hid;
173183090Smarcel
174183090Smarcel	hid = mfspr(SPR_HID0);
175183090Smarcel	if (hid & HID0_DCE)
176183090Smarcel		return (hid);
177183090Smarcel
178183090Smarcel	/* Enable L1 D-cache */
179183090Smarcel	hid |= HID0_DCE;
180183090Smarcel	powerpc_sync();
181183090Smarcel	mtspr(SPR_HID0, hid | HID0_DCFI);
182183090Smarcel	powerpc_sync();
183183090Smarcel
184183090Smarcel	return (hid);
185183090Smarcel}
186183090Smarcel
187183090Smarcelstatic register_t
188209114Snwhitehornmpc74xx_l1i_enable(void)
189183090Smarcel{
190183090Smarcel	register_t hid;
191183090Smarcel
192183090Smarcel	hid = mfspr(SPR_HID0);
193183090Smarcel	if (hid & HID0_ICE)
194183090Smarcel		return (hid);
195183090Smarcel
196183090Smarcel	/* Enable L1 I-cache */
197183090Smarcel	hid |= HID0_ICE;
198183090Smarcel	isync();
199183090Smarcel	mtspr(SPR_HID0, hid | HID0_ICFI);
200183090Smarcel	isync();
201183090Smarcel
202183090Smarcel	return (hid);
203183090Smarcel}
204183090Smarcel
205198378Snwhitehornstatic void
206198378Snwhitehorncpudep_save_config(void *dummy)
207178628Smarcel{
208198378Snwhitehorn	uint16_t	vers;
209178628Smarcel
210198378Snwhitehorn	vers = mfpvr() >> 16;
211183090Smarcel
212198378Snwhitehorn	switch(vers) {
213198378Snwhitehorn	case IBM970:
214198378Snwhitehorn	case IBM970FX:
215198378Snwhitehorn	case IBM970MP:
216209975Snwhitehorn		#ifdef __powerpc64__
217209975Snwhitehorn		bsp_state[0] = mfspr(SPR_HID0);
218209975Snwhitehorn		bsp_state[1] = mfspr(SPR_HID1);
219209975Snwhitehorn		bsp_state[2] = mfspr(SPR_HID4);
220209975Snwhitehorn		bsp_state[3] = mfspr(SPR_HID5);
221209975Snwhitehorn		#else
222198378Snwhitehorn		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
223198378Snwhitehorn		    : "=r" (bsp_state[0]),"=r" (bsp_state[1]) : "K" (SPR_HID0));
224198378Snwhitehorn		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
225198378Snwhitehorn		    : "=r" (bsp_state[2]),"=r" (bsp_state[3]) : "K" (SPR_HID1));
226198378Snwhitehorn		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
227198378Snwhitehorn		    : "=r" (bsp_state[4]),"=r" (bsp_state[5]) : "K" (SPR_HID4));
228198378Snwhitehorn		__asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32"
229198378Snwhitehorn		    : "=r" (bsp_state[6]),"=r" (bsp_state[7]) : "K" (SPR_HID5));
230209975Snwhitehorn		#endif
231178628Smarcel
232198427Snwhitehorn		powerpc_sync();
233198427Snwhitehorn
234198378Snwhitehorn		break;
235215182Snwhitehorn	case IBMCELLBE:
236215197Snwhitehorn		#ifdef NOTYET /* Causes problems if in instruction stream on 970 */
237215182Snwhitehorn		if (mfmsr() & PSL_HV) {
238215182Snwhitehorn			bsp_state[0] = mfspr(SPR_HID0);
239215182Snwhitehorn			bsp_state[1] = mfspr(SPR_HID1);
240215182Snwhitehorn			bsp_state[2] = mfspr(SPR_HID4);
241215182Snwhitehorn			bsp_state[3] = mfspr(SPR_HID6);
242215182Snwhitehorn
243215182Snwhitehorn			bsp_state[4] = mfspr(SPR_CELL_TSCR);
244215182Snwhitehorn		}
245215197Snwhitehorn		#endif
246215182Snwhitehorn
247215182Snwhitehorn		bsp_state[5] = mfspr(SPR_CELL_TSRL);
248215182Snwhitehorn
249215182Snwhitehorn		break;
250198378Snwhitehorn	case MPC7450:
251198378Snwhitehorn	case MPC7455:
252198378Snwhitehorn	case MPC7457:
253198378Snwhitehorn		/* Only MPC745x CPUs have an L3 cache. */
254198378Snwhitehorn		bsp_state[3] = mfspr(SPR_L3CR);
255178628Smarcel
256198378Snwhitehorn		/* Fallthrough */
257198378Snwhitehorn	case MPC7400:
258198378Snwhitehorn	case MPC7410:
259198378Snwhitehorn	case MPC7447A:
260198378Snwhitehorn	case MPC7448:
261198378Snwhitehorn		bsp_state[2] = mfspr(SPR_L2CR);
262198378Snwhitehorn		bsp_state[1] = mfspr(SPR_HID1);
263198378Snwhitehorn		bsp_state[0] = mfspr(SPR_HID0);
264198378Snwhitehorn		break;
265198378Snwhitehorn	}
266198378Snwhitehorn}
267178628Smarcel
268198378Snwhitehornvoid
269198378Snwhitehorncpudep_ap_setup()
270198378Snwhitehorn{
271198378Snwhitehorn	register_t	reg;
272198378Snwhitehorn	uint16_t	vers;
273183090Smarcel
274198378Snwhitehorn	vers = mfpvr() >> 16;
275178628Smarcel
276262675Sjhibbits	/* The following is needed for restoring from sleep. */
277262675Sjhibbits#ifdef __powerpc64__
278262675Sjhibbits	/* Writing to the time base register is hypervisor-privileged */
279262675Sjhibbits	if (mfmsr() & PSL_HV)
280262675Sjhibbits		mttb(0);
281262675Sjhibbits#else
282262675Sjhibbits	mttb(0);
283262675Sjhibbits#endif
284198378Snwhitehorn	switch(vers) {
285198378Snwhitehorn	case IBM970:
286198378Snwhitehorn	case IBM970FX:
287198378Snwhitehorn	case IBM970MP:
288198378Snwhitehorn		/* Set HIOR to 0 */
289198378Snwhitehorn		__asm __volatile("mtspr 311,%0" :: "r"(0));
290198378Snwhitehorn		powerpc_sync();
291178628Smarcel
292198378Snwhitehorn		/*
293198378Snwhitehorn		 * The 970 has strange rules about how to update HID registers.
294198378Snwhitehorn		 * See Table 2-3, 970MP manual
295198378Snwhitehorn		 */
296198378Snwhitehorn
297198427Snwhitehorn		__asm __volatile("mtasr %0; sync" :: "r"(0));
298198378Snwhitehorn		__asm __volatile(" \
299198378Snwhitehorn			ld	%0,0(%2);				\
300198427Snwhitehorn			sync; isync;					\
301198378Snwhitehorn			mtspr	%1, %0;					\
302198378Snwhitehorn			mfspr	%0, %1;	mfspr	%0, %1;	mfspr	%0, %1;	\
303198427Snwhitehorn			mfspr	%0, %1;	mfspr	%0, %1;	mfspr	%0, %1; \
304198427Snwhitehorn			sync; isync"
305198378Snwhitehorn		    : "=r"(reg) : "K"(SPR_HID0), "r"(bsp_state));
306198427Snwhitehorn		__asm __volatile("ld %0, 8(%2); sync; isync;	\
307198427Snwhitehorn		    mtspr %1, %0; mtspr %1, %0; sync; isync"
308198427Snwhitehorn		    : "=r"(reg) : "K"(SPR_HID1), "r"(bsp_state));
309198427Snwhitehorn		__asm __volatile("ld %0, 16(%2); sync; isync;	\
310198427Snwhitehorn		    mtspr %1, %0; sync; isync;"
311198378Snwhitehorn		    : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state));
312198427Snwhitehorn		__asm __volatile("ld %0, 24(%2); sync; isync;	\
313198427Snwhitehorn		    mtspr %1, %0; sync; isync;"
314198378Snwhitehorn		    : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state));
315198378Snwhitehorn
316198378Snwhitehorn		powerpc_sync();
317198378Snwhitehorn		break;
318215182Snwhitehorn	case IBMCELLBE:
319215197Snwhitehorn		#ifdef NOTYET /* Causes problems if in instruction stream on 970 */
320215182Snwhitehorn		if (mfmsr() & PSL_HV) {
321215182Snwhitehorn			mtspr(SPR_HID0, bsp_state[0]);
322215182Snwhitehorn			mtspr(SPR_HID1, bsp_state[1]);
323215182Snwhitehorn			mtspr(SPR_HID4, bsp_state[2]);
324215182Snwhitehorn			mtspr(SPR_HID6, bsp_state[3]);
325215182Snwhitehorn
326215182Snwhitehorn			mtspr(SPR_CELL_TSCR, bsp_state[4]);
327215182Snwhitehorn		}
328215197Snwhitehorn		#endif
329215182Snwhitehorn
330215182Snwhitehorn		mtspr(SPR_CELL_TSRL, bsp_state[5]);
331215182Snwhitehorn
332215182Snwhitehorn		break;
333198378Snwhitehorn	case MPC7400:
334198378Snwhitehorn	case MPC7410:
335198378Snwhitehorn	case MPC7447A:
336198378Snwhitehorn	case MPC7448:
337260674Sjhibbits	case MPC7450:
338260674Sjhibbits	case MPC7455:
339260674Sjhibbits	case MPC7457:
340198378Snwhitehorn		/* XXX: Program the CPU ID into PIR */
341198378Snwhitehorn		__asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid)));
342198378Snwhitehorn
343198378Snwhitehorn		powerpc_sync();
344198378Snwhitehorn		isync();
345198378Snwhitehorn
346198378Snwhitehorn		mtspr(SPR_HID0, bsp_state[0]); isync();
347198378Snwhitehorn		mtspr(SPR_HID1, bsp_state[1]); isync();
348198378Snwhitehorn
349260674Sjhibbits		/* Now enable the L3 cache. */
350260674Sjhibbits		switch (vers) {
351260674Sjhibbits		case MPC7450:
352260674Sjhibbits		case MPC7455:
353260674Sjhibbits		case MPC7457:
354260674Sjhibbits			/* Only MPC745x CPUs have an L3 cache. */
355260674Sjhibbits			reg = mpc745x_l3_enable(bsp_state[3]);
356260674Sjhibbits		default:
357260674Sjhibbits			break;
358260674Sjhibbits		}
359260674Sjhibbits
360209114Snwhitehorn		reg = mpc74xx_l2_enable(bsp_state[2]);
361209114Snwhitehorn		reg = mpc74xx_l1d_enable();
362209114Snwhitehorn		reg = mpc74xx_l1i_enable();
363198378Snwhitehorn
364198378Snwhitehorn		break;
365198378Snwhitehorn	default:
366222618Snwhitehorn#ifdef __powerpc64__
367222618Snwhitehorn		if (!(mfmsr() & PSL_HV)) /* Rely on HV to have set things up */
368222618Snwhitehorn			break;
369222618Snwhitehorn#endif
370198378Snwhitehorn		printf("WARNING: Unknown CPU type. Cache performace may be "
371198378Snwhitehorn		    "suboptimal.\n");
372198378Snwhitehorn		break;
373198378Snwhitehorn	}
374178628Smarcel}
375178628Smarcel
376