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