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/arm64/qoriq/qoriq_therm.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  *
    3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    4  *
    5  * Copyright  2020 Michal Meloun <mmel@FreeBSD.org>
    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 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /*
   33  * Thermometer driver for QorIQ  SoCs.
   34  */
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 #include <sys/endian.h>
   39 #include <sys/kernel.h>
   40 #include <sys/module.h>
   41 #include <sys/malloc.h>
   42 #include <sys/rman.h>
   43 #include <sys/sysctl.h>
   44 
   45 #include <machine/bus.h>
   46 
   47 #include <dev/extres/clk/clk.h>
   48 #include <dev/ofw/ofw_bus.h>
   49 #include <dev/ofw/ofw_bus_subr.h>
   50 
   51 #include "qoriq_therm_if.h"
   52 
   53 #define TMU_TMR         0x00
   54 #define TMU_TSR         0x04
   55 #define TMUV1_TMTMIR    0x08
   56 #define TMUV2_TMSR      0x08
   57 #define TMUV2_TMTMIR    0x0C
   58 #define TMU_TIER        0x20
   59 #define TMU_TTCFGR      0x80
   60 #define TMU_TSCFGR      0x84
   61 #define TMU_TRITSR(x)   (0x100 + (16 * (x)))
   62 #define  TMU_TRITSR_VALID       (1U << 31)
   63 #define TMUV2_TMSAR(x)  (0x304 + (16 * (x)))
   64 #define TMU_VERSION     0xBF8                   /* not in TRM */
   65 #define TMUV2_TEUMR(x)  (0xF00 + (4 * (x)))
   66 #define TMU_TTRCR(x)    (0xF10 + (4 * (x)))
   67 
   68 
   69 struct tsensor {
   70         int                     site_id;
   71         char                    *name;
   72         int                     id;
   73 };
   74 
   75 struct qoriq_therm_softc {
   76         device_t                dev;
   77         struct resource         *mem_res;
   78         struct resource         *irq_res;
   79         void                    *irq_ih;
   80         int                     ntsensors;
   81         struct tsensor          *tsensors;
   82         bool                    little_endian;
   83         clk_t                   clk;
   84         int                     ver;
   85 };
   86 
   87 static struct sysctl_ctx_list qoriq_therm_sysctl_ctx;
   88 
   89 struct tsensor default_sensors[] =
   90 {
   91         { 0,    "site0",                0 },
   92         { 1,    "site1",                1 },
   93         { 2,    "site2",                2 },
   94         { 3,    "site3",                3 },
   95         { 4,    "site4",                4 },
   96         { 5,    "site5",                5 },
   97         { 6,    "site6",                6 },
   98         { 7,    "site7",                7 },
   99         { 8,    "site8",                8 },
  100         { 9,    "site9",                9 },
  101         { 10,   "site10",               10 },
  102         { 11,   "site11",               11 },
  103         { 12,   "site12",               12 },
  104         { 13,   "site13",               13 },
  105         { 14,   "site14",               14 },
  106         { 15,   "site15",               15 },
  107 };
  108 
  109 static struct tsensor imx8mq_sensors[] =
  110 {
  111         { 0,    "cpu",                  0 },
  112         { 1,    "gpu",                  1 },
  113         { 2,    "vpu",                  2 },
  114 };
  115 
  116 static struct tsensor ls1012_sensors[] =
  117 {
  118         { 0,    "cpu-thermal",          0 },
  119 };
  120 
  121 static struct tsensor ls1028_sensors[] =
  122 {
  123         { 0,    "ddr-controller",       0 },
  124         { 1,    "core-cluster",         1 },
  125 };
  126 
  127 static struct tsensor ls1043_sensors[] =
  128 {
  129         { 0,    "ddr-controller",       0 },
  130         { 1,    "serdes",               1 },
  131         { 2,    "fman",                 2 },
  132         { 3,    "core-cluster",         3 },
  133 };
  134 
  135 static struct tsensor ls1046_sensors[] =
  136 {
  137         { 0,    "ddr-controller",       0 },
  138         { 1,    "serdes",               1 },
  139         { 2,    "fman",                 2 },
  140         { 3,    "core-cluster",         3 },
  141         { 4,    "sec",                  4 },
  142 };
  143 
  144 static struct tsensor ls1088_sensors[] =
  145 {
  146         { 0,    "core-cluster",         0 },
  147         { 1,    "soc",                  1 },
  148 };
  149 
  150 /* Note: tmu[1..7] not [0..6]. */
  151 static struct tsensor lx2080_sensors[] =
  152 {
  153         { 1,    "ddr-controller1",      0 },
  154         { 2,    "ddr-controller2",      1 },
  155         { 3,    "ddr-controller3",      2 },
  156         { 4,    "core-cluster1",        3 },
  157         { 5,    "core-cluster2",        4 },
  158         { 6,    "core-cluster3",        5 },
  159         { 7,    "core-cluster4",        6 },
  160 };
  161 
  162 static struct tsensor lx2160_sensors[] =
  163 {
  164         { 0,    "cluster6-7",           0 },
  165         { 1,    "ddr-cluster5",         1 },
  166         { 2,    "wriop",                2 },
  167         { 3,    "dce-qbman-hsio2",      3 },
  168         { 4,    "ccn-dpaa-tbu",         4 },
  169         { 5,    "cluster4-hsio3",       5 },
  170         { 6,    "cluster2-3",           6 },
  171 };
  172 
  173 struct qoriq_therm_socs {
  174         const char              *name;
  175         struct tsensor          *tsensors;
  176         int                     ntsensors;
  177 } qoriq_therm_socs[] = {
  178 #define _SOC(_n, _a)    { _n, _a, nitems(_a) }
  179         _SOC("fsl,imx8mq",      imx8mq_sensors),
  180         _SOC("fsl,ls1012a",     ls1012_sensors),
  181         _SOC("fsl,ls1028a",     ls1028_sensors),
  182         _SOC("fsl,ls1043a",     ls1043_sensors),
  183         _SOC("fsl,ls1046a",     ls1046_sensors),
  184         _SOC("fsl,ls1088a",     ls1088_sensors),
  185         _SOC("fsl,ls2080a",     lx2080_sensors),
  186         _SOC("fsl,lx2160a",     lx2160_sensors),
  187         { NULL, NULL, 0 }
  188 #undef _SOC
  189 };
  190 
  191 static struct ofw_compat_data compat_data[] = {
  192         {"fsl,qoriq-tmu",       1},
  193         {"fsl,imx8mq-tmu",      1},
  194         {NULL,                  0},
  195 };
  196 
  197 static inline void
  198 WR4(struct qoriq_therm_softc *sc, bus_size_t addr, uint32_t val)
  199 {
  200 
  201         val = sc->little_endian ? htole32(val): htobe32(val);
  202         bus_write_4(sc->mem_res, addr, val);
  203 }
  204 
  205 static inline uint32_t
  206 RD4(struct qoriq_therm_softc *sc, bus_size_t addr)
  207 {
  208         uint32_t val;
  209 
  210         val = bus_read_4(sc->mem_res, addr);
  211         return (sc->little_endian ? le32toh(val): be32toh(val));
  212 }
  213 
  214 static int
  215 qoriq_therm_read_temp(struct qoriq_therm_softc *sc, struct tsensor *sensor,
  216     int *temp)
  217 {
  218         int timeout;
  219         uint32_t val;
  220 
  221         /* wait for valid sample */
  222         for (timeout = 1000; timeout > 0; timeout--) {
  223                 val = RD4(sc, TMU_TRITSR(sensor->site_id));
  224                 if (val & TMU_TRITSR_VALID)
  225                         break;
  226                 DELAY(100);
  227         }
  228         if (timeout <= 0)
  229                 device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
  230 
  231         *temp = (int)(val & 0x1FF) * 1000;
  232         if (sc->ver == 1)
  233                 *temp = (int)(val & 0xFF) * 1000;
  234         else
  235                 *temp = (int)(val & 0x1FF) * 1000 - 273100;
  236 
  237         return (0);
  238 }
  239 
  240 static int
  241 qoriq_therm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
  242 {
  243         struct qoriq_therm_softc *sc;
  244 
  245         sc = device_get_softc(dev);
  246         if (id >= sc->ntsensors)
  247                 return (ERANGE);
  248         return(qoriq_therm_read_temp(sc, sc->tsensors + id, val));
  249 }
  250 
  251 static int
  252 qoriq_therm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
  253 {
  254         struct qoriq_therm_softc *sc;
  255         int val;
  256         int rv;
  257         int id;
  258 
  259         /* Write request */
  260         if (req->newptr != NULL)
  261                 return (EINVAL);
  262 
  263         sc = arg1;
  264         id = arg2;
  265 
  266         if (id >= sc->ntsensors)
  267                 return (ERANGE);
  268         rv =  qoriq_therm_read_temp(sc, sc->tsensors + id, &val);
  269         if (rv != 0)
  270                 return (rv);
  271 
  272         val = val / 100;
  273         val +=  2731;
  274         rv = sysctl_handle_int(oidp, &val, 0, req);
  275         return (rv);
  276 }
  277 
  278 static int
  279 qoriq_therm_init_sysctl(struct qoriq_therm_softc *sc)
  280 {
  281         int i;
  282         struct sysctl_oid *oid, *tmp;
  283 
  284         /* create node for hw.temp */
  285         oid = SYSCTL_ADD_NODE(&qoriq_therm_sysctl_ctx,
  286             SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
  287             CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
  288         if (oid == NULL)
  289                 return (ENXIO);
  290 
  291         /* add sensors */
  292         for (i = sc->ntsensors  - 1; i >= 0; i--) {
  293                 tmp = SYSCTL_ADD_PROC(&qoriq_therm_sysctl_ctx,
  294                     SYSCTL_CHILDREN(oid), OID_AUTO, sc->tsensors[i].name,
  295                     CTLTYPE_INT | CTLFLAG_RD , sc, i,
  296                     qoriq_therm_sysctl_temperature, "IK", "SoC Temperature");
  297                 if (tmp == NULL)
  298                         return (ENXIO);
  299         }
  300         return (0);
  301 }
  302 
  303 static int
  304 qoriq_therm_fdt_calib(struct qoriq_therm_softc *sc, phandle_t node)
  305 {
  306         int     nranges, ncalibs, i;
  307         int     *ranges, *calibs;
  308 
  309         /* initialize temperature range control registes */
  310         nranges = OF_getencprop_alloc_multi(node, "fsl,tmu-range",
  311             sizeof(*ranges), (void **)&ranges);
  312         if (nranges < 2 || nranges > 4) {
  313                 device_printf(sc->dev, "Invalid 'tmu-range' property\n");
  314                 return (ERANGE);
  315         }
  316         for (i = 0; i < nranges; i++) {
  317                 WR4(sc, TMU_TTRCR(i), ranges[i]);
  318         }
  319 
  320         /* initialize calibration data for above ranges */
  321         ncalibs = OF_getencprop_alloc_multi(node, "fsl,tmu-calibration",
  322             sizeof(*calibs),(void **)&calibs);
  323         if (ncalibs <= 0 || (ncalibs % 2) != 0) {
  324                 device_printf(sc->dev, "Invalid 'tmu-calibration' property\n");
  325                 return (ERANGE);
  326         }
  327         for (i = 0; i < ncalibs; i +=2) {
  328                 WR4(sc, TMU_TTCFGR, calibs[i]);
  329                 WR4(sc, TMU_TSCFGR, calibs[i + 1]);
  330         }
  331 
  332         return (0);
  333 }
  334 
  335 static int
  336 qoriq_therm_probe(device_t dev)
  337 {
  338 
  339         if (!ofw_bus_status_okay(dev))
  340                 return (ENXIO);
  341 
  342         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  343                 return (ENXIO);
  344 
  345         device_set_desc(dev, "QorIQ temperature sensors");
  346         return (BUS_PROBE_DEFAULT);
  347 }
  348 
  349 static int
  350 qoriq_therm_attach(device_t dev)
  351 {
  352         struct qoriq_therm_softc *sc;
  353         struct qoriq_therm_socs *soc;
  354         phandle_t node, root;
  355         uint32_t sites;
  356         int rid, rv;
  357 
  358         sc = device_get_softc(dev);
  359         sc->dev = dev;
  360         node = ofw_bus_get_node(sc->dev);
  361         sc->little_endian = OF_hasprop(node, "little-endian");
  362 
  363         sysctl_ctx_init(&qoriq_therm_sysctl_ctx);
  364 
  365         rid = 0;
  366         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  367             RF_ACTIVE);
  368         if (sc->mem_res == NULL) {
  369                 device_printf(dev, "Cannot allocate memory resources\n");
  370                 goto fail;
  371         }
  372 
  373         rid = 0;
  374         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
  375         if (sc->irq_res == NULL) {
  376                 device_printf(dev, "Cannot allocate IRQ resources\n");
  377                 goto fail;
  378         }
  379 
  380 /*
  381         if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  382             qoriq_therm_intr, NULL, sc, &sc->irq_ih))) {
  383                 device_printf(dev,
  384                     "WARNING: unable to register interrupt handler\n");
  385                 goto fail;
  386         }
  387 */
  388         rv = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
  389         if (rv != 0 && rv != ENOENT) {
  390                 device_printf(dev, "Cannot get clock: %d %d\n", rv, ENOENT);
  391                 goto fail;
  392         }
  393         if (sc->clk != NULL) {
  394                 rv = clk_enable(sc->clk);
  395                 if (rv != 0) {
  396                         device_printf(dev, "Cannot enable clock: %d\n", rv);
  397                         goto fail;
  398                 }
  399         }
  400 
  401         sc->ver = (RD4(sc, TMU_VERSION) >> 8) & 0xFF;
  402 
  403         /* Select per SoC configuration. */
  404         root = OF_finddevice("/");
  405         if (root < 0) {
  406                 device_printf(dev, "Cannot get root node: %d\n", root);
  407                 goto fail;
  408         }
  409         soc = qoriq_therm_socs;
  410         while (soc != NULL && soc->name != NULL) {
  411                 if (ofw_bus_node_is_compatible(root, soc->name))
  412                         break;
  413                 soc++;
  414         }
  415         if (soc == NULL) {
  416                 device_printf(dev, "Unsupported SoC, using default sites.\n");
  417                 sc->tsensors = default_sensors;
  418                 sc->ntsensors = nitems(default_sensors);
  419         } else {
  420                 sc->tsensors = soc->tsensors;
  421                 sc->ntsensors = soc->ntsensors;
  422         }
  423 
  424         /* stop monitoring */
  425         WR4(sc, TMU_TMR, 0);
  426         RD4(sc, TMU_TMR);
  427 
  428         /* disable all interrupts */
  429         WR4(sc, TMU_TIER, 0);
  430 
  431         /* setup measurement interval */
  432         if (sc->ver == 1) {
  433                 WR4(sc, TMUV1_TMTMIR, 0x0F);
  434         } else {
  435                 WR4(sc, TMUV2_TMTMIR, 0x0F);    /* disable */
  436                 /* these registers are not of settings is not in TRM */
  437                 WR4(sc, TMUV2_TEUMR(0), 0x51009c00);
  438                 for (int i = 0; i < sc->ntsensors; i++)
  439                         WR4(sc, TMUV2_TMSAR(sc->tsensors[i].site_id), 0xE);
  440         }
  441 
  442         /* prepare calibration tables */
  443         rv = qoriq_therm_fdt_calib(sc, node);
  444         if (rv != 0) {
  445                 device_printf(sc->dev,
  446                     "Cannot initialize calibration tables\n");
  447                 goto fail;
  448         }
  449         /* start monitoring */
  450         sites = 0;
  451         if (sc->ver == 1) {
  452                 for (int i = 0; i < sc->ntsensors; i++)
  453                         sites |= 1 << (15 - sc->tsensors[i].site_id);
  454                 WR4(sc, TMU_TMR, 0x8C000000 | sites);
  455         } else {
  456                 for (int i = 0; i < sc->ntsensors; i++)
  457                         sites |= 1 << sc->tsensors[i].site_id;
  458                 WR4(sc, TMUV2_TMSR, sites);
  459                 WR4(sc, TMU_TMR, 0x83000000);
  460         }
  461 
  462         rv = qoriq_therm_init_sysctl(sc);
  463         if (rv != 0) {
  464                 device_printf(sc->dev, "Cannot initialize sysctls\n");
  465                 goto fail;
  466         }
  467 
  468         OF_device_register_xref(OF_xref_from_node(node), dev);
  469         return (bus_generic_attach(dev));
  470 
  471 fail:
  472         if (sc->irq_ih != NULL)
  473                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
  474         sysctl_ctx_free(&qoriq_therm_sysctl_ctx);
  475         if (sc->clk != NULL)
  476                 clk_release(sc->clk);
  477         if (sc->irq_res != NULL)
  478                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  479         if (sc->mem_res != NULL)
  480                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  481 
  482         return (ENXIO);
  483 }
  484 
  485 static int
  486 qoriq_therm_detach(device_t dev)
  487 {
  488         struct qoriq_therm_softc *sc;
  489         sc = device_get_softc(dev);
  490 
  491         if (sc->irq_ih != NULL)
  492                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
  493         sysctl_ctx_free(&qoriq_therm_sysctl_ctx);
  494         if (sc->clk != NULL)
  495                 clk_release(sc->clk);
  496         if (sc->irq_res != NULL)
  497                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  498         if (sc->mem_res != NULL)
  499                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  500 
  501         return (0);
  502 }
  503 
  504 static device_method_t qoriq_qoriq_therm_methods[] = {
  505         /* Device interface */
  506         DEVMETHOD(device_probe,                 qoriq_therm_probe),
  507         DEVMETHOD(device_attach,                qoriq_therm_attach),
  508         DEVMETHOD(device_detach,                qoriq_therm_detach),
  509 
  510         /* SOCTHERM interface */
  511         DEVMETHOD(qoriq_therm_get_temperature,  qoriq_therm_get_temp),
  512 
  513         DEVMETHOD_END
  514 };
  515 
  516 static DEFINE_CLASS_0(soctherm, qoriq_qoriq_therm_driver, qoriq_qoriq_therm_methods,
  517     sizeof(struct qoriq_therm_softc));
  518 DRIVER_MODULE(qoriq_soctherm, simplebus, qoriq_qoriq_therm_driver, NULL, NULL);

Cache object: f66fd76257c57ae8eeb92b5ffd7dd906


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