sbsa_gwdt.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Watchdog driver for SBSA
  4. *
  5. * Copyright 2020 NXP
  6. */
  7. #include <asm/global_data.h>
  8. #include <asm/io.h>
  9. #include <common.h>
  10. #include <dm/device.h>
  11. #include <dm/fdtaddr.h>
  12. #include <dm/read.h>
  13. #include <linux/bitops.h>
  14. #include <linux/err.h>
  15. #include <watchdog.h>
  16. #include <wdt.h>
  17. DECLARE_GLOBAL_DATA_PTR;
  18. /* SBSA Generic Watchdog register definitions */
  19. /* refresh frame */
  20. #define SBSA_GWDT_WRR 0x000
  21. /* control frame */
  22. #define SBSA_GWDT_WCS 0x000
  23. #define SBSA_GWDT_WOR 0x008
  24. #define SBSA_GWDT_WCV 0x010
  25. /* refresh/control frame */
  26. #define SBSA_GWDT_W_IIDR 0xfcc
  27. #define SBSA_GWDT_IDR 0xfd0
  28. /* Watchdog Control and Status Register */
  29. #define SBSA_GWDT_WCS_EN BIT(0)
  30. #define SBSA_GWDT_WCS_WS0 BIT(1)
  31. #define SBSA_GWDT_WCS_WS1 BIT(2)
  32. struct sbsa_gwdt_priv {
  33. void __iomem *reg_refresh;
  34. void __iomem *reg_control;
  35. };
  36. static int sbsa_gwdt_reset(struct udevice *dev)
  37. {
  38. struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  39. writel(0, priv->reg_refresh + SBSA_GWDT_WRR);
  40. return 0;
  41. }
  42. static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags)
  43. {
  44. struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  45. u32 clk;
  46. /*
  47. * it work in the single stage mode in u-boot,
  48. * The first signal (WS0) is ignored,
  49. * the timeout is (WOR * 2), so the WOR should be configured
  50. * to half value of timeout.
  51. */
  52. clk = get_tbclk();
  53. writel(clk / (2 * 1000) * timeout,
  54. priv->reg_control + SBSA_GWDT_WOR);
  55. /* writing WCS will cause an explicit watchdog refresh */
  56. writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS);
  57. return 0;
  58. }
  59. static int sbsa_gwdt_stop(struct udevice *dev)
  60. {
  61. struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  62. writel(0, priv->reg_control + SBSA_GWDT_WCS);
  63. return 0;
  64. }
  65. static int sbsa_gwdt_expire_now(struct udevice *dev, ulong flags)
  66. {
  67. sbsa_gwdt_start(dev, 0, flags);
  68. return 0;
  69. }
  70. static int sbsa_gwdt_probe(struct udevice *dev)
  71. {
  72. debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev_seq(dev));
  73. return 0;
  74. }
  75. static int sbsa_gwdt_of_to_plat(struct udevice *dev)
  76. {
  77. struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  78. priv->reg_control = (void __iomem *)dev_read_addr_index(dev, 0);
  79. if (IS_ERR(priv->reg_control))
  80. return PTR_ERR(priv->reg_control);
  81. priv->reg_refresh = (void __iomem *)dev_read_addr_index(dev, 1);
  82. if (IS_ERR(priv->reg_refresh))
  83. return PTR_ERR(priv->reg_refresh);
  84. return 0;
  85. }
  86. static const struct wdt_ops sbsa_gwdt_ops = {
  87. .start = sbsa_gwdt_start,
  88. .reset = sbsa_gwdt_reset,
  89. .stop = sbsa_gwdt_stop,
  90. .expire_now = sbsa_gwdt_expire_now,
  91. };
  92. static const struct udevice_id sbsa_gwdt_ids[] = {
  93. { .compatible = "arm,sbsa-gwdt" },
  94. {}
  95. };
  96. U_BOOT_DRIVER(sbsa_gwdt) = {
  97. .name = "sbsa_gwdt",
  98. .id = UCLASS_WDT,
  99. .of_match = sbsa_gwdt_ids,
  100. .probe = sbsa_gwdt_probe,
  101. .priv_auto = sizeof(struct sbsa_gwdt_priv),
  102. .of_to_plat = sbsa_gwdt_of_to_plat,
  103. .ops = &sbsa_gwdt_ops,
  104. };