0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/of.h>
0012 #include <linux/phylink.h>
0013 #include <linux/regmap.h>
0014
0015 #include "mtk_eth_soc.h"
0016
0017 static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs)
0018 {
0019 return container_of(pcs, struct mtk_pcs, pcs);
0020 }
0021
0022
0023 static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs)
0024 {
0025 unsigned int val;
0026
0027
0028 regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
0029 SGMII_LINK_TIMER_DEFAULT);
0030
0031 regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
0032 val |= SGMII_REMOTE_FAULT_DIS;
0033 regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
0034
0035 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
0036 val |= SGMII_AN_RESTART;
0037 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
0038
0039 regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
0040 val &= ~SGMII_PHYA_PWD;
0041 regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val);
0042
0043 return 0;
0044
0045 }
0046
0047
0048
0049
0050 static int mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs,
0051 phy_interface_t interface)
0052 {
0053 unsigned int val;
0054
0055 regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
0056 val &= ~RG_PHY_SPEED_MASK;
0057 if (interface == PHY_INTERFACE_MODE_2500BASEX)
0058 val |= RG_PHY_SPEED_3_125G;
0059 regmap_write(mpcs->regmap, mpcs->ana_rgc3, val);
0060
0061
0062 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
0063 val &= ~SGMII_AN_ENABLE;
0064 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
0065
0066
0067 regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
0068 val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK;
0069 val |= SGMII_SPEED_1000;
0070 regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
0071
0072
0073 regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
0074 val &= ~SGMII_PHYA_PWD;
0075 regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val);
0076
0077 return 0;
0078 }
0079
0080 static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
0081 phy_interface_t interface,
0082 const unsigned long *advertising,
0083 bool permit_pause_to_mac)
0084 {
0085 struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
0086 int err = 0;
0087
0088
0089 if (interface != PHY_INTERFACE_MODE_SGMII)
0090 err = mtk_pcs_setup_mode_force(mpcs, interface);
0091 else if (phylink_autoneg_inband(mode))
0092 err = mtk_pcs_setup_mode_an(mpcs);
0093
0094 return err;
0095 }
0096
0097 static void mtk_pcs_restart_an(struct phylink_pcs *pcs)
0098 {
0099 struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
0100 unsigned int val;
0101
0102 regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
0103 val |= SGMII_AN_RESTART;
0104 regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
0105 }
0106
0107 static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
0108 phy_interface_t interface, int speed, int duplex)
0109 {
0110 struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
0111 unsigned int val;
0112
0113 if (!phy_interface_mode_is_8023z(interface))
0114 return;
0115
0116
0117 regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
0118 val &= ~SGMII_DUPLEX_FULL;
0119 if (duplex == DUPLEX_FULL)
0120 val |= SGMII_DUPLEX_FULL;
0121
0122 regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
0123 }
0124
0125 static const struct phylink_pcs_ops mtk_pcs_ops = {
0126 .pcs_config = mtk_pcs_config,
0127 .pcs_an_restart = mtk_pcs_restart_an,
0128 .pcs_link_up = mtk_pcs_link_up,
0129 };
0130
0131 int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
0132 {
0133 struct device_node *np;
0134 int i;
0135
0136 for (i = 0; i < MTK_MAX_DEVS; i++) {
0137 np = of_parse_phandle(r, "mediatek,sgmiisys", i);
0138 if (!np)
0139 break;
0140
0141 ss->pcs[i].ana_rgc3 = ana_rgc3;
0142 ss->pcs[i].regmap = syscon_node_to_regmap(np);
0143 of_node_put(np);
0144 if (IS_ERR(ss->pcs[i].regmap))
0145 return PTR_ERR(ss->pcs[i].regmap);
0146
0147 ss->pcs[i].pcs.ops = &mtk_pcs_ops;
0148 }
0149
0150 return 0;
0151 }
0152
0153 struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id)
0154 {
0155 if (!ss->pcs[id].regmap)
0156 return NULL;
0157
0158 return &ss->pcs[id].pcs;
0159 }