27f94dca0270e6586f3b368bef723af7ef1e81b9
[openwrt/staging/blogic.git] /
1 From cef08115846e581f80ff99abf7bf218da1840616 Mon Sep 17 00:00:00 2001
2 From: Ansuel Smith <ansuelsmth@gmail.com>
3 Date: Thu, 14 Oct 2021 00:39:18 +0200
4 Subject: net: dsa: qca8k: set internal delay also for sgmii
5
6 QCA original code report port instability and sa that SGMII also require
7 to set internal delay. Generalize the rgmii delay function and apply the
8 advised value if they are not defined in DT.
9
10 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
11 Signed-off-by: David S. Miller <davem@davemloft.net>
12 ---
13 drivers/net/dsa/qca8k.c | 88 +++++++++++++++++++++++++++++++++----------------
14 drivers/net/dsa/qca8k.h | 2 ++
15 2 files changed, 62 insertions(+), 28 deletions(-)
16
17 --- a/drivers/net/dsa/qca8k.c
18 +++ b/drivers/net/dsa/qca8k.c
19 @@ -1004,6 +1004,7 @@ qca8k_parse_port_config(struct qca8k_pri
20 case PHY_INTERFACE_MODE_RGMII_ID:
21 case PHY_INTERFACE_MODE_RGMII_TXID:
22 case PHY_INTERFACE_MODE_RGMII_RXID:
23 + case PHY_INTERFACE_MODE_SGMII:
24 delay = 0;
25
26 if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay))
27 @@ -1036,8 +1037,13 @@ qca8k_parse_port_config(struct qca8k_pri
28
29 priv->rgmii_rx_delay[cpu_port_index] = delay;
30
31 - break;
32 - case PHY_INTERFACE_MODE_SGMII:
33 + /* Skip sgmii parsing for rgmii* mode */
34 + if (mode == PHY_INTERFACE_MODE_RGMII ||
35 + mode == PHY_INTERFACE_MODE_RGMII_ID ||
36 + mode == PHY_INTERFACE_MODE_RGMII_TXID ||
37 + mode == PHY_INTERFACE_MODE_RGMII_RXID)
38 + break;
39 +
40 if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
41 priv->sgmii_tx_clk_falling_edge = true;
42
43 @@ -1261,12 +1267,53 @@ qca8k_setup(struct dsa_switch *ds)
44 }
45
46 static void
47 +qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index,
48 + u32 reg)
49 +{
50 + u32 delay, val = 0;
51 + int ret;
52 +
53 + /* Delay can be declared in 3 different way.
54 + * Mode to rgmii and internal-delay standard binding defined
55 + * rgmii-id or rgmii-tx/rx phy mode set.
56 + * The parse logic set a delay different than 0 only when one
57 + * of the 3 different way is used. In all other case delay is
58 + * not enabled. With ID or TX/RXID delay is enabled and set
59 + * to the default and recommended value.
60 + */
61 + if (priv->rgmii_tx_delay[cpu_port_index]) {
62 + delay = priv->rgmii_tx_delay[cpu_port_index];
63 +
64 + val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
65 + QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
66 + }
67 +
68 + if (priv->rgmii_rx_delay[cpu_port_index]) {
69 + delay = priv->rgmii_rx_delay[cpu_port_index];
70 +
71 + val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
72 + QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
73 + }
74 +
75 + /* Set RGMII delay based on the selected values */
76 + ret = qca8k_rmw(priv, reg,
77 + QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK |
78 + QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK |
79 + QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
80 + QCA8K_PORT_PAD_RGMII_RX_DELAY_EN,
81 + val);
82 + if (ret)
83 + dev_err(priv->dev, "Failed to set internal delay for CPU port%d",
84 + cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6);
85 +}
86 +
87 +static void
88 qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
89 const struct phylink_link_state *state)
90 {
91 struct qca8k_priv *priv = ds->priv;
92 int cpu_port_index, ret;
93 - u32 reg, val, delay;
94 + u32 reg, val;
95
96 switch (port) {
97 case 0: /* 1st CPU port */
98 @@ -1315,32 +1362,10 @@ qca8k_phylink_mac_config(struct dsa_swit
99 case PHY_INTERFACE_MODE_RGMII_ID:
100 case PHY_INTERFACE_MODE_RGMII_TXID:
101 case PHY_INTERFACE_MODE_RGMII_RXID:
102 - val = QCA8K_PORT_PAD_RGMII_EN;
103 -
104 - /* Delay can be declared in 3 different way.
105 - * Mode to rgmii and internal-delay standard binding defined
106 - * rgmii-id or rgmii-tx/rx phy mode set.
107 - * The parse logic set a delay different than 0 only when one
108 - * of the 3 different way is used. In all other case delay is
109 - * not enabled. With ID or TX/RXID delay is enabled and set
110 - * to the default and recommended value.
111 - */
112 - if (priv->rgmii_tx_delay[cpu_port_index]) {
113 - delay = priv->rgmii_tx_delay[cpu_port_index];
114 -
115 - val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
116 - QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
117 - }
118 -
119 - if (priv->rgmii_rx_delay[cpu_port_index]) {
120 - delay = priv->rgmii_rx_delay[cpu_port_index];
121 -
122 - val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
123 - QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
124 - }
125 + qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
126
127 - /* Set RGMII delay based on the selected values */
128 - qca8k_write(priv, reg, val);
129 + /* Configure rgmii delay */
130 + qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg);
131
132 /* QCA8337 requires to set rgmii rx delay for all ports.
133 * This is enabled through PORT5_PAD_CTRL for all ports,
134 @@ -1411,6 +1436,13 @@ qca8k_phylink_mac_config(struct dsa_swit
135 QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
136 QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
137 val);
138 +
139 + /* From original code is reported port instability as SGMII also
140 + * require delay set. Apply advised values here or take them from DT.
141 + */
142 + if (state->interface == PHY_INTERFACE_MODE_SGMII)
143 + qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg);
144 +
145 break;
146 default:
147 dev_err(ds->dev, "xMII mode %s not supported for port %d\n",
148 --- a/drivers/net/dsa/qca8k.h
149 +++ b/drivers/net/dsa/qca8k.h
150 @@ -39,7 +39,9 @@
151 #define QCA8K_REG_PORT5_PAD_CTRL 0x008
152 #define QCA8K_REG_PORT6_PAD_CTRL 0x00c
153 #define QCA8K_PORT_PAD_RGMII_EN BIT(26)
154 +#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22)
155 #define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22)
156 +#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20)
157 #define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20)
158 #define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
159 #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)