stm32mp_wdt.c 3.2 KB

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