162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (c) 2018-2019 MediaTek Inc. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* A library for configuring path from GMAC/GDM to target PHY 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Sean Wang <sean.wang@mediatek.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/phy.h> 1162306a36Sopenharmony_ci#include <linux/regmap.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "mtk_eth_soc.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct mtk_eth_muxc { 1662306a36Sopenharmony_ci const char *name; 1762306a36Sopenharmony_ci int cap_bit; 1862306a36Sopenharmony_ci int (*set_path)(struct mtk_eth *eth, u64 path); 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic const char *mtk_eth_path_name(u64 path) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci switch (path) { 2462306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC1_RGMII: 2562306a36Sopenharmony_ci return "gmac1_rgmii"; 2662306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC1_TRGMII: 2762306a36Sopenharmony_ci return "gmac1_trgmii"; 2862306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC1_SGMII: 2962306a36Sopenharmony_ci return "gmac1_sgmii"; 3062306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_RGMII: 3162306a36Sopenharmony_ci return "gmac2_rgmii"; 3262306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_SGMII: 3362306a36Sopenharmony_ci return "gmac2_sgmii"; 3462306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_GEPHY: 3562306a36Sopenharmony_ci return "gmac2_gephy"; 3662306a36Sopenharmony_ci case MTK_ETH_PATH_GDM1_ESW: 3762306a36Sopenharmony_ci return "gdm1_esw"; 3862306a36Sopenharmony_ci default: 3962306a36Sopenharmony_ci return "unknown path"; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci bool updated = true; 4662306a36Sopenharmony_ci u32 mask, set, reg; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci switch (path) { 4962306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC1_SGMII: 5062306a36Sopenharmony_ci mask = ~(u32)MTK_MUX_TO_ESW; 5162306a36Sopenharmony_ci set = 0; 5262306a36Sopenharmony_ci break; 5362306a36Sopenharmony_ci case MTK_ETH_PATH_GDM1_ESW: 5462306a36Sopenharmony_ci mask = ~(u32)MTK_MUX_TO_ESW; 5562306a36Sopenharmony_ci set = MTK_MUX_TO_ESW; 5662306a36Sopenharmony_ci break; 5762306a36Sopenharmony_ci default: 5862306a36Sopenharmony_ci updated = false; 5962306a36Sopenharmony_ci break; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (mtk_is_netsys_v3_or_greater(eth)) 6362306a36Sopenharmony_ci reg = MTK_MAC_MISC_V3; 6462306a36Sopenharmony_ci else 6562306a36Sopenharmony_ci reg = MTK_MAC_MISC; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (updated) 6862306a36Sopenharmony_ci mtk_m32(eth, mask, set, reg); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci dev_dbg(eth->dev, "path %s in %s updated = %d\n", 7162306a36Sopenharmony_ci mtk_eth_path_name(path), __func__, updated); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci unsigned int val = 0; 7962306a36Sopenharmony_ci bool updated = true; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci switch (path) { 8262306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_GEPHY: 8362306a36Sopenharmony_ci val = ~(u32)GEPHY_MAC_SEL; 8462306a36Sopenharmony_ci break; 8562306a36Sopenharmony_ci default: 8662306a36Sopenharmony_ci updated = false; 8762306a36Sopenharmony_ci break; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (updated) 9162306a36Sopenharmony_ci regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci dev_dbg(eth->dev, "path %s in %s updated = %d\n", 9462306a36Sopenharmony_ci mtk_eth_path_name(path), __func__, updated); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci unsigned int val = 0, mask = 0, reg = 0; 10262306a36Sopenharmony_ci bool updated = true; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci switch (path) { 10562306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_SGMII: 10662306a36Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) { 10762306a36Sopenharmony_ci reg = USB_PHY_SWITCH_REG; 10862306a36Sopenharmony_ci val = SGMII_QPHY_SEL; 10962306a36Sopenharmony_ci mask = QPHY_SEL_MASK; 11062306a36Sopenharmony_ci } else { 11162306a36Sopenharmony_ci reg = INFRA_MISC2; 11262306a36Sopenharmony_ci val = CO_QPHY_SEL; 11362306a36Sopenharmony_ci mask = val; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci default: 11762306a36Sopenharmony_ci updated = false; 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (updated) 12262306a36Sopenharmony_ci regmap_update_bits(eth->infra, reg, mask, val); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci dev_dbg(eth->dev, "path %s in %s updated = %d\n", 12562306a36Sopenharmony_ci mtk_eth_path_name(path), __func__, updated); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci unsigned int val = 0; 13362306a36Sopenharmony_ci bool updated = true; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci switch (path) { 13662306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC1_SGMII: 13762306a36Sopenharmony_ci val = SYSCFG0_SGMII_GMAC1; 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_SGMII: 14062306a36Sopenharmony_ci val = SYSCFG0_SGMII_GMAC2; 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC1_RGMII: 14362306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_RGMII: 14462306a36Sopenharmony_ci regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); 14562306a36Sopenharmony_ci val &= SYSCFG0_SGMII_MASK; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) || 14862306a36Sopenharmony_ci (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2)) 14962306a36Sopenharmony_ci val = 0; 15062306a36Sopenharmony_ci else 15162306a36Sopenharmony_ci updated = false; 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci default: 15462306a36Sopenharmony_ci updated = false; 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (updated) 15962306a36Sopenharmony_ci regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, 16062306a36Sopenharmony_ci SYSCFG0_SGMII_MASK, val); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci dev_dbg(eth->dev, "path %s in %s updated = %d\n", 16362306a36Sopenharmony_ci mtk_eth_path_name(path), __func__, updated); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci unsigned int val = 0; 17162306a36Sopenharmony_ci bool updated = true; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci switch (path) { 17662306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC1_SGMII: 17762306a36Sopenharmony_ci val |= SYSCFG0_SGMII_GMAC1_V2; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_GEPHY: 18062306a36Sopenharmony_ci val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci case MTK_ETH_PATH_GMAC2_SGMII: 18362306a36Sopenharmony_ci val |= SYSCFG0_SGMII_GMAC2_V2; 18462306a36Sopenharmony_ci break; 18562306a36Sopenharmony_ci default: 18662306a36Sopenharmony_ci updated = false; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (updated) 19062306a36Sopenharmony_ci regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, 19162306a36Sopenharmony_ci SYSCFG0_SGMII_MASK, val); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci dev_dbg(eth->dev, "path %s in %s updated = %d\n", 19462306a36Sopenharmony_ci mtk_eth_path_name(path), __func__, updated); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic const struct mtk_eth_muxc mtk_eth_muxc[] = { 20062306a36Sopenharmony_ci { 20162306a36Sopenharmony_ci .name = "mux_gdm1_to_gmac1_esw", 20262306a36Sopenharmony_ci .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW, 20362306a36Sopenharmony_ci .set_path = set_mux_gdm1_to_gmac1_esw, 20462306a36Sopenharmony_ci }, { 20562306a36Sopenharmony_ci .name = "mux_gmac2_gmac0_to_gephy", 20662306a36Sopenharmony_ci .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY, 20762306a36Sopenharmony_ci .set_path = set_mux_gmac2_gmac0_to_gephy, 20862306a36Sopenharmony_ci }, { 20962306a36Sopenharmony_ci .name = "mux_u3_gmac2_to_qphy", 21062306a36Sopenharmony_ci .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY, 21162306a36Sopenharmony_ci .set_path = set_mux_u3_gmac2_to_qphy, 21262306a36Sopenharmony_ci }, { 21362306a36Sopenharmony_ci .name = "mux_gmac1_gmac2_to_sgmii_rgmii", 21462306a36Sopenharmony_ci .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, 21562306a36Sopenharmony_ci .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, 21662306a36Sopenharmony_ci }, { 21762306a36Sopenharmony_ci .name = "mux_gmac12_to_gephy_sgmii", 21862306a36Sopenharmony_ci .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, 21962306a36Sopenharmony_ci .set_path = set_mux_gmac12_to_gephy_sgmii, 22062306a36Sopenharmony_ci }, 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci int i, err = 0; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (!MTK_HAS_CAPS(eth->soc->caps, path)) { 22862306a36Sopenharmony_ci dev_err(eth->dev, "path %s isn't support on the SoC\n", 22962306a36Sopenharmony_ci mtk_eth_path_name(path)); 23062306a36Sopenharmony_ci return -EINVAL; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX)) 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* Setup MUX in path fabric */ 23762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) { 23862306a36Sopenharmony_ci if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) { 23962306a36Sopenharmony_ci err = mtk_eth_muxc[i].set_path(eth, path); 24062306a36Sopenharmony_ci if (err) 24162306a36Sopenharmony_ci goto out; 24262306a36Sopenharmony_ci } else { 24362306a36Sopenharmony_ci dev_dbg(eth->dev, "mux %s isn't present on the SoC\n", 24462306a36Sopenharmony_ci mtk_eth_muxc[i].name); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ciout: 24962306a36Sopenharmony_ci return err; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ciint mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci u64 path; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : 25762306a36Sopenharmony_ci MTK_ETH_PATH_GMAC2_SGMII; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Setup proper MUXes along the path */ 26062306a36Sopenharmony_ci return mtk_eth_mux_setup(eth, path); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ciint mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci u64 path = 0; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (mac_id == 1) 26862306a36Sopenharmony_ci path = MTK_ETH_PATH_GMAC2_GEPHY; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (!path) 27162306a36Sopenharmony_ci return -EINVAL; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Setup proper MUXes along the path */ 27462306a36Sopenharmony_ci return mtk_eth_mux_setup(eth, path); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ciint mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci u64 path; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII : 28262306a36Sopenharmony_ci MTK_ETH_PATH_GMAC2_RGMII; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Setup proper MUXes along the path */ 28562306a36Sopenharmony_ci return mtk_eth_mux_setup(eth, path); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 288