starfive-power-domain.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
  4. */
  5. #include <asm/io.h>
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <linux/bitops.h>
  9. #include <linux/iopoll.h>
  10. #include <malloc.h>
  11. #include <power-domain-uclass.h>
  12. #define usleep_range(a, b) udelay((b))
  13. #define MAX_DOMAINS 64
  14. #define TIMEOUT_US 100000
  15. /* register define */
  16. #define HW_EVENT_TURN_ON_MASK 0x04
  17. #define HW_EVENT_TURN_OFF_MASK 0x08
  18. #define SW_TURN_ON_POWER_MODE 0x0C
  19. #define SW_TURN_OFF_POWER_MODE 0x10
  20. #define SW_ENCOURAGE 0x44
  21. #define PMU_INT_MASK 0x48
  22. #define PCH_BYPASS 0x4C
  23. #define PCH_PSTATE 0x50
  24. #define PCH_TIMEOUT 0x54
  25. #define LP_TIMEOUT 0x58
  26. #define HW_TURN_ON_MODE 0x5C
  27. #define CURR_POWER_MODE 0x80
  28. #define PMU_EVENT_STATUS 0x88
  29. #define PMU_INT_STATUS 0x8C
  30. /* sw encourage cfg */
  31. #define SW_MODE_ENCOURAGE_EN_LO 0x05
  32. #define SW_MODE_ENCOURAGE_EN_HI 0x50
  33. #define SW_MODE_ENCOURAGE_DIS_LO 0x0A
  34. #define SW_MODE_ENCOURAGE_DIS_HI 0xA0
  35. #define SW_MODE_ENCOURAGE_ON 0xFF
  36. struct sf_power_domain {
  37. void __iomem *regs;
  38. };
  39. static int sf_power_domain_request(struct power_domain *power_domain)
  40. {
  41. if (power_domain->id >= MAX_DOMAINS)
  42. return -EINVAL;
  43. return 0;
  44. }
  45. static int sf_power_domain_free(struct power_domain *power_domain)
  46. {
  47. return 0;
  48. }
  49. static int sf_power_domain_on(struct power_domain *power_domain)
  50. {
  51. struct sf_power_domain *priv = dev_get_priv(power_domain->dev);
  52. uint32_t mode;
  53. uint32_t val;
  54. uint32_t encourage_lo;
  55. uint32_t encourage_hi;
  56. int ret;
  57. mode = SW_TURN_ON_POWER_MODE;
  58. encourage_lo = SW_MODE_ENCOURAGE_EN_LO;
  59. encourage_hi = SW_MODE_ENCOURAGE_EN_HI;
  60. /* write SW_ENCOURAGE to make the configuration take effect */
  61. val = __raw_readl(priv->regs + mode) | BIT(power_domain->id);
  62. __raw_writel(val, priv->regs + mode);
  63. __raw_writel(SW_MODE_ENCOURAGE_ON, priv->regs + SW_ENCOURAGE);
  64. __raw_writel(encourage_lo, priv->regs + SW_ENCOURAGE);
  65. __raw_writel(encourage_hi, priv->regs + SW_ENCOURAGE);
  66. ret = readl_poll_timeout(priv->regs + CURR_POWER_MODE, val,
  67. val & BIT(power_domain->id),
  68. TIMEOUT_US);
  69. if (ret) {
  70. pr_err("power_on failed");
  71. return -ETIMEDOUT;
  72. }
  73. return 0;
  74. }
  75. static int sf_power_domain_off(struct power_domain *power_domain)
  76. {
  77. struct sf_power_domain *priv = dev_get_priv(power_domain->dev);
  78. uint32_t mode;
  79. uint32_t val;
  80. uint32_t encourage_lo;
  81. uint32_t encourage_hi;
  82. int ret;
  83. mode = SW_TURN_OFF_POWER_MODE;
  84. encourage_lo = SW_MODE_ENCOURAGE_DIS_LO;
  85. encourage_hi = SW_MODE_ENCOURAGE_DIS_HI;
  86. val = __raw_readl(priv->regs + mode) & ~(BIT(power_domain->id));
  87. __raw_writel(val, priv->regs + mode);
  88. __raw_writel(SW_MODE_ENCOURAGE_ON, priv->regs + SW_ENCOURAGE);
  89. __raw_writel(encourage_lo, priv->regs + SW_ENCOURAGE);
  90. __raw_writel(encourage_hi, priv->regs + SW_ENCOURAGE);
  91. ret = readl_poll_timeout(priv->regs + CURR_POWER_MODE, val,
  92. !(val & BIT(power_domain->id)),
  93. TIMEOUT_US);
  94. if (ret) {
  95. pr_err("power_off failed");
  96. return -ETIMEDOUT;
  97. }
  98. return 0;
  99. }
  100. static int sf_power_domain_probe(struct udevice *dev)
  101. {
  102. struct sf_power_domain *priv = dev_get_priv(dev);
  103. fdt_addr_t addr;
  104. addr = dev_read_addr_index(dev, 0);
  105. priv->regs = (void __iomem *)addr;
  106. if (!priv->regs)
  107. return -EINVAL;
  108. return 0;
  109. }
  110. static const struct udevice_id sf_power_domain_ids[] = {
  111. { .compatible = "starfive,jh7110-pmu" },
  112. { /* sentinel */ }
  113. };
  114. struct power_domain_ops sf_power_domain_ops = {
  115. .rfree = sf_power_domain_free,
  116. .off = sf_power_domain_off,
  117. .on = sf_power_domain_on,
  118. .request = sf_power_domain_request,
  119. };
  120. U_BOOT_DRIVER(sf_power_domain) = {
  121. .name = "sf_power_domain",
  122. .id = UCLASS_POWER_DOMAIN,
  123. .of_match = sf_power_domain_ids,
  124. .ops = &sf_power_domain_ops,
  125. .priv_auto = sizeof(struct sf_power_domain),
  126. .probe = sf_power_domain_probe,
  127. };