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