uboot/drivers/watchdog/ulp_wdog.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
   4 */
   5
   6#include <common.h>
   7#include <cpu_func.h>
   8#include <asm/io.h>
   9#include <asm/arch/imx-regs.h>
  10#include <dm.h>
  11#include <wdt.h>
  12
  13/*
  14 * MX7ULP WDOG Register Map
  15 */
  16struct wdog_regs {
  17        u32 cs;
  18        u32 cnt;
  19        u32 toval;
  20        u32 win;
  21};
  22
  23struct ulp_wdt_priv {
  24        struct wdog_regs *wdog;
  25        u32 clk_rate;
  26};
  27
  28#define REFRESH_WORD0 0xA602 /* 1st refresh word */
  29#define REFRESH_WORD1 0xB480 /* 2nd refresh word */
  30
  31#define UNLOCK_WORD0 0xC520 /* 1st unlock word */
  32#define UNLOCK_WORD1 0xD928 /* 2nd unlock word */
  33
  34#define UNLOCK_WORD 0xD928C520 /* unlock word */
  35#define REFRESH_WORD 0xB480A602 /* refresh word */
  36
  37#define WDGCS_WDGE                      BIT(7)
  38#define WDGCS_WDGUPDATE                 BIT(5)
  39
  40#define WDGCS_RCS                       BIT(10)
  41#define WDGCS_ULK                       BIT(11)
  42#define WDOG_CS_PRES                    BIT(12)
  43#define WDGCS_CMD32EN                   BIT(13)
  44#define WDGCS_FLG                       BIT(14)
  45#define WDGCS_INT                       BIT(6)
  46
  47#define WDG_BUS_CLK                      (0x0)
  48#define WDG_LPO_CLK                      (0x1)
  49#define WDG_32KHZ_CLK                    (0x2)
  50#define WDG_EXT_CLK                      (0x3)
  51
  52#define CLK_RATE_1KHZ                   1000
  53#define CLK_RATE_32KHZ                  125
  54
  55void hw_watchdog_set_timeout(u16 val)
  56{
  57        /* setting timeout value */
  58        struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
  59
  60        writel(val, &wdog->toval);
  61}
  62
  63void ulp_watchdog_reset(struct wdog_regs *wdog)
  64{
  65        if (readl(&wdog->cs) & WDGCS_CMD32EN) {
  66                writel(REFRESH_WORD, &wdog->cnt);
  67        } else {
  68                dmb();
  69                __raw_writel(REFRESH_WORD0, &wdog->cnt);
  70                __raw_writel(REFRESH_WORD1, &wdog->cnt);
  71                dmb();
  72        }
  73}
  74
  75void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout)
  76{
  77        u32 cmd32 = 0;
  78
  79        if (readl(&wdog->cs) & WDGCS_CMD32EN) {
  80                writel(UNLOCK_WORD, &wdog->cnt);
  81                cmd32 = WDGCS_CMD32EN;
  82        } else {
  83                dmb();
  84                __raw_writel(UNLOCK_WORD0, &wdog->cnt);
  85                __raw_writel(UNLOCK_WORD1, &wdog->cnt);
  86                dmb();
  87        }
  88
  89        /* Wait WDOG Unlock */
  90        while (!(readl(&wdog->cs) & WDGCS_ULK))
  91                ;
  92
  93        hw_watchdog_set_timeout(timeout);
  94        writel(0, &wdog->win);
  95
  96        /* setting 1-kHz clock source, enable counter running, and clear interrupt */
  97        if (IS_ENABLED(CONFIG_ARCH_IMX9))
  98                writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
  99                       WDGCS_FLG | WDOG_CS_PRES | WDGCS_INT), &wdog->cs);
 100        else
 101                writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
 102                       WDGCS_FLG), &wdog->cs);
 103
 104        /* Wait WDOG reconfiguration */
 105        while (!(readl(&wdog->cs) & WDGCS_RCS))
 106                ;
 107
 108        ulp_watchdog_reset(wdog);
 109}
 110
 111void hw_watchdog_reset(void)
 112{
 113        struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
 114
 115        ulp_watchdog_reset(wdog);
 116}
 117
 118void hw_watchdog_init(void)
 119{
 120        struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
 121
 122        ulp_watchdog_init(wdog, CONFIG_WATCHDOG_TIMEOUT_MSECS);
 123}
 124
 125void reset_cpu(void)
 126{
 127        struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
 128        u32 cmd32 = 0;
 129
 130        if (readl(&wdog->cs) & WDGCS_CMD32EN) {
 131                writel(UNLOCK_WORD, &wdog->cnt);
 132                cmd32 = WDGCS_CMD32EN;
 133        } else {
 134                dmb();
 135                __raw_writel(UNLOCK_WORD0, &wdog->cnt);
 136                __raw_writel(UNLOCK_WORD1, &wdog->cnt);
 137                dmb();
 138        }
 139
 140        /* Wait WDOG Unlock */
 141        while (!(readl(&wdog->cs) & WDGCS_ULK))
 142                ;
 143
 144        hw_watchdog_set_timeout(5); /* 5ms timeout for general; 40ms timeout for imx93 */
 145        writel(0, &wdog->win);
 146
 147        /* enable counter running */
 148        if (IS_ENABLED(CONFIG_ARCH_IMX9))
 149                writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8) | WDOG_CS_PRES |
 150                       WDGCS_INT), &wdog->cs);
 151        else
 152                writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8)), &wdog->cs);
 153
 154        /* Wait WDOG reconfiguration */
 155        while (!(readl(&wdog->cs) & WDGCS_RCS))
 156                ;
 157
 158        hw_watchdog_reset();
 159
 160        while (1);
 161}
 162
 163static int ulp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
 164{
 165        struct ulp_wdt_priv *priv = dev_get_priv(dev);
 166        u64 timeout = 0;
 167
 168        timeout = (timeout_ms * priv->clk_rate) / 1000;
 169        if (timeout > U16_MAX)
 170                return -EINVAL;
 171
 172        ulp_watchdog_init(priv->wdog, (u16)timeout);
 173
 174        return 0;
 175}
 176
 177static int ulp_wdt_reset(struct udevice *dev)
 178{
 179        struct ulp_wdt_priv *priv = dev_get_priv(dev);
 180
 181        ulp_watchdog_reset(priv->wdog);
 182
 183        return 0;
 184}
 185
 186static int ulp_wdt_probe(struct udevice *dev)
 187{
 188        struct ulp_wdt_priv *priv = dev_get_priv(dev);
 189
 190        priv->wdog = dev_read_addr_ptr(dev);
 191        if (!priv->wdog)
 192                return -EINVAL;
 193
 194        priv->clk_rate = (u32)dev_get_driver_data(dev);
 195        if (!priv->clk_rate)
 196                return -EINVAL;
 197
 198        return 0;
 199}
 200
 201static const struct wdt_ops ulp_wdt_ops = {
 202        .start = ulp_wdt_start,
 203        .reset = ulp_wdt_reset,
 204};
 205
 206static const struct udevice_id ulp_wdt_ids[] = {
 207        { .compatible = "fsl,imx7ulp-wdt", .data = CLK_RATE_1KHZ },
 208        { .compatible = "fsl,imx8ulp-wdt", .data = CLK_RATE_1KHZ },
 209        { .compatible = "fsl,imx93-wdt", .data = CLK_RATE_32KHZ },
 210        {}
 211};
 212
 213U_BOOT_DRIVER(ulp_wdt) = {
 214        .name   = "ulp_wdt",
 215        .id     = UCLASS_WDT,
 216        .of_match       = ulp_wdt_ids,
 217        .priv_auto      = sizeof(struct ulp_wdt_priv),
 218        .probe          = ulp_wdt_probe,
 219        .ops    = &ulp_wdt_ops,
 220};
 221