1178596Sraj/*-
2178596Sraj * Copyright (C) 2008 Semihalf, Rafal Jaworowski
3178596Sraj * All rights reserved.
4178596Sraj *
5178596Sraj * Redistribution and use in source and binary forms, with or without
6178596Sraj * modification, are permitted provided that the following conditions
7178596Sraj * are met:
8178596Sraj * 1. Redistributions of source code must retain the above copyright
9178596Sraj *    notice, this list of conditions and the following disclaimer.
10178596Sraj * 2. Redistributions in binary form must reproduce the above copyright
11178596Sraj *    notice, this list of conditions and the following disclaimer in the
12178596Sraj *    documentation and/or other materials provided with the distribution.
13178596Sraj *
14178596Sraj * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15178596Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16178596Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17178596Sraj * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18178596Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19178596Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20178596Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21178596Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22178596Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23178596Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24178596Sraj * SUCH DAMAGE.
25178596Sraj */
26178596Sraj
27178596Sraj#include <sys/cdefs.h>
28178596Sraj__FBSDID("$FreeBSD: releng/11.0/sys/powerpc/mpc85xx/mpc85xx.c 295908 2016-02-23 02:28:19Z jhibbits $");
29178596Sraj
30291008Sjhibbits#include "opt_platform.h"
31178596Sraj#include <sys/param.h>
32178596Sraj#include <sys/systm.h>
33209908Sraj#include <sys/lock.h>
34209908Sraj#include <sys/mutex.h>
35292903Sjhibbits#include <sys/reboot.h>
36209908Sraj#include <sys/rman.h>
37178596Sraj
38178597Sraj#include <vm/vm.h>
39178597Sraj#include <vm/vm_param.h>
40292903Sjhibbits#include <vm/pmap.h>
41178597Sraj
42178596Sraj#include <machine/cpu.h>
43178596Sraj#include <machine/cpufunc.h>
44292903Sjhibbits#include <machine/machdep.h>
45234609Snwhitehorn#include <machine/pio.h>
46178596Sraj#include <machine/spr.h>
47178596Sraj
48257178Snwhitehorn#include <dev/fdt/fdt_common.h>
49257178Snwhitehorn
50292903Sjhibbits#include <dev/fdt/fdt_common.h>
51292903Sjhibbits#include <dev/ofw/ofw_bus.h>
52292903Sjhibbits#include <dev/ofw/ofw_bus_subr.h>
53292903Sjhibbits#include <dev/ofw/openfirm.h>
54292903Sjhibbits
55186227Sraj#include <powerpc/mpc85xx/mpc85xx.h>
56178597Sraj
57291008Sjhibbits
58178596Sraj/*
59178596Sraj * MPC85xx system specific routines
60178596Sraj */
61178596Sraj
62186227Srajuint32_t
63186227Srajccsr_read4(uintptr_t addr)
64186227Sraj{
65186227Sraj	volatile uint32_t *ptr = (void *)addr;
66186227Sraj
67186227Sraj	return (*ptr);
68186227Sraj}
69186227Sraj
70178596Srajvoid
71186227Srajccsr_write4(uintptr_t addr, uint32_t val)
72178596Sraj{
73186227Sraj	volatile uint32_t *ptr = (void *)addr;
74178596Sraj
75186227Sraj	*ptr = val;
76234579Snwhitehorn	powerpc_iomb();
77186227Sraj}
78186227Sraj
79189757Srajint
80186288Srajlaw_getmax(void)
81186288Sraj{
82186288Sraj	uint32_t ver;
83291008Sjhibbits	int law_max;
84186288Sraj
85186288Sraj	ver = SVR_VER(mfspr(SPR_SVR));
86291008Sjhibbits	switch (ver) {
87291008Sjhibbits	case SVR_MPC8555:
88291008Sjhibbits	case SVR_MPC8555E:
89291008Sjhibbits		law_max = 8;
90291008Sjhibbits		break;
91291008Sjhibbits	case SVR_MPC8533:
92291008Sjhibbits	case SVR_MPC8533E:
93291008Sjhibbits	case SVR_MPC8548:
94291008Sjhibbits	case SVR_MPC8548E:
95291008Sjhibbits		law_max = 10;
96291008Sjhibbits		break;
97291008Sjhibbits	case SVR_P5020:
98291008Sjhibbits	case SVR_P5020E:
99291008Sjhibbits		law_max = 32;
100291008Sjhibbits		break;
101291008Sjhibbits	default:
102291008Sjhibbits		law_max = 8;
103291008Sjhibbits	}
104222428Smarcel
105291008Sjhibbits	return (law_max);
106186288Sraj}
107186288Sraj
108291008Sjhibbitsstatic inline void
109291008Sjhibbitslaw_write(uint32_t n, uint64_t bar, uint32_t sr)
110291008Sjhibbits{
111291008Sjhibbits#if defined(QORIQ_DPAA)
112291008Sjhibbits	ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32);
113291008Sjhibbits	ccsr_write4(OCP85XX_LAWBARL(n), bar);
114291008Sjhibbits#else
115291008Sjhibbits	ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12);
116291008Sjhibbits#endif
117291008Sjhibbits	ccsr_write4(OCP85XX_LAWSR(n), sr);
118291008Sjhibbits
119291008Sjhibbits	/*
120291008Sjhibbits	 * The last write to LAWAR should be followed by a read
121291008Sjhibbits	 * of LAWAR before any device try to use any of windows.
122291008Sjhibbits	 * What more the read of LAWAR should be followed by isync
123291008Sjhibbits	 * instruction.
124291008Sjhibbits	 */
125291008Sjhibbits
126291008Sjhibbits	ccsr_read4(OCP85XX_LAWSR(n));
127291008Sjhibbits	isync();
128291008Sjhibbits}
129291008Sjhibbits
130291008Sjhibbitsstatic inline void
131291008Sjhibbitslaw_read(uint32_t n, uint64_t *bar, uint32_t *sr)
132291008Sjhibbits{
133291008Sjhibbits#if defined(QORIQ_DPAA)
134291008Sjhibbits	*bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 |
135291008Sjhibbits	    ccsr_read4(OCP85XX_LAWBARL(n));
136291008Sjhibbits#else
137291008Sjhibbits	*bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12;
138291008Sjhibbits#endif
139291008Sjhibbits	*sr = ccsr_read4(OCP85XX_LAWSR(n));
140291008Sjhibbits}
141291008Sjhibbits
142291008Sjhibbitsstatic int
143291008Sjhibbitslaw_find_free(void)
144291008Sjhibbits{
145291008Sjhibbits	uint32_t i,sr;
146291008Sjhibbits	uint64_t bar;
147291008Sjhibbits	int law_max;
148291008Sjhibbits
149291008Sjhibbits	law_max = law_getmax();
150291008Sjhibbits	/* Find free LAW */
151291008Sjhibbits	for (i = 0; i < law_max; i++) {
152291008Sjhibbits		law_read(i, &bar, &sr);
153291008Sjhibbits		if ((sr & 0x80000000) == 0)
154291008Sjhibbits			break;
155291008Sjhibbits	}
156291008Sjhibbits
157291008Sjhibbits	return (i);
158291008Sjhibbits}
159291008Sjhibbits
160295908Sjhibbits#define	_LAW_SR(trgt,size)	(0x80000000 | (trgt << 20) | \
161295908Sjhibbits				(flsl(size + (size - 1)) - 2))
162186288Sraj
163186288Srajint
164291008Sjhibbitslaw_enable(int trgt, uint64_t bar, uint32_t size)
165186288Sraj{
166291008Sjhibbits	uint64_t bar_tmp;
167291008Sjhibbits	uint32_t sr, sr_tmp;
168186288Sraj	int i, law_max;
169186288Sraj
170235934Smarcel	if (size == 0)
171235934Smarcel		return (0);
172235934Smarcel
173186288Sraj	law_max = law_getmax();
174186288Sraj	sr = _LAW_SR(trgt, size);
175186288Sraj
176186288Sraj	/* Bail if already programmed. */
177291008Sjhibbits	for (i = 0; i < law_max; i++) {
178291008Sjhibbits		law_read(i, &bar_tmp, &sr_tmp);
179291008Sjhibbits		if (sr == sr_tmp && bar == bar_tmp)
180186288Sraj			return (0);
181291008Sjhibbits	}
182186288Sraj
183186288Sraj	/* Find an unused access window. */
184291008Sjhibbits	i = law_find_free();
185186288Sraj
186186288Sraj	if (i == law_max)
187186288Sraj		return (ENOSPC);
188186288Sraj
189291008Sjhibbits	law_write(i, bar, sr);
190186288Sraj	return (0);
191186288Sraj}
192186288Sraj
193186288Srajint
194291008Sjhibbitslaw_disable(int trgt, uint64_t bar, uint32_t size)
195186288Sraj{
196291008Sjhibbits	uint64_t bar_tmp;
197291008Sjhibbits	uint32_t sr, sr_tmp;
198186288Sraj	int i, law_max;
199186288Sraj
200186288Sraj	law_max = law_getmax();
201186288Sraj	sr = _LAW_SR(trgt, size);
202186288Sraj
203186288Sraj	/* Find and disable requested LAW. */
204291008Sjhibbits	for (i = 0; i < law_max; i++) {
205291008Sjhibbits		law_read(i, &bar_tmp, &sr_tmp);
206291008Sjhibbits		if (sr == sr_tmp && bar == bar_tmp) {
207291008Sjhibbits			law_write(i, 0, 0);
208186288Sraj			return (0);
209186288Sraj		}
210291008Sjhibbits	}
211186288Sraj
212186288Sraj	return (ENOENT);
213186288Sraj}
214186288Sraj
215209908Srajint
216209908Srajlaw_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
217209908Sraj{
218209908Sraj	u_long start;
219209908Sraj	uint32_t ver;
220209908Sraj	int trgt, rv;
221209908Sraj
222209908Sraj	ver = SVR_VER(mfspr(SPR_SVR));
223209908Sraj
224209908Sraj	start = rman_get_start(res) & 0xf000;
225209908Sraj
226209908Sraj	rv = 0;
227209908Sraj	trgt = -1;
228209908Sraj	switch (start) {
229291008Sjhibbits	case 0x0000:
230209908Sraj	case 0x8000:
231209908Sraj		trgt = 0;
232209908Sraj		break;
233291008Sjhibbits	case 0x1000:
234209908Sraj	case 0x9000:
235209908Sraj		trgt = 1;
236209908Sraj		break;
237291008Sjhibbits	case 0x2000:
238209908Sraj	case 0xa000:
239222428Smarcel		if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
240222428Smarcel			trgt = 3;
241222428Smarcel		else
242209908Sraj			trgt = 2;
243222428Smarcel		break;
244291008Sjhibbits	case 0x3000:
245222428Smarcel	case 0xb000:
246222428Smarcel		if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
247222428Smarcel			rv = EINVAL;
248209908Sraj		else
249222428Smarcel			trgt = 3;
250209908Sraj		break;
251209908Sraj	default:
252209908Sraj		rv = ENXIO;
253209908Sraj	}
254235934Smarcel	if (rv == 0) {
255235934Smarcel		*trgt_mem = trgt;
256235934Smarcel		*trgt_io = trgt;
257235934Smarcel	}
258209908Sraj	return (rv);
259209908Sraj}
260209908Sraj
261292903Sjhibbitsstatic void
262292903Sjhibbitsl3cache_inval(void)
263292903Sjhibbits{
264292903Sjhibbits
265292903Sjhibbits	/* Flash invalidate the CPC and clear all the locks */
266292903Sjhibbits	ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI |
267292903Sjhibbits	    OCP85XX_CPC_CSR0_LFC);
268292903Sjhibbits	while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI |
269292903Sjhibbits	    OCP85XX_CPC_CSR0_LFC))
270292903Sjhibbits		;
271292903Sjhibbits}
272292903Sjhibbits
273292903Sjhibbitsstatic void
274292903Sjhibbitsl3cache_enable(void)
275292903Sjhibbits{
276292903Sjhibbits
277292903Sjhibbits	ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE |
278292903Sjhibbits	    OCP85XX_CPC_CSR0_PE);
279292903Sjhibbits	/* Read back to sync write */
280292903Sjhibbits	ccsr_read4(OCP85XX_CPC_CSR0);
281292903Sjhibbits}
282292903Sjhibbits
283292903Sjhibbitsvoid
284292903Sjhibbitsmpc85xx_enable_l3_cache(void)
285292903Sjhibbits{
286292903Sjhibbits	uint32_t csr, size, ver;
287292903Sjhibbits
288292903Sjhibbits	/* Enable L3 CoreNet Platform Cache (CPC) */
289292903Sjhibbits	ver = SVR_VER(mfspr(SPR_SVR));
290292903Sjhibbits	if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 ||
291292903Sjhibbits	    ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) {
292292903Sjhibbits		csr = ccsr_read4(OCP85XX_CPC_CSR0);
293292903Sjhibbits		if ((csr & OCP85XX_CPC_CSR0_CE) == 0) {
294292903Sjhibbits			l3cache_inval();
295292903Sjhibbits			l3cache_enable();
296292903Sjhibbits		}
297292903Sjhibbits
298292903Sjhibbits		csr = ccsr_read4(OCP85XX_CPC_CSR0);
299292903Sjhibbits		if ((boothowto & RB_VERBOSE) != 0 ||
300292903Sjhibbits		    (csr & OCP85XX_CPC_CSR0_CE) == 0) {
301292903Sjhibbits			size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0));
302292903Sjhibbits			printf("L3 Corenet Platform Cache: %d KB %sabled\n",
303292903Sjhibbits			    size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ?
304292903Sjhibbits			    "dis" : "en");
305292903Sjhibbits		}
306292903Sjhibbits	}
307292903Sjhibbits}
308292903Sjhibbits
309292903Sjhibbitsstatic void
310292903Sjhibbitsmpc85xx_dataloss_erratum_spr976(void)
311292903Sjhibbits{
312292903Sjhibbits	uint32_t svr = SVR_VER(mfspr(SPR_SVR));
313292903Sjhibbits
314292903Sjhibbits	/* Ignore whether it's the E variant */
315292903Sjhibbits	svr &= ~0x8;
316292903Sjhibbits
317292903Sjhibbits	if (svr != SVR_P3041 && svr != SVR_P4040 &&
318292903Sjhibbits	    svr != SVR_P4080 && svr != SVR_P5020)
319292903Sjhibbits		return;
320292903Sjhibbits
321292903Sjhibbits	mb();
322292903Sjhibbits	isync();
323292903Sjhibbits	mtspr(976, (mfspr(976) & ~0x1f8) | 0x48);
324292903Sjhibbits	isync();
325292903Sjhibbits}
326292903Sjhibbits
327292903Sjhibbitsstatic vm_offset_t
328292903Sjhibbitsmpc85xx_map_dcsr(void)
329292903Sjhibbits{
330292903Sjhibbits	phandle_t node;
331292903Sjhibbits	u_long b, s;
332292903Sjhibbits	int err;
333292903Sjhibbits
334292903Sjhibbits	/*
335292903Sjhibbits	 * Try to access the dcsr node directly i.e. through /aliases/.
336292903Sjhibbits	 */
337292903Sjhibbits	if ((node = OF_finddevice("dcsr")) != -1)
338292903Sjhibbits		if (fdt_is_compatible_strict(node, "fsl,dcsr"))
339292903Sjhibbits			goto moveon;
340292903Sjhibbits	/*
341292903Sjhibbits	 * Find the node the long way.
342292903Sjhibbits	 */
343292903Sjhibbits	if ((node = OF_finddevice("/")) == -1)
344292903Sjhibbits		return (ENXIO);
345292903Sjhibbits
346292903Sjhibbits	if ((node = ofw_bus_find_compatible(node, "fsl,dcsr")) == 0)
347292903Sjhibbits		return (ENXIO);
348292903Sjhibbits
349292903Sjhibbitsmoveon:
350292903Sjhibbits	err = fdt_get_range(node, 0, &b, &s);
351292903Sjhibbits
352292903Sjhibbits	if (err != 0)
353292903Sjhibbits		return (err);
354292903Sjhibbits
355292903Sjhibbits#ifdef QORIQ_DPAA
356292903Sjhibbits	law_enable(OCP85XX_TGTIF_DCSR, b, 0x400000);
357292903Sjhibbits#endif
358292903Sjhibbits	return pmap_early_io_map(b, 0x400000);
359292903Sjhibbits}
360292903Sjhibbits
361292903Sjhibbits
362292903Sjhibbits
363292903Sjhibbitsvoid
364292903Sjhibbitsmpc85xx_fix_errata(vm_offset_t va_ccsr)
365292903Sjhibbits{
366292903Sjhibbits	uint32_t svr = SVR_VER(mfspr(SPR_SVR));
367292903Sjhibbits	vm_offset_t va_dcsr;
368292903Sjhibbits
369292903Sjhibbits	/* Ignore whether it's the E variant */
370292903Sjhibbits	svr &= ~0x8;
371292903Sjhibbits
372292903Sjhibbits	if (svr != SVR_P3041 && svr != SVR_P4040 &&
373292903Sjhibbits	    svr != SVR_P4080 && svr != SVR_P5020)
374292903Sjhibbits		return;
375292903Sjhibbits
376292903Sjhibbits	if (mfmsr() & PSL_EE)
377292903Sjhibbits		return;
378292903Sjhibbits
379292903Sjhibbits	/*
380292903Sjhibbits	 * dcsr region need to be mapped thus patch can refer to.
381292903Sjhibbits	 * Align dcsr right after ccsbar.
382292903Sjhibbits	 */
383292903Sjhibbits	va_dcsr = mpc85xx_map_dcsr();
384292903Sjhibbits	if (va_dcsr == 0)
385292903Sjhibbits		goto err;
386292903Sjhibbits
387292903Sjhibbits	/*
388292903Sjhibbits	 * As A004510 errata specify, special purpose register 976
389292903Sjhibbits	 * SPR976[56:60] = 6'b001001 must be set. e500mc core reference manual
390292903Sjhibbits	 * does not document SPR976 register.
391292903Sjhibbits	 */
392292903Sjhibbits	mpc85xx_dataloss_erratum_spr976();
393292903Sjhibbits
394292903Sjhibbits	/*
395292903Sjhibbits	 * Specific settings in the CCF and core platform cache (CPC)
396292903Sjhibbits	 * are required to reconfigure the CoreNet coherency fabric.
397292903Sjhibbits	 * The register settings that should be updated are described
398292903Sjhibbits	 * in errata and relay on base address, offset and updated value.
399292903Sjhibbits	 * Special conditions must be used to update these registers correctly.
400292903Sjhibbits	 */
401292903Sjhibbits	dataloss_erratum_access(va_dcsr + 0xb0e08, 0xe0201800);
402292903Sjhibbits	dataloss_erratum_access(va_dcsr + 0xb0e18, 0xe0201800);
403292903Sjhibbits	dataloss_erratum_access(va_dcsr + 0xb0e38, 0xe0400000);
404292903Sjhibbits	dataloss_erratum_access(va_dcsr + 0xb0008, 0x00900000);
405292903Sjhibbits	dataloss_erratum_access(va_dcsr + 0xb0e40, 0xe00a0000);
406292903Sjhibbits
407292903Sjhibbits	switch (svr) {
408292903Sjhibbits	case SVR_P5020:
409292903Sjhibbits		dataloss_erratum_access(va_ccsr + 0x18600, 0xc0000000);
410292903Sjhibbits		break;
411292903Sjhibbits	case SVR_P4040:
412292903Sjhibbits	case SVR_P4080:
413292903Sjhibbits		dataloss_erratum_access(va_ccsr + 0x18600, 0xff000000);
414292903Sjhibbits		break;
415292903Sjhibbits	case SVR_P3041:
416292903Sjhibbits		dataloss_erratum_access(va_ccsr + 0x18600, 0xf0000000);
417292903Sjhibbits	}
418292903Sjhibbits	dataloss_erratum_access(va_ccsr + 0x10f00, 0x415e5000);
419292903Sjhibbits	dataloss_erratum_access(va_ccsr + 0x11f00, 0x415e5000);
420292903Sjhibbits
421292903Sjhibbitserr:
422292903Sjhibbits	return;
423292903Sjhibbits}
424