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/mv/armada/thermal.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) 2017 Semihalf.
    3  * Copyright (c) 2017 Stormshield.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/12.0/sys/arm/mv/armada/thermal.c 312739 2017-01-25 06:08:10Z wma $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/sysctl.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/conf.h>
   35 #include <sys/rman.h>
   36 #include <sys/types.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/resource.h>
   40 
   41 #include <machine/fdt.h>
   42 
   43 #include <dev/ofw/ofw_bus_subr.h>
   44 
   45 #define READOUT_TO_C(temp)      ((temp) / 1000)
   46 
   47 #define STAT_RID                0
   48 #define CTRL_RID                1
   49 
   50 #define TSEN_STAT_READOUT_VALID 0x1
   51 
   52 #define A380_TSEN_CTRL_RESET    (1 << 8)
   53 
   54 struct armada_thermal_softc;
   55 
   56 typedef struct armada_thermal_data {
   57         /* Initialize the sensor */
   58         void (*tsen_init)(struct armada_thermal_softc *);
   59 
   60         /* Test for a valid sensor value */
   61         boolean_t (*is_valid)(struct armada_thermal_softc *);
   62 
   63         /* Formula coefficients: temp = (b + m * reg) / div */
   64         u_long coef_b;
   65         u_long coef_m;
   66         u_long coef_div;
   67 
   68         boolean_t inverted;
   69 
   70         /* Shift and mask to access the sensor temperature */
   71         u_int temp_shift;
   72         u_int temp_mask;
   73         u_int is_valid_shift;
   74 } armada_tdata_t;
   75 
   76 static boolean_t armada_tsen_readout_valid(struct armada_thermal_softc *);
   77 static int armada_tsen_get_temp(struct armada_thermal_softc *, u_long *);
   78 static void armada380_tsen_init(struct armada_thermal_softc *);
   79 static void armada_temp_update(void *);
   80 
   81 static const armada_tdata_t armada380_tdata = {
   82         .tsen_init = armada380_tsen_init,
   83         .is_valid = armada_tsen_readout_valid,
   84         .is_valid_shift = 10,
   85         .temp_shift = 0,
   86         .temp_mask = 0x3ff,
   87         .coef_b = 1172499100UL,
   88         .coef_m = 2000096UL,
   89         .coef_div = 4201,
   90         .inverted = TRUE,
   91 };
   92 
   93 static int armada_thermal_probe(device_t);
   94 static int armada_thermal_attach(device_t);
   95 static int armada_thermal_detach(device_t);
   96 
   97 static device_method_t armada_thermal_methods[] = {
   98         DEVMETHOD(device_probe,         armada_thermal_probe),
   99         DEVMETHOD(device_attach,        armada_thermal_attach),
  100         DEVMETHOD(device_detach,        armada_thermal_detach),
  101 
  102         DEVMETHOD_END
  103 };
  104 
  105 struct armada_thermal_softc {
  106         device_t                dev;
  107 
  108         struct resource         *stat_res;
  109         struct resource         *ctrl_res;
  110 
  111         struct callout          temp_upd;
  112         struct mtx              temp_upd_mtx;
  113 
  114         const armada_tdata_t    *tdata;
  115 
  116         u_long                  chip_temperature;
  117 };
  118 
  119 static driver_t armada_thermal_driver = {
  120         "armada_thermal",
  121         armada_thermal_methods,
  122         sizeof(struct armada_thermal_softc)
  123 };
  124 
  125 static devclass_t armada_thermal_devclass;
  126 
  127 DRIVER_MODULE(armada_thermal, simplebus, armada_thermal_driver,
  128         armada_thermal_devclass, 0, 0);
  129 DRIVER_MODULE(armada_thermal, ofwbus, armada_thermal_driver,
  130         armada_thermal_devclass, 0, 0);
  131 
  132 static int
  133 armada_thermal_probe(device_t dev)
  134 {
  135         struct armada_thermal_softc *sc;
  136 
  137         sc = device_get_softc(dev);
  138 
  139         if (!ofw_bus_status_okay(dev))
  140                 return (ENXIO);
  141 
  142         if (ofw_bus_is_compatible(dev, "marvell,armada380-thermal")) {
  143                 device_set_desc(dev, "Armada380 Thermal Control");
  144                 sc->tdata = &armada380_tdata;
  145 
  146                 return (BUS_PROBE_DEFAULT);
  147         }
  148 
  149         return (ENXIO);
  150 }
  151 
  152 static int
  153 armada_thermal_attach(device_t dev)
  154 {
  155         struct armada_thermal_softc *sc;
  156         const armada_tdata_t *tdata;
  157         struct sysctl_ctx_list *sctx;
  158         struct sysctl_oid_list *schildren;
  159         int timeout;
  160         int rid;
  161 
  162         sc = device_get_softc(dev);
  163 
  164         /* Allocate CTRL and STAT register spaces */
  165         rid = STAT_RID;
  166         sc->stat_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  167             &rid, RF_ACTIVE);
  168         if (sc->stat_res == NULL) {
  169                 device_printf(dev,
  170                     "Could not allocate memory for the status register\n");
  171                 return (ENXIO);
  172         }
  173 
  174         rid = CTRL_RID;
  175         sc->ctrl_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  176             &rid, RF_ACTIVE);
  177         if (sc->ctrl_res == NULL) {
  178                 device_printf(dev,
  179                     "Could not allocate memory for the control register\n");
  180                 bus_release_resource(dev, SYS_RES_MEMORY,
  181                     rman_get_rid(sc->stat_res), sc->stat_res);
  182                 sc->stat_res = NULL;
  183                 return (ENXIO);
  184         }
  185 
  186         /* Now initialize the sensor */
  187         tdata = sc->tdata;
  188         tdata->tsen_init(sc);
  189         /* Set initial temperature value */
  190         for (timeout = 1000; timeout > 0; timeout--) {
  191                 if (armada_tsen_get_temp(sc, &sc->chip_temperature) == 0)
  192                         break;
  193                 DELAY(10);
  194         }
  195         if (timeout <= 0) {
  196                 bus_release_resource(dev, SYS_RES_MEMORY,
  197                     rman_get_rid(sc->stat_res), sc->stat_res);
  198                 sc->stat_res = NULL;
  199                 bus_release_resource(dev, SYS_RES_MEMORY,
  200                     rman_get_rid(sc->ctrl_res), sc->ctrl_res);
  201                 sc->ctrl_res = NULL;
  202                 return (ENXIO);
  203         }
  204         /* Initialize mutex */
  205         mtx_init(&sc->temp_upd_mtx, "Armada Thermal", NULL, MTX_DEF);
  206         /* Set up the temperature update callout */
  207         callout_init_mtx(&sc->temp_upd, &sc->temp_upd_mtx, 0);
  208         /* Schedule callout */
  209         callout_reset(&sc->temp_upd, hz, armada_temp_update, sc);
  210 
  211         sctx = device_get_sysctl_ctx(dev);
  212         schildren = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
  213         SYSCTL_ADD_LONG(sctx, schildren, OID_AUTO, "temperature",
  214             CTLFLAG_RD, &sc->chip_temperature, "SoC temperature");
  215 
  216         return (0);
  217 }
  218 
  219 static int
  220 armada_thermal_detach(device_t dev)
  221 {
  222         struct armada_thermal_softc *sc;
  223 
  224         sc = device_get_softc(dev);
  225 
  226         if (!device_is_attached(dev))
  227                 return (0);
  228 
  229         callout_drain(&sc->temp_upd);
  230 
  231         sc->chip_temperature = 0;
  232 
  233         bus_release_resource(dev, SYS_RES_MEMORY,
  234             rman_get_rid(sc->stat_res), sc->stat_res);
  235         sc->stat_res = NULL;
  236 
  237         bus_release_resource(dev, SYS_RES_MEMORY,
  238             rman_get_rid(sc->ctrl_res), sc->ctrl_res);
  239         sc->ctrl_res = NULL;
  240 
  241         return (0);
  242 }
  243 
  244 static boolean_t
  245 armada_tsen_readout_valid(struct armada_thermal_softc *sc)
  246 {
  247         const armada_tdata_t *tdata;
  248         uint32_t tsen_stat;
  249         boolean_t is_valid;
  250 
  251         tdata = sc->tdata;
  252         tsen_stat = bus_read_4(sc->stat_res, 0);
  253 
  254         tsen_stat >>= tdata->is_valid_shift;
  255         is_valid = ((tsen_stat & TSEN_STAT_READOUT_VALID) != 0);
  256 
  257         return (is_valid);
  258 }
  259 
  260 static int
  261 armada_tsen_get_temp(struct armada_thermal_softc *sc, u_long *temp)
  262 {
  263         const armada_tdata_t *tdata;
  264         uint32_t reg;
  265         u_long tmp;
  266         u_long m, b, div;
  267 
  268         tdata = sc->tdata;
  269         /* Check if the readout is valid */
  270         if ((tdata->is_valid != NULL) && !tdata->is_valid(sc))
  271                 return (EIO);
  272 
  273         reg = bus_read_4(sc->stat_res, 0);
  274         reg = (reg >> tdata->temp_shift) & tdata->temp_mask;
  275 
  276         /* Get formula coefficients */
  277         b = tdata->coef_b;
  278         m = tdata->coef_m;
  279         div = tdata->coef_div;
  280 
  281         if (tdata->inverted)
  282                 tmp = ((m * reg) - b) / div;
  283         else
  284                 tmp = (b - (m * reg)) / div;
  285 
  286         *temp = READOUT_TO_C(tmp);
  287 
  288         return (0);
  289 }
  290 
  291 static void
  292 armada380_tsen_init(struct armada_thermal_softc *sc)
  293 {
  294         uint32_t tsen_ctrl;
  295 
  296         tsen_ctrl = bus_read_4(sc->ctrl_res, 0);
  297         if ((tsen_ctrl & A380_TSEN_CTRL_RESET) == 0) {
  298                 tsen_ctrl |= A380_TSEN_CTRL_RESET;
  299                 bus_write_4(sc->ctrl_res, 0, tsen_ctrl);
  300                 DELAY(10000);
  301         }
  302 }
  303 
  304 static void
  305 armada_temp_update(void *arg)
  306 {
  307         struct armada_thermal_softc *sc;
  308 
  309         sc = arg;
  310         /* Update temperature value, keel old if the readout is not valid */
  311         (void)armada_tsen_get_temp(sc, &sc->chip_temperature);
  312 
  313         callout_reset(&sc->temp_upd, hz, armada_temp_update, sc);
  314 }

Cache object: 520f46f43c9d10a94be65eeb74ccce81


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