/* Copyright (c) 2015 Broadcom Corporation All Rights Reserved <:label-BRCM:2015:DUAL/GPL:standard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation (the "GPL"). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php, or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. :> */ /* * Created on: Dec 2015 * Author: yuval.raviv@broadcom.com */ #ifndef __PHY_DRV_H__ #define __PHY_DRV_H__ #include "bus_drv.h" #define PHY_CAP_10_HALF (1 << 0) #define PHY_CAP_10_FULL (1 << 1) #define PHY_CAP_100_HALF (1 << 2) #define PHY_CAP_100_FULL (1 << 3) #define PHY_CAP_1000_HALF (1 << 4) #define PHY_CAP_1000_FULL (1 << 5) #define PHY_CAP_2500 (1 << 6) #define PHY_CAP_5000 (1 << 7) #define PHY_CAP_10000 (1 << 8) #define PHY_CAP_AUTONEG (1 << 9) #define PHY_CAP_PAUSE (1 << 10) #define PHY_CAP_PAUSE_ASYM (1 << 11) #define PHY_CAP_REPEATER (1 << 12) typedef enum { PHY_SPEED_UNKNOWN, PHY_SPEED_AUTO = PHY_SPEED_UNKNOWN, PHY_SPEED_10, PHY_SPEED_100, PHY_SPEED_1000, PHY_SPEED_2500, PHY_SPEED_5000, PHY_SPEED_10000, } phy_speed_t; static inline char *phy_get_speed_string(phy_speed_t speed) { static char *speedStr[] = { [PHY_SPEED_UNKNOWN] = "Auto", [PHY_SPEED_10] = "10M", [PHY_SPEED_100] = "100M", [PHY_SPEED_1000] = "1G", [PHY_SPEED_2500] = "2.5G", [PHY_SPEED_5000] = "5G", [PHY_SPEED_10000] = "10G" }; return speedStr[speed]; } typedef enum { PHY_DUPLEX_UNKNOWN, PHY_DUPLEX_HALF, PHY_DUPLEX_FULL, } phy_duplex_t; typedef enum { PHY_MII_TYPE_UNKNOWN, PHY_MII_TYPE_MII, PHY_MII_TYPE_TMII, PHY_MII_TYPE_GMII, PHY_MII_TYPE_RGMII, PHY_MII_TYPE_SGMII, PHY_MII_TYPE_HSGMII, PHY_MII_TYPE_XFI, PHY_MII_TYPE_SERDES, } phy_mii_type_t; typedef enum { PHY_TYPE_UNKNOWN, PHY_TYPE_6848_EPHY, PHY_TYPE_6848_EGPHY, PHY_TYPE_6848_SGMII, PHY_TYPE_PCS, PHY_TYPE_6858_EGPHY, PHY_TYPE_6846_EGPHY, PHY_TYPE_6856_SGMII, PHY_TYPE_EXT1, PHY_TYPE_EXT2, PHY_TYPE_EXT3, PHY_TYPE_LPORT_SERDES, PHY_TYPE_53125, PHY_TYPE_PON, PHY_TYPE_SF2_GPHY, PHY_TYPE_SF2_CL45_PHY, PHY_TYPE_SF2_SERDES, PHY_TYPE_I2C_PHY, PHY_TYPE_XGAE, PHY_TYPE_CROSSBAR, PHY_TYPE_MAC2MAC, PHY_TYPE_G9991, PHY_TYPE_MAX, } phy_type_t; typedef void (*link_change_cb_t)(void *ctx); typedef enum { INTER_PHY_TYPE_UNKNOWN, INTER_PHY_TYPE_2P5GBASE_X, INTER_PHY_TYPE_2P5GBASE_R, INTER_PHY_TYPE_2P5GIDLE, INTER_PHY_TYPE_5GBASE_R, INTER_PHY_TYPE_5GBASE_X, INTER_PHY_TYPE_5GIDLE, } inter_phy_type_t; /* Phy device */ typedef struct phy_dev_s { struct phy_drv_s *phy_drv; phy_mii_type_t mii_type; link_change_cb_t link_change_cb; void *link_change_ctx; uint32_t addr; // contains phy address only uint32_t meta_id; // contains extra phyId info from board param void *priv; int link; phy_speed_t speed; phy_duplex_t duplex; int pause_rx; int pause_tx; int delay_rx; int delay_tx; int disable_hd; int disable_10m; int disable_100m; int disable_1000m; int disable_2500m; int disable_5000m; int disable_10000m; int swap_pair; int flag; int loopback_save; int reset_gpio; int reset_gpio_active_hi; inter_phy_type_t inter_phy_types; void *macsec_dev; /* For cascaded PHY */ void *sw_port; struct phy_dev_s *cascade_next; struct phy_dev_s *cascade_prev; } phy_dev_t; #define PHY_FLAG_NOT_PRESENTED (1<<0) /* for SFP module indicating not inserted */ #define PHY_FLAG_POWER_SET_ENABLED (1<<1) #define PHY_FLAG_DYNAMIC (1<<2) #define PHY_FLAG_CABLE_DIAG_ENABLED (1<<3) #define PHY_FLAG_TO_EXTSW (1<<4) #define PHY_FLAG_CABLE_DIAG_INITED (1<<5) #define PHY_FLAG_CONF_PAUSE_RX (1<<6) #define PHY_FLAG_CONF_PAUSE_TX (1<<7) #define PHY_FLAG_CONF_PAUSE_VALID (1<<8) #define CAPS_TYPE_ADVERTISE 0 #define CAPS_TYPE_SUPPORTED 1 #define CAPS_TYPE_LP_ADVERTISED 2 #define INTER_PHY_TYPE_2P5GBASE_X_M (1<cascade_prev || phy->cascade_next) #define cascade_phy_get_next(phy) ((phy->cascade_next && !(phy->cascade_next->flag & PHY_FLAG_NOT_PRESENTED))? phy->cascade_next : NULL) static inline phy_dev_t *cascade_phy_get_first(phy_dev_t *phy_dev) { phy_dev_t *phy; for(phy=phy_dev; phy->cascade_prev; phy=phy->cascade_prev); return phy; } static inline phy_dev_t *cascade_phy_get_last(phy_dev_t *phy_dev) { phy_dev_t *phy; if (!phy_dev) return NULL; for(phy=phy_dev; phy->cascade_next && !(phy->cascade_next->flag & PHY_FLAG_NOT_PRESENTED); phy=phy->cascade_next); return phy; } static inline int phy_bus_read(phy_dev_t *phy_dev, uint16_t reg, uint16_t *val) { if (!phy_dev->phy_drv->bus_drv) return 0; return phy_dev->phy_drv->bus_drv->c22_read(phy_dev->addr, reg, val); } static inline int phy_bus_write(phy_dev_t *phy_dev, uint16_t reg, uint16_t val) { if (!phy_dev->phy_drv->bus_drv) return 0; return phy_dev->phy_drv->bus_drv->c22_write(phy_dev->addr, reg, val); } static inline int phy_bus_c45_read(phy_dev_t *phy_dev, uint16_t dev, uint16_t reg, uint16_t *val) { if (!phy_dev->phy_drv->bus_drv) return 0; return phy_dev->phy_drv->bus_drv->c45_read(phy_dev->addr, dev, reg, val); } static inline int phy_bus_c45_write(phy_dev_t *phy_dev, uint16_t dev, uint16_t reg, uint16_t val) { if (!phy_dev->phy_drv->bus_drv) return 0; return phy_dev->phy_drv->bus_drv->c45_write(phy_dev->addr, dev, reg, val); } static inline int phy_dev_read(phy_dev_t *phy_dev, uint16_t reg, uint16_t *val) { if (phy_dev->phy_drv->read) return phy_dev->phy_drv->read(phy_dev, reg, val); else return phy_bus_read(phy_dev, reg, val); } static inline int phy_dev_write(phy_dev_t *phy_dev, uint16_t reg, uint16_t val) { if (phy_dev->phy_drv->write) return phy_dev->phy_drv->write(phy_dev, reg, val); else return phy_bus_write(phy_dev, reg, val); } static inline int phy_dev_isolate_phy(phy_dev_t *phy_dev, int isolate) { if (!phy_dev->phy_drv->isolate_phy) return 0; return phy_dev->phy_drv->isolate_phy(phy_dev, isolate); } static inline int phy_dev_super_isolate_phy(phy_dev_t *phy_dev, int isolate) { if (!phy_dev->phy_drv->super_isolate_phy) return 0; return phy_dev->phy_drv->super_isolate_phy(phy_dev, isolate); } static inline int phy_dev_pair_swap_set(phy_dev_t *phy_dev, int enable) { if (!phy_dev->phy_drv->pair_swap_set) return 0; return phy_dev->phy_drv->pair_swap_set(phy_dev, enable); } static inline int phy_dev_power_get(phy_dev_t *phy_dev, int *enable) { *enable = 0; if (!phy_dev->phy_drv->power_get) return 0; return phy_dev->phy_drv->power_get(phy_dev, enable); } static inline int phy_dev_power_set(phy_dev_t *phy_dev, int enable) { if (is_cascade_phy(phy_dev)) { phy_dev_t *cascade; for (cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) { //printk("phy %s:%d power_set=%d\n", (phy_dev->phy_drv) ? cascade->phy_drv->name : NULL, cascade->addr, enable); if (enable) cascade->flag |= PHY_FLAG_POWER_SET_ENABLED; else cascade->flag &= ~PHY_FLAG_POWER_SET_ENABLED; if (cascade->phy_drv->power_set) cascade->phy_drv->power_set(cascade, enable); } return 0; } //printk("phy %s:%d power_set=%d\n", (phy_dev->phy_drv) ? phy_dev->phy_drv->name : NULL, phy_dev->addr, enable); if (enable) phy_dev->flag |= PHY_FLAG_POWER_SET_ENABLED; else phy_dev->flag &= ~PHY_FLAG_POWER_SET_ENABLED; if (!phy_dev->phy_drv->power_set) return 0; return phy_dev->phy_drv->power_set(phy_dev, enable); } static inline int phy_dev_apd_get(phy_dev_t *phy_dev, int *enable) { *enable = 0; if (!phy_dev->phy_drv->apd_get) return 0; return phy_dev->phy_drv->apd_get(phy_dev, enable); } static inline int cascade_phy_dev_apd_get(phy_dev_t *phy_dev, int *enable) { int _enable; int rc = 0; phy_dev_t *cascade; if (is_cascade_phy(phy_dev)) { for (*enable = 0, cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) { if (cascade->flag & PHY_FLAG_NOT_PRESENTED) break; rc |= phy_dev_apd_get(cascade, &_enable); *enable |= _enable; } return rc; } return phy_dev_apd_get(phy_dev, enable); } static inline int phy_dev_apd_set(phy_dev_t *phy_dev, int enable) { if (!phy_dev->phy_drv->apd_set) return 0; return phy_dev->phy_drv->apd_set(phy_dev, enable); } static inline int cascade_phy_dev_apd_set(phy_dev_t *phy_dev, int enable) { int rc = 0; phy_dev_t *cascade; if (is_cascade_phy(phy_dev)) { for (cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) { if (cascade->flag & PHY_FLAG_NOT_PRESENTED) break; rc |= phy_dev_apd_set(cascade, enable); } return rc; } return phy_dev_apd_set(phy_dev, enable); } static inline int phy_dev_cable_diag_run(phy_dev_t *phy_dev, int *result, int *pair_len) { if (!phy_dev->phy_drv->cable_diag_run) return -1; return phy_dev->phy_drv->cable_diag_run(phy_dev, result, pair_len); } static inline int phy_dev_cable_diag_is_supported(phy_dev_t *phy_dev) { return phy_dev->phy_drv->cable_diag_run != NULL; } static inline int phy_dev_cable_diag_is_enabled(phy_dev_t *phy_dev) { return (phy_dev->flag & PHY_FLAG_CABLE_DIAG_ENABLED) > 0; } static inline int phy_dev_cable_diag_set(phy_dev_t *phy_dev, int enable) { if (!phy_dev->phy_drv->cable_diag_run) return -1; phy_dev->flag &= ~PHY_FLAG_CABLE_DIAG_ENABLED; phy_dev->flag |= enable? PHY_FLAG_CABLE_DIAG_ENABLED: 0; if (!phy_dev->phy_drv->cable_diag_set) return 0; return phy_dev->phy_drv->cable_diag_set(phy_dev, enable); } static inline int phy_dev_cable_diag_get(phy_dev_t *phy_dev, int *enable) { if (!phy_dev->phy_drv->cable_diag_run) return -1; *enable = (phy_dev->flag & PHY_FLAG_CABLE_DIAG_ENABLED) > 0; return 0; } static inline int phy_dev_eee_get(phy_dev_t *phy_dev, int *enable) { *enable = 0; if (!phy_dev->phy_drv->eee_get) return 0; return phy_dev->phy_drv->eee_get(phy_dev, enable); } static inline int phy_dev_eee_set(phy_dev_t *phy_dev, int enable) { if (!phy_dev->phy_drv->eee_set) return 0; return phy_dev->phy_drv->eee_set(phy_dev, enable); } static inline int phy_dev_eee_resolution_get(phy_dev_t *phy_dev, int *enable) { *enable = 0; if (!phy_dev->phy_drv->eee_resolution_get) return 0; return phy_dev->phy_drv->eee_resolution_get(phy_dev, enable); } static inline int phy_dev_read_status(phy_dev_t *phy_dev) { int ret = 0; #if !defined(DSL_DEVICES) phy_speed_t speed = phy_dev->speed; #endif if (!phy_dev->phy_drv->read_status) goto Exit; if ((ret = phy_dev->phy_drv->read_status(phy_dev))) goto Exit; #if !defined(DSL_DEVICES) /* DSL product has revert chain direction due to dyanmic module support */ if (phy_dev->speed == speed) goto Exit; if (!phy_dev->cascade_prev) goto Exit; if (!phy_dev->cascade_prev->phy_drv->speed_set) goto Exit; if ((ret = phy_dev->cascade_prev->phy_drv->speed_set(phy_dev->cascade_prev, phy_dev->speed, phy_dev->duplex))) goto Exit; #endif #if defined(DSL_DEVICES) // administratively force link down if ethernet phy is not in power enable state if (phy_dev->phy_drv->phy_type != PHY_TYPE_PON && !(phy_dev->flag & PHY_FLAG_POWER_SET_ENABLED) && !(phy_dev->flag & PHY_FLAG_TO_EXTSW)) { phy_dev->link = 0; } #endif Exit: return ret; } static inline int phy_dev_config_speed_get(phy_dev_t *phy_dev, phy_speed_t *speed, phy_duplex_t *duplex) { if (!phy_dev->phy_drv->config_speed_get) return 0; return phy_dev->phy_drv->config_speed_get(phy_dev, speed, duplex); } static inline int phy_dev_speed_set(phy_dev_t *phy_dev, phy_speed_t speed, phy_duplex_t duplex) { if (!phy_dev->phy_drv->speed_set) return 0; return phy_dev->phy_drv->speed_set(phy_dev, speed, duplex); } static inline int phy_dev_auto_mdix_set(phy_dev_t *phy_dev, int enable) { if (!phy_dev->phy_drv->auto_mdix_set) return -1; return phy_dev->phy_drv->auto_mdix_set(phy_dev, enable); } static inline int phy_dev_auto_mdix_get(phy_dev_t *phy_dev, int *enable) { if (!phy_dev->phy_drv->auto_mdix_get) return -1; return phy_dev->phy_drv->auto_mdix_get(phy_dev, enable); } static inline int phy_dev_wirespeed_set(phy_dev_t *phy_dev, int enable) { if (!phy_dev->phy_drv->wirespeed_set) return -1; return phy_dev->phy_drv->wirespeed_set(phy_dev, enable); } static inline int phy_dev_wirespeed_get(phy_dev_t *phy_dev, int *enable) { if (!phy_dev->phy_drv->wirespeed_get) return -1; return phy_dev->phy_drv->wirespeed_get(phy_dev, enable); } static inline void phy_dev_status_propagate(phy_dev_t *end_phy) { phy_dev_t *phy_dev; for (phy_dev = end_phy->cascade_prev; phy_dev; phy_dev = phy_dev->cascade_prev) { phy_dev_speed_set(phy_dev, end_phy->speed, end_phy->duplex); phy_dev->link = end_phy->link; phy_dev->speed = end_phy->speed; phy_dev->duplex = end_phy->duplex; } } /* For propagating status toward end PHY for status only without changing configuration during the link up due to the status call-back is done in internal PHY */ static inline void phy_dev_status_reverse_propagate(phy_dev_t *end_phy) { phy_dev_t *phy_dev; for (phy_dev = end_phy->cascade_next; phy_dev && !(phy_dev->flag & PHY_FLAG_NOT_PRESENTED); phy_dev = phy_dev->cascade_next) { phy_dev->link = end_phy->link; phy_dev->speed = end_phy->speed; phy_dev->duplex = end_phy->duplex; } } static inline int phy_dev_caps_set(phy_dev_t *phy_dev, uint32_t caps) { if (!phy_dev->phy_drv->caps_set) return 0; return phy_dev->phy_drv->caps_set(phy_dev, caps); } static inline int phy_dev_caps_get(phy_dev_t *phy_dev, int caps_type, uint32_t *caps) { *caps = 0; if (!phy_dev->phy_drv->caps_get) return 0; return phy_dev->phy_drv->caps_get(phy_dev, caps_type, caps); } static inline phy_speed_t phy_caps_to_max_speed(uint32_t caps) { int i; static int speed[] = {PHY_CAP_10000, PHY_SPEED_10000, PHY_CAP_5000, PHY_SPEED_5000, PHY_CAP_2500, PHY_SPEED_2500, PHY_CAP_1000_FULL, PHY_SPEED_1000, PHY_CAP_1000_HALF, PHY_SPEED_1000, PHY_CAP_100_FULL, PHY_SPEED_100, PHY_CAP_100_HALF, PHY_SPEED_100, PHY_CAP_10_FULL, PHY_SPEED_10, PHY_CAP_10_HALF, PHY_SPEED_10}; for (i=0; i>= 1; return cap; } static inline int phy_dev_phyid_get(phy_dev_t *phy_dev, uint32_t *phyid) { *phyid = 0; if (!phy_dev->phy_drv->phyid_get) return 0; return phy_dev->phy_drv->phyid_get(phy_dev, phyid); } static inline int phy_dev_init(phy_dev_t *first_phy) { int rc = 0; phy_dev_t *phy_dev; for (phy_dev = cascade_phy_get_first(first_phy); phy_dev; phy_dev = phy_dev->cascade_next) { phy_dev->link = 0; phy_dev->speed = PHY_SPEED_UNKNOWN; phy_dev->duplex = PHY_DUPLEX_UNKNOWN; if (phy_dev->phy_drv->init != NULL) rc |= phy_dev->phy_drv->init(phy_dev); if (phy_dev->phy_drv->phy_type != PHY_TYPE_CROSSBAR) { if (phy_dev->phy_drv->phy_type != PHY_TYPE_SF2_SERDES && phy_dev->phy_drv->phy_type != PHY_TYPE_SF2_CL45_PHY) rc |= phy_dev_apd_set(phy_dev, 1); rc |= phy_dev_eee_set(phy_dev, 1); } } return rc; } static inline int cascade_phy_dev_isolate_phy(phy_dev_t *phy_dev, int isolate) { if (is_cascade_phy(phy_dev)) { int rc = 0; phy_dev_t *cascade; for (cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) rc |= phy_dev_isolate_phy(cascade, isolate); return rc; } return phy_dev_isolate_phy(phy_dev, isolate); } static inline int cascade_phy_dev_eee_set(phy_dev_t *phy_dev, int enable) { if (is_cascade_phy(phy_dev)) { int rc = 0; phy_dev_t *cascade; for (cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) rc |= phy_dev_eee_set(cascade, enable); return rc; } return phy_dev_eee_set(phy_dev, enable); } static inline int cascade_phy_dev_eee_get(phy_dev_t *phy_dev, int *enable) { int val; if (is_cascade_phy(phy_dev)) { int rc = 0; phy_dev_t *cascade; *enable = 0; for (cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) { rc |= phy_dev_eee_get(cascade, &val); *enable |= val; } return rc; } return phy_dev_eee_get(phy_dev, enable); } static inline int cascade_phy_dev_eee_resolution_get(phy_dev_t *phy_dev, int *enable) { int val; if (is_cascade_phy(phy_dev)) { int rc = 0; phy_dev_t *cascade; *enable = 0; for (cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) { rc |= phy_dev_eee_resolution_get(cascade, &val); *enable |= val; } return rc; } return phy_dev_eee_resolution_get(phy_dev, enable); } static inline int cascade_phy_dev_speed_set(phy_dev_t *phy_dev, phy_speed_t speed, phy_duplex_t duplex) { if (is_cascade_phy(phy_dev)) { int rc = 0; phy_dev_t *cascade; for (cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) { rc |= phy_dev_speed_set(cascade, speed, duplex); } return rc; } return phy_dev_speed_set(phy_dev, speed, duplex); } // find minimum caps static inline int cascade_phy_dev_caps_get(phy_dev_t *phy_dev, int caps_type, uint32_t *caps) { int rc = 0; phy_dev_t *cascade; uint32_t cascade_caps; *caps = 0; if (is_cascade_phy(phy_dev)) { for (cascade = cascade_phy_get_first(phy_dev), *caps = 0; cascade; cascade = cascade_phy_get_next(cascade)) { if (cascade->phy_drv->caps_get) { rc |= cascade->phy_drv->caps_get(cascade, caps_type, &cascade_caps); if (cascade_caps) *caps = (*caps) ? ((*caps & cascade_caps) | (cascade_caps & (PHY_CAP_PAUSE|PHY_CAP_PAUSE_ASYM))) : cascade_caps; } } return rc; } return phy_dev_caps_get(phy_dev, caps_type, caps); } static inline int cascade_phy_dev_caps_set(phy_dev_t *phy_dev, uint32_t caps) { if (is_cascade_phy(phy_dev)) { int rc = 0; phy_dev_t *cascade; for (cascade = cascade_phy_get_first(phy_dev); cascade; cascade = cascade_phy_get_next(cascade)) rc |= phy_dev_caps_set(cascade, caps); return rc; } return phy_dev_caps_set(phy_dev, caps); } /* Return if the phy_speed_t is covered by the PHY Speed CAP */ static inline int phy_dev_cap_speed_match(uint32_t caps, phy_speed_t speed) { switch (speed) { case PHY_SPEED_10000: return ((caps & PHY_CAP_10000)>0); case PHY_SPEED_5000: return ((caps & PHY_CAP_5000)>0); case PHY_SPEED_2500: return ((caps & PHY_CAP_2500)>0); case PHY_SPEED_1000: return ((caps & PHY_CAP_1000_FULL)>0); case PHY_SPEED_100: return ((caps & PHY_CAP_100_FULL)>0); case PHY_SPEED_10: return ((caps & PHY_CAP_10_FULL)>0); default: break; } return 0; } static inline phy_speed_t cascade_phy_max_speed_get(phy_dev_t *phy_dev) { uint32_t caps; if (cascade_phy_dev_caps_get(phy_dev, CAPS_TYPE_SUPPORTED, &caps)) return 0; return phy_caps_to_max_speed(caps); } static inline phy_speed_t phy_max_speed_get(phy_dev_t *phy_dev) { uint32_t caps; if (phy_dev_caps_get(phy_dev, CAPS_TYPE_SUPPORTED, &caps)) return 0; return phy_caps_to_max_speed(caps); } static inline int cascade_phy_dev_power_set(phy_dev_t *phy_dev, int enable) { // current phy_dev_power_set() already handle cascade return phy_dev_power_set(phy_dev, enable); } /* Get last non dynamic PHY */ static inline phy_dev_t *cascade_phy_get_last_active(phy_dev_t *phy_dev) { phy_dev_t *phy = cascade_phy_get_last(phy_dev); if (phy && (phy->flag & PHY_FLAG_DYNAMIC)) phy = phy->cascade_prev; return phy; } static inline void _phy_register_polling_timer(phy_dev_t *phy, link_change_cb_t cb, int _register) { phy_dev_t *end_phy = cascade_phy_get_last_active(phy); if (_register) phy_dev_link_change_register(end_phy, cb, end_phy); else phy_dev_link_change_unregister(end_phy); } #define phy_register_polling_timer(phy, cb) _phy_register_polling_timer(phy, cb, 1) #define phy_unregister_polling_timer(phy) _phy_register_polling_timer(phy, 0, 0) static inline int phy_drv_dev_add(phy_dev_t *phy_dev) { if (phy_dev->phy_drv->initialized) return 0; if (!phy_dev->phy_drv->dev_add) return 0; return phy_dev->phy_drv->dev_add(phy_dev); } static inline int phy_drv_dev_del(phy_dev_t *phy_dev) { if (phy_dev->phy_drv->initialized) return 0; if (!phy_dev->phy_drv->dev_del) return 0; return phy_dev->phy_drv->dev_del(phy_dev); } static inline int phy_drv_init(phy_drv_t *phy_drv) { if (phy_drv->initialized) return 0; if (!phy_drv->drv_init) return 0; return phy_drv->drv_init(phy_drv); } static inline int phy_loopback_set(phy_dev_t *phy_dev, int enable, phy_speed_t speed) { phy_drv_t *phy_drv = phy_dev->phy_drv; if(!phy_drv->loopback_set) return 0; return phy_drv->loopback_set(phy_dev, enable, speed); } static inline int phy_loopback_get(phy_dev_t *phy_dev, int *enable, phy_speed_t *speed) { phy_drv_t *phy_drv = phy_dev->phy_drv; if(!phy_drv->loopback_get) return 0; return phy_drv->loopback_get(phy_dev, enable, speed); } static inline int phy_speed_2_mbps(phy_speed_t speed) { int i; int speeds[] = {PHY_SPEED_10000, 10000, PHY_SPEED_5000, 5000, PHY_SPEED_2500, 2500, PHY_SPEED_1000, 1000, PHY_SPEED_100, 100, PHY_SPEED_10, 10}; for (i=0; iphy_drv->macsec_oper) return 0; return phy_dev->phy_drv->macsec_oper(phy_dev, data); } #endif