288 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (c) 2018-2019 MediaTek Inc.3 4/* A library for configuring path from GMAC/GDM to target PHY5 *6 * Author: Sean Wang <sean.wang@mediatek.com>7 *8 */9 10#include <linux/phy.h>11#include <linux/regmap.h>12 13#include "mtk_eth_soc.h"14 15struct mtk_eth_muxc {16 const char *name;17 int cap_bit;18 int (*set_path)(struct mtk_eth *eth, u64 path);19};20 21static const char *mtk_eth_path_name(u64 path)22{23 switch (path) {24 case MTK_ETH_PATH_GMAC1_RGMII:25 return "gmac1_rgmii";26 case MTK_ETH_PATH_GMAC1_TRGMII:27 return "gmac1_trgmii";28 case MTK_ETH_PATH_GMAC1_SGMII:29 return "gmac1_sgmii";30 case MTK_ETH_PATH_GMAC2_RGMII:31 return "gmac2_rgmii";32 case MTK_ETH_PATH_GMAC2_SGMII:33 return "gmac2_sgmii";34 case MTK_ETH_PATH_GMAC2_GEPHY:35 return "gmac2_gephy";36 case MTK_ETH_PATH_GDM1_ESW:37 return "gdm1_esw";38 default:39 return "unknown path";40 }41}42 43static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path)44{45 bool updated = true;46 u32 mask, set, reg;47 48 switch (path) {49 case MTK_ETH_PATH_GMAC1_SGMII:50 mask = ~(u32)MTK_MUX_TO_ESW;51 set = 0;52 break;53 case MTK_ETH_PATH_GDM1_ESW:54 mask = ~(u32)MTK_MUX_TO_ESW;55 set = MTK_MUX_TO_ESW;56 break;57 default:58 updated = false;59 break;60 }61 62 if (mtk_is_netsys_v3_or_greater(eth))63 reg = MTK_MAC_MISC_V3;64 else65 reg = MTK_MAC_MISC;66 67 if (updated)68 mtk_m32(eth, mask, set, reg);69 70 dev_dbg(eth->dev, "path %s in %s updated = %d\n",71 mtk_eth_path_name(path), __func__, updated);72 73 return 0;74}75 76static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path)77{78 unsigned int val = 0;79 bool updated = true;80 81 switch (path) {82 case MTK_ETH_PATH_GMAC2_GEPHY:83 val = ~(u32)GEPHY_MAC_SEL;84 break;85 default:86 updated = false;87 break;88 }89 90 if (updated)91 regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);92 93 dev_dbg(eth->dev, "path %s in %s updated = %d\n",94 mtk_eth_path_name(path), __func__, updated);95 96 return 0;97}98 99static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)100{101 unsigned int val = 0, mask = 0, reg = 0;102 bool updated = true;103 104 switch (path) {105 case MTK_ETH_PATH_GMAC2_SGMII:106 if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {107 reg = USB_PHY_SWITCH_REG;108 val = SGMII_QPHY_SEL;109 mask = QPHY_SEL_MASK;110 } else {111 reg = INFRA_MISC2;112 val = CO_QPHY_SEL;113 mask = val;114 }115 break;116 default:117 updated = false;118 break;119 }120 121 if (updated)122 regmap_update_bits(eth->infra, reg, mask, val);123 124 dev_dbg(eth->dev, "path %s in %s updated = %d\n",125 mtk_eth_path_name(path), __func__, updated);126 127 return 0;128}129 130static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path)131{132 unsigned int val = 0;133 bool updated = true;134 135 switch (path) {136 case MTK_ETH_PATH_GMAC1_SGMII:137 val = SYSCFG0_SGMII_GMAC1;138 break;139 case MTK_ETH_PATH_GMAC2_SGMII:140 val = SYSCFG0_SGMII_GMAC2;141 break;142 case MTK_ETH_PATH_GMAC1_RGMII:143 case MTK_ETH_PATH_GMAC2_RGMII:144 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);145 val &= SYSCFG0_SGMII_MASK;146 147 if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||148 (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))149 val = 0;150 else151 updated = false;152 break;153 default:154 updated = false;155 break;156 }157 158 if (updated)159 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,160 SYSCFG0_SGMII_MASK, val);161 162 dev_dbg(eth->dev, "path %s in %s updated = %d\n",163 mtk_eth_path_name(path), __func__, updated);164 165 return 0;166}167 168static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path)169{170 unsigned int val = 0;171 bool updated = true;172 173 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);174 175 switch (path) {176 case MTK_ETH_PATH_GMAC1_SGMII:177 val |= SYSCFG0_SGMII_GMAC1_V2;178 break;179 case MTK_ETH_PATH_GMAC2_GEPHY:180 val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;181 break;182 case MTK_ETH_PATH_GMAC2_SGMII:183 val |= SYSCFG0_SGMII_GMAC2_V2;184 break;185 default:186 updated = false;187 }188 189 if (updated)190 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,191 SYSCFG0_SGMII_MASK, val);192 193 dev_dbg(eth->dev, "path %s in %s updated = %d\n",194 mtk_eth_path_name(path), __func__, updated);195 196 return 0;197}198 199static const struct mtk_eth_muxc mtk_eth_muxc[] = {200 {201 .name = "mux_gdm1_to_gmac1_esw",202 .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,203 .set_path = set_mux_gdm1_to_gmac1_esw,204 }, {205 .name = "mux_gmac2_gmac0_to_gephy",206 .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,207 .set_path = set_mux_gmac2_gmac0_to_gephy,208 }, {209 .name = "mux_u3_gmac2_to_qphy",210 .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,211 .set_path = set_mux_u3_gmac2_to_qphy,212 }, {213 .name = "mux_gmac1_gmac2_to_sgmii_rgmii",214 .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,215 .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,216 }, {217 .name = "mux_gmac12_to_gephy_sgmii",218 .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,219 .set_path = set_mux_gmac12_to_gephy_sgmii,220 },221};222 223static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path)224{225 int i, err = 0;226 227 if (!MTK_HAS_CAPS(eth->soc->caps, path)) {228 dev_err(eth->dev, "path %s isn't support on the SoC\n",229 mtk_eth_path_name(path));230 return -EINVAL;231 }232 233 if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))234 return 0;235 236 /* Setup MUX in path fabric */237 for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {238 if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {239 err = mtk_eth_muxc[i].set_path(eth, path);240 if (err)241 goto out;242 } else {243 dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",244 mtk_eth_muxc[i].name);245 }246 }247 248out:249 return err;250}251 252int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)253{254 u64 path;255 256 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :257 MTK_ETH_PATH_GMAC2_SGMII;258 259 /* Setup proper MUXes along the path */260 return mtk_eth_mux_setup(eth, path);261}262 263int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)264{265 u64 path = 0;266 267 if (mac_id == 1)268 path = MTK_ETH_PATH_GMAC2_GEPHY;269 270 if (!path)271 return -EINVAL;272 273 /* Setup proper MUXes along the path */274 return mtk_eth_mux_setup(eth, path);275}276 277int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)278{279 u64 path;280 281 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII :282 MTK_ETH_PATH_GMAC2_RGMII;283 284 /* Setup proper MUXes along the path */285 return mtk_eth_mux_setup(eth, path);286}287 288