[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>
This commit is contained in:
parent
8b4d1c0c5d
commit
c2545cdd7b
|
@ -21,6 +21,7 @@ rsource "touch/Kconfig"
|
||||||
rsource "graphic/Kconfig"
|
rsource "graphic/Kconfig"
|
||||||
rsource "hwcrypto/Kconfig"
|
rsource "hwcrypto/Kconfig"
|
||||||
rsource "wlan/Kconfig"
|
rsource "wlan/Kconfig"
|
||||||
|
rsource "phye/Kconfig"
|
||||||
rsource "block/Kconfig"
|
rsource "block/Kconfig"
|
||||||
rsource "nvme/Kconfig"
|
rsource "nvme/Kconfig"
|
||||||
rsource "scsi/Kconfig"
|
rsource "scsi/Kconfig"
|
||||||
|
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -67,6 +67,10 @@ extern "C" {
|
||||||
#include "drivers/ofw_raw.h"
|
#include "drivers/ofw_raw.h"
|
||||||
#endif /* RT_USING_OFW */
|
#endif /* RT_USING_OFW */
|
||||||
|
|
||||||
|
#ifdef RT_USING_PHYE
|
||||||
|
#include "drivers/phye.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef RT_USING_PIC
|
#ifdef RT_USING_PIC
|
||||||
#include "drivers/pic.h"
|
#include "drivers/pic.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
|
@ -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')
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue