uboot/drivers/watchdog/tangier_wdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2017 Intel Corporation
   4 */
   5#include <common.h>
   6#include <dm.h>
   7#include <log.h>
   8#include <wdt.h>
   9#include <div64.h>
  10#include <asm/scu.h>
  11
  12/* Hardware timeout in seconds */
  13#define WDT_PRETIMEOUT          15
  14#define WDT_TIMEOUT_MIN         (1 + WDT_PRETIMEOUT)
  15#define WDT_TIMEOUT_MAX         170
  16
  17/*
  18 * Note, firmware chooses 90 seconds as a default timeout for watchdog on
  19 * Intel Tangier SoC. It means that without handling it in the running code
  20 * the reboot will happen.
  21 */
  22
  23enum {
  24        SCU_WATCHDOG_START                      = 0,
  25        SCU_WATCHDOG_STOP                       = 1,
  26        SCU_WATCHDOG_KEEPALIVE                  = 2,
  27        SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT      = 3,
  28};
  29
  30static int tangier_wdt_reset(struct udevice *dev)
  31{
  32        scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_KEEPALIVE);
  33        return 0;
  34}
  35
  36static int tangier_wdt_stop(struct udevice *dev)
  37{
  38        return scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_STOP);
  39}
  40
  41static int tangier_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
  42{
  43        u32 timeout_sec;
  44        int in_size;
  45        struct ipc_wd_start {
  46                u32 pretimeout;
  47                u32 timeout;
  48        } ipc_wd_start;
  49
  50        /* Calculate timeout in seconds and restrict to min and max value */
  51        do_div(timeout_ms, 1000);
  52        timeout_sec = clamp_t(u32, timeout_ms, WDT_TIMEOUT_MIN, WDT_TIMEOUT_MAX);
  53
  54        /* Update values in the IPC request */
  55        ipc_wd_start.pretimeout = timeout_sec - WDT_PRETIMEOUT;
  56        ipc_wd_start.timeout = timeout_sec;
  57
  58        /*
  59         * SCU expects the input size for watchdog IPC
  60         * to be based on 4 bytes
  61         */
  62        in_size = DIV_ROUND_UP(sizeof(ipc_wd_start), 4);
  63
  64        scu_ipc_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_START,
  65                        (u32 *)&ipc_wd_start, in_size, NULL, 0);
  66
  67        return 0;
  68}
  69
  70static const struct wdt_ops tangier_wdt_ops = {
  71        .reset = tangier_wdt_reset,
  72        .start = tangier_wdt_start,
  73        .stop = tangier_wdt_stop,
  74};
  75
  76static const struct udevice_id tangier_wdt_ids[] = {
  77        { .compatible = "intel,tangier-wdt" },
  78        { /* sentinel */ }
  79};
  80
  81static int tangier_wdt_probe(struct udevice *dev)
  82{
  83        debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
  84        return 0;
  85}
  86
  87U_BOOT_DRIVER(wdt_tangier) = {
  88        .name = "wdt_tangier",
  89        .id = UCLASS_WDT,
  90        .of_match = tangier_wdt_ids,
  91        .ops = &tangier_wdt_ops,
  92        .probe = tangier_wdt_probe,
  93};
  94