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