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/nvidia/tegra_soctherm.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 Michal Meloun <mmel@FreeBSD.org>
    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$");
   29 
   30 /*
   31  * Thermometer and thermal zones driver for Tegra SoCs.
   32  * Calibration data and algo are taken from Linux, because this part of SoC
   33  * is undocumented in TRM.
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/gpio.h>
   40 #include <sys/kernel.h>
   41 #include <sys/module.h>
   42 #include <sys/malloc.h>
   43 #include <sys/rman.h>
   44 #include <sys/sysctl.h>
   45 
   46 #include <machine/bus.h>
   47 
   48 #include <dev/extres/clk/clk.h>
   49 #include <dev/extres/hwreset/hwreset.h>
   50 #include <dev/ofw/ofw_bus.h>
   51 #include <dev/ofw/ofw_bus_subr.h>
   52 
   53 #include <arm/nvidia/tegra_efuse.h>
   54 #include <dt-bindings/thermal/tegra124-soctherm.h>
   55 #include "tegra_soctherm_if.h"
   56 
   57 /* Per sensors registers - base is 0x0c0*/
   58 #define TSENSOR_CONFIG0                         0x000
   59 #define  TSENSOR_CONFIG0_TALL(x)                        (((x) & 0xFFFFF) << 8)
   60 #define  TSENSOR_CONFIG0_STATUS_CLR                     (1 << 5)
   61 #define  TSENSOR_CONFIG0_TCALC_OVERFLOW                 (1 << 4)
   62 #define  TSENSOR_CONFIG0_OVERFLOW                       (1 << 3)
   63 #define  TSENSOR_CONFIG0_CPTR_OVERFLOW                  (1 << 2)
   64 #define  TSENSOR_CONFIG0_RO_SEL                         (1 << 1)
   65 #define  TSENSOR_CONFIG0_STOP                           (1 << 0)
   66 
   67 #define TSENSOR_CONFIG1                         0x004
   68 #define  TSENSOR_CONFIG1_TEMP_ENABLE                    (1U << 31)
   69 #define  TSENSOR_CONFIG1_TEN_COUNT(x)                   (((x) & 0x3F) << 24)
   70 #define  TSENSOR_CONFIG1_TIDDQ_EN(x)                    (((x) & 0x3F) << 15)
   71 #define  TSENSOR_CONFIG1_TSAMPLE(x)                     (((x) & 0x3FF) << 0)
   72 
   73 #define TSENSOR_CONFIG2                         0x008
   74 #define TSENSOR_CONFIG2_THERMA(x)                       (((x) & 0xFFFF) << 16)
   75 #define TSENSOR_CONFIG2_THERMB(x)                       (((x) & 0xFFFF) << 0)
   76 
   77 #define TSENSOR_STATUS0                         0x00c
   78 #define  TSENSOR_STATUS0_CAPTURE_VALID                  (1U << 31)
   79 #define  TSENSOR_STATUS0_CAPTURE(x)                     (((x) >> 0) & 0xffff)
   80 
   81 #define TSENSOR_STATUS1                         0x010
   82 #define  TSENSOR_STATUS1_TEMP_VALID                     (1U << 31)
   83 #define  TSENSOR_STATUS1_TEMP(x)                        (((x) >> 0) & 0xffff)
   84 
   85 #define TSENSOR_STATUS2                         0x014
   86 #define  TSENSOR_STATUS2_TEMP_MAX(x)                    (((x) >> 16) & 0xffff)
   87 #define  TSENSOR_STATUS2_TEMP_MIN(x)                    (((x) >>  0) & 0xffff)
   88 
   89 
   90 /* Readbacks */
   91 #define READBACK_VALUE(x)                               (((x) >> 8) & 0xff)
   92 #define READBACK_ADD_HALF                               (1 << 7)
   93 #define READBACK_NEGATE                                 (1 << 0)
   94 
   95 /* Global registers */
   96 #define TSENSOR_PDIV                            0x1c0
   97 #define TSENSOR_HOTSPOT_OFF                     0x1c4
   98 #define TSENSOR_TEMP1                           0x1c8
   99 #define TSENSOR_TEMP2                           0x1cc
  100 
  101 /* Fuses */
  102 #define  FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT            0
  103 #define  FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS             13
  104 #define  FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT            13
  105 #define  FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS             13
  106 
  107 /* Layout is different for Tegra124 and Tegra210 */
  108 #define FUSE_TSENSOR_COMMON                     0x180
  109 #define  TEGRA124_FUSE_COMMON_CP_TS_BASE(x)             (((x) >>  0) & 0x3ff)
  110 #define  TEGRA124_FUSE_COMMON_FT_TS_BASE(x)             (((x) >> 10) & 0x7ff)
  111 #define  TEGRA124_FUSE_COMMON_SHIFT_FT_SHIFT            21
  112 #define  TEGRA124_FUSE_COMMON_SHIFT_FT_BITS             5
  113 
  114 #define  TEGRA210_FUSE_COMMON_CP_TS_BASE(x)             (((x) >>  11) & 0x3ff)
  115 #define  TEGRA210_FUSE_COMMON_FT_TS_BASE(x)             (((x) >> 21) & 0x7ff)
  116 #define  TEGRA210_FUSE_COMMON_SHIFT_CP_SHIFT            0
  117 #define  TEGRA210_FUSE_COMMON_SHIFT_CP_BITS             6
  118 #define  TEGRA210_FUSE_COMMON_SHIFT_FT_SHIFT            6
  119 #define  TEGRA210_FUSE_COMMON_SHIFT_FT_BITS             5
  120 
  121 
  122 /* Only for Tegra124 */
  123 #define FUSE_SPARE_REALIGNMENT_REG              0x1fc
  124 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT      0
  125 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS       6
  126 
  127 #define TEGRA124_NOMINAL_CALIB_FT       105
  128 #define TEGRA124_NOMINAL_CALIB_CP       25
  129 
  130 #define TEGRA210_NOMINAL_CALIB_FT       105
  131 #define TEGRA210_NOMINAL_CALIB_CP       25
  132 
  133 #define WR4(_sc, _r, _v)        bus_write_4((_sc)->mem_res, (_r), (_v))
  134 #define RD4(_sc, _r)            bus_read_4((_sc)->mem_res, (_r))
  135 
  136 static struct sysctl_ctx_list soctherm_sysctl_ctx;
  137 
  138 struct tsensor_cfg {
  139         uint32_t                tall;
  140         uint32_t                tsample;
  141         uint32_t                tiddq_en;
  142         uint32_t                ten_count;
  143         uint32_t                pdiv;
  144         uint32_t                tsample_ate;
  145         uint32_t                pdiv_ate;
  146 };
  147 
  148 struct soctherm_shared_cal {
  149         uint32_t                base_cp;
  150         uint32_t                base_ft;
  151         int32_t                 actual_temp_cp;
  152         int32_t                 actual_temp_ft;
  153 };
  154 
  155 struct tsensor {
  156         char                    *name;
  157         int                     id;
  158         bus_addr_t              sensor_base;
  159         bus_addr_t              calib_fuse;
  160         int                     fuse_corr_alpha;
  161         int                     fuse_corr_beta;
  162 
  163         int16_t                 therm_a;
  164         int16_t                 therm_b;
  165 };
  166 
  167 struct soctherm_soc;
  168 struct soctherm_softc {
  169         device_t                dev;
  170         struct resource         *mem_res;
  171         struct resource         *irq_res;
  172         void                    *irq_ih;
  173 
  174         clk_t                   tsensor_clk;
  175         clk_t                   soctherm_clk;
  176         hwreset_t               reset;
  177 
  178         struct soctherm_soc     *soc;
  179         struct soctherm_shared_cal shared_cal;
  180 };
  181 
  182 struct soctherm_soc {
  183         void                    (*shared_cal)(struct soctherm_softc *sc);
  184         uint32_t                tsensor_pdiv;
  185         uint32_t                tsensor_hotspot_off;
  186         struct tsensor_cfg      *tsensor_cfg;
  187         struct tsensor          *tsensors;
  188         int                     ntsensors;
  189 };
  190 
  191 /* Tegra124 config */
  192 
  193 static struct tsensor_cfg t124_tsensor_config = {
  194         .tall = 16300,
  195         .tsample = 120,
  196         .tiddq_en = 1,
  197         .ten_count = 1,
  198         .pdiv = 8,
  199         .tsample_ate = 480,
  200         .pdiv_ate = 8
  201 };
  202 
  203 static struct tsensor t124_tsensors[] = {
  204         {
  205                 .name = "cpu0",
  206                 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
  207                 .sensor_base = 0x0c0,
  208                 .calib_fuse = 0x098,
  209                 .fuse_corr_alpha = 1135400,
  210                 .fuse_corr_beta = -6266900,
  211         },
  212         {
  213                 .name = "cpu1",
  214                 .id = -1,
  215                 .sensor_base = 0x0e0,
  216                 .calib_fuse = 0x084,
  217                 .fuse_corr_alpha = 1122220,
  218                 .fuse_corr_beta = -5700700,
  219         },
  220         {
  221                 .name = "cpu2",
  222                 .id = -1,
  223                 .sensor_base = 0x100,
  224                 .calib_fuse = 0x088,
  225                 .fuse_corr_alpha = 1127000,
  226                 .fuse_corr_beta = -6768200,
  227         },
  228         {
  229                 .name = "cpu3",
  230                 .id = -1,
  231                 .sensor_base = 0x120,
  232                 .calib_fuse = 0x12c,
  233                 .fuse_corr_alpha = 1110900,
  234                 .fuse_corr_beta = -6232000,
  235         },
  236         {
  237                 .name = "mem0",
  238                 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
  239                 .sensor_base = 0x140,
  240                 .calib_fuse = 0x158,
  241                 .fuse_corr_alpha = 1122300,
  242                 .fuse_corr_beta = -5936400,
  243         },
  244         {
  245                 .name = "mem1",
  246                 .id = -1,
  247                 .sensor_base = 0x160,
  248                 .calib_fuse = 0x15c,
  249                 .fuse_corr_alpha = 1145700,
  250                 .fuse_corr_beta = -7124600,
  251         },
  252         {
  253                 .name = "gpu",
  254                 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
  255                 .sensor_base = 0x180,
  256                 .calib_fuse = 0x154,
  257                 .fuse_corr_alpha = 1120100,
  258                 .fuse_corr_beta = -6000500,
  259         },
  260         {
  261                 .name = "pllX",
  262                 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
  263                 .sensor_base = 0x1a0,
  264                 .calib_fuse = 0x160,
  265                 .fuse_corr_alpha = 1106500,
  266                 .fuse_corr_beta = -6729300,
  267         },
  268 };
  269 
  270 static void tegra124_shared_cal(struct soctherm_softc *sc);
  271 
  272 static struct soctherm_soc tegra124_soc = {
  273         .shared_cal = tegra124_shared_cal,
  274         .tsensor_pdiv = 0x8888,
  275         .tsensor_hotspot_off = 0x00060600 ,
  276         .tsensor_cfg = &t124_tsensor_config,
  277         .tsensors = t124_tsensors,
  278         .ntsensors = nitems(t124_tsensors),
  279 };
  280 
  281 /* Tegra210 config */
  282 static struct tsensor_cfg t210_tsensor_config = {
  283         .tall = 16300,
  284         .tsample = 120,
  285         .tiddq_en = 1,
  286         .ten_count = 1,
  287         .pdiv = 8,
  288         .tsample_ate = 480,
  289         .pdiv_ate = 8
  290 };
  291 
  292 static struct tsensor t210_tsensors[] = {
  293         {
  294                 .name = "cpu0",
  295                 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
  296                 .sensor_base = 0x0c0,
  297                 .calib_fuse = 0x098,
  298                 .fuse_corr_alpha = 1085000,
  299                 .fuse_corr_beta = 3244200,
  300         },
  301         {
  302                 .name = "cpu1",
  303                 .id = -1,
  304                 .sensor_base = 0x0e0,
  305                 .calib_fuse = 0x084,
  306                 .fuse_corr_alpha = 1126200,
  307                 .fuse_corr_beta = -67500,
  308         },
  309         {
  310                 .name = "cpu2",
  311                 .id = -1,
  312                 .sensor_base = 0x100,
  313                 .calib_fuse = 0x088,
  314                 .fuse_corr_alpha = 1098400,
  315                 .fuse_corr_beta = 2251100,
  316         },
  317         {
  318                 .name = "cpu3",
  319                 .id = -1,
  320                 .sensor_base = 0x120,
  321                 .calib_fuse = 0x12c,
  322                 .fuse_corr_alpha = 1108000,
  323                 .fuse_corr_beta = 602700,
  324         },
  325         {
  326                 .name = "mem0",
  327                 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
  328                 .sensor_base = 0x140,
  329                 .calib_fuse = 0x158,
  330                 .fuse_corr_alpha = 1069200,
  331                 .fuse_corr_beta = 3549900,
  332         },
  333         {
  334                 .name = "mem1",
  335                 .id = -1,
  336                 .sensor_base = 0x160,
  337                 .calib_fuse = 0x15c,
  338                 .fuse_corr_alpha = 1173700,
  339                 .fuse_corr_beta = -6263600,
  340         },
  341         {
  342                 .name = "gpu",
  343                 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
  344                 .sensor_base = 0x180,
  345                 .calib_fuse = 0x154,
  346                 .fuse_corr_alpha = 1074300,
  347                 .fuse_corr_beta = 2734900,
  348         },
  349         {
  350                 .name = "pllX",
  351                 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
  352                 .sensor_base = 0x1a0,
  353                 .calib_fuse = 0x160,
  354                 .fuse_corr_alpha = 1039700,
  355                 .fuse_corr_beta = 6829100,
  356         },
  357 };
  358 
  359 static void tegra210_shared_cal(struct soctherm_softc *sc);
  360 
  361 static struct soctherm_soc tegra210_soc = {
  362         .shared_cal = tegra210_shared_cal,
  363         .tsensor_pdiv = 0x8888,
  364         .tsensor_hotspot_off = 0x000A0500 ,
  365         .tsensor_cfg = &t210_tsensor_config,
  366         .tsensors = t210_tsensors,
  367         .ntsensors = nitems(t210_tsensors),
  368 };
  369 
  370 static struct ofw_compat_data compat_data[] = {
  371         {"nvidia,tegra124-soctherm", (uintptr_t)&tegra124_soc},
  372         {"nvidia,tegra210-soctherm", (uintptr_t)&tegra210_soc},
  373         {NULL,                          0},
  374 };
  375 
  376 /* Extract signed integer bitfield from register */
  377 static int
  378 extract_signed(uint32_t reg, int shift, int bits)
  379 {
  380         int32_t val;
  381         uint32_t mask;
  382 
  383         mask = (1 << bits) - 1;
  384         val = ((reg >> shift) & mask) << (32 - bits);
  385         val >>= 32 - bits;
  386         return ((int32_t)val);
  387 }
  388 
  389 static inline
  390 int64_t div64_s64_precise(int64_t a, int64_t b)
  391 {
  392         int64_t r, al;
  393 
  394         al = a << 16;
  395         r = (al * 2 + 1) / (2 * b);
  396         return (r >> 16);
  397 }
  398 
  399 static void
  400 tegra124_shared_cal(struct soctherm_softc *sc)
  401 {
  402         uint32_t val;
  403         int calib_cp, calib_ft;
  404         struct soctherm_shared_cal *cal;
  405 
  406         cal = &sc->shared_cal;
  407         val = tegra_fuse_read_4(FUSE_TSENSOR_COMMON);
  408         cal->base_cp = TEGRA124_FUSE_COMMON_CP_TS_BASE(val);
  409         cal->base_ft = TEGRA124_FUSE_COMMON_FT_TS_BASE(val);
  410 
  411         calib_ft = extract_signed(val,
  412             TEGRA124_FUSE_COMMON_SHIFT_FT_SHIFT,
  413             TEGRA124_FUSE_COMMON_SHIFT_FT_BITS);
  414 
  415         val = tegra_fuse_read_4(FUSE_SPARE_REALIGNMENT_REG);
  416         calib_cp = extract_signed(val,
  417             FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT,
  418             FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS);
  419 
  420         cal->actual_temp_cp = 2 * TEGRA124_NOMINAL_CALIB_CP + calib_cp;
  421         cal->actual_temp_ft = 2 * TEGRA124_NOMINAL_CALIB_FT + calib_ft;
  422 #ifdef DEBUG
  423         printf("%s: base_cp: %u, base_ft: %d,"
  424             " actual_temp_cp: %d, actual_temp_ft: %d\n",
  425             __func__, cal->base_cp, cal->base_ft,
  426             cal->actual_temp_cp, cal->actual_temp_ft);
  427 #endif
  428 }
  429 
  430 static void
  431 tegra210_shared_cal(struct soctherm_softc *sc)
  432 {
  433         uint32_t val;
  434         int calib_cp, calib_ft;
  435         struct soctherm_shared_cal *cal;
  436 
  437         cal = &sc->shared_cal;
  438 
  439         val = tegra_fuse_read_4(FUSE_TSENSOR_COMMON);
  440         cal->base_cp = TEGRA210_FUSE_COMMON_CP_TS_BASE(val);
  441         cal->base_ft = TEGRA210_FUSE_COMMON_FT_TS_BASE(val);
  442 
  443         calib_ft = extract_signed(val,
  444             TEGRA210_FUSE_COMMON_SHIFT_FT_SHIFT,
  445             TEGRA210_FUSE_COMMON_SHIFT_FT_BITS);
  446         calib_cp = extract_signed(val,
  447             TEGRA210_FUSE_COMMON_SHIFT_CP_SHIFT,
  448             TEGRA210_FUSE_COMMON_SHIFT_CP_BITS);
  449 
  450         cal->actual_temp_cp = 2 * TEGRA210_NOMINAL_CALIB_CP + calib_cp;
  451         cal->actual_temp_ft = 2 * TEGRA210_NOMINAL_CALIB_FT + calib_ft;
  452 #ifdef DEBUG
  453         printf("%s: base_cp: %u, base_ft: %d,"
  454             " actual_temp_cp: %d, actual_temp_ft: %d\n",
  455             __func__, cal->base_cp, cal->base_ft,
  456             cal->actual_temp_cp, cal->actual_temp_ft);
  457 #endif
  458 }
  459 
  460 static void
  461 tsensor_calibration(struct soctherm_softc *sc, struct tsensor *sensor)
  462 {
  463         uint32_t val;
  464         int mult, div, calib_cp, calib_ft;
  465         int actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp;
  466         int temp_a, temp_b;
  467         struct tsensor_cfg *cfg;
  468         struct soctherm_shared_cal *cal;
  469         int64_t tmp;
  470 
  471         cfg = sc->soc->tsensor_cfg;
  472         cal = &sc->shared_cal;
  473 
  474         val =  tegra_fuse_read_4(sensor->calib_fuse);
  475         calib_cp = extract_signed(val,
  476             FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT,
  477             FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS);
  478         actual_tsensor_cp = cal->base_cp * 64 + calib_cp;
  479 
  480         calib_ft = extract_signed(val,
  481             FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT,
  482             FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS);
  483         actual_tsensor_ft = cal->base_ft * 32 + calib_ft;
  484 
  485         delta_sens = actual_tsensor_ft - actual_tsensor_cp;
  486         delta_temp = cal->actual_temp_ft - cal->actual_temp_cp;
  487         mult = cfg->pdiv * cfg->tsample_ate;
  488         div = cfg->tsample * cfg->pdiv_ate;
  489 
  490         temp_a = div64_s64_precise((int64_t) delta_temp * (1LL << 13) * mult,
  491                                    (int64_t) delta_sens * div);
  492 
  493         tmp = (int64_t)actual_tsensor_ft * cal->actual_temp_cp -
  494               (int64_t)actual_tsensor_cp * cal->actual_temp_ft;
  495         temp_b = div64_s64_precise(tmp, (int64_t)delta_sens);
  496 
  497         temp_a = div64_s64_precise((int64_t)temp_a * sensor->fuse_corr_alpha,
  498                                    1000000);
  499         temp_b = div64_s64_precise((int64_t)temp_b * sensor->fuse_corr_alpha +
  500                                    sensor->fuse_corr_beta, 1000000);
  501         sensor->therm_a = (int16_t)temp_a;
  502         sensor->therm_b = (int16_t)temp_b;
  503 #ifdef DEBUG
  504         printf("%s: sensor %s fuse: 0x%08X (0x%04X, 0x%04X)"
  505             " calib_cp: %d(0x%04X), calib_ft: %d(0x%04X)\n",
  506             __func__, sensor->name, val, val & 0x1FFF, (val >> 13) & 0x1FFF,
  507             calib_cp, calib_cp, calib_ft, calib_ft);
  508         printf("therma: 0x%04X(%d), thermb: 0x%04X(%d)\n",
  509             (uint16_t)sensor->therm_a, sensor->therm_a,
  510             (uint16_t)sensor->therm_b, sensor->therm_b);
  511 #endif
  512 }
  513 
  514 static void
  515 soctherm_init_tsensor(struct soctherm_softc *sc, struct tsensor *sensor)
  516 {
  517         struct tsensor_cfg *cfg;
  518         uint32_t val;
  519 
  520         cfg = sc->soc->tsensor_cfg;
  521         tsensor_calibration(sc, sensor);
  522 
  523         val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
  524         val |= TSENSOR_CONFIG0_STOP;
  525         val |= TSENSOR_CONFIG0_STATUS_CLR;
  526         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
  527 
  528         val = TSENSOR_CONFIG0_TALL(cfg->tall);
  529         val |= TSENSOR_CONFIG0_STOP;
  530         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
  531 
  532         val = TSENSOR_CONFIG1_TSAMPLE(cfg->tsample - 1);
  533         val |= TSENSOR_CONFIG1_TIDDQ_EN(cfg->tiddq_en);
  534         val |= TSENSOR_CONFIG1_TEN_COUNT(cfg->ten_count);
  535         val |= TSENSOR_CONFIG1_TEMP_ENABLE;
  536         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG1, val);
  537 
  538         val = TSENSOR_CONFIG2_THERMA((uint16_t)sensor->therm_a) |
  539              TSENSOR_CONFIG2_THERMB((uint16_t)sensor->therm_b);
  540         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG2, val);
  541 
  542         val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
  543         val &= ~TSENSOR_CONFIG0_STOP;
  544         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
  545 #ifdef DEBUG
  546         printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
  547             " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
  548             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
  549             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
  550             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
  551             RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
  552             RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
  553             RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
  554             );
  555 #endif
  556 }
  557 
  558 static int
  559 soctherm_convert_raw(uint32_t val)
  560 {
  561         int32_t t;
  562 
  563         t = READBACK_VALUE(val) * 1000;
  564         if (val & READBACK_ADD_HALF)
  565                 t += 500;
  566         if (val & READBACK_NEGATE)
  567                 t *= -1;
  568 
  569         return (t);
  570 }
  571 
  572 static int
  573 soctherm_read_temp(struct soctherm_softc *sc, struct tsensor *sensor, int *temp)
  574 {
  575         int timeout;
  576         uint32_t val;
  577 
  578         /* wait for valid sample */
  579         for (timeout = 100; timeout > 0; timeout--) {
  580                 val = RD4(sc, sensor->sensor_base + TSENSOR_STATUS1);
  581                 if ((val & TSENSOR_STATUS1_TEMP_VALID) != 0)
  582                         break;
  583                 DELAY(100);
  584         }
  585         if (timeout <= 0)
  586                 device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
  587         *temp = soctherm_convert_raw(val);
  588 #ifdef DEBUG
  589         printf("%s: Raw: 0x%08X, temp: %d\n", __func__, val, *temp);
  590         printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
  591             " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
  592             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
  593             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
  594             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
  595             RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
  596             RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
  597             RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
  598             );
  599 #endif
  600         return (0);
  601 }
  602 
  603 static int
  604 soctherm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
  605 {
  606         struct soctherm_softc *sc;
  607         int i;
  608 
  609         sc = device_get_softc(dev);
  610         /* The direct sensor map starts at 0x100 */
  611         if (id >= 0x100) {
  612                 id -= 0x100;
  613                 if (id >= sc->soc->ntsensors)
  614                         return (ERANGE);
  615                 return(soctherm_read_temp(sc, sc->soc->tsensors + id, val));
  616         }
  617         /* Linux (DT) compatible thermal zones */
  618         for (i = 0; i < sc->soc->ntsensors; i++) {
  619                 if (sc->soc->tsensors->id == id) {
  620                         return(soctherm_read_temp(sc, sc->soc->tsensors + id,
  621                             val));
  622                 }
  623         }
  624         return (ERANGE);
  625 }
  626 
  627 static int
  628 soctherm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
  629 {
  630         struct soctherm_softc *sc;
  631         int val;
  632         int rv;
  633         int id;
  634 
  635         /* Write request */
  636         if (req->newptr != NULL)
  637                 return (EINVAL);
  638 
  639         sc = arg1;
  640         id = arg2;
  641 
  642         if (id >= sc->soc->ntsensors)
  643                 return (ERANGE);
  644         rv =  soctherm_read_temp(sc, sc->soc->tsensors + id, &val);
  645         if (rv != 0)
  646                 return (rv);
  647 
  648         val = val / 100;
  649         val +=  2731;
  650         rv = sysctl_handle_int(oidp, &val, 0, req);
  651         return (rv);
  652 }
  653 
  654 static int
  655 soctherm_init_sysctl(struct soctherm_softc *sc)
  656 {
  657         int i;
  658         struct sysctl_oid *oid, *tmp;
  659 
  660         sysctl_ctx_init(&soctherm_sysctl_ctx);
  661         /* create node for hw.temp */
  662         oid = SYSCTL_ADD_NODE(&soctherm_sysctl_ctx,
  663             SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
  664             CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
  665         if (oid == NULL)
  666                 return (ENXIO);
  667 
  668         /* Add sensors */
  669         for (i = sc->soc->ntsensors  - 1; i >= 0; i--) {
  670                 tmp = SYSCTL_ADD_PROC(&soctherm_sysctl_ctx,
  671                     SYSCTL_CHILDREN(oid), OID_AUTO, sc->soc->tsensors[i].name,
  672                     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, i,
  673                     soctherm_sysctl_temperature, "IK", "SoC Temperature");
  674                 if (tmp == NULL)
  675                         return (ENXIO);
  676         }
  677 
  678         return (0);
  679 }
  680 
  681 static int
  682 soctherm_probe(device_t dev)
  683 {
  684 
  685         if (!ofw_bus_status_okay(dev))
  686                 return (ENXIO);
  687 
  688         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  689                 return (ENXIO);
  690 
  691         device_set_desc(dev, "Tegra temperature sensors");
  692         return (BUS_PROBE_DEFAULT);
  693 }
  694 
  695 static int
  696 soctherm_attach(device_t dev)
  697 {
  698         struct soctherm_softc *sc;
  699         phandle_t node;
  700         int i, rid, rv;
  701 
  702         sc = device_get_softc(dev);
  703         sc->dev = dev;
  704         sc->soc = (struct soctherm_soc *)ofw_bus_search_compatible(dev,
  705            compat_data)->ocd_data;
  706         node = ofw_bus_get_node(sc->dev);
  707 
  708         rid = 0;
  709         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  710             RF_ACTIVE);
  711         if (sc->mem_res == NULL) {
  712                 device_printf(dev, "Cannot allocate memory resources\n");
  713                 goto fail;
  714         }
  715 
  716         rid = 0;
  717         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
  718         if (sc->irq_res == NULL) {
  719                 device_printf(dev, "Cannot allocate IRQ resources\n");
  720                 goto fail;
  721         }
  722 
  723 /*
  724         if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
  725             soctherm_intr, NULL, sc, &sc->irq_ih))) {
  726                 device_printf(dev,
  727                     "WARNING: unable to register interrupt handler\n");
  728                 goto fail;
  729         }
  730 */
  731 
  732         /* OWF resources */
  733         rv = hwreset_get_by_ofw_name(dev, 0, "soctherm", &sc->reset);
  734         if (rv != 0) {
  735                 device_printf(dev, "Cannot get fuse reset\n");
  736                 goto fail;
  737         }
  738         rv = clk_get_by_ofw_name(dev, 0, "tsensor", &sc->tsensor_clk);
  739         if (rv != 0) {
  740                 device_printf(dev, "Cannot get 'tsensor' clock: %d\n", rv);
  741                 goto fail;
  742         }
  743         rv = clk_get_by_ofw_name(dev, 0, "soctherm", &sc->soctherm_clk);
  744         if (rv != 0) {
  745                 device_printf(dev, "Cannot get 'soctherm' clock: %d\n", rv);
  746                 goto fail;
  747         }
  748 
  749         rv = hwreset_assert(sc->reset);
  750         if (rv != 0) {
  751                 device_printf(dev, "Cannot assert reset\n");
  752                 goto fail;
  753         }
  754         rv = clk_enable(sc->tsensor_clk);
  755         if (rv != 0) {
  756                 device_printf(dev, "Cannot enable 'tsensor' clock: %d\n", rv);
  757                 goto fail;
  758         }
  759         rv = clk_enable(sc->soctherm_clk);
  760         if (rv != 0) {
  761                 device_printf(dev, "Cannot enable 'soctherm' clock: %d\n", rv);
  762                 goto fail;
  763         }
  764         rv = hwreset_deassert(sc->reset);
  765         if (rv != 0) {
  766                 device_printf(dev, "Cannot clear reset\n");
  767                 goto fail;
  768         }
  769 
  770         sc->soc->shared_cal(sc);
  771 
  772         WR4(sc, TSENSOR_PDIV, sc->soc->tsensor_pdiv);
  773         WR4(sc, TSENSOR_HOTSPOT_OFF, sc->soc->tsensor_hotspot_off);
  774 
  775         for (i = 0; i < sc->soc->ntsensors; i++)
  776                 soctherm_init_tsensor(sc, sc->soc->tsensors + i);
  777 
  778         rv = soctherm_init_sysctl(sc);
  779         if (rv != 0) {
  780                 device_printf(sc->dev, "Cannot initialize sysctls\n");
  781                 goto fail;
  782         }
  783 
  784         OF_device_register_xref(OF_xref_from_node(node), dev);
  785         return (bus_generic_attach(dev));
  786 
  787 fail:
  788         if (sc->irq_ih != NULL)
  789                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
  790         sysctl_ctx_free(&soctherm_sysctl_ctx);
  791         if (sc->tsensor_clk != NULL)
  792                 clk_release(sc->tsensor_clk);
  793         if (sc->soctherm_clk != NULL)
  794                 clk_release(sc->soctherm_clk);
  795         if (sc->reset != NULL)
  796                 hwreset_release(sc->reset);
  797         if (sc->irq_res != NULL)
  798                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  799         if (sc->mem_res != NULL)
  800                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  801 
  802         return (ENXIO);
  803 }
  804 
  805 static int
  806 soctherm_detach(device_t dev)
  807 {
  808         struct soctherm_softc *sc;
  809         sc = device_get_softc(dev);
  810 
  811         if (sc->irq_ih != NULL)
  812                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
  813         sysctl_ctx_free(&soctherm_sysctl_ctx);
  814         if (sc->tsensor_clk != NULL)
  815                 clk_release(sc->tsensor_clk);
  816         if (sc->soctherm_clk != NULL)
  817                 clk_release(sc->soctherm_clk);
  818         if (sc->reset != NULL)
  819                 hwreset_release(sc->reset);
  820         if (sc->irq_res != NULL)
  821                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  822         if (sc->mem_res != NULL)
  823                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  824 
  825         return (ENXIO);
  826 }
  827 
  828 static device_method_t tegra_soctherm_methods[] = {
  829         /* Device interface */
  830         DEVMETHOD(device_probe,                 soctherm_probe),
  831         DEVMETHOD(device_attach,                soctherm_attach),
  832         DEVMETHOD(device_detach,                soctherm_detach),
  833 
  834         /* SOCTHERM interface */
  835         DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
  836 
  837         DEVMETHOD_END
  838 };
  839 
  840 static devclass_t tegra_soctherm_devclass;
  841 static DEFINE_CLASS_0(soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
  842     sizeof(struct soctherm_softc));
  843 EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,
  844     tegra_soctherm_devclass, NULL, NULL, 79);

Cache object: bbc3425539113c74b7b56f4cc97db93f


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