]> git.ipfire.org Git - thirdparty/openwrt.git/blob
3bf5f1f7989e0d6b77dd3e8c9d681f7b6008a58d
[thirdparty/openwrt.git] /
1 From a2e687df29e457621616d5d769688e6c972f9ac6 Mon Sep 17 00:00:00 2001
2 From: Lei Wei <quic_leiwei@quicinc.com>
3 Date: Tue, 2 Apr 2024 18:28:42 +0800
4 Subject: [PATCH] net: pcs: Add 2500BASEX interface mode support to IPQ UNIPHY
5 PCS driver
6
7 2500BASEX mode is used when PCS connects with QCA8386 switch in a fixed
8 2500M link. It is also used when PCS connectes with QCA8081 PHY which
9 works at 2500M link speed. In addition, it can be also used when PCS
10 connects with a 2.5G SFP module.
11
12 Change-Id: I3fe61113c1b3685debc20659736a9488216a029d
13 Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
14 Alex G: use regmap to read/write registers
15 Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
16 ---
17 drivers/net/pcs/pcs-qcom-ipq9574.c | 94 ++++++++++++++++++++++++++++++
18 1 file changed, 94 insertions(+)
19
20 --- a/drivers/net/pcs/pcs-qcom-ipq9574.c
21 +++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
22 @@ -29,6 +29,7 @@
23 #define PCS_MODE_SGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x4)
24 #define PCS_MODE_QSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
25 #define PCS_MODE_PSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x2)
26 +#define PCS_MODE_SGMII_PLUS FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
27 #define PCS_MODE_XPCS FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
28
29 #define PCS_MII_CTRL(x) (0x480 + 0x18 * (x))
30 @@ -188,6 +189,30 @@ static void ipq_pcs_get_state_sgmii(stru
31 state->pause |= MLO_PAUSE_RX;
32 }
33
34 +static void ipq_unipcs_get_state_2500basex(struct ipq_pcs *qpcs,
35 + int index,
36 + struct phylink_link_state *state)
37 +{
38 + unsigned int val;
39 + int ret;
40 +
41 + ret = regmap_read(qpcs->regmap, PCS_MII_STS(index), &val);
42 + if (ret) {
43 + state->link = 0;
44 + return;
45 + }
46 +
47 +
48 + state->link = !!(val & PCS_MII_LINK_STS);
49 +
50 + if (!state->link)
51 + return;
52 +
53 + state->speed = SPEED_2500;
54 + state->duplex = DUPLEX_FULL;
55 + state->pause |= MLO_PAUSE_TXRX_MASK;
56 +}
57 +
58 static void ipq_pcs_get_state_usxgmii(struct ipq_pcs *qpcs,
59 struct phylink_link_state *state)
60 {
61 @@ -272,6 +297,10 @@ static int ipq_pcs_config_mode(struct ip
62 case PHY_INTERFACE_MODE_QSGMII:
63 val = PCS_MODE_QSGMII;
64 break;
65 + case PHY_INTERFACE_MODE_2500BASEX:
66 + val = PCS_MODE_SGMII_PLUS;
67 + rate = 312500000;
68 + break;
69 case PHY_INTERFACE_MODE_PSGMII:
70 val = PCS_MODE_PSGMII;
71 break;
72 @@ -355,6 +384,22 @@ static int ipq_pcs_config_sgmii(struct i
73 PCS_MII_CTRL(index), PCS_MII_FORCE_MODE);
74 }
75
76 +static int ipq_unipcs_config_2500basex(struct ipq_pcs *qpcs,
77 + phy_interface_t interface)
78 +{
79 + int ret;
80 +
81 + if (qpcs->interface != interface) {
82 + ret = ipq_pcs_config_mode(qpcs, interface);
83 + if (ret)
84 + return ret;
85 +
86 + qpcs->interface = interface;
87 + }
88 +
89 + return 0;
90 +}
91 +
92 static int ipq_pcs_config_usxgmii(struct ipq_pcs *qpcs)
93 {
94 int ret;
95 @@ -421,6 +466,21 @@ static unsigned long ipq_unipcs_clock_ra
96 return rate;
97 }
98
99 +static unsigned long ipq_unipcs_clock_rate_get_gmiiplus(int speed)
100 +{
101 + unsigned long rate = 0;
102 +
103 + switch (speed) {
104 + case SPEED_2500:
105 + rate = 312500000;
106 + break;
107 + default:
108 + break;
109 + }
110 +
111 + return rate;
112 +}
113 +
114 static unsigned long ipq_unipcs_clock_rate_get_xgmii(int speed)
115 {
116 unsigned long rate = 0;
117 @@ -465,6 +525,9 @@ ipq_unipcs_link_up_clock_rate_set(struct
118 case PHY_INTERFACE_MODE_PSGMII:
119 rate = ipq_unipcs_clock_rate_get_gmii(speed);
120 break;
121 + case PHY_INTERFACE_MODE_2500BASEX:
122 + rate = ipq_unipcs_clock_rate_get_gmiiplus(speed);
123 + break;
124 case PHY_INTERFACE_MODE_USXGMII:
125 case PHY_INTERFACE_MODE_10GBASER:
126 rate = ipq_unipcs_clock_rate_get_xgmii(speed);
127 @@ -528,6 +591,25 @@ static int ipq_pcs_link_up_config_sgmii(
128 PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
129 }
130
131 +static int ipq_unipcs_link_up_config_2500basex(struct ipq_pcs *qpcs,
132 + int index,
133 + int speed)
134 +{
135 + unsigned int val;
136 + int ret;
137 +
138 + /* 2500BASEX do not support autoneg and do not need to
139 + * configure PCS speed, only reset PCS adapter here.
140 + */
141 + ret = regmap_clear_bits(qpcs->regmap,
142 + PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
143 + if (ret)
144 + return ret;
145 +
146 + return regmap_set_bits(qpcs->regmap,
147 + PCS_MII_CTRL(index), PCS_MII_ADPT_RESET);
148 +}
149 +
150 static int ipq_pcs_link_up_config_usxgmii(struct ipq_pcs *qpcs, int speed)
151 {
152 unsigned int val;
153 @@ -575,6 +657,10 @@ static int ipq_pcs_validate(struct phyli
154 case PHY_INTERFACE_MODE_SGMII:
155 case PHY_INTERFACE_MODE_QSGMII:
156 return 0;
157 + case PHY_INTERFACE_MODE_2500BASEX:
158 + /* In-band autoneg is not supported for 2500BASEX */
159 + phylink_clear(supported, Autoneg);
160 + return 0;
161 case PHY_INTERFACE_MODE_USXGMII:
162 /* USXGMII only supports full duplex mode */
163 phylink_clear(supported, 100baseT_Half);
164 @@ -645,6 +731,9 @@ static void ipq_pcs_get_state(struct phy
165 case PHY_INTERFACE_MODE_PSGMII:
166 ipq_pcs_get_state_sgmii(qpcs, index, state);
167 break;
168 + case PHY_INTERFACE_MODE_2500BASEX:
169 + ipq_unipcs_get_state_2500basex(qpcs, index, state);
170 + break;
171 case PHY_INTERFACE_MODE_USXGMII:
172 ipq_pcs_get_state_usxgmii(qpcs, state);
173 break;
174 @@ -678,6 +767,8 @@ static int ipq_pcs_config(struct phylink
175 case PHY_INTERFACE_MODE_QSGMII:
176 case PHY_INTERFACE_MODE_PSGMII:
177 return ipq_pcs_config_sgmii(qpcs, index, neg_mode, interface);
178 + case PHY_INTERFACE_MODE_2500BASEX:
179 + return ipq_unipcs_config_2500basex(qpcs, interface);
180 case PHY_INTERFACE_MODE_USXGMII:
181 return ipq_pcs_config_usxgmii(qpcs);
182 case PHY_INTERFACE_MODE_10GBASER:
183 @@ -710,6 +801,9 @@ static void ipq_pcs_link_up(struct phyli
184 ret = ipq_pcs_link_up_config_sgmii(qpcs, index,
185 neg_mode, speed);
186 break;
187 + case PHY_INTERFACE_MODE_2500BASEX:
188 + ret = ipq_unipcs_link_up_config_2500basex(qpcs, index, speed);
189 + break;
190 case PHY_INTERFACE_MODE_USXGMII:
191 ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
192 break;