mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-01-22 20:17:35 +08:00
2168ed8e7d
PCI/PCIe have better performance and more devices support, such as NVMe, GPU, Powerful NIC (Like RDMA). PCI/PCIe can access control by IOMMU that the virtualiztion and userspace driver will more safety. PCI/PCIe device could hot plugging, no design modifications SoC required, PCI/PCIe on Embedded SoC is popular now. We make a simple framework to support them. Feature Lists: 1.PCI INTx: the INT[A-D] pin IRQ for legacy PCI, work with platform PIC. 2.MSI/MSI-X: the message write IRQ for PCIe, work with platform's PIC. 3.PME: we only support the D0, D1, D2, D3HOT, D3COLD init by framework. 4.Endpoint: a simple EP framework for PCI FPGA or NTB function. 5.OFW: we only support work on OFW SoC, ACPI support in the future maybe. Host controller: 1. Common PCI host controller on ECAM. 2. Generic PCI host controller on ECAM. Signed-off-by: GuEe-GUI <2991707448@qq.com>
130 lines
3.1 KiB
C
130 lines
3.1 KiB
C
/*
|
|
* Copyright (c) 2006-2022, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2022-10-24 GuEe-GUI first version
|
|
*/
|
|
|
|
#include <rtthread.h>
|
|
|
|
#include <drivers/pm.h>
|
|
#include <drivers/pci.h>
|
|
|
|
#ifdef RT_USING_PM
|
|
struct host_bridge_pm_status
|
|
{
|
|
rt_uint8_t mode;
|
|
rt_bool_t enable;
|
|
};
|
|
|
|
static const enum rt_pci_power system_pci_pm_mode[] =
|
|
{
|
|
[PM_SLEEP_MODE_NONE] = RT_PCI_D0,
|
|
[PM_SLEEP_MODE_IDLE] = RT_PCI_D3HOT,
|
|
[PM_SLEEP_MODE_LIGHT] = RT_PCI_D1,
|
|
[PM_SLEEP_MODE_DEEP] = RT_PCI_D1,
|
|
[PM_SLEEP_MODE_STANDBY] = RT_PCI_D2,
|
|
[PM_SLEEP_MODE_SHUTDOWN] = RT_PCI_D3COLD,
|
|
};
|
|
|
|
static rt_bool_t pci_device_pm_ops(struct rt_pci_device *pdev, void *data)
|
|
{
|
|
struct host_bridge_pm_status *status = data;
|
|
|
|
rt_pci_enable_wake(pdev, system_pci_pm_mode[status->mode], status->enable);
|
|
|
|
/* To find all devices, always return false */
|
|
return RT_FALSE;
|
|
}
|
|
|
|
static rt_err_t host_bridge_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
|
|
{
|
|
struct host_bridge_pm_status status;
|
|
struct rt_pci_device *pdev = rt_container_of(device, struct rt_pci_device, parent);
|
|
|
|
status.mode = mode;
|
|
status.enable = RT_FALSE;
|
|
rt_pci_enum_device(pdev->bus, pci_device_pm_ops, &status);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static void host_bridge_pm_resume(const struct rt_device *device, rt_uint8_t mode)
|
|
{
|
|
struct host_bridge_pm_status status;
|
|
struct rt_pci_device *pdev = rt_container_of(device, struct rt_pci_device, parent);
|
|
|
|
status.mode = mode;
|
|
status.enable = RT_TRUE;
|
|
rt_pci_enum_device(pdev->bus, pci_device_pm_ops, &status);
|
|
}
|
|
|
|
static const struct rt_device_pm_ops host_bridge_pm_ops =
|
|
{
|
|
.suspend = host_bridge_pm_suspend,
|
|
.resume = host_bridge_pm_resume,
|
|
};
|
|
#endif /* RT_USING_PM */
|
|
|
|
static void host_bridge_free(struct rt_pci_device *pdev)
|
|
{
|
|
#ifdef RT_USING_PM
|
|
rt_pm_device_unregister(&pdev->parent);
|
|
#endif
|
|
}
|
|
|
|
static rt_err_t host_bridge_probe(struct rt_pci_device *pdev)
|
|
{
|
|
rt_err_t err = RT_EOK;
|
|
|
|
rt_pci_set_master(pdev);
|
|
|
|
#ifdef RT_USING_PM
|
|
rt_pm_device_register(&pdev->parent, &host_bridge_pm_ops);
|
|
#endif
|
|
|
|
return err;
|
|
}
|
|
|
|
static rt_err_t host_bridge_remove(struct rt_pci_device *pdev)
|
|
{
|
|
host_bridge_free(pdev);
|
|
rt_pci_clear_master(pdev);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t host_bridge_shutdown(struct rt_pci_device *pdev)
|
|
{
|
|
host_bridge_free(pdev);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static const struct rt_pci_device_id host_bridge_pci_ids[] =
|
|
{
|
|
/* PCI host bridges */
|
|
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0008) },
|
|
/* Any PCI-Express port */
|
|
{ RT_PCI_DEVICE_CLASS(PCIS_BRIDGE_PCI_NORMAL, ~0) },
|
|
/* PCI-to-PCI bridge */
|
|
{ RT_PCI_DEVICE_CLASS(PCIS_BRIDGE_PCI_SUBTRACTIVE, ~0) },
|
|
/* Any Root Complex Event Collector */
|
|
{ RT_PCI_DEVICE_CLASS(((PCIS_SYSTEM_RCEC << 8) | 0x00), ~0) },
|
|
{ /* sentinel */ }
|
|
};
|
|
|
|
static struct rt_pci_driver host_bridge_driver =
|
|
{
|
|
.name = "host-bridge",
|
|
|
|
.ids = host_bridge_pci_ids,
|
|
.probe = host_bridge_probe,
|
|
.remove = host_bridge_remove,
|
|
.shutdown = host_bridge_shutdown,
|
|
};
|
|
RT_PCI_DRIVER_EXPORT(host_bridge_driver);
|