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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2008-2012 Semihalf.
    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  *
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include "opt_platform.h"
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/module.h>
   37 #include <sys/bus.h>
   38 #include <sys/pcpu.h>
   39 #include <sys/proc.h>
   40 #include <sys/smp.h>
   41 
   42 #include <machine/bus.h>
   43 #include <machine/cpu.h>
   44 #include <machine/hid.h>
   45 #include <machine/_inttypes.h>
   46 #include <machine/machdep.h>
   47 #include <machine/md_var.h>
   48 #include <machine/platform.h>
   49 #include <machine/platformvar.h>
   50 #include <machine/smp.h>
   51 #include <machine/spr.h>
   52 #include <machine/vmparam.h>
   53 
   54 #include <dev/fdt/fdt_common.h>
   55 #include <dev/ofw/ofw_bus.h>
   56 #include <dev/ofw/ofw_bus_subr.h>
   57 #include <dev/ofw/openfirm.h>
   58 
   59 #include <vm/vm.h>
   60 #include <vm/pmap.h>
   61 #include <vm/vm_extern.h>
   62 
   63 #include <powerpc/mpc85xx/mpc85xx.h>
   64 
   65 #include "platform_if.h"
   66 
   67 #ifdef SMP
   68 extern void *ap_pcpu;
   69 extern vm_paddr_t kernload;             /* Kernel physical load address */
   70 extern uint8_t __boot_page[];           /* Boot page body */
   71 extern vm_paddr_t bp_kernload;          /* Boot page copy of kernload */
   72 extern vm_offset_t bp_virtaddr;         /* Virtual address of boot page */
   73 extern vm_offset_t __startkernel;
   74 
   75 struct cpu_release {
   76         uint32_t entry_h;
   77         uint32_t entry_l;
   78         uint32_t r3_h;
   79         uint32_t r3_l;
   80         uint32_t reserved;
   81         uint32_t pir;
   82 };
   83 #endif
   84 
   85 extern uint32_t *bootinfo;
   86 vm_paddr_t ccsrbar_pa;
   87 vm_offset_t ccsrbar_va;
   88 vm_size_t ccsrbar_size;
   89 
   90 static int cpu, maxcpu;
   91 
   92 static device_t rcpm_dev;
   93 static void dummy_freeze(device_t, bool);
   94 
   95 static void (*freeze_timebase)(device_t, bool) = dummy_freeze;
   96 
   97 static int mpc85xx_probe(platform_t);
   98 static void mpc85xx_mem_regions(platform_t, struct mem_region *phys,
   99     int *physsz, struct mem_region *avail, int *availsz);
  100 static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref);
  101 static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref);
  102 static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref);
  103 static int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref);
  104 static int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu);
  105 static void mpc85xx_smp_timebase_sync(platform_t, u_long tb, int ap);
  106 
  107 static void mpc85xx_reset(platform_t);
  108 
  109 static platform_method_t mpc85xx_methods[] = {
  110         PLATFORMMETHOD(platform_probe,          mpc85xx_probe),
  111         PLATFORMMETHOD(platform_attach,         mpc85xx_attach),
  112         PLATFORMMETHOD(platform_mem_regions,    mpc85xx_mem_regions),
  113         PLATFORMMETHOD(platform_timebase_freq,  mpc85xx_timebase_freq),
  114 
  115         PLATFORMMETHOD(platform_smp_first_cpu,  mpc85xx_smp_first_cpu),
  116         PLATFORMMETHOD(platform_smp_next_cpu,   mpc85xx_smp_next_cpu),
  117         PLATFORMMETHOD(platform_smp_get_bsp,    mpc85xx_smp_get_bsp),
  118         PLATFORMMETHOD(platform_smp_start_cpu,  mpc85xx_smp_start_cpu),
  119         PLATFORMMETHOD(platform_smp_timebase_sync, mpc85xx_smp_timebase_sync),
  120 
  121         PLATFORMMETHOD(platform_reset,          mpc85xx_reset),
  122 
  123         PLATFORMMETHOD_END
  124 };
  125 
  126 DEFINE_CLASS_0(mpc85xx, mpc85xx_platform, mpc85xx_methods, 0);
  127 
  128 PLATFORM_DEF(mpc85xx_platform);
  129 
  130 static int
  131 mpc85xx_probe(platform_t plat)
  132 {
  133         u_int pvr = (mfpvr() >> 16) & 0xFFFF;
  134 
  135         switch (pvr) {
  136                 case FSL_E500v1:
  137                 case FSL_E500v2:
  138                 case FSL_E500mc:
  139                 case FSL_E5500:
  140                 case FSL_E6500:
  141                         return (BUS_PROBE_DEFAULT);
  142         }
  143         return (ENXIO);
  144 }
  145 
  146 int
  147 mpc85xx_attach(platform_t plat)
  148 {
  149         phandle_t cpus, child, ccsr;
  150         const char *soc_name_guesses[] = {"/soc", "soc", NULL};
  151         const char **name;
  152         pcell_t ranges[6], acells, pacells, scells;
  153         uint64_t ccsrbar, ccsrsize;
  154         int i;
  155 
  156         if ((cpus = OF_finddevice("/cpus")) != -1) {
  157                 for (maxcpu = 0, child = OF_child(cpus); child != 0;
  158                     child = OF_peer(child), maxcpu++)
  159                         ;
  160         } else
  161                 maxcpu = 1;
  162 
  163         /*
  164          * Locate CCSR region. Irritatingly, there is no way to find it
  165          * unless you already know where it is. Try to infer its location
  166          * from the device tree.
  167          */
  168 
  169         ccsr = -1;
  170         for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++)
  171                 ccsr = OF_finddevice(*name);
  172         if (ccsr == -1) {
  173                 char type[64];
  174 
  175                 /* That didn't work. Search for devices of type "soc" */
  176                 child = OF_child(OF_peer(0));
  177                 for (OF_child(child); child != 0; child = OF_peer(child)) {
  178                         if (OF_getprop(child, "device_type", type, sizeof(type))
  179                             <= 0)
  180                                 continue;
  181 
  182                         if (strcmp(type, "soc") == 0) {
  183                                 ccsr = child;
  184                                 break;
  185                         }
  186                 }
  187         }
  188 
  189         if (ccsr == -1)
  190                 panic("Could not locate CCSR window!");
  191 
  192         OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells));
  193         OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells));
  194         OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells,
  195             sizeof(pacells));
  196         OF_getprop(ccsr, "ranges", ranges, sizeof(ranges));
  197         ccsrbar = ccsrsize = 0;
  198         for (i = acells; i < acells + pacells; i++) {
  199                 ccsrbar <<= 32;
  200                 ccsrbar |= ranges[i];
  201         }
  202         for (i = acells + pacells; i < acells + pacells + scells; i++) {
  203                 ccsrsize <<= 32;
  204                 ccsrsize |= ranges[i];
  205         }
  206         ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize);
  207         ccsrbar_pa = ccsrbar;
  208         ccsrbar_size = ccsrsize;
  209 
  210         mpc85xx_enable_l3_cache();
  211 
  212         return (0);
  213 }
  214 
  215 void
  216 mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
  217     struct mem_region *avail, int *availsz)
  218 {
  219 
  220         ofw_mem_regions(phys, physsz, avail, availsz);
  221 }
  222 
  223 static u_long
  224 mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref)
  225 {
  226         u_long ticks;
  227         phandle_t cpus, child;
  228         pcell_t freq;
  229 
  230         if (bootinfo != NULL) {
  231                 if (bootinfo[0] == 1) {
  232                         /* Backward compatibility. See 8-STABLE. */
  233                         ticks = bootinfo[3] >> 3;
  234                 } else {
  235                         /* Compatibility with Juniper's loader. */
  236                         ticks = bootinfo[5] >> 3;
  237                 }
  238         } else
  239                 ticks = 0;
  240 
  241         if ((cpus = OF_finddevice("/cpus")) == -1)
  242                 goto out;
  243 
  244         if ((child = OF_child(cpus)) == 0)
  245                 goto out;
  246 
  247         switch (OF_getproplen(child, "timebase-frequency")) {
  248         case 4:
  249         {
  250                 uint32_t tbase;
  251                 OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
  252                 ticks = tbase;
  253                 return (ticks);
  254         }
  255         case 8:
  256         {
  257                 uint64_t tbase;
  258                 OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
  259                 ticks = tbase;
  260                 return (ticks);
  261         }
  262         default:
  263                 break;
  264         }
  265 
  266         freq = 0;
  267         if (OF_getprop(child, "bus-frequency", (void *)&freq,
  268             sizeof(freq)) <= 0)
  269                 goto out;
  270 
  271         if (freq == 0)
  272                 goto out;
  273 
  274         /*
  275          * Time Base and Decrementer are updated every 8 CCB bus clocks.
  276          * HID0[SEL_TBCLK] = 0
  277          */
  278         if (mpc85xx_is_qoriq())
  279                 ticks = freq / 32;
  280         else
  281                 ticks = freq / 8;
  282 
  283 out:
  284         if (ticks <= 0)
  285                 panic("Unable to determine timebase frequency!");
  286 
  287         return (ticks);
  288 }
  289 
  290 static int
  291 mpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
  292 {
  293 
  294         cpu = 0;
  295         cpuref->cr_cpuid = cpu;
  296         cpuref->cr_hwref = cpuref->cr_cpuid;
  297         if (bootverbose)
  298                 printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid);
  299         cpu++;
  300 
  301         return (0);
  302 }
  303 
  304 static int
  305 mpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
  306 {
  307 
  308         if (cpu >= maxcpu)
  309                 return (ENOENT);
  310 
  311         cpuref->cr_cpuid = cpu++;
  312         cpuref->cr_hwref = cpuref->cr_cpuid;
  313         if (bootverbose)
  314                 printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid);
  315 
  316         return (0);
  317 }
  318 
  319 static int
  320 mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
  321 {
  322 
  323         cpuref->cr_cpuid = mfspr(SPR_PIR);
  324         cpuref->cr_hwref = cpuref->cr_cpuid;
  325 
  326         return (0);
  327 }
  328 
  329 #ifdef SMP
  330 static int
  331 mpc85xx_smp_start_cpu_epapr(platform_t plat, struct pcpu *pc)
  332 {
  333         vm_paddr_t rel_pa, bptr;
  334         volatile struct cpu_release *rel;
  335         vm_offset_t rel_va, rel_page;
  336         phandle_t node;
  337         int i;
  338 
  339         /* If we're calling this, the node already exists. */
  340         node = OF_finddevice("/cpus");
  341         for (i = 0, node = OF_child(node); i < pc->pc_cpuid;
  342             i++, node = OF_peer(node))
  343                 ;
  344         if (OF_getencprop(node, "cpu-release-addr", (pcell_t *)&rel_pa,
  345             sizeof(rel_pa)) == -1) {
  346                 return (ENOENT);
  347         }
  348 
  349         rel_page = kva_alloc(PAGE_SIZE);
  350         if (rel_page == 0)
  351                 return (ENOMEM);
  352 
  353         critical_enter();
  354         rel_va = rel_page + (rel_pa & PAGE_MASK);
  355         pmap_kenter(rel_page, rel_pa & ~PAGE_MASK);
  356         rel = (struct cpu_release *)rel_va;
  357         bptr = pmap_kextract((uintptr_t)__boot_page);
  358 
  359         cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
  360         rel->pir = pc->pc_cpuid; __asm __volatile("sync" ::: "memory");
  361         rel->entry_h = (bptr >> 32); __asm __volatile("sync" ::: "memory");
  362         cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
  363         rel->entry_l = bptr & 0xffffffff; __asm __volatile("sync" ::: "memory");
  364         cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
  365         if (bootverbose)
  366                 printf("Waking up CPU %d via CPU release page %p\n",
  367                     pc->pc_cpuid, rel);
  368         critical_exit();
  369         pmap_kremove(rel_page);
  370         kva_free(rel_page, PAGE_SIZE);
  371 
  372         return (0);
  373 }
  374 #endif
  375 
  376 static int
  377 mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
  378 {
  379 #ifdef SMP
  380         vm_paddr_t bptr;
  381         uint32_t reg;
  382         int timeout;
  383         uintptr_t brr;
  384         int cpuid;
  385         int epapr_boot = 0;
  386         uint32_t tgt;
  387 
  388         if (mpc85xx_is_qoriq()) {
  389                 reg = ccsr_read4(OCP85XX_COREDISR);
  390                 cpuid = pc->pc_cpuid;
  391 
  392                 if ((reg & (1 << cpuid)) != 0) {
  393                     printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid);
  394                     return (-1);
  395                 }
  396 
  397                 brr = OCP85XX_BRR;
  398         } else {
  399                 brr = OCP85XX_EEBPCR;
  400                 cpuid = pc->pc_cpuid + 24;
  401         }
  402         bp_kernload = kernload;
  403         bp_virtaddr = (vm_offset_t)&__boot_page;
  404         /*
  405          * bp_kernload and bp_virtaddr are in the boot page.  Sync the cache
  406          * because ePAPR booting has the other core(s) already running.
  407          */
  408         cpu_flush_dcache(&bp_kernload, sizeof(bp_kernload));
  409         cpu_flush_dcache(&bp_virtaddr, sizeof(bp_virtaddr));
  410 
  411         ap_pcpu = pc;
  412         __asm __volatile("msync; isync");
  413 
  414         /* First try the ePAPR way. */
  415         if (mpc85xx_smp_start_cpu_epapr(plat, pc) == 0) {
  416                 epapr_boot = 1;
  417                 goto spin_wait;
  418         }
  419 
  420         reg = ccsr_read4(brr);
  421         if ((reg & (1 << cpuid)) != 0) {
  422                 printf("SMP: CPU %d already out of hold-off state!\n",
  423                     pc->pc_cpuid);
  424                 return (ENXIO);
  425         }
  426 
  427         /* Flush caches to have our changes hit DRAM. */
  428         cpu_flush_dcache(__boot_page, 4096);
  429 
  430         bptr = pmap_kextract((uintptr_t)__boot_page);
  431         KASSERT((bptr & 0xfff) == 0,
  432             ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr));
  433         if (mpc85xx_is_qoriq()) {
  434                 /*
  435                  * Read DDR controller configuration to select proper BPTR target ID.
  436                  *
  437                  * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers
  438                  * interleaving. If this bit is set, we have to use
  439                  * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs,
  440                  * this bit is reserved and always 0.
  441                  */
  442 
  443                 reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG);
  444                 if (reg & (1 << 29))
  445                         tgt = OCP85XX_TGTIF_RAM_INTL;
  446                 else
  447                         tgt = OCP85XX_TGTIF_RAM1;
  448 
  449                 /*
  450                  * Set BSTR to the physical address of the boot page
  451                  */
  452                 ccsr_write4(OCP85XX_BSTRH, bptr >> 32);
  453                 ccsr_write4(OCP85XX_BSTRL, bptr);
  454                 ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK |
  455                     (tgt << OCP85XX_TRGT_SHIFT_QORIQ) | (ffsl(PAGE_SIZE) - 2));
  456 
  457                 /* Read back OCP85XX_BSTAR to synchronize write */
  458                 ccsr_read4(OCP85XX_BSTAR);
  459 
  460                 /*
  461                  * Enable and configure time base on new CPU.
  462                  */
  463 
  464                 /* Set TB clock source to platform clock / 32 */
  465                 reg = ccsr_read4(CCSR_CTBCKSELR);
  466                 ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid));
  467 
  468                 /* Enable TB */
  469                 reg = ccsr_read4(CCSR_CTBENR);
  470                 ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid));
  471         } else {
  472                 /*
  473                  * Set BPTR to the physical address of the boot page
  474                  */
  475                 bptr = (bptr >> 12) | 0x80000000u;
  476                 ccsr_write4(OCP85XX_BPTR, bptr);
  477                 __asm __volatile("isync; msync");
  478         }
  479 
  480         /*
  481          * Release AP from hold-off state
  482          */
  483         reg = ccsr_read4(brr);
  484         ccsr_write4(brr, reg | (1 << cpuid));
  485         __asm __volatile("isync; msync");
  486 
  487 spin_wait:
  488         timeout = 500;
  489         while (!pc->pc_awake && timeout--)
  490                 DELAY(1000);    /* wait 1ms */
  491 
  492         /*
  493          * Disable boot page translation so that the 4K page at the default
  494          * address (= 0xfffff000) isn't permanently remapped and thus not
  495          * usable otherwise.
  496          */
  497         if (!epapr_boot) {
  498                 if (mpc85xx_is_qoriq())
  499                         ccsr_write4(OCP85XX_BSTAR, 0);
  500                 else
  501                         ccsr_write4(OCP85XX_BPTR, 0);
  502                 __asm __volatile("isync; msync");
  503         }
  504 
  505         if (!pc->pc_awake)
  506                 panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid);
  507         return ((pc->pc_awake) ? 0 : EBUSY);
  508 #else
  509         /* No SMP support */
  510         return (ENXIO);
  511 #endif
  512 }
  513 
  514 static void
  515 mpc85xx_reset(platform_t plat)
  516 {
  517 
  518         /*
  519          * Try the dedicated reset register first.
  520          * If the SoC doesn't have one, we'll fall
  521          * back to using the debug control register.
  522          */
  523         ccsr_write4(OCP85XX_RSTCR, 2);
  524 
  525         mtmsr(mfmsr() & ~PSL_DE);
  526 
  527         /* Enable debug interrupts and issue reset. */
  528         mtspr(SPR_DBCR0, DBCR0_IDM | DBCR0_RST_SYSTEM);
  529         __asm __volatile("isync");
  530 
  531         /* Enable Debug Interrupts in MSR. */
  532         mtmsr(mfmsr() | PSL_DE);
  533 
  534         printf("Reset failed...\n");
  535         while (1)
  536                 ;
  537 }
  538 
  539 static void
  540 mpc85xx_smp_timebase_sync(platform_t plat, u_long tb, int ap)
  541 {
  542         static volatile bool tb_ready;
  543         static volatile int cpu_done;
  544 
  545         if (ap) {
  546                 /* APs.  Hold off until we get a stable timebase. */
  547                 while (!tb_ready)
  548                         atomic_thread_fence_seq_cst();
  549                 mttb(tb);
  550                 atomic_add_int(&cpu_done, 1);
  551                 while (cpu_done < mp_ncpus)
  552                         atomic_thread_fence_seq_cst();
  553         } else {
  554                 /* BSP */
  555                 freeze_timebase(rcpm_dev, true);
  556                 tb_ready = true;
  557                 mttb(tb);
  558                 atomic_add_int(&cpu_done, 1);
  559                 while (cpu_done < mp_ncpus)
  560                         atomic_thread_fence_seq_cst();
  561                 freeze_timebase(rcpm_dev, false);
  562         }
  563 }
  564 
  565 /* Fallback freeze.  In case no real handler is found in the device tree. */
  566 static void
  567 dummy_freeze(device_t dev, bool freeze)
  568 {
  569         /* Nothing to do here, move along. */
  570 }
  571 
  572 /* QorIQ Run control/power management timebase management. */
  573 
  574 #define RCPM_CTBENR     0x00000084
  575 struct mpc85xx_rcpm_softc {
  576         struct resource *sc_mem;
  577 };
  578 
  579 static void
  580 mpc85xx_rcpm_freeze_timebase(device_t dev, bool freeze)
  581 {
  582         struct mpc85xx_rcpm_softc *sc;
  583 
  584         sc = device_get_softc(dev);
  585 
  586         if (freeze)
  587                 bus_write_4(sc->sc_mem, RCPM_CTBENR, 0);
  588         else
  589                 bus_write_4(sc->sc_mem, RCPM_CTBENR, (1 << maxcpu) - 1);
  590 }
  591 
  592 static int
  593 mpc85xx_rcpm_probe(device_t dev)
  594 {
  595         if (!ofw_bus_is_compatible(dev, "fsl,qoriq-rcpm-1.0"))
  596                 return (ENXIO);
  597 
  598         device_set_desc(dev, "QorIQ Run control and power management");
  599         return (BUS_PROBE_GENERIC);
  600 }
  601 
  602 static int
  603 mpc85xx_rcpm_attach(device_t dev)
  604 {
  605         struct mpc85xx_rcpm_softc *sc;
  606         int rid;
  607 
  608         sc = device_get_softc(dev);
  609         freeze_timebase = mpc85xx_rcpm_freeze_timebase;
  610         rcpm_dev = dev;
  611 
  612         rid = 0;
  613         sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  614             RF_ACTIVE | RF_SHAREABLE);
  615 
  616         return (0);
  617 }
  618 
  619 static device_method_t mpc85xx_rcpm_methods[] = {
  620         DEVMETHOD(device_probe,         mpc85xx_rcpm_probe),
  621         DEVMETHOD(device_attach,        mpc85xx_rcpm_attach),
  622         DEVMETHOD_END
  623 };
  624 
  625 static driver_t mpc85xx_rcpm_driver = {
  626         "rcpm",
  627         mpc85xx_rcpm_methods,
  628         sizeof(struct mpc85xx_rcpm_softc)
  629 };
  630 
  631 EARLY_DRIVER_MODULE(mpc85xx_rcpm, simplebus, mpc85xx_rcpm_driver, 0, 0,
  632     BUS_PASS_BUS);
  633 
  634 /* "Global utilities" power management/Timebase management. */
  635 
  636 #define GUTS_DEVDISR    0x00000070
  637 #define   DEVDISR_TB0   0x00004000
  638 #define   DEVDISR_TB1   0x00001000
  639 
  640 struct mpc85xx_guts_softc {
  641         struct resource *sc_mem;
  642 };
  643 
  644 static void
  645 mpc85xx_guts_freeze_timebase(device_t dev, bool freeze)
  646 {
  647         struct mpc85xx_guts_softc *sc;
  648         uint32_t devdisr;
  649 
  650         sc = device_get_softc(dev);
  651 
  652         devdisr = bus_read_4(sc->sc_mem, GUTS_DEVDISR);
  653         if (freeze)
  654                 bus_write_4(sc->sc_mem, GUTS_DEVDISR,
  655                     devdisr | (DEVDISR_TB0 | DEVDISR_TB1));
  656         else
  657                 bus_write_4(sc->sc_mem, GUTS_DEVDISR,
  658                     devdisr & ~(DEVDISR_TB0 | DEVDISR_TB1));
  659 }
  660 
  661 static int
  662 mpc85xx_guts_probe(device_t dev)
  663 {
  664         if (!ofw_bus_is_compatible(dev, "fsl,mpc8572-guts") &&
  665             !ofw_bus_is_compatible(dev, "fsl,p1020-guts") &&
  666             !ofw_bus_is_compatible(dev, "fsl,p1021-guts") &&
  667             !ofw_bus_is_compatible(dev, "fsl,p1022-guts") &&
  668             !ofw_bus_is_compatible(dev, "fsl,p1023-guts") &&
  669             !ofw_bus_is_compatible(dev, "fsl,p2020-guts"))
  670                 return (ENXIO);
  671 
  672         device_set_desc(dev, "MPC85xx Global Utilities");
  673         return (BUS_PROBE_GENERIC);
  674 }
  675 
  676 static int
  677 mpc85xx_guts_attach(device_t dev)
  678 {
  679         struct mpc85xx_rcpm_softc *sc;
  680         int rid;
  681 
  682         sc = device_get_softc(dev);
  683         freeze_timebase = mpc85xx_guts_freeze_timebase;
  684         rcpm_dev = dev;
  685 
  686         rid = 0;
  687         sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  688             RF_ACTIVE | RF_SHAREABLE);
  689 
  690         return (0);
  691 }
  692 
  693 static device_method_t mpc85xx_guts_methods[] = {
  694         DEVMETHOD(device_probe,         mpc85xx_guts_probe),
  695         DEVMETHOD(device_attach,        mpc85xx_guts_attach),
  696         DEVMETHOD_END
  697 };
  698 
  699 static driver_t mpc85xx_guts_driver = {
  700         "guts",
  701         mpc85xx_guts_methods,
  702         sizeof(struct mpc85xx_guts_softc)
  703 };
  704 
  705 EARLY_DRIVER_MODULE(mpc85xx_guts, simplebus, mpc85xx_guts_driver, 0, 0,
  706     BUS_PASS_BUS);

Cache object: 7fc6c68a9420e62295c591077418cbd4


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