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/allwinner/aw_wdog.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) 2013 Oleksandr Tymoshenko <gonzo@freebsd.org>
    3  * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org>
    4  * Copyright (c) 2022 Julien Cassette <julien.cassette@gmail.com>
    5  * All rights reserved.
    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 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/eventhandler.h>
   33 #include <sys/systm.h>
   34 #include <sys/watchdog.h>
   35 #include <sys/reboot.h>
   36 #include <sys/bus.h>
   37 #include <sys/kernel.h>
   38 #include <sys/lock.h>
   39 #include <sys/module.h>
   40 #include <sys/mutex.h>
   41 #include <sys/rman.h>
   42 
   43 #include <dev/ofw/openfirm.h>
   44 #include <dev/ofw/ofw_bus.h>
   45 #include <dev/ofw/ofw_bus_subr.h>
   46 
   47 #include <machine/bus.h>
   48 
   49 #include <arm/allwinner/aw_wdog.h>
   50 
   51 #define READ(_sc, _r) bus_read_4((_sc)->res, (_r))
   52 #define WRITE(_sc, _r, _v) bus_write_4((_sc)->res, (_r), (_v))
   53 
   54 #define A10_WDOG_CTRL           0x00
   55 #define A31_WDOG_CTRL           0x10
   56 #define D1_WDOG_CTRL            0x10
   57 #define  WDOG_CTRL_RESTART      (1 << 0)
   58 #define  A31_WDOG_CTRL_KEY      (0xa57 << 1)
   59 #define  D1_WDOG_CTRL_KEY       (0xa57 << 1)
   60 #define A10_WDOG_MODE           0x04
   61 #define A31_WDOG_MODE           0x18
   62 #define D1_WDOG_MODE            0x18
   63 #define  D1_WDOG_MODE_KEY       (0x16AA << 16)
   64 #define  A10_WDOG_MODE_INTVL_SHIFT      3
   65 #define  A31_WDOG_MODE_INTVL_SHIFT      4
   66 #define  D1_WDOG_MODE_INTVL_SHIFT       4
   67 #define  A10_WDOG_MODE_RST_EN   (1 << 1)
   68 #define  WDOG_MODE_EN           (1 << 0)
   69 #define A31_WDOG_CONFIG         0x14
   70 #define D1_WDOG_CONFIG          0x14
   71 #define  A31_WDOG_CONFIG_RST_EN_SYSTEM  (1 << 0)
   72 #define  A31_WDOG_CONFIG_RST_EN_INT     (2 << 0)
   73 #define  D1_WDOG_CONFIG_KEY             (0x16AA << 16)
   74 #define  D1_WDOG_CONFIG_RST_EN_SYSTEM   (1 << 0)
   75 #define  D1_WDOG_CONFIG_RST_EN_INT      (2 << 0)
   76 
   77 struct aw_wdog_interval {
   78         uint64_t        milliseconds;
   79         unsigned int    value;
   80 };
   81 
   82 struct aw_wdog_interval wd_intervals[] = {
   83         {   500,         0 },
   84         {  1000,         1 },
   85         {  2000,         2 },
   86         {  3000,         3 },
   87         {  4000,         4 },
   88         {  5000,         5 },
   89         {  6000,         6 },
   90         {  8000,         7 },
   91         { 10000,         8 },
   92         { 12000,         9 },
   93         { 14000,        10 },
   94         { 16000,        11 },
   95         { 0,             0 } /* sentinel */
   96 };
   97 
   98 static struct aw_wdog_softc *aw_wdog_sc = NULL;
   99 
  100 struct aw_wdog_softc {
  101         device_t                dev;
  102         struct resource *       res;
  103         struct mtx              mtx;
  104         uint8_t                 wdog_ctrl;
  105         uint32_t                wdog_ctrl_key;
  106         uint8_t                 wdog_mode;
  107         uint32_t                wdog_mode_key;
  108         uint8_t                 wdog_mode_intvl_shift;
  109         uint8_t                 wdog_mode_en;
  110         uint8_t                 wdog_config;
  111         uint32_t                wdog_config_value;
  112 };
  113 
  114 #define A10_WATCHDOG    1
  115 #define A31_WATCHDOG    2
  116 #define D1_WATCHDOG     3
  117 
  118 static struct ofw_compat_data compat_data[] = {
  119         {"allwinner,sun4i-a10-wdt", A10_WATCHDOG},
  120         {"allwinner,sun6i-a31-wdt", A31_WATCHDOG},
  121         {"allwinner,sun20i-d1-wdt", D1_WATCHDOG},
  122         {NULL,             0}
  123 };
  124 
  125 static void aw_wdog_watchdog_fn(void *, u_int, int *);
  126 static void aw_wdog_shutdown_fn(void *, int);
  127 
  128 static int
  129 aw_wdog_probe(device_t dev)
  130 {
  131 
  132         if (!ofw_bus_status_okay(dev))
  133                 return (ENXIO);
  134         switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
  135         case A10_WATCHDOG:
  136                 device_set_desc(dev, "Allwinner A10 Watchdog");
  137                 return (BUS_PROBE_DEFAULT);
  138         case A31_WATCHDOG:
  139                 device_set_desc(dev, "Allwinner A31 Watchdog");
  140                 return (BUS_PROBE_DEFAULT);
  141         case D1_WATCHDOG:
  142                 device_set_desc(dev, "Allwinner D1 Watchdog");
  143                 return (BUS_PROBE_DEFAULT);
  144         }
  145         return (ENXIO);
  146 }
  147 
  148 static int
  149 aw_wdog_attach(device_t dev)
  150 {
  151         struct aw_wdog_softc *sc;
  152         int rid;
  153 
  154         if (aw_wdog_sc != NULL)
  155                 return (ENXIO);
  156 
  157         sc = device_get_softc(dev);
  158         sc->dev = dev;
  159 
  160         rid = 0;
  161         sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
  162         if (sc->res == NULL) {
  163                 device_printf(dev, "could not allocate memory resource\n");
  164                 return (ENXIO);
  165         }
  166 
  167         aw_wdog_sc = sc;
  168 
  169         switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
  170         case A10_WATCHDOG:
  171                 sc->wdog_ctrl = A10_WDOG_CTRL;
  172                 sc->wdog_mode = A10_WDOG_MODE;
  173                 sc->wdog_mode_key = 0;
  174                 sc->wdog_mode_intvl_shift = A10_WDOG_MODE_INTVL_SHIFT;
  175                 sc->wdog_mode_en = A10_WDOG_MODE_RST_EN | WDOG_MODE_EN;
  176                 break;
  177         case A31_WATCHDOG:
  178                 sc->wdog_ctrl = A31_WDOG_CTRL;
  179                 sc->wdog_ctrl_key = A31_WDOG_CTRL_KEY;
  180                 sc->wdog_mode = A31_WDOG_MODE;
  181                 sc->wdog_mode_key = 0;
  182                 sc->wdog_mode_intvl_shift = A31_WDOG_MODE_INTVL_SHIFT;
  183                 sc->wdog_mode_en = WDOG_MODE_EN;
  184                 sc->wdog_config = A31_WDOG_CONFIG;
  185                 sc->wdog_config_value = A31_WDOG_CONFIG_RST_EN_SYSTEM;
  186                 break;
  187         case D1_WATCHDOG:
  188                 sc->wdog_ctrl = D1_WDOG_CTRL;
  189                 sc->wdog_ctrl_key = D1_WDOG_CTRL_KEY;
  190                 sc->wdog_mode = D1_WDOG_MODE;
  191                 sc->wdog_mode_key = D1_WDOG_MODE_KEY;
  192                 sc->wdog_mode_intvl_shift = D1_WDOG_MODE_INTVL_SHIFT;
  193                 sc->wdog_mode_en = WDOG_MODE_EN;
  194                 sc->wdog_config = D1_WDOG_CONFIG;
  195                 sc->wdog_config_value = D1_WDOG_CONFIG_KEY | D1_WDOG_CONFIG_RST_EN_SYSTEM;
  196                 break;
  197         default:
  198                 bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->res);
  199                 return (ENXIO);
  200         }
  201 
  202         mtx_init(&sc->mtx, "AW Watchdog", "aw_wdog", MTX_DEF);
  203         EVENTHANDLER_REGISTER(watchdog_list, aw_wdog_watchdog_fn, sc, 0);
  204         EVENTHANDLER_REGISTER(shutdown_final, aw_wdog_shutdown_fn, sc,
  205             SHUTDOWN_PRI_LAST - 1);
  206 
  207         return (0);
  208 }
  209 
  210 static void
  211 aw_wdog_watchdog_fn(void *private, u_int cmd, int *error)
  212 {
  213         struct aw_wdog_softc *sc;
  214         uint64_t ms;
  215         int i;
  216 
  217         sc = private;
  218         mtx_lock(&sc->mtx);
  219 
  220         cmd &= WD_INTERVAL;
  221 
  222         if (cmd > 0) {
  223                 ms = ((uint64_t)1 << (cmd & WD_INTERVAL)) / 1000000;
  224                 i = 0;
  225                 while (wd_intervals[i].milliseconds &&
  226                     (ms > wd_intervals[i].milliseconds))
  227                         i++;
  228                 if (wd_intervals[i].milliseconds) {
  229                         WRITE(sc, sc->wdog_mode, sc->wdog_mode_key |
  230                           (wd_intervals[i].value << sc->wdog_mode_intvl_shift) |
  231                             sc->wdog_mode_en);
  232                         WRITE(sc, sc->wdog_ctrl,
  233                             WDOG_CTRL_RESTART | sc->wdog_ctrl_key);
  234                         if (sc->wdog_config)
  235                                 WRITE(sc, sc->wdog_config,
  236                                     sc->wdog_config_value);
  237                         *error = 0;
  238                 }
  239                 else {
  240                         /*
  241                          * Can't arm
  242                          * disable watchdog as watchdog(9) requires
  243                          */
  244                         device_printf(sc->dev,
  245                             "Can't arm, timeout is more than 16 sec\n");
  246                         mtx_unlock(&sc->mtx);
  247                         WRITE(sc, sc->wdog_mode, sc->wdog_mode_key);
  248                         return;
  249                 }
  250         }
  251         else
  252                 WRITE(sc, sc->wdog_mode, sc->wdog_mode_key);
  253 
  254         mtx_unlock(&sc->mtx);
  255 }
  256 
  257 static void
  258 aw_wdog_shutdown_fn(void *private, int howto)
  259 {
  260         if ((howto & (RB_POWEROFF|RB_HALT)) == 0)
  261                 aw_wdog_watchdog_reset();
  262 }
  263 
  264 void
  265 aw_wdog_watchdog_reset(void)
  266 {
  267 
  268         if (aw_wdog_sc == NULL) {
  269                 printf("Reset: watchdog device has not been initialized\n");
  270                 return;
  271         }
  272 
  273         WRITE(aw_wdog_sc, aw_wdog_sc->wdog_mode, aw_wdog_sc->wdog_mode_key |
  274             (wd_intervals[0].value << aw_wdog_sc->wdog_mode_intvl_shift) |
  275             aw_wdog_sc->wdog_mode_en);
  276         if (aw_wdog_sc->wdog_config)
  277                 WRITE(aw_wdog_sc, aw_wdog_sc->wdog_config,
  278                       aw_wdog_sc->wdog_config_value);
  279         WRITE(aw_wdog_sc, aw_wdog_sc->wdog_ctrl,
  280             WDOG_CTRL_RESTART | aw_wdog_sc->wdog_ctrl_key);
  281         while(1)
  282                 ;
  283 
  284 }
  285 
  286 static device_method_t aw_wdog_methods[] = {
  287         DEVMETHOD(device_probe, aw_wdog_probe),
  288         DEVMETHOD(device_attach, aw_wdog_attach),
  289 
  290         DEVMETHOD_END
  291 };
  292 
  293 static driver_t aw_wdog_driver = {
  294         "aw_wdog",
  295         aw_wdog_methods,
  296         sizeof(struct aw_wdog_softc),
  297 };
  298 static devclass_t aw_wdog_devclass;
  299 
  300 DRIVER_MODULE(aw_wdog, simplebus, aw_wdog_driver, aw_wdog_devclass, 0, 0);

Cache object: 15683a5fe628154680e76ef52386aabd


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