2009-10-15 02:13:45 +04:00
/*******************************************************************************
STMMAC Ethernet Driver - - MDIO bus implementation
Provides Bus interface for MII registers
Copyright ( C ) 2007 - 2009 STMicroelectronics Ltd
This program is free software ; you can redistribute it and / or modify it
under the terms and conditions of the GNU General Public License ,
version 2 , as published by the Free Software Foundation .
This program is distributed in the hope 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 .
The full GNU General Public License is included in this distribution in
the file called " COPYING " .
Author : Carl Shaw < carl . shaw @ st . com >
Maintainer : Giuseppe Cavallaro < peppe . cavallaro @ st . com >
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-08 11:31:10 +03:00
# include <linux/io.h>
2017-02-08 11:31:12 +03:00
# include <linux/iopoll.h>
2009-10-15 02:13:45 +04:00
# include <linux/mii.h>
2013-07-04 13:35:48 +04:00
# include <linux/of.h>
# include <linux/of_gpio.h>
2015-12-14 06:31:59 +03:00
# include <linux/of_mdio.h>
2017-02-08 11:31:10 +03:00
# include <linux/phy.h>
# include <linux/slab.h>
2009-10-15 02:13:45 +04:00
# include "stmmac.h"
# define MII_BUSY 0x00000001
# define MII_WRITE 0x00000002
2016-04-28 16:56:45 +03:00
/* GMAC4 defines */
# define MII_GMAC4_GOC_SHIFT 2
# define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT)
# define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
2009-10-15 02:13:45 +04:00
/**
* stmmac_mdio_read
* @ bus : points to the mii_bus structure
2016-12-01 18:19:41 +03:00
* @ phyaddr : MII addr
* @ phyreg : MII reg
2009-10-15 02:13:45 +04:00
* Description : it reads data from the MII register from within the phy device .
* For the 7111 GMAC , we must set the bit 0 in the MII address register while
* accessing the PHY registers .
* Fortunately , it seems this has no drawback for the 7109 MAC .
*/
static int stmmac_mdio_read ( struct mii_bus * bus , int phyaddr , int phyreg )
{
struct net_device * ndev = bus - > priv ;
struct stmmac_priv * priv = netdev_priv ( ndev ) ;
2010-01-07 02:07:17 +03:00
unsigned int mii_address = priv - > hw - > mii . addr ;
unsigned int mii_data = priv - > hw - > mii . data ;
2017-02-08 11:31:12 +03:00
u32 v ;
2009-10-15 02:13:45 +04:00
int data ;
2016-12-01 18:19:41 +03:00
u32 value = MII_BUSY ;
value | = ( phyaddr < < priv - > hw - > mii . addr_shift )
& priv - > hw - > mii . addr_mask ;
value | = ( phyreg < < priv - > hw - > mii . reg_shift ) & priv - > hw - > mii . reg_mask ;
2016-12-23 13:15:59 +03:00
value | = ( priv - > clk_csr < < priv - > hw - > mii . clk_csr_shift )
& priv - > hw - > mii . clk_csr_mask ;
2016-12-01 18:19:41 +03:00
if ( priv - > plat - > has_gmac4 )
value | = MII_GMAC4_READ ;
2009-10-15 02:13:45 +04:00
2017-02-08 11:31:12 +03:00
if ( readl_poll_timeout ( priv - > ioaddr + mii_address , v , ! ( v & MII_BUSY ) ,
100 , 10000 ) )
2012-04-04 08:33:24 +04:00
return - EBUSY ;
2016-12-01 18:19:40 +03:00
writel ( value , priv - > ioaddr + mii_address ) ;
2012-04-04 08:33:24 +04:00
2017-02-08 11:31:12 +03:00
if ( readl_poll_timeout ( priv - > ioaddr + mii_address , v , ! ( v & MII_BUSY ) ,
100 , 10000 ) )
2012-04-04 08:33:24 +04:00
return - EBUSY ;
2009-10-15 02:13:45 +04:00
/* Read the data from the MII data register */
2010-08-24 00:40:42 +04:00
data = ( int ) readl ( priv - > ioaddr + mii_data ) ;
2009-10-15 02:13:45 +04:00
return data ;
}
/**
* stmmac_mdio_write
* @ bus : points to the mii_bus structure
2016-12-01 18:19:41 +03:00
* @ phyaddr : MII addr
* @ phyreg : MII reg
2009-10-15 02:13:45 +04:00
* @ phydata : phy data
* Description : it writes the data into the MII register from within the device .
*/
static int stmmac_mdio_write ( struct mii_bus * bus , int phyaddr , int phyreg ,
u16 phydata )
{
struct net_device * ndev = bus - > priv ;
struct stmmac_priv * priv = netdev_priv ( ndev ) ;
2010-01-07 02:07:17 +03:00
unsigned int mii_address = priv - > hw - > mii . addr ;
unsigned int mii_data = priv - > hw - > mii . data ;
2017-02-08 11:31:12 +03:00
u32 v ;
2016-12-27 23:07:41 +03:00
u32 value = MII_BUSY ;
2009-10-15 02:13:45 +04:00
2016-12-01 18:19:41 +03:00
value | = ( phyaddr < < priv - > hw - > mii . addr_shift )
& priv - > hw - > mii . addr_mask ;
value | = ( phyreg < < priv - > hw - > mii . reg_shift ) & priv - > hw - > mii . reg_mask ;
2010-09-17 07:23:39 +04:00
2016-12-23 13:15:59 +03:00
value | = ( priv - > clk_csr < < priv - > hw - > mii . clk_csr_shift )
& priv - > hw - > mii . clk_csr_mask ;
2016-12-01 18:19:41 +03:00
if ( priv - > plat - > has_gmac4 )
value | = MII_GMAC4_WRITE ;
2016-12-27 23:07:41 +03:00
else
value | = MII_WRITE ;
2016-04-28 16:56:45 +03:00
/* Wait until any existing MII operation is complete */
2017-02-08 11:31:12 +03:00
if ( readl_poll_timeout ( priv - > ioaddr + mii_address , v , ! ( v & MII_BUSY ) ,
100 , 10000 ) )
2016-04-28 16:56:45 +03:00
return - EBUSY ;
/* Set the MII address register to write */
writel ( phydata , priv - > ioaddr + mii_data ) ;
writel ( value , priv - > ioaddr + mii_address ) ;
/* Wait until any existing MII operation is complete */
2017-02-08 11:31:12 +03:00
return readl_poll_timeout ( priv - > ioaddr + mii_address , v , ! ( v & MII_BUSY ) ,
100 , 10000 ) ;
2016-04-28 16:56:45 +03:00
}
2009-10-15 02:13:45 +04:00
/**
* stmmac_mdio_reset
* @ bus : points to the mii_bus structure
* Description : reset the MII bus
*/
2014-01-16 14:52:27 +04:00
int stmmac_mdio_reset ( struct mii_bus * bus )
2009-10-15 02:13:45 +04:00
{
2011-12-21 07:58:19 +04:00
# if defined(CONFIG_STMMAC_PLATFORM)
2009-10-15 02:13:45 +04:00
struct net_device * ndev = bus - > priv ;
struct stmmac_priv * priv = netdev_priv ( ndev ) ;
2010-01-07 02:07:17 +03:00
unsigned int mii_address = priv - > hw - > mii . addr ;
2013-07-04 13:35:48 +04:00
struct stmmac_mdio_bus_data * data = priv - > plat - > mdio_bus_data ;
# ifdef CONFIG_OF
if ( priv - > device - > of_node ) {
if ( data - > reset_gpio < 0 ) {
struct device_node * np = priv - > device - > of_node ;
2017-02-08 11:31:11 +03:00
2013-07-04 13:35:48 +04:00
if ( ! np )
return 0 ;
data - > reset_gpio = of_get_named_gpio ( np ,
" snps,reset-gpio " , 0 ) ;
if ( data - > reset_gpio < 0 )
return 0 ;
data - > active_low = of_property_read_bool ( np ,
" snps,reset-active-low " ) ;
of_property_read_u32_array ( np ,
" snps,reset-delays-us " , data - > delays , 3 ) ;
2015-11-26 10:35:44 +03:00
if ( gpio_request ( data - > reset_gpio , " mdio-reset " ) )
return 0 ;
}
2013-07-04 13:35:48 +04:00
2015-11-26 10:35:44 +03:00
gpio_direction_output ( data - > reset_gpio ,
data - > active_low ? 1 : 0 ) ;
if ( data - > delays [ 0 ] )
msleep ( DIV_ROUND_UP ( data - > delays [ 0 ] , 1000 ) ) ;
2015-09-11 23:25:48 +03:00
2015-11-26 10:35:44 +03:00
gpio_set_value ( data - > reset_gpio , data - > active_low ? 0 : 1 ) ;
if ( data - > delays [ 1 ] )
msleep ( DIV_ROUND_UP ( data - > delays [ 1 ] , 1000 ) ) ;
2015-09-11 23:25:48 +03:00
2015-11-26 10:35:44 +03:00
gpio_set_value ( data - > reset_gpio , data - > active_low ? 1 : 0 ) ;
if ( data - > delays [ 2 ] )
msleep ( DIV_ROUND_UP ( data - > delays [ 2 ] , 1000 ) ) ;
2013-07-04 13:35:48 +04:00
}
# endif
2009-10-15 02:13:45 +04:00
2013-07-04 13:35:48 +04:00
if ( data - > phy_reset ) {
2016-11-16 22:09:39 +03:00
netdev_dbg ( ndev , " stmmac_mdio_reset: calling phy_reset \n " ) ;
2013-07-04 13:35:48 +04:00
data - > phy_reset ( priv - > plat - > bsp_priv ) ;
2009-10-15 02:13:45 +04:00
}
/* This is a workaround for problems with the STE101P PHY.
* It doesn ' t complete its reset until at least one clock cycle
2017-02-08 11:31:08 +03:00
* on MDC , so perform a dummy mdio read . To be updated for GMAC4
2016-04-28 16:56:45 +03:00
* if needed .
2009-10-15 02:13:45 +04:00
*/
2016-04-28 16:56:45 +03:00
if ( ! priv - > plat - > has_gmac4 )
writel ( 0 , priv - > ioaddr + mii_address ) ;
2011-12-21 07:58:19 +04:00
# endif
2009-10-15 02:13:45 +04:00
return 0 ;
}
/**
* stmmac_mdio_register
* @ ndev : net device structure
* Description : it registers the MII bus
*/
int stmmac_mdio_register ( struct net_device * ndev )
{
int err = 0 ;
struct mii_bus * new_bus ;
struct stmmac_priv * priv = netdev_priv ( ndev ) ;
2011-07-20 04:05:23 +04:00
struct stmmac_mdio_bus_data * mdio_bus_data = priv - > plat - > mdio_bus_data ;
2016-04-01 10:07:16 +03:00
struct device_node * mdio_node = priv - > plat - > mdio_node ;
2017-08-10 17:56:05 +03:00
struct device * dev = ndev - > dev . parent ;
2009-10-15 02:13:45 +04:00
int addr , found ;
2011-07-20 04:05:23 +04:00
if ( ! mdio_bus_data )
return 0 ;
2009-10-15 02:13:45 +04:00
new_bus = mdiobus_alloc ( ) ;
2017-02-08 11:31:11 +03:00
if ( ! new_bus )
2009-10-15 02:13:45 +04:00
return - ENOMEM ;
2016-01-06 22:11:15 +03:00
if ( mdio_bus_data - > irqs )
2016-05-26 01:40:23 +03:00
memcpy ( new_bus - > irq , mdio_bus_data - > irqs , sizeof ( new_bus - > irq ) ) ;
2009-10-15 02:13:45 +04:00
2013-07-04 13:35:48 +04:00
# ifdef CONFIG_OF
if ( priv - > device - > of_node )
mdio_bus_data - > reset_gpio = - 1 ;
# endif
2012-01-24 03:26:48 +04:00
new_bus - > name = " stmmac " ;
2016-12-01 18:19:41 +03:00
new_bus - > read = & stmmac_mdio_read ;
new_bus - > write = & stmmac_mdio_write ;
2016-04-28 16:56:45 +03:00
2009-10-15 02:13:45 +04:00
new_bus - > reset = & stmmac_mdio_reset ;
2012-01-10 03:59:20 +04:00
snprintf ( new_bus - > id , MII_BUS_ID_SIZE , " %s-%x " ,
2013-04-08 06:10:01 +04:00
new_bus - > name , priv - > plat - > bus_id ) ;
2009-10-15 02:13:45 +04:00
new_bus - > priv = ndev ;
2011-07-20 04:05:23 +04:00
new_bus - > phy_mask = mdio_bus_data - > phy_mask ;
2009-10-15 02:13:45 +04:00
new_bus - > parent = priv - > device ;
2015-12-14 06:31:59 +03:00
2016-01-07 23:13:28 +03:00
if ( mdio_node )
err = of_mdiobus_register ( new_bus , mdio_node ) ;
else
err = mdiobus_register ( new_bus ) ;
2009-10-15 02:13:45 +04:00
if ( err ! = 0 ) {
2017-08-10 17:56:05 +03:00
dev_err ( dev , " Cannot register the MDIO bus \n " ) ;
2009-10-15 02:13:45 +04:00
goto bus_register_fail ;
}
2016-03-15 10:34:33 +03:00
if ( priv - > plat - > phy_node | | mdio_node )
goto bus_register_done ;
2009-10-15 02:13:45 +04:00
found = 0 ;
2011-07-20 04:05:23 +04:00
for ( addr = 0 ; addr < PHY_MAX_ADDR ; addr + + ) {
2016-01-06 22:11:18 +03:00
struct phy_device * phydev = mdiobus_get_phy ( new_bus , addr ) ;
2017-02-15 12:46:44 +03:00
int act = 0 ;
char irq_num [ 4 ] ;
char * irq_str ;
if ( ! phydev )
continue ;
/*
* If an IRQ was provided to be assigned after
* the bus probe , do it here .
*/
if ( ! mdio_bus_data - > irqs & &
( mdio_bus_data - > probed_phy_irq > 0 ) ) {
new_bus - > irq [ addr ] = mdio_bus_data - > probed_phy_irq ;
phydev - > irq = mdio_bus_data - > probed_phy_irq ;
}
2017-02-08 11:31:11 +03:00
2017-02-15 12:46:44 +03:00
/*
* If we ' re going to bind the MAC to this PHY bus ,
* and no PHY number was provided to the MAC ,
* use the one probed here .
*/
if ( priv - > plat - > phy_addr = = - 1 )
priv - > plat - > phy_addr = addr ;
act = ( priv - > plat - > phy_addr = = addr ) ;
switch ( phydev - > irq ) {
case PHY_POLL :
irq_str = " POLL " ;
break ;
case PHY_IGNORE_INTERRUPT :
irq_str = " IGNORE " ;
break ;
default :
sprintf ( irq_num , " %d " , phydev - > irq ) ;
irq_str = irq_num ;
break ;
2009-10-15 02:13:45 +04:00
}
2017-08-10 17:56:05 +03:00
phy_attached_info ( phydev ) ;
2017-02-15 12:46:44 +03:00
found = 1 ;
2009-10-15 02:13:45 +04:00
}
2015-12-14 06:31:59 +03:00
if ( ! found & & ! mdio_node ) {
2017-08-10 17:56:05 +03:00
dev_warn ( dev , " No PHY found \n " ) ;
2013-02-07 00:47:52 +04:00
mdiobus_unregister ( new_bus ) ;
mdiobus_free ( new_bus ) ;
return - ENODEV ;
}
2016-03-15 10:34:33 +03:00
bus_register_done :
2013-02-07 00:47:52 +04:00
priv - > mii = new_bus ;
2009-10-15 02:13:45 +04:00
return 0 ;
2011-07-20 04:05:23 +04:00
2009-10-15 02:13:45 +04:00
bus_register_fail :
2011-07-20 04:05:23 +04:00
mdiobus_free ( new_bus ) ;
2009-10-15 02:13:45 +04:00
return err ;
}
/**
* stmmac_mdio_unregister
* @ ndev : net device structure
* Description : it unregisters the MII bus
*/
int stmmac_mdio_unregister ( struct net_device * ndev )
{
struct stmmac_priv * priv = netdev_priv ( ndev ) ;
2012-08-30 09:49:58 +04:00
if ( ! priv - > mii )
return 0 ;
2009-10-15 02:13:45 +04:00
mdiobus_unregister ( priv - > mii ) ;
priv - > mii - > priv = NULL ;
2011-07-20 04:05:23 +04:00
mdiobus_free ( priv - > mii ) ;
priv - > mii = NULL ;
2009-10-15 02:13:45 +04:00
return 0 ;
}