mtk_sgmii.c (4111B)
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/phylink.h> 13#include <linux/regmap.h> 14 15#include "mtk_eth_soc.h" 16 17static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs) 18{ 19 return container_of(pcs, struct mtk_pcs, pcs); 20} 21 22/* For SGMII interface mode */ 23static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) 24{ 25 unsigned int val; 26 27 /* Setup the link timer and QPHY power up inside SGMIISYS */ 28 regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, 29 SGMII_LINK_TIMER_DEFAULT); 30 31 regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); 32 val |= SGMII_REMOTE_FAULT_DIS; 33 regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); 34 35 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); 36 val |= SGMII_AN_RESTART; 37 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); 38 39 regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); 40 val &= ~SGMII_PHYA_PWD; 41 regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); 42 43 return 0; 44 45} 46 47/* For 1000BASE-X and 2500BASE-X interface modes, which operate at a 48 * fixed speed. 49 */ 50static int mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, 51 phy_interface_t interface) 52{ 53 unsigned int val; 54 55 regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); 56 val &= ~RG_PHY_SPEED_MASK; 57 if (interface == PHY_INTERFACE_MODE_2500BASEX) 58 val |= RG_PHY_SPEED_3_125G; 59 regmap_write(mpcs->regmap, mpcs->ana_rgc3, val); 60 61 /* Disable SGMII AN */ 62 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); 63 val &= ~SGMII_AN_ENABLE; 64 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); 65 66 /* Set the speed etc but leave the duplex unchanged */ 67 regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); 68 val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK; 69 val |= SGMII_SPEED_1000; 70 regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); 71 72 /* Release PHYA power down state */ 73 regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); 74 val &= ~SGMII_PHYA_PWD; 75 regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); 76 77 return 0; 78} 79 80static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, 81 phy_interface_t interface, 82 const unsigned long *advertising, 83 bool permit_pause_to_mac) 84{ 85 struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); 86 int err = 0; 87 88 /* Setup SGMIISYS with the determined property */ 89 if (interface != PHY_INTERFACE_MODE_SGMII) 90 err = mtk_pcs_setup_mode_force(mpcs, interface); 91 else if (phylink_autoneg_inband(mode)) 92 err = mtk_pcs_setup_mode_an(mpcs); 93 94 return err; 95} 96 97static void mtk_pcs_restart_an(struct phylink_pcs *pcs) 98{ 99 struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); 100 unsigned int val; 101 102 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); 103 val |= SGMII_AN_RESTART; 104 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); 105} 106 107static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, 108 phy_interface_t interface, int speed, int duplex) 109{ 110 struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); 111 unsigned int val; 112 113 if (!phy_interface_mode_is_8023z(interface)) 114 return; 115 116 /* SGMII force duplex setting */ 117 regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); 118 val &= ~SGMII_DUPLEX_FULL; 119 if (duplex == DUPLEX_FULL) 120 val |= SGMII_DUPLEX_FULL; 121 122 regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); 123} 124 125static const struct phylink_pcs_ops mtk_pcs_ops = { 126 .pcs_config = mtk_pcs_config, 127 .pcs_an_restart = mtk_pcs_restart_an, 128 .pcs_link_up = mtk_pcs_link_up, 129}; 130 131int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) 132{ 133 struct device_node *np; 134 int i; 135 136 for (i = 0; i < MTK_MAX_DEVS; i++) { 137 np = of_parse_phandle(r, "mediatek,sgmiisys", i); 138 if (!np) 139 break; 140 141 ss->pcs[i].ana_rgc3 = ana_rgc3; 142 ss->pcs[i].regmap = syscon_node_to_regmap(np); 143 of_node_put(np); 144 if (IS_ERR(ss->pcs[i].regmap)) 145 return PTR_ERR(ss->pcs[i].regmap); 146 147 ss->pcs[i].pcs.ops = &mtk_pcs_ops; 148 } 149 150 return 0; 151} 152 153struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id) 154{ 155 if (!ss->pcs[id].regmap) 156 return NULL; 157 158 return &ss->pcs[id].pcs; 159}