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, int path); 19 }; 20 21 static const char *mtk_eth_path_name(int 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, int path) 44 { 45 bool updated = true; 46 u32 val, mask, set; 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 (updated) { 63 val = mtk_r32(eth, MTK_MAC_MISC); 64 val = (val & mask) | set; 65 mtk_w32(eth, val, MTK_MAC_MISC); 66 } 67 68 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 69 mtk_eth_path_name(path), __func__, updated); 70 71 return 0; 72 } 73 74 static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path) 75 { 76 unsigned int val = 0; 77 bool updated = true; 78 79 switch (path) { 80 case MTK_ETH_PATH_GMAC2_GEPHY: 81 val = ~(u32)GEPHY_MAC_SEL; 82 break; 83 default: 84 updated = false; 85 break; 86 } 87 88 if (updated) 89 regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val); 90 91 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 92 mtk_eth_path_name(path), __func__, updated); 93 94 return 0; 95 } 96 97 static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) 98 { 99 unsigned int val = 0, mask = 0, reg = 0; 100 bool updated = true; 101 102 switch (path) { 103 case MTK_ETH_PATH_GMAC2_SGMII: 104 if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) { 105 reg = USB_PHY_SWITCH_REG; 106 val = SGMII_QPHY_SEL; 107 mask = QPHY_SEL_MASK; 108 } else { 109 reg = INFRA_MISC2; 110 val = CO_QPHY_SEL; 111 mask = val; 112 } 113 break; 114 default: 115 updated = false; 116 break; 117 } 118 119 if (updated) 120 regmap_update_bits(eth->infra, reg, mask, val); 121 122 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 123 mtk_eth_path_name(path), __func__, updated); 124 125 return 0; 126 } 127 128 static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path) 129 { 130 unsigned int val = 0; 131 bool updated = true; 132 133 switch (path) { 134 case MTK_ETH_PATH_GMAC1_SGMII: 135 val = SYSCFG0_SGMII_GMAC1; 136 break; 137 case MTK_ETH_PATH_GMAC2_SGMII: 138 val = SYSCFG0_SGMII_GMAC2; 139 break; 140 case MTK_ETH_PATH_GMAC1_RGMII: 141 case MTK_ETH_PATH_GMAC2_RGMII: 142 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); 143 val &= SYSCFG0_SGMII_MASK; 144 145 if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) || 146 (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2)) 147 val = 0; 148 else 149 updated = false; 150 break; 151 default: 152 updated = false; 153 break; 154 } 155 156 if (updated) 157 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, 158 SYSCFG0_SGMII_MASK, val); 159 160 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 161 mtk_eth_path_name(path), __func__, updated); 162 163 return 0; 164 } 165 166 static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path) 167 { 168 unsigned int val = 0; 169 bool updated = true; 170 171 regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); 172 173 switch (path) { 174 case MTK_ETH_PATH_GMAC1_SGMII: 175 val |= SYSCFG0_SGMII_GMAC1_V2; 176 break; 177 case MTK_ETH_PATH_GMAC2_GEPHY: 178 val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; 179 break; 180 case MTK_ETH_PATH_GMAC2_SGMII: 181 val |= SYSCFG0_SGMII_GMAC2_V2; 182 break; 183 default: 184 updated = false; 185 } 186 187 if (updated) 188 regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, 189 SYSCFG0_SGMII_MASK, val); 190 191 dev_dbg(eth->dev, "path %s in %s updated = %d\n", 192 mtk_eth_path_name(path), __func__, updated); 193 194 return 0; 195 } 196 197 static const struct mtk_eth_muxc mtk_eth_muxc[] = { 198 { 199 .name = "mux_gdm1_to_gmac1_esw", 200 .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW, 201 .set_path = set_mux_gdm1_to_gmac1_esw, 202 }, { 203 .name = "mux_gmac2_gmac0_to_gephy", 204 .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY, 205 .set_path = set_mux_gmac2_gmac0_to_gephy, 206 }, { 207 .name = "mux_u3_gmac2_to_qphy", 208 .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY, 209 .set_path = set_mux_u3_gmac2_to_qphy, 210 }, { 211 .name = "mux_gmac1_gmac2_to_sgmii_rgmii", 212 .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, 213 .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, 214 }, { 215 .name = "mux_gmac12_to_gephy_sgmii", 216 .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, 217 .set_path = set_mux_gmac12_to_gephy_sgmii, 218 }, 219 }; 220 221 static int mtk_eth_mux_setup(struct mtk_eth *eth, int path) 222 { 223 int i, err = 0; 224 225 if (!MTK_HAS_CAPS(eth->soc->caps, path)) { 226 dev_err(eth->dev, "path %s isn't support on the SoC\n", 227 mtk_eth_path_name(path)); 228 return -EINVAL; 229 } 230 231 if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX)) 232 return 0; 233 234 /* Setup MUX in path fabric */ 235 for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) { 236 if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) { 237 err = mtk_eth_muxc[i].set_path(eth, path); 238 if (err) 239 goto out; 240 } else { 241 dev_dbg(eth->dev, "mux %s isn't present on the SoC\n", 242 mtk_eth_muxc[i].name); 243 } 244 } 245 246 out: 247 return err; 248 } 249 250 int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) 251 { 252 int path; 253 254 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : 255 MTK_ETH_PATH_GMAC2_SGMII; 256 257 /* Setup proper MUXes along the path */ 258 return mtk_eth_mux_setup(eth, path); 259 } 260 261 int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) 262 { 263 int path = 0; 264 265 if (mac_id == 1) 266 path = MTK_ETH_PATH_GMAC2_GEPHY; 267 268 if (!path) 269 return -EINVAL; 270 271 /* Setup proper MUXes along the path */ 272 return mtk_eth_mux_setup(eth, path); 273 } 274 275 int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) 276 { 277 int path; 278 279 path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII : 280 MTK_ETH_PATH_GMAC2_RGMII; 281 282 /* Setup proper MUXes along the path */ 283 return mtk_eth_mux_setup(eth, path); 284 } 285 286