ipq40xx: switch default to 6.6
[openwrt/staging/stintel.git] / target / linux / ipq40xx / patches-6.1 / 706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch
1 From a38126870488398932e017dd9d76174b4aadbbbb Mon Sep 17 00:00:00 2001
2 From: Robert Marko <robert.marko@sartura.hr>
3 Date: Sat, 10 Sep 2022 15:46:09 +0200
4 Subject: [PATCH] net: dsa: qca8k: add IPQ4019 built-in switch support
5
6 Qualcomm IPQ40xx SoC-s have a variant of QCA8337N switch built-in.
7
8 It shares most of the stuff with its external counterpart, however it is
9 modified for the SoC.
10 Namely, it doesn't have second CPU port (Port 6), so it has 6 ports
11 instead of 7.
12 It also has no built-in PHY-s but rather requires external PSGMII based
13 companion PHY-s (QCA8072 and QCA8075) for which it first needs to carry
14 out calibration before using them.
15 PSGMII has a SoC built-in PHY that is used to connect to the PHY-s which
16 unfortunately requires some magic values as the datasheet doesnt document
17 the bits that are being set or the register at all.
18
19 Since its built-in it is MMIO like other peripherals and doesn't have its
20 own MDIO bus but depends on the SoC provided one.
21
22 CPU connection is at Port 0 and it uses some kind of a internal connection
23 and no traditional RGMII/SGMII.
24
25 It also doesn't use in-band tagging like other qca8k switches so a out of
26 band based tagger is used.
27
28 Signed-off-by: Robert Marko <robert.marko@sartura.hr>
29 ---
30 drivers/net/dsa/qca/Kconfig | 8 +
31 drivers/net/dsa/qca/Makefile | 1 +
32 drivers/net/dsa/qca/qca8k-common.c | 6 +-
33 drivers/net/dsa/qca/qca8k-ipq4019.c | 948 ++++++++++++++++++++++++++++
34 drivers/net/dsa/qca/qca8k.h | 56 ++
35 5 files changed, 1016 insertions(+), 3 deletions(-)
36 create mode 100644 drivers/net/dsa/qca/qca8k-ipq4019.c
37
38 --- a/drivers/net/dsa/qca/Kconfig
39 +++ b/drivers/net/dsa/qca/Kconfig
40 @@ -23,3 +23,11 @@ config NET_DSA_QCA8K_LEDS_SUPPORT
41 help
42 This enabled support for LEDs present on the Qualcomm Atheros
43 QCA8K Ethernet switch chips.
44 +
45 +config NET_DSA_QCA8K_IPQ4019
46 + tristate "Qualcomm Atheros IPQ4019 Ethernet switch support"
47 + select NET_DSA_TAG_OOB
48 + select REGMAP_MMIO
49 + help
50 + This enables support for the switch built-into Qualcomm Atheros
51 + IPQ4019 SoCs.
52 --- a/drivers/net/dsa/qca/Makefile
53 +++ b/drivers/net/dsa/qca/Makefile
54 @@ -5,3 +5,4 @@ qca8k-y += qca8k-common.o qca8k-8xxx.
55 ifdef CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT
56 qca8k-y += qca8k-leds.o
57 endif
58 +obj-$(CONFIG_NET_DSA_QCA8K_IPQ4019) += qca8k-ipq4019.o qca8k-common.o
59 --- a/drivers/net/dsa/qca/qca8k-common.c
60 +++ b/drivers/net/dsa/qca/qca8k-common.c
61 @@ -412,7 +412,7 @@ static int qca8k_vlan_del(struct qca8k_p
62
63 /* Check if we're the last member to be removed */
64 del = true;
65 - for (i = 0; i < QCA8K_NUM_PORTS; i++) {
66 + for (i = 0; i < priv->ds->num_ports; i++) {
67 mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i);
68
69 if ((reg & mask) != mask) {
70 @@ -653,7 +653,7 @@ int qca8k_port_bridge_join(struct dsa_sw
71 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
72 port_mask = BIT(cpu_port);
73
74 - for (i = 0; i < QCA8K_NUM_PORTS; i++) {
75 + for (i = 0; i < ds->num_ports; i++) {
76 if (dsa_is_cpu_port(ds, i))
77 continue;
78 if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
79 @@ -685,7 +685,7 @@ void qca8k_port_bridge_leave(struct dsa_
80
81 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
82
83 - for (i = 0; i < QCA8K_NUM_PORTS; i++) {
84 + for (i = 0; i < ds->num_ports; i++) {
85 if (dsa_is_cpu_port(ds, i))
86 continue;
87 if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
88 --- /dev/null
89 +++ b/drivers/net/dsa/qca/qca8k-ipq4019.c
90 @@ -0,0 +1,948 @@
91 +// SPDX-License-Identifier: GPL-2.0
92 +/*
93 + * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
94 + * Copyright (C) 2011-2012, 2020-2021 Gabor Juhos <juhosg@openwrt.org>
95 + * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved.
96 + * Copyright (c) 2016 John Crispin <john@phrozen.org>
97 + * Copyright (c) 2022 Robert Marko <robert.marko@sartura.hr>
98 + */
99 +
100 +#include <linux/module.h>
101 +#include <linux/phy.h>
102 +#include <linux/netdevice.h>
103 +#include <linux/bitfield.h>
104 +#include <linux/regmap.h>
105 +#include <net/dsa.h>
106 +#include <linux/of_net.h>
107 +#include <linux/of_mdio.h>
108 +#include <linux/of_platform.h>
109 +#include <linux/mdio.h>
110 +#include <linux/phylink.h>
111 +
112 +#include "qca8k.h"
113 +
114 +static struct regmap_config qca8k_ipq4019_regmap_config = {
115 + .reg_bits = 32,
116 + .val_bits = 32,
117 + .reg_stride = 4,
118 + .max_register = 0x16ac, /* end MIB - Port6 range */
119 + .rd_table = &qca8k_readable_table,
120 +};
121 +
122 +static struct regmap_config qca8k_ipq4019_psgmii_phy_regmap_config = {
123 + .name = "psgmii-phy",
124 + .reg_bits = 32,
125 + .val_bits = 32,
126 + .reg_stride = 4,
127 + .max_register = 0x7fc,
128 +};
129 +
130 +static enum dsa_tag_protocol
131 +qca8k_ipq4019_get_tag_protocol(struct dsa_switch *ds, int port,
132 + enum dsa_tag_protocol mp)
133 +{
134 + return DSA_TAG_PROTO_OOB;
135 +}
136 +
137 +static struct phylink_pcs *
138 +qca8k_ipq4019_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
139 + phy_interface_t interface)
140 +{
141 + struct qca8k_priv *priv = ds->priv;
142 + struct phylink_pcs *pcs = NULL;
143 +
144 + switch (interface) {
145 + case PHY_INTERFACE_MODE_PSGMII:
146 + switch (port) {
147 + case 0:
148 + pcs = &priv->pcs_port_0.pcs;
149 + break;
150 + }
151 + break;
152 + default:
153 + break;
154 + }
155 +
156 + return pcs;
157 +}
158 +
159 +static int qca8k_ipq4019_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
160 + phy_interface_t interface,
161 + const unsigned long *advertising,
162 + bool permit_pause_to_mac)
163 +{
164 + return 0;
165 +}
166 +
167 +static void qca8k_ipq4019_pcs_an_restart(struct phylink_pcs *pcs)
168 +{
169 +}
170 +
171 +static struct qca8k_pcs *pcs_to_qca8k_pcs(struct phylink_pcs *pcs)
172 +{
173 + return container_of(pcs, struct qca8k_pcs, pcs);
174 +}
175 +
176 +static void qca8k_ipq4019_pcs_get_state(struct phylink_pcs *pcs,
177 + struct phylink_link_state *state)
178 +{
179 + struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv;
180 + int port = pcs_to_qca8k_pcs(pcs)->port;
181 + u32 reg;
182 + int ret;
183 +
184 + ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), &reg);
185 + if (ret < 0) {
186 + state->link = false;
187 + return;
188 + }
189 +
190 + state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP);
191 + state->an_complete = state->link;
192 + state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL :
193 + DUPLEX_HALF;
194 +
195 + switch (reg & QCA8K_PORT_STATUS_SPEED) {
196 + case QCA8K_PORT_STATUS_SPEED_10:
197 + state->speed = SPEED_10;
198 + break;
199 + case QCA8K_PORT_STATUS_SPEED_100:
200 + state->speed = SPEED_100;
201 + break;
202 + case QCA8K_PORT_STATUS_SPEED_1000:
203 + state->speed = SPEED_1000;
204 + break;
205 + default:
206 + state->speed = SPEED_UNKNOWN;
207 + break;
208 + }
209 +
210 + if (reg & QCA8K_PORT_STATUS_RXFLOW)
211 + state->pause |= MLO_PAUSE_RX;
212 + if (reg & QCA8K_PORT_STATUS_TXFLOW)
213 + state->pause |= MLO_PAUSE_TX;
214 +}
215 +
216 +static const struct phylink_pcs_ops qca8k_pcs_ops = {
217 + .pcs_get_state = qca8k_ipq4019_pcs_get_state,
218 + .pcs_config = qca8k_ipq4019_pcs_config,
219 + .pcs_an_restart = qca8k_ipq4019_pcs_an_restart,
220 +};
221 +
222 +static void qca8k_ipq4019_setup_pcs(struct qca8k_priv *priv,
223 + struct qca8k_pcs *qpcs,
224 + int port)
225 +{
226 + qpcs->pcs.ops = &qca8k_pcs_ops;
227 +
228 + /* We don't have interrupts for link changes, so we need to poll */
229 + qpcs->pcs.poll = true;
230 + qpcs->priv = priv;
231 + qpcs->port = port;
232 +}
233 +
234 +static void qca8k_ipq4019_phylink_get_caps(struct dsa_switch *ds, int port,
235 + struct phylink_config *config)
236 +{
237 + switch (port) {
238 + case 0: /* CPU port */
239 + __set_bit(PHY_INTERFACE_MODE_INTERNAL,
240 + config->supported_interfaces);
241 + break;
242 +
243 + case 1:
244 + case 2:
245 + case 3:
246 + __set_bit(PHY_INTERFACE_MODE_PSGMII,
247 + config->supported_interfaces);
248 + break;
249 + case 4:
250 + case 5:
251 + phy_interface_set_rgmii(config->supported_interfaces);
252 + __set_bit(PHY_INTERFACE_MODE_PSGMII,
253 + config->supported_interfaces);
254 + break;
255 + }
256 +
257 + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
258 + MAC_10 | MAC_100 | MAC_1000FD;
259 +
260 + config->legacy_pre_march2020 = false;
261 +}
262 +
263 +static void
264 +qca8k_phylink_ipq4019_mac_link_down(struct dsa_switch *ds, int port,
265 + unsigned int mode,
266 + phy_interface_t interface)
267 +{
268 + struct qca8k_priv *priv = ds->priv;
269 +
270 + qca8k_port_set_status(priv, port, 0);
271 +}
272 +
273 +static void
274 +qca8k_phylink_ipq4019_mac_link_up(struct dsa_switch *ds, int port,
275 + unsigned int mode, phy_interface_t interface,
276 + struct phy_device *phydev, int speed,
277 + int duplex, bool tx_pause, bool rx_pause)
278 +{
279 + struct qca8k_priv *priv = ds->priv;
280 + u32 reg;
281 +
282 + if (phylink_autoneg_inband(mode)) {
283 + reg = QCA8K_PORT_STATUS_LINK_AUTO;
284 + } else {
285 + switch (speed) {
286 + case SPEED_10:
287 + reg = QCA8K_PORT_STATUS_SPEED_10;
288 + break;
289 + case SPEED_100:
290 + reg = QCA8K_PORT_STATUS_SPEED_100;
291 + break;
292 + case SPEED_1000:
293 + reg = QCA8K_PORT_STATUS_SPEED_1000;
294 + break;
295 + default:
296 + reg = QCA8K_PORT_STATUS_LINK_AUTO;
297 + break;
298 + }
299 +
300 + if (duplex == DUPLEX_FULL)
301 + reg |= QCA8K_PORT_STATUS_DUPLEX;
302 +
303 + if (rx_pause || dsa_is_cpu_port(ds, port))
304 + reg |= QCA8K_PORT_STATUS_RXFLOW;
305 +
306 + if (tx_pause || dsa_is_cpu_port(ds, port))
307 + reg |= QCA8K_PORT_STATUS_TXFLOW;
308 + }
309 +
310 + reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
311 +
312 + qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg);
313 +}
314 +
315 +static int psgmii_vco_calibrate(struct qca8k_priv *priv)
316 +{
317 + int val, ret;
318 +
319 + if (!priv->psgmii_ethphy) {
320 + dev_err(priv->dev, "PSGMII eth PHY missing, calibration failed!\n");
321 + return -ENODEV;
322 + }
323 +
324 + /* Fix PSGMII RX 20bit */
325 + ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5b);
326 + /* Reset PHY PSGMII */
327 + ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x1b);
328 + /* Release PHY PSGMII reset */
329 + ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5b);
330 +
331 + /* Poll for VCO PLL calibration finish - Malibu(QCA8075) */
332 + ret = phy_read_mmd_poll_timeout(priv->psgmii_ethphy,
333 + MDIO_MMD_PMAPMD,
334 + 0x28, val,
335 + (val & BIT(0)),
336 + 10000, 1000000,
337 + false);
338 + if (ret) {
339 + dev_err(priv->dev, "QCA807x PSGMII VCO calibration PLL not ready\n");
340 + return ret;
341 + }
342 + mdelay(50);
343 +
344 + /* Freeze PSGMII RX CDR */
345 + ret = phy_write(priv->psgmii_ethphy, MII_RESV2, 0x2230);
346 +
347 + /* Start PSGMIIPHY VCO PLL calibration */
348 + ret = regmap_set_bits(priv->psgmii,
349 + PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_1,
350 + PSGMIIPHY_REG_PLL_VCO_CALIB_RESTART);
351 +
352 + /* Poll for PSGMIIPHY PLL calibration finish - Dakota(IPQ40xx) */
353 + ret = regmap_read_poll_timeout(priv->psgmii,
354 + PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_2,
355 + val, val & PSGMIIPHY_REG_PLL_VCO_CALIB_READY,
356 + 10000, 1000000);
357 + if (ret) {
358 + dev_err(priv->dev, "IPQ PSGMIIPHY VCO calibration PLL not ready\n");
359 + return ret;
360 + }
361 + mdelay(50);
362 +
363 + /* Release PSGMII RX CDR */
364 + ret = phy_write(priv->psgmii_ethphy, MII_RESV2, 0x3230);
365 + /* Release PSGMII RX 20bit */
366 + ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5f);
367 + mdelay(200);
368 +
369 + return ret;
370 +}
371 +
372 +static void
373 +qca8k_switch_port_loopback_on_off(struct qca8k_priv *priv, int port, int on)
374 +{
375 + u32 val = QCA8K_PORT_LOOKUP_LOOPBACK_EN;
376 +
377 + if (on == 0)
378 + val = 0;
379 +
380 + qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
381 + QCA8K_PORT_LOOKUP_LOOPBACK_EN, val);
382 +}
383 +
384 +static int
385 +qca8k_wait_for_phy_link_state(struct phy_device *phy, int need_status)
386 +{
387 + int a;
388 + u16 status;
389 +
390 + for (a = 0; a < 100; a++) {
391 + status = phy_read(phy, MII_QCA8075_SSTATUS);
392 + status &= QCA8075_PHY_SPEC_STATUS_LINK;
393 + status = !!status;
394 + if (status == need_status)
395 + return 0;
396 + mdelay(8);
397 + }
398 +
399 + return -1;
400 +}
401 +
402 +static void
403 +qca8k_phy_loopback_on_off(struct qca8k_priv *priv, struct phy_device *phy,
404 + int sw_port, int on)
405 +{
406 + if (on) {
407 + phy_write(phy, MII_BMCR, BMCR_ANENABLE | BMCR_RESET);
408 + phy_modify(phy, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
409 + qca8k_wait_for_phy_link_state(phy, 0);
410 + qca8k_write(priv, QCA8K_REG_PORT_STATUS(sw_port), 0);
411 + phy_write(phy, MII_BMCR,
412 + BMCR_SPEED1000 |
413 + BMCR_FULLDPLX |
414 + BMCR_LOOPBACK);
415 + qca8k_wait_for_phy_link_state(phy, 1);
416 + qca8k_write(priv, QCA8K_REG_PORT_STATUS(sw_port),
417 + QCA8K_PORT_STATUS_SPEED_1000 |
418 + QCA8K_PORT_STATUS_TXMAC |
419 + QCA8K_PORT_STATUS_RXMAC |
420 + QCA8K_PORT_STATUS_DUPLEX);
421 + qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(sw_port),
422 + QCA8K_PORT_LOOKUP_STATE_FORWARD,
423 + QCA8K_PORT_LOOKUP_STATE_FORWARD);
424 + } else { /* off */
425 + qca8k_write(priv, QCA8K_REG_PORT_STATUS(sw_port), 0);
426 + qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(sw_port),
427 + QCA8K_PORT_LOOKUP_STATE_DISABLED,
428 + QCA8K_PORT_LOOKUP_STATE_DISABLED);
429 + phy_write(phy, MII_BMCR, BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_RESET);
430 + /* turn off the power of the phys - so that unused
431 + ports do not raise links */
432 + phy_modify(phy, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
433 + }
434 +}
435 +
436 +static void
437 +qca8k_phy_pkt_gen_prep(struct qca8k_priv *priv, struct phy_device *phy,
438 + int pkts_num, int on)
439 +{
440 + if (on) {
441 + /* enable CRC checker and packets counters */
442 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_CRC_AND_PKTS_COUNT, 0);
443 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_CRC_AND_PKTS_COUNT,
444 + QCA8075_MMD7_CNT_FRAME_CHK_EN | QCA8075_MMD7_CNT_SELFCLR);
445 + qca8k_wait_for_phy_link_state(phy, 1);
446 + /* packet number */
447 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_PKT_NUMB, pkts_num);
448 + /* pkt size - 1504 bytes + 20 bytes */
449 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_PKT_SIZE, 1504);
450 + } else { /* off */
451 + /* packet number */
452 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_PKT_NUMB, 0);
453 + /* disable CRC checker and packet counter */
454 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_CRC_AND_PKTS_COUNT, 0);
455 + /* disable traffic gen */
456 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_CTRL, 0);
457 + }
458 +}
459 +
460 +static void
461 +qca8k_wait_for_phy_pkt_gen_fin(struct qca8k_priv *priv, struct phy_device *phy)
462 +{
463 + int val;
464 + /* wait for all traffic end: 4096(pkt num)*1524(size)*8ns(125MHz)=49938us */
465 + phy_read_mmd_poll_timeout(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_CTRL,
466 + val, !(val & QCA8075_MMD7_PKT_GEN_INPROGR),
467 + 50000, 1000000, true);
468 +}
469 +
470 +static void
471 +qca8k_start_phy_pkt_gen(struct phy_device *phy)
472 +{
473 + /* start traffic gen */
474 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_CTRL,
475 + QCA8075_MMD7_PKT_GEN_START | QCA8075_MMD7_PKT_GEN_INPROGR);
476 +}
477 +
478 +static int
479 +qca8k_start_all_phys_pkt_gens(struct qca8k_priv *priv)
480 +{
481 + struct phy_device *phy;
482 + phy = phy_device_create(priv->bus, QCA8075_MDIO_BRDCST_PHY_ADDR,
483 + 0, 0, NULL);
484 + if (!phy) {
485 + dev_err(priv->dev, "unable to create mdio broadcast PHY(0x%x)\n",
486 + QCA8075_MDIO_BRDCST_PHY_ADDR);
487 + return -ENODEV;
488 + }
489 +
490 + qca8k_start_phy_pkt_gen(phy);
491 +
492 + phy_device_free(phy);
493 + return 0;
494 +}
495 +
496 +static int
497 +qca8k_get_phy_pkt_gen_test_result(struct phy_device *phy, int pkts_num)
498 +{
499 + u32 tx_ok, tx_error;
500 + u32 rx_ok, rx_error;
501 + u32 tx_ok_high16;
502 + u32 rx_ok_high16;
503 + u32 tx_all_ok, rx_all_ok;
504 +
505 + /* check counters */
506 + tx_ok = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_EG_FRAME_RECV_CNT_LO);
507 + tx_ok_high16 = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_EG_FRAME_RECV_CNT_HI);
508 + tx_error = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_EG_FRAME_ERR_CNT);
509 + rx_ok = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_IG_FRAME_RECV_CNT_LO);
510 + rx_ok_high16 = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_IG_FRAME_RECV_CNT_HI);
511 + rx_error = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_IG_FRAME_ERR_CNT);
512 + tx_all_ok = tx_ok + (tx_ok_high16 << 16);
513 + rx_all_ok = rx_ok + (rx_ok_high16 << 16);
514 +
515 + if (tx_all_ok < pkts_num)
516 + return -1;
517 + if(rx_all_ok < pkts_num)
518 + return -2;
519 + if(tx_error)
520 + return -3;
521 + if(rx_error)
522 + return -4;
523 + return 0; /* test is ok */
524 +}
525 +
526 +static
527 +void qca8k_phy_broadcast_write_on_off(struct qca8k_priv *priv,
528 + struct phy_device *phy, int on)
529 +{
530 + u32 val;
531 +
532 + val = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_MDIO_BRDCST_WRITE);
533 +
534 + if (on == 0)
535 + val &= ~QCA8075_MMD7_MDIO_BRDCST_WRITE_EN;
536 + else
537 + val |= QCA8075_MMD7_MDIO_BRDCST_WRITE_EN;
538 +
539 + phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_MDIO_BRDCST_WRITE, val);
540 +}
541 +
542 +static int
543 +qca8k_test_dsa_port_for_errors(struct qca8k_priv *priv, struct phy_device *phy,
544 + int port, int test_phase)
545 +{
546 + int res = 0;
547 + const int test_pkts_num = QCA8075_PKT_GEN_PKTS_COUNT;
548 +
549 + if (test_phase == 1) { /* start test preps */
550 + qca8k_phy_loopback_on_off(priv, phy, port, 1);
551 + qca8k_switch_port_loopback_on_off(priv, port, 1);
552 + qca8k_phy_broadcast_write_on_off(priv, phy, 1);
553 + qca8k_phy_pkt_gen_prep(priv, phy, test_pkts_num, 1);
554 + } else if (test_phase == 2) {
555 + /* wait for test results, collect it and cleanup */
556 + qca8k_wait_for_phy_pkt_gen_fin(priv, phy);
557 + res = qca8k_get_phy_pkt_gen_test_result(phy, test_pkts_num);
558 + qca8k_phy_pkt_gen_prep(priv, phy, test_pkts_num, 0);
559 + qca8k_phy_broadcast_write_on_off(priv, phy, 0);
560 + qca8k_switch_port_loopback_on_off(priv, port, 0);
561 + qca8k_phy_loopback_on_off(priv, phy, port, 0);
562 + }
563 +
564 + return res;
565 +}
566 +
567 +static int
568 +qca8k_do_dsa_sw_ports_self_test(struct qca8k_priv *priv, int parallel_test)
569 +{
570 + struct device_node *dn = priv->dev->of_node;
571 + struct device_node *ports, *port;
572 + struct device_node *phy_dn;
573 + struct phy_device *phy;
574 + int reg, err = 0, test_phase;
575 + u32 tests_result = 0;
576 +
577 + ports = of_get_child_by_name(dn, "ports");
578 + if (!ports) {
579 + dev_err(priv->dev, "no ports child node found\n");
580 + return -EINVAL;
581 + }
582 +
583 + for (test_phase = 1; test_phase <= 2; test_phase++) {
584 + if (parallel_test && test_phase == 2) {
585 + err = qca8k_start_all_phys_pkt_gens(priv);
586 + if (err)
587 + goto error;
588 + }
589 + for_each_available_child_of_node(ports, port) {
590 + err = of_property_read_u32(port, "reg", &reg);
591 + if (err)
592 + goto error;
593 + if (reg >= QCA8K_NUM_PORTS) {
594 + err = -EINVAL;
595 + goto error;
596 + }
597 + phy_dn = of_parse_phandle(port, "phy-handle", 0);
598 + if (phy_dn) {
599 + phy = of_phy_find_device(phy_dn);
600 + of_node_put(phy_dn);
601 + if (phy) {
602 + int result;
603 + result = qca8k_test_dsa_port_for_errors(priv,
604 + phy, reg, test_phase);
605 + if (!parallel_test && test_phase == 1)
606 + qca8k_start_phy_pkt_gen(phy);
607 + put_device(&phy->mdio.dev);
608 + if (test_phase == 2) {
609 + tests_result <<= 1;
610 + if (result)
611 + tests_result |= 1;
612 + }
613 + }
614 + }
615 + }
616 + }
617 +
618 +end:
619 + of_node_put(ports);
620 + qca8k_fdb_flush(priv);
621 + return tests_result;
622 +error:
623 + tests_result |= 0xf000;
624 + goto end;
625 +}
626 +
627 +static int
628 +psgmii_vco_calibrate_and_test(struct dsa_switch *ds)
629 +{
630 + int ret, a, test_result;
631 + struct qca8k_priv *priv = ds->priv;
632 +
633 + for (a = 0; a <= QCA8K_PSGMII_CALB_NUM; a++) {
634 + ret = psgmii_vco_calibrate(priv);
635 + if (ret)
636 + return ret;
637 + /* first we run serial test */
638 + test_result = qca8k_do_dsa_sw_ports_self_test(priv, 0);
639 + /* and if it is ok then we run the test in parallel */
640 + if (!test_result)
641 + test_result = qca8k_do_dsa_sw_ports_self_test(priv, 1);
642 + if (!test_result) {
643 + if (a > 0) {
644 + dev_warn(priv->dev, "PSGMII work was stabilized after %d "
645 + "calibration retries !\n", a);
646 + }
647 + return 0;
648 + } else {
649 + schedule();
650 + if (a > 0 && a % 10 == 0) {
651 + dev_err(priv->dev, "PSGMII work is unstable !!! "
652 + "Let's try to wait a bit ... %d\n", a);
653 + set_current_state(TASK_INTERRUPTIBLE);
654 + schedule_timeout(msecs_to_jiffies(a * 100));
655 + }
656 + }
657 + }
658 +
659 + panic("PSGMII work is unstable !!! "
660 + "Repeated recalibration attempts did not help(0x%x) !\n",
661 + test_result);
662 +
663 + return -EFAULT;
664 +}
665 +
666 +static int
667 +ipq4019_psgmii_configure(struct dsa_switch *ds)
668 +{
669 + struct qca8k_priv *priv = ds->priv;
670 + int ret;
671 +
672 + if (!priv->psgmii_calibrated) {
673 + dev_info(ds->dev, "PSGMII calibration!\n");
674 + ret = psgmii_vco_calibrate_and_test(ds);
675 +
676 + ret = regmap_clear_bits(priv->psgmii, PSGMIIPHY_MODE_CONTROL,
677 + PSGMIIPHY_MODE_ATHR_CSCO_MODE_25M);
678 + ret = regmap_write(priv->psgmii, PSGMIIPHY_TX_CONTROL,
679 + PSGMIIPHY_TX_CONTROL_MAGIC_VALUE);
680 +
681 + priv->psgmii_calibrated = true;
682 +
683 + return ret;
684 + }
685 +
686 + return 0;
687 +}
688 +
689 +static void
690 +qca8k_phylink_ipq4019_mac_config(struct dsa_switch *ds, int port,
691 + unsigned int mode,
692 + const struct phylink_link_state *state)
693 +{
694 + struct qca8k_priv *priv = ds->priv;
695 +
696 + switch (port) {
697 + case 0:
698 + /* CPU port, no configuration needed */
699 + return;
700 + case 1:
701 + case 2:
702 + case 3:
703 + if (state->interface == PHY_INTERFACE_MODE_PSGMII)
704 + if (ipq4019_psgmii_configure(ds))
705 + dev_err(ds->dev, "PSGMII configuration failed!\n");
706 + return;
707 + case 4:
708 + case 5:
709 + if (state->interface == PHY_INTERFACE_MODE_RGMII ||
710 + state->interface == PHY_INTERFACE_MODE_RGMII_ID ||
711 + state->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
712 + state->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
713 + regmap_set_bits(priv->regmap,
714 + QCA8K_IPQ4019_REG_RGMII_CTRL,
715 + QCA8K_IPQ4019_RGMII_CTRL_CLK);
716 + }
717 +
718 + if (state->interface == PHY_INTERFACE_MODE_PSGMII)
719 + if (ipq4019_psgmii_configure(ds))
720 + dev_err(ds->dev, "PSGMII configuration failed!\n");
721 + return;
722 + default:
723 + dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
724 + return;
725 + }
726 +}
727 +
728 +static int
729 +qca8k_ipq4019_setup_port(struct dsa_switch *ds, int port)
730 +{
731 + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
732 + int ret;
733 +
734 + /* CPU port gets connected to all user ports of the switch */
735 + if (dsa_is_cpu_port(ds, port)) {
736 + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
737 + QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
738 + if (ret)
739 + return ret;
740 +
741 + /* Disable CPU ARP Auto-learning by default */
742 + ret = regmap_clear_bits(priv->regmap,
743 + QCA8K_PORT_LOOKUP_CTRL(port),
744 + QCA8K_PORT_LOOKUP_LEARN);
745 + if (ret)
746 + return ret;
747 + }
748 +
749 + /* Individual user ports get connected to CPU port only */
750 + if (dsa_is_user_port(ds, port)) {
751 + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
752 + QCA8K_PORT_LOOKUP_MEMBER,
753 + BIT(QCA8K_IPQ4019_CPU_PORT));
754 + if (ret)
755 + return ret;
756 +
757 + /* Enable ARP Auto-learning by default */
758 + ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
759 + QCA8K_PORT_LOOKUP_LEARN);
760 + if (ret)
761 + return ret;
762 +
763 + /* For port based vlans to work we need to set the
764 + * default egress vid
765 + */
766 + ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
767 + QCA8K_EGREES_VLAN_PORT_MASK(port),
768 + QCA8K_EGREES_VLAN_PORT(port, QCA8K_PORT_VID_DEF));
769 + if (ret)
770 + return ret;
771 +
772 + ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
773 + QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
774 + QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
775 + if (ret)
776 + return ret;
777 + }
778 +
779 + return 0;
780 +}
781 +
782 +static int
783 +qca8k_ipq4019_setup(struct dsa_switch *ds)
784 +{
785 + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
786 + int ret, i;
787 +
788 + /* Make sure that port 0 is the cpu port */
789 + if (!dsa_is_cpu_port(ds, QCA8K_IPQ4019_CPU_PORT)) {
790 + dev_err(priv->dev, "port %d is not the CPU port",
791 + QCA8K_IPQ4019_CPU_PORT);
792 + return -EINVAL;
793 + }
794 +
795 + qca8k_ipq4019_setup_pcs(priv, &priv->pcs_port_0, 0);
796 +
797 + /* Enable CPU Port */
798 + ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
799 + QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
800 + if (ret) {
801 + dev_err(priv->dev, "failed enabling CPU port");
802 + return ret;
803 + }
804 +
805 + /* Enable MIB counters */
806 + ret = qca8k_mib_init(priv);
807 + if (ret)
808 + dev_warn(priv->dev, "MIB init failed");
809 +
810 + /* Disable forwarding by default on all ports */
811 + for (i = 0; i < QCA8K_IPQ4019_NUM_PORTS; i++) {
812 + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
813 + QCA8K_PORT_LOOKUP_MEMBER, 0);
814 + if (ret)
815 + return ret;
816 + }
817 +
818 + /* Enable QCA header mode on the CPU port */
819 + ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_IPQ4019_CPU_PORT),
820 + FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) |
821 + FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL));
822 + if (ret) {
823 + dev_err(priv->dev, "failed enabling QCA header mode");
824 + return ret;
825 + }
826 +
827 + /* Disable MAC by default on all ports */
828 + for (i = 0; i < QCA8K_IPQ4019_NUM_PORTS; i++) {
829 + if (dsa_is_user_port(ds, i))
830 + qca8k_port_set_status(priv, i, 0);
831 + }
832 +
833 + /* Forward all unknown frames to CPU port for Linux processing */
834 + ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
835 + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(QCA8K_IPQ4019_CPU_PORT)) |
836 + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(QCA8K_IPQ4019_CPU_PORT)) |
837 + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(QCA8K_IPQ4019_CPU_PORT)) |
838 + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(QCA8K_IPQ4019_CPU_PORT)));
839 + if (ret)
840 + return ret;
841 +
842 + /* Setup connection between CPU port & user ports */
843 + for (i = 0; i < QCA8K_IPQ4019_NUM_PORTS; i++) {
844 + ret = qca8k_ipq4019_setup_port(ds, i);
845 + if (ret)
846 + return ret;
847 + }
848 +
849 + /* Setup our port MTUs to match power on defaults */
850 + ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
851 + if (ret)
852 + dev_warn(priv->dev, "failed setting MTU settings");
853 +
854 + /* Flush the FDB table */
855 + qca8k_fdb_flush(priv);
856 +
857 + /* Set min a max ageing value supported */
858 + ds->ageing_time_min = 7000;
859 + ds->ageing_time_max = 458745000;
860 +
861 + /* Set max number of LAGs supported */
862 + ds->num_lag_ids = QCA8K_NUM_LAGS;
863 +
864 + /* CPU port HW learning doesnt work correctly, so let DSA handle it */
865 + ds->assisted_learning_on_cpu_port = true;
866 +
867 + return 0;
868 +}
869 +
870 +static const struct dsa_switch_ops qca8k_ipq4019_switch_ops = {
871 + .get_tag_protocol = qca8k_ipq4019_get_tag_protocol,
872 + .setup = qca8k_ipq4019_setup,
873 + .get_strings = qca8k_get_strings,
874 + .get_ethtool_stats = qca8k_get_ethtool_stats,
875 + .get_sset_count = qca8k_get_sset_count,
876 + .set_ageing_time = qca8k_set_ageing_time,
877 + .get_mac_eee = qca8k_get_mac_eee,
878 + .set_mac_eee = qca8k_set_mac_eee,
879 + .port_enable = qca8k_port_enable,
880 + .port_disable = qca8k_port_disable,
881 + .port_change_mtu = qca8k_port_change_mtu,
882 + .port_max_mtu = qca8k_port_max_mtu,
883 + .port_stp_state_set = qca8k_port_stp_state_set,
884 + .port_bridge_join = qca8k_port_bridge_join,
885 + .port_bridge_leave = qca8k_port_bridge_leave,
886 + .port_fast_age = qca8k_port_fast_age,
887 + .port_fdb_add = qca8k_port_fdb_add,
888 + .port_fdb_del = qca8k_port_fdb_del,
889 + .port_fdb_dump = qca8k_port_fdb_dump,
890 + .port_mdb_add = qca8k_port_mdb_add,
891 + .port_mdb_del = qca8k_port_mdb_del,
892 + .port_mirror_add = qca8k_port_mirror_add,
893 + .port_mirror_del = qca8k_port_mirror_del,
894 + .port_vlan_filtering = qca8k_port_vlan_filtering,
895 + .port_vlan_add = qca8k_port_vlan_add,
896 + .port_vlan_del = qca8k_port_vlan_del,
897 + .phylink_mac_select_pcs = qca8k_ipq4019_phylink_mac_select_pcs,
898 + .phylink_get_caps = qca8k_ipq4019_phylink_get_caps,
899 + .phylink_mac_config = qca8k_phylink_ipq4019_mac_config,
900 + .phylink_mac_link_down = qca8k_phylink_ipq4019_mac_link_down,
901 + .phylink_mac_link_up = qca8k_phylink_ipq4019_mac_link_up,
902 + .port_lag_join = qca8k_port_lag_join,
903 + .port_lag_leave = qca8k_port_lag_leave,
904 +};
905 +
906 +static const struct qca8k_match_data ipq4019 = {
907 + .id = QCA8K_ID_IPQ4019,
908 + .mib_count = QCA8K_QCA833X_MIB_COUNT,
909 +};
910 +
911 +static int
912 +qca8k_ipq4019_probe(struct platform_device *pdev)
913 +{
914 + struct device *dev = &pdev->dev;
915 + struct qca8k_priv *priv;
916 + void __iomem *base, *psgmii;
917 + struct device_node *np = dev->of_node, *mdio_np, *psgmii_ethphy_np;
918 + int ret;
919 +
920 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
921 + if (!priv)
922 + return -ENOMEM;
923 +
924 + priv->dev = dev;
925 + priv->info = &ipq4019;
926 +
927 + /* Start by setting up the register mapping */
928 + base = devm_platform_ioremap_resource_byname(pdev, "base");
929 + if (IS_ERR(base))
930 + return PTR_ERR(base);
931 +
932 + priv->regmap = devm_regmap_init_mmio(dev, base,
933 + &qca8k_ipq4019_regmap_config);
934 + if (IS_ERR(priv->regmap)) {
935 + ret = PTR_ERR(priv->regmap);
936 + dev_err(dev, "base regmap initialization failed, %d\n", ret);
937 + return ret;
938 + }
939 +
940 + psgmii = devm_platform_ioremap_resource_byname(pdev, "psgmii_phy");
941 + if (IS_ERR(psgmii))
942 + return PTR_ERR(psgmii);
943 +
944 + priv->psgmii = devm_regmap_init_mmio(dev, psgmii,
945 + &qca8k_ipq4019_psgmii_phy_regmap_config);
946 + if (IS_ERR(priv->psgmii)) {
947 + ret = PTR_ERR(priv->psgmii);
948 + dev_err(dev, "PSGMII regmap initialization failed, %d\n", ret);
949 + return ret;
950 + }
951 +
952 + mdio_np = of_parse_phandle(np, "mdio", 0);
953 + if (!mdio_np) {
954 + dev_err(dev, "unable to get MDIO bus phandle\n");
955 + of_node_put(mdio_np);
956 + return -EINVAL;
957 + }
958 +
959 + priv->bus = of_mdio_find_bus(mdio_np);
960 + of_node_put(mdio_np);
961 + if (!priv->bus) {
962 + dev_err(dev, "unable to find MDIO bus\n");
963 + return -EPROBE_DEFER;
964 + }
965 +
966 + psgmii_ethphy_np = of_parse_phandle(np, "psgmii-ethphy", 0);
967 + if (!psgmii_ethphy_np) {
968 + dev_dbg(dev, "unable to get PSGMII eth PHY phandle\n");
969 + of_node_put(psgmii_ethphy_np);
970 + }
971 +
972 + if (psgmii_ethphy_np) {
973 + priv->psgmii_ethphy = of_phy_find_device(psgmii_ethphy_np);
974 + of_node_put(psgmii_ethphy_np);
975 + if (!priv->psgmii_ethphy) {
976 + dev_err(dev, "unable to get PSGMII eth PHY\n");
977 + return -ENODEV;
978 + }
979 + }
980 +
981 + /* Check the detected switch id */
982 + ret = qca8k_read_switch_id(priv);
983 + if (ret)
984 + return ret;
985 +
986 + priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
987 + if (!priv->ds)
988 + return -ENOMEM;
989 +
990 + priv->ds->dev = dev;
991 + priv->ds->num_ports = QCA8K_IPQ4019_NUM_PORTS;
992 + priv->ds->priv = priv;
993 + priv->ds->ops = &qca8k_ipq4019_switch_ops;
994 + mutex_init(&priv->reg_mutex);
995 + platform_set_drvdata(pdev, priv);
996 +
997 + return dsa_register_switch(priv->ds);
998 +}
999 +
1000 +static int
1001 +qca8k_ipq4019_remove(struct platform_device *pdev)
1002 +{
1003 + struct qca8k_priv *priv = dev_get_drvdata(&pdev->dev);
1004 + int i;
1005 +
1006 + if (!priv)
1007 + return 0;
1008 +
1009 + for (i = 0; i < QCA8K_IPQ4019_NUM_PORTS; i++)
1010 + qca8k_port_set_status(priv, i, 0);
1011 +
1012 + dsa_unregister_switch(priv->ds);
1013 +
1014 + platform_set_drvdata(pdev, NULL);
1015 +
1016 + return 0;
1017 +}
1018 +
1019 +static const struct of_device_id qca8k_ipq4019_of_match[] = {
1020 + { .compatible = "qca,ipq4019-qca8337n", },
1021 + { /* sentinel */ },
1022 +};
1023 +
1024 +static struct platform_driver qca8k_ipq4019_driver = {
1025 + .probe = qca8k_ipq4019_probe,
1026 + .remove = qca8k_ipq4019_remove,
1027 + .driver = {
1028 + .name = "qca8k-ipq4019",
1029 + .of_match_table = qca8k_ipq4019_of_match,
1030 + },
1031 +};
1032 +
1033 +module_platform_driver(qca8k_ipq4019_driver);
1034 +
1035 +MODULE_AUTHOR("Mathieu Olivari, John Crispin <john@phrozen.org>");
1036 +MODULE_AUTHOR("Gabor Juhos <j4g8y7@gmail.com>, Robert Marko <robert.marko@sartura.hr>");
1037 +MODULE_DESCRIPTION("Qualcomm IPQ4019 built-in switch driver");
1038 +MODULE_LICENSE("GPL");
1039 --- a/drivers/net/dsa/qca/qca8k.h
1040 +++ b/drivers/net/dsa/qca/qca8k.h
1041 @@ -19,7 +19,10 @@
1042 #define QCA8K_ETHERNET_TIMEOUT 5
1043
1044 #define QCA8K_NUM_PORTS 7
1045 +#define QCA8K_IPQ4019_NUM_PORTS 6
1046 #define QCA8K_NUM_CPU_PORTS 2
1047 +#define QCA8K_IPQ4019_NUM_CPU_PORTS 1
1048 +#define QCA8K_IPQ4019_CPU_PORT 0
1049 #define QCA8K_MAX_MTU 9000
1050 #define QCA8K_NUM_LAGS 4
1051 #define QCA8K_NUM_PORTS_FOR_LAG 4
1052 @@ -28,6 +31,7 @@
1053 #define QCA8K_ID_QCA8327 0x12
1054 #define PHY_ID_QCA8337 0x004dd036
1055 #define QCA8K_ID_QCA8337 0x13
1056 +#define QCA8K_ID_IPQ4019 0x14
1057
1058 #define QCA8K_QCA832X_MIB_COUNT 39
1059 #define QCA8K_QCA833X_MIB_COUNT 41
1060 @@ -265,6 +269,7 @@
1061 #define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3)
1062 #define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4)
1063 #define QCA8K_PORT_LOOKUP_LEARN BIT(20)
1064 +#define QCA8K_PORT_LOOKUP_LOOPBACK_EN BIT(21)
1065 #define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
1066
1067 #define QCA8K_REG_GOL_TRUNK_CTRL0 0x700
1068 @@ -341,6 +346,53 @@
1069 #define MII_ATH_MMD_ADDR 0x0d
1070 #define MII_ATH_MMD_DATA 0x0e
1071
1072 +/* IPQ4019 PSGMII PHY registers */
1073 +#define QCA8K_IPQ4019_REG_RGMII_CTRL 0x004
1074 +#define QCA8K_IPQ4019_RGMII_CTRL_RGMII_RXC GENMASK(1, 0)
1075 +#define QCA8K_IPQ4019_RGMII_CTRL_RGMII_TXC GENMASK(9, 8)
1076 +/* Some kind of CLK selection
1077 + * 0: gcc_ess_dly2ns
1078 + * 1: gcc_ess_clk
1079 + */
1080 +#define QCA8K_IPQ4019_RGMII_CTRL_CLK BIT(10)
1081 +#define QCA8K_IPQ4019_RGMII_CTRL_DELAY_RMII0 GENMASK(17, 16)
1082 +#define QCA8K_IPQ4019_RGMII_CTRL_INVERT_RMII0_REF_CLK BIT(18)
1083 +#define QCA8K_IPQ4019_RGMII_CTRL_DELAY_RMII1 GENMASK(20, 19)
1084 +#define QCA8K_IPQ4019_RGMII_CTRL_INVERT_RMII1_REF_CLK BIT(21)
1085 +#define QCA8K_IPQ4019_RGMII_CTRL_INVERT_RMII0_MASTER_EN BIT(24)
1086 +#define QCA8K_IPQ4019_RGMII_CTRL_INVERT_RMII1_MASTER_EN BIT(25)
1087 +
1088 +#define PSGMIIPHY_MODE_CONTROL 0x1b4
1089 +#define PSGMIIPHY_MODE_ATHR_CSCO_MODE_25M BIT(0)
1090 +#define PSGMIIPHY_TX_CONTROL 0x288
1091 +#define PSGMIIPHY_TX_CONTROL_MAGIC_VALUE 0x8380
1092 +#define PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_1 0x9c
1093 +#define PSGMIIPHY_REG_PLL_VCO_CALIB_RESTART BIT(14)
1094 +#define PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_2 0xa0
1095 +#define PSGMIIPHY_REG_PLL_VCO_CALIB_READY BIT(0)
1096 +
1097 +#define QCA8K_PSGMII_CALB_NUM 100
1098 +#define MII_QCA8075_SSTATUS 0x11
1099 +#define QCA8075_PHY_SPEC_STATUS_LINK BIT(10)
1100 +#define QCA8075_MMD7_CRC_AND_PKTS_COUNT 0x8029
1101 +#define QCA8075_MMD7_PKT_GEN_PKT_NUMB 0x8021
1102 +#define QCA8075_MMD7_PKT_GEN_PKT_SIZE 0x8062
1103 +#define QCA8075_MMD7_PKT_GEN_CTRL 0x8020
1104 +#define QCA8075_MMD7_CNT_SELFCLR BIT(1)
1105 +#define QCA8075_MMD7_CNT_FRAME_CHK_EN BIT(0)
1106 +#define QCA8075_MMD7_PKT_GEN_START BIT(13)
1107 +#define QCA8075_MMD7_PKT_GEN_INPROGR BIT(15)
1108 +#define QCA8075_MMD7_IG_FRAME_RECV_CNT_HI 0x802a
1109 +#define QCA8075_MMD7_IG_FRAME_RECV_CNT_LO 0x802b
1110 +#define QCA8075_MMD7_IG_FRAME_ERR_CNT 0x802c
1111 +#define QCA8075_MMD7_EG_FRAME_RECV_CNT_HI 0x802d
1112 +#define QCA8075_MMD7_EG_FRAME_RECV_CNT_LO 0x802e
1113 +#define QCA8075_MMD7_EG_FRAME_ERR_CNT 0x802f
1114 +#define QCA8075_MMD7_MDIO_BRDCST_WRITE 0x8028
1115 +#define QCA8075_MMD7_MDIO_BRDCST_WRITE_EN BIT(15)
1116 +#define QCA8075_MDIO_BRDCST_PHY_ADDR 0x1f
1117 +#define QCA8075_PKT_GEN_PKTS_COUNT 4096
1118 +
1119 enum {
1120 QCA8K_PORT_SPEED_10M = 0,
1121 QCA8K_PORT_SPEED_100M = 1,
1122 @@ -466,6 +518,10 @@ struct qca8k_priv {
1123 struct qca8k_pcs pcs_port_6;
1124 const struct qca8k_match_data *info;
1125 struct qca8k_led ports_led[QCA8K_LED_COUNT];
1126 + /* IPQ4019 specific */
1127 + struct regmap *psgmii;
1128 + struct phy_device *psgmii_ethphy;
1129 + bool psgmii_calibrated;
1130 };
1131
1132 struct qca8k_mib_desc {