pme.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-10-24 GuEe-GUI first version
  9. */
  10. #include <drivers/pci.h>
  11. #include <drivers/core/power_domain.h>
  12. #define DBG_TAG "pci.pme"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. /*
  16. * Power Management Capability Register:
  17. *
  18. * 31 27 26 25 24 22 21 20 19 18 16 15 8 7 0
  19. * +---------+---+---+--------+---+---+---+------+-----------+----------------+
  20. * | | | | | | | | | | Capabilitiy ID |
  21. * +---------+---+---+--------+---+---+---+------+-----------+----------------+
  22. * ^ ^ ^ ^ ^ ^ ^ ^ ^
  23. * | | | | | | | | |
  24. * | | | | | | | | +---- Next Capabilitiy Pointer
  25. * | | | | | | | +------------- Version
  26. * | | | | | | +------------------- PME Clock
  27. * | | | | | +----------------------- Immediate Readiness on Return to D0
  28. * | | | | +--------------------------- Device Specifiic Initializtion
  29. * | | | +--------------------------------- Aux Current
  30. * | | +---------------------------------------- D1 Support
  31. * | +-------------------------------------------- D2 Support
  32. * +--------------------------------------------------- PME Support
  33. */
  34. void rt_pci_pme_init(struct rt_pci_device *pdev)
  35. {
  36. rt_uint16_t pmc;
  37. if (!pdev || !(pdev->pme_cap = rt_pci_find_capability(pdev, PCIY_PMG)))
  38. {
  39. return;
  40. }
  41. rt_pci_read_config_u16(pdev, pdev->pme_cap + PCIR_POWER_CAP, &pmc);
  42. if ((pmc & PCIM_PCAP_SPEC) > 3)
  43. {
  44. LOG_E("%s: Unsupported PME CAP regs spec %u",
  45. rt_dm_dev_get_name(&pdev->parent), pmc & PCIM_PCAP_SPEC);
  46. return;
  47. }
  48. pmc &= PCIM_PCAP_PMEMASK;
  49. if (pmc)
  50. {
  51. pdev->pme_support = RT_FIELD_GET(PCIM_PCAP_PMEMASK, pmc);
  52. rt_pci_pme_active(pdev, RT_FALSE);
  53. }
  54. }
  55. rt_err_t rt_pci_enable_wake(struct rt_pci_device *pdev,
  56. enum rt_pci_power state, rt_bool_t enable)
  57. {
  58. if (!pdev || state >= RT_PCI_PME_MAX)
  59. {
  60. return -RT_EINVAL;
  61. }
  62. if (enable)
  63. {
  64. if (rt_pci_pme_capable(pdev, state) ||
  65. rt_pci_pme_capable(pdev, RT_PCI_D3COLD))
  66. {
  67. rt_pci_pme_active(pdev, RT_EOK);
  68. }
  69. }
  70. else
  71. {
  72. rt_pci_pme_active(pdev, RT_FALSE);
  73. }
  74. return RT_EOK;
  75. }
  76. static void pci_pme_active(struct rt_pci_device *pdev, rt_bool_t enable)
  77. {
  78. rt_uint16_t pmcsr;
  79. if (!pdev->pme_support)
  80. {
  81. return;
  82. }
  83. rt_pci_read_config_u16(pdev, pdev->pme_cap + PCIR_POWER_STATUS, &pmcsr);
  84. /* Clear PME_Status by writing 1 to it and enable PME# */
  85. pmcsr |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
  86. if (!enable)
  87. {
  88. pmcsr &= ~PCIM_PSTAT_PMEENABLE;
  89. }
  90. rt_pci_write_config_u16(pdev, pdev->pme_cap + PCIR_POWER_STATUS, pmcsr);
  91. pdev->pm_enabled = enable;
  92. }
  93. void rt_pci_pme_active(struct rt_pci_device *pdev, rt_bool_t enable)
  94. {
  95. if (!pdev)
  96. {
  97. return;
  98. }
  99. pci_pme_active(pdev, enable);
  100. rt_dm_power_domain_attach(&pdev->parent, enable);
  101. }