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
11 #include <drivers/pci.h>
12 #include <drivers/core/power_domain.h>
13
14 #define DBG_TAG "pci.pme"
15 #define DBG_LVL DBG_INFO
16 #include <rtdbg.h>
17
18 /*
19 * Power Management Capability Register:
20 *
21 * 31 27 26 25 24 22 21 20 19 18 16 15 8 7 0
22 * +---------+---+---+--------+---+---+---+------+-----------+----------------+
23 * | | | | | | | | | | Capabilitiy ID |
24 * +---------+---+---+--------+---+---+---+------+-----------+----------------+
25 * ^ ^ ^ ^ ^ ^ ^ ^ ^
26 * | | | | | | | | |
27 * | | | | | | | | +---- Next Capabilitiy Pointer
28 * | | | | | | | +------------- Version
29 * | | | | | | +------------------- PME Clock
30 * | | | | | +----------------------- Immediate Readiness on Return to D0
31 * | | | | +--------------------------- Device Specifiic Initializtion
32 * | | | +--------------------------------- Aux Current
33 * | | +---------------------------------------- D1 Support
34 * | +-------------------------------------------- D2 Support
35 * +--------------------------------------------------- PME Support
36 */
37
rt_pci_pme_init(struct rt_pci_device * pdev)38 void rt_pci_pme_init(struct rt_pci_device *pdev)
39 {
40 rt_uint16_t pmc;
41
42 if (!pdev || !(pdev->pme_cap = rt_pci_find_capability(pdev, PCIY_PMG)))
43 {
44 return;
45 }
46
47 rt_pci_read_config_u16(pdev, pdev->pme_cap + PCIR_POWER_CAP, &pmc);
48
49 if ((pmc & PCIM_PCAP_SPEC) > 3)
50 {
51 LOG_E("%s: Unsupported PME CAP regs spec %u",
52 rt_dm_dev_get_name(&pdev->parent), pmc & PCIM_PCAP_SPEC);
53
54 return;
55 }
56
57 pmc &= PCIM_PCAP_PMEMASK;
58
59 if (pmc)
60 {
61 pdev->pme_support = RT_FIELD_GET(PCIM_PCAP_PMEMASK, pmc);
62
63 rt_pci_pme_active(pdev, RT_FALSE);
64 }
65 }
66
rt_pci_enable_wake(struct rt_pci_device * pdev,enum rt_pci_power state,rt_bool_t enable)67 rt_err_t rt_pci_enable_wake(struct rt_pci_device *pdev,
68 enum rt_pci_power state, rt_bool_t enable)
69 {
70 if (!pdev || state >= RT_PCI_PME_MAX)
71 {
72 return -RT_EINVAL;
73 }
74
75 if (enable)
76 {
77 if (rt_pci_pme_capable(pdev, state) ||
78 rt_pci_pme_capable(pdev, RT_PCI_D3COLD))
79 {
80 rt_pci_pme_active(pdev, RT_EOK);
81 }
82 }
83 else
84 {
85 rt_pci_pme_active(pdev, RT_FALSE);
86 }
87
88 return RT_EOK;
89 }
90
pci_pme_active(struct rt_pci_device * pdev,rt_bool_t enable)91 static void pci_pme_active(struct rt_pci_device *pdev, rt_bool_t enable)
92 {
93 rt_uint16_t pmcsr;
94
95 if (!pdev->pme_support)
96 {
97 return;
98 }
99
100 rt_pci_read_config_u16(pdev, pdev->pme_cap + PCIR_POWER_STATUS, &pmcsr);
101 /* Clear PME_Status by writing 1 to it and enable PME# */
102 pmcsr |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
103
104 if (!enable)
105 {
106 pmcsr &= ~PCIM_PSTAT_PMEENABLE;
107 }
108
109 rt_pci_write_config_u16(pdev, pdev->pme_cap + PCIR_POWER_STATUS, pmcsr);
110 pdev->pm_enabled = enable;
111 }
112
rt_pci_pme_active(struct rt_pci_device * pdev,rt_bool_t enable)113 void rt_pci_pme_active(struct rt_pci_device *pdev, rt_bool_t enable)
114 {
115 if (!pdev)
116 {
117 return;
118 }
119
120 pci_pme_active(pdev, enable);
121 rt_dm_power_domain_attach(&pdev->parent, enable);
122 }
123