rtt更新
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
config RT_USING_PHY
|
||||
bool "Using ethernet phy device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_PHY_V2
|
||||
bool "Using phy device and mii bus v2"
|
||||
depends on !RT_USING_PHY
|
||||
default n
|
||||
|
@@ -1,8 +1,18 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd, cwd + '/../include']
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd + '/../include']
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_PHY'], CPPPATH = CPPPATH)
|
||||
if GetDepend('RT_USING_OFW') == False:
|
||||
SrcRemove(src, ['ofw.c'])
|
||||
|
||||
if GetDepend('RT_USING_PHY_V2') == False:
|
||||
SrcRemove(src, ['general.c','mdio.c','ofw.c'])
|
||||
|
||||
if GetDepend('RT_USING_PHY_V2') == False:
|
||||
if GetDepend('RT_USING_PHY') == False:
|
||||
SrcRemove(src, ['phy.c'])
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
349
rt-thread/components/drivers/phy/general.c
Normal file
349
rt-thread/components/drivers/phy/general.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-10-08 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <drivers/phy.h>
|
||||
#include "general_phy.h"
|
||||
#define DBG_TAG "rtdm.phy"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static int __genphy_set_adv(int adv,int advertise)
|
||||
{
|
||||
adv &= ~(RT_ADVERTISE_ALL | RT_ADVERTISE_100BASE4 | RT_ADVERTISE_PAUSE_CAP |
|
||||
RT_ADVERTISE_PAUSE_ASYM);
|
||||
if (advertise & RT_ADVERTISED__10baseT_Half)
|
||||
adv |= RT_ADVERTISE_10HALF;
|
||||
if (advertise & RT_ADVERTISED__10baseT_Full)
|
||||
adv |= RT_ADVERTISE_10FULL;
|
||||
if (advertise & RT_ADVERTISED__100baseT_Half)
|
||||
adv |= RT_ADVERTISE_100HALF;
|
||||
if (advertise & RT_ADVERTISED__100baseT_Full)
|
||||
adv |= RT_ADVERTISE_100FULL;
|
||||
if (advertise & RT_ADVERTISED__Pause)
|
||||
adv |= RT_ADVERTISE_PAUSE_CAP;
|
||||
if (advertise & RT_ADVERTISED__Asym_Pause)
|
||||
adv |= RT_ADVERTISE_PAUSE_ASYM;
|
||||
if (advertise & RT_ADVERTISED__1000baseX_Half)
|
||||
adv |= RT_ADVERTISE_1000XHALF;
|
||||
if (advertise & RT_ADVERTISED__1000baseX_Full)
|
||||
adv |= RT_ADVERTISE_1000XFULL;
|
||||
|
||||
return adv;
|
||||
}
|
||||
static int __genphy_config_advert(struct rt_phy_device *phydev)
|
||||
{
|
||||
rt_uint32_t advertise;
|
||||
int oldadv, adv, bmsr;
|
||||
int err, changed = 0;
|
||||
|
||||
phydev->advertising &= phydev->supported;
|
||||
advertise = phydev->advertising;
|
||||
|
||||
adv = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_ADVERTISE);
|
||||
oldadv = adv;
|
||||
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
|
||||
adv = __genphy_set_adv(adv, advertise);
|
||||
|
||||
if (adv != oldadv)
|
||||
{
|
||||
err = rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_ADVERTISE, adv);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
bmsr = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
|
||||
if (bmsr < 0)
|
||||
return bmsr;
|
||||
|
||||
if (!(bmsr & RT_BMSR_ESTATEN))
|
||||
return changed;
|
||||
|
||||
adv = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_CTRL1000);
|
||||
oldadv = adv;
|
||||
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
|
||||
adv &= ~(RT_ADVERTISE_1000FULL | RT_ADVERTISE_1000HALF);
|
||||
|
||||
if (phydev->supported & (RT_SUPPORTED_1000baseT_Half |
|
||||
RT_SUPPORTED_1000baseT_Full))
|
||||
{
|
||||
if (advertise & RT_SUPPORTED_1000baseT_Half)
|
||||
adv |= RT_ADVERTISE_1000HALF;
|
||||
if (advertise & RT_SUPPORTED_1000baseT_Full)
|
||||
adv |= RT_ADVERTISE_1000FULL;
|
||||
}
|
||||
|
||||
if (adv != oldadv)
|
||||
changed = 1;
|
||||
|
||||
err = rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_CTRL1000, adv);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
int __genphy_restart_aneg(struct rt_phy_device *phydev)
|
||||
{
|
||||
int ctl;
|
||||
|
||||
ctl = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR);
|
||||
|
||||
if (ctl < 0)
|
||||
return ctl;
|
||||
|
||||
ctl |= (RT_BMCR_ANENABLE | RT_BMCR_ANRESTART);
|
||||
|
||||
ctl &= ~(RT_BMCR_ISOLATE);
|
||||
|
||||
ctl = rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR, ctl);
|
||||
|
||||
return ctl;
|
||||
}
|
||||
|
||||
int rt_genphy_config_aneg(struct rt_phy_device *phydev)
|
||||
{
|
||||
int result;
|
||||
int err;
|
||||
int ctl = RT_BMCR_ANRESTART;
|
||||
if (phydev->autoneg != AUTONEG_ENABLE)
|
||||
{
|
||||
phydev->pause = 0;
|
||||
|
||||
if (phydev->speed == SPEED_1000)
|
||||
ctl |= RT_BMCR_SPEED1000;
|
||||
else if (phydev->speed == SPEED_100)
|
||||
ctl |= RT_BMCR_SPEED100;
|
||||
|
||||
if (phydev->duplex == DUPLEX_FULL)
|
||||
ctl |= RT_BMCR_FULLDPLX;
|
||||
|
||||
err = rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR, ctl);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
result = __genphy_config_advert(phydev);
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
int ctl = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR);
|
||||
|
||||
if (ctl < 0)
|
||||
return ctl;
|
||||
|
||||
if (!(ctl & RT_BMCR_ANENABLE) || (ctl & RT_BMCR_ISOLATE))
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (result > 0)
|
||||
result = __genphy_restart_aneg(phydev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int rt_genphy_update_link(struct rt_phy_device *phydev)
|
||||
{
|
||||
unsigned int mii_reg;
|
||||
|
||||
mii_reg = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
|
||||
|
||||
if (phydev->link && mii_reg & RT_BMSR_LSTATUS)
|
||||
return 0;
|
||||
|
||||
if ((phydev->autoneg == AUTONEG_ENABLE) &&
|
||||
!(mii_reg & RT_BMSR_ANEGCOMPLETE))
|
||||
{
|
||||
int i = 0;
|
||||
rt_kprintf("Waiting for PHY auto negotiation to complete");
|
||||
while (!(mii_reg & RT_BMSR_ANEGCOMPLETE))
|
||||
{
|
||||
|
||||
if (i > (RT_PHY_ANEG_TIMEOUT))
|
||||
{
|
||||
LOG_E(" TIMEOUT !\n");
|
||||
phydev->link = 0;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
mii_reg = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
|
||||
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
LOG_D(" done\n");
|
||||
phydev->link = 1;
|
||||
} else {
|
||||
mii_reg = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
|
||||
|
||||
if (mii_reg & RT_BMSR_LSTATUS)
|
||||
phydev->link = 1;
|
||||
else
|
||||
phydev->link = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __genphy_auto_neg(struct rt_phy_device *phydev,int mii_reg)
|
||||
{
|
||||
rt_uint32_t lpa = 0;
|
||||
int gblpa = 0;
|
||||
rt_uint32_t estatus = 0;
|
||||
|
||||
if (phydev->supported & (RT_SUPPORTED_1000baseT_Full |
|
||||
RT_SUPPORTED_1000baseT_Half))
|
||||
{
|
||||
|
||||
gblpa = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_STAT1000);
|
||||
if (gblpa < 0)
|
||||
{
|
||||
LOG_D("Could not read RT_MII_STAT1000. Ignoring gigabit capability\n");
|
||||
gblpa = 0;
|
||||
}
|
||||
gblpa &= rt_phy_read(phydev,
|
||||
RT_MDIO_DEVAD_NONE, RT_MII_CTRL1000) << 2;
|
||||
}
|
||||
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
if (gblpa & (RT_PHY_1000BTSR_1000FD | RT_PHY_1000BTSR_1000HD))
|
||||
{
|
||||
phydev->speed = SPEED_1000;
|
||||
|
||||
if (gblpa & RT_PHY_1000BTSR_1000FD)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
lpa = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_ADVERTISE);
|
||||
lpa &= rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_LPA);
|
||||
|
||||
if (lpa & (RT_LINK_PARTNER__100FULL | RT_LINK_PARTNER__100HALF))
|
||||
{
|
||||
phydev->speed = SPEED_100;
|
||||
|
||||
if (lpa & RT_LINK_PARTNER__100FULL)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
} else if (lpa & RT_LINK_PARTNER__10FULL)
|
||||
{
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
}
|
||||
|
||||
if ((mii_reg & RT_BMSR_ESTATEN) && !(mii_reg & RT_BMSR_ERCAP))
|
||||
estatus = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE,
|
||||
RT_MII_ESTATUS);
|
||||
|
||||
if (estatus & (RT_SUPORT_1000B_XFULL | RT_SUPORT_1000B_XHALF |
|
||||
RT_SUPORT_1000B_TFULL | RT_SUPORT_1000B_THALF))
|
||||
{
|
||||
phydev->speed = SPEED_1000;
|
||||
if (estatus & (RT_SUPORT_1000B_XFULL | RT_SUPORT_1000B_TFULL))
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
}
|
||||
}
|
||||
int rt_genphy_parse_link(struct rt_phy_device *phydev)
|
||||
{
|
||||
int mii_reg = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE)
|
||||
{
|
||||
__genphy_auto_neg(phydev, mii_reg);
|
||||
} else {
|
||||
rt_uint32_t bmcr = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR);
|
||||
|
||||
phydev->speed = SPEED_10;
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
if (bmcr & RT_BMCR_FULLDPLX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
if (bmcr & RT_BMCR_SPEED1000)
|
||||
phydev->speed = SPEED_1000;
|
||||
else if (bmcr & RT_BMCR_SPEED100)
|
||||
phydev->speed = SPEED_100;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt_genphy_config(struct rt_phy_device *phydev)
|
||||
{
|
||||
int val;
|
||||
rt_uint32_t features;
|
||||
|
||||
features = (RT_SUPPORTED_TP | RT_SUPPORTED_MII
|
||||
| RT_SUPPORTED_AUI | RT_SUPPORTED_FIBRE |
|
||||
RT_SUPPORTED_BNC);
|
||||
|
||||
val = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val & RT_BMSR_ANEGCAPABLE)
|
||||
features |= RT_SUPPORTED_Autoneg;
|
||||
|
||||
if (val & RT_BMSR_100FULL)
|
||||
features |= RT_SUPPORTED_100baseT_Full;
|
||||
if (val & RT_BMSR_100HALF)
|
||||
features |= RT_SUPPORTED_100baseT_Half;
|
||||
if (val & RT_BMSR_10FULL)
|
||||
features |= RT_SUPPORTED_10baseT_Full;
|
||||
if (val & RT_BMSR_10HALF)
|
||||
features |= RT_SUPPORTED_10baseT_Half;
|
||||
|
||||
if (val & RT_BMSR_ESTATEN)
|
||||
{
|
||||
val = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_ESTATUS);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val & RT_SUPORT_1000B_TFULL)
|
||||
features |= RT_SUPPORTED_1000baseT_Full;
|
||||
if (val & RT_SUPORT_1000B_THALF)
|
||||
features |= RT_SUPPORTED_1000baseT_Half;
|
||||
if (val & RT_SUPORT_1000B_XFULL)
|
||||
features |= RT_SUPPORTED_1000baseX_Full;
|
||||
if (val & RT_SUPORT_1000B_XHALF)
|
||||
features |= RT_SUPPORTED_1000baseX_Half;
|
||||
}
|
||||
|
||||
phydev->supported &= features;
|
||||
phydev->advertising &= features;
|
||||
|
||||
rt_genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt_genphy_startup(struct rt_phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rt_genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return rt_genphy_parse_link(phydev);
|
||||
}
|
143
rt-thread/components/drivers/phy/general_phy.h
Normal file
143
rt-thread/components/drivers/phy/general_phy.h
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-10-08 zhujiale the first version
|
||||
*/
|
||||
#ifndef __PHY_GENERAL_H__
|
||||
#define __PHY_GENERAL_H__
|
||||
/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
|
||||
#define SPEED_10 10
|
||||
#define SPEED_100 100
|
||||
#define SPEED_1000 1000
|
||||
#define SPEED_2500 2500
|
||||
#define SPEED_10000 10000
|
||||
/* Advertisement control register. */
|
||||
#define RT_ADVERTISE_SLCT 0x001f /* Selector bits */
|
||||
#define RT_ADVERTISE_CSMA 0x0001 /* Only selector supported */
|
||||
#define RT_ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
|
||||
#define RT_ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
|
||||
#define RT_ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
|
||||
#define RT_ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
|
||||
#define RT_ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
|
||||
#define RT_ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
|
||||
#define RT_ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
|
||||
#define RT_ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
|
||||
#define RT_ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
|
||||
#define RT_ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
|
||||
#define RT_ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
|
||||
#define RT_ADVERTISE_RESV 0x1000 /* Unused... */
|
||||
#define RT_ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
|
||||
#define RT_ADVERTISE_LPACK 0x4000 /* Ack link partners response */
|
||||
#define RT_ADVERTISE_NPAGE 0x8000 /* Next page bit */
|
||||
|
||||
#define RT_ADVERTISE_FULL (RT_ADVERTISE_100FULL | RT_ADVERTISE_10FULL | \
|
||||
RT_ADVERTISE_CSMA)
|
||||
#define RT_ADVERTISE_ALL (RT_ADVERTISE_10HALF | RT_ADVERTISE_10FULL | \
|
||||
RT_ADVERTISE_100HALF | RT_ADVERTISE_100FULL)
|
||||
|
||||
/* Indicates what features are advertised by the interface. */
|
||||
#define RT_ADVERTISED__10baseT_Half (1 << 0)
|
||||
#define RT_ADVERTISED__10baseT_Full (1 << 1)
|
||||
#define RT_ADVERTISED__100baseT_Half (1 << 2)
|
||||
#define RT_ADVERTISED__100baseT_Full (1 << 3)
|
||||
#define RT_ADVERTISED__1000baseT_Half (1 << 4)
|
||||
#define RT_ADVERTISED__1000baseT_Full (1 << 5)
|
||||
#define RT_ADVERTISED__Autoneg (1 << 6)
|
||||
#define RT_ADVERTISED__TP (1 << 7)
|
||||
#define RT_ADVERTISED__AUI (1 << 8)
|
||||
#define RT_ADVERTISED__MII (1 << 9)
|
||||
#define RT_ADVERTISED__FIBRE (1 << 10)
|
||||
#define RT_ADVERTISED__BNC (1 << 11)
|
||||
#define RT_ADVERTISED__10000baseT_Full (1 << 12)
|
||||
#define RT_ADVERTISED__Pause (1 << 13)
|
||||
#define RT_ADVERTISED__Asym_Pause (1 << 14)
|
||||
#define RT_ADVERTISED__2500baseX_Full (1 << 15)
|
||||
#define RT_ADVERTISED__Backplane (1 << 16)
|
||||
#define RT_ADVERTISED__1000baseKX_Full (1 << 17)
|
||||
#define RT_ADVERTISED__10000baseKX4_Full (1 << 18)
|
||||
#define RT_ADVERTISED__10000baseKR_Full (1 << 19)
|
||||
#define RT_ADVERTISED__10000baseR_FEC (1 << 20)
|
||||
#define RT_ADVERTISED__1000baseX_Half (1 << 21)
|
||||
#define RT_ADVERTISED__1000baseX_Full (1 << 22)
|
||||
|
||||
/* Basic mode status register. */
|
||||
#define RT_BMSR_ERCAP 0x0001 /* Ext-reg capability */
|
||||
#define RT_BMSR_JCD 0x0002 /* Jabber detected */
|
||||
#define RT_BMSR_LSTATUS 0x0004 /* Link status */
|
||||
#define RT_BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
|
||||
#define RT_BMSR_RFAULT 0x0010 /* Remote fault detected */
|
||||
#define RT_BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
|
||||
#define RT_BMSR_RESV 0x00c0 /* Unused... */
|
||||
#define RT_BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
|
||||
#define RT_BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
|
||||
#define RT_BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
|
||||
#define RT_BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
|
||||
#define RT_BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
|
||||
#define RT_BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
|
||||
#define RT_BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
|
||||
#define RT_BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
|
||||
/* 1000BASE-T Control register */
|
||||
#define RT_ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
|
||||
#define RT_ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
|
||||
#define CTL1000_AS_MASTER 0x0800
|
||||
#define CTL1000_ENABLE_MASTER 0x1000
|
||||
|
||||
/* Duplex, half or full. */
|
||||
#define DUPLEX_HALF 0x00
|
||||
#define DUPLEX_FULL 0x01
|
||||
|
||||
#define AUTONEG_DISABLE 0x00
|
||||
#define AUTONEG_ENABLE 0x01
|
||||
#define RT_PHY_1000BTSR_MSCF 0x8000
|
||||
#define RT_PHY_1000BTSR_MSCR 0x4000
|
||||
#define RT_PHY_1000BTSR_LRS 0x2000
|
||||
#define RT_PHY_1000BTSR_RRS 0x1000
|
||||
#define RT_PHY_1000BTSR_1000FD 0x0800
|
||||
#define RT_PHY_1000BTSR_1000HD 0x0400
|
||||
|
||||
/* Link partner ability register. */
|
||||
#define RT_LINK_PARTNER__SLCT 0x001f /* Same as advertise selector */
|
||||
#define RT_LINK_PARTNER__10HALF 0x0020 /* Can do 10mbps half-duplex */
|
||||
#define RT_LINK_PARTNER__1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */
|
||||
#define RT_LINK_PARTNER__10FULL 0x0040 /* Can do 10mbps full-duplex */
|
||||
#define RT_LINK_PARTNER__1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */
|
||||
#define RT_LINK_PARTNER__100HALF 0x0080 /* Can do 100mbps half-duplex */
|
||||
#define RT_LINK_PARTNER__1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */
|
||||
#define RT_LINK_PARTNER__100FULL 0x0100 /* Can do 100mbps full-duplex */
|
||||
#define RT_LINK_PARTNER__1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/
|
||||
#define RT_LINK_PARTNER__100BASE4 0x0200 /* Can do 100mbps 4k packets */
|
||||
#define RT_LINK_PARTNER__PAUSE_CAP 0x0400 /* Can pause */
|
||||
#define RT_LINK_PARTNER__PAUSE_ASYM 0x0800 /* Can pause asymetrically */
|
||||
#define RT_LINK_PARTNER__RESV 0x1000 /* Unused... */
|
||||
#define RT_LINK_PARTNER__RFAULT 0x2000 /* Link partner faulted */
|
||||
#define RT_LINK_PARTNER__LPACK 0x4000 /* Link partner acked us */
|
||||
#define RT_LINK_PARTNER__NPAGE 0x8000 /* Next page bit */
|
||||
|
||||
#define RT_LINK_PARTNER__DUPLEX (RT_LINK_PARTNER__10FULL | RT_LINK_PARTNER__100FULL)
|
||||
#define RT_LINK_PARTNER__100 (RT_LINK_PARTNER__100FULL | RT_LINK_PARTNER__100HALF | RT_LINK_PARTNER__100BASE4)
|
||||
/* Expansion register for auto-negotiation. */
|
||||
#define RT_EXPANSION_REG_NWAY 0x0001 /* Can do N-way auto-nego */
|
||||
#define RT_EXPANSION_REG_LCWP 0x0002 /* Got new RX page code word */
|
||||
#define RT_EXPANSION_REG_ENABLENPAGE 0x0004 /* This enables npage words */
|
||||
#define RT_EXPANSION_REG_NPCAPABLE 0x0008 /* Link partner supports npage */
|
||||
#define RT_EXPANSION_REG_MFAULTS 0x0010 /* Multiple faults detected */
|
||||
#define RT_EXPANSION_REG_RESV 0xffe0 /* Unused... */
|
||||
|
||||
#define RT_SUPORT_1000B_XFULL 0x8000 /* Can do 1000BX Full */
|
||||
#define RT_SUPORT_1000B_XHALF 0x4000 /* Can do 1000BX Half */
|
||||
#define RT_SUPORT_1000B_TFULL 0x2000 /* Can do 1000BT Full */
|
||||
#define RT_SUPORT_1000B_THALF 0x1000 /* Can do 1000BT Half */
|
||||
#define RT_PHY_ANEG_TIMEOUT 4000
|
||||
struct rt_phy_device;
|
||||
|
||||
int rt_genphy_parse_link(struct rt_phy_device *phydev);
|
||||
int rt_genphy_config_aneg(struct rt_phy_device *phydev);
|
||||
int rt_genphy_update_link(struct rt_phy_device *phydev);
|
||||
int rt_genphy_startup(struct rt_phy_device *phydev);
|
||||
int rt_genphy_config(struct rt_phy_device *phydev);
|
||||
#endif
|
75
rt-thread/components/drivers/phy/mdio.c
Normal file
75
rt-thread/components/drivers/phy/mdio.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-10-08 zhujiale the first version
|
||||
*/
|
||||
#include "mdio.h"
|
||||
|
||||
static struct rt_list_node mdio_list;
|
||||
|
||||
struct mii_bus *rt_mdio_get_bus_by_name(const char *busname)
|
||||
{
|
||||
struct rt_list_node *entry;
|
||||
struct mii_bus *bus;
|
||||
|
||||
if (!busname)
|
||||
{
|
||||
rt_kprintf("NULL bus name!\n");
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
rt_list_for_each(entry, &mdio_list)
|
||||
{
|
||||
bus = rt_container_of(entry, struct mii_bus, node);
|
||||
if (!strcmp(bus->name, busname))
|
||||
return bus;
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
struct mii_bus *rt_mdio_alloc(void)
|
||||
{
|
||||
struct mii_bus *mii;
|
||||
mii = rt_malloc(sizeof(struct mii_bus));
|
||||
if (!mii)
|
||||
return RT_NULL;
|
||||
|
||||
rt_list_init(&mii->node);
|
||||
return mii;
|
||||
}
|
||||
|
||||
rt_err_t rt_mdio_register(struct mii_bus *bus)
|
||||
{
|
||||
if (!bus)
|
||||
return -RT_ERROR;
|
||||
|
||||
if(rt_mdio_get_bus_by_name(bus->name))
|
||||
{
|
||||
rt_kprintf("mdio bus %s already exist!\n", bus->name);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_list_insert_before(&mdio_list, &bus->node);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_mdio_unregister(struct mii_bus *bus)
|
||||
{
|
||||
if (!bus)
|
||||
return -RT_ERROR;
|
||||
|
||||
rt_list_remove(&bus->node);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int mdio_init(void)
|
||||
{
|
||||
rt_list_init(&mdio_list);
|
||||
return 0;
|
||||
}
|
||||
INIT_CORE_EXPORT(mdio_init);
|
98
rt-thread/components/drivers/phy/mdio.h
Normal file
98
rt-thread/components/drivers/phy/mdio.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-10-08 zhujiale the first version
|
||||
*/
|
||||
#ifndef __PHY_MDIO_H__
|
||||
#define __PHY_MDIO_H__
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define RT_MDIO_DEVAD_NONE (-1)
|
||||
#define RT_MDIO_MMD_PMAPMD 1 /* Physical Medium Attachment/
|
||||
* Physical Medium Dependent */
|
||||
#define RT_MDIO_MMD_WIS 2 /* WAN Interface Sublayer */
|
||||
#define RT_MDIO_MMD_PCS 3 /* Physical Coding Sublayer */
|
||||
#define RT_MDIO_MMD_PHYXS 4 /* PHY Extender Sublayer */
|
||||
#define RT_MDIO_MMD_DTEXS 5 /* DTE Extender Sublayer */
|
||||
#define RT_MDIO_MMD_TC 6 /* Transmission Convergence */
|
||||
#define RT_MDIO_MMD_AN 7 /* Auto-Negotiation */
|
||||
#define RT_MDIO_MMD_C22EXT 29 /* Clause 22 extension */
|
||||
#define RT_MDIO_MMD_VEND1 30 /* Vendor specific 1 */
|
||||
#define RT_MDIO_MMD_VEND2 31 /* Vendor specific 2 */
|
||||
|
||||
#define RT_MII_BMCR 0x00 /* Basic mode control register */
|
||||
#define RT_MII_BMSR 0x01 /* Basic mode status register */
|
||||
#define RT_MII_PHYSID1 0x02 /* PHYS ID 1 */
|
||||
#define RT_MII_PHYSID2 0x03 /* PHYS ID 2 */
|
||||
#define RT_MII_ADVERTISE 0x04 /* Advertisement control reg */
|
||||
#define RT_MII_LPA 0x05 /* Link partner ability reg */
|
||||
#define RT_MII_EXPANSION 0x06 /* Expansion register */
|
||||
#define RT_MII_CTRL1000 0x09 /* 1000BASE-T control */
|
||||
#define RT_MII_STAT1000 0x0a /* 1000BASE-T status */
|
||||
#define RT_MII_MMD_CTRL 0x0d /* MMD Access Control Register */
|
||||
#define RT_MII_MMD_DATA 0x0e /* MMD Access Data Register */
|
||||
#define RT_MII_ESTATUS 0x0f /* Extended Status */
|
||||
#define RT_MII_DCOUNTER 0x12 /* Disconnect counter */
|
||||
#define RT_MII_FCSCOUNTER 0x13 /* False carrier counter */
|
||||
#define RT_MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
|
||||
#define RT_MII_RERRCOUNTER 0x15 /* Receive error counter */
|
||||
#define RT_MII_SREVISION 0x16 /* Silicon revision */
|
||||
#define RT_MII_RESV1 0x17 /* Reserved... */
|
||||
#define RT_MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
|
||||
#define RT_MII_PHYADDR 0x19 /* PHY address */
|
||||
#define RT_MII_RESV2 0x1a /* Reserved... */
|
||||
#define RT_MII_TPISTATUS 0x1b /* TPI status for 10mbps */
|
||||
#define RT_MII_NCONFIG 0x1c /* Network interface config */
|
||||
|
||||
/* Basic mode control register. */
|
||||
#define RT_BMCR_RESV 0x003f /* Unused... */
|
||||
#define RT_BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
|
||||
#define RT_BMCR_CTST 0x0080 /* Collision test */
|
||||
#define RT_BMCR_FULLDPLX 0x0100 /* Full duplex */
|
||||
#define RT_BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
|
||||
#define RT_BMCR_ISOLATE 0x0400 /* Isolate data paths from MII */
|
||||
#define RT_BMCR_PDOWN 0x0800 /* Enable low power state */
|
||||
#define RT_BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
|
||||
#define RT_BMCR_SPEED100 0x2000 /* Select 100Mbps */
|
||||
#define RT_BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
|
||||
#define RT_BMCR_RESET 0x8000 /* Reset to default state */
|
||||
#define RT_BMCR_SPEED10 0x0000 /* Select 10Mbps */
|
||||
|
||||
#define RT_MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
|
||||
#define RT_MII_MMD_CTRL_ADDR 0x0000 /* Address */
|
||||
#define RT_MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */
|
||||
#define RT_MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */
|
||||
#define RT_MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
|
||||
|
||||
|
||||
#define RT_PHY_MAX 32
|
||||
|
||||
struct mii_bus
|
||||
{
|
||||
struct rt_list_node node;
|
||||
char name[RT_NAME_MAX];
|
||||
void* priv;
|
||||
int (*read)(struct mii_bus* bus, int addr, int devad, int reg);
|
||||
int (*write)(struct mii_bus* bus, int addr, int devad, int reg, rt_uint16_t val);
|
||||
/** @read_c45: Perform a C45 read transfer on the bus */
|
||||
int (*read_c45)(struct mii_bus* bus, int addr, int devad, int reg);
|
||||
/** @write_c45: Perform a C45 write transfer on the bus */
|
||||
int (*write_c45)(struct mii_bus* bus, int addr, int devad, int reg, rt_uint16_t val);
|
||||
int (*reset)(struct mii_bus* bus);
|
||||
struct rt_phy_device* phymap[RT_PHY_MAX];
|
||||
rt_uint32_t phy_mask;
|
||||
int reset_delay_us;
|
||||
int reset_post_delay_us;
|
||||
};
|
||||
|
||||
rt_err_t rt_mdio_register(struct mii_bus* bus);
|
||||
rt_err_t rt_mdio_unregister(struct mii_bus* bus);
|
||||
|
||||
struct mii_bus* rt_mdio_get_bus_by_name(const char* busname);
|
||||
struct mii_bus* rt_mdio_alloc(void);
|
||||
#endif
|
156
rt-thread/components/drivers/phy/ofw.c
Normal file
156
rt-thread/components/drivers/phy/ofw.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-09-25 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <stdio.h>
|
||||
#define DBG_TAG "rtdm.phy"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
#include "ofw.h"
|
||||
|
||||
static const char* const rt_phy_modes[] =
|
||||
{
|
||||
[RT_PHY_INTERFACE_MODE_NA] = "",
|
||||
[RT_PHY_INTERFACE_MODE_INTERNAL] = "internal",
|
||||
[RT_PHY_INTERFACE_MODE_MII] = "mii",
|
||||
[RT_PHY_INTERFACE_MODE_GMII] = "gmii",
|
||||
[RT_PHY_INTERFACE_MODE_SGMII] = "sgmii",
|
||||
[RT_PHY_INTERFACE_MODE_TBI] = "tbi",
|
||||
[RT_PHY_INTERFACE_MODE_REVMII] = "rev-mii",
|
||||
[RT_PHY_INTERFACE_MODE_RMII] = "rmii",
|
||||
[RT_PHY_INTERFACE_MODE_REVRMII] = "rev-rmii",
|
||||
[RT_PHY_INTERFACE_MODE_RGMII] = "rgmii",
|
||||
[RT_PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id",
|
||||
[RT_PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
|
||||
[RT_PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
|
||||
[RT_PHY_INTERFACE_MODE_RTBI] = "rtbi",
|
||||
[RT_PHY_INTERFACE_MODE_SMII] = "smii",
|
||||
[RT_PHY_INTERFACE_MODE_XGMII] = "xgmii",
|
||||
[RT_PHY_INTERFACE_MODE_XLGMII] = "xlgmii",
|
||||
[RT_PHY_INTERFACE_MODE_MOCA] = "moca",
|
||||
[RT_PHY_INTERFACE_MODE_PSGMII] = "psgmii",
|
||||
[RT_PHY_INTERFACE_MODE_QSGMII] = "qsgmii",
|
||||
[RT_PHY_INTERFACE_MODE_TRGMII] = "trgmii",
|
||||
[RT_PHY_INTERFACE_MODE_1000BASEX] = "1000base-x",
|
||||
[RT_PHY_INTERFACE_MODE_1000BASEKX] = "1000base-kx",
|
||||
[RT_PHY_INTERFACE_MODE_2500BASEX] = "2500base-x",
|
||||
[RT_PHY_INTERFACE_MODE_5GBASER] = "5gbase-r",
|
||||
[RT_PHY_INTERFACE_MODE_RXAUI] = "rxaui",
|
||||
[RT_PHY_INTERFACE_MODE_XAUI] = "xaui",
|
||||
[RT_PHY_INTERFACE_MODE_10GBASER] = "10gbase-r",
|
||||
[RT_PHY_INTERFACE_MODE_25GBASER] = "25gbase-r",
|
||||
[RT_PHY_INTERFACE_MODE_USXGMII] = "usxgmii",
|
||||
[RT_PHY_INTERFACE_MODE_10GKR] = "10gbase-kr",
|
||||
[RT_PHY_INTERFACE_MODE_100BASEX] = "100base-x",
|
||||
[RT_PHY_INTERFACE_MODE_QUSGMII] = "qusgmii",
|
||||
[RT_PHY_INTERFACE_MODE_MAX] = "",
|
||||
};
|
||||
|
||||
static rt_err_t _get_interface_by_name(const char *name, rt_phy_interface *interface)
|
||||
{
|
||||
for (int i = 0; i < RT_PHY_INTERFACE_MODE_MAX; i++)
|
||||
{
|
||||
if (!strcmp(name, rt_phy_modes[i]))
|
||||
{
|
||||
*interface = i;
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_err_t rt_ofw_get_interface(struct rt_ofw_node *np, rt_phy_interface *interface)
|
||||
{
|
||||
const char *phy_mode = RT_NULL;
|
||||
|
||||
if (rt_ofw_prop_read_string(np, "phy-mode", &phy_mode))
|
||||
rt_ofw_prop_read_string(np, "phy-connection-type", &phy_mode);
|
||||
if (!phy_mode)
|
||||
return -RT_ERROR;
|
||||
|
||||
return _get_interface_by_name(phy_mode, interface);
|
||||
}
|
||||
|
||||
rt_err_t rt_ofw_get_mac_addr_by_name(struct rt_ofw_node *np, const char *name, rt_uint8_t *addr)
|
||||
{
|
||||
rt_ssize_t len;
|
||||
const void *p;
|
||||
p = rt_ofw_prop_read_raw(np, name, &len);
|
||||
if (p)
|
||||
{
|
||||
rt_memcpy(addr, p, len);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_err_t rt_ofw_get_mac_addr(struct rt_ofw_node *np, rt_uint8_t *addr)
|
||||
{
|
||||
if (!rt_ofw_get_mac_addr_by_name(np, "mac-address", addr))
|
||||
return RT_EOK;
|
||||
|
||||
if (!rt_ofw_get_mac_addr_by_name(np, "local-mac-address", addr))
|
||||
return RT_EOK;
|
||||
|
||||
if (!rt_ofw_get_mac_addr_by_name(np, "address", addr))
|
||||
return RT_EOK;
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_err_t rt_ofw_get_phyid(struct rt_ofw_node *np,rt_uint32_t *id)
|
||||
{
|
||||
const char *phy_id;
|
||||
unsigned int upper, lower;
|
||||
int ret;
|
||||
|
||||
ret = rt_ofw_prop_read_string(np,"compatible",&phy_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rt_sscanf(phy_id,"ethernet-phy-id%4x.%4x",&upper, &lower);
|
||||
if(ret != 2)
|
||||
return -RT_ERROR;
|
||||
|
||||
*id = ((upper & 0xffff) << 16) | (lower & 0xffff);
|
||||
return RT_EOK;
|
||||
|
||||
}
|
||||
struct rt_phy_device *rt_ofw_create_phy(struct mii_bus *bus,struct rt_ofw_node *np,int phyaddr)
|
||||
{
|
||||
struct rt_phy_device *dev = RT_NULL;
|
||||
struct rt_ofw_node *phy_node;
|
||||
int ret;
|
||||
rt_uint32_t id = 0xffff;
|
||||
|
||||
phy_node = rt_ofw_parse_phandle(np, "phy-handle", 0);
|
||||
if (!phy_node)
|
||||
{
|
||||
LOG_D("Failed to find phy-handle");
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
ret = rt_ofw_get_phyid(np, &id);
|
||||
if (ret)
|
||||
{
|
||||
LOG_D("Failed to read eth PHY id, err: %d\n", ret);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
LOG_D("Found a PHY id: 0x%x\n", id);
|
||||
|
||||
dev = rt_phy_device_create(bus, phyaddr, id, RT_FALSE);
|
||||
|
||||
if(dev)
|
||||
dev->node = phy_node;
|
||||
|
||||
return dev;
|
||||
}
|
58
rt-thread/components/drivers/phy/ofw.h
Normal file
58
rt-thread/components/drivers/phy/ofw.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-09-25 zhujiale the first version
|
||||
*/
|
||||
#ifndef __NET_OFW_H__
|
||||
#define __NET_OFW_H__
|
||||
#include <rtthread.h>
|
||||
#include <drivers/ofw.h>
|
||||
typedef enum
|
||||
{
|
||||
RT_PHY_INTERFACE_MODE_NA,
|
||||
RT_PHY_INTERFACE_MODE_INTERNAL,
|
||||
RT_PHY_INTERFACE_MODE_MII,
|
||||
RT_PHY_INTERFACE_MODE_GMII,
|
||||
RT_PHY_INTERFACE_MODE_SGMII,
|
||||
RT_PHY_INTERFACE_MODE_TBI,
|
||||
RT_PHY_INTERFACE_MODE_REVMII,
|
||||
RT_PHY_INTERFACE_MODE_RMII,
|
||||
RT_PHY_INTERFACE_MODE_REVRMII,
|
||||
RT_PHY_INTERFACE_MODE_RGMII,
|
||||
RT_PHY_INTERFACE_MODE_RGMII_ID,
|
||||
RT_PHY_INTERFACE_MODE_RGMII_RXID,
|
||||
RT_PHY_INTERFACE_MODE_RGMII_TXID,
|
||||
RT_PHY_INTERFACE_MODE_RTBI,
|
||||
RT_PHY_INTERFACE_MODE_SMII,
|
||||
RT_PHY_INTERFACE_MODE_XGMII,
|
||||
RT_PHY_INTERFACE_MODE_XLGMII,
|
||||
RT_PHY_INTERFACE_MODE_MOCA,
|
||||
RT_PHY_INTERFACE_MODE_PSGMII,
|
||||
RT_PHY_INTERFACE_MODE_QSGMII,
|
||||
RT_PHY_INTERFACE_MODE_TRGMII,
|
||||
RT_PHY_INTERFACE_MODE_100BASEX,
|
||||
RT_PHY_INTERFACE_MODE_1000BASEX,
|
||||
RT_PHY_INTERFACE_MODE_2500BASEX,
|
||||
RT_PHY_INTERFACE_MODE_5GBASER,
|
||||
RT_PHY_INTERFACE_MODE_RXAUI,
|
||||
RT_PHY_INTERFACE_MODE_XAUI,
|
||||
/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
|
||||
RT_PHY_INTERFACE_MODE_10GBASER,
|
||||
RT_PHY_INTERFACE_MODE_25GBASER,
|
||||
RT_PHY_INTERFACE_MODE_USXGMII,
|
||||
/* 10GBASE-KR - with Clause 73 AN */
|
||||
RT_PHY_INTERFACE_MODE_10GKR,
|
||||
RT_PHY_INTERFACE_MODE_QUSGMII,
|
||||
RT_PHY_INTERFACE_MODE_1000BASEKX,
|
||||
RT_PHY_INTERFACE_MODE_MAX,
|
||||
} rt_phy_interface;
|
||||
|
||||
rt_err_t rt_ofw_get_mac_addr(struct rt_ofw_node *np, rt_uint8_t *addr);
|
||||
rt_err_t rt_ofw_get_mac_addr_by_name(struct rt_ofw_node *np, const char *name, rt_uint8_t *addr);
|
||||
rt_err_t rt_ofw_get_interface(struct rt_ofw_node *np, rt_phy_interface *interface);
|
||||
|
||||
#endif
|
@@ -1,22 +1,21 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-09-27 wangqiang first version
|
||||
* Date Author Notes
|
||||
* 2020-09-27 wangqiang first version
|
||||
* 2024-10-08 zhujiale add phy v2.0
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "PHY"
|
||||
#define DBG_TAG "rtdm.phy"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef RT_USING_PHY
|
||||
|
||||
static rt_ssize_t phy_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t count)
|
||||
{
|
||||
@@ -74,3 +73,503 @@ rt_err_t rt_hw_phy_register(struct rt_phy_device *phy, const char *name)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_PHY_V2
|
||||
int rt_phy_set_supported(struct rt_phy_device *phydev, rt_uint32_t max_speed)
|
||||
{
|
||||
phydev->supported &= RT_PHY_DEFAULT_FEATURES;
|
||||
|
||||
switch (max_speed)
|
||||
{
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
case SPEED_1000:
|
||||
phydev->supported |= RT_PHY_1000BT_FEATURES;
|
||||
case SPEED_100:
|
||||
phydev->supported |= RT_PHY_100BT_FEATURES;
|
||||
case SPEED_10:
|
||||
phydev->supported |= RT_PHY_10BT_FEATURES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt_phy_read(struct rt_phy_device *phydev, int devad, int regnum)
|
||||
{
|
||||
struct mii_bus *bus = phydev->bus;
|
||||
if(phydev->is_c45)
|
||||
{
|
||||
if(bus->read_c45)
|
||||
return bus->read_c45(bus, phydev->addr, devad, regnum);
|
||||
}
|
||||
|
||||
if( bus && bus->read )
|
||||
return bus->read(bus, phydev->addr, devad, regnum);
|
||||
|
||||
LOG_D("no read function\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rt_phy_write(struct rt_phy_device *phydev, int devad, int regnum, rt_uint16_t val)
|
||||
{
|
||||
struct mii_bus *bus = phydev->bus;
|
||||
if(phydev->is_c45)
|
||||
{
|
||||
if(bus->write_c45)
|
||||
return bus->write_c45(bus, phydev->addr, devad, regnum, val);
|
||||
}
|
||||
if( bus && bus->write )
|
||||
return bus->write(bus, phydev->addr, devad, regnum, val);
|
||||
|
||||
LOG_D("no write function\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rt_phy_startup(struct rt_phy_device *phydev)
|
||||
{
|
||||
if(!phydev->drv)
|
||||
{
|
||||
LOG_D("PHY device hace no driver\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (phydev->drv->startup)
|
||||
return phydev->drv->startup(phydev);
|
||||
|
||||
LOG_D("phy startup err\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rt_phy_config(struct rt_phy_device *phydev)
|
||||
{
|
||||
if(!phydev->drv)
|
||||
{
|
||||
LOG_D("PHY device hace no driver\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (phydev->drv->config)
|
||||
return phydev->drv->config(phydev);
|
||||
|
||||
LOG_D("no config function\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rt_phy_shutdown(struct rt_phy_device *phydev)
|
||||
{
|
||||
if(!phydev->drv)
|
||||
{
|
||||
LOG_D("PHY device hace no driver\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (phydev->drv->shutdown)
|
||||
phydev->drv->shutdown(phydev);
|
||||
|
||||
LOG_D("no shutdown function\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void rt_phy_mmd_start_indirect(struct rt_phy_device *phydev, int devad, int regnum)
|
||||
{
|
||||
/* Write the desired MMD Devad */
|
||||
rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_MMD_CTRL, devad);
|
||||
|
||||
/* Write the desired MMD register address */
|
||||
rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_MMD_DATA, regnum);
|
||||
|
||||
/* Select the Function : DATA with no post increment */
|
||||
rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_MMD_CTRL,
|
||||
(devad | RT_MII_MMD_CTRL_NOINCR));
|
||||
}
|
||||
|
||||
int rt_phy_read_mmd(struct rt_phy_device *phydev, int devad, int regnum)
|
||||
{
|
||||
struct rt_phy_driver *drv = phydev->drv;
|
||||
|
||||
if (regnum > (rt_uint16_t)~0 || devad > 32 || !drv)
|
||||
return -EINVAL;
|
||||
|
||||
if (drv->read_mmd)
|
||||
return drv->read_mmd(phydev, devad, regnum);
|
||||
|
||||
if ((drv->features & RT_PHY_10G_FEATURES) == RT_PHY_10G_FEATURES ||
|
||||
devad == RT_MDIO_DEVAD_NONE || !devad)
|
||||
return rt_phy_read(phydev, devad, regnum);
|
||||
|
||||
rt_phy_mmd_start_indirect(phydev, devad, regnum);
|
||||
|
||||
return rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_MMD_DATA);
|
||||
}
|
||||
|
||||
int rt_phy_write_mmd(struct rt_phy_device *phydev, int devad, int regnum, rt_uint16_t val)
|
||||
{
|
||||
struct rt_phy_driver *drv = phydev->drv;
|
||||
|
||||
if (regnum > (rt_uint16_t)~0 || devad > 32 || !drv)
|
||||
return -EINVAL;
|
||||
|
||||
if (drv->write_mmd)
|
||||
return drv->write_mmd(phydev, devad, regnum, val);
|
||||
|
||||
if ((drv->features & RT_PHY_10G_FEATURES) == RT_PHY_10G_FEATURES ||
|
||||
devad == RT_MDIO_DEVAD_NONE || !devad)
|
||||
return rt_phy_write(phydev, devad, regnum, val);
|
||||
|
||||
rt_phy_mmd_start_indirect(phydev, devad, regnum);
|
||||
|
||||
return rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_MMD_DATA, val);
|
||||
}
|
||||
|
||||
int rt_phy_reset(struct rt_phy_device *phydev)
|
||||
{
|
||||
int reg;
|
||||
int timeout = 500;
|
||||
int devad = RT_MDIO_DEVAD_NONE;
|
||||
|
||||
if (phydev->flags & RT_PHY_FLAG_BROKEN_RESET)
|
||||
return 0;
|
||||
|
||||
if (rt_phy_write(phydev, devad, RT_MII_BMCR, RT_BMCR_RESET) < 0)
|
||||
{
|
||||
LOG_D("PHY reset failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg = rt_phy_read(phydev, devad, RT_MII_BMCR);
|
||||
while ((reg & RT_BMCR_RESET) && timeout--)
|
||||
{
|
||||
reg = rt_phy_read(phydev, devad, RT_MII_BMCR);
|
||||
|
||||
if (reg < 0)
|
||||
{
|
||||
LOG_D("PHY status read failed\n");
|
||||
return -1;
|
||||
}
|
||||
rt_thread_mdelay(1);
|
||||
}
|
||||
|
||||
if (reg & RT_BMCR_RESET)
|
||||
{
|
||||
LOG_D("PHY reset timed out\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rt_bus rt_phy_bus;
|
||||
|
||||
/**
|
||||
* @brief create a phy device
|
||||
*
|
||||
* Creates a new PHY device based on the given bus, address, PHY ID, and whether Clause 45 is supported.
|
||||
*
|
||||
* @param bus the pointer to the bus
|
||||
* @param addr PHY device address
|
||||
* @param phy_id PHY device id
|
||||
* @param is_c45 if suport Clause 45
|
||||
*
|
||||
* @return if create success return the phy device pointer,else return RT_NULL
|
||||
*/
|
||||
struct rt_phy_device *rt_phy_device_create(struct mii_bus *bus, int addr,
|
||||
rt_uint32_t phy_id, rt_bool_t is_c45)
|
||||
{
|
||||
struct rt_phy_device *dev = rt_malloc(sizeof(struct rt_phy_device));
|
||||
|
||||
if (!dev)
|
||||
{
|
||||
LOG_E("Failed to allocate PHY device for %s:%d\n",
|
||||
bus ? bus->name : "(null bus)", addr);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
dev->duplex = -1;
|
||||
dev->link = 0;
|
||||
dev->interface = RT_PHY_INTERFACE_MODE_NA;
|
||||
#ifdef RT_USING_OFW
|
||||
dev->node = RT_NULL;
|
||||
#endif
|
||||
dev->autoneg = RT_TRUE;
|
||||
|
||||
dev->addr = addr;
|
||||
dev->phy_id = phy_id;
|
||||
dev->is_c45 = is_c45;
|
||||
dev->bus = bus;
|
||||
|
||||
if(rt_phy_device_register(dev))
|
||||
{
|
||||
LOG_D("register phy device filed")
|
||||
}
|
||||
|
||||
if (addr >= 0 && addr < RT_PHY_MAX && phy_id != RT_PHY_FIXED_ID &&
|
||||
phy_id != RT_PHY_NCSI_ID)
|
||||
bus->phymap[addr] = dev;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get phy id
|
||||
*
|
||||
* get phy id by read the register 2 and 3 of PHY device,
|
||||
* Register of the MII management interface stipulates that
|
||||
* register 2 contains thehigh 16 bits of the PHY’s identifier
|
||||
* the register 3 contains the low 16 bits of the PHY’s identifier
|
||||
*
|
||||
* @param bus MII bus pointer
|
||||
* @param addr PHY device address
|
||||
* @param devad dev addr if be set to zero it means c22 mode,else it means c45 mode
|
||||
* @param phy_id the phy id which will be read
|
||||
*
|
||||
* @return if read success return 0,else return -RT_EIO
|
||||
*/
|
||||
static int get_phy_id(struct mii_bus *bus, int addr, int devad, rt_uint32_t *phy_id)
|
||||
{
|
||||
int phy_reg;
|
||||
|
||||
phy_reg = bus->read(bus, addr, devad, RT_MII_PHYSID1);
|
||||
|
||||
if (phy_reg < 0)
|
||||
return -RT_EIO;
|
||||
|
||||
*phy_id = (phy_reg & 0xffff) << 16;
|
||||
|
||||
phy_reg = bus->read(bus, addr, devad, RT_MII_PHYSID2);
|
||||
|
||||
if (phy_reg < 0)
|
||||
return -RT_EIO;
|
||||
|
||||
*phy_id |= (phy_reg & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief create phy device by mask
|
||||
*
|
||||
* @param bus MII bus pointer
|
||||
* @param phy_mask the mask which phy addr corresponding will be set 1
|
||||
* @param devad dev addr if be set to zero it means c22 mode,else it means c45 mode
|
||||
*
|
||||
* @return if create success return the phy device pointer,if create fail return NULL
|
||||
*/
|
||||
static struct rt_phy_device *create_phy_by_mask(struct mii_bus *bus, unsigned int phy_mask,int devad)
|
||||
{
|
||||
rt_uint32_t id = 0xffffffff;
|
||||
rt_bool_t is_c45;
|
||||
|
||||
while (phy_mask)
|
||||
{
|
||||
int addr = __rt_ffs(phy_mask) - 1;
|
||||
int r = get_phy_id(bus, addr, devad, &id);
|
||||
|
||||
if (r == 0 && id == 0)
|
||||
{
|
||||
phy_mask &= ~(1 << addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r == 0 && (id & 0x1fffffff) != 0x1fffffff)
|
||||
{
|
||||
is_c45 = (devad == RT_MDIO_DEVAD_NONE) ? RT_FALSE : RT_TRUE;
|
||||
return rt_phy_device_create(bus, addr, id, is_c45);
|
||||
}
|
||||
|
||||
}
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief create phy device by mask
|
||||
*
|
||||
* it will create phy device by c22 mode or c45 mode
|
||||
*
|
||||
* @param bus mii bus pointer
|
||||
* @param phy_mask PHY mask it depend on the phy addr, the phy addr corresponding will be set 1
|
||||
*
|
||||
* @return if create success return the phy device pointer,if create fail return NULL
|
||||
*/
|
||||
static struct rt_phy_device *rt_phydev_create_by_mask(struct mii_bus *bus, unsigned int phy_mask)
|
||||
{
|
||||
struct rt_phy_device *phy;
|
||||
/*
|
||||
*The bit of devad is dev addr which is the new features in c45
|
||||
*so if devad equal to zero it means it is c22 mode ,and if not
|
||||
*equal to zero it means it is c45 mode,which include PMD/PMA ,
|
||||
*WIS ,PCS,PHY XS,PHY XS ....
|
||||
*/
|
||||
int devad[] = {
|
||||
/* Clause-22 */
|
||||
RT_MDIO_DEVAD_NONE,
|
||||
/* Clause-45 */
|
||||
RT_MDIO_MMD_PMAPMD,
|
||||
RT_MDIO_MMD_WIS,
|
||||
RT_MDIO_MMD_PCS,
|
||||
RT_MDIO_MMD_PHYXS,
|
||||
RT_MDIO_MMD_VEND1,
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(devad)/sizeof(devad[0]); i++)
|
||||
{
|
||||
phy = create_phy_by_mask(bus, phy_mask, devad[i]);
|
||||
if(phy)
|
||||
return phy;
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
struct rt_phy_device *rt_phy_find_by_mask(struct mii_bus *bus, unsigned int phy_mask)
|
||||
{
|
||||
struct rt_phy_device *phy;
|
||||
unsigned int mask = phy_mask;
|
||||
unsigned int addr;
|
||||
if (bus->reset)
|
||||
{
|
||||
bus->reset(bus);
|
||||
|
||||
rt_thread_mdelay(15);
|
||||
}
|
||||
|
||||
while (mask)
|
||||
{
|
||||
/*
|
||||
*Whichever bit of the mask is the 1,
|
||||
*which bit is the addr as the array subscript to search
|
||||
*such as mask = 1110 ,this loop will search for subscript
|
||||
*1,2,3,if the array subscript is not null then return it,
|
||||
*if the array subscript is null then continue to search
|
||||
*/
|
||||
addr = __rt_ffs(mask) - 1;
|
||||
|
||||
if (bus->phymap[addr])
|
||||
return bus->phymap[addr];
|
||||
|
||||
mask &= ~(1U << addr);
|
||||
}
|
||||
/*ifcan't find phy device, create a new phy device*/
|
||||
phy = rt_phydev_create_by_mask(bus, phy_mask);
|
||||
|
||||
return phy;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get phy device by given mii bus, node and address
|
||||
* @param bus MII bus pointer
|
||||
* @param np the dtb node of device which need to get phy device
|
||||
* @param addr address of phy device
|
||||
* @param interface interface of phy device
|
||||
*
|
||||
* @return phy device pointer or NULL if not found
|
||||
*/
|
||||
struct rt_phy_device *rt_phy_get_device(struct mii_bus *bus,struct rt_ofw_node *np, int addr,rt_phy_interface interface)
|
||||
{
|
||||
struct rt_phy_device *phy = RT_NULL;
|
||||
unsigned int phy_mask = addr? 1 << addr:0xffffffff;
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if(np)
|
||||
phy = rt_ofw_create_phy(bus,np,addr);
|
||||
#endif
|
||||
if(!phy)
|
||||
phy = rt_phy_find_by_mask(bus,phy_mask);
|
||||
|
||||
if(phy)
|
||||
{
|
||||
rt_phy_reset(phy);
|
||||
phy->interface = interface;
|
||||
return phy;
|
||||
}
|
||||
|
||||
LOG_D("PHY device get failed");
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static struct rt_phy_driver genphy = {
|
||||
.uid = 0xffffffff,
|
||||
.mask = 0xffffffff,
|
||||
.name = "Generic PHY",
|
||||
.features = RT_PHY_GBIT_FEATURES | RT_SUPPORTED_MII |
|
||||
RT_SUPPORTED_AUI | RT_SUPPORTED_FIBRE |
|
||||
RT_SUPPORTED_BNC,
|
||||
.config = rt_genphy_config,
|
||||
.startup = rt_genphy_startup,
|
||||
};
|
||||
RT_PHY_DRIVER_REGISTER(genphy);
|
||||
|
||||
rt_err_t rt_phy_device_register(struct rt_phy_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
RT_ASSERT(pdev != RT_NULL);
|
||||
err = rt_bus_add_device(&rt_phy_bus, &pdev->parent);
|
||||
if (err)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
if(!pdev->drv)
|
||||
pdev->drv = &genphy;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_phy_driver_register(struct rt_phy_driver *pdrv)
|
||||
{
|
||||
RT_ASSERT(pdrv != RT_NULL);
|
||||
|
||||
pdrv->parent.bus = &rt_phy_bus;
|
||||
#if RT_NAME_MAX > 0
|
||||
rt_strcpy(pdrv->parent.parent.name, pdrv->name);
|
||||
#else
|
||||
pdrv->parent.parent.name = pdrv->name;
|
||||
#endif
|
||||
|
||||
return rt_driver_register(&pdrv->parent);
|
||||
}
|
||||
|
||||
static rt_bool_t phy_match(rt_driver_t drv, rt_device_t dev)
|
||||
{
|
||||
struct rt_phy_device *pdev = rt_container_of(dev, struct rt_phy_device, parent);
|
||||
struct rt_phy_driver *pdrv = rt_container_of(drv, struct rt_phy_driver, parent);
|
||||
if ((pdrv->uid & pdrv->mask) == (pdev->phy_id & pdrv->mask))
|
||||
return RT_TRUE;
|
||||
|
||||
return RT_FALSE;
|
||||
|
||||
}
|
||||
|
||||
static rt_err_t phy_probe(rt_device_t dev)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct rt_phy_driver *pdrv = rt_container_of(dev->drv, struct rt_phy_driver, parent);
|
||||
struct rt_phy_device *pdev = rt_container_of(dev, struct rt_phy_device, parent);
|
||||
pdev->drv = pdrv;
|
||||
pdev->advertising = pdev->drv->features;
|
||||
pdev->supported = pdev->drv->features;
|
||||
|
||||
pdev->mmds = pdev->drv->mmds;
|
||||
if(pdrv->probe)
|
||||
err = pdrv->probe(pdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct rt_bus rt_phy_bus =
|
||||
{
|
||||
.name = "phy",
|
||||
.match = phy_match,
|
||||
.probe = phy_probe,
|
||||
};
|
||||
|
||||
static int rt_phy_bus_init(void)
|
||||
{
|
||||
rt_bus_register(&rt_phy_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_CORE_EXPORT(rt_phy_bus_init);
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user