starfive-power-domain.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. __raw_writel(BIT(power_domain->id), priv->regs + mode);
  62. __raw_writel(SW_MODE_ENCOURAGE_ON, priv->regs + SW_ENCOURAGE);
  63. __raw_writel(encourage_lo, priv->regs + SW_ENCOURAGE);
  64. __raw_writel(encourage_hi, priv->regs + SW_ENCOURAGE);
  65. ret = readl_poll_timeout(priv->regs + CURR_POWER_MODE, val,
  66. val & BIT(power_domain->id),
  67. TIMEOUT_US);
  68. if (ret) {
  69. pr_err("power_on failed");
  70. return -ETIMEDOUT;
  71. }
  72. return 0;
  73. }
  74. static int sf_power_domain_off(struct power_domain *power_domain)
  75. {
  76. struct sf_power_domain *priv = dev_get_priv(power_domain->dev);
  77. uint32_t mode;
  78. uint32_t val;
  79. uint32_t encourage_lo;
  80. uint32_t encourage_hi;
  81. int ret;
  82. mode = SW_TURN_OFF_POWER_MODE;
  83. encourage_lo = SW_MODE_ENCOURAGE_DIS_LO;
  84. encourage_hi = SW_MODE_ENCOURAGE_DIS_HI;
  85. __raw_writel(BIT(power_domain->id), priv->regs + mode);
  86. __raw_writel(SW_MODE_ENCOURAGE_ON, priv->regs + SW_ENCOURAGE);
  87. __raw_writel(encourage_lo, priv->regs + SW_ENCOURAGE);
  88. __raw_writel(encourage_hi, priv->regs + SW_ENCOURAGE);
  89. ret = readl_poll_timeout(priv->regs + CURR_POWER_MODE, val,
  90. !(val & BIT(power_domain->id)),
  91. TIMEOUT_US);
  92. if (ret) {
  93. pr_err("power_off failed\n");
  94. return -ETIMEDOUT;
  95. }
  96. return 0;
  97. }
  98. static int sf_power_domain_probe(struct udevice *dev)
  99. {
  100. struct sf_power_domain *priv = dev_get_priv(dev);
  101. fdt_addr_t addr;
  102. addr = dev_read_addr_index(dev, 0);
  103. priv->regs = (void __iomem *)addr;
  104. if (!priv->regs)
  105. return -EINVAL;
  106. return 0;
  107. }
  108. static const struct udevice_id sf_power_domain_ids[] = {
  109. { .compatible = "starfive,jh7110-pmu" },
  110. { /* sentinel */ }
  111. };
  112. struct power_domain_ops sf_power_domain_ops = {
  113. .rfree = sf_power_domain_free,
  114. .off = sf_power_domain_off,
  115. .on = sf_power_domain_on,
  116. .request = sf_power_domain_request,
  117. };
  118. U_BOOT_DRIVER(sf_power_domain) = {
  119. .name = "sf_power_domain",
  120. .id = UCLASS_POWER_DOMAIN,
  121. .of_match = sf_power_domain_ids,
  122. .ops = &sf_power_domain_ops,
  123. .priv_auto = sizeof(struct sf_power_domain),
  124. .probe = sf_power_domain_probe,
  125. };