2009-04-25 16:52:56 +04:00
/*
* OF helpers for the MDIO ( Ethernet PHY ) API
*
* Copyright ( c ) 2009 Secret Lab Technologies , Ltd .
*
* This file is released under the GPLv2
*
* This file provides helper functions for extracting PHY device information
* out of the OpenFirmware device tree and using it to populate an mii_bus .
*/
2009-07-17 01:31:31 +04:00
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/netdevice.h>
# include <linux/err.h>
2009-04-25 16:52:56 +04:00
# include <linux/phy.h>
2014-05-16 18:14:05 +04:00
# include <linux/phy_fixed.h>
2009-04-25 16:52:56 +04:00
# include <linux/of.h>
2015-08-31 16:56:53 +03:00
# include <linux/of_gpio.h>
2010-06-18 21:09:59 +04:00
# include <linux/of_irq.h>
2009-04-25 16:52:56 +04:00
# include <linux/of_mdio.h>
2016-07-15 11:26:34 +03:00
# include <linux/of_net.h>
2009-04-25 16:52:56 +04:00
# include <linux/module.h>
2017-04-21 16:15:38 +03:00
# define DEFAULT_GPIO_RESET_DELAY 10 /* in microseconds */
2009-04-25 16:52:56 +04:00
MODULE_AUTHOR ( " Grant Likely <grant.likely@secretlab.ca> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2014-03-20 02:15:24 +04:00
/* Extract the clause 22 phy ID from the compatible string of the form
* ethernet - phy - idAAAA . BBBB */
static int of_get_phy_id ( struct device_node * device , u32 * phy_id )
{
struct property * prop ;
const char * cp ;
unsigned int upper , lower ;
of_property_for_each_string ( device , " compatible " , prop , cp ) {
if ( sscanf ( cp , " ethernet-phy-id%4x.%4x " , & upper , & lower ) = = 2 ) {
* phy_id = ( ( upper & 0xFFFF ) < < 16 ) | ( lower & 0xFFFF ) ;
return 0 ;
}
}
return - EINVAL ;
}
2016-04-17 01:05:19 +03:00
static void of_mdiobus_register_phy ( struct mii_bus * mdio ,
struct device_node * child , u32 addr )
2013-12-06 02:52:10 +04:00
{
struct phy_device * phy ;
bool is_c45 ;
2014-02-18 16:16:58 +04:00
int rc ;
2014-03-20 02:15:24 +04:00
u32 phy_id ;
2013-12-06 02:52:10 +04:00
is_c45 = of_device_is_compatible ( child ,
" ethernet-phy-ieee802.3-c45 " ) ;
2014-03-20 02:15:24 +04:00
if ( ! is_c45 & & ! of_get_phy_id ( child , & phy_id ) )
phy = phy_device_create ( mdio , addr , phy_id , 0 , NULL ) ;
else
phy = get_phy_device ( mdio , addr , is_c45 ) ;
2016-04-24 20:31:42 +03:00
if ( IS_ERR ( phy ) )
2016-04-17 01:05:19 +03:00
return ;
2013-12-06 02:52:10 +04:00
2014-02-18 16:16:58 +04:00
rc = irq_of_parse_and_map ( child , 0 ) ;
if ( rc > 0 ) {
phy - > irq = rc ;
2016-01-12 12:35:34 +03:00
mdio - > irq [ addr ] = rc ;
2014-02-18 16:16:58 +04:00
} else {
2016-01-12 12:35:34 +03:00
phy - > irq = mdio - > irq [ addr ] ;
2013-12-06 02:52:10 +04:00
}
2015-05-12 20:33:25 +03:00
if ( of_property_read_bool ( child , " broken-turn-around " ) )
mdio - > phy_ignore_ta_mask | = 1 < < addr ;
2013-12-06 02:52:10 +04:00
/* Associate the OF node with the device structure so it
* can be looked up later */
of_node_get ( child ) ;
2016-01-06 22:11:16 +03:00
phy - > mdio . dev . of_node = child ;
2013-12-06 02:52:10 +04:00
/* All data is now stored in the phy struct;
* register it */
rc = phy_device_register ( phy ) ;
if ( rc ) {
phy_device_free ( phy ) ;
of_node_put ( child ) ;
2016-04-17 01:05:19 +03:00
return ;
2013-12-06 02:52:10 +04:00
}
dev_dbg ( & mdio - > dev , " registered phy %s at address %i \n " ,
2013-12-06 02:52:14 +04:00
child - > name , addr ) ;
2013-12-06 02:52:10 +04:00
}
2016-04-17 01:05:19 +03:00
static void of_mdiobus_register_device ( struct mii_bus * mdio ,
struct device_node * child , u32 addr )
2016-01-06 22:11:26 +03:00
{
struct mdio_device * mdiodev ;
int rc ;
mdiodev = mdio_device_create ( mdio , addr ) ;
2016-03-13 00:33:13 +03:00
if ( IS_ERR ( mdiodev ) )
2016-04-17 01:05:19 +03:00
return ;
2016-01-06 22:11:26 +03:00
/* Associate the OF node with the device structure so it
* can be looked up later .
*/
of_node_get ( child ) ;
mdiodev - > dev . of_node = child ;
/* All data is now stored in the mdiodev struct; register it. */
rc = mdio_device_register ( mdiodev ) ;
if ( rc ) {
mdio_device_free ( mdiodev ) ;
of_node_put ( child ) ;
2016-04-17 01:05:19 +03:00
return ;
2016-01-06 22:11:26 +03:00
}
dev_dbg ( & mdio - > dev , " registered mdio device %s at address %i \n " ,
child - > name , addr ) ;
}
2016-01-28 04:30:29 +03:00
/* The following is a list of PHY compatible strings which appear in
* some DTBs . The compatible string is never matched against a PHY
* driver , so is pointless . We only expect devices which are not PHYs
* to have a compatible string , so they can be matched to an MDIO
* driver . Encourage users to upgrade their DT blobs to remove these .
*/
static const struct of_device_id whitelist_phys [ ] = {
{ . compatible = " brcm,40nm-ephy " } ,
2017-02-17 23:04:12 +03:00
{ . compatible = " broadcom,bcm5241 " } ,
2016-01-28 04:30:29 +03:00
{ . compatible = " marvell,88E1111 " , } ,
{ . compatible = " marvell,88e1116 " , } ,
{ . compatible = " marvell,88e1118 " , } ,
2016-02-03 22:35:29 +03:00
{ . compatible = " marvell,88e1145 " , } ,
2016-01-28 04:30:29 +03:00
{ . compatible = " marvell,88e1149r " , } ,
{ . compatible = " marvell,88e1310 " , } ,
{ . compatible = " marvell,88E1510 " , } ,
{ . compatible = " marvell,88E1514 " , } ,
{ . compatible = " moxa,moxart-rtl8201cp " , } ,
{ }
} ;
2016-01-06 22:11:17 +03:00
/*
* Return true if the child node is for a phy . It must either :
* o Compatible string of " ethernet-phy-idX.X "
* o Compatible string of " ethernet-phy-ieee802.3-c45 "
* o Compatible string of " ethernet-phy-ieee802.3-c22 "
2016-01-28 04:30:29 +03:00
* o In the white list above ( and issue a warning )
2016-01-06 22:11:17 +03:00
* o No compatibility string
*
* A device which is not a phy is expected to have a compatible string
* indicating what sort of device it is .
*/
static bool of_mdiobus_child_is_phy ( struct device_node * child )
{
u32 phy_id ;
if ( of_get_phy_id ( child , & phy_id ) ! = - EINVAL )
return true ;
if ( of_device_is_compatible ( child , " ethernet-phy-ieee802.3-c45 " ) )
return true ;
if ( of_device_is_compatible ( child , " ethernet-phy-ieee802.3-c22 " ) )
return true ;
2016-01-28 04:30:29 +03:00
if ( of_match_node ( whitelist_phys , child ) ) {
pr_warn ( FW_WARN
2017-06-01 23:50:55 +03:00
" %pOF: Whitelisted compatible string. Please remove \n " ,
child ) ;
2016-01-28 04:30:29 +03:00
return true ;
}
2016-01-06 22:11:17 +03:00
if ( ! of_find_property ( child , " compatible " , NULL ) )
return true ;
return false ;
}
2009-04-25 16:52:56 +04:00
/**
* of_mdiobus_register - Register mii_bus and create PHYs from the device tree
* @ mdio : pointer to mii_bus structure
* @ np : pointer to device_node of MDIO bus .
*
* This function registers the mii_bus structure and registers a phy_device
* for each child node of @ np .
*/
int of_mdiobus_register ( struct mii_bus * mdio , struct device_node * np )
{
struct device_node * child ;
2013-12-06 02:52:10 +04:00
bool scanphys = false ;
2016-01-06 22:11:15 +03:00
int addr , rc ;
2009-04-25 16:52:56 +04:00
2016-04-29 02:24:12 +03:00
/* Do not continue if the node is disabled */
if ( ! of_device_is_available ( np ) )
return - ENODEV ;
2009-04-25 16:52:56 +04:00
/* Mask out all PHYs from auto probing. Instead the PHYs listed in
* the device tree are populated after the bus has been registered */
mdio - > phy_mask = ~ 0 ;
2012-05-02 19:16:37 +04:00
mdio - > dev . of_node = np ;
2017-04-21 16:15:38 +03:00
/* Get bus level PHY reset GPIO details */
mdio - > reset_delay_us = DEFAULT_GPIO_RESET_DELAY ;
of_property_read_u32 ( np , " reset-delay-us " , & mdio - > reset_delay_us ) ;
2009-04-25 16:52:56 +04:00
/* Register the MDIO bus */
rc = mdiobus_register ( mdio ) ;
if ( rc )
return rc ;
2016-01-06 22:11:17 +03:00
/* Loop over the child nodes and register a phy_device for each phy */
2012-11-29 11:45:20 +04:00
for_each_available_child_of_node ( np , child ) {
2014-05-24 11:34:25 +04:00
addr = of_mdio_parse_addr ( & mdio - > dev , child ) ;
if ( addr < 0 ) {
2013-04-07 05:09:48 +04:00
scanphys = true ;
2010-10-28 05:03:47 +04:00
continue ;
}
2016-01-06 22:11:17 +03:00
if ( of_mdiobus_child_is_phy ( child ) )
of_mdiobus_register_phy ( mdio , child , addr ) ;
2016-01-06 22:11:26 +03:00
else
of_mdiobus_register_device ( mdio , child , addr ) ;
2009-04-25 16:52:56 +04:00
}
2013-04-07 05:09:48 +04:00
if ( ! scanphys )
return 0 ;
/* auto scan for PHYs with empty reg property */
for_each_available_child_of_node ( np , child ) {
/* Skip PHYs with reg property set */
2016-02-28 21:56:34 +03:00
if ( of_find_property ( child , " reg " , NULL ) )
2013-04-07 05:09:48 +04:00
continue ;
for ( addr = 0 ; addr < PHY_MAX_ADDR ; addr + + ) {
/* skip already registered PHYs */
2016-01-06 22:11:18 +03:00
if ( mdiobus_is_registered_device ( mdio , addr ) )
2013-04-07 05:09:48 +04:00
continue ;
/* be noisy to encourage people to set reg property */
dev_info ( & mdio - > dev , " scan phy %s at address %i \n " ,
child - > name , addr ) ;
2016-01-06 22:11:17 +03:00
if ( of_mdiobus_child_is_phy ( child ) )
of_mdiobus_register_phy ( mdio , child , addr ) ;
2013-04-07 05:09:48 +04:00
}
}
2009-04-25 16:52:56 +04:00
return 0 ;
}
EXPORT_SYMBOL ( of_mdiobus_register ) ;
2009-10-15 19:58:27 +04:00
/* Helper function for of_phy_find_device */
static int of_phy_match ( struct device * dev , void * phy_np )
{
2010-04-14 03:12:29 +04:00
return dev - > of_node = = phy_np ;
2009-10-15 19:58:27 +04:00
}
2009-04-25 16:52:56 +04:00
/**
* of_phy_find_device - Give a PHY node , find the phy_device
* @ phy_np : Pointer to the phy ' s device tree node
*
2015-09-24 22:36:13 +03:00
* If successful , returns a pointer to the phy_device with the embedded
* struct device refcount incremented by one , or NULL on failure .
2009-04-25 16:52:56 +04:00
*/
struct phy_device * of_phy_find_device ( struct device_node * phy_np )
{
struct device * d ;
2016-01-26 17:12:30 +03:00
struct mdio_device * mdiodev ;
2009-04-25 16:52:56 +04:00
if ( ! phy_np )
return NULL ;
2009-10-15 19:58:27 +04:00
d = bus_find_device ( & mdio_bus_type , NULL , phy_np , of_phy_match ) ;
2016-01-26 17:12:30 +03:00
if ( d ) {
mdiodev = to_mdio_device ( d ) ;
if ( mdiodev - > flags & MDIO_DEVICE_FLAG_PHY )
return to_phy_device ( d ) ;
2016-11-16 17:20:37 +03:00
put_device ( d ) ;
2016-01-26 17:12:30 +03:00
}
return NULL ;
2009-04-25 16:52:56 +04:00
}
EXPORT_SYMBOL ( of_phy_find_device ) ;
/**
* of_phy_connect - Connect to the phy described in the device tree
* @ dev : pointer to net_device claiming the phy
* @ phy_np : Pointer to device tree node for the PHY
* @ hndlr : Link state callback for the network device
2016-02-28 22:50:59 +03:00
* @ flags : flags to pass to the PHY
2009-04-25 16:52:56 +04:00
* @ iface : PHY data interface type
*
2015-09-24 22:36:13 +03:00
* If successful , returns a pointer to the phy_device with the embedded
* struct device refcount incremented by one , or NULL on failure . The
* refcount must be dropped by calling phy_disconnect ( ) or phy_detach ( ) .
2009-04-25 16:52:56 +04:00
*/
struct phy_device * of_phy_connect ( struct net_device * dev ,
struct device_node * phy_np ,
void ( * hndlr ) ( struct net_device * ) , u32 flags ,
phy_interface_t iface )
{
struct phy_device * phy = of_phy_find_device ( phy_np ) ;
2015-09-24 22:36:13 +03:00
int ret ;
2009-04-25 16:52:56 +04:00
if ( ! phy )
return NULL ;
2014-09-20 00:07:49 +04:00
phy - > dev_flags = flags ;
2015-09-24 22:36:13 +03:00
ret = phy_connect_direct ( dev , phy , hndlr , iface ) ;
/* refcount is held by phy_connect_direct() on success */
2016-01-06 22:11:16 +03:00
put_device ( & phy - > mdio . dev ) ;
2015-09-24 22:36:13 +03:00
return ret ? NULL : phy ;
2009-04-25 16:52:56 +04:00
}
EXPORT_SYMBOL ( of_phy_connect ) ;
2009-07-17 01:31:31 +04:00
2016-07-15 11:26:34 +03:00
/**
* of_phy_get_and_connect
* - Get phy node and connect to the phy described in the device tree
* @ dev : pointer to net_device claiming the phy
* @ np : Pointer to device tree node for the net_device claiming the phy
* @ hndlr : Link state callback for the network device
*
* If successful , returns a pointer to the phy_device with the embedded
* struct device refcount incremented by one , or NULL on failure . The
* refcount must be dropped by calling phy_disconnect ( ) or phy_detach ( ) .
*/
struct phy_device * of_phy_get_and_connect ( struct net_device * dev ,
struct device_node * np ,
void ( * hndlr ) ( struct net_device * ) )
{
phy_interface_t iface ;
struct device_node * phy_np ;
struct phy_device * phy ;
iface = of_get_phy_mode ( np ) ;
if ( iface < 0 )
return NULL ;
phy_np = of_parse_phandle ( np , " phy-handle " , 0 ) ;
if ( ! phy_np )
return NULL ;
phy = of_phy_connect ( dev , phy_np , hndlr , 0 , iface ) ;
of_node_put ( phy_np ) ;
return phy ;
}
EXPORT_SYMBOL ( of_phy_get_and_connect ) ;
2014-01-10 10:28:11 +04:00
/**
* of_phy_attach - Attach to a PHY without starting the state machine
* @ dev : pointer to net_device claiming the phy
* @ phy_np : Node pointer for the PHY
* @ flags : flags to pass to the PHY
* @ iface : PHY data interface type
2015-09-24 22:36:13 +03:00
*
* If successful , returns a pointer to the phy_device with the embedded
* struct device refcount incremented by one , or NULL on failure . The
* refcount must be dropped by calling phy_disconnect ( ) or phy_detach ( ) .
2014-01-10 10:28:11 +04:00
*/
struct phy_device * of_phy_attach ( struct net_device * dev ,
struct device_node * phy_np , u32 flags ,
phy_interface_t iface )
{
struct phy_device * phy = of_phy_find_device ( phy_np ) ;
2015-09-24 22:36:13 +03:00
int ret ;
2014-01-10 10:28:11 +04:00
if ( ! phy )
return NULL ;
2015-09-24 22:36:13 +03:00
ret = phy_attach_direct ( dev , phy , flags , iface ) ;
/* refcount is held by phy_attach_direct() on success */
2016-01-06 22:11:16 +03:00
put_device ( & phy - > mdio . dev ) ;
2015-09-24 22:36:13 +03:00
return ret ? NULL : phy ;
2014-01-10 10:28:11 +04:00
}
EXPORT_SYMBOL ( of_phy_attach ) ;
2014-05-16 18:14:05 +04:00
/*
* of_phy_is_fixed_link ( ) and of_phy_register_fixed_link ( ) must
* support two DT bindings :
* - the old DT binding , where ' fixed - link ' was a property with 5
* cells encoding various informations about the fixed PHY
* - the new DT binding , where ' fixed - link ' is a sub - node of the
* Ethernet device .
*/
bool of_phy_is_fixed_link ( struct device_node * np )
{
struct device_node * dn ;
2015-07-21 03:49:57 +03:00
int len , err ;
const char * managed ;
2014-05-16 18:14:05 +04:00
/* New binding */
dn = of_get_child_by_name ( np , " fixed-link " ) ;
if ( dn ) {
of_node_put ( dn ) ;
return true ;
}
2015-07-21 03:49:57 +03:00
err = of_property_read_string ( np , " managed " , & managed ) ;
if ( err = = 0 & & strcmp ( managed , " auto " ) ! = 0 )
return true ;
2014-05-16 18:14:05 +04:00
/* Old binding */
if ( of_get_property ( np , " fixed-link " , & len ) & &
len = = ( 5 * sizeof ( __be32 ) ) )
return true ;
return false ;
}
EXPORT_SYMBOL ( of_phy_is_fixed_link ) ;
int of_phy_register_fixed_link ( struct device_node * np )
{
struct fixed_phy_status status = { } ;
struct device_node * fixed_link_node ;
2017-08-05 00:43:43 +03:00
u32 fixed_link_prop [ 5 ] ;
2015-07-21 03:49:57 +03:00
const char * managed ;
2017-08-13 00:03:06 +03:00
int link_gpio = - 1 ;
2015-07-21 03:49:57 +03:00
2017-08-13 00:03:06 +03:00
if ( of_property_read_string ( np , " managed " , & managed ) = = 0 & &
strcmp ( managed , " in-band-status " ) = = 0 ) {
/* status is zeroed, namely its .link member */
goto register_phy ;
2015-07-21 03:49:57 +03:00
}
2014-05-16 18:14:05 +04:00
/* New binding */
fixed_link_node = of_get_child_by_name ( np , " fixed-link " ) ;
if ( fixed_link_node ) {
status . link = 1 ;
2014-06-20 18:11:07 +04:00
status . duplex = of_property_read_bool ( fixed_link_node ,
" full-duplex " ) ;
2016-11-16 17:20:36 +03:00
if ( of_property_read_u32 ( fixed_link_node , " speed " ,
& status . speed ) ) {
of_node_put ( fixed_link_node ) ;
2014-05-16 18:14:05 +04:00
return - EINVAL ;
2016-11-16 17:20:36 +03:00
}
2014-06-20 18:11:07 +04:00
status . pause = of_property_read_bool ( fixed_link_node , " pause " ) ;
status . asym_pause = of_property_read_bool ( fixed_link_node ,
" asym-pause " ) ;
2015-08-31 16:56:53 +03:00
link_gpio = of_get_named_gpio_flags ( fixed_link_node ,
" link-gpios " , 0 , NULL ) ;
2014-05-16 18:14:05 +04:00
of_node_put ( fixed_link_node ) ;
2015-08-31 16:56:53 +03:00
if ( link_gpio = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
2017-08-13 00:03:06 +03:00
goto register_phy ;
2014-05-16 18:14:05 +04:00
}
/* Old binding */
2017-08-05 00:43:43 +03:00
if ( of_property_read_u32_array ( np , " fixed-link " , fixed_link_prop ,
ARRAY_SIZE ( fixed_link_prop ) ) = = 0 ) {
2014-05-16 18:14:05 +04:00
status . link = 1 ;
2017-08-05 00:43:43 +03:00
status . duplex = fixed_link_prop [ 1 ] ;
status . speed = fixed_link_prop [ 2 ] ;
status . pause = fixed_link_prop [ 3 ] ;
status . asym_pause = fixed_link_prop [ 4 ] ;
2017-08-13 00:03:06 +03:00
goto register_phy ;
2014-05-16 18:14:05 +04:00
}
return - ENODEV ;
2017-08-13 00:03:06 +03:00
register_phy :
return PTR_ERR_OR_ZERO ( fixed_phy_register ( PHY_POLL , & status , link_gpio ,
np ) ) ;
2014-05-16 18:14:05 +04:00
}
EXPORT_SYMBOL ( of_phy_register_fixed_link ) ;
2016-11-28 21:24:55 +03:00
void of_phy_deregister_fixed_link ( struct device_node * np )
{
struct phy_device * phydev ;
phydev = of_phy_find_device ( np ) ;
if ( ! phydev )
return ;
fixed_phy_unregister ( phydev ) ;
put_device ( & phydev - > mdio . dev ) ; /* of_phy_find_device() */
phy_device_free ( phydev ) ; /* fixed_phy_register() */
}
EXPORT_SYMBOL ( of_phy_deregister_fixed_link ) ;