blob: 8198c7cb592d26b3e652dc992e805687a987b41c [file] [log] [blame]
developerfd40db22021-04-29 10:08:25 +08001// 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 if (IS_ERR(ss->regmap[i]))
30 return PTR_ERR(ss->regmap[i]);
developerf8ac94a2021-07-29 16:40:01 +080031
32 ss->flags[i] &= ~(MTK_SGMII_PN_SWAP);
33 if (of_property_read_bool(np, "pn_swap"))
34 ss->flags[i] |= MTK_SGMII_PN_SWAP;
developerfd40db22021-04-29 10:08:25 +080035 }
36
37 return 0;
38}
39
developerfb556ca2021-10-13 10:52:09 +080040int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, unsigned int id)
developerfd40db22021-04-29 10:08:25 +080041{
42 unsigned int val;
43
44 if (!ss->regmap[id])
45 return -EINVAL;
46
developer2fbee452022-08-12 13:58:20 +080047 /* Assert PHYA power down state */
48 regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
49
50 regmap_read(ss->regmap[id], ss->ana_rgc3, &val);
51 val &= ~RG_PHY_SPEED_3_125G;
52 regmap_write(ss->regmap[id], ss->ana_rgc3, val);
53
developerfd40db22021-04-29 10:08:25 +080054 /* Setup the link timer and QPHY power up inside SGMIISYS */
55 regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER,
56 SGMII_LINK_TIMER_DEFAULT);
57
58 regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
59 val |= SGMII_REMOTE_FAULT_DIS;
60 regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
61
developer2fbee452022-08-12 13:58:20 +080062 /* SGMII AN mode setting */
63 regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
64 val &= ~SGMII_IF_MODE_MASK;
65 val |= SGMII_SPEED_DUPLEX_AN;
66 regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
67
developerfd40db22021-04-29 10:08:25 +080068 regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
69 val |= SGMII_AN_RESTART;
developer2fbee452022-08-12 13:58:20 +080070 val |= SGMII_AN_ENABLE;
developerfd40db22021-04-29 10:08:25 +080071 regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
72
developerf8ac94a2021-07-29 16:40:01 +080073 if(MTK_HAS_FLAGS(ss->flags[id],MTK_SGMII_PN_SWAP))
74 regmap_update_bits(ss->regmap[id], SGMSYS_QPHY_WRAP_CTRL,
75 SGMII_PN_SWAP_MASK, SGMII_PN_SWAP_TX_RX);
76
developer3d014da2022-05-11 16:29:59 +080077 /* Release PHYA power down state */
78 regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
developerfd40db22021-04-29 10:08:25 +080079
80 return 0;
81}
82
developerfb556ca2021-10-13 10:52:09 +080083int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, unsigned int id,
developerfd40db22021-04-29 10:08:25 +080084 const struct phylink_link_state *state)
85{
86 unsigned int val;
87
88 if (!ss->regmap[id])
89 return -EINVAL;
90
developer2fbee452022-08-12 13:58:20 +080091 /* Assert PHYA power down state */
92 regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
93
developerfd40db22021-04-29 10:08:25 +080094 regmap_read(ss->regmap[id], ss->ana_rgc3, &val);
95 val &= ~RG_PHY_SPEED_MASK;
96 if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
97 val |= RG_PHY_SPEED_3_125G;
98 regmap_write(ss->regmap[id], ss->ana_rgc3, val);
99
100 /* Disable SGMII AN */
101 regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
102 val &= ~SGMII_AN_ENABLE;
103 regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
104
105 /* SGMII force mode setting */
106 regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
107 val &= ~SGMII_IF_MODE_MASK;
108
109 switch (state->speed) {
110 case SPEED_10:
111 val |= SGMII_SPEED_10;
112 break;
113 case SPEED_100:
114 val |= SGMII_SPEED_100;
115 break;
116 case SPEED_2500:
117 case SPEED_1000:
118 val |= SGMII_SPEED_1000;
119 break;
120 };
121
122 if (state->duplex == DUPLEX_FULL)
123 val |= SGMII_DUPLEX_FULL;
124
125 regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
126
developerf8ac94a2021-07-29 16:40:01 +0800127 if(MTK_HAS_FLAGS(ss->flags[id],MTK_SGMII_PN_SWAP))
128 regmap_update_bits(ss->regmap[id], SGMSYS_QPHY_WRAP_CTRL,
129 SGMII_PN_SWAP_MASK, SGMII_PN_SWAP_TX_RX);
developer3d014da2022-05-11 16:29:59 +0800130
developerfd40db22021-04-29 10:08:25 +0800131 /* Release PHYA power down state */
developer3d014da2022-05-11 16:29:59 +0800132 regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
developerfd40db22021-04-29 10:08:25 +0800133
134 return 0;
135}
136
137void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id)
138{
139 struct mtk_sgmii *ss = eth->sgmii;
140 unsigned int val, sid;
141
142 /* Decide how GMAC and SGMIISYS be mapped */
143 sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
144 0 : mac_id;
145
146 if (!ss->regmap[sid])
147 return;
148
149 regmap_read(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, &val);
150 val |= SGMII_AN_RESTART;
151 regmap_write(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, val);
152}