17093f9d8SSean Wang // SPDX-License-Identifier: GPL-2.0
27093f9d8SSean Wang // Copyright (c) 2018-2019 MediaTek Inc.
37093f9d8SSean Wang
47093f9d8SSean Wang /* A library for configuring path from GMAC/GDM to target PHY
57093f9d8SSean Wang *
67093f9d8SSean Wang * Author: Sean Wang <sean.wang@mediatek.com>
77093f9d8SSean Wang *
87093f9d8SSean Wang */
97093f9d8SSean Wang
107093f9d8SSean Wang #include <linux/phy.h>
117093f9d8SSean Wang #include <linux/regmap.h>
127093f9d8SSean Wang
137093f9d8SSean Wang #include "mtk_eth_soc.h"
147093f9d8SSean Wang
157093f9d8SSean Wang struct mtk_eth_muxc {
16e2c74694SRené van Dorst const char *name;
17e2c74694SRené van Dorst int cap_bit;
1851a4df60SLorenzo Bianconi int (*set_path)(struct mtk_eth *eth, u64 path);
197093f9d8SSean Wang };
207093f9d8SSean Wang
mtk_eth_path_name(u64 path)2151a4df60SLorenzo Bianconi static const char *mtk_eth_path_name(u64 path)
22e2c74694SRené van Dorst {
23e2c74694SRené van Dorst switch (path) {
24e2c74694SRené van Dorst case MTK_ETH_PATH_GMAC1_RGMII:
25e2c74694SRené van Dorst return "gmac1_rgmii";
26e2c74694SRené van Dorst case MTK_ETH_PATH_GMAC1_TRGMII:
27e2c74694SRené van Dorst return "gmac1_trgmii";
28e2c74694SRené van Dorst case MTK_ETH_PATH_GMAC1_SGMII:
29e2c74694SRené van Dorst return "gmac1_sgmii";
30e2c74694SRené van Dorst case MTK_ETH_PATH_GMAC2_RGMII:
31e2c74694SRené van Dorst return "gmac2_rgmii";
32e2c74694SRené van Dorst case MTK_ETH_PATH_GMAC2_SGMII:
33e2c74694SRené van Dorst return "gmac2_sgmii";
34e2c74694SRené van Dorst case MTK_ETH_PATH_GMAC2_GEPHY:
35e2c74694SRené van Dorst return "gmac2_gephy";
36e2c74694SRené van Dorst case MTK_ETH_PATH_GDM1_ESW:
37e2c74694SRené van Dorst return "gdm1_esw";
38e2c74694SRené van Dorst default:
39e2c74694SRené van Dorst return "unknown path";
40e2c74694SRené van Dorst }
41e2c74694SRené van Dorst }
427093f9d8SSean Wang
set_mux_gdm1_to_gmac1_esw(struct mtk_eth * eth,u64 path)4351a4df60SLorenzo Bianconi static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path)
447093f9d8SSean Wang {
457093f9d8SSean Wang bool updated = true;
46*445eb644SLorenzo Bianconi u32 mask, set, reg;
477093f9d8SSean Wang
487093f9d8SSean Wang switch (path) {
497093f9d8SSean Wang case MTK_ETH_PATH_GMAC1_SGMII:
507093f9d8SSean Wang mask = ~(u32)MTK_MUX_TO_ESW;
517093f9d8SSean Wang set = 0;
527093f9d8SSean Wang break;
537093f9d8SSean Wang case MTK_ETH_PATH_GDM1_ESW:
547093f9d8SSean Wang mask = ~(u32)MTK_MUX_TO_ESW;
557093f9d8SSean Wang set = MTK_MUX_TO_ESW;
567093f9d8SSean Wang break;
577093f9d8SSean Wang default:
587093f9d8SSean Wang updated = false;
597093f9d8SSean Wang break;
6011b3412cSYueHaibing }
617093f9d8SSean Wang
62*445eb644SLorenzo Bianconi if (mtk_is_netsys_v3_or_greater(eth))
63*445eb644SLorenzo Bianconi reg = MTK_MAC_MISC_V3;
64*445eb644SLorenzo Bianconi else
65*445eb644SLorenzo Bianconi reg = MTK_MAC_MISC;
66*445eb644SLorenzo Bianconi
67*445eb644SLorenzo Bianconi if (updated)
68*445eb644SLorenzo Bianconi mtk_m32(eth, mask, set, reg);
697093f9d8SSean Wang
707093f9d8SSean Wang dev_dbg(eth->dev, "path %s in %s updated = %d\n",
71e2c74694SRené van Dorst mtk_eth_path_name(path), __func__, updated);
727093f9d8SSean Wang
737093f9d8SSean Wang return 0;
747093f9d8SSean Wang }
757093f9d8SSean Wang
set_mux_gmac2_gmac0_to_gephy(struct mtk_eth * eth,u64 path)7651a4df60SLorenzo Bianconi static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path)
777093f9d8SSean Wang {
787093f9d8SSean Wang unsigned int val = 0;
797093f9d8SSean Wang bool updated = true;
807093f9d8SSean Wang
817093f9d8SSean Wang switch (path) {
827093f9d8SSean Wang case MTK_ETH_PATH_GMAC2_GEPHY:
837093f9d8SSean Wang val = ~(u32)GEPHY_MAC_SEL;
847093f9d8SSean Wang break;
857093f9d8SSean Wang default:
867093f9d8SSean Wang updated = false;
877093f9d8SSean Wang break;
887093f9d8SSean Wang }
897093f9d8SSean Wang
907093f9d8SSean Wang if (updated)
917093f9d8SSean Wang regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
927093f9d8SSean Wang
937093f9d8SSean Wang dev_dbg(eth->dev, "path %s in %s updated = %d\n",
94e2c74694SRené van Dorst mtk_eth_path_name(path), __func__, updated);
957093f9d8SSean Wang
967093f9d8SSean Wang return 0;
977093f9d8SSean Wang }
987093f9d8SSean Wang
set_mux_u3_gmac2_to_qphy(struct mtk_eth * eth,u64 path)9951a4df60SLorenzo Bianconi static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
1007093f9d8SSean Wang {
101f5d43dddSDaniel Golle unsigned int val = 0, mask = 0, reg = 0;
1027093f9d8SSean Wang bool updated = true;
1037093f9d8SSean Wang
1047093f9d8SSean Wang switch (path) {
1057093f9d8SSean Wang case MTK_ETH_PATH_GMAC2_SGMII:
106f5d43dddSDaniel Golle if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {
107f5d43dddSDaniel Golle reg = USB_PHY_SWITCH_REG;
108f5d43dddSDaniel Golle val = SGMII_QPHY_SEL;
109f5d43dddSDaniel Golle mask = QPHY_SEL_MASK;
110f5d43dddSDaniel Golle } else {
111f5d43dddSDaniel Golle reg = INFRA_MISC2;
1127093f9d8SSean Wang val = CO_QPHY_SEL;
113f5d43dddSDaniel Golle mask = val;
114f5d43dddSDaniel Golle }
1157093f9d8SSean Wang break;
1167093f9d8SSean Wang default:
1177093f9d8SSean Wang updated = false;
1187093f9d8SSean Wang break;
1197093f9d8SSean Wang }
1207093f9d8SSean Wang
1217093f9d8SSean Wang if (updated)
122f5d43dddSDaniel Golle regmap_update_bits(eth->infra, reg, mask, val);
1237093f9d8SSean Wang
1247093f9d8SSean Wang dev_dbg(eth->dev, "path %s in %s updated = %d\n",
125e2c74694SRené van Dorst mtk_eth_path_name(path), __func__, updated);
1267093f9d8SSean Wang
1277093f9d8SSean Wang return 0;
1287093f9d8SSean Wang }
1297093f9d8SSean Wang
set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth * eth,u64 path)13051a4df60SLorenzo Bianconi static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path)
1317093f9d8SSean Wang {
1327093f9d8SSean Wang unsigned int val = 0;
1337093f9d8SSean Wang bool updated = true;
1347093f9d8SSean Wang
1357093f9d8SSean Wang switch (path) {
1367093f9d8SSean Wang case MTK_ETH_PATH_GMAC1_SGMII:
1377093f9d8SSean Wang val = SYSCFG0_SGMII_GMAC1;
1387093f9d8SSean Wang break;
1397093f9d8SSean Wang case MTK_ETH_PATH_GMAC2_SGMII:
1407093f9d8SSean Wang val = SYSCFG0_SGMII_GMAC2;
1417093f9d8SSean Wang break;
1427093f9d8SSean Wang case MTK_ETH_PATH_GMAC1_RGMII:
1437093f9d8SSean Wang case MTK_ETH_PATH_GMAC2_RGMII:
1447093f9d8SSean Wang regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
1457093f9d8SSean Wang val &= SYSCFG0_SGMII_MASK;
1467093f9d8SSean Wang
1477093f9d8SSean Wang if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
1487093f9d8SSean Wang (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
1497093f9d8SSean Wang val = 0;
1507093f9d8SSean Wang else
1517093f9d8SSean Wang updated = false;
1527093f9d8SSean Wang break;
1537093f9d8SSean Wang default:
1547093f9d8SSean Wang updated = false;
1557093f9d8SSean Wang break;
15611b3412cSYueHaibing }
1577093f9d8SSean Wang
1587093f9d8SSean Wang if (updated)
1597093f9d8SSean Wang regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
1607093f9d8SSean Wang SYSCFG0_SGMII_MASK, val);
1617093f9d8SSean Wang
1627093f9d8SSean Wang dev_dbg(eth->dev, "path %s in %s updated = %d\n",
163e2c74694SRené van Dorst mtk_eth_path_name(path), __func__, updated);
1647093f9d8SSean Wang
1657093f9d8SSean Wang return 0;
1667093f9d8SSean Wang }
1677093f9d8SSean Wang
set_mux_gmac12_to_gephy_sgmii(struct mtk_eth * eth,u64 path)16851a4df60SLorenzo Bianconi static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path)
1697093f9d8SSean Wang {
1707093f9d8SSean Wang unsigned int val = 0;
1717093f9d8SSean Wang bool updated = true;
1727093f9d8SSean Wang
1737093f9d8SSean Wang regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
1747093f9d8SSean Wang
1757093f9d8SSean Wang switch (path) {
1767093f9d8SSean Wang case MTK_ETH_PATH_GMAC1_SGMII:
1777093f9d8SSean Wang val |= SYSCFG0_SGMII_GMAC1_V2;
1787093f9d8SSean Wang break;
1797093f9d8SSean Wang case MTK_ETH_PATH_GMAC2_GEPHY:
1807093f9d8SSean Wang val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
1817093f9d8SSean Wang break;
1827093f9d8SSean Wang case MTK_ETH_PATH_GMAC2_SGMII:
1837093f9d8SSean Wang val |= SYSCFG0_SGMII_GMAC2_V2;
1847093f9d8SSean Wang break;
1857093f9d8SSean Wang default:
1867093f9d8SSean Wang updated = false;
18711b3412cSYueHaibing }
1887093f9d8SSean Wang
1897093f9d8SSean Wang if (updated)
1907093f9d8SSean Wang regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
1917093f9d8SSean Wang SYSCFG0_SGMII_MASK, val);
1927093f9d8SSean Wang
1937093f9d8SSean Wang dev_dbg(eth->dev, "path %s in %s updated = %d\n",
194e2c74694SRené van Dorst mtk_eth_path_name(path), __func__, updated);
1957093f9d8SSean Wang
1967093f9d8SSean Wang return 0;
1977093f9d8SSean Wang }
1987093f9d8SSean Wang
1997093f9d8SSean Wang static const struct mtk_eth_muxc mtk_eth_muxc[] = {
200e2c74694SRené van Dorst {
201e2c74694SRené van Dorst .name = "mux_gdm1_to_gmac1_esw",
202e2c74694SRené van Dorst .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
203e2c74694SRené van Dorst .set_path = set_mux_gdm1_to_gmac1_esw,
204e2c74694SRené van Dorst }, {
205e2c74694SRené van Dorst .name = "mux_gmac2_gmac0_to_gephy",
206e2c74694SRené van Dorst .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
207e2c74694SRené van Dorst .set_path = set_mux_gmac2_gmac0_to_gephy,
208e2c74694SRené van Dorst }, {
209e2c74694SRené van Dorst .name = "mux_u3_gmac2_to_qphy",
210e2c74694SRené van Dorst .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
211e2c74694SRené van Dorst .set_path = set_mux_u3_gmac2_to_qphy,
212e2c74694SRené van Dorst }, {
213e2c74694SRené van Dorst .name = "mux_gmac1_gmac2_to_sgmii_rgmii",
214e2c74694SRené van Dorst .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
215e2c74694SRené van Dorst .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
216e2c74694SRené van Dorst }, {
217e2c74694SRené van Dorst .name = "mux_gmac12_to_gephy_sgmii",
218e2c74694SRené van Dorst .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
219e2c74694SRené van Dorst .set_path = set_mux_gmac12_to_gephy_sgmii,
220e2c74694SRené van Dorst },
2217093f9d8SSean Wang };
2227093f9d8SSean Wang
mtk_eth_mux_setup(struct mtk_eth * eth,u64 path)22351a4df60SLorenzo Bianconi static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path)
2247093f9d8SSean Wang {
2257093f9d8SSean Wang int i, err = 0;
2267093f9d8SSean Wang
227e2c74694SRené van Dorst if (!MTK_HAS_CAPS(eth->soc->caps, path)) {
2287093f9d8SSean Wang dev_err(eth->dev, "path %s isn't support on the SoC\n",
229e2c74694SRené van Dorst mtk_eth_path_name(path));
2307093f9d8SSean Wang return -EINVAL;
2317093f9d8SSean Wang }
2327093f9d8SSean Wang
2337093f9d8SSean Wang if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
2347093f9d8SSean Wang return 0;
2357093f9d8SSean Wang
2367093f9d8SSean Wang /* Setup MUX in path fabric */
237e2c74694SRené van Dorst for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {
238e2c74694SRené van Dorst if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {
2397093f9d8SSean Wang err = mtk_eth_muxc[i].set_path(eth, path);
2407093f9d8SSean Wang if (err)
2417093f9d8SSean Wang goto out;
2427093f9d8SSean Wang } else {
2437093f9d8SSean Wang dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
244e2c74694SRené van Dorst mtk_eth_muxc[i].name);
2457093f9d8SSean Wang }
2467093f9d8SSean Wang }
2477093f9d8SSean Wang
2487093f9d8SSean Wang out:
2497093f9d8SSean Wang return err;
2507093f9d8SSean Wang }
2517093f9d8SSean Wang
mtk_gmac_sgmii_path_setup(struct mtk_eth * eth,int mac_id)2527e538372SRené van Dorst int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
2537093f9d8SSean Wang {
25451a4df60SLorenzo Bianconi u64 path;
2557093f9d8SSean Wang
2567093f9d8SSean Wang path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
2577093f9d8SSean Wang MTK_ETH_PATH_GMAC2_SGMII;
2587093f9d8SSean Wang
2597093f9d8SSean Wang /* Setup proper MUXes along the path */
260a76b6b1fSZheng Yongjun return mtk_eth_mux_setup(eth, path);
2617093f9d8SSean Wang }
2627093f9d8SSean Wang
mtk_gmac_gephy_path_setup(struct mtk_eth * eth,int mac_id)2637e538372SRené van Dorst int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
2647093f9d8SSean Wang {
26551a4df60SLorenzo Bianconi u64 path = 0;
2667093f9d8SSean Wang
2677093f9d8SSean Wang if (mac_id == 1)
2687093f9d8SSean Wang path = MTK_ETH_PATH_GMAC2_GEPHY;
2697093f9d8SSean Wang
2707093f9d8SSean Wang if (!path)
2717093f9d8SSean Wang return -EINVAL;
2727093f9d8SSean Wang
2737093f9d8SSean Wang /* Setup proper MUXes along the path */
274bb7eae6dSZheng Yongjun return mtk_eth_mux_setup(eth, path);
2757093f9d8SSean Wang }
2767093f9d8SSean Wang
mtk_gmac_rgmii_path_setup(struct mtk_eth * eth,int mac_id)2777e538372SRené van Dorst int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
2787093f9d8SSean Wang {
27951a4df60SLorenzo Bianconi u64 path;
2807093f9d8SSean Wang
2817093f9d8SSean Wang path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII :
2827093f9d8SSean Wang MTK_ETH_PATH_GMAC2_RGMII;
2837093f9d8SSean Wang
2847093f9d8SSean Wang /* Setup proper MUXes along the path */
285bb7eae6dSZheng Yongjun return mtk_eth_mux_setup(eth, path);
2867093f9d8SSean Wang }
2877093f9d8SSean Wang
288