1a1cd472aSRafal Jaworowski /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
371e3c308SPedro F. Giffuni *
4a1cd472aSRafal Jaworowski * Copyright (C) 2008 Semihalf, Rafal Jaworowski
5a1cd472aSRafal Jaworowski * All rights reserved.
6a1cd472aSRafal Jaworowski *
7a1cd472aSRafal Jaworowski * Redistribution and use in source and binary forms, with or without
8a1cd472aSRafal Jaworowski * modification, are permitted provided that the following conditions
9a1cd472aSRafal Jaworowski * are met:
10a1cd472aSRafal Jaworowski * 1. Redistributions of source code must retain the above copyright
11a1cd472aSRafal Jaworowski * notice, this list of conditions and the following disclaimer.
12a1cd472aSRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright
13a1cd472aSRafal Jaworowski * notice, this list of conditions and the following disclaimer in the
14a1cd472aSRafal Jaworowski * documentation and/or other materials provided with the distribution.
15a1cd472aSRafal Jaworowski *
16a1cd472aSRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17a1cd472aSRafal Jaworowski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18a1cd472aSRafal Jaworowski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19a1cd472aSRafal Jaworowski * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20a1cd472aSRafal Jaworowski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21a1cd472aSRafal Jaworowski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22a1cd472aSRafal Jaworowski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23a1cd472aSRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24a1cd472aSRafal Jaworowski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25a1cd472aSRafal Jaworowski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26a1cd472aSRafal Jaworowski * SUCH DAMAGE.
27a1cd472aSRafal Jaworowski */
28a1cd472aSRafal Jaworowski
29a1cd472aSRafal Jaworowski #include <sys/cdefs.h>
305d89896cSJustin Hibbits #include "opt_platform.h"
31a1cd472aSRafal Jaworowski #include <sys/param.h>
32a1cd472aSRafal Jaworowski #include <sys/systm.h>
33d1d3233eSRafal Jaworowski #include <sys/lock.h>
34d1d3233eSRafal Jaworowski #include <sys/mutex.h>
353f068cbfSJustin Hibbits #include <sys/reboot.h>
36d1d3233eSRafal Jaworowski #include <sys/rman.h>
37a1cd472aSRafal Jaworowski
388b79898eSRafal Jaworowski #include <vm/vm.h>
398b79898eSRafal Jaworowski #include <vm/vm_param.h>
403f068cbfSJustin Hibbits #include <vm/pmap.h>
418b79898eSRafal Jaworowski
42a1cd472aSRafal Jaworowski #include <machine/cpu.h>
43a1cd472aSRafal Jaworowski #include <machine/cpufunc.h>
443f068cbfSJustin Hibbits #include <machine/machdep.h>
452a134f71SNathan Whitehorn #include <machine/pio.h>
46a1cd472aSRafal Jaworowski #include <machine/spr.h>
47a1cd472aSRafal Jaworowski
4833724f17SNathan Whitehorn #include <dev/fdt/fdt_common.h>
4933724f17SNathan Whitehorn
503f068cbfSJustin Hibbits #include <dev/fdt/fdt_common.h>
513f068cbfSJustin Hibbits #include <dev/ofw/ofw_bus.h>
523f068cbfSJustin Hibbits #include <dev/ofw/ofw_bus_subr.h>
533f068cbfSJustin Hibbits #include <dev/ofw/openfirm.h>
543f068cbfSJustin Hibbits
55fe48da3fSRafal Jaworowski #include <powerpc/mpc85xx/mpc85xx.h>
568b79898eSRafal Jaworowski
57a1cd472aSRafal Jaworowski /*
58a1cd472aSRafal Jaworowski * MPC85xx system specific routines
59a1cd472aSRafal Jaworowski */
60a1cd472aSRafal Jaworowski
61fe48da3fSRafal Jaworowski uint32_t
ccsr_read4(uintptr_t addr)62fe48da3fSRafal Jaworowski ccsr_read4(uintptr_t addr)
63a1cd472aSRafal Jaworowski {
64fe48da3fSRafal Jaworowski volatile uint32_t *ptr = (void *)addr;
65a1cd472aSRafal Jaworowski
66fe48da3fSRafal Jaworowski return (*ptr);
67fe48da3fSRafal Jaworowski }
68fe48da3fSRafal Jaworowski
69fe48da3fSRafal Jaworowski void
ccsr_write4(uintptr_t addr,uint32_t val)70fe48da3fSRafal Jaworowski ccsr_write4(uintptr_t addr, uint32_t val)
71fe48da3fSRafal Jaworowski {
72fe48da3fSRafal Jaworowski volatile uint32_t *ptr = (void *)addr;
73fe48da3fSRafal Jaworowski
74fe48da3fSRafal Jaworowski *ptr = val;
7513d47f30SNathan Whitehorn powerpc_iomb();
76fe48da3fSRafal Jaworowski }
77fe48da3fSRafal Jaworowski
78389e4721SRafal Jaworowski int
law_getmax(void)7925c22eb4SRafal Jaworowski law_getmax(void)
8025c22eb4SRafal Jaworowski {
8125c22eb4SRafal Jaworowski uint32_t ver;
825d89896cSJustin Hibbits int law_max;
8325c22eb4SRafal Jaworowski
8425c22eb4SRafal Jaworowski ver = SVR_VER(mfspr(SPR_SVR));
855d89896cSJustin Hibbits switch (ver) {
865d89896cSJustin Hibbits case SVR_MPC8555:
875d89896cSJustin Hibbits case SVR_MPC8555E:
885d89896cSJustin Hibbits law_max = 8;
895d89896cSJustin Hibbits break;
905d89896cSJustin Hibbits case SVR_MPC8533:
915d89896cSJustin Hibbits case SVR_MPC8533E:
925d89896cSJustin Hibbits case SVR_MPC8548:
935d89896cSJustin Hibbits case SVR_MPC8548E:
945d89896cSJustin Hibbits law_max = 10;
955d89896cSJustin Hibbits break;
965d89896cSJustin Hibbits case SVR_P5020:
975d89896cSJustin Hibbits case SVR_P5020E:
98c5fea8adSJustin Hibbits case SVR_P5021:
99c5fea8adSJustin Hibbits case SVR_P5021E:
100c5fea8adSJustin Hibbits case SVR_P5040:
101c5fea8adSJustin Hibbits case SVR_P5040E:
1025d89896cSJustin Hibbits law_max = 32;
1035d89896cSJustin Hibbits break;
1045d89896cSJustin Hibbits default:
1055d89896cSJustin Hibbits law_max = 8;
1065d89896cSJustin Hibbits }
1078a4b7c64SMarcel Moolenaar
1085d89896cSJustin Hibbits return (law_max);
1095d89896cSJustin Hibbits }
1105d89896cSJustin Hibbits
1115d89896cSJustin Hibbits static inline void
law_write(uint32_t n,uint64_t bar,uint32_t sr)1125d89896cSJustin Hibbits law_write(uint32_t n, uint64_t bar, uint32_t sr)
1135d89896cSJustin Hibbits {
1146cedae09SJustin Hibbits
1156cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) {
1165d89896cSJustin Hibbits ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32);
1175d89896cSJustin Hibbits ccsr_write4(OCP85XX_LAWBARL(n), bar);
1186cedae09SJustin Hibbits ccsr_write4(OCP85XX_LAWSR_QORIQ(n), sr);
1196cedae09SJustin Hibbits ccsr_read4(OCP85XX_LAWSR_QORIQ(n));
1206cedae09SJustin Hibbits } else {
1215d89896cSJustin Hibbits ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12);
1226cedae09SJustin Hibbits ccsr_write4(OCP85XX_LAWSR_85XX(n), sr);
1236cedae09SJustin Hibbits ccsr_read4(OCP85XX_LAWSR_85XX(n));
1246cedae09SJustin Hibbits }
1255d89896cSJustin Hibbits
1265d89896cSJustin Hibbits /*
1275d89896cSJustin Hibbits * The last write to LAWAR should be followed by a read
1285d89896cSJustin Hibbits * of LAWAR before any device try to use any of windows.
1295d89896cSJustin Hibbits * What more the read of LAWAR should be followed by isync
1305d89896cSJustin Hibbits * instruction.
1315d89896cSJustin Hibbits */
1325d89896cSJustin Hibbits
1335d89896cSJustin Hibbits isync();
1345d89896cSJustin Hibbits }
1355d89896cSJustin Hibbits
1365d89896cSJustin Hibbits static inline void
law_read(uint32_t n,uint64_t * bar,uint32_t * sr)1375d89896cSJustin Hibbits law_read(uint32_t n, uint64_t *bar, uint32_t *sr)
1385d89896cSJustin Hibbits {
1396cedae09SJustin Hibbits
1406cedae09SJustin Hibbits if (mpc85xx_is_qoriq()) {
1415d89896cSJustin Hibbits *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 |
1425d89896cSJustin Hibbits ccsr_read4(OCP85XX_LAWBARL(n));
1436cedae09SJustin Hibbits *sr = ccsr_read4(OCP85XX_LAWSR_QORIQ(n));
1446cedae09SJustin Hibbits } else {
1455d89896cSJustin Hibbits *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12;
1466cedae09SJustin Hibbits *sr = ccsr_read4(OCP85XX_LAWSR_85XX(n));
1476cedae09SJustin Hibbits }
1485d89896cSJustin Hibbits }
1495d89896cSJustin Hibbits
1505d89896cSJustin Hibbits static int
law_find_free(void)1515d89896cSJustin Hibbits law_find_free(void)
1525d89896cSJustin Hibbits {
1535d89896cSJustin Hibbits uint32_t i,sr;
1545d89896cSJustin Hibbits uint64_t bar;
1555d89896cSJustin Hibbits int law_max;
1565d89896cSJustin Hibbits
1575d89896cSJustin Hibbits law_max = law_getmax();
1585d89896cSJustin Hibbits /* Find free LAW */
1595d89896cSJustin Hibbits for (i = 0; i < law_max; i++) {
1605d89896cSJustin Hibbits law_read(i, &bar, &sr);
1615d89896cSJustin Hibbits if ((sr & 0x80000000) == 0)
1625d89896cSJustin Hibbits break;
1635d89896cSJustin Hibbits }
1645d89896cSJustin Hibbits
1655d89896cSJustin Hibbits return (i);
16625c22eb4SRafal Jaworowski }
16725c22eb4SRafal Jaworowski
1689ef05032SJustin Hibbits #define _LAW_SR(trgt,size) (0x80000000 | (trgt << 20) | \
1699ef05032SJustin Hibbits (flsl(size + (size - 1)) - 2))
17025c22eb4SRafal Jaworowski
17125c22eb4SRafal Jaworowski int
law_enable(int trgt,uint64_t bar,uint32_t size)1725d89896cSJustin Hibbits law_enable(int trgt, uint64_t bar, uint32_t size)
17325c22eb4SRafal Jaworowski {
1745d89896cSJustin Hibbits uint64_t bar_tmp;
1755d89896cSJustin Hibbits uint32_t sr, sr_tmp;
17625c22eb4SRafal Jaworowski int i, law_max;
17725c22eb4SRafal Jaworowski
178e845939dSMarcel Moolenaar if (size == 0)
179e845939dSMarcel Moolenaar return (0);
180e845939dSMarcel Moolenaar
18125c22eb4SRafal Jaworowski law_max = law_getmax();
18225c22eb4SRafal Jaworowski sr = _LAW_SR(trgt, size);
18325c22eb4SRafal Jaworowski
18425c22eb4SRafal Jaworowski /* Bail if already programmed. */
1855d89896cSJustin Hibbits for (i = 0; i < law_max; i++) {
1865d89896cSJustin Hibbits law_read(i, &bar_tmp, &sr_tmp);
1875d89896cSJustin Hibbits if (sr == sr_tmp && bar == bar_tmp)
18825c22eb4SRafal Jaworowski return (0);
1895d89896cSJustin Hibbits }
19025c22eb4SRafal Jaworowski
19125c22eb4SRafal Jaworowski /* Find an unused access window. */
1925d89896cSJustin Hibbits i = law_find_free();
19325c22eb4SRafal Jaworowski
19425c22eb4SRafal Jaworowski if (i == law_max)
19525c22eb4SRafal Jaworowski return (ENOSPC);
19625c22eb4SRafal Jaworowski
1975d89896cSJustin Hibbits law_write(i, bar, sr);
19825c22eb4SRafal Jaworowski return (0);
19925c22eb4SRafal Jaworowski }
20025c22eb4SRafal Jaworowski
20125c22eb4SRafal Jaworowski int
law_disable(int trgt,uint64_t bar,uint32_t size)2025d89896cSJustin Hibbits law_disable(int trgt, uint64_t bar, uint32_t size)
20325c22eb4SRafal Jaworowski {
2045d89896cSJustin Hibbits uint64_t bar_tmp;
2055d89896cSJustin Hibbits uint32_t sr, sr_tmp;
20625c22eb4SRafal Jaworowski int i, law_max;
20725c22eb4SRafal Jaworowski
20825c22eb4SRafal Jaworowski law_max = law_getmax();
20925c22eb4SRafal Jaworowski sr = _LAW_SR(trgt, size);
21025c22eb4SRafal Jaworowski
21125c22eb4SRafal Jaworowski /* Find and disable requested LAW. */
2125d89896cSJustin Hibbits for (i = 0; i < law_max; i++) {
2135d89896cSJustin Hibbits law_read(i, &bar_tmp, &sr_tmp);
2145d89896cSJustin Hibbits if (sr == sr_tmp && bar == bar_tmp) {
2155d89896cSJustin Hibbits law_write(i, 0, 0);
21625c22eb4SRafal Jaworowski return (0);
21725c22eb4SRafal Jaworowski }
2185d89896cSJustin Hibbits }
21925c22eb4SRafal Jaworowski
22025c22eb4SRafal Jaworowski return (ENOENT);
22125c22eb4SRafal Jaworowski }
22225c22eb4SRafal Jaworowski
223d1d3233eSRafal Jaworowski int
law_pci_target(struct resource * res,int * trgt_mem,int * trgt_io)224d1d3233eSRafal Jaworowski law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
225d1d3233eSRafal Jaworowski {
226d1d3233eSRafal Jaworowski u_long start;
227d1d3233eSRafal Jaworowski uint32_t ver;
228d1d3233eSRafal Jaworowski int trgt, rv;
229d1d3233eSRafal Jaworowski
230d1d3233eSRafal Jaworowski ver = SVR_VER(mfspr(SPR_SVR));
231d1d3233eSRafal Jaworowski
232d1d3233eSRafal Jaworowski start = rman_get_start(res) & 0xf000;
233d1d3233eSRafal Jaworowski
234d1d3233eSRafal Jaworowski rv = 0;
235d1d3233eSRafal Jaworowski trgt = -1;
236d1d3233eSRafal Jaworowski switch (start) {
2375d89896cSJustin Hibbits case 0x0000:
238d1d3233eSRafal Jaworowski case 0x8000:
239d1d3233eSRafal Jaworowski trgt = 0;
240d1d3233eSRafal Jaworowski break;
2415d89896cSJustin Hibbits case 0x1000:
242d1d3233eSRafal Jaworowski case 0x9000:
243d1d3233eSRafal Jaworowski trgt = 1;
244d1d3233eSRafal Jaworowski break;
2455d89896cSJustin Hibbits case 0x2000:
246d1d3233eSRafal Jaworowski case 0xa000:
2478a4b7c64SMarcel Moolenaar if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
2488a4b7c64SMarcel Moolenaar trgt = 3;
249d1d3233eSRafal Jaworowski else
2508a4b7c64SMarcel Moolenaar trgt = 2;
2518a4b7c64SMarcel Moolenaar break;
2525d89896cSJustin Hibbits case 0x3000:
2538a4b7c64SMarcel Moolenaar case 0xb000:
2548a4b7c64SMarcel Moolenaar if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
255d1d3233eSRafal Jaworowski rv = EINVAL;
2568a4b7c64SMarcel Moolenaar else
2578a4b7c64SMarcel Moolenaar trgt = 3;
258d1d3233eSRafal Jaworowski break;
259d1d3233eSRafal Jaworowski default:
260d1d3233eSRafal Jaworowski rv = ENXIO;
261d1d3233eSRafal Jaworowski }
262e845939dSMarcel Moolenaar if (rv == 0) {
263e845939dSMarcel Moolenaar *trgt_mem = trgt;
264e845939dSMarcel Moolenaar *trgt_io = trgt;
265e845939dSMarcel Moolenaar }
266d1d3233eSRafal Jaworowski return (rv);
267d1d3233eSRafal Jaworowski }
268d1d3233eSRafal Jaworowski
2693f068cbfSJustin Hibbits static void
l3cache_inval(void)2703f068cbfSJustin Hibbits l3cache_inval(void)
2713f068cbfSJustin Hibbits {
2723f068cbfSJustin Hibbits
2733f068cbfSJustin Hibbits /* Flash invalidate the CPC and clear all the locks */
2743f068cbfSJustin Hibbits ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI |
2753f068cbfSJustin Hibbits OCP85XX_CPC_CSR0_LFC);
2763f068cbfSJustin Hibbits while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI |
2773f068cbfSJustin Hibbits OCP85XX_CPC_CSR0_LFC))
2783f068cbfSJustin Hibbits ;
2793f068cbfSJustin Hibbits }
2803f068cbfSJustin Hibbits
2813f068cbfSJustin Hibbits static void
l3cache_enable(void)2823f068cbfSJustin Hibbits l3cache_enable(void)
2833f068cbfSJustin Hibbits {
2843f068cbfSJustin Hibbits
2853f068cbfSJustin Hibbits ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE |
2863f068cbfSJustin Hibbits OCP85XX_CPC_CSR0_PE);
2873f068cbfSJustin Hibbits /* Read back to sync write */
2883f068cbfSJustin Hibbits ccsr_read4(OCP85XX_CPC_CSR0);
2893f068cbfSJustin Hibbits }
2903f068cbfSJustin Hibbits
2913f068cbfSJustin Hibbits void
mpc85xx_enable_l3_cache(void)2923f068cbfSJustin Hibbits mpc85xx_enable_l3_cache(void)
2933f068cbfSJustin Hibbits {
2943f068cbfSJustin Hibbits uint32_t csr, size, ver;
2953f068cbfSJustin Hibbits
2963f068cbfSJustin Hibbits /* Enable L3 CoreNet Platform Cache (CPC) */
2973f068cbfSJustin Hibbits ver = SVR_VER(mfspr(SPR_SVR));
2983f068cbfSJustin Hibbits if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 ||
2993f068cbfSJustin Hibbits ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) {
3003f068cbfSJustin Hibbits csr = ccsr_read4(OCP85XX_CPC_CSR0);
3013f068cbfSJustin Hibbits if ((csr & OCP85XX_CPC_CSR0_CE) == 0) {
3023f068cbfSJustin Hibbits l3cache_inval();
3033f068cbfSJustin Hibbits l3cache_enable();
3043f068cbfSJustin Hibbits }
3053f068cbfSJustin Hibbits
3063f068cbfSJustin Hibbits csr = ccsr_read4(OCP85XX_CPC_CSR0);
3073f068cbfSJustin Hibbits if ((boothowto & RB_VERBOSE) != 0 ||
3083f068cbfSJustin Hibbits (csr & OCP85XX_CPC_CSR0_CE) == 0) {
3093f068cbfSJustin Hibbits size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0));
3103f068cbfSJustin Hibbits printf("L3 Corenet Platform Cache: %d KB %sabled\n",
3113f068cbfSJustin Hibbits size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ?
3123f068cbfSJustin Hibbits "dis" : "en");
3133f068cbfSJustin Hibbits }
3143f068cbfSJustin Hibbits }
3153f068cbfSJustin Hibbits }
3163f068cbfSJustin Hibbits
3176cedae09SJustin Hibbits int
mpc85xx_is_qoriq(void)3186cedae09SJustin Hibbits mpc85xx_is_qoriq(void)
3196cedae09SJustin Hibbits {
3206cedae09SJustin Hibbits uint16_t pvr = mfpvr() >> 16;
3216cedae09SJustin Hibbits
3226cedae09SJustin Hibbits /* QorIQ register set is only in e500mc and derivative core based SoCs. */
3236cedae09SJustin Hibbits if (pvr == FSL_E500mc || pvr == FSL_E5500 || pvr == FSL_E6500)
3246cedae09SJustin Hibbits return (1);
3256cedae09SJustin Hibbits
3266cedae09SJustin Hibbits return (0);
3276cedae09SJustin Hibbits }
3286cedae09SJustin Hibbits
329bba2d2bdSJustin Hibbits uint32_t
mpc85xx_get_platform_clock(void)33037ea599bSJustin Hibbits mpc85xx_get_platform_clock(void)
331bba2d2bdSJustin Hibbits {
332bba2d2bdSJustin Hibbits phandle_t soc;
33337ea599bSJustin Hibbits static uint32_t freq;
33437ea599bSJustin Hibbits
33537ea599bSJustin Hibbits if (freq != 0)
33637ea599bSJustin Hibbits return (freq);
337bba2d2bdSJustin Hibbits
338bba2d2bdSJustin Hibbits soc = OF_finddevice("/soc");
339bba2d2bdSJustin Hibbits
340bba2d2bdSJustin Hibbits /* freq isn't modified on error. */
341bba2d2bdSJustin Hibbits OF_getencprop(soc, "bus-frequency", (void *)&freq, sizeof(freq));
342bba2d2bdSJustin Hibbits
34337ea599bSJustin Hibbits return (freq);
34437ea599bSJustin Hibbits }
34537ea599bSJustin Hibbits
34637ea599bSJustin Hibbits uint32_t
mpc85xx_get_system_clock(void)34737ea599bSJustin Hibbits mpc85xx_get_system_clock(void)
34837ea599bSJustin Hibbits {
34937ea599bSJustin Hibbits uint32_t freq;
35037ea599bSJustin Hibbits
35137ea599bSJustin Hibbits freq = mpc85xx_get_platform_clock();
35237ea599bSJustin Hibbits
353bba2d2bdSJustin Hibbits return (freq / 2);
354bba2d2bdSJustin Hibbits }
355