mpc85xx.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (C) 2008 Semihalf, Rafal Jaworowski
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/powerpc/mpc85xx/mpc85xx.c 330897 2018-03-14 03:19:51Z eadler $");
31
32#include "opt_platform.h"
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/lock.h>
36#include <sys/mutex.h>
37#include <sys/reboot.h>
38#include <sys/rman.h>
39
40#include <vm/vm.h>
41#include <vm/vm_param.h>
42#include <vm/pmap.h>
43
44#include <machine/cpu.h>
45#include <machine/cpufunc.h>
46#include <machine/machdep.h>
47#include <machine/pio.h>
48#include <machine/spr.h>
49
50#include <dev/fdt/fdt_common.h>
51
52#include <dev/fdt/fdt_common.h>
53#include <dev/ofw/ofw_bus.h>
54#include <dev/ofw/ofw_bus_subr.h>
55#include <dev/ofw/openfirm.h>
56
57#include <powerpc/mpc85xx/mpc85xx.h>
58
59
60/*
61 * MPC85xx system specific routines
62 */
63
64uint32_t
65ccsr_read4(uintptr_t addr)
66{
67	volatile uint32_t *ptr = (void *)addr;
68
69	return (*ptr);
70}
71
72void
73ccsr_write4(uintptr_t addr, uint32_t val)
74{
75	volatile uint32_t *ptr = (void *)addr;
76
77	*ptr = val;
78	powerpc_iomb();
79}
80
81int
82law_getmax(void)
83{
84	uint32_t ver;
85	int law_max;
86
87	ver = SVR_VER(mfspr(SPR_SVR));
88	switch (ver) {
89	case SVR_MPC8555:
90	case SVR_MPC8555E:
91		law_max = 8;
92		break;
93	case SVR_MPC8533:
94	case SVR_MPC8533E:
95	case SVR_MPC8548:
96	case SVR_MPC8548E:
97		law_max = 10;
98		break;
99	case SVR_P5020:
100	case SVR_P5020E:
101		law_max = 32;
102		break;
103	default:
104		law_max = 8;
105	}
106
107	return (law_max);
108}
109
110static inline void
111law_write(uint32_t n, uint64_t bar, uint32_t sr)
112{
113
114	if (mpc85xx_is_qoriq()) {
115		ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32);
116		ccsr_write4(OCP85XX_LAWBARL(n), bar);
117		ccsr_write4(OCP85XX_LAWSR_QORIQ(n), sr);
118		ccsr_read4(OCP85XX_LAWSR_QORIQ(n));
119	} else {
120		ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12);
121		ccsr_write4(OCP85XX_LAWSR_85XX(n), sr);
122		ccsr_read4(OCP85XX_LAWSR_85XX(n));
123	}
124
125	/*
126	 * The last write to LAWAR should be followed by a read
127	 * of LAWAR before any device try to use any of windows.
128	 * What more the read of LAWAR should be followed by isync
129	 * instruction.
130	 */
131
132	isync();
133}
134
135static inline void
136law_read(uint32_t n, uint64_t *bar, uint32_t *sr)
137{
138
139	if (mpc85xx_is_qoriq()) {
140		*bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 |
141		    ccsr_read4(OCP85XX_LAWBARL(n));
142		*sr = ccsr_read4(OCP85XX_LAWSR_QORIQ(n));
143	} else {
144		*bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12;
145		*sr = ccsr_read4(OCP85XX_LAWSR_85XX(n));
146	}
147}
148
149static int
150law_find_free(void)
151{
152	uint32_t i,sr;
153	uint64_t bar;
154	int law_max;
155
156	law_max = law_getmax();
157	/* Find free LAW */
158	for (i = 0; i < law_max; i++) {
159		law_read(i, &bar, &sr);
160		if ((sr & 0x80000000) == 0)
161			break;
162	}
163
164	return (i);
165}
166
167#define	_LAW_SR(trgt,size)	(0x80000000 | (trgt << 20) | \
168				(flsl(size + (size - 1)) - 2))
169
170int
171law_enable(int trgt, uint64_t bar, uint32_t size)
172{
173	uint64_t bar_tmp;
174	uint32_t sr, sr_tmp;
175	int i, law_max;
176
177	if (size == 0)
178		return (0);
179
180	law_max = law_getmax();
181	sr = _LAW_SR(trgt, size);
182
183	/* Bail if already programmed. */
184	for (i = 0; i < law_max; i++) {
185		law_read(i, &bar_tmp, &sr_tmp);
186		if (sr == sr_tmp && bar == bar_tmp)
187			return (0);
188	}
189
190	/* Find an unused access window. */
191	i = law_find_free();
192
193	if (i == law_max)
194		return (ENOSPC);
195
196	law_write(i, bar, sr);
197	return (0);
198}
199
200int
201law_disable(int trgt, uint64_t bar, uint32_t size)
202{
203	uint64_t bar_tmp;
204	uint32_t sr, sr_tmp;
205	int i, law_max;
206
207	law_max = law_getmax();
208	sr = _LAW_SR(trgt, size);
209
210	/* Find and disable requested LAW. */
211	for (i = 0; i < law_max; i++) {
212		law_read(i, &bar_tmp, &sr_tmp);
213		if (sr == sr_tmp && bar == bar_tmp) {
214			law_write(i, 0, 0);
215			return (0);
216		}
217	}
218
219	return (ENOENT);
220}
221
222int
223law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
224{
225	u_long start;
226	uint32_t ver;
227	int trgt, rv;
228
229	ver = SVR_VER(mfspr(SPR_SVR));
230
231	start = rman_get_start(res) & 0xf000;
232
233	rv = 0;
234	trgt = -1;
235	switch (start) {
236	case 0x0000:
237	case 0x8000:
238		trgt = 0;
239		break;
240	case 0x1000:
241	case 0x9000:
242		trgt = 1;
243		break;
244	case 0x2000:
245	case 0xa000:
246		if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
247			trgt = 3;
248		else
249			trgt = 2;
250		break;
251	case 0x3000:
252	case 0xb000:
253		if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
254			rv = EINVAL;
255		else
256			trgt = 3;
257		break;
258	default:
259		rv = ENXIO;
260	}
261	if (rv == 0) {
262		*trgt_mem = trgt;
263		*trgt_io = trgt;
264	}
265	return (rv);
266}
267
268static void
269l3cache_inval(void)
270{
271
272	/* Flash invalidate the CPC and clear all the locks */
273	ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI |
274	    OCP85XX_CPC_CSR0_LFC);
275	while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI |
276	    OCP85XX_CPC_CSR0_LFC))
277		;
278}
279
280static void
281l3cache_enable(void)
282{
283
284	ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE |
285	    OCP85XX_CPC_CSR0_PE);
286	/* Read back to sync write */
287	ccsr_read4(OCP85XX_CPC_CSR0);
288}
289
290void
291mpc85xx_enable_l3_cache(void)
292{
293	uint32_t csr, size, ver;
294
295	/* Enable L3 CoreNet Platform Cache (CPC) */
296	ver = SVR_VER(mfspr(SPR_SVR));
297	if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 ||
298	    ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) {
299		csr = ccsr_read4(OCP85XX_CPC_CSR0);
300		if ((csr & OCP85XX_CPC_CSR0_CE) == 0) {
301			l3cache_inval();
302			l3cache_enable();
303		}
304
305		csr = ccsr_read4(OCP85XX_CPC_CSR0);
306		if ((boothowto & RB_VERBOSE) != 0 ||
307		    (csr & OCP85XX_CPC_CSR0_CE) == 0) {
308			size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0));
309			printf("L3 Corenet Platform Cache: %d KB %sabled\n",
310			    size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ?
311			    "dis" : "en");
312		}
313	}
314}
315
316int
317mpc85xx_is_qoriq(void)
318{
319	uint16_t pvr = mfpvr() >> 16;
320
321	/* QorIQ register set is only in e500mc and derivative core based SoCs. */
322	if (pvr == FSL_E500mc || pvr == FSL_E5500 || pvr == FSL_E6500)
323		return (1);
324
325	return (0);
326}
327
328static void
329mpc85xx_dataloss_erratum_spr976(void)
330{
331	uint32_t svr = SVR_VER(mfspr(SPR_SVR));
332
333	/* Ignore whether it's the E variant */
334	svr &= ~0x8;
335
336	if (svr != SVR_P3041 && svr != SVR_P4040 &&
337	    svr != SVR_P4080 && svr != SVR_P5020)
338		return;
339
340	mb();
341	isync();
342	mtspr(976, (mfspr(976) & ~0x1f8) | 0x48);
343	isync();
344}
345
346static vm_offset_t
347mpc85xx_map_dcsr(void)
348{
349	phandle_t node;
350	u_long b, s;
351	int err;
352
353	/*
354	 * Try to access the dcsr node directly i.e. through /aliases/.
355	 */
356	if ((node = OF_finddevice("dcsr")) != -1)
357		if (fdt_is_compatible_strict(node, "fsl,dcsr"))
358			goto moveon;
359	/*
360	 * Find the node the long way.
361	 */
362	if ((node = OF_finddevice("/")) == -1)
363		return (ENXIO);
364
365	if ((node = ofw_bus_find_compatible(node, "fsl,dcsr")) == 0)
366		return (ENXIO);
367
368moveon:
369	err = fdt_get_range(node, 0, &b, &s);
370
371	if (err != 0)
372		return (err);
373
374	law_enable(OCP85XX_TGTIF_DCSR, b, 0x400000);
375	return pmap_early_io_map(b, 0x400000);
376}
377
378
379
380void
381mpc85xx_fix_errata(vm_offset_t va_ccsr)
382{
383	uint32_t svr = SVR_VER(mfspr(SPR_SVR));
384	vm_offset_t va_dcsr;
385
386	/* Ignore whether it's the E variant */
387	svr &= ~0x8;
388
389	if (svr != SVR_P3041 && svr != SVR_P4040 &&
390	    svr != SVR_P4080 && svr != SVR_P5020)
391		return;
392
393	if (mfmsr() & PSL_EE)
394		return;
395
396	/*
397	 * dcsr region need to be mapped thus patch can refer to.
398	 * Align dcsr right after ccsbar.
399	 */
400	va_dcsr = mpc85xx_map_dcsr();
401	if (va_dcsr == 0)
402		goto err;
403
404	/*
405	 * As A004510 errata specify, special purpose register 976
406	 * SPR976[56:60] = 6'b001001 must be set. e500mc core reference manual
407	 * does not document SPR976 register.
408	 */
409	mpc85xx_dataloss_erratum_spr976();
410
411	/*
412	 * Specific settings in the CCF and core platform cache (CPC)
413	 * are required to reconfigure the CoreNet coherency fabric.
414	 * The register settings that should be updated are described
415	 * in errata and relay on base address, offset and updated value.
416	 * Special conditions must be used to update these registers correctly.
417	 */
418	dataloss_erratum_access(va_dcsr + 0xb0e08, 0xe0201800);
419	dataloss_erratum_access(va_dcsr + 0xb0e18, 0xe0201800);
420	dataloss_erratum_access(va_dcsr + 0xb0e38, 0xe0400000);
421	dataloss_erratum_access(va_dcsr + 0xb0008, 0x00900000);
422	dataloss_erratum_access(va_dcsr + 0xb0e40, 0xe00a0000);
423
424	switch (svr) {
425	case SVR_P5020:
426		dataloss_erratum_access(va_ccsr + 0x18600, 0xc0000000);
427		break;
428	case SVR_P4040:
429	case SVR_P4080:
430		dataloss_erratum_access(va_ccsr + 0x18600, 0xff000000);
431		break;
432	case SVR_P3041:
433		dataloss_erratum_access(va_ccsr + 0x18600, 0xf0000000);
434	}
435	dataloss_erratum_access(va_ccsr + 0x10f00, 0x415e5000);
436	dataloss_erratum_access(va_ccsr + 0x11f00, 0x415e5000);
437
438err:
439	return;
440}
441