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/arm/xilinx/zy7_slcr.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) 2013 Thomas Skibo
    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  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 /*
   32  * Zynq-700 SLCR driver.  Provides hooks for cpu_reset and PL control stuff.
   33  * In the future, maybe MIO control, clock control, etc. could go here.
   34  *
   35  * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
   36  * (v1.4) November 16, 2012.  Xilinx doc UG585.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __FBSDID("$FreeBSD$");
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/conf.h>
   45 #include <sys/kernel.h>
   46 #include <sys/module.h>
   47 #include <sys/lock.h>
   48 #include <sys/mutex.h>
   49 #include <sys/resource.h>
   50 #include <sys/sysctl.h>
   51 #include <sys/rman.h>
   52 
   53 #include <machine/bus.h>
   54 #include <machine/resource.h>
   55 #include <machine/stdarg.h>
   56 
   57 #include <dev/ofw/ofw_bus.h>
   58 #include <dev/ofw/ofw_bus_subr.h>
   59 
   60 #include <arm/xilinx/zy7_slcr.h>
   61 
   62 struct zy7_slcr_softc {
   63         device_t        dev;
   64         struct mtx      sc_mtx;
   65         struct resource *mem_res;
   66 };
   67 
   68 static struct zy7_slcr_softc *zy7_slcr_softc_p;
   69 extern void (*zynq7_cpu_reset);
   70 
   71 #define ZSLCR_LOCK(sc)          mtx_lock(&(sc)->sc_mtx)
   72 #define ZSLCR_UNLOCK(sc)                mtx_unlock(&(sc)->sc_mtx)
   73 #define ZSLCR_LOCK_INIT(sc) \
   74         mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \
   75             "zy7_slcr", MTX_DEF)
   76 #define ZSLCR_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
   77 
   78 #define RD4(sc, off)            (bus_read_4((sc)->mem_res, (off)))
   79 #define WR4(sc, off, val)       (bus_write_4((sc)->mem_res, (off), (val)))
   80 
   81 #define ZYNQ_DEFAULT_PS_CLK_FREQUENCY   33333333        /* 33.3 Mhz */
   82 
   83 SYSCTL_NODE(_hw, OID_AUTO, zynq, CTLFLAG_RD, 0, "Xilinx Zynq-7000");
   84 
   85 static char zynq_bootmode[64];
   86 SYSCTL_STRING(_hw_zynq, OID_AUTO, bootmode, CTLFLAG_RD, zynq_bootmode, 0,
   87               "Zynq boot mode");
   88 
   89 static char zynq_pssid[100];
   90 SYSCTL_STRING(_hw_zynq, OID_AUTO, pssid, CTLFLAG_RD, zynq_pssid, 0,
   91            "Zynq PSS IDCODE");
   92 
   93 static uint32_t zynq_reboot_status;
   94 SYSCTL_INT(_hw_zynq, OID_AUTO, reboot_status, CTLFLAG_RD, &zynq_reboot_status,
   95            0, "Zynq REBOOT_STATUS register");
   96 
   97 static int ps_clk_frequency;
   98 SYSCTL_INT(_hw_zynq, OID_AUTO, ps_clk_frequency, CTLFLAG_RD, &ps_clk_frequency,
   99            0, "Zynq PS_CLK Frequency");
  100 
  101 static int io_pll_frequency;
  102 SYSCTL_INT(_hw_zynq, OID_AUTO, io_pll_frequency, CTLFLAG_RD, &io_pll_frequency,
  103            0, "Zynq IO PLL Frequency");
  104 
  105 static int arm_pll_frequency;
  106 SYSCTL_INT(_hw_zynq, OID_AUTO, arm_pll_frequency, CTLFLAG_RD,
  107            &arm_pll_frequency, 0, "Zynq ARM PLL Frequency");
  108 
  109 static int ddr_pll_frequency;
  110 SYSCTL_INT(_hw_zynq, OID_AUTO, ddr_pll_frequency, CTLFLAG_RD,
  111            &ddr_pll_frequency, 0, "Zynq DDR PLL Frequency");
  112 
  113 static void
  114 zy7_slcr_unlock(struct zy7_slcr_softc *sc)
  115 {
  116 
  117         /* Unlock SLCR with magic number. */
  118         WR4(sc, ZY7_SLCR_UNLOCK, ZY7_SLCR_UNLOCK_MAGIC);
  119 }
  120 
  121 static void
  122 zy7_slcr_lock(struct zy7_slcr_softc *sc)
  123 {
  124 
  125         /* Lock SLCR with magic number. */
  126         WR4(sc, ZY7_SLCR_LOCK, ZY7_SLCR_LOCK_MAGIC);
  127 }
  128 
  129 static void
  130 zy7_slcr_cpu_reset(void)
  131 {
  132         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  133 
  134         /* Unlock SLCR registers. */
  135         zy7_slcr_unlock(sc);
  136 
  137         /* This has something to do with a work-around so the fsbl will load
  138          * the bitstream after soft-reboot.  It's very important.
  139          */
  140         WR4(sc, ZY7_SLCR_REBOOT_STAT,
  141             RD4(sc, ZY7_SLCR_REBOOT_STAT) & 0xf0ffffff);
  142 
  143         /* Soft reset */
  144         WR4(sc, ZY7_SLCR_PSS_RST_CTRL, ZY7_SLCR_PSS_RST_CTRL_SOFT_RESET);
  145 
  146         for (;;)
  147                 ;
  148 }
  149 
  150 /* Assert PL resets and disable level shifters in preparation of programming
  151  * the PL (FPGA) section.  Called from zy7_devcfg.c.
  152  */
  153 void
  154 zy7_slcr_preload_pl(void)
  155 {
  156         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  157 
  158         if (!sc)
  159                 return;
  160 
  161         ZSLCR_LOCK(sc);
  162 
  163         /* Unlock SLCR registers. */
  164         zy7_slcr_unlock(sc);
  165 
  166         /* Assert top level output resets. */
  167         WR4(sc, ZY7_SLCR_FPGA_RST_CTRL, ZY7_SLCR_FPGA_RST_CTRL_RST_ALL);
  168 
  169         /* Disable all level shifters. */
  170         WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, 0);
  171 
  172         /* Lock SLCR registers. */
  173         zy7_slcr_lock(sc);
  174 
  175         ZSLCR_UNLOCK(sc);
  176 }
  177 
  178 /* After PL configuration, enable level shifters and deassert top-level
  179  * PL resets.  Called from zy7_devcfg.c.  Optionally, the level shifters
  180  * can be left disabled but that's rare of an FPGA application. That option
  181  * is controlled by a sysctl in the devcfg driver.
  182  */
  183 void
  184 zy7_slcr_postload_pl(int en_level_shifters)
  185 {
  186         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  187 
  188         if (!sc)
  189                 return;
  190 
  191         ZSLCR_LOCK(sc);
  192 
  193         /* Unlock SLCR registers. */
  194         zy7_slcr_unlock(sc);
  195 
  196         if (en_level_shifters)
  197                 /* Enable level shifters. */
  198                 WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, ZY7_SLCR_LVL_SHFTR_EN_ALL);
  199 
  200         /* Deassert top level output resets. */
  201         WR4(sc, ZY7_SLCR_FPGA_RST_CTRL, 0);
  202 
  203         /* Lock SLCR registers. */
  204         zy7_slcr_lock(sc);
  205 
  206         ZSLCR_UNLOCK(sc);
  207 }
  208 
  209 /* Override cgem_set_refclk() in gigabit ethernet driver
  210  * (sys/dev/cadence/if_cgem.c).  This function is called to
  211  * request a change in the gem's reference clock speed.
  212  */
  213 int
  214 cgem_set_ref_clk(int unit, int frequency)
  215 {
  216         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  217         int div0, div1;
  218 
  219         if (!sc)
  220                 return (-1);
  221 
  222         /* Find suitable divisor pairs.  Round result to nearest khz
  223          * to test for match.
  224          */
  225         for (div1 = 1; div1 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX; div1++) {
  226                 div0 = (io_pll_frequency + div1 * frequency / 2) /
  227                         div1 / frequency;
  228                 if (div0 > 0 && div0 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_MAX &&
  229                     ((io_pll_frequency / div0 / div1) + 500) / 1000 ==
  230                     (frequency + 500) / 1000)
  231                         break;
  232         }
  233 
  234         if (div1 > ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX)
  235                 return (-1);
  236 
  237         ZSLCR_LOCK(sc);
  238 
  239         /* Unlock SLCR registers. */
  240         zy7_slcr_unlock(sc);
  241 
  242         /* Modify GEM reference clock. */
  243         WR4(sc, unit ? ZY7_SLCR_GEM1_CLK_CTRL : ZY7_SLCR_GEM0_CLK_CTRL,
  244             (div1 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_SHIFT) |
  245             (div0 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_SHIFT) |
  246             ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_IO_PLL |
  247             ZY7_SLCR_GEM_CLK_CTRL_CLKACT);
  248 
  249         /* Lock SLCR registers. */
  250         zy7_slcr_lock(sc);
  251 
  252         ZSLCR_UNLOCK(sc);
  253 
  254         return (0);
  255 }
  256 
  257 /* 
  258  * PL clocks management function
  259  */
  260 int 
  261 zy7_pl_fclk_set_source(int unit, int source)
  262 {
  263         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  264         uint32_t reg;
  265 
  266         if (!sc)
  267                 return (-1);
  268 
  269         ZSLCR_LOCK(sc);
  270 
  271         /* Unlock SLCR registers. */
  272         zy7_slcr_unlock(sc);
  273 
  274         /* Modify FPGAx source. */
  275         reg = RD4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit));
  276         reg &= ~(ZY7_SLCR_FPGA_CLK_CTRL_SRCSEL_MASK);
  277         reg |= (source << ZY7_SLCR_FPGA_CLK_CTRL_SRCSEL_SHIFT);
  278         WR4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit), reg);
  279 
  280         /* Lock SLCR registers. */
  281         zy7_slcr_lock(sc);
  282 
  283         ZSLCR_UNLOCK(sc);
  284 
  285         return (0);
  286 }
  287 
  288 int 
  289 zy7_pl_fclk_get_source(int unit)
  290 {
  291         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  292         uint32_t reg;
  293         int source;
  294 
  295         if (!sc)
  296                 return (-1);
  297 
  298         ZSLCR_LOCK(sc);
  299 
  300         /* Modify GEM reference clock. */
  301         reg = RD4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit));
  302         source = (reg & ZY7_SLCR_FPGA_CLK_CTRL_SRCSEL_MASK) >> 
  303             ZY7_SLCR_FPGA_CLK_CTRL_SRCSEL_SHIFT;
  304 
  305         /* ZY7_PL_FCLK_SRC_IO is actually b0x */
  306         if ((source & 2) == 0)
  307                 source = ZY7_PL_FCLK_SRC_IO;
  308 
  309         ZSLCR_UNLOCK(sc);
  310 
  311         return (source);
  312 }
  313 
  314 int
  315 zy7_pl_fclk_set_freq(int unit, int frequency)
  316 {
  317         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  318         int div0, div1;
  319         int base_frequency;
  320         uint32_t reg;
  321         int source;
  322 
  323         if (!sc)
  324                 return (-1);
  325 
  326         source = zy7_pl_fclk_get_source(unit);
  327         switch (source) {
  328                 case ZY7_PL_FCLK_SRC_IO:
  329                         base_frequency = io_pll_frequency;
  330                         break;
  331 
  332                 case ZY7_PL_FCLK_SRC_ARM:
  333                         base_frequency = arm_pll_frequency;
  334                         break;
  335 
  336                 case ZY7_PL_FCLK_SRC_DDR:
  337                         base_frequency = ddr_pll_frequency;
  338                         break;
  339 
  340                 default:
  341                         return (-1);
  342         }
  343 
  344         /* Find suitable divisor pairs.  Round result to nearest khz
  345          * to test for match.
  346          */
  347         for (div1 = 1; div1 <= ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR_MAX; div1++) {
  348                 div0 = (base_frequency + div1 * frequency / 2) /
  349                         div1 / frequency;
  350                 if (div0 > 0 && div0 <= ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR_MAX &&
  351                     ((base_frequency / div0 / div1) + 500) / 1000 ==
  352                     (frequency + 500) / 1000)
  353                         break;
  354         }
  355 
  356         if (div1 > ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR_MAX)
  357                 return (-1);
  358 
  359         ZSLCR_LOCK(sc);
  360 
  361         /* Unlock SLCR registers. */
  362         zy7_slcr_unlock(sc);
  363 
  364         /* Modify FPGAx reference clock. */
  365         reg = RD4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit));
  366         reg &= ~(ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR1_MASK |
  367             ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR0_MASK);
  368         reg |= (div1 << ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR1_SHIFT) |
  369             (div0 << ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR0_SHIFT);
  370         WR4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit), reg);
  371 
  372         /* Lock SLCR registers. */
  373         zy7_slcr_lock(sc);
  374 
  375         ZSLCR_UNLOCK(sc);
  376 
  377         return (base_frequency / div0 / div1);
  378 }
  379 
  380 int
  381 zy7_pl_fclk_get_freq(int unit)
  382 {
  383         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  384         int div0, div1;
  385         int base_frequency;
  386         int frequency;
  387         uint32_t reg;
  388         int source;
  389 
  390         if (!sc)
  391                 return (-1);
  392 
  393         source = zy7_pl_fclk_get_source(unit);
  394         switch (source) {
  395                 case ZY7_PL_FCLK_SRC_IO:
  396                         base_frequency = io_pll_frequency;
  397                         break;
  398 
  399                 case ZY7_PL_FCLK_SRC_ARM:
  400                         base_frequency = arm_pll_frequency;
  401                         break;
  402 
  403                 case ZY7_PL_FCLK_SRC_DDR:
  404                         base_frequency = ddr_pll_frequency;
  405                         break;
  406 
  407                 default:
  408                         return (-1);
  409         }
  410 
  411         ZSLCR_LOCK(sc);
  412 
  413         /* Modify FPGAx reference clock. */
  414         reg = RD4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit));
  415         div1 = (reg & ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR1_MASK) >>
  416             ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR1_SHIFT;
  417         div0 = (reg & ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR0_MASK) >>
  418             ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR0_SHIFT;
  419 
  420         ZSLCR_UNLOCK(sc);
  421 
  422         if (div0 == 0)
  423                 div0 = 1;
  424 
  425         if (div1 == 0)
  426                 div1 = 1;
  427 
  428         frequency = (base_frequency / div0 / div1);
  429         /* Round to KHz */
  430         frequency = (frequency + 500) / 1000;
  431         frequency = frequency * 1000;
  432 
  433         return (frequency);
  434 }
  435 
  436 int 
  437 zy7_pl_fclk_enable(int unit)
  438 {
  439         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  440 
  441         if (!sc)
  442                 return (-1);
  443 
  444         ZSLCR_LOCK(sc);
  445 
  446         /* Unlock SLCR registers. */
  447         zy7_slcr_unlock(sc);
  448 
  449         WR4(sc, ZY7_SLCR_FPGA_THR_CTRL(unit), 0);
  450         WR4(sc, ZY7_SLCR_FPGA_THR_CNT(unit), 0);
  451 
  452         /* Lock SLCR registers. */
  453         zy7_slcr_lock(sc);
  454 
  455         ZSLCR_UNLOCK(sc);
  456 
  457         return (0);
  458 }
  459 
  460 int 
  461 zy7_pl_fclk_disable(int unit)
  462 {
  463         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  464 
  465         if (!sc)
  466                 return (-1);
  467 
  468         ZSLCR_LOCK(sc);
  469 
  470         /* Unlock SLCR registers. */
  471         zy7_slcr_unlock(sc);
  472 
  473         WR4(sc, ZY7_SLCR_FPGA_THR_CTRL(unit), 0);
  474         WR4(sc, ZY7_SLCR_FPGA_THR_CNT(unit), 1);
  475 
  476         /* Lock SLCR registers. */
  477         zy7_slcr_lock(sc);
  478 
  479         ZSLCR_UNLOCK(sc);
  480 
  481         return (0);
  482 }
  483 
  484 int 
  485 zy7_pl_fclk_enabled(int unit)
  486 {
  487         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  488         uint32_t reg;
  489 
  490         if (!sc)
  491                 return (-1);
  492 
  493         ZSLCR_LOCK(sc);
  494         reg = RD4(sc, ZY7_SLCR_FPGA_THR_CNT(unit));
  495         ZSLCR_UNLOCK(sc);
  496 
  497         return !(reg & 1);
  498 }
  499 
  500 int
  501 zy7_pl_level_shifters_enabled(void)
  502 {
  503         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  504 
  505         uint32_t reg;
  506 
  507         if (!sc)
  508                 return (-1);
  509 
  510         ZSLCR_LOCK(sc);
  511         reg = RD4(sc, ZY7_SLCR_LVL_SHFTR_EN);
  512         ZSLCR_UNLOCK(sc);
  513 
  514         return (reg == ZY7_SLCR_LVL_SHFTR_EN_ALL);
  515 }
  516 
  517 void
  518 zy7_pl_level_shifters_enable(void)
  519 {
  520         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  521 
  522         if (!sc)
  523                 return;
  524 
  525         ZSLCR_LOCK(sc);
  526         zy7_slcr_unlock(sc);
  527         WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, ZY7_SLCR_LVL_SHFTR_EN_ALL);
  528         zy7_slcr_lock(sc);
  529         ZSLCR_UNLOCK(sc);
  530 }
  531 
  532 void
  533 zy7_pl_level_shifters_disable(void)
  534 {
  535         struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
  536 
  537         if (!sc)
  538                 return;
  539 
  540         ZSLCR_LOCK(sc);
  541         zy7_slcr_unlock(sc);
  542         WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, 0);
  543         zy7_slcr_lock(sc);
  544         ZSLCR_UNLOCK(sc);
  545 }
  546 
  547 static int
  548 zy7_slcr_probe(device_t dev)
  549 {
  550 
  551         if (!ofw_bus_status_okay(dev))
  552                 return (ENXIO);
  553 
  554         if (!ofw_bus_is_compatible(dev, "xlnx,zy7_slcr"))
  555                 return (ENXIO);
  556 
  557         device_set_desc(dev, "Zynq-7000 slcr block");
  558         return (0);
  559 }
  560 
  561 static int
  562 zy7_slcr_attach(device_t dev)
  563 {
  564         struct zy7_slcr_softc *sc = device_get_softc(dev);
  565         int rid;
  566         phandle_t node;
  567         pcell_t cell;
  568         uint32_t bootmode;
  569         uint32_t pss_idcode;
  570         uint32_t arm_pll_ctrl;
  571         uint32_t ddr_pll_ctrl;
  572         uint32_t io_pll_ctrl;
  573         static char *bootdev_names[] = {
  574                 "JTAG", "Quad-SPI", "NOR", "(3?)",
  575                 "NAND", "SD Card", "(6?)", "(7?)"
  576         };
  577 
  578         /* Allow only one attach. */
  579         if (zy7_slcr_softc_p != NULL)
  580                 return (ENXIO);
  581 
  582         sc->dev = dev;
  583 
  584         ZSLCR_LOCK_INIT(sc);
  585 
  586         /* Get memory resource. */
  587         rid = 0;
  588         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  589                                              RF_ACTIVE);
  590         if (sc->mem_res == NULL) {
  591                 device_printf(dev, "could not allocate memory resources.\n");
  592                 return (ENOMEM);
  593         }
  594 
  595         /* Hook up cpu_reset. */
  596         zy7_slcr_softc_p = sc;
  597         zynq7_cpu_reset = zy7_slcr_cpu_reset;
  598 
  599         /* Read info and set sysctls. */
  600         bootmode = RD4(sc, ZY7_SLCR_BOOT_MODE);
  601         snprintf(zynq_bootmode, sizeof(zynq_bootmode),
  602                  "0x%x: boot device: %s", bootmode,
  603                  bootdev_names[bootmode & ZY7_SLCR_BOOT_MODE_BOOTDEV_MASK]);
  604 
  605         pss_idcode = RD4(sc, ZY7_SLCR_PSS_IDCODE);
  606         snprintf(zynq_pssid, sizeof(zynq_pssid),
  607                  "0x%x: manufacturer: 0x%x device: 0x%x "
  608                  "family: 0x%x sub-family: 0x%x rev: 0x%x",
  609                  pss_idcode,
  610                  (pss_idcode & ZY7_SLCR_PSS_IDCODE_MNFR_ID_MASK) >>
  611                  ZY7_SLCR_PSS_IDCODE_MNFR_ID_SHIFT,
  612                  (pss_idcode & ZY7_SLCR_PSS_IDCODE_DEVICE_MASK) >>
  613                  ZY7_SLCR_PSS_IDCODE_DEVICE_SHIFT,
  614                  (pss_idcode & ZY7_SLCR_PSS_IDCODE_FAMILY_MASK) >>
  615                  ZY7_SLCR_PSS_IDCODE_FAMILY_SHIFT,
  616                  (pss_idcode & ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_MASK) >>
  617                  ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_SHIFT,
  618                  (pss_idcode & ZY7_SLCR_PSS_IDCODE_REVISION_MASK) >>
  619                  ZY7_SLCR_PSS_IDCODE_REVISION_SHIFT);
  620 
  621         zynq_reboot_status = RD4(sc, ZY7_SLCR_REBOOT_STAT);
  622 
  623         /* Derive PLL frequencies from PS_CLK. */
  624         node = ofw_bus_get_node(dev);
  625         if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) > 0)
  626                 ps_clk_frequency = cell;
  627         else
  628                 ps_clk_frequency = ZYNQ_DEFAULT_PS_CLK_FREQUENCY;
  629 
  630         arm_pll_ctrl = RD4(sc, ZY7_SLCR_ARM_PLL_CTRL);
  631         ddr_pll_ctrl = RD4(sc, ZY7_SLCR_DDR_PLL_CTRL);
  632         io_pll_ctrl = RD4(sc, ZY7_SLCR_IO_PLL_CTRL);
  633 
  634         /* Determine ARM PLL frequency. */
  635         if (((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 &&
  636              (arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) ||
  637             ((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 &&
  638              (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0))
  639                 /* PLL is bypassed. */
  640                 arm_pll_frequency = ps_clk_frequency;
  641         else
  642                 arm_pll_frequency = ps_clk_frequency *
  643                         ((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >>
  644                          ZY7_SLCR_PLL_CTRL_FDIV_SHIFT);
  645 
  646         /* Determine DDR PLL frequency. */
  647         if (((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 &&
  648              (ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) ||
  649             ((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 &&
  650              (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0))
  651                 /* PLL is bypassed. */
  652                 ddr_pll_frequency = ps_clk_frequency;
  653         else
  654                 ddr_pll_frequency = ps_clk_frequency *
  655                         ((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >>
  656                          ZY7_SLCR_PLL_CTRL_FDIV_SHIFT);
  657 
  658         /* Determine IO PLL frequency. */
  659         if (((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 &&
  660              (io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) ||
  661             ((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 &&
  662              (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0))
  663                 /* PLL is bypassed. */
  664                 io_pll_frequency = ps_clk_frequency;
  665         else
  666                 io_pll_frequency = ps_clk_frequency *
  667                         ((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >>
  668                          ZY7_SLCR_PLL_CTRL_FDIV_SHIFT);
  669 
  670         /* Lock SLCR registers. */
  671         zy7_slcr_lock(sc);
  672 
  673         return (0);
  674 }
  675 
  676 static int
  677 zy7_slcr_detach(device_t dev)
  678 {
  679         struct zy7_slcr_softc *sc = device_get_softc(dev);
  680 
  681         bus_generic_detach(dev);
  682 
  683         /* Release memory resource. */
  684         if (sc->mem_res != NULL)
  685                 bus_release_resource(dev, SYS_RES_MEMORY,
  686                              rman_get_rid(sc->mem_res), sc->mem_res);
  687 
  688         zy7_slcr_softc_p = NULL;
  689         zynq7_cpu_reset = NULL;
  690 
  691         ZSLCR_LOCK_DESTROY(sc);
  692 
  693         return (0);
  694 }
  695 
  696 static device_method_t zy7_slcr_methods[] = {
  697         /* device_if */
  698         DEVMETHOD(device_probe,         zy7_slcr_probe),
  699         DEVMETHOD(device_attach,        zy7_slcr_attach),
  700         DEVMETHOD(device_detach,        zy7_slcr_detach),
  701 
  702         DEVMETHOD_END
  703 };
  704 
  705 static driver_t zy7_slcr_driver = {
  706         "zy7_slcr",
  707         zy7_slcr_methods,
  708         sizeof(struct zy7_slcr_softc),
  709 };
  710 static devclass_t zy7_slcr_devclass;
  711 
  712 DRIVER_MODULE(zy7_slcr, simplebus, zy7_slcr_driver, zy7_slcr_devclass, 0, 0);
  713 MODULE_VERSION(zy7_slcr, 1);

Cache object: 1780821c2edd2d960b09cd68471c4f49


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