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>
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>
# include <linux/module.h>
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 ;
}
2013-12-06 02:52:10 +04:00
static int of_mdiobus_register_phy ( struct mii_bus * mdio , struct device_node * child ,
u32 addr )
{
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 ) ;
2013-12-06 02:52:10 +04:00
if ( ! phy | | IS_ERR ( phy ) )
return 1 ;
2014-02-18 16:16:58 +04:00
rc = irq_of_parse_and_map ( child , 0 ) ;
if ( rc > 0 ) {
phy - > irq = rc ;
if ( mdio - > irq )
mdio - > irq [ addr ] = rc ;
} else {
if ( mdio - > irq )
phy - > irq = mdio - > irq [ 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 ) ;
phy - > dev . of_node = child ;
/* 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 ) ;
return 1 ;
}
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
return 0 ;
}
2014-05-24 11:34:25 +04:00
static int of_mdio_parse_addr ( struct device * dev , const struct device_node * np )
{
u32 addr ;
int ret ;
ret = of_property_read_u32 ( np , " reg " , & addr ) ;
if ( ret < 0 ) {
dev_err ( dev , " %s has invalid PHY address \n " , np - > full_name ) ;
return ret ;
}
/* A PHY must have a reg property in the range [0-31] */
if ( addr > = PHY_MAX_ADDR ) {
dev_err ( dev , " %s PHY address %i is too large \n " ,
np - > full_name , addr ) ;
return - EINVAL ;
}
return addr ;
}
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-04-07 05:09:48 +04:00
const __be32 * paddr ;
2013-12-06 02:52:10 +04:00
bool scanphys = false ;
2014-06-02 15:32:45 +04:00
int addr , rc , i ;
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 ;
/* Clear all the IRQ properties */
if ( mdio - > irq )
for ( i = 0 ; i < PHY_MAX_ADDR ; i + + )
mdio - > irq [ i ] = PHY_POLL ;
2012-05-02 19:16:37 +04:00
mdio - > dev . of_node = np ;
2009-04-25 16:52:56 +04:00
/* Register the MDIO bus */
rc = mdiobus_register ( mdio ) ;
if ( rc )
return rc ;
/* Loop over the child nodes and register a phy_device for each one */
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 ;
}
2013-12-06 02:52:10 +04:00
rc = of_mdiobus_register_phy ( mdio , child , addr ) ;
if ( rc )
2009-04-25 16:52:56 +04:00
continue ;
}
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 */
2014-05-24 11:34:27 +04:00
paddr = of_get_property ( child , " reg " , NULL ) ;
2013-04-07 05:09:48 +04:00
if ( paddr )
continue ;
for ( addr = 0 ; addr < PHY_MAX_ADDR ; addr + + ) {
/* skip already registered PHYs */
if ( mdio - > phy_map [ addr ] )
continue ;
/* be noisy to encourage people to set reg property */
dev_info ( & mdio - > dev , " scan phy %s at address %i \n " ,
child - > name , addr ) ;
2013-12-06 02:52:10 +04:00
rc = of_mdiobus_register_phy ( mdio , child , addr ) ;
if ( rc )
2013-04-07 05:09:48 +04:00
continue ;
}
}
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
*
* Returns a pointer to the phy_device .
*/
struct phy_device * of_phy_find_device ( struct device_node * phy_np )
{
struct device * d ;
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 ) ;
2009-04-25 16:52:56 +04:00
return d ? to_phy_device ( d ) : NULL ;
}
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
* @ iface : PHY data interface type
*
2011-03-31 05:57:33 +04:00
* Returns a pointer to the phy_device if successful . NULL otherwise
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 ) ;
if ( ! phy )
return NULL ;
2014-09-20 00:07:49 +04:00
phy - > dev_flags = flags ;
2013-01-14 04:52:52 +04:00
return phy_connect_direct ( dev , phy , hndlr , iface ) ? NULL : phy ;
2009-04-25 16:52:56 +04:00
}
EXPORT_SYMBOL ( of_phy_connect ) ;
2009-07-17 01:31:31 +04:00
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
*/
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 ) ;
if ( ! phy )
return NULL ;
return phy_attach_direct ( dev , phy , flags , iface ) ? NULL : phy ;
}
EXPORT_SYMBOL ( of_phy_attach ) ;
2014-05-16 18:14:05 +04:00
# if defined(CONFIG_FIXED_PHY)
/*
* 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 ;
int len ;
/* New binding */
dn = of_get_child_by_name ( np , " fixed-link " ) ;
if ( dn ) {
of_node_put ( dn ) ;
return true ;
}
/* 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 ;
const __be32 * fixed_link_prop ;
int len ;
2014-10-06 22:38:30 +04:00
struct phy_device * phy ;
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 " ) ;
2014-05-16 18:14:05 +04:00
if ( of_property_read_u32 ( fixed_link_node , " speed " , & status . speed ) )
return - EINVAL ;
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 " ) ;
2014-05-16 18:14:05 +04:00
of_node_put ( fixed_link_node ) ;
2014-10-06 22:38:30 +04:00
phy = fixed_phy_register ( PHY_POLL , & status , np ) ;
return IS_ERR ( phy ) ? PTR_ERR ( phy ) : 0 ;
2014-05-16 18:14:05 +04:00
}
/* Old binding */
fixed_link_prop = of_get_property ( np , " fixed-link " , & len ) ;
if ( fixed_link_prop & & len = = ( 5 * sizeof ( __be32 ) ) ) {
status . link = 1 ;
status . duplex = be32_to_cpu ( fixed_link_prop [ 1 ] ) ;
status . speed = be32_to_cpu ( fixed_link_prop [ 2 ] ) ;
status . pause = be32_to_cpu ( fixed_link_prop [ 3 ] ) ;
status . asym_pause = be32_to_cpu ( fixed_link_prop [ 4 ] ) ;
2014-10-06 22:38:30 +04:00
phy = fixed_phy_register ( PHY_POLL , & status , np ) ;
return IS_ERR ( phy ) ? PTR_ERR ( phy ) : 0 ;
2014-05-16 18:14:05 +04:00
}
return - ENODEV ;
}
EXPORT_SYMBOL ( of_phy_register_fixed_link ) ;
# endif