reset-rockchip.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * (C) Copyright 2017 Rockchip Electronics Co., Ltd
  4. */
  5. #include <common.h>
  6. #include <dm.h>
  7. #include <log.h>
  8. #include <malloc.h>
  9. #include <reset-uclass.h>
  10. #include <linux/bitops.h>
  11. #include <linux/io.h>
  12. #include <asm/arch-rockchip/hardware.h>
  13. #include <dm/device-internal.h>
  14. #include <dm/lists.h>
  15. /*
  16. * Each reg has 16 bits reset signal for devices
  17. * Note: Not including rk2818 and older SoCs
  18. */
  19. #define ROCKCHIP_RESET_NUM_IN_REG 16
  20. struct rockchip_reset_priv {
  21. void __iomem *base;
  22. const int *lut;
  23. /* Rockchip reset reg locate at cru controller */
  24. u32 reset_reg_offset;
  25. /* Rockchip reset reg number */
  26. u32 reset_reg_num;
  27. };
  28. static int rockchip_reset_request(struct reset_ctl *reset_ctl)
  29. {
  30. struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
  31. unsigned long id = reset_ctl->id;
  32. if (priv->lut)
  33. id = priv->lut[id];
  34. debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_num=%d)\n", __func__,
  35. reset_ctl, reset_ctl->dev, id, priv->reset_reg_num);
  36. if (id / ROCKCHIP_RESET_NUM_IN_REG >= priv->reset_reg_num)
  37. return -EINVAL;
  38. return 0;
  39. }
  40. static int rockchip_reset_assert(struct reset_ctl *reset_ctl)
  41. {
  42. struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
  43. unsigned long id = reset_ctl->id;
  44. int bank, offset;
  45. if (priv->lut)
  46. id = priv->lut[id];
  47. bank = id / ROCKCHIP_RESET_NUM_IN_REG;
  48. offset = id % ROCKCHIP_RESET_NUM_IN_REG;
  49. debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_addr=%p)\n", __func__,
  50. reset_ctl, reset_ctl->dev, id, priv->base + (bank * 4));
  51. rk_setreg(priv->base + (bank * 4), BIT(offset));
  52. return 0;
  53. }
  54. static int rockchip_reset_deassert(struct reset_ctl *reset_ctl)
  55. {
  56. struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
  57. unsigned long id = reset_ctl->id;
  58. int bank, offset;
  59. if (priv->lut)
  60. id = priv->lut[id];
  61. bank = id / ROCKCHIP_RESET_NUM_IN_REG;
  62. offset = id % ROCKCHIP_RESET_NUM_IN_REG;
  63. debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_addr=%p)\n", __func__,
  64. reset_ctl, reset_ctl->dev, id, priv->base + (bank * 4));
  65. rk_clrreg(priv->base + (bank * 4), BIT(offset));
  66. return 0;
  67. }
  68. struct reset_ops rockchip_reset_ops = {
  69. .request = rockchip_reset_request,
  70. .rst_assert = rockchip_reset_assert,
  71. .rst_deassert = rockchip_reset_deassert,
  72. };
  73. static int rockchip_reset_probe(struct udevice *dev)
  74. {
  75. struct rockchip_reset_priv *priv = dev_get_priv(dev);
  76. fdt_addr_t addr;
  77. fdt_size_t size;
  78. addr = dev_read_addr_size(dev, &size);
  79. if (addr == FDT_ADDR_T_NONE)
  80. return -EINVAL;
  81. if ((priv->reset_reg_offset == 0) && (priv->reset_reg_num == 0))
  82. return -EINVAL;
  83. addr += priv->reset_reg_offset;
  84. priv->base = ioremap(addr, size);
  85. debug("%s(base=%p) (reg_offset=%x, reg_num=%d)\n", __func__,
  86. priv->base, priv->reset_reg_offset, priv->reset_reg_num);
  87. return 0;
  88. }
  89. int rockchip_reset_bind_lut(struct udevice *pdev,
  90. const int *lookup_table,
  91. u32 reg_offset,
  92. u32 reg_number)
  93. {
  94. struct udevice *rst_dev;
  95. struct rockchip_reset_priv *priv;
  96. int ret;
  97. ret = device_bind_driver_to_node(pdev, "rockchip_reset", "reset",
  98. dev_ofnode(pdev), &rst_dev);
  99. if (ret) {
  100. debug("Warning: No rockchip reset driver: ret=%d\n", ret);
  101. return ret;
  102. }
  103. priv = malloc(sizeof(struct rockchip_reset_priv));
  104. priv->reset_reg_offset = reg_offset;
  105. priv->reset_reg_num = reg_number;
  106. priv->lut = lookup_table;
  107. dev_set_priv(rst_dev, priv);
  108. return 0;
  109. }
  110. int rockchip_reset_bind(struct udevice *pdev, u32 reg_offset, u32 reg_number)
  111. {
  112. return rockchip_reset_bind_lut(pdev, NULL, reg_offset, reg_number);
  113. }
  114. U_BOOT_DRIVER(rockchip_reset) = {
  115. .name = "rockchip_reset",
  116. .id = UCLASS_RESET,
  117. .probe = rockchip_reset_probe,
  118. .ops = &rockchip_reset_ops,
  119. .priv_auto = sizeof(struct rockchip_reset_priv),
  120. };