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 int 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_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 43 static 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 else 65 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 76 static 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 99 static 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 130 static 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 else 151 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 168 static 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 199 static 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 223 static 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 248 out: 249 return err; 250 } 251 252 int 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 263 int 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 277 int 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