1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2018-2019 MediaTek Inc. 3 4/* A library for MediaTek SGMII circuit 5 * 6 * Author: Sean Wang <sean.wang@mediatek.com> 7 * 8 */ 9 10#include <linux/mfd/syscon.h> 11#include <linux/of.h> 12#include <linux/regmap.h> 13 14#include "mtk_eth_soc.h" 15 16int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) 17{ 18 struct device_node *np; 19 int i; 20 21 ss->ana_rgc3 = ana_rgc3; 22 23 for (i = 0; i < MTK_MAX_DEVS; i++) { 24 np = of_parse_phandle(r, "mediatek,sgmiisys", i); 25 if (!np) 26 break; 27 28 ss->regmap[i] = syscon_node_to_regmap(np); 29 of_node_put(np); 30 if (IS_ERR(ss->regmap[i])) 31 return PTR_ERR(ss->regmap[i]); 32 } 33 34 return 0; 35} 36 37int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) 38{ 39 unsigned int val; 40 41 if (!ss->regmap[id]) 42 return -EINVAL; 43 44 /* Setup the link timer and QPHY power up inside SGMIISYS */ 45 regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER, 46 SGMII_LINK_TIMER_DEFAULT); 47 48 regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); 49 val |= SGMII_REMOTE_FAULT_DIS; 50 regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); 51 52 regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); 53 val |= SGMII_AN_RESTART; 54 regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); 55 56 regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); 57 val &= ~SGMII_PHYA_PWD; 58 regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); 59 60 return 0; 61} 62 63int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, 64 const struct phylink_link_state *state) 65{ 66 unsigned int val; 67 68 if (!ss->regmap[id]) 69 return -EINVAL; 70 71 regmap_read(ss->regmap[id], ss->ana_rgc3, &val); 72 val &= ~RG_PHY_SPEED_MASK; 73 if (state->interface == PHY_INTERFACE_MODE_2500BASEX) 74 val |= RG_PHY_SPEED_3_125G; 75 regmap_write(ss->regmap[id], ss->ana_rgc3, val); 76 77 /* Disable SGMII AN */ 78 regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); 79 val &= ~SGMII_AN_ENABLE; 80 regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); 81 82 /* SGMII force mode setting */ 83 regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); 84 val &= ~SGMII_IF_MODE_MASK; 85 86 switch (state->speed) { 87 case SPEED_10: 88 val |= SGMII_SPEED_10; 89 break; 90 case SPEED_100: 91 val |= SGMII_SPEED_100; 92 break; 93 case SPEED_2500: 94 case SPEED_1000: 95 val |= SGMII_SPEED_1000; 96 break; 97 } 98 99 if (state->duplex == DUPLEX_FULL) 100 val |= SGMII_DUPLEX_FULL; 101 102 regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); 103 104 /* Release PHYA power down state */ 105 regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); 106 val &= ~SGMII_PHYA_PWD; 107 regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); 108 109 return 0; 110} 111 112void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id) 113{ 114 struct mtk_sgmii *ss = eth->sgmii; 115 unsigned int val, sid; 116 117 /* Decide how GMAC and SGMIISYS be mapped */ 118 sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 119 0 : mac_id; 120 121 if (!ss->regmap[sid]) 122 return; 123 124 regmap_read(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, &val); 125 val |= SGMII_AN_RESTART; 126 regmap_write(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, val); 127} 128