1
2/*
3 * r3 = fdt pointer (ignored)
4 * r4 = 0
5 * r5 = 0
6 * r6 = EPAPR magic (0x45505150)
7 * r7 = TLB1[0] entry size (64MB)
8 * r8 = 0
9 * r9 = 0
10 */
11	.p2align 5
12ENTRY_NOPROFILE(e500_spinup_trampoline)
13
14	stw	%r7, 4(%r0)		/* r7 to 4 */
15
16	lis	%r31, 0xdeadbeef@h
17	ori	%r31, %r31, 0xdeadbeef@l
18	mr	%r30, %r31
19	mr	%r29, %r31
20	mr	%r28, %r31
21	mr	%r27, %r31
22	mr	%r26, %r31
23	mr	%r25, %r31
24	mr	%r24, %r31
25	mr	%r23, %r31
26	mr	%r22, %r31
27	mr	%r21, %r31
28	mr	%r20, %r31
29	mr	%r19, %r31
30	mr	%r18, %r31
31	mr	%r17, %r31
32	mr	%r16, %r31
33	mr	%r15, %r31
34	mr	%r14, %r31
35	mr	%r13, %r31
36	mr	%r12, %r31
37	mr	%r11, %r31
38	mr	%r10, %r31
39	mr	%r2, %r31
40
41	/*
42	 * First thing we need to do is to set SPRG0 with our cpu_info
43	 * and get our initial stack pointer (this must be within the
44	 * bounds of the TLB1[0] entry U-boot setup for us).
45	 *
46	 * cpu_hatch will return a new SP to use.
47	 *
48	 * All the caller-saved register are ours to use.  So we will.
49	 */
50	lis	%r20, _C_LABEL(cpu_hatch_data)@h
51	ori	%r20, %r20, _C_LABEL(cpu_hatch_data)@l
52
53	li	%r0, 0
54	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
55	eieio
56
57	lwz	%r1, HATCH_SP(%r20)		/* get hatch SP */
58	lwz	%r21, HATCH_CI(%r20)		/* get cpu_info */
59	mtsprg0	%r21				/* save cpu_info */
60	lwz	%r13, CI_CURLWP(%r21)		/* load r13 with curlwp */
61	mtsprg2	%r13				/* save it in sprg2 */
62
63	/*
64	 * Now to synchronize timebase values.  First to make sure HID0 is
65	 * set correctly, except with the timebase disabled.
66	 */
67	lwz	%r22, HATCH_HID0(%r20)		/* get HID0 */
68	li	%r28, HID0_TBEN			/* HID0_TBEN */
69	andc	%r0,%r22,%r28			/* clear TBEN from HID0 */
70	mtspr	SPR_HID0, %r0			/* set HID0 (timebase off) */
71	isync
72	lwz	%r24, HATCH_TBL(%r20)		/* get lower timebase value */
73	lwz	%r23, HATCH_TBU(%r20)		/* get upper timebase value */
74
75	/*
76	 * Figure out how much we are adjusting the timebase
77	 */
78	mftbl	%r4				/* get lower timebase */
79	subfc	%r0, %r4, %r24			/* subtract from new value */
80	stw	%r0, HATCH_TBL(%r20)		/* save it */
81	mftbu	%r3				/* get upper timebase */
82	subfe	%r0, %r3, %r23			/* subtract from new value */
83	stw	%r0, HATCH_TBU(%r20)		/* save it */
84
85	/*
86	 * Since we've disabled timebase, we can set the timebase registers
87	 * without fear of them changing.  Have to do this after we read the
88	 * previous values.
89	 */
90	mttbu	%r23				/* set upper timebase */
91	mttbl	%r24				/* set lower timebase */
92
93	/*
94	 * Now we loop until the boot cpu tells us to enable timebase
95	 */
961:	lwz	%r0, HATCH_RUNNING(%r20)	/* is it time? */
97	cmplwi	%r0, 0
98	beq+	1b
99
100	mtspr	SPR_HID0, %r22			/* start timebase running */
101	isync
102
103	li	%r0, 2
104	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
105
106	/*
107	 * We have to setup the IVOR SPRs since the ones u-boot setup
108	 * don't work for us.
109	 */
110	bl	_C_LABEL(exception_init)	/* setup IVORs */
111
112	li	%r0, 3
113	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
114
115	/*
116	 * U-boot has mapped the bottom 64MB in TLB1[0].  We are going to need
117	 * to change this entry and it's not safe to do so while running out
118	 * of it.  So we copy TLB1[0] to TLB1[1] but set it for AS1.  We then
119	 * switch to AS1 and reload TLB1[0] with its correct value, and then we
120	 * switch back to AS0.  After that, we can load the rest of the TLB1
121	 * entries.
122	 */
123
124	/*
125	 * Fetch TLB1[0]
126	 */
127	lis	%r16, (MASX_TLBSEL_MAKE(1)|MAS0_ESEL_MAKE(0))@h
128	mtspr	SPR_MAS0, %r16
129	tlbre
130
131	li	%r0, 4
132	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
133
134	/*
135	 * Copy TLB1[0] to TLB[1] and set it to use AS1
136	 */
137	mfspr	%r3, SPR_MAS0
138	addis	%r3, %r3, MAS0_ESEL@h		/* advance to next TLB entry */
139	mtspr	SPR_MAS0, %r3			/* place into SPR */
140	mfspr	%r4, SPR_MAS1
141	ori	%r4, %r4, MAS1_TS@l		/* Make it use AS1 */
142	mtspr	SPR_MAS1, %r4
143	tlbwe					/* write the TLB entry */
144
145	li	%r0, 5
146	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
147
148	/*
149	 * Let's find out what TLB1[0] entry we are supposed to use.
150	 */
151	li	%r3, 0
152	bl	_C_LABEL(e500_tlb1_fetch)
153	lwz	%r28, 0(%r3)			/* load the saved TLB1 entry */
154	mtspr	SPR_MAS0, %r28			/* place into SPRs */
155	mtspr	SPR_MAS1, %r29
156	mtspr	SPR_MAS2, %r30
157	mtspr	SPR_MAS3, %r31
158
159	li	%r0, 6
160	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
161
162	/*
163	 * Now to switch to running in AS1
164	 */
165	mfmsr	%r3
166	ori	%r4,%r3,(PSL_DS|PSL_IS)@l
167	mtsrr1	%r4
168
169	bl	1f
1701:	mflr	%r11
171	addi	%r4,%r11,.Las1start-1b
172	addi	%r5,%r11,.Las1end-1b
173	mtsrr0	%r4
174	li	%r0, 7
175	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
176	rfi			/* switch to AS1, context synchronizing */
177
178.Las1start:
179	/*
180	 * We are now running in AS1, update TLB1[0]
181	 */
182	li	%r0, 8
183	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
184
185	tlbwe
186
187	mtsrr0	%r5
188	mtsrr1	%r3
189
190	li	%r0, 9
191	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
192
193	rfi			/* switch back to AS0, context synchronizing */
194
195.Las1end:
196	li	%r0, 10
197	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
198
199	/*
200	 * Now we can use our stack...
201	 */
202	lwz	%r0, CI_CURPCB(%r21)
203	lwz	%r1, PCB_SP(%r0)
204
205	li	%r0, 11
206	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
207
208	/*
209	 * Tell spinup code we are done with the hatch stack.
210	 */
211	li	%r0, 0
212	stw	%r0, HATCH_SP(%r20)
213
214	li	%r0, 12
215	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
216
217	/*
218	 * We now have our TLB1[0] in place.  Now we need to load the rest of
219	 * TLB1 with our entries.  After this is done, we should have access
220	 * to everything.
221	 */
222	bl	_C_LABEL(e500_tlb1_sync)
223
224	li	%r0, 13
225	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
226
227	/*
228	 * We've gotten the low level stuff done.
229	 * Now to do more advanced stuff.
230	 */
231	mr	%r3, %r21
232	bl	_C_LABEL(e500_cpu_hatch)
233
234	li	%r0, 14
235	stw	%r0, HATCH_RUNNING(%r20)	/* progress */
236
237	/*
238	 * Now wait to become runnable
239	 */
240	bl	_C_LABEL(cpu_hatch)
241
242	wrteei	1				/* allow interrupts */
243	bl	_C_LABEL(spl0)			/* unblock interrupts */
244
245	b	_C_LABEL(idle_loop)
246