uboot/drivers/watchdog/stm32mp_wdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
   2/*
   3 * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
   4 */
   5
   6#define LOG_CATEGORY UCLASS_WDT
   7
   8#include <common.h>
   9#include <clk.h>
  10#include <dm.h>
  11#include <log.h>
  12#include <syscon.h>
  13#include <wdt.h>
  14#include <asm/io.h>
  15#include <dm/device_compat.h>
  16#include <linux/bitops.h>
  17#include <linux/iopoll.h>
  18
  19/* IWDG registers */
  20#define IWDG_KR         0x00    /* Key register */
  21#define IWDG_PR         0x04    /* Prescaler Register */
  22#define IWDG_RLR        0x08    /* ReLoad Register */
  23#define IWDG_SR         0x0C    /* Status Register */
  24
  25/* IWDG_KR register bit mask */
  26#define KR_KEY_RELOAD   0xAAAA  /* Reload counter enable */
  27#define KR_KEY_ENABLE   0xCCCC  /* Peripheral enable */
  28#define KR_KEY_EWA      0x5555  /* Write access enable */
  29
  30/* IWDG_PR register bit values */
  31#define PR_256          0x06    /* Prescaler set to 256 */
  32
  33/* IWDG_RLR register values */
  34#define RLR_MAX         0xFFF   /* Max value supported by reload register */
  35
  36/* IWDG_SR register bit values */
  37#define SR_PVU          BIT(0)  /* Watchdog prescaler value update */
  38#define SR_RVU          BIT(1)  /* Watchdog counter reload value update */
  39
  40struct stm32mp_wdt_priv {
  41        fdt_addr_t base;                /* registers addr in physical memory */
  42        unsigned long wdt_clk_rate;     /* Watchdog dedicated clock rate */
  43};
  44
  45static int stm32mp_wdt_reset(struct udevice *dev)
  46{
  47        struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
  48
  49        writel(KR_KEY_RELOAD, priv->base + IWDG_KR);
  50
  51        return 0;
  52}
  53
  54static int stm32mp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
  55{
  56        struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
  57        int reload;
  58        u32 val;
  59        int ret;
  60
  61        /* Prescaler fixed to 256 */
  62        reload = timeout_ms * priv->wdt_clk_rate / 256;
  63        if (reload > RLR_MAX + 1)
  64                /* Force to max watchdog counter reload value */
  65                reload = RLR_MAX + 1;
  66        else if (!reload)
  67                /* Force to min watchdog counter reload value */
  68                reload = priv->wdt_clk_rate / 256;
  69
  70        /* Set prescaler & reload registers */
  71        writel(KR_KEY_EWA, priv->base + IWDG_KR);
  72        writel(PR_256, priv->base + IWDG_PR);
  73        writel(reload - 1, priv->base + IWDG_RLR);
  74
  75        /* Enable watchdog */
  76        writel(KR_KEY_ENABLE, priv->base + IWDG_KR);
  77
  78        /* Wait for the registers to be updated */
  79        ret = readl_poll_timeout(priv->base + IWDG_SR, val,
  80                                 val & (SR_PVU | SR_RVU), CONFIG_SYS_HZ);
  81
  82        if (ret < 0) {
  83                dev_err(dev, "Updating IWDG registers timeout");
  84                return -ETIMEDOUT;
  85        }
  86
  87        return 0;
  88}
  89
  90static int stm32mp_wdt_probe(struct udevice *dev)
  91{
  92        struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
  93        struct clk clk;
  94        int ret;
  95
  96        dev_dbg(dev, "IWDG init\n");
  97
  98        priv->base = dev_read_addr(dev);
  99        if (priv->base == FDT_ADDR_T_NONE)
 100                return -EINVAL;
 101
 102        /* Enable clock */
 103        ret = clk_get_by_name(dev, "pclk", &clk);
 104        if (ret)
 105                return ret;
 106
 107        ret = clk_enable(&clk);
 108        if (ret)
 109                return ret;
 110
 111        /* Get LSI clock */
 112        ret = clk_get_by_name(dev, "lsi", &clk);
 113        if (ret)
 114                return ret;
 115
 116        priv->wdt_clk_rate = clk_get_rate(&clk);
 117
 118        dev_dbg(dev, "IWDG init done\n");
 119
 120        return 0;
 121}
 122
 123static const struct wdt_ops stm32mp_wdt_ops = {
 124        .start = stm32mp_wdt_start,
 125        .reset = stm32mp_wdt_reset,
 126};
 127
 128static const struct udevice_id stm32mp_wdt_match[] = {
 129        { .compatible = "st,stm32mp1-iwdg" },
 130        { /* sentinel */ }
 131};
 132
 133U_BOOT_DRIVER(stm32mp_wdt) = {
 134        .name = "stm32mp-wdt",
 135        .id = UCLASS_WDT,
 136        .of_match = stm32mp_wdt_match,
 137        .priv_auto      = sizeof(struct stm32mp_wdt_priv),
 138        .probe = stm32mp_wdt_probe,
 139        .ops = &stm32mp_wdt_ops,
 140};
 141