1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2018-2019 MediaTek Inc. 3 4 /* A library for configuring path from GMAC/GDM to target PHY 5 * 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 15 struct mtk_eth_muxc { 16 const char *name; 17 u64 cap_bit; 18 int (*set_path)(struct mtk_eth *eth, u64 path); 19 }; 20 21 static 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_2P5GPHY: 35 return "gmac2_2p5gphy"; 36 case MTK_ETH_PATH_GMAC2_GEPHY: 37 return "gmac2_gephy"; 38 case MTK_ETH_PATH_GDM1_ESW: 39 return "gdm1_esw"; 40 default: 41 return "unknown path"; 42 } 43 } 44 45 static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path) 46 { 47 bool updated = true; 48 u32 mask, set, reg; 49 50 switch (path) { 51 case MTK_ETH_PATH_GMAC1_SGMII: 52 mask = ~(u32)MTK_MUX_TO_ESW; 53 set = 0; 54 break; 55 case MTK_ETH_PATH_GDM1_ESW: 56 mask = ~(u32)MTK_MUX_TO_ESW; 57 set = MTK_MUX_TO_ESW; 58 break; 59 default: 60 updated = false; 61 break; 62 } 63 64 if (mtk_is_netsys_v3_or_greater(eth)) 65 reg = MTK_MAC_MISC_V3; 66 else 67 reg = MTK_MAC_MISC; 68 69 if (updated) 70 mtk_m32(eth, mask, set, reg); 71 72 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 73 mtk_eth_path_name(path), __func__, updated); 74 75 return 0; 76 } 77 78 static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path) 79 { 80 unsigned int val = 0; 81 bool updated = true; 82 83 switch (path) { 84 case MTK_ETH_PATH_GMAC2_GEPHY: 85 val = ~(u32)GEPHY_MAC_SEL; 86 break; 87 default: 88 updated = false; 89 break; 90 } 91 92 if (updated) 93 regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val); 94 95 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 96 mtk_eth_path_name(path), __func__, updated); 97 98 return 0; 99 } 100 101 static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path) 102 { 103 unsigned int val = 0, mask = 0, reg = 0; 104 bool updated = true; 105 106 switch (path) { 107 case MTK_ETH_PATH_GMAC2_SGMII: 108 if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) { 109 reg = USB_PHY_SWITCH_REG; 110 val = SGMII_QPHY_SEL; 111 mask = QPHY_SEL_MASK; 112 } else { 113 reg = INFRA_MISC2; 114 val = CO_QPHY_SEL; 115 mask = val; 116 } 117 break; 118 default: 119 updated = false; 120 break; 121 } 122 123 if (updated) 124 regmap_update_bits(eth->infra, reg, mask, val); 125 126 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 127 mtk_eth_path_name(path), __func__, updated); 128 129 return 0; 130 } 131 132 static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path) 133 { 134 int ret; 135 136 if (path == MTK_ETH_PATH_GMAC2_2P5GPHY) { 137 ret = regmap_clear_bits(eth->ethsys, ETHSYS_SYSCFG0, 138 SYSCFG0_SGMII_GMAC2_V2); 139 if (ret) 140 return ret; 141 142 /* Setup mux to 2p5g PHY */ 143 ret = regmap_clear_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX, 144 MUX_G2_USXGMII_SEL); 145 if (ret) 146 return ret; 147 148 dev_dbg(eth->dev, "path %s in %s updated\n", 149 mtk_eth_path_name(path), __func__); 150 } 151 152 return 0; 153 } 154 155 static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) 156 { 157 unsigned int val = 0; 158 bool updated = true; 159 160 switch (path) { 161 case MTK_ETH_PATH_GMAC1_SGMII: 162 val = SYSCFG0_SGMII_GMAC1; 163 break; 164 case MTK_ETH_PATH_GMAC2_SGMII: 165 val = SYSCFG0_SGMII_GMAC2; 166 break; 167 case MTK_ETH_PATH_GMAC1_RGMII: 168 case MTK_ETH_PATH_GMAC2_RGMII: 169 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); 170 val &= SYSCFG0_SGMII_MASK; 171 172 if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) || 173 (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2)) 174 val = 0; 175 else 176 updated = false; 177 break; 178 default: 179 updated = false; 180 break; 181 } 182 183 if (updated) 184 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, 185 SYSCFG0_SGMII_MASK, val); 186 187 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 188 mtk_eth_path_name(path), __func__, updated); 189 190 return 0; 191 } 192 193 static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) 194 { 195 unsigned int val = 0; 196 bool updated = true; 197 198 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); 199 200 switch (path) { 201 case MTK_ETH_PATH_GMAC1_SGMII: 202 val |= SYSCFG0_SGMII_GMAC1_V2; 203 break; 204 case MTK_ETH_PATH_GMAC2_GEPHY: 205 val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; 206 break; 207 case MTK_ETH_PATH_GMAC2_SGMII: 208 val |= SYSCFG0_SGMII_GMAC2_V2; 209 break; 210 default: 211 updated = false; 212 } 213 214 if (updated) 215 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, 216 SYSCFG0_SGMII_MASK, val); 217 218 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 219 mtk_eth_path_name(path), __func__, updated); 220 221 return 0; 222 } 223 224 static const struct mtk_eth_muxc mtk_eth_muxc[] = { 225 { 226 .name = "mux_gdm1_to_gmac1_esw", 227 .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW, 228 .set_path = set_mux_gdm1_to_gmac1_esw, 229 }, { 230 .name = "mux_gmac2_gmac0_to_gephy", 231 .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY, 232 .set_path = set_mux_gmac2_gmac0_to_gephy, 233 }, { 234 .name = "mux_u3_gmac2_to_qphy", 235 .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY, 236 .set_path = set_mux_u3_gmac2_to_qphy, 237 }, { 238 .name = "mux_gmac2_to_2p5gphy", 239 .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY, 240 .set_path = set_mux_gmac2_to_2p5gphy, 241 }, { 242 .name = "mux_gmac1_gmac2_to_sgmii_rgmii", 243 .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, 244 .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, 245 }, { 246 .name = "mux_gmac12_to_gephy_sgmii", 247 .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, 248 .set_path = set_mux_gmac12_to_gephy_sgmii, 249 }, 250 }; 251 252 static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path) 253 { 254 int i, err = 0; 255 256 if (!MTK_HAS_CAPS(eth->soc->caps, path)) { 257 dev_err(eth->dev, "path %s isn't support on the SoC\n", 258 mtk_eth_path_name(path)); 259 return -EINVAL; 260 } 261 262 if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX)) 263 return 0; 264 265 /* Setup MUX in path fabric */ 266 for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) { 267 if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) { 268 err = mtk_eth_muxc[i].set_path(eth, path); 269 if (err) 270 goto out; 271 } else { 272 dev_dbg(eth->dev, "mux %s isn't present on the SoC\n", 273 mtk_eth_muxc[i].name); 274 } 275 } 276 277 out: 278 return err; 279 } 280 281 int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) 282 { 283 u64 path; 284 285 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : 286 MTK_ETH_PATH_GMAC2_SGMII; 287 288 /* Setup proper MUXes along the path */ 289 return mtk_eth_mux_setup(eth, path); 290 } 291 292 int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id) 293 { 294 u64 path = 0; 295 296 if (mac_id == MTK_GMAC2_ID) 297 path = MTK_ETH_PATH_GMAC2_2P5GPHY; 298 299 if (!path) 300 return -EINVAL; 301 302 /* Setup proper MUXes along the path */ 303 return mtk_eth_mux_setup(eth, path); 304 } 305 306 int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) 307 { 308 u64 path = 0; 309 310 if (mac_id == 1) 311 path = MTK_ETH_PATH_GMAC2_GEPHY; 312 313 if (!path) 314 return -EINVAL; 315 316 /* Setup proper MUXes along the path */ 317 return mtk_eth_mux_setup(eth, path); 318 } 319 320 int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) 321 { 322 u64 path; 323 324 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII : 325 MTK_ETH_PATH_GMAC2_RGMII; 326 327 /* Setup proper MUXes along the path */ 328 return mtk_eth_mux_setup(eth, path); 329 } 330 331