529f9f7005ac784bbd305a6dc8a6ed12e47bb639
[openwrt/openwrt.git] /
1 From e770b36f0353fd11c4628360fe412acb7f02f346 Mon Sep 17 00:00:00 2001
2 From: Lei Wei <quic_leiwei@quicinc.com>
3 Date: Wed, 6 Mar 2024 17:40:52 +0800
4 Subject: [PATCH] net: pcs: Add 10GBASER interface mode support to IPQ UNIPHY
5 PCS driver
6
7 10GBASER mode is used when PCS connects with a 10G SFP module.
8
9 Change-Id: Ifc3c3bb23811807a9b34e88771aab2c830c2327c
10 Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
11 Alex G: Use regmap to read/write registers
12 Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
13 ---
14 drivers/net/pcs/pcs-qcom-ipq9574.c | 53 ++++++++++++++++++++++++++++++
15 1 file changed, 53 insertions(+)
16
17 --- a/drivers/net/pcs/pcs-qcom-ipq9574.c
18 +++ b/drivers/net/pcs/pcs-qcom-ipq9574.c
19 @@ -60,6 +60,9 @@
20 FIELD_PREP(GENMASK(9, 2), \
21 FIELD_GET(XPCS_INDIRECT_ADDR_L, reg)))
22
23 +#define XPCS_10GBASER_STS 0x30020
24 +#define XPCS_10GBASER_LINK_STS BIT(12)
25 +
26 #define XPCS_DIG_CTRL 0x38000
27 #define XPCS_USXG_ADPT_RESET BIT(10)
28 #define XPCS_USXG_EN BIT(9)
29 @@ -229,6 +232,28 @@ static void ipq_pcs_get_state_usxgmii(st
30 state->duplex = DUPLEX_FULL;
31 }
32
33 +static void ipq_unipcs_get_state_10gbaser(struct ipq_pcs *qpcs,
34 + struct phylink_link_state *state)
35 +{
36 + unsigned int val;
37 + int ret;
38 +
39 + ret = regmap_read(qpcs->regmap, XPCS_10GBASER_STS, &val);
40 + if (ret) {
41 + state->link = 0;
42 + return;
43 + }
44 +
45 + state->link = !!(val & XPCS_10GBASER_LINK_STS);
46 +
47 + if (!state->link)
48 + return;
49 +
50 + state->speed = SPEED_10000;
51 + state->duplex = DUPLEX_FULL;
52 + state->pause |= MLO_PAUSE_TXRX_MASK;
53 +}
54 +
55 static int ipq_pcs_config_mode(struct ipq_pcs *qpcs,
56 phy_interface_t interface)
57 {
58 @@ -251,6 +276,7 @@ static int ipq_pcs_config_mode(struct ip
59 val = PCS_MODE_PSGMII;
60 break;
61 case PHY_INTERFACE_MODE_USXGMII:
62 + case PHY_INTERFACE_MODE_10GBASER:
63 val = PCS_MODE_XPCS;
64 rate = 312500000;
65 break;
66 @@ -355,6 +381,25 @@ static int ipq_pcs_config_usxgmii(struct
67 return regmap_set_bits(qpcs->regmap, XPCS_MII_CTRL, XPCS_MII_AN_EN);
68 }
69
70 +static int ipq_unipcs_config_10gbaser(struct ipq_pcs *qpcs,
71 + phy_interface_t interface)
72 +{
73 + int ret;
74 +
75 + if (qpcs->interface != interface) {
76 + ret = ipq_pcs_config_mode(qpcs, interface);
77 + if (ret)
78 + return ret;
79 +
80 + /* Deassert XPCS */
81 + reset_control_deassert(qpcs->reset[XPCS_RESET]);
82 +
83 + qpcs->interface = interface;
84 + }
85 +
86 + return 0;
87 +}
88 +
89 static unsigned long ipq_unipcs_clock_rate_get_gmii(int speed)
90 {
91 unsigned long rate = 0;
92 @@ -421,6 +466,7 @@ ipq_unipcs_link_up_clock_rate_set(struct
93 rate = ipq_unipcs_clock_rate_get_gmii(speed);
94 break;
95 case PHY_INTERFACE_MODE_USXGMII:
96 + case PHY_INTERFACE_MODE_10GBASER:
97 rate = ipq_unipcs_clock_rate_get_xgmii(speed);
98 break;
99 default:
100 @@ -602,6 +648,9 @@ static void ipq_pcs_get_state(struct phy
101 case PHY_INTERFACE_MODE_USXGMII:
102 ipq_pcs_get_state_usxgmii(qpcs, state);
103 break;
104 + case PHY_INTERFACE_MODE_10GBASER:
105 + ipq_unipcs_get_state_10gbaser(qpcs, state);
106 + break;
107 default:
108 break;
109 }
110 @@ -631,6 +680,8 @@ static int ipq_pcs_config(struct phylink
111 return ipq_pcs_config_sgmii(qpcs, index, neg_mode, interface);
112 case PHY_INTERFACE_MODE_USXGMII:
113 return ipq_pcs_config_usxgmii(qpcs);
114 + case PHY_INTERFACE_MODE_10GBASER:
115 + return ipq_unipcs_config_10gbaser(qpcs, interface);
116 default:
117 dev_err(qpcs->dev,
118 "interface %s not supported\n", phy_modes(interface));
119 @@ -662,6 +713,8 @@ static void ipq_pcs_link_up(struct phyli
120 case PHY_INTERFACE_MODE_USXGMII:
121 ret = ipq_pcs_link_up_config_usxgmii(qpcs, speed);
122 break;
123 + case PHY_INTERFACE_MODE_10GBASER:
124 + break;
125 default:
126 dev_err(qpcs->dev,
127 "interface %s not supported\n", phy_modes(interface));