From 762b3c8726c7e46b5723fc0877e0473c3cef8d27 Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Thu, 31 Oct 2024 16:18:58 +0800 Subject: [PATCH] [DM/FEATURE] Support PHY (external) This framework will be of use only to devices that use external PHY (PHY functionality is not embedded within the controller). Use in PCIE, USB, HDMI, DP... Signed-off-by: GuEe-GUI <2991707448@qq.com> --- components/drivers/Kconfig | 1 + components/drivers/include/drivers/phye.h | 91 +++++ .../drivers/include/dt-bindings/phye/phye.h | 24 ++ components/drivers/include/rtdevice.h | 4 + components/drivers/phye/Kconfig | 12 + components/drivers/phye/SConscript | 15 + components/drivers/phye/phye.c | 319 ++++++++++++++++++ 7 files changed, 466 insertions(+) create mode 100644 components/drivers/include/drivers/phye.h create mode 100644 components/drivers/include/dt-bindings/phye/phye.h create mode 100644 components/drivers/phye/Kconfig create mode 100644 components/drivers/phye/SConscript create mode 100644 components/drivers/phye/phye.c diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 8b69868205f..3cb56ee43aa 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -21,6 +21,7 @@ rsource "touch/Kconfig" rsource "graphic/Kconfig" rsource "hwcrypto/Kconfig" rsource "wlan/Kconfig" +rsource "phye/Kconfig" rsource "virtio/Kconfig" rsource "ofw/Kconfig" rsource "pci/Kconfig" diff --git a/components/drivers/include/drivers/phye.h b/components/drivers/include/drivers/phye.h new file mode 100644 index 00000000000..3776cdeac92 --- /dev/null +++ b/components/drivers/include/drivers/phye.h @@ -0,0 +1,91 @@ +/* + * 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 + */ + +#ifndef __PHYE_H__ +#define __PHYE_H__ + +#include +#include + +enum rt_phye_mode +{ + RT_PHYE_MODE_INVALID, + RT_PHYE_MODE_USB_HOST, + RT_PHYE_MODE_USB_HOST_LS, + RT_PHYE_MODE_USB_HOST_FS, + RT_PHYE_MODE_USB_HOST_HS, + RT_PHYE_MODE_USB_HOST_SS, + RT_PHYE_MODE_USB_DEVICE, + RT_PHYE_MODE_USB_DEVICE_LS, + RT_PHYE_MODE_USB_DEVICE_FS, + RT_PHYE_MODE_USB_DEVICE_HS, + RT_PHYE_MODE_USB_DEVICE_SS, + RT_PHYE_MODE_USB_OTG, + RT_PHYE_MODE_UFS_HS_A, + RT_PHYE_MODE_UFS_HS_B, + RT_PHYE_MODE_PCIE, + RT_PHYE_MODE_ETHERNET, + RT_PHYE_MODE_MIPI_DPHY, + RT_PHYE_MODE_SATA, + RT_PHYE_MODE_LVDS, + RT_PHYE_MODE_DP, + + RT_PHYE_MODE_MAX, + + /* PCIe */ + RT_PHYE_MODE_PCIE_RC = RT_PHYE_MODE_MAX, + RT_PHYE_MODE_PCIE_EP, + RT_PHYE_MODE_PCIE_BIFURCATION, +}; + +struct rt_phye_ops; + +struct rt_phye +{ + struct rt_device *dev; + + const struct rt_phye_ops *ops; + + int init_count; + int power_count; + struct rt_spinlock lock; +}; + +struct rt_phye_ops +{ + rt_err_t (*init)(struct rt_phye *phye); + rt_err_t (*exit)(struct rt_phye *phye); + rt_err_t (*reset)(struct rt_phye *phye); + rt_err_t (*power_on)(struct rt_phye *phye); + rt_err_t (*power_off)(struct rt_phye *phye); + rt_err_t (*set_mode)(struct rt_phye *phye, enum rt_phye_mode mode, int submode); + rt_err_t (*ofw_parse)(struct rt_phye *phye, struct rt_ofw_cell_args *phye_args); +}; + +rt_err_t rt_phye_register(struct rt_phye *phye); +rt_err_t rt_phye_unregister(struct rt_phye *phye); + +rt_err_t rt_phye_init(struct rt_phye *phye); +rt_err_t rt_phye_exit(struct rt_phye *phye); +rt_err_t rt_phye_reset(struct rt_phye *phye); +rt_err_t rt_phye_power_on(struct rt_phye *phye); +rt_err_t rt_phye_power_off(struct rt_phye *phye); +rt_err_t rt_phye_set_mode(struct rt_phye *phye, enum rt_phye_mode mode, int submode); + +rt_inline rt_err_t rt_phye_set_mode_simple(struct rt_phye *phye, enum rt_phye_mode mode) +{ + return rt_phye_set_mode(phye, mode, RT_PHYE_MODE_INVALID); +} + +struct rt_phye *rt_phye_get_by_index(struct rt_device *dev, int index); +struct rt_phye *rt_phye_get_by_name(struct rt_device *dev, const char *id); +void rt_phye_put(struct rt_phye *phye); + +#endif /* __PHYE_H__ */ diff --git a/components/drivers/include/dt-bindings/phye/phye.h b/components/drivers/include/dt-bindings/phye/phye.h new file mode 100644 index 00000000000..54a9cce958d --- /dev/null +++ b/components/drivers/include/dt-bindings/phye/phye.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PHYE_H__ +#define __DT_BINDINGS_PHYE_H__ + +#define PHY_NONE 0 +#define PHY_TYPE_SATA 1 +#define PHY_TYPE_PCIE 2 +#define PHY_TYPE_USB2 3 +#define PHY_TYPE_USB3 4 +#define PHY_TYPE_UFS 5 +#define PHY_TYPE_DP 6 +#define PHY_TYPE_XPCS 7 +#define PHY_TYPE_SGMII 8 +#define PHY_TYPE_QSGMII 9 +#define PHY_TYPE_DPHY 10 +#define PHY_TYPE_CPHY 11 +#define PHY_TYPE_USXGMII 12 + +#endif /* __DT_BINDINGS_PHYE_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index c8ed3c04899..4b6d246aad0 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -53,6 +53,10 @@ extern "C" { #include "drivers/ofw_raw.h" #endif /* RT_USING_OFW */ +#ifdef RT_USING_PHYE +#include "drivers/phye.h" +#endif + #ifdef RT_USING_PIC #include "drivers/pic.h" #endif diff --git a/components/drivers/phye/Kconfig b/components/drivers/phye/Kconfig new file mode 100644 index 00000000000..062835d05f4 --- /dev/null +++ b/components/drivers/phye/Kconfig @@ -0,0 +1,12 @@ +menuconfig RT_USING_PHYE + bool "Using External Port Physical Layer (PHY) device drivers" + depends on RT_USING_DM + default n + help + This framework will be of use only to devices that use + external PHY (PHY functionality is not embedded within the controller). + +if RT_USING_PHYE && SOC_DM_PHYE +comment "SoC Device Drivers" +source "$(SOC_DM_DIR)/phye/Kconfig" +endif diff --git a/components/drivers/phye/SConscript b/components/drivers/phye/SConscript new file mode 100644 index 00000000000..23deafed7cd --- /dev/null +++ b/components/drivers/phye/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_PHYE']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['phye.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/phye/phye.c b/components/drivers/phye/phye.c new file mode 100644 index 00000000000..48cd6f242cd --- /dev/null +++ b/components/drivers/phye/phye.c @@ -0,0 +1,319 @@ +/* + * 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 + */ + +#define DBG_TAG "rtdm.phye" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +rt_err_t rt_phye_register(struct rt_phye *phye) +{ + rt_err_t err; + + if (phye && phye->dev && phye->ops) + { + err = RT_EOK; + + rt_spin_lock_init(&phye->lock); + rt_dm_dev_bind_fwdata(phye->dev, RT_NULL, phye); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_phye_unregister(struct rt_phye *phye) +{ + rt_err_t err; + + if (phye) + { + err = RT_EOK; + + rt_spin_lock(&phye->lock); + + if (phye->dev->ref_count) + { + err = -RT_EBUSY; + LOG_E("%s is busy in unregister", rt_dm_dev_get_name(phye->dev)); + } + + rt_dm_dev_unbind_fwdata(phye->dev, RT_NULL); + + rt_spin_unlock(&phye->lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_phye_init(struct rt_phye *phye) +{ + rt_err_t err; + + if (phye) + { + err = RT_EOK; + + rt_spin_lock(&phye->lock); + + if (phye->init_count == 0 && phye->ops->init) + { + if ((err = phye->ops->init(phye))) + { + goto _out_lock; + } + } + ++phye->init_count; + + _out_lock: + rt_spin_unlock(&phye->lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_phye_exit(struct rt_phye *phye) +{ + rt_err_t err; + + if (phye) + { + err = RT_EOK; + + rt_spin_lock(&phye->lock); + + if (phye->init_count == 1 && phye->ops->exit) + { + if ((err = phye->ops->exit(phye))) + { + goto _out_lock; + } + } + --phye->init_count; + + _out_lock: + rt_spin_unlock(&phye->lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_phye_reset(struct rt_phye *phye) +{ + rt_err_t err; + + if (phye) + { + err = RT_EOK; + + rt_spin_lock(&phye->lock); + + if (phye->ops->reset) + { + err = phye->ops->reset(phye); + } + + rt_spin_unlock(&phye->lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_phye_power_on(struct rt_phye *phye) +{ + rt_err_t err; + + if (phye) + { + err = RT_EOK; + + rt_spin_lock(&phye->lock); + + if (phye->power_count == 0 && phye->ops->power_on) + { + if ((err = phye->ops->power_on(phye))) + { + goto _out_lock; + } + } + ++phye->power_count; + + _out_lock: + rt_spin_unlock(&phye->lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_phye_power_off(struct rt_phye *phye) +{ + rt_err_t err; + + if (phye) + { + err = RT_EOK; + + rt_spin_lock(&phye->lock); + + if (phye->power_count == 1 && phye->ops->power_off) + { + if ((err = phye->ops->power_off(phye))) + { + goto _out_lock; + } + } + --phye->power_count; + + _out_lock: + rt_spin_unlock(&phye->lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_phye_set_mode(struct rt_phye *phye, enum rt_phye_mode mode, int submode) +{ + rt_err_t err; + + if (phye && mode < RT_PHYE_MODE_MAX && + (submode == RT_PHYE_MODE_INVALID || submode >= RT_PHYE_MODE_MAX)) + { + err = RT_EOK; + + rt_spin_lock(&phye->lock); + + if (phye->ops->set_mode) + { + err = phye->ops->set_mode(phye, mode, submode); + } + + rt_spin_unlock(&phye->lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static struct rt_phye *ofw_phye_get_by_index(struct rt_ofw_node *np, int index) +{ + struct rt_phye *phye = RT_NULL; +#ifdef RT_USING_OFW + rt_err_t err; + struct rt_ofw_node *phye_np; + struct rt_ofw_cell_args phye_args; + + if (!rt_ofw_parse_phandle_cells(np, "phys", "#phy-cells", index, &phye_args)) + { + phye_np = phye_args.data; + + if (!rt_ofw_data(phye_np)) + { + rt_platform_ofw_request(phye_np); + } + + phye = rt_ofw_data(phye_np); + rt_ofw_node_put(phye_np); + + if (phye && phye->ops->ofw_parse) + { + if ((err = phye->ops->ofw_parse(phye, &phye_args))) + { + phye = rt_err_ptr(err); + } + } + } +#endif /* RT_USING_OFW */ + return phye; +} + +struct rt_phye *rt_phye_get_by_index(struct rt_device *dev, int index) +{ + struct rt_phye *phye = RT_NULL; + + if (!dev || index < 0) + { + return rt_err_ptr(-RT_EINVAL); + } + + if (dev->ofw_node) + { + phye = ofw_phye_get_by_index(dev->ofw_node, index); + } + + if (!rt_is_err_or_null(phye)) + { + rt_spin_lock(&phye->lock); + ++phye->dev->ref_count; + rt_spin_unlock(&phye->lock); + } + + return phye; +} + +struct rt_phye *rt_phye_get_by_name(struct rt_device *dev, const char *id) +{ + int index; + + if (!dev || !id) + { + return rt_err_ptr(-RT_EINVAL); + } + + index = rt_dm_dev_prop_index_of_string(dev, "phy-names", id); + + if (index >= 0) + { + return rt_phye_get_by_index(dev, index); + } + + return RT_NULL; +} + +void rt_phye_put(struct rt_phye *phye) +{ + if (phye) + { + rt_spin_lock(&phye->lock); + --phye->dev->ref_count; + rt_spin_unlock(&phye->lock); + } +}