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/mips/mediatek/mtk_soc.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) 2016 Stanislav Galabov.
    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 THE 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 THE 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.2/sys/mips/mediatek/mtk_soc.c 300196 2016-05-19 06:29:43Z sgalabov $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <sys/rman.h>
   36 
   37 #include <machine/fdt.h>
   38 
   39 #include <dev/ofw/openfirm.h>
   40 #include <dev/ofw/ofw_bus.h>
   41 #include <dev/ofw/ofw_bus_subr.h>
   42 
   43 #include <dev/fdt/fdt_common.h>
   44 #include <dev/fdt/fdt_clock.h>
   45 
   46 #include <mips/mediatek/fdt_reset.h>
   47 #include <mips/mediatek/mtk_sysctl.h>
   48 #include <mips/mediatek/mtk_soc.h>
   49 
   50 static uint32_t mtk_soc_socid = MTK_SOC_UNKNOWN;
   51 static uint32_t mtk_soc_uartclk = 0;
   52 static uint32_t mtk_soc_cpuclk = MTK_CPU_CLK_880MHZ;
   53 static uint32_t mtk_soc_timerclk = MTK_CPU_CLK_880MHZ / 2;
   54 
   55 static const struct ofw_compat_data compat_data[] = {
   56         { "ralink,rt3050-soc",          MTK_SOC_RT3050 },
   57         { "ralink,rt3052-soc",          MTK_SOC_RT3052 },
   58         { "ralink,rt3350-soc",          MTK_SOC_RT3350 },
   59         { "ralink,rt3352-soc",          MTK_SOC_RT3352 },
   60         { "ralink,rt3662-soc",          MTK_SOC_RT3662 },
   61         { "ralink,rt3883-soc",          MTK_SOC_RT3883 },
   62         { "ralink,rt5350-soc",          MTK_SOC_RT5350 },
   63         { "ralink,mtk7620a-soc",        MTK_SOC_MT7620A },
   64         { "ralink,mt7620a-soc",         MTK_SOC_MT7620A },
   65         { "ralink,mtk7620n-soc",        MTK_SOC_MT7620N },
   66         { "ralink,mt7620n-soc",         MTK_SOC_MT7620N },
   67         { "mediatek,mtk7621-soc",       MTK_SOC_MT7621 },
   68         { "mediatek,mt7621-soc",        MTK_SOC_MT7621 },
   69         { "ralink,mt7621-soc",          MTK_SOC_MT7621 },
   70         { "ralink,mtk7621-soc",         MTK_SOC_MT7621 },
   71         { "ralink,mtk7628an-soc",       MTK_SOC_MT7628 },
   72         { "mediatek,mt7628an-soc",      MTK_SOC_MT7628 },
   73         { "ralink,mtk7688-soc",         MTK_SOC_MT7688 },
   74 
   75         /* Sentinel */
   76         { NULL,                         MTK_SOC_UNKNOWN },
   77 };
   78 
   79 static uint32_t
   80 mtk_detect_cpuclk_rt305x(bus_space_tag_t bst, bus_space_handle_t bsh)
   81 {
   82         uint32_t val;
   83 
   84         val = bus_space_read_4(bst, bsh, SYSCTL_CHIPID0_3);
   85         if (val == RT3350_CHIPID0_3)
   86                 return (MTK_CPU_CLK_320MHZ);
   87 
   88         val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
   89         val >>= RT305X_CPU_CLKSEL_OFF;
   90         val &= RT305X_CPU_CLKSEL_MSK;
   91 
   92         return ((val == 0) ? MTK_CPU_CLK_320MHZ : MTK_CPU_CLK_384MHZ);
   93 }
   94 
   95 static uint32_t
   96 mtk_detect_cpuclk_rt3352(bus_space_tag_t bst, bus_space_handle_t bsh)
   97 {
   98         uint32_t val;
   99 
  100         val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
  101         val >>= RT3352_CPU_CLKSEL_OFF;
  102         val &= RT3352_CPU_CLKSEL_MSK;
  103 
  104         if (val)
  105                 return (MTK_CPU_CLK_400MHZ);
  106 
  107         return (MTK_CPU_CLK_384MHZ);
  108 }
  109 
  110 static uint32_t
  111 mtk_detect_cpuclk_rt3883(bus_space_tag_t bst, bus_space_handle_t bsh)
  112 {
  113         uint32_t val;
  114 
  115         val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
  116         val >>= RT3883_CPU_CLKSEL_OFF;
  117         val &= RT3883_CPU_CLKSEL_MSK;
  118 
  119         switch (val) {
  120         case 0:
  121                 return (MTK_CPU_CLK_250MHZ);
  122         case 1:
  123                 return (MTK_CPU_CLK_384MHZ);
  124         case 2:
  125                 return (MTK_CPU_CLK_480MHZ);
  126         case 3:
  127                 return (MTK_CPU_CLK_500MHZ);
  128         }
  129 
  130         /* Never reached */
  131         return (0);
  132 }
  133 
  134 static uint32_t
  135 mtk_detect_cpuclk_rt5350(bus_space_tag_t bst, bus_space_handle_t bsh)
  136 {
  137         uint32_t val1, val2;
  138 
  139         val1 = val2 = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
  140 
  141         val1 >>= RT5350_CPU_CLKSEL_OFF1;
  142         val2 >>= RT5350_CPU_CLKSEL_OFF2;
  143         val1 &= RT5350_CPU_CLKSEL_MSK;
  144         val2 &= RT5350_CPU_CLKSEL_MSK;
  145         val1 |= (val2 << 1);
  146 
  147         switch (val1) {
  148         case 0:
  149                 return (MTK_CPU_CLK_360MHZ);
  150         case 1:
  151                 /* Reserved value, but we return UNKNOWN */
  152                 return (MTK_CPU_CLK_UNKNOWN);
  153         case 2:
  154                 return (MTK_CPU_CLK_320MHZ);
  155         case 3:
  156                 return (MTK_CPU_CLK_300MHZ);
  157         }
  158 
  159         /* Never reached */
  160         return (0);
  161 }
  162 
  163 static uint32_t
  164 mtk_detect_cpuclk_mt7620(bus_space_tag_t bst, bus_space_handle_t bsh)
  165 {
  166         uint32_t val, mul, div, res;
  167 
  168         val = bus_space_read_4(bst, bsh, SYSCTL_MT7620_CPLL_CFG1);
  169         if (val & MT7620_CPU_CLK_AUX0)
  170                 return (MTK_CPU_CLK_480MHZ);
  171 
  172         val = bus_space_read_4(bst, bsh, SYSCTL_MT7620_CPLL_CFG0);
  173         if (!(val & MT7620_CPLL_SW_CFG))
  174                 return (MTK_CPU_CLK_600MHZ);
  175 
  176         mul = MT7620_PLL_MULT_RATIO_BASE + ((val >> MT7620_PLL_MULT_RATIO_OFF) &
  177             MT7620_PLL_MULT_RATIO_MSK);
  178         div = (val >> MT7620_PLL_DIV_RATIO_OFF) & MT7620_PLL_DIV_RATIO_MSK;
  179 
  180         if (div != MT7620_PLL_DIV_RATIO_MSK)
  181                 div += MT7620_PLL_DIV_RATIO_BASE;
  182         else
  183                 div = MT7620_PLL_DIV_RATIO_MAX;
  184 
  185         res = (MT7620_XTAL_40 * mul) / div;
  186 
  187         return (MTK_MHZ(res));
  188 }
  189 
  190 static uint32_t
  191 mtk_detect_cpuclk_mt7621(bus_space_tag_t bst, bus_space_handle_t bsh)
  192 {
  193         uint32_t val, div, res;
  194 
  195         val = bus_space_read_4(bst, bsh, SYSCTL_CLKCFG0);
  196         if (val & MT7621_USES_MEMDIV) {
  197                 div = bus_space_read_4(bst, bsh, MTK_MT7621_CLKDIV_REG);
  198                 div >>= MT7621_MEMDIV_OFF;
  199                 div &= MT7621_MEMDIV_MSK;
  200                 div += MT7621_MEMDIV_BASE;
  201 
  202                 val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
  203                 val >>= MT7621_CLKSEL_OFF;
  204                 val &= MT7621_CLKSEL_MSK;
  205 
  206                 if (val >= MT7621_CLKSEL_25MHZ_VAL)
  207                         res = div * MT7621_CLKSEL_25MHZ;
  208                 else if (val >= MT7621_CLKSEL_20MHZ_VAL)
  209                         res = div * MT7621_CLKSEL_20MHZ;
  210                 else
  211                         res = div * 0; /* XXX: not sure about this */
  212         } else {
  213                 val = bus_space_read_4(bst, bsh, SYSCTL_CUR_CLK_STS);
  214                 div = (val >> MT7621_CLK_STS_DIV_OFF) & MT7621_CLK_STS_MSK;
  215                 val &= MT7621_CLK_STS_MSK;
  216 
  217                 res = (MT7621_CLK_STS_BASE * val) / div;
  218         }
  219 
  220         return (MTK_MHZ(res));
  221 }
  222 
  223 static uint32_t
  224 mtk_detect_cpuclk_mt7628(bus_space_tag_t bst, bus_space_handle_t bsh)
  225 {
  226         uint32_t val;
  227 
  228         val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
  229         val >>= MT7628_CPU_CLKSEL_OFF;
  230         val &= MT7628_CPU_CLKSEL_MSK;
  231 
  232         if (val)
  233                 return (MTK_CPU_CLK_580MHZ);
  234 
  235         return (MTK_CPU_CLK_575MHZ);
  236 }
  237 
  238 void
  239 mtk_soc_try_early_detect(void)
  240 {
  241         bus_space_tag_t bst;
  242         bus_space_handle_t bsh;
  243         uint32_t base;
  244         phandle_t node;
  245         int i;
  246 
  247         if ((node = OF_finddevice("/")) == -1)
  248                 return;
  249 
  250         for (i = 0; compat_data[i].ocd_str != NULL; i++) {
  251                 if (fdt_is_compatible(node, compat_data[i].ocd_str)) {
  252                         mtk_soc_socid = compat_data[i].ocd_data;
  253                         break;
  254                 }
  255         }
  256 
  257         if (mtk_soc_socid == MTK_SOC_UNKNOWN) {
  258                 /* We don't know the SoC, so we don't know how to get clocks */
  259                 return;
  260         }
  261 
  262         bst = fdtbus_bs_tag;
  263         if (mtk_soc_socid == MTK_SOC_MT7621)
  264                 base = MTK_MT7621_BASE;
  265         else
  266                 base = MTK_DEFAULT_BASE;
  267 
  268         if (bus_space_map(bst, base, MTK_DEFAULT_SIZE, 0, &bsh))
  269                 return;
  270 
  271         /* First, figure out the CPU clock */
  272         switch (mtk_soc_socid) {
  273         case MTK_SOC_RT3050:  /* fallthrough */
  274         case MTK_SOC_RT3052:
  275         case MTK_SOC_RT3350:
  276                 mtk_soc_cpuclk = mtk_detect_cpuclk_rt305x(bst, bsh);
  277                 break;
  278         case MTK_SOC_RT3352:
  279                 mtk_soc_cpuclk = mtk_detect_cpuclk_rt3352(bst, bsh);
  280                 break;
  281         case MTK_SOC_RT3662:  /* fallthrough */
  282         case MTK_SOC_RT3883:
  283                 mtk_soc_cpuclk = mtk_detect_cpuclk_rt3883(bst, bsh);
  284                 break;
  285         case MTK_SOC_RT5350:
  286                 mtk_soc_cpuclk = mtk_detect_cpuclk_rt5350(bst, bsh);
  287                 break;
  288         case MTK_SOC_MT7620A: /* fallthrough */
  289         case MTK_SOC_MT7620N:
  290                 mtk_soc_cpuclk = mtk_detect_cpuclk_mt7620(bst, bsh);
  291                 break;
  292         case MTK_SOC_MT7621:
  293                 mtk_soc_cpuclk = mtk_detect_cpuclk_mt7621(bst, bsh);
  294                 break;
  295         case MTK_SOC_MT7628:  /* fallthrough */
  296         case MTK_SOC_MT7688:
  297                 mtk_soc_cpuclk = mtk_detect_cpuclk_mt7628(bst, bsh);
  298                 break;
  299         default:
  300                 /* We don't know the SoC, so we can't find the CPU clock */
  301                 break;
  302         }
  303 
  304         /* Now figure out the timer clock */
  305         if (mtk_soc_socid == MTK_SOC_MT7621) {
  306 #ifdef notyet
  307                 /* 
  308                  * We use the GIC timer for timing source and its clock freq is
  309                  * the same as the CPU's clock freq
  310                  */
  311                 mtk_soc_timerclk = mtk_soc_cpuclk;
  312 #else
  313                 /*
  314                  * When GIC timer and MIPS timer are ready to co-exist and
  315                  * GIC timer is actually implemented, we need to switch to it.
  316                  * Until then we use a fake GIC timer, which is actually a
  317                  * normal MIPS ticker, so the timer clock is half the CPU clock
  318                  */
  319                 mtk_soc_timerclk = mtk_soc_cpuclk / 2;
  320 #endif
  321         } else {
  322                 /*
  323                  * We use the MIPS ticker for the rest for now, so
  324                  * the CPU clock is divided by 2
  325                  */
  326                 mtk_soc_timerclk = mtk_soc_cpuclk / 2;
  327         }
  328 
  329         switch (mtk_soc_socid) {
  330         case MTK_SOC_RT3350:  /* fallthrough */
  331         case MTK_SOC_RT3050:  /* fallthrough */
  332         case MTK_SOC_RT3052:
  333                 /* UART clock is CPU clock / 3 */
  334                 mtk_soc_uartclk = mtk_soc_cpuclk / MTK_UARTDIV_3;
  335                 break;
  336         case MTK_SOC_RT3352:  /* fallthrough */
  337         case MTK_SOC_RT3662:  /* fallthrough */
  338         case MTK_SOC_RT3883:  /* fallthrough */
  339         case MTK_SOC_RT5350:  /* fallthrough */
  340         case MTK_SOC_MT7620A: /* fallthrough */
  341         case MTK_SOC_MT7620N: /* fallthrough */
  342         case MTK_SOC_MT7628:  /* fallthrough */
  343         case MTK_SOC_MT7688:
  344                 /* UART clock is always 40MHz */
  345                 mtk_soc_uartclk = MTK_UART_CLK_40MHZ;
  346                 break;
  347         case MTK_SOC_MT7621:
  348                 /* UART clock is always 50MHz */
  349                 mtk_soc_uartclk = MTK_UART_CLK_50MHZ;
  350                 break;
  351         default:
  352                 /* We don't know the SoC, so we don't know the UART clock */
  353                 break;
  354         }
  355 
  356         bus_space_unmap(bst, bsh, MTK_DEFAULT_SIZE);
  357 }
  358 
  359 uint32_t
  360 mtk_soc_get_uartclk(void)
  361 {
  362 
  363         return mtk_soc_uartclk;
  364 }
  365 
  366 uint32_t
  367 mtk_soc_get_cpuclk(void)
  368 {
  369 
  370         return mtk_soc_cpuclk;
  371 }
  372 
  373 uint32_t
  374 mtk_soc_get_timerclk(void)
  375 {
  376 
  377         return mtk_soc_timerclk;
  378 }
  379 
  380 uint32_t
  381 mtk_soc_get_socid(void)
  382 {
  383 
  384         return mtk_soc_socid;
  385 }
  386 
  387 /*
  388  * The following are generic reset and clock functions
  389  */
  390 
  391 /* Default reset time is 100ms */
  392 #define DEFAULT_RESET_TIME      100000
  393 
  394 int
  395 mtk_soc_reset_device(device_t dev)
  396 {
  397         int res;
  398 
  399         res = fdt_reset_assert_all(dev);
  400         if (res == 0) {
  401                 DELAY(DEFAULT_RESET_TIME);
  402                 res = fdt_reset_deassert_all(dev);
  403                 if (res == 0)
  404                         DELAY(DEFAULT_RESET_TIME);
  405         }
  406 
  407         return (res);
  408 }
  409 
  410 int
  411 mtk_soc_stop_clock(device_t dev)
  412 {
  413 
  414         return (fdt_clock_disable_all(dev));
  415 }
  416 
  417 int
  418 mtk_soc_start_clock(device_t dev)
  419 {
  420 
  421         return (fdt_clock_enable_all(dev));
  422 }
  423 
  424 int
  425 mtk_soc_assert_reset(device_t dev)
  426 {
  427 
  428         return (fdt_reset_assert_all(dev));
  429 }
  430 
  431 int
  432 mtk_soc_deassert_reset(device_t dev)
  433 {
  434 
  435         return (fdt_reset_deassert_all(dev));
  436 }
  437 
  438 void
  439 mtk_soc_reset(void)
  440 {
  441 
  442         mtk_sysctl_clr_set(SYSCTL_RSTCTRL, 0, 1);
  443         mtk_sysctl_clr_set(SYSCTL_RSTCTRL, 1, 0);
  444 }

Cache object: 9c1f659c1dacfefd8639d16e90d8af7d


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