2021-05-19 11:31:59 +08:00
// SPDX-License-Identifier: GPL-2.0+
# include <linux/bitfield.h>
# include <linux/module.h>
# include <linux/phy.h>
# define MTK_EXT_PAGE_ACCESS 0x1f
# define MTK_PHY_PAGE_STANDARD 0x0000
# define MTK_PHY_PAGE_EXTENDED 0x0001
# define MTK_PHY_PAGE_EXTENDED_2 0x0002
# define MTK_PHY_PAGE_EXTENDED_3 0x0003
# define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
# define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
static int mtk_gephy_read_page ( struct phy_device * phydev )
{
return __phy_read ( phydev , MTK_EXT_PAGE_ACCESS ) ;
}
static int mtk_gephy_write_page ( struct phy_device * phydev , int page )
{
return __phy_write ( phydev , MTK_EXT_PAGE_ACCESS , page ) ;
}
static void mtk_gephy_config_init ( struct phy_device * phydev )
{
/* Disable EEE */
phy_write_mmd ( phydev , MDIO_MMD_AN , MDIO_AN_EEE_ADV , 0 ) ;
/* Enable HW auto downshift */
phy_modify_paged ( phydev , MTK_PHY_PAGE_EXTENDED , 0x14 , 0 , BIT ( 4 ) ) ;
/* Increase SlvDPSready time */
phy_select_page ( phydev , MTK_PHY_PAGE_EXTENDED_52B5 ) ;
__phy_write ( phydev , 0x10 , 0xafae ) ;
__phy_write ( phydev , 0x12 , 0x2f ) ;
__phy_write ( phydev , 0x10 , 0x8fae ) ;
phy_restore_page ( phydev , MTK_PHY_PAGE_STANDARD , 0 ) ;
/* Adjust 100_mse_threshold */
phy_write_mmd ( phydev , MDIO_MMD_VEND1 , 0x123 , 0xffff ) ;
/* Disable mcc */
phy_write_mmd ( phydev , MDIO_MMD_VEND1 , 0xa6 , 0x300 ) ;
}
static int mt7530_phy_config_init ( struct phy_device * phydev )
{
mtk_gephy_config_init ( phydev ) ;
/* Increase post_update_timer */
phy_write_paged ( phydev , MTK_PHY_PAGE_EXTENDED_3 , 0x11 , 0x4b ) ;
return 0 ;
}
static int mt7531_phy_config_init ( struct phy_device * phydev )
{
mtk_gephy_config_init ( phydev ) ;
/* PHY link down power saving enable */
phy_set_bits ( phydev , 0x17 , BIT ( 4 ) ) ;
phy_clear_bits_mmd ( phydev , MDIO_MMD_VEND1 , 0xc6 , 0x300 ) ;
/* Set TX Pair delay selection */
phy_write_mmd ( phydev , MDIO_MMD_VEND1 , 0x13 , 0x404 ) ;
phy_write_mmd ( phydev , MDIO_MMD_VEND1 , 0x14 , 0x404 ) ;
return 0 ;
}
static struct phy_driver mtk_gephy_driver [ ] = {
{
PHY_ID_MATCH_EXACT ( 0x03a29412 ) ,
. name = " MediaTek MT7530 PHY " ,
. config_init = mt7530_phy_config_init ,
/* Interrupts are handled by the switch, not the PHY
* itself .
*/
. config_intr = genphy_no_config_intr ,
. handle_interrupt = genphy_handle_interrupt_no_ack ,
2021-08-23 12:44:21 +08:00
. suspend = genphy_suspend ,
. resume = genphy_resume ,
2021-05-19 11:31:59 +08:00
. read_page = mtk_gephy_read_page ,
. write_page = mtk_gephy_write_page ,
} ,
{
PHY_ID_MATCH_EXACT ( 0x03a29441 ) ,
. name = " MediaTek MT7531 PHY " ,
. config_init = mt7531_phy_config_init ,
/* Interrupts are handled by the switch, not the PHY
* itself .
*/
. config_intr = genphy_no_config_intr ,
. handle_interrupt = genphy_handle_interrupt_no_ack ,
2021-08-23 12:44:21 +08:00
. suspend = genphy_suspend ,
. resume = genphy_resume ,
2021-05-19 11:31:59 +08:00
. read_page = mtk_gephy_read_page ,
. write_page = mtk_gephy_write_page ,
} ,
} ;
module_phy_driver ( mtk_gephy_driver ) ;
static struct mdio_device_id __maybe_unused mtk_gephy_tbl [ ] = {
2023-06-11 00:48:10 +01:00
{ PHY_ID_MATCH_EXACT ( 0x03a29441 ) } ,
{ PHY_ID_MATCH_EXACT ( 0x03a29412 ) } ,
2021-05-19 11:31:59 +08:00
{ }
} ;
MODULE_DESCRIPTION ( " MediaTek Gigabit Ethernet PHY driver " ) ;
MODULE_AUTHOR ( " DENG, Qingfang <dqfext@gmail.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( mdio , mtk_gephy_tbl ) ;