softrst.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) 2014 MundoReader S.L.
  4. * Author: Heiko Stuebner <heiko@sntech.de>
  5. */
  6. #include <linux/slab.h>
  7. #include <linux/io.h>
  8. #include <linux/reset-controller.h>
  9. #include <linux/spinlock.h>
  10. #include "clk.h"
  11. struct rockchip_softrst {
  12. struct reset_controller_dev rcdev;
  13. const int *lut;
  14. void __iomem *reg_base;
  15. int num_regs;
  16. int num_per_reg;
  17. u8 flags;
  18. spinlock_t lock;
  19. };
  20. static int rockchip_softrst_assert(struct reset_controller_dev *rcdev,
  21. unsigned long id)
  22. {
  23. struct rockchip_softrst *softrst = container_of(rcdev,
  24. struct rockchip_softrst,
  25. rcdev);
  26. int bank, offset;
  27. if (softrst->lut)
  28. id = softrst->lut[id];
  29. bank = id / softrst->num_per_reg;
  30. offset = id % softrst->num_per_reg;
  31. if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
  32. writel(BIT(offset) | (BIT(offset) << 16),
  33. softrst->reg_base + (bank * 4));
  34. } else {
  35. unsigned long flags;
  36. u32 reg;
  37. spin_lock_irqsave(&softrst->lock, flags);
  38. reg = readl(softrst->reg_base + (bank * 4));
  39. writel(reg | BIT(offset), softrst->reg_base + (bank * 4));
  40. spin_unlock_irqrestore(&softrst->lock, flags);
  41. }
  42. return 0;
  43. }
  44. static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev,
  45. unsigned long id)
  46. {
  47. struct rockchip_softrst *softrst = container_of(rcdev,
  48. struct rockchip_softrst,
  49. rcdev);
  50. int bank, offset;
  51. if (softrst->lut)
  52. id = softrst->lut[id];
  53. bank = id / softrst->num_per_reg;
  54. offset = id % softrst->num_per_reg;
  55. if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
  56. writel((BIT(offset) << 16), softrst->reg_base + (bank * 4));
  57. } else {
  58. unsigned long flags;
  59. u32 reg;
  60. spin_lock_irqsave(&softrst->lock, flags);
  61. reg = readl(softrst->reg_base + (bank * 4));
  62. writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4));
  63. spin_unlock_irqrestore(&softrst->lock, flags);
  64. }
  65. return 0;
  66. }
  67. static const struct reset_control_ops rockchip_softrst_ops = {
  68. .assert = rockchip_softrst_assert,
  69. .deassert = rockchip_softrst_deassert,
  70. };
  71. void rockchip_register_softrst_lut(struct device_node *np,
  72. const int *lookup_table,
  73. unsigned int num_regs,
  74. void __iomem *base, u8 flags)
  75. {
  76. struct rockchip_softrst *softrst;
  77. int ret;
  78. softrst = kzalloc(sizeof(*softrst), GFP_KERNEL);
  79. if (!softrst)
  80. return;
  81. spin_lock_init(&softrst->lock);
  82. softrst->reg_base = base;
  83. softrst->lut = lookup_table;
  84. softrst->flags = flags;
  85. softrst->num_regs = num_regs;
  86. softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16
  87. : 32;
  88. softrst->rcdev.owner = THIS_MODULE;
  89. if (lookup_table)
  90. softrst->rcdev.nr_resets = num_regs;
  91. else
  92. softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg;
  93. softrst->rcdev.ops = &rockchip_softrst_ops;
  94. softrst->rcdev.of_node = np;
  95. ret = reset_controller_register(&softrst->rcdev);
  96. if (ret) {
  97. pr_err("%s: could not register reset controller, %d\n",
  98. __func__, ret);
  99. kfree(softrst);
  100. }
  101. };
  102. EXPORT_SYMBOL_GPL(rockchip_register_softrst_lut);