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 <rtthread.h>
12 
13 #include <drivers/pm.h>
14 #include <drivers/pci.h>
15 
16 #ifdef RT_USING_PM
17 struct host_bridge_pm_status
18 {
19     rt_uint8_t mode;
20     rt_bool_t enable;
21 };
22 
23 static const enum rt_pci_power system_pci_pm_mode[] =
24 {
25     [PM_SLEEP_MODE_NONE]        = RT_PCI_D0,
26     [PM_SLEEP_MODE_IDLE]        = RT_PCI_D3HOT,
27     [PM_SLEEP_MODE_LIGHT]       = RT_PCI_D1,
28     [PM_SLEEP_MODE_DEEP]        = RT_PCI_D1,
29     [PM_SLEEP_MODE_STANDBY]     = RT_PCI_D2,
30     [PM_SLEEP_MODE_SHUTDOWN]    = RT_PCI_D3COLD,
31 };
32 
pci_device_pm_ops(struct rt_pci_device * pdev,void * data)33 static rt_bool_t pci_device_pm_ops(struct rt_pci_device *pdev, void *data)
34 {
35     struct host_bridge_pm_status *status = data;
36 
37     rt_pci_enable_wake(pdev, system_pci_pm_mode[status->mode], status->enable);
38 
39     /* To find all devices, always return false */
40     return RT_FALSE;
41 }
42 
host_bridge_pm_suspend(const struct rt_device * device,rt_uint8_t mode)43 static rt_err_t host_bridge_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
44 {
45     struct host_bridge_pm_status status;
46     struct rt_pci_device *pdev = rt_container_of(device, struct rt_pci_device, parent);
47 
48     status.mode = mode;
49     status.enable = RT_FALSE;
50     rt_pci_enum_device(pdev->bus, pci_device_pm_ops, &status);
51 
52     return RT_EOK;
53 }
54 
host_bridge_pm_resume(const struct rt_device * device,rt_uint8_t mode)55 static void host_bridge_pm_resume(const struct rt_device *device, rt_uint8_t mode)
56 {
57     struct host_bridge_pm_status status;
58     struct rt_pci_device *pdev = rt_container_of(device, struct rt_pci_device, parent);
59 
60     status.mode = mode;
61     status.enable = RT_TRUE;
62     rt_pci_enum_device(pdev->bus, pci_device_pm_ops, &status);
63 }
64 
65 static const struct rt_device_pm_ops host_bridge_pm_ops =
66 {
67     .suspend = host_bridge_pm_suspend,
68     .resume = host_bridge_pm_resume,
69 };
70 #endif /* RT_USING_PM */
71 
host_bridge_free(struct rt_pci_device * pdev)72 static void host_bridge_free(struct rt_pci_device *pdev)
73 {
74 #ifdef RT_USING_PM
75     rt_pm_device_unregister(&pdev->parent);
76 #endif
77 }
78 
host_bridge_probe(struct rt_pci_device * pdev)79 static rt_err_t host_bridge_probe(struct rt_pci_device *pdev)
80 {
81     rt_err_t err = RT_EOK;
82 
83     rt_pci_set_master(pdev);
84 
85 #ifdef RT_USING_PM
86     rt_pm_device_register(&pdev->parent, &host_bridge_pm_ops);
87 #endif
88 
89     return err;
90 }
91 
host_bridge_remove(struct rt_pci_device * pdev)92 static rt_err_t host_bridge_remove(struct rt_pci_device *pdev)
93 {
94     host_bridge_free(pdev);
95     rt_pci_clear_master(pdev);
96 
97     return RT_EOK;
98 }
99 
host_bridge_shutdown(struct rt_pci_device * pdev)100 static rt_err_t host_bridge_shutdown(struct rt_pci_device *pdev)
101 {
102     host_bridge_free(pdev);
103 
104     return RT_EOK;
105 }
106 
107 static const struct rt_pci_device_id host_bridge_pci_ids[] =
108 {
109     /* PCI host bridges */
110     { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0008) },
111     /* Any PCI-Express port */
112     { RT_PCI_DEVICE_CLASS(PCIS_BRIDGE_PCI_NORMAL, ~0) },
113     /* PCI-to-PCI bridge */
114     { RT_PCI_DEVICE_CLASS(PCIS_BRIDGE_PCI_SUBTRACTIVE, ~0) },
115     /* Any Root Complex Event Collector */
116     { RT_PCI_DEVICE_CLASS(((PCIS_SYSTEM_RCEC << 8) | 0x00), ~0) },
117     { /* sentinel */ }
118 };
119 
120 static struct rt_pci_driver host_bridge_driver =
121 {
122     .name = "host-bridge",
123 
124     .ids = host_bridge_pci_ids,
125     .probe = host_bridge_probe,
126     .remove = host_bridge_remove,
127     .shutdown = host_bridge_shutdown,
128 };
129 RT_PCI_DRIVER_EXPORT(host_bridge_driver);
130