2009-04-25 12:52:56 +00: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-16 21:31:31 +00:00
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/netdevice.h>
# include <linux/err.h>
2009-04-25 12:52:56 +00:00
# include <linux/phy.h>
2014-05-16 16:14:05 +02:00
# include <linux/phy_fixed.h>
2009-04-25 12:52:56 +00:00
# include <linux/of.h>
2015-08-31 15:56:53 +02:00
# include <linux/of_gpio.h>
2010-06-18 11:09:59 -06:00
# include <linux/of_irq.h>
2009-04-25 12:52:56 +00:00
# include <linux/of_mdio.h>
2016-07-15 16:26:34 +08:00
# include <linux/of_net.h>
2009-04-25 12:52:56 +00:00
# include <linux/module.h>
2017-04-21 16:15:38 +03:00
# define DEFAULT_GPIO_RESET_DELAY 10 /* in microseconds */
2009-04-25 12:52:56 +00:00
MODULE_AUTHOR ( " Grant Likely <grant.likely@secretlab.ca> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2014-03-19 16:15:24 -06: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 ;
}
2017-10-18 13:54:03 +02:00
static int of_mdiobus_register_phy ( struct mii_bus * mdio ,
2016-04-17 01:05:19 +03:00
struct device_node * child , u32 addr )
2013-12-05 14:52:10 -08:00
{
struct phy_device * phy ;
bool is_c45 ;
2014-02-18 12:16:58 +00:00
int rc ;
2014-03-19 16:15:24 -06:00
u32 phy_id ;
2013-12-05 14:52:10 -08:00
is_c45 = of_device_is_compatible ( child ,
" ethernet-phy-ieee802.3-c45 " ) ;
2014-03-19 16:15:24 -06: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 ) )
2017-10-18 13:54:03 +02:00
return PTR_ERR ( phy ) ;
2013-12-05 14:52:10 -08:00
2017-10-18 13:54:03 +02:00
rc = of_irq_get ( child , 0 ) ;
if ( rc = = - EPROBE_DEFER ) {
phy_device_free ( phy ) ;
return rc ;
}
2014-02-18 12:16:58 +00:00
if ( rc > 0 ) {
phy - > irq = rc ;
2016-01-12 12:35:34 +03:00
mdio - > irq [ addr ] = rc ;
2014-02-18 12:16:58 +00:00
} else {
2016-01-12 12:35:34 +03:00
phy - > irq = mdio - > irq [ addr ] ;
2013-12-05 14:52:10 -08:00
}
2015-05-12 10:33:25 -07:00
if ( of_property_read_bool ( child , " broken-turn-around " ) )
mdio - > phy_ignore_ta_mask | = 1 < < addr ;
2017-12-11 13:16:57 +01:00
of_property_read_u32 ( child , " reset-delay-us " , & phy - > mdio . reset_delay ) ;
of_property_read_u32 ( child , " reset-post-delay-us " ,
& phy - > mdio . reset_post_delay ) ;
2013-12-05 14:52:10 -08:00
/* Associate the OF node with the device structure so it
* can be looked up later */
of_node_get ( child ) ;
2016-01-06 20:11:16 +01:00
phy - > mdio . dev . of_node = child ;
2017-12-12 10:49:15 +00:00
phy - > mdio . dev . fwnode = of_fwnode_handle ( child ) ;
2013-12-05 14:52:10 -08: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 ) ;
2017-10-18 13:54:03 +02:00
return rc ;
2013-12-05 14:52:10 -08:00
}
dev_dbg ( & mdio - > dev , " registered phy %s at address %i \n " ,
2013-12-05 14:52:14 -08:00
child - > name , addr ) ;
2017-10-18 13:54:03 +02:00
return 0 ;
2013-12-05 14:52:10 -08:00
}
2017-10-18 13:54:03 +02:00
static int of_mdiobus_register_device ( struct mii_bus * mdio ,
struct device_node * child , u32 addr )
2016-01-06 20:11:26 +01: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 ) )
2017-10-18 13:54:03 +02:00
return PTR_ERR ( mdiodev ) ;
2016-01-06 20:11:26 +01: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 ;
2017-12-12 10:49:15 +00:00
mdiodev - > dev . fwnode = of_fwnode_handle ( child ) ;
2016-01-06 20:11:26 +01:00
/* 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 ) ;
2017-10-18 13:54:03 +02:00
return rc ;
2016-01-06 20:11:26 +01:00
}
dev_dbg ( & mdio - > dev , " registered mdio device %s at address %i \n " ,
child - > name , addr ) ;
2017-10-18 13:54:03 +02:00
return 0 ;
2016-01-06 20:11:26 +01:00
}
2016-01-28 02:30:29 +01: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 12:04:12 -08:00
{ . compatible = " broadcom,bcm5241 " } ,
2016-01-28 02:30:29 +01:00
{ . compatible = " marvell,88E1111 " , } ,
{ . compatible = " marvell,88e1116 " , } ,
{ . compatible = " marvell,88e1118 " , } ,
2016-02-03 21:35:29 +02:00
{ . compatible = " marvell,88e1145 " , } ,
2016-01-28 02:30:29 +01:00
{ . compatible = " marvell,88e1149r " , } ,
{ . compatible = " marvell,88e1310 " , } ,
{ . compatible = " marvell,88E1510 " , } ,
{ . compatible = " marvell,88E1514 " , } ,
{ . compatible = " moxa,moxart-rtl8201cp " , } ,
{ }
} ;
2016-01-06 20:11:17 +01: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 02:30:29 +01:00
* o In the white list above ( and issue a warning )
2016-01-06 20:11:17 +01: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 02:30:29 +01:00
if ( of_match_node ( whitelist_phys , child ) ) {
pr_warn ( FW_WARN
2017-06-01 15:50:55 -05:00
" %pOF: Whitelisted compatible string. Please remove \n " ,
child ) ;
2016-01-28 02:30:29 +01:00
return true ;
}
2016-01-06 20:11:17 +01:00
if ( ! of_find_property ( child , " compatible " , NULL ) )
return true ;
return false ;
}
2009-04-25 12:52:56 +00: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-05 14:52:10 -08:00
bool scanphys = false ;
2016-01-06 20:11:15 +01:00
int addr , rc ;
2009-04-25 12:52:56 +00:00
2016-04-28 16:24:12 -07:00
/* Do not continue if the node is disabled */
if ( ! of_device_is_available ( np ) )
return - ENODEV ;
2009-04-25 12:52:56 +00: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 15:16:37 +00:00
mdio - > dev . of_node = np ;
2017-12-12 10:49:15 +00:00
mdio - > dev . fwnode = of_fwnode_handle ( np ) ;
2012-05-02 15:16:37 +00:00
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 12:52:56 +00:00
/* Register the MDIO bus */
rc = mdiobus_register ( mdio ) ;
if ( rc )
return rc ;
2016-01-06 20:11:17 +01:00
/* Loop over the child nodes and register a phy_device for each phy */
2012-11-29 08:45:20 +01:00
for_each_available_child_of_node ( np , child ) {
2014-05-24 09:34:25 +02:00
addr = of_mdio_parse_addr ( & mdio - > dev , child ) ;
if ( addr < 0 ) {
2013-04-07 01:09:48 +00:00
scanphys = true ;
2010-10-27 18:03:47 -07:00
continue ;
}
2016-01-06 20:11:17 +01:00
if ( of_mdiobus_child_is_phy ( child ) )
2017-10-18 13:54:03 +02:00
rc = of_mdiobus_register_phy ( mdio , child , addr ) ;
2016-01-06 20:11:26 +01:00
else
2017-10-18 13:54:03 +02:00
rc = of_mdiobus_register_device ( mdio , child , addr ) ;
if ( rc )
goto unregister ;
2009-04-25 12:52:56 +00:00
}
2013-04-07 01:09:48 +00: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 01:09:48 +00:00
continue ;
for ( addr = 0 ; addr < PHY_MAX_ADDR ; addr + + ) {
/* skip already registered PHYs */
2016-01-06 20:11:18 +01:00
if ( mdiobus_is_registered_device ( mdio , addr ) )
2013-04-07 01:09:48 +00: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 ) ;
2017-10-18 13:54:03 +02:00
if ( of_mdiobus_child_is_phy ( child ) ) {
rc = of_mdiobus_register_phy ( mdio , child , addr ) ;
if ( rc )
goto unregister ;
}
2013-04-07 01:09:48 +00:00
}
}
2009-04-25 12:52:56 +00:00
return 0 ;
2017-10-18 13:54:03 +02:00
unregister :
mdiobus_unregister ( mdio ) ;
return rc ;
2009-04-25 12:52:56 +00:00
}
EXPORT_SYMBOL ( of_mdiobus_register ) ;
2009-10-15 09:58:27 -06:00
/* Helper function for of_phy_find_device */
static int of_phy_match ( struct device * dev , void * phy_np )
{
2010-04-13 16:12:29 -07:00
return dev - > of_node = = phy_np ;
2009-10-15 09:58:27 -06:00
}
2009-04-25 12:52:56 +00: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 20:36:13 +01: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 12:52:56 +00:00
*/
struct phy_device * of_phy_find_device ( struct device_node * phy_np )
{
struct device * d ;
2016-01-26 15:12:30 +01:00
struct mdio_device * mdiodev ;
2009-04-25 12:52:56 +00:00
if ( ! phy_np )
return NULL ;
2009-10-15 09:58:27 -06:00
d = bus_find_device ( & mdio_bus_type , NULL , phy_np , of_phy_match ) ;
2016-01-26 15:12:30 +01:00
if ( d ) {
mdiodev = to_mdio_device ( d ) ;
if ( mdiodev - > flags & MDIO_DEVICE_FLAG_PHY )
return to_phy_device ( d ) ;
2016-11-16 15:20:37 +01:00
put_device ( d ) ;
2016-01-26 15:12:30 +01:00
}
return NULL ;
2009-04-25 12:52:56 +00: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 12:52:56 +00:00
* @ iface : PHY data interface type
*
2015-09-24 20:36:13 +01: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 12:52:56 +00: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 20:36:13 +01:00
int ret ;
2009-04-25 12:52:56 +00:00
if ( ! phy )
return NULL ;
2014-09-19 13:07:49 -07:00
phy - > dev_flags = flags ;
2015-09-24 20:36:13 +01:00
ret = phy_connect_direct ( dev , phy , hndlr , iface ) ;
/* refcount is held by phy_connect_direct() on success */
2016-01-06 20:11:16 +01:00
put_device ( & phy - > mdio . dev ) ;
2015-09-24 20:36:13 +01:00
return ret ? NULL : phy ;
2009-04-25 12:52:56 +00:00
}
EXPORT_SYMBOL ( of_phy_connect ) ;
2009-07-16 21:31:31 +00:00
2016-07-15 16:26:34 +08: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 14:28:11 +08: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 20:36:13 +01: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 14:28:11 +08: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 20:36:13 +01:00
int ret ;
2014-01-10 14:28:11 +08:00
if ( ! phy )
return NULL ;
2015-09-24 20:36:13 +01:00
ret = phy_attach_direct ( dev , phy , flags , iface ) ;
/* refcount is held by phy_attach_direct() on success */
2016-01-06 20:11:16 +01:00
put_device ( & phy - > mdio . dev ) ;
2015-09-24 20:36:13 +01:00
return ret ? NULL : phy ;
2014-01-10 14:28:11 +08:00
}
EXPORT_SYMBOL ( of_phy_attach ) ;
2014-05-16 16:14:05 +02: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-20 17:49:57 -07:00
int len , err ;
const char * managed ;
2014-05-16 16:14:05 +02:00
/* New binding */
dn = of_get_child_by_name ( np , " fixed-link " ) ;
if ( dn ) {
of_node_put ( dn ) ;
return true ;
}
2015-07-20 17:49:57 -07:00
err = of_property_read_string ( np , " managed " , & managed ) ;
if ( err = = 0 & & strcmp ( managed , " auto " ) ! = 0 )
return true ;
2014-05-16 16:14:05 +02: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-20 17:49:57 -07:00
const char * managed ;
2017-08-13 00:03:06 +03:00
int link_gpio = - 1 ;
2015-07-20 17:49:57 -07: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-20 17:49:57 -07:00
}
2014-05-16 16:14:05 +02:00
/* New binding */
fixed_link_node = of_get_child_by_name ( np , " fixed-link " ) ;
if ( fixed_link_node ) {
status . link = 1 ;
2014-06-20 10:11:07 -04:00
status . duplex = of_property_read_bool ( fixed_link_node ,
" full-duplex " ) ;
2016-11-16 15:20:36 +01:00
if ( of_property_read_u32 ( fixed_link_node , " speed " ,
& status . speed ) ) {
of_node_put ( fixed_link_node ) ;
2014-05-16 16:14:05 +02:00
return - EINVAL ;
2016-11-16 15:20:36 +01:00
}
2014-06-20 10: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 15:56:53 +02:00
link_gpio = of_get_named_gpio_flags ( fixed_link_node ,
" link-gpios " , 0 , NULL ) ;
2014-05-16 16:14:05 +02:00
of_node_put ( fixed_link_node ) ;
2015-08-31 15:56:53 +02:00
if ( link_gpio = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
2017-08-13 00:03:06 +03:00
goto register_phy ;
2014-05-16 16:14:05 +02: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 16:14:05 +02: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 16:14:05 +02: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 16:14:05 +02:00
}
EXPORT_SYMBOL ( of_phy_register_fixed_link ) ;
2016-11-28 19:24:55 +01: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 ) ;