xref: /freebsd/sys/powerpc/mpc85xx/platform_mpc85xx.c (revision 1f4bcc459a76b7aa664f3fd557684cd0ba6da352)
1 /*-
2  * Copyright (c) 2008-2012 Semihalf.
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 "opt_platform.h"
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/bus.h>
35 #include <sys/pcpu.h>
36 #include <sys/proc.h>
37 #include <sys/smp.h>
38 
39 #include <machine/bus.h>
40 #include <machine/cpu.h>
41 #include <machine/hid.h>
42 #include <machine/machdep.h>
43 #include <machine/platform.h>
44 #include <machine/platformvar.h>
45 #include <machine/smp.h>
46 #include <machine/spr.h>
47 #include <machine/vmparam.h>
48 
49 #include <dev/fdt/fdt_common.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52 #include <dev/ofw/openfirm.h>
53 
54 #include <vm/vm.h>
55 #include <vm/pmap.h>
56 
57 #include <powerpc/mpc85xx/mpc85xx.h>
58 
59 #include "platform_if.h"
60 
61 #ifdef SMP
62 extern void *ap_pcpu;
63 extern vm_paddr_t kernload;		/* Kernel physical load address */
64 extern uint8_t __boot_page[];		/* Boot page body */
65 extern uint32_t bp_ntlb1s;
66 extern uint32_t bp_tlb1[];
67 extern uint32_t bp_tlb1_end[];
68 #endif
69 
70 extern uint32_t *bootinfo;
71 vm_offset_t ccsrbar_va;
72 
73 static int cpu, maxcpu;
74 
75 static int mpc85xx_probe(platform_t);
76 static void mpc85xx_mem_regions(platform_t, struct mem_region *phys,
77     int *physsz, struct mem_region *avail, int *availsz);
78 static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref);
79 static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref);
80 static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref);
81 static int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref);
82 static int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu);
83 static void mpc85xx_idle(platform_t, int cpu);
84 static int mpc85xx_idle_wakeup(platform_t plat, int cpu);
85 
86 static void mpc85xx_reset(platform_t);
87 
88 static platform_method_t mpc85xx_methods[] = {
89 	PLATFORMMETHOD(platform_probe,		mpc85xx_probe),
90 	PLATFORMMETHOD(platform_attach,		mpc85xx_attach),
91 	PLATFORMMETHOD(platform_mem_regions,	mpc85xx_mem_regions),
92 	PLATFORMMETHOD(platform_timebase_freq,	mpc85xx_timebase_freq),
93 
94 	PLATFORMMETHOD(platform_smp_first_cpu,	mpc85xx_smp_first_cpu),
95 	PLATFORMMETHOD(platform_smp_next_cpu,	mpc85xx_smp_next_cpu),
96 	PLATFORMMETHOD(platform_smp_get_bsp,	mpc85xx_smp_get_bsp),
97 	PLATFORMMETHOD(platform_smp_start_cpu,	mpc85xx_smp_start_cpu),
98 
99 	PLATFORMMETHOD(platform_reset,		mpc85xx_reset),
100 	PLATFORMMETHOD(platform_idle,		mpc85xx_idle),
101 	PLATFORMMETHOD(platform_idle_wakeup,	mpc85xx_idle_wakeup),
102 
103 	PLATFORMMETHOD_END
104 };
105 
106 DEFINE_CLASS_0(mpc85xx, mpc85xx_platform, mpc85xx_methods, 0);
107 
108 PLATFORM_DEF(mpc85xx_platform);
109 
110 static int
111 mpc85xx_probe(platform_t plat)
112 {
113 	u_int pvr = mfpvr() >> 16;
114 
115 	if ((pvr & 0xfff0) == FSL_E500v1)
116 		return (BUS_PROBE_DEFAULT);
117 
118 	return (ENXIO);
119 }
120 
121 int
122 mpc85xx_attach(platform_t plat)
123 {
124 	phandle_t cpus, child, ccsr;
125 	const char *soc_name_guesses[] = {"/soc", "soc", NULL};
126 	const char **name;
127 	pcell_t ranges[6], acells, pacells, scells;
128 	uint32_t sr;
129 	uint64_t ccsrbar, ccsrsize;
130 	int i, law_max, tgt;
131 
132 	if ((cpus = OF_finddevice("/cpus")) != -1) {
133 		for (maxcpu = 0, child = OF_child(cpus); child != 0;
134 		    child = OF_peer(child), maxcpu++)
135 			;
136 	} else
137 		maxcpu = 1;
138 
139 	/*
140 	 * Locate CCSR region. Irritatingly, there is no way to find it
141 	 * unless you already know where it is. Try to infer its location
142 	 * from the device tree.
143 	 */
144 
145 	ccsr = -1;
146 	for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++)
147 		ccsr = OF_finddevice(*name);
148 	if (ccsr == -1) {
149 		char type[64];
150 
151 	 	/* That didn't work. Search for devices of type "soc" */
152 		child = OF_child(OF_peer(0));
153 		for (OF_child(child); child != 0; child = OF_peer(child)) {
154 			if (OF_getprop(child, "device_type", type, sizeof(type))
155 			    <= 0)
156 				continue;
157 
158 			if (strcmp(type, "soc") == 0) {
159 				ccsr = child;
160 				break;
161 			}
162 		}
163 	}
164 
165 	if (ccsr == -1)
166 		panic("Could not locate CCSR window!");
167 
168 	OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells));
169 	OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells));
170 	OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells,
171 	    sizeof(pacells));
172 	OF_getprop(ccsr, "ranges", ranges, sizeof(ranges));
173 	ccsrbar = ccsrsize = 0;
174 	for (i = acells; i < acells + pacells; i++) {
175 		ccsrbar <<= 32;
176 		ccsrbar |= ranges[i];
177 	}
178 	for (i = acells + pacells; i < acells + pacells + scells; i++) {
179 		ccsrsize <<= 32;
180 		ccsrsize |= ranges[i];
181 	}
182 	ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize);
183 
184 	mpc85xx_fix_errata(ccsrbar_va);
185 	mpc85xx_enable_l3_cache();
186 
187 	/*
188 	 * Clear local access windows. Skip DRAM entries, so we don't shoot
189 	 * ourselves in the foot.
190 	 */
191 	law_max = law_getmax();
192 	for (i = 0; i < law_max; i++) {
193 		sr = ccsr_read4(OCP85XX_LAWSR(i));
194 		if ((sr & OCP85XX_ENA_MASK) == 0)
195 			continue;
196 		tgt = (sr & 0x01f00000) >> 20;
197 		if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 ||
198 		    tgt == OCP85XX_TGTIF_RAM_INTL)
199 			continue;
200 
201 		ccsr_write4(OCP85XX_LAWSR(i), sr & OCP85XX_DIS_MASK);
202 	}
203 
204 	return (0);
205 }
206 
207 void
208 mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
209     struct mem_region *avail, int *availsz)
210 {
211 
212 	ofw_mem_regions(phys, physsz, avail, availsz);
213 }
214 
215 static u_long
216 mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref)
217 {
218 	u_long ticks;
219 	phandle_t cpus, child;
220 	pcell_t freq;
221 
222 	if (bootinfo != NULL) {
223 		if (bootinfo[0] == 1) {
224 			/* Backward compatibility. See 8-STABLE. */
225 			ticks = bootinfo[3] >> 3;
226 		} else {
227 			/* Compatibility with Juniper's loader. */
228 			ticks = bootinfo[5] >> 3;
229 		}
230 	} else
231 		ticks = 0;
232 
233 	if ((cpus = OF_finddevice("/cpus")) == -1)
234 		goto out;
235 
236 	if ((child = OF_child(cpus)) == 0)
237 		goto out;
238 
239 	switch (OF_getproplen(child, "timebase-frequency")) {
240 	case 4:
241 	{
242 		uint32_t tbase;
243 		OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
244 		ticks = tbase;
245 		return (ticks);
246 	}
247 	case 8:
248 	{
249 		uint64_t tbase;
250 		OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
251 		ticks = tbase;
252 		return (ticks);
253 	}
254 	default:
255 		break;
256 	}
257 
258 	freq = 0;
259 	if (OF_getprop(child, "bus-frequency", (void *)&freq,
260 	    sizeof(freq)) <= 0)
261 		goto out;
262 
263 	/*
264 	 * Time Base and Decrementer are updated every 8 CCB bus clocks.
265 	 * HID0[SEL_TBCLK] = 0
266 	 */
267 	if (freq != 0)
268 #ifdef QORIQ_DPAA
269 		ticks = freq / 32;
270 #else
271 		ticks = freq / 8;
272 #endif
273 
274 out:
275 	if (ticks <= 0)
276 		panic("Unable to determine timebase frequency!");
277 
278 	return (ticks);
279 }
280 
281 static int
282 mpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
283 {
284 
285 	cpu = 0;
286 	cpuref->cr_cpuid = cpu;
287 	cpuref->cr_hwref = cpuref->cr_cpuid;
288 	if (bootverbose)
289 		printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid);
290 	cpu++;
291 
292 	return (0);
293 }
294 
295 static int
296 mpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
297 {
298 
299 	if (cpu >= maxcpu)
300 		return (ENOENT);
301 
302 	cpuref->cr_cpuid = cpu++;
303 	cpuref->cr_hwref = cpuref->cr_cpuid;
304 	if (bootverbose)
305 		printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid);
306 
307 	return (0);
308 }
309 
310 static int
311 mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
312 {
313 
314 	cpuref->cr_cpuid = mfspr(SPR_PIR);
315 	cpuref->cr_hwref = cpuref->cr_cpuid;
316 
317 	return (0);
318 }
319 
320 static int
321 mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
322 {
323 #ifdef SMP
324 	uint32_t *tlb1;
325 	vm_paddr_t bptr;
326 	uint32_t reg;
327 	int i, timeout;
328 	uintptr_t brr;
329 	int cpuid;
330 
331 #ifdef QORIQ_DPAA
332 	uint32_t tgt;
333 
334 	reg = ccsr_read4(OCP85XX_COREDISR);
335 	cpuid = pc->pc_cpuid;
336 
337 	if ((reg & cpuid) != 0) {
338 		printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid);
339 		return (-1);
340 	}
341 
342 	brr = OCP85XX_BRR;
343 #else /* QORIQ_DPAA */
344 	brr = OCP85XX_EEBPCR;
345 	cpuid = pc->pc_cpuid + 24;
346 #endif
347 	reg = ccsr_read4(brr);
348 	if ((reg & (1 << cpuid)) != 0) {
349 		printf("SMP: CPU %d already out of hold-off state!\n",
350 		    pc->pc_cpuid);
351 		return (ENXIO);
352 	}
353 
354 	ap_pcpu = pc;
355 	__asm __volatile("msync; isync");
356 
357 	i = 0;
358 	tlb1 = bp_tlb1;
359 	while (i < bp_ntlb1s && tlb1 < bp_tlb1_end) {
360 		mtspr(SPR_MAS0, MAS0_TLBSEL(1) | MAS0_ESEL(i));
361 		__asm __volatile("isync; tlbre");
362 		tlb1[0] = mfspr(SPR_MAS1);
363 		tlb1[1] = mfspr(SPR_MAS2);
364 		tlb1[2] = mfspr(SPR_MAS3);
365 		i++;
366 		tlb1 += 3;
367 	}
368 	if (i < bp_ntlb1s)
369 		bp_ntlb1s = i;
370 
371 	/* Flush caches to have our changes hit DRAM. */
372 	cpu_flush_dcache(__boot_page, 4096);
373 
374 	bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload;
375 	KASSERT((bptr & 0xfff) == 0,
376 	    ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr));
377 #ifdef QORIQ_DPAA
378 
379 	/*
380 	 * Read DDR controller configuration to select proper BPTR target ID.
381 	 *
382 	 * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers
383 	 * interleaving. If this bit is set, we have to use
384 	 * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs,
385 	 * this bit is reserved and always 0.
386 	 */
387 
388 	reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG);
389 	if (reg & (1 << 29))
390 		tgt = OCP85XX_TGTIF_RAM_INTL;
391 	else
392 		tgt = OCP85XX_TGTIF_RAM1;
393 
394 	/*
395 	 * Set BSTR to the physical address of the boot page
396 	 */
397 	ccsr_write4(OCP85XX_BSTRH, bptr >> 32);
398 	ccsr_write4(OCP85XX_BSTRL, bptr);
399 	ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK |
400 	    (tgt << OCP85XX_TRGT_SHIFT) | (ffsl(PAGE_SIZE) - 2));
401 
402 	/* Read back OCP85XX_BSTAR to synchronize write */
403 	ccsr_read4(OCP85XX_BSTAR);
404 
405 	/*
406 	 * Enable and configure time base on new CPU.
407 	 */
408 
409 	/* Set TB clock source to platform clock / 32 */
410 	reg = ccsr_read4(CCSR_CTBCKSELR);
411 	ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid));
412 
413 	/* Enable TB */
414 	reg = ccsr_read4(CCSR_CTBENR);
415 	ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid));
416 #else
417 
418 	/*
419 	 * Set BPTR to the physical address of the boot page
420 	 */
421 	bptr = (bptr >> 12) | 0x80000000u;
422 	ccsr_write4(OCP85XX_BPTR, bptr);
423 	__asm __volatile("isync; msync");
424 
425 #endif /* QORIQ_DPAA */
426 
427 	/*
428 	 * Release AP from hold-off state
429 	 */
430 	reg = ccsr_read4(brr);
431 	ccsr_write4(brr, reg | (1 << cpuid));
432 	__asm __volatile("isync; msync");
433 
434 	timeout = 500;
435 	while (!pc->pc_awake && timeout--)
436 		DELAY(1000);	/* wait 1ms */
437 
438 	/*
439 	 * Disable boot page translation so that the 4K page at the default
440 	 * address (= 0xfffff000) isn't permanently remapped and thus not
441 	 * usable otherwise.
442 	 */
443 #ifdef QORIQ_DPAA
444 	ccsr_write4(OCP85XX_BSTAR, 0);
445 #else
446 	ccsr_write4(OCP85XX_BPTR, 0);
447 #endif
448 	__asm __volatile("isync; msync");
449 
450 	if (!pc->pc_awake)
451 		printf("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid);
452 	return ((pc->pc_awake) ? 0 : EBUSY);
453 #else
454 	/* No SMP support */
455 	return (ENXIO);
456 #endif
457 }
458 
459 static void
460 mpc85xx_reset(platform_t plat)
461 {
462 
463 	/*
464 	 * Try the dedicated reset register first.
465 	 * If the SoC doesn't have one, we'll fall
466 	 * back to using the debug control register.
467 	 */
468 	ccsr_write4(OCP85XX_RSTCR, 2);
469 
470 	/* Clear DBCR0, disables debug interrupts and events. */
471 	mtspr(SPR_DBCR0, 0);
472 	__asm __volatile("isync");
473 
474 	/* Enable Debug Interrupts in MSR. */
475 	mtmsr(mfmsr() | PSL_DE);
476 
477 	/* Enable debug interrupts and issue reset. */
478 	mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM);
479 
480 	printf("Reset failed...\n");
481 	while (1)
482 		;
483 }
484 
485 static void
486 mpc85xx_idle(platform_t plat, int cpu)
487 {
488 #ifdef QORIQ_DPAA
489 	uint32_t reg;
490 
491 	reg = ccsr_read4(OCP85XX_RCPM_CDOZCR);
492 	ccsr_write4(OCP85XX_RCPM_CDOZCR, reg | (1 << cpu));
493 	ccsr_read4(OCP85XX_RCPM_CDOZCR);
494 #else
495 	register_t msr;
496 
497 	msr = mfmsr();
498 	/* Freescale E500 core RM section 6.4.1. */
499 	__asm __volatile("msync; mtmsr %0; isync" ::
500 	    "r" (msr | PSL_WE));
501 #endif
502 }
503 
504 static int
505 mpc85xx_idle_wakeup(platform_t plat, int cpu)
506 {
507 #ifdef QORIQ_DPAA
508 	uint32_t reg;
509 
510 	reg = ccsr_read4(OCP85XX_RCPM_CDOZCR);
511 	ccsr_write4(OCP85XX_RCPM_CDOZCR, reg & ~(1 << cpu));
512 	ccsr_read4(OCP85XX_RCPM_CDOZCR);
513 
514 	return (1);
515 #endif
516 	return (0);
517 }
518