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/platform_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-2012 Semihalf.
    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  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include "opt_platform.h"
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/11.0/sys/powerpc/mpc85xx/platform_mpc85xx.c 298237 2016-04-19 01:48:18Z jhibbits $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/bus.h>
   35 #include <sys/pcpu.h>
   36 #include <sys/proc.h>
   37 #include <sys/smp.h>
   38 
   39 #include <machine/bus.h>
   40 #include <machine/cpu.h>
   41 #include <machine/hid.h>
   42 #include <machine/machdep.h>
   43 #include <machine/platform.h>
   44 #include <machine/platformvar.h>
   45 #include <machine/smp.h>
   46 #include <machine/spr.h>
   47 #include <machine/vmparam.h>
   48 
   49 #include <dev/fdt/fdt_common.h>
   50 #include <dev/ofw/ofw_bus.h>
   51 #include <dev/ofw/ofw_bus_subr.h>
   52 #include <dev/ofw/openfirm.h>
   53 
   54 #include <vm/vm.h>
   55 #include <vm/pmap.h>
   56 
   57 #include <powerpc/mpc85xx/mpc85xx.h>
   58 
   59 #include "platform_if.h"
   60 
   61 #ifdef SMP
   62 extern void *ap_pcpu;
   63 extern vm_paddr_t kernload;             /* Kernel physical load address */
   64 extern uint8_t __boot_page[];           /* Boot page body */
   65 extern uint32_t bp_kernload;
   66 #endif
   67 
   68 extern uint32_t *bootinfo;
   69 vm_offset_t ccsrbar_va;
   70 
   71 static int cpu, maxcpu;
   72 
   73 static int mpc85xx_probe(platform_t);
   74 static void mpc85xx_mem_regions(platform_t, struct mem_region *phys,
   75     int *physsz, struct mem_region *avail, int *availsz);
   76 static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref);
   77 static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref);
   78 static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref);
   79 static int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref);
   80 static int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu);
   81 static void mpc85xx_idle(platform_t, int cpu);
   82 static int mpc85xx_idle_wakeup(platform_t plat, int cpu);
   83 
   84 static void mpc85xx_reset(platform_t);
   85 
   86 static platform_method_t mpc85xx_methods[] = {
   87         PLATFORMMETHOD(platform_probe,          mpc85xx_probe),
   88         PLATFORMMETHOD(platform_attach,         mpc85xx_attach),
   89         PLATFORMMETHOD(platform_mem_regions,    mpc85xx_mem_regions),
   90         PLATFORMMETHOD(platform_timebase_freq,  mpc85xx_timebase_freq),
   91 
   92         PLATFORMMETHOD(platform_smp_first_cpu,  mpc85xx_smp_first_cpu),
   93         PLATFORMMETHOD(platform_smp_next_cpu,   mpc85xx_smp_next_cpu),
   94         PLATFORMMETHOD(platform_smp_get_bsp,    mpc85xx_smp_get_bsp),
   95         PLATFORMMETHOD(platform_smp_start_cpu,  mpc85xx_smp_start_cpu),
   96 
   97         PLATFORMMETHOD(platform_reset,          mpc85xx_reset),
   98         PLATFORMMETHOD(platform_idle,           mpc85xx_idle),
   99         PLATFORMMETHOD(platform_idle_wakeup,    mpc85xx_idle_wakeup),
  100 
  101         PLATFORMMETHOD_END
  102 };
  103 
  104 DEFINE_CLASS_0(mpc85xx, mpc85xx_platform, mpc85xx_methods, 0);
  105 
  106 PLATFORM_DEF(mpc85xx_platform);
  107 
  108 static int
  109 mpc85xx_probe(platform_t plat)
  110 {
  111         u_int pvr = mfpvr() >> 16;
  112 
  113         if ((pvr & 0xfff0) == FSL_E500v1)
  114                 return (BUS_PROBE_DEFAULT);
  115 
  116         return (ENXIO);
  117 }
  118 
  119 int
  120 mpc85xx_attach(platform_t plat)
  121 {
  122         phandle_t cpus, child, ccsr;
  123         const char *soc_name_guesses[] = {"/soc", "soc", NULL};
  124         const char **name;
  125         pcell_t ranges[6], acells, pacells, scells;
  126         uint32_t sr;
  127         uint64_t ccsrbar, ccsrsize;
  128         int i, law_max, tgt;
  129 
  130         if ((cpus = OF_finddevice("/cpus")) != -1) {
  131                 for (maxcpu = 0, child = OF_child(cpus); child != 0;
  132                     child = OF_peer(child), maxcpu++)
  133                         ;
  134         } else
  135                 maxcpu = 1;
  136 
  137         /*
  138          * Locate CCSR region. Irritatingly, there is no way to find it
  139          * unless you already know where it is. Try to infer its location
  140          * from the device tree.
  141          */
  142 
  143         ccsr = -1;
  144         for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++)
  145                 ccsr = OF_finddevice(*name);
  146         if (ccsr == -1) {
  147                 char type[64];
  148 
  149                 /* That didn't work. Search for devices of type "soc" */
  150                 child = OF_child(OF_peer(0));
  151                 for (OF_child(child); child != 0; child = OF_peer(child)) {
  152                         if (OF_getprop(child, "device_type", type, sizeof(type))
  153                             <= 0)
  154                                 continue;
  155 
  156                         if (strcmp(type, "soc") == 0) {
  157                                 ccsr = child;
  158                                 break;
  159                         }
  160                 }
  161         }
  162 
  163         if (ccsr == -1)
  164                 panic("Could not locate CCSR window!");
  165 
  166         OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells));
  167         OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells));
  168         OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells,
  169             sizeof(pacells));
  170         OF_getprop(ccsr, "ranges", ranges, sizeof(ranges));
  171         ccsrbar = ccsrsize = 0;
  172         for (i = acells; i < acells + pacells; i++) {
  173                 ccsrbar <<= 32;
  174                 ccsrbar |= ranges[i];
  175         }
  176         for (i = acells + pacells; i < acells + pacells + scells; i++) {
  177                 ccsrsize <<= 32;
  178                 ccsrsize |= ranges[i];
  179         }
  180         ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize);
  181 
  182         mpc85xx_fix_errata(ccsrbar_va);
  183         mpc85xx_enable_l3_cache();
  184 
  185         /*
  186          * Clear local access windows. Skip DRAM entries, so we don't shoot
  187          * ourselves in the foot.
  188          */
  189         law_max = law_getmax();
  190         for (i = 0; i < law_max; i++) {
  191                 sr = ccsr_read4(OCP85XX_LAWSR(i));
  192                 if ((sr & OCP85XX_ENA_MASK) == 0)
  193                         continue;
  194                 tgt = (sr & 0x01f00000) >> 20;
  195                 if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 ||
  196                     tgt == OCP85XX_TGTIF_RAM_INTL)
  197                         continue;
  198 
  199                 ccsr_write4(OCP85XX_LAWSR(i), sr & OCP85XX_DIS_MASK);
  200         }
  201 
  202         return (0);
  203 }
  204 
  205 void
  206 mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
  207     struct mem_region *avail, int *availsz)
  208 {
  209 
  210         ofw_mem_regions(phys, physsz, avail, availsz);
  211 }
  212 
  213 static u_long
  214 mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref)
  215 {
  216         u_long ticks;
  217         phandle_t cpus, child;
  218         pcell_t freq;
  219 
  220         if (bootinfo != NULL) {
  221                 if (bootinfo[0] == 1) {
  222                         /* Backward compatibility. See 8-STABLE. */
  223                         ticks = bootinfo[3] >> 3;
  224                 } else {
  225                         /* Compatibility with Juniper's loader. */
  226                         ticks = bootinfo[5] >> 3;
  227                 }
  228         } else
  229                 ticks = 0;
  230 
  231         if ((cpus = OF_finddevice("/cpus")) == -1)
  232                 goto out;
  233 
  234         if ((child = OF_child(cpus)) == 0)
  235                 goto out;
  236 
  237         switch (OF_getproplen(child, "timebase-frequency")) {
  238         case 4:
  239         {
  240                 uint32_t tbase;
  241                 OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
  242                 ticks = tbase;
  243                 return (ticks);
  244         }
  245         case 8:
  246         {
  247                 uint64_t tbase;
  248                 OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
  249                 ticks = tbase;
  250                 return (ticks);
  251         }
  252         default:
  253                 break;
  254         }
  255 
  256         freq = 0;
  257         if (OF_getprop(child, "bus-frequency", (void *)&freq,
  258             sizeof(freq)) <= 0)
  259                 goto out;
  260 
  261         /*
  262          * Time Base and Decrementer are updated every 8 CCB bus clocks.
  263          * HID0[SEL_TBCLK] = 0
  264          */
  265         if (freq != 0)
  266 #ifdef QORIQ_DPAA
  267                 ticks = freq / 32;
  268 #else
  269                 ticks = freq / 8;
  270 #endif
  271 
  272 out:
  273         if (ticks <= 0)
  274                 panic("Unable to determine timebase frequency!");
  275 
  276         return (ticks);
  277 }
  278 
  279 static int
  280 mpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
  281 {
  282 
  283         cpu = 0;
  284         cpuref->cr_cpuid = cpu;
  285         cpuref->cr_hwref = cpuref->cr_cpuid;
  286         if (bootverbose)
  287                 printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid);
  288         cpu++;
  289 
  290         return (0);
  291 }
  292 
  293 static int
  294 mpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
  295 {
  296 
  297         if (cpu >= maxcpu)
  298                 return (ENOENT);
  299 
  300         cpuref->cr_cpuid = cpu++;
  301         cpuref->cr_hwref = cpuref->cr_cpuid;
  302         if (bootverbose)
  303                 printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid);
  304 
  305         return (0);
  306 }
  307 
  308 static int
  309 mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
  310 {
  311 
  312         cpuref->cr_cpuid = mfspr(SPR_PIR);
  313         cpuref->cr_hwref = cpuref->cr_cpuid;
  314 
  315         return (0);
  316 }
  317 
  318 static int
  319 mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
  320 {
  321 #ifdef SMP
  322         vm_paddr_t bptr;
  323         uint32_t reg;
  324         int timeout;
  325         uintptr_t brr;
  326         int cpuid;
  327 
  328 #ifdef QORIQ_DPAA
  329         uint32_t tgt;
  330 
  331         reg = ccsr_read4(OCP85XX_COREDISR);
  332         cpuid = pc->pc_cpuid;
  333 
  334         if ((reg & cpuid) != 0) {
  335                 printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid);
  336                 return (-1);
  337         }
  338 
  339         brr = OCP85XX_BRR;
  340 #else /* QORIQ_DPAA */
  341         brr = OCP85XX_EEBPCR;
  342         cpuid = pc->pc_cpuid + 24;
  343 #endif
  344         bp_kernload = kernload;
  345         reg = ccsr_read4(brr);
  346         if ((reg & (1 << cpuid)) != 0) {
  347                 printf("SMP: CPU %d already out of hold-off state!\n",
  348                     pc->pc_cpuid);
  349                 return (ENXIO);
  350         }
  351 
  352         ap_pcpu = pc;
  353         __asm __volatile("msync; isync");
  354 
  355         /* Flush caches to have our changes hit DRAM. */
  356         cpu_flush_dcache(__boot_page, 4096);
  357 
  358         bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload;
  359         KASSERT((bptr & 0xfff) == 0,
  360             ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr));
  361 #ifdef QORIQ_DPAA
  362 
  363         /*
  364          * Read DDR controller configuration to select proper BPTR target ID.
  365          *
  366          * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers
  367          * interleaving. If this bit is set, we have to use
  368          * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs,
  369          * this bit is reserved and always 0.
  370          */
  371 
  372         reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG);
  373         if (reg & (1 << 29))
  374                 tgt = OCP85XX_TGTIF_RAM_INTL;
  375         else
  376                 tgt = OCP85XX_TGTIF_RAM1;
  377 
  378         /*
  379          * Set BSTR to the physical address of the boot page
  380          */
  381         ccsr_write4(OCP85XX_BSTRH, bptr >> 32);
  382         ccsr_write4(OCP85XX_BSTRL, bptr);
  383         ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK |
  384             (tgt << OCP85XX_TRGT_SHIFT) | (ffsl(PAGE_SIZE) - 2));
  385 
  386         /* Read back OCP85XX_BSTAR to synchronize write */
  387         ccsr_read4(OCP85XX_BSTAR);
  388 
  389         /*
  390          * Enable and configure time base on new CPU.
  391          */
  392 
  393         /* Set TB clock source to platform clock / 32 */
  394         reg = ccsr_read4(CCSR_CTBCKSELR);
  395         ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid));
  396 
  397         /* Enable TB */
  398         reg = ccsr_read4(CCSR_CTBENR);
  399         ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid));
  400 #else
  401 
  402         /*
  403          * Set BPTR to the physical address of the boot page
  404          */
  405         bptr = (bptr >> 12) | 0x80000000u;
  406         ccsr_write4(OCP85XX_BPTR, bptr);
  407         __asm __volatile("isync; msync");
  408 
  409 #endif /* QORIQ_DPAA */
  410 
  411         /*
  412          * Release AP from hold-off state
  413          */
  414         reg = ccsr_read4(brr);
  415         ccsr_write4(brr, reg | (1 << cpuid));
  416         __asm __volatile("isync; msync");
  417 
  418         timeout = 500;
  419         while (!pc->pc_awake && timeout--)
  420                 DELAY(1000);    /* wait 1ms */
  421 
  422         /*
  423          * Disable boot page translation so that the 4K page at the default
  424          * address (= 0xfffff000) isn't permanently remapped and thus not
  425          * usable otherwise.
  426          */
  427 #ifdef QORIQ_DPAA
  428         ccsr_write4(OCP85XX_BSTAR, 0);
  429 #else
  430         ccsr_write4(OCP85XX_BPTR, 0);
  431 #endif
  432         __asm __volatile("isync; msync");
  433 
  434         if (!pc->pc_awake)
  435                 printf("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid);
  436         return ((pc->pc_awake) ? 0 : EBUSY);
  437 #else
  438         /* No SMP support */
  439         return (ENXIO);
  440 #endif
  441 }
  442 
  443 static void
  444 mpc85xx_reset(platform_t plat)
  445 {
  446 
  447         /*
  448          * Try the dedicated reset register first.
  449          * If the SoC doesn't have one, we'll fall
  450          * back to using the debug control register.
  451          */
  452         ccsr_write4(OCP85XX_RSTCR, 2);
  453 
  454         /* Clear DBCR0, disables debug interrupts and events. */
  455         mtspr(SPR_DBCR0, 0);
  456         __asm __volatile("isync");
  457 
  458         /* Enable Debug Interrupts in MSR. */
  459         mtmsr(mfmsr() | PSL_DE);
  460 
  461         /* Enable debug interrupts and issue reset. */
  462         mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM);
  463 
  464         printf("Reset failed...\n");
  465         while (1)
  466                 ;
  467 }
  468 
  469 static void
  470 mpc85xx_idle(platform_t plat, int cpu)
  471 {
  472 #ifdef QORIQ_DPAA
  473         uint32_t reg;
  474 
  475         reg = ccsr_read4(OCP85XX_RCPM_CDOZCR);
  476         ccsr_write4(OCP85XX_RCPM_CDOZCR, reg | (1 << cpu));
  477         ccsr_read4(OCP85XX_RCPM_CDOZCR);
  478 #else
  479         register_t msr;
  480 
  481         msr = mfmsr();
  482         /* Freescale E500 core RM section 6.4.1. */
  483         __asm __volatile("msync; mtmsr %0; isync" ::
  484             "r" (msr | PSL_WE));
  485 #endif
  486 }
  487 
  488 static int
  489 mpc85xx_idle_wakeup(platform_t plat, int cpu)
  490 {
  491 #ifdef QORIQ_DPAA
  492         uint32_t reg;
  493 
  494         reg = ccsr_read4(OCP85XX_RCPM_CDOZCR);
  495         ccsr_write4(OCP85XX_RCPM_CDOZCR, reg & ~(1 << cpu));
  496         ccsr_read4(OCP85XX_RCPM_CDOZCR);
  497 
  498         return (1);
  499 #endif
  500         return (0);
  501 }

Cache object: 8a6f991b755c538114ca38eed559f7e8


[ 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.