2019-06-01 08:03:13 +08:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018-2019 MediaTek Inc.
/* A library for configuring path from GMAC/GDM to target PHY
*
* Author : Sean Wang < sean . wang @ mediatek . com >
*
*/
# include <linux/phy.h>
# include <linux/regmap.h>
# include "mtk_eth_soc.h"
struct mtk_eth_muxc {
2019-07-03 20:42:04 +02:00
const char * name ;
int cap_bit ;
2023-07-25 01:53:13 +01:00
int ( * set_path ) ( struct mtk_eth * eth , u64 path ) ;
2019-06-01 08:03:13 +08:00
} ;
2023-07-25 01:53:13 +01:00
static const char * mtk_eth_path_name ( u64 path )
2019-07-03 20:42:04 +02:00
{
switch ( path ) {
case MTK_ETH_PATH_GMAC1_RGMII :
return " gmac1_rgmii " ;
case MTK_ETH_PATH_GMAC1_TRGMII :
return " gmac1_trgmii " ;
case MTK_ETH_PATH_GMAC1_SGMII :
return " gmac1_sgmii " ;
case MTK_ETH_PATH_GMAC2_RGMII :
return " gmac2_rgmii " ;
case MTK_ETH_PATH_GMAC2_SGMII :
return " gmac2_sgmii " ;
case MTK_ETH_PATH_GMAC2_GEPHY :
return " gmac2_gephy " ;
case MTK_ETH_PATH_GDM1_ESW :
return " gdm1_esw " ;
default :
return " unknown path " ;
}
}
2019-06-01 08:03:13 +08:00
2023-07-25 01:53:13 +01:00
static int set_mux_gdm1_to_gmac1_esw ( struct mtk_eth * eth , u64 path )
2019-06-01 08:03:13 +08:00
{
bool updated = true ;
2023-07-25 01:57:42 +01:00
u32 mask , set , reg ;
2019-06-01 08:03:13 +08:00
switch ( path ) {
case MTK_ETH_PATH_GMAC1_SGMII :
mask = ~ ( u32 ) MTK_MUX_TO_ESW ;
set = 0 ;
break ;
case MTK_ETH_PATH_GDM1_ESW :
mask = ~ ( u32 ) MTK_MUX_TO_ESW ;
set = MTK_MUX_TO_ESW ;
break ;
default :
updated = false ;
break ;
2019-10-25 17:13:08 +08:00
}
2019-06-01 08:03:13 +08:00
2023-07-25 01:57:42 +01:00
if ( mtk_is_netsys_v3_or_greater ( eth ) )
reg = MTK_MAC_MISC_V3 ;
else
reg = MTK_MAC_MISC ;
if ( updated )
mtk_m32 ( eth , mask , set , reg ) ;
2019-06-01 08:03:13 +08:00
dev_dbg ( eth - > dev , " path %s in %s updated = %d \n " ,
2019-07-03 20:42:04 +02:00
mtk_eth_path_name ( path ) , __func__ , updated ) ;
2019-06-01 08:03:13 +08:00
return 0 ;
}
2023-07-25 01:53:13 +01:00
static int set_mux_gmac2_gmac0_to_gephy ( struct mtk_eth * eth , u64 path )
2019-06-01 08:03:13 +08:00
{
unsigned int val = 0 ;
bool updated = true ;
switch ( path ) {
case MTK_ETH_PATH_GMAC2_GEPHY :
val = ~ ( u32 ) GEPHY_MAC_SEL ;
break ;
default :
updated = false ;
break ;
}
if ( updated )
regmap_update_bits ( eth - > infra , INFRA_MISC2 , GEPHY_MAC_SEL , val ) ;
dev_dbg ( eth - > dev , " path %s in %s updated = %d \n " ,
2019-07-03 20:42:04 +02:00
mtk_eth_path_name ( path ) , __func__ , updated ) ;
2019-06-01 08:03:13 +08:00
return 0 ;
}
2023-07-25 01:53:13 +01:00
static int set_mux_u3_gmac2_to_qphy ( struct mtk_eth * eth , u64 path )
2019-06-01 08:03:13 +08:00
{
2023-03-19 12:56:28 +00:00
unsigned int val = 0 , mask = 0 , reg = 0 ;
2019-06-01 08:03:13 +08:00
bool updated = true ;
switch ( path ) {
case MTK_ETH_PATH_GMAC2_SGMII :
2023-03-19 12:56:28 +00:00
if ( MTK_HAS_CAPS ( eth - > soc - > caps , MTK_U3_COPHY_V2 ) ) {
reg = USB_PHY_SWITCH_REG ;
val = SGMII_QPHY_SEL ;
mask = QPHY_SEL_MASK ;
} else {
reg = INFRA_MISC2 ;
val = CO_QPHY_SEL ;
mask = val ;
}
2019-06-01 08:03:13 +08:00
break ;
default :
updated = false ;
break ;
}
if ( updated )
2023-03-19 12:56:28 +00:00
regmap_update_bits ( eth - > infra , reg , mask , val ) ;
2019-06-01 08:03:13 +08:00
dev_dbg ( eth - > dev , " path %s in %s updated = %d \n " ,
2019-07-03 20:42:04 +02:00
mtk_eth_path_name ( path ) , __func__ , updated ) ;
2019-06-01 08:03:13 +08:00
return 0 ;
}
2023-07-25 01:53:13 +01:00
static int set_mux_gmac1_gmac2_to_sgmii_rgmii ( struct mtk_eth * eth , u64 path )
2019-06-01 08:03:13 +08:00
{
unsigned int val = 0 ;
bool updated = true ;
switch ( path ) {
case MTK_ETH_PATH_GMAC1_SGMII :
val = SYSCFG0_SGMII_GMAC1 ;
break ;
case MTK_ETH_PATH_GMAC2_SGMII :
val = SYSCFG0_SGMII_GMAC2 ;
break ;
case MTK_ETH_PATH_GMAC1_RGMII :
case MTK_ETH_PATH_GMAC2_RGMII :
regmap_read ( eth - > ethsys , ETHSYS_SYSCFG0 , & val ) ;
val & = SYSCFG0_SGMII_MASK ;
if ( ( path = = MTK_GMAC1_RGMII & & val = = SYSCFG0_SGMII_GMAC1 ) | |
( path = = MTK_GMAC2_RGMII & & val = = SYSCFG0_SGMII_GMAC2 ) )
val = 0 ;
else
updated = false ;
break ;
default :
updated = false ;
break ;
2019-10-25 17:13:08 +08:00
}
2019-06-01 08:03:13 +08:00
if ( updated )
regmap_update_bits ( eth - > ethsys , ETHSYS_SYSCFG0 ,
SYSCFG0_SGMII_MASK , val ) ;
dev_dbg ( eth - > dev , " path %s in %s updated = %d \n " ,
2019-07-03 20:42:04 +02:00
mtk_eth_path_name ( path ) , __func__ , updated ) ;
2019-06-01 08:03:13 +08:00
return 0 ;
}
2023-07-25 01:53:13 +01:00
static int set_mux_gmac12_to_gephy_sgmii ( struct mtk_eth * eth , u64 path )
2019-06-01 08:03:13 +08:00
{
unsigned int val = 0 ;
bool updated = true ;
regmap_read ( eth - > ethsys , ETHSYS_SYSCFG0 , & val ) ;
switch ( path ) {
case MTK_ETH_PATH_GMAC1_SGMII :
val | = SYSCFG0_SGMII_GMAC1_V2 ;
break ;
case MTK_ETH_PATH_GMAC2_GEPHY :
val & = ~ ( u32 ) SYSCFG0_SGMII_GMAC2_V2 ;
break ;
case MTK_ETH_PATH_GMAC2_SGMII :
val | = SYSCFG0_SGMII_GMAC2_V2 ;
break ;
default :
updated = false ;
2019-10-25 17:13:08 +08:00
}
2019-06-01 08:03:13 +08:00
if ( updated )
regmap_update_bits ( eth - > ethsys , ETHSYS_SYSCFG0 ,
SYSCFG0_SGMII_MASK , val ) ;
dev_dbg ( eth - > dev , " path %s in %s updated = %d \n " ,
2019-07-03 20:42:04 +02:00
mtk_eth_path_name ( path ) , __func__ , updated ) ;
2019-06-01 08:03:13 +08:00
return 0 ;
}
static const struct mtk_eth_muxc mtk_eth_muxc [ ] = {
2019-07-03 20:42:04 +02:00
{
. name = " mux_gdm1_to_gmac1_esw " ,
. cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW ,
. set_path = set_mux_gdm1_to_gmac1_esw ,
} , {
. name = " mux_gmac2_gmac0_to_gephy " ,
. cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY ,
. set_path = set_mux_gmac2_gmac0_to_gephy ,
} , {
. name = " mux_u3_gmac2_to_qphy " ,
. cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY ,
. set_path = set_mux_u3_gmac2_to_qphy ,
} , {
. name = " mux_gmac1_gmac2_to_sgmii_rgmii " ,
. cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII ,
. set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii ,
} , {
. name = " mux_gmac12_to_gephy_sgmii " ,
. cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII ,
. set_path = set_mux_gmac12_to_gephy_sgmii ,
} ,
2019-06-01 08:03:13 +08:00
} ;
2023-07-25 01:53:13 +01:00
static int mtk_eth_mux_setup ( struct mtk_eth * eth , u64 path )
2019-06-01 08:03:13 +08:00
{
int i , err = 0 ;
2019-07-03 20:42:04 +02:00
if ( ! MTK_HAS_CAPS ( eth - > soc - > caps , path ) ) {
2019-06-01 08:03:13 +08:00
dev_err ( eth - > dev , " path %s isn't support on the SoC \n " ,
2019-07-03 20:42:04 +02:00
mtk_eth_path_name ( path ) ) ;
2019-06-01 08:03:13 +08:00
return - EINVAL ;
}
if ( ! MTK_HAS_CAPS ( eth - > soc - > caps , MTK_MUX ) )
return 0 ;
/* Setup MUX in path fabric */
2019-07-03 20:42:04 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( mtk_eth_muxc ) ; i + + ) {
if ( MTK_HAS_CAPS ( eth - > soc - > caps , mtk_eth_muxc [ i ] . cap_bit ) ) {
2019-06-01 08:03:13 +08:00
err = mtk_eth_muxc [ i ] . set_path ( eth , path ) ;
if ( err )
goto out ;
} else {
dev_dbg ( eth - > dev , " mux %s isn't present on the SoC \n " ,
2019-07-03 20:42:04 +02:00
mtk_eth_muxc [ i ] . name ) ;
2019-06-01 08:03:13 +08:00
}
}
out :
return err ;
}
2019-08-25 19:43:40 +02:00
int mtk_gmac_sgmii_path_setup ( struct mtk_eth * eth , int mac_id )
2019-06-01 08:03:13 +08:00
{
2023-07-25 01:53:13 +01:00
u64 path ;
2019-06-01 08:03:13 +08:00
path = ( mac_id = = 0 ) ? MTK_ETH_PATH_GMAC1_SGMII :
MTK_ETH_PATH_GMAC2_SGMII ;
/* Setup proper MUXes along the path */
2020-12-10 21:50:50 +08:00
return mtk_eth_mux_setup ( eth , path ) ;
2019-06-01 08:03:13 +08:00
}
2019-08-25 19:43:40 +02:00
int mtk_gmac_gephy_path_setup ( struct mtk_eth * eth , int mac_id )
2019-06-01 08:03:13 +08:00
{
2023-07-25 01:53:13 +01:00
u64 path = 0 ;
2019-06-01 08:03:13 +08:00
if ( mac_id = = 1 )
path = MTK_ETH_PATH_GMAC2_GEPHY ;
if ( ! path )
return - EINVAL ;
/* Setup proper MUXes along the path */
2020-12-11 16:38:01 +08:00
return mtk_eth_mux_setup ( eth , path ) ;
2019-06-01 08:03:13 +08:00
}
2019-08-25 19:43:40 +02:00
int mtk_gmac_rgmii_path_setup ( struct mtk_eth * eth , int mac_id )
2019-06-01 08:03:13 +08:00
{
2023-07-25 01:53:13 +01:00
u64 path ;
2019-06-01 08:03:13 +08:00
path = ( mac_id = = 0 ) ? MTK_ETH_PATH_GMAC1_RGMII :
MTK_ETH_PATH_GMAC2_RGMII ;
/* Setup proper MUXes along the path */
2020-12-11 16:38:01 +08:00
return mtk_eth_mux_setup ( eth , path ) ;
2019-06-01 08:03:13 +08:00
}