reset-starfive-jh71x0.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Reset driver for the StarFive JH71X0 SoCs
  4. *
  5. * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
  6. */
  7. #include <linux/bitmap.h>
  8. #include <linux/device.h>
  9. #include <linux/io.h>
  10. #include <linux/iopoll.h>
  11. #include <linux/reset-controller.h>
  12. #include <linux/spinlock.h>
  13. #include "reset-starfive-jh71x0.h"
  14. struct jh71x0_reset {
  15. struct reset_controller_dev rcdev;
  16. /* protect registers against concurrent read-modify-write */
  17. spinlock_t lock;
  18. void __iomem *assert;
  19. void __iomem *status;
  20. const u32 *asserted;
  21. };
  22. static inline struct jh71x0_reset *
  23. jh71x0_reset_from(struct reset_controller_dev *rcdev)
  24. {
  25. return container_of(rcdev, struct jh71x0_reset, rcdev);
  26. }
  27. static int jh71x0_reset_update(struct reset_controller_dev *rcdev,
  28. unsigned long id, bool assert)
  29. {
  30. struct jh71x0_reset *data = jh71x0_reset_from(rcdev);
  31. unsigned long offset = id / 32;
  32. u32 mask = BIT(id % 32);
  33. void __iomem *reg_assert = data->assert + offset * sizeof(u32);
  34. void __iomem *reg_status = data->status + offset * sizeof(u32);
  35. u32 done = data->asserted ? data->asserted[offset] & mask : 0;
  36. u32 value;
  37. unsigned long flags;
  38. int ret;
  39. if (!assert)
  40. done ^= mask;
  41. spin_lock_irqsave(&data->lock, flags);
  42. value = readl(reg_assert);
  43. if (assert)
  44. value |= mask;
  45. else
  46. value &= ~mask;
  47. writel(value, reg_assert);
  48. /* if the associated clock is gated, deasserting might otherwise hang forever */
  49. ret = readl_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000);
  50. spin_unlock_irqrestore(&data->lock, flags);
  51. return ret;
  52. }
  53. static int jh71x0_reset_assert(struct reset_controller_dev *rcdev,
  54. unsigned long id)
  55. {
  56. return jh71x0_reset_update(rcdev, id, true);
  57. }
  58. static int jh71x0_reset_deassert(struct reset_controller_dev *rcdev,
  59. unsigned long id)
  60. {
  61. return jh71x0_reset_update(rcdev, id, false);
  62. }
  63. static int jh71x0_reset_reset(struct reset_controller_dev *rcdev,
  64. unsigned long id)
  65. {
  66. int ret;
  67. ret = jh71x0_reset_assert(rcdev, id);
  68. if (ret)
  69. return ret;
  70. return jh71x0_reset_deassert(rcdev, id);
  71. }
  72. static int jh71x0_reset_status(struct reset_controller_dev *rcdev,
  73. unsigned long id)
  74. {
  75. struct jh71x0_reset *data = jh71x0_reset_from(rcdev);
  76. unsigned long offset = id / 32;
  77. u32 mask = BIT(id % 32);
  78. void __iomem *reg_status = data->status + offset * sizeof(u32);
  79. u32 value = readl(reg_status);
  80. if (!data->asserted)
  81. return !(value & mask);
  82. return !((value ^ data->asserted[offset]) & mask);
  83. }
  84. static const struct reset_control_ops jh71x0_reset_ops = {
  85. .assert = jh71x0_reset_assert,
  86. .deassert = jh71x0_reset_deassert,
  87. .reset = jh71x0_reset_reset,
  88. .status = jh71x0_reset_status,
  89. };
  90. int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node,
  91. void __iomem *assert, void __iomem *status,
  92. const u32 *asserted, unsigned int nr_resets,
  93. struct module *owner)
  94. {
  95. struct jh71x0_reset *data;
  96. data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  97. if (!data)
  98. return -ENOMEM;
  99. data->rcdev.ops = &jh71x0_reset_ops;
  100. data->rcdev.owner = owner;
  101. data->rcdev.nr_resets = nr_resets;
  102. data->rcdev.dev = dev;
  103. data->rcdev.of_node = of_node;
  104. spin_lock_init(&data->lock);
  105. data->assert = assert;
  106. data->status = status;
  107. data->asserted = asserted;
  108. return devm_reset_controller_register(dev, &data->rcdev);
  109. }
  110. EXPORT_SYMBOL_GPL(reset_starfive_jh71x0_register);