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