The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/mpc85xx/mpc85xx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/11.0/sys/powerpc/mpc85xx/mpc85xx.c 295908 2016-02-23 02:28:19Z jhibbits $");
   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                 law_max = 32;
  100                 break;
  101         default:
  102                 law_max = 8;
  103         }
  104 
  105         return (law_max);
  106 }
  107 
  108 static inline void
  109 law_write(uint32_t n, uint64_t bar, uint32_t sr)
  110 {
  111 #if defined(QORIQ_DPAA)
  112         ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32);
  113         ccsr_write4(OCP85XX_LAWBARL(n), bar);
  114 #else
  115         ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12);
  116 #endif
  117         ccsr_write4(OCP85XX_LAWSR(n), sr);
  118 
  119         /*
  120          * The last write to LAWAR should be followed by a read
  121          * of LAWAR before any device try to use any of windows.
  122          * What more the read of LAWAR should be followed by isync
  123          * instruction.
  124          */
  125 
  126         ccsr_read4(OCP85XX_LAWSR(n));
  127         isync();
  128 }
  129 
  130 static inline void
  131 law_read(uint32_t n, uint64_t *bar, uint32_t *sr)
  132 {
  133 #if defined(QORIQ_DPAA)
  134         *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 |
  135             ccsr_read4(OCP85XX_LAWBARL(n));
  136 #else
  137         *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12;
  138 #endif
  139         *sr = ccsr_read4(OCP85XX_LAWSR(n));
  140 }
  141 
  142 static int
  143 law_find_free(void)
  144 {
  145         uint32_t i,sr;
  146         uint64_t bar;
  147         int law_max;
  148 
  149         law_max = law_getmax();
  150         /* Find free LAW */
  151         for (i = 0; i < law_max; i++) {
  152                 law_read(i, &bar, &sr);
  153                 if ((sr & 0x80000000) == 0)
  154                         break;
  155         }
  156 
  157         return (i);
  158 }
  159 
  160 #define _LAW_SR(trgt,size)      (0x80000000 | (trgt << 20) | \
  161                                 (flsl(size + (size - 1)) - 2))
  162 
  163 int
  164 law_enable(int trgt, uint64_t bar, uint32_t size)
  165 {
  166         uint64_t bar_tmp;
  167         uint32_t sr, sr_tmp;
  168         int i, law_max;
  169 
  170         if (size == 0)
  171                 return (0);
  172 
  173         law_max = law_getmax();
  174         sr = _LAW_SR(trgt, size);
  175 
  176         /* Bail if already programmed. */
  177         for (i = 0; i < law_max; i++) {
  178                 law_read(i, &bar_tmp, &sr_tmp);
  179                 if (sr == sr_tmp && bar == bar_tmp)
  180                         return (0);
  181         }
  182 
  183         /* Find an unused access window. */
  184         i = law_find_free();
  185 
  186         if (i == law_max)
  187                 return (ENOSPC);
  188 
  189         law_write(i, bar, sr);
  190         return (0);
  191 }
  192 
  193 int
  194 law_disable(int trgt, uint64_t bar, uint32_t size)
  195 {
  196         uint64_t bar_tmp;
  197         uint32_t sr, sr_tmp;
  198         int i, law_max;
  199 
  200         law_max = law_getmax();
  201         sr = _LAW_SR(trgt, size);
  202 
  203         /* Find and disable requested LAW. */
  204         for (i = 0; i < law_max; i++) {
  205                 law_read(i, &bar_tmp, &sr_tmp);
  206                 if (sr == sr_tmp && bar == bar_tmp) {
  207                         law_write(i, 0, 0);
  208                         return (0);
  209                 }
  210         }
  211 
  212         return (ENOENT);
  213 }
  214 
  215 int
  216 law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
  217 {
  218         u_long start;
  219         uint32_t ver;
  220         int trgt, rv;
  221 
  222         ver = SVR_VER(mfspr(SPR_SVR));
  223 
  224         start = rman_get_start(res) & 0xf000;
  225 
  226         rv = 0;
  227         trgt = -1;
  228         switch (start) {
  229         case 0x0000:
  230         case 0x8000:
  231                 trgt = 0;
  232                 break;
  233         case 0x1000:
  234         case 0x9000:
  235                 trgt = 1;
  236                 break;
  237         case 0x2000:
  238         case 0xa000:
  239                 if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
  240                         trgt = 3;
  241                 else
  242                         trgt = 2;
  243                 break;
  244         case 0x3000:
  245         case 0xb000:
  246                 if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
  247                         rv = EINVAL;
  248                 else
  249                         trgt = 3;
  250                 break;
  251         default:
  252                 rv = ENXIO;
  253         }
  254         if (rv == 0) {
  255                 *trgt_mem = trgt;
  256                 *trgt_io = trgt;
  257         }
  258         return (rv);
  259 }
  260 
  261 static void
  262 l3cache_inval(void)
  263 {
  264 
  265         /* Flash invalidate the CPC and clear all the locks */
  266         ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI |
  267             OCP85XX_CPC_CSR0_LFC);
  268         while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI |
  269             OCP85XX_CPC_CSR0_LFC))
  270                 ;
  271 }
  272 
  273 static void
  274 l3cache_enable(void)
  275 {
  276 
  277         ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE |
  278             OCP85XX_CPC_CSR0_PE);
  279         /* Read back to sync write */
  280         ccsr_read4(OCP85XX_CPC_CSR0);
  281 }
  282 
  283 void
  284 mpc85xx_enable_l3_cache(void)
  285 {
  286         uint32_t csr, size, ver;
  287 
  288         /* Enable L3 CoreNet Platform Cache (CPC) */
  289         ver = SVR_VER(mfspr(SPR_SVR));
  290         if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 ||
  291             ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) {
  292                 csr = ccsr_read4(OCP85XX_CPC_CSR0);
  293                 if ((csr & OCP85XX_CPC_CSR0_CE) == 0) {
  294                         l3cache_inval();
  295                         l3cache_enable();
  296                 }
  297 
  298                 csr = ccsr_read4(OCP85XX_CPC_CSR0);
  299                 if ((boothowto & RB_VERBOSE) != 0 ||
  300                     (csr & OCP85XX_CPC_CSR0_CE) == 0) {
  301                         size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0));
  302                         printf("L3 Corenet Platform Cache: %d KB %sabled\n",
  303                             size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ?
  304                             "dis" : "en");
  305                 }
  306         }
  307 }
  308 
  309 static void
  310 mpc85xx_dataloss_erratum_spr976(void)
  311 {
  312         uint32_t svr = SVR_VER(mfspr(SPR_SVR));
  313 
  314         /* Ignore whether it's the E variant */
  315         svr &= ~0x8;
  316 
  317         if (svr != SVR_P3041 && svr != SVR_P4040 &&
  318             svr != SVR_P4080 && svr != SVR_P5020)
  319                 return;
  320 
  321         mb();
  322         isync();
  323         mtspr(976, (mfspr(976) & ~0x1f8) | 0x48);
  324         isync();
  325 }
  326 
  327 static vm_offset_t
  328 mpc85xx_map_dcsr(void)
  329 {
  330         phandle_t node;
  331         u_long b, s;
  332         int err;
  333 
  334         /*
  335          * Try to access the dcsr node directly i.e. through /aliases/.
  336          */
  337         if ((node = OF_finddevice("dcsr")) != -1)
  338                 if (fdt_is_compatible_strict(node, "fsl,dcsr"))
  339                         goto moveon;
  340         /*
  341          * Find the node the long way.
  342          */
  343         if ((node = OF_finddevice("/")) == -1)
  344                 return (ENXIO);
  345 
  346         if ((node = ofw_bus_find_compatible(node, "fsl,dcsr")) == 0)
  347                 return (ENXIO);
  348 
  349 moveon:
  350         err = fdt_get_range(node, 0, &b, &s);
  351 
  352         if (err != 0)
  353                 return (err);
  354 
  355 #ifdef QORIQ_DPAA
  356         law_enable(OCP85XX_TGTIF_DCSR, b, 0x400000);
  357 #endif
  358         return pmap_early_io_map(b, 0x400000);
  359 }
  360 
  361 
  362 
  363 void
  364 mpc85xx_fix_errata(vm_offset_t va_ccsr)
  365 {
  366         uint32_t svr = SVR_VER(mfspr(SPR_SVR));
  367         vm_offset_t va_dcsr;
  368 
  369         /* Ignore whether it's the E variant */
  370         svr &= ~0x8;
  371 
  372         if (svr != SVR_P3041 && svr != SVR_P4040 &&
  373             svr != SVR_P4080 && svr != SVR_P5020)
  374                 return;
  375 
  376         if (mfmsr() & PSL_EE)
  377                 return;
  378 
  379         /*
  380          * dcsr region need to be mapped thus patch can refer to.
  381          * Align dcsr right after ccsbar.
  382          */
  383         va_dcsr = mpc85xx_map_dcsr();
  384         if (va_dcsr == 0)
  385                 goto err;
  386 
  387         /*
  388          * As A004510 errata specify, special purpose register 976
  389          * SPR976[56:60] = 6'b001001 must be set. e500mc core reference manual
  390          * does not document SPR976 register.
  391          */
  392         mpc85xx_dataloss_erratum_spr976();
  393 
  394         /*
  395          * Specific settings in the CCF and core platform cache (CPC)
  396          * are required to reconfigure the CoreNet coherency fabric.
  397          * The register settings that should be updated are described
  398          * in errata and relay on base address, offset and updated value.
  399          * Special conditions must be used to update these registers correctly.
  400          */
  401         dataloss_erratum_access(va_dcsr + 0xb0e08, 0xe0201800);
  402         dataloss_erratum_access(va_dcsr + 0xb0e18, 0xe0201800);
  403         dataloss_erratum_access(va_dcsr + 0xb0e38, 0xe0400000);
  404         dataloss_erratum_access(va_dcsr + 0xb0008, 0x00900000);
  405         dataloss_erratum_access(va_dcsr + 0xb0e40, 0xe00a0000);
  406 
  407         switch (svr) {
  408         case SVR_P5020:
  409                 dataloss_erratum_access(va_ccsr + 0x18600, 0xc0000000);
  410                 break;
  411         case SVR_P4040:
  412         case SVR_P4080:
  413                 dataloss_erratum_access(va_ccsr + 0x18600, 0xff000000);
  414                 break;
  415         case SVR_P3041:
  416                 dataloss_erratum_access(va_ccsr + 0x18600, 0xf0000000);
  417         }
  418         dataloss_erratum_access(va_ccsr + 0x10f00, 0x415e5000);
  419         dataloss_erratum_access(va_ccsr + 0x11f00, 0x415e5000);
  420 
  421 err:
  422         return;
  423 }

Cache object: eb5418acf1e204abe90a99e98e746cee


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.