pmu.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2017 Intel Corporation
  4. */
  5. #include <common.h>
  6. #include <dm.h>
  7. #include <regmap.h>
  8. #include <syscon.h>
  9. #include <asm/cpu.h>
  10. #include <asm/pmu.h>
  11. #include <linux/delay.h>
  12. #include <linux/errno.h>
  13. #include <linux/io.h>
  14. /* Registers */
  15. struct pmu_regs {
  16. u32 sts;
  17. u32 cmd;
  18. u32 ics;
  19. u32 reserved;
  20. u32 wkc[4];
  21. u32 wks[4];
  22. u32 ssc[4];
  23. u32 sss[4];
  24. };
  25. /* Bits in PMU_REGS_STS */
  26. #define PMU_REGS_STS_BUSY (1 << 8)
  27. struct pmu_mid {
  28. struct pmu_regs *regs;
  29. };
  30. static int pmu_read_status(struct pmu_regs *regs)
  31. {
  32. int retry = 500000;
  33. u32 val;
  34. do {
  35. val = readl(&regs->sts);
  36. if (!(val & PMU_REGS_STS_BUSY))
  37. return 0;
  38. udelay(1);
  39. } while (--retry);
  40. printf("WARNING: PMU still busy\n");
  41. return -EBUSY;
  42. }
  43. static int pmu_power_lss(struct pmu_regs *regs, unsigned int lss, bool on)
  44. {
  45. unsigned int offset = (lss * 2) / 32;
  46. unsigned int shift = (lss * 2) % 32;
  47. u32 ssc;
  48. int ret;
  49. /* Check PMU status */
  50. ret = pmu_read_status(regs);
  51. if (ret)
  52. return ret;
  53. /* Read PMU values */
  54. ssc = readl(&regs->sss[offset]);
  55. /* Modify PMU values */
  56. if (on)
  57. ssc &= ~(0x3 << shift); /* D0 */
  58. else
  59. ssc |= 0x3 << shift; /* D3hot */
  60. /* Write modified PMU values */
  61. writel(ssc, &regs->ssc[offset]);
  62. /* Update modified PMU values */
  63. writel(0x00002201, &regs->cmd);
  64. /* Check PMU status */
  65. return pmu_read_status(regs);
  66. }
  67. int pmu_turn_power(unsigned int lss, bool on)
  68. {
  69. struct pmu_mid *pmu;
  70. struct udevice *dev;
  71. int ret;
  72. ret = syscon_get_by_driver_data(X86_SYSCON_PMU, &dev);
  73. if (ret)
  74. return ret;
  75. pmu = dev_get_priv(dev);
  76. return pmu_power_lss(pmu->regs, lss, on);
  77. }
  78. static int pmu_mid_probe(struct udevice *dev)
  79. {
  80. struct pmu_mid *pmu = dev_get_priv(dev);
  81. pmu->regs = syscon_get_first_range(X86_SYSCON_PMU);
  82. return 0;
  83. }
  84. static const struct udevice_id pmu_mid_match[] = {
  85. { .compatible = "intel,pmu-mid", .data = X86_SYSCON_PMU },
  86. { /* sentinel */ }
  87. };
  88. U_BOOT_DRIVER(intel_mid_pmu) = {
  89. .name = "pmu_mid",
  90. .id = UCLASS_SYSCON,
  91. .of_match = pmu_mid_match,
  92. .probe = pmu_mid_probe,
  93. .priv_auto_alloc_size = sizeof(struct pmu_mid),
  94. };