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$");
   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/kernel.h>
   37 #include <sys/lock.h>
   38 #include <sys/module.h>
   39 #include <sys/mutex.h>
   40 #include <sys/resource.h>
   41 
   42 #include <machine/fdt.h>
   43 
   44 #include <dev/ofw/ofw_bus_subr.h>
   45 
   46 #define READOUT_TO_C(temp)      ((temp) / 1000)
   47 
   48 #define STAT_RID                0
   49 #define CTRL_RID                1
   50 
   51 #define TSEN_STAT_READOUT_VALID 0x1
   52 
   53 #define A380_TSEN_CTRL_RESET    (1 << 8)
   54 
   55 struct armada_thermal_softc;
   56 
   57 typedef struct armada_thermal_data {
   58         /* Initialize the sensor */
   59         void (*tsen_init)(struct armada_thermal_softc *);
   60 
   61         /* Test for a valid sensor value */
   62         boolean_t (*is_valid)(struct armada_thermal_softc *);
   63 
   64         /* Formula coefficients: temp = (b + m * reg) / div */
   65         u_long coef_b;
   66         u_long coef_m;
   67         u_long coef_div;
   68 
   69         boolean_t inverted;
   70 
   71         /* Shift and mask to access the sensor temperature */
   72         u_int temp_shift;
   73         u_int temp_mask;
   74         u_int is_valid_shift;
   75 } armada_tdata_t;
   76 
   77 static boolean_t armada_tsen_readout_valid(struct armada_thermal_softc *);
   78 static int armada_tsen_get_temp(struct armada_thermal_softc *, u_long *);
   79 static void armada380_tsen_init(struct armada_thermal_softc *);
   80 static void armada_temp_update(void *);
   81 
   82 static const armada_tdata_t armada380_tdata = {
   83         .tsen_init = armada380_tsen_init,
   84         .is_valid = armada_tsen_readout_valid,
   85         .is_valid_shift = 10,
   86         .temp_shift = 0,
   87         .temp_mask = 0x3ff,
   88         .coef_b = 1172499100UL,
   89         .coef_m = 2000096UL,
   90         .coef_div = 4201,
   91         .inverted = TRUE,
   92 };
   93 
   94 static int armada_thermal_probe(device_t);
   95 static int armada_thermal_attach(device_t);
   96 static int armada_thermal_detach(device_t);
   97 
   98 static device_method_t armada_thermal_methods[] = {
   99         DEVMETHOD(device_probe,         armada_thermal_probe),
  100         DEVMETHOD(device_attach,        armada_thermal_attach),
  101         DEVMETHOD(device_detach,        armada_thermal_detach),
  102 
  103         DEVMETHOD_END
  104 };
  105 
  106 struct armada_thermal_softc {
  107         device_t                dev;
  108 
  109         struct resource         *stat_res;
  110         struct resource         *ctrl_res;
  111 
  112         struct callout          temp_upd;
  113         struct mtx              temp_upd_mtx;
  114 
  115         const armada_tdata_t    *tdata;
  116 
  117         u_long                  chip_temperature;
  118 };
  119 
  120 static driver_t armada_thermal_driver = {
  121         "armada_thermal",
  122         armada_thermal_methods,
  123         sizeof(struct armada_thermal_softc)
  124 };
  125 
  126 DRIVER_MODULE(armada_thermal, simplebus, armada_thermal_driver, 0, 0);
  127 DRIVER_MODULE(armada_thermal, ofwbus, armada_thermal_driver, 0, 0);
  128 
  129 static int
  130 armada_thermal_probe(device_t dev)
  131 {
  132         struct armada_thermal_softc *sc;
  133 
  134         sc = device_get_softc(dev);
  135 
  136         if (!ofw_bus_status_okay(dev))
  137                 return (ENXIO);
  138 
  139         if (ofw_bus_is_compatible(dev, "marvell,armada380-thermal")) {
  140                 device_set_desc(dev, "Armada380 Thermal Control");
  141                 sc->tdata = &armada380_tdata;
  142 
  143                 return (BUS_PROBE_DEFAULT);
  144         }
  145 
  146         return (ENXIO);
  147 }
  148 
  149 static int
  150 armada_thermal_attach(device_t dev)
  151 {
  152         struct armada_thermal_softc *sc;
  153         const armada_tdata_t *tdata;
  154         struct sysctl_ctx_list *sctx;
  155         struct sysctl_oid_list *schildren;
  156         int timeout;
  157         int rid;
  158 
  159         sc = device_get_softc(dev);
  160 
  161         /* Allocate CTRL and STAT register spaces */
  162         rid = STAT_RID;
  163         sc->stat_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  164             &rid, RF_ACTIVE);
  165         if (sc->stat_res == NULL) {
  166                 device_printf(dev,
  167                     "Could not allocate memory for the status register\n");
  168                 return (ENXIO);
  169         }
  170 
  171         rid = CTRL_RID;
  172         sc->ctrl_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  173             &rid, RF_ACTIVE);
  174         if (sc->ctrl_res == NULL) {
  175                 device_printf(dev,
  176                     "Could not allocate memory for the control register\n");
  177                 bus_release_resource(dev, SYS_RES_MEMORY,
  178                     rman_get_rid(sc->stat_res), sc->stat_res);
  179                 sc->stat_res = NULL;
  180                 return (ENXIO);
  181         }
  182 
  183         /* Now initialize the sensor */
  184         tdata = sc->tdata;
  185         tdata->tsen_init(sc);
  186         /* Set initial temperature value */
  187         for (timeout = 1000; timeout > 0; timeout--) {
  188                 if (armada_tsen_get_temp(sc, &sc->chip_temperature) == 0)
  189                         break;
  190                 DELAY(10);
  191         }
  192         if (timeout <= 0) {
  193                 bus_release_resource(dev, SYS_RES_MEMORY,
  194                     rman_get_rid(sc->stat_res), sc->stat_res);
  195                 sc->stat_res = NULL;
  196                 bus_release_resource(dev, SYS_RES_MEMORY,
  197                     rman_get_rid(sc->ctrl_res), sc->ctrl_res);
  198                 sc->ctrl_res = NULL;
  199                 return (ENXIO);
  200         }
  201         /* Initialize mutex */
  202         mtx_init(&sc->temp_upd_mtx, "Armada Thermal", NULL, MTX_DEF);
  203         /* Set up the temperature update callout */
  204         callout_init_mtx(&sc->temp_upd, &sc->temp_upd_mtx, 0);
  205         /* Schedule callout */
  206         callout_reset(&sc->temp_upd, hz, armada_temp_update, sc);
  207 
  208         sctx = device_get_sysctl_ctx(dev);
  209         schildren = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
  210         SYSCTL_ADD_LONG(sctx, schildren, OID_AUTO, "temperature",
  211             CTLFLAG_RD, &sc->chip_temperature, "SoC temperature");
  212 
  213         return (0);
  214 }
  215 
  216 static int
  217 armada_thermal_detach(device_t dev)
  218 {
  219         struct armada_thermal_softc *sc;
  220 
  221         sc = device_get_softc(dev);
  222 
  223         if (!device_is_attached(dev))
  224                 return (0);
  225 
  226         callout_drain(&sc->temp_upd);
  227 
  228         sc->chip_temperature = 0;
  229 
  230         bus_release_resource(dev, SYS_RES_MEMORY,
  231             rman_get_rid(sc->stat_res), sc->stat_res);
  232         sc->stat_res = NULL;
  233 
  234         bus_release_resource(dev, SYS_RES_MEMORY,
  235             rman_get_rid(sc->ctrl_res), sc->ctrl_res);
  236         sc->ctrl_res = NULL;
  237 
  238         return (0);
  239 }
  240 
  241 static boolean_t
  242 armada_tsen_readout_valid(struct armada_thermal_softc *sc)
  243 {
  244         const armada_tdata_t *tdata;
  245         uint32_t tsen_stat;
  246         boolean_t is_valid;
  247 
  248         tdata = sc->tdata;
  249         tsen_stat = bus_read_4(sc->stat_res, 0);
  250 
  251         tsen_stat >>= tdata->is_valid_shift;
  252         is_valid = ((tsen_stat & TSEN_STAT_READOUT_VALID) != 0);
  253 
  254         return (is_valid);
  255 }
  256 
  257 static int
  258 armada_tsen_get_temp(struct armada_thermal_softc *sc, u_long *temp)
  259 {
  260         const armada_tdata_t *tdata;
  261         uint32_t reg;
  262         u_long tmp;
  263         u_long m, b, div;
  264 
  265         tdata = sc->tdata;
  266         /* Check if the readout is valid */
  267         if ((tdata->is_valid != NULL) && !tdata->is_valid(sc))
  268                 return (EIO);
  269 
  270         reg = bus_read_4(sc->stat_res, 0);
  271         reg = (reg >> tdata->temp_shift) & tdata->temp_mask;
  272 
  273         /* Get formula coefficients */
  274         b = tdata->coef_b;
  275         m = tdata->coef_m;
  276         div = tdata->coef_div;
  277 
  278         if (tdata->inverted)
  279                 tmp = ((m * reg) - b) / div;
  280         else
  281                 tmp = (b - (m * reg)) / div;
  282 
  283         *temp = READOUT_TO_C(tmp);
  284 
  285         return (0);
  286 }
  287 
  288 static void
  289 armada380_tsen_init(struct armada_thermal_softc *sc)
  290 {
  291         uint32_t tsen_ctrl;
  292 
  293         tsen_ctrl = bus_read_4(sc->ctrl_res, 0);
  294         if ((tsen_ctrl & A380_TSEN_CTRL_RESET) == 0) {
  295                 tsen_ctrl |= A380_TSEN_CTRL_RESET;
  296                 bus_write_4(sc->ctrl_res, 0, tsen_ctrl);
  297                 DELAY(10000);
  298         }
  299 }
  300 
  301 static void
  302 armada_temp_update(void *arg)
  303 {
  304         struct armada_thermal_softc *sc;
  305 
  306         sc = arg;
  307         /* Update temperature value, keel old if the readout is not valid */
  308         (void)armada_tsen_get_temp(sc, &sc->chip_temperature);
  309 
  310         callout_reset(&sc->temp_upd, hz, armada_temp_update, sc);
  311 }

Cache object: de1a119ccbe88f3105d6ce006fdb8dd7


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