Przeglądaj źródła

[DM/FEATURE] Support PHY (external) (#9597)

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>
GUI 5 miesięcy temu
rodzic
commit
c2545cdd7b

+ 1 - 0
components/drivers/Kconfig

@@ -21,6 +21,7 @@ rsource "touch/Kconfig"
 rsource "graphic/Kconfig"
 rsource "hwcrypto/Kconfig"
 rsource "wlan/Kconfig"
+rsource "phye/Kconfig"
 rsource "block/Kconfig"
 rsource "nvme/Kconfig"
 rsource "scsi/Kconfig"

+ 91 - 0
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 <rtthread.h>
+#include <drivers/ofw.h>
+
+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__ */

+ 24 - 0
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__ */

+ 4 - 0
components/drivers/include/rtdevice.h

@@ -67,6 +67,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

+ 11 - 0
components/drivers/phye/Kconfig

@@ -0,0 +1,11 @@
+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
+    osource "$(SOC_DM_PHYE_DIR)/Kconfig"
+endif

+ 15 - 0
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')

+ 320 - 0
components/drivers/phye/phye.c

@@ -0,0 +1,320 @@
+/*
+ * 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 <rtdbg.h>
+
+#include <rtdevice.h>
+#include <rtthread.h>
+
+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)
+    {
+        return RT_EOK;
+    }
+
+    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);
+
+    return err;
+}
+
+rt_err_t rt_phye_exit(struct rt_phye *phye)
+{
+    rt_err_t err;
+
+    if (!phye)
+    {
+        return RT_EOK;
+    }
+
+    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;
+        }
+    }
+    if (phye->init_count)
+    {
+        --phye->init_count;
+    }
+
+_out_lock:
+    rt_spin_unlock(&phye->lock);
+
+    return err;
+}
+
+rt_err_t rt_phye_reset(struct rt_phye *phye)
+{
+    rt_err_t err;
+
+    if (!phye)
+    {
+        return RT_EOK;
+    }
+
+    err = RT_EOK;
+
+    rt_spin_lock(&phye->lock);
+
+    if (phye->ops->reset)
+    {
+        err = phye->ops->reset(phye);
+    }
+
+    rt_spin_unlock(&phye->lock);
+
+    return err;
+}
+
+rt_err_t rt_phye_power_on(struct rt_phye *phye)
+{
+    rt_err_t err;
+
+    if (!phye)
+    {
+        return RT_EOK;
+    }
+
+    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);
+
+    return err;
+}
+
+rt_err_t rt_phye_power_off(struct rt_phye *phye)
+{
+    rt_err_t err;
+
+    if (!phye)
+    {
+        return RT_EOK;
+    }
+
+    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;
+        }
+    }
+    if (phye->power_count)
+    {
+        --phye->power_count;
+    }
+
+_out_lock:
+    rt_spin_unlock(&phye->lock);
+
+    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)
+    {
+        return RT_EOK;
+    }
+
+    if (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);
+    }
+}