summaryrefslogtreecommitdiffstats
path: root/target/linux/ipq40xx/patches-6.1/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ipq40xx/patches-6.1/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch')
-rw-r--r--target/linux/ipq40xx/patches-6.1/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch1132
1 files changed, 0 insertions, 1132 deletions
diff --git a/target/linux/ipq40xx/patches-6.1/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch b/target/linux/ipq40xx/patches-6.1/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch
deleted file mode 100644
index 992884cf31..0000000000
--- a/target/linux/ipq40xx/patches-6.1/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch
+++ /dev/null
@@ -1,1132 +0,0 @@
-From a38126870488398932e017dd9d76174b4aadbbbb Mon Sep 17 00:00:00 2001
-From: Robert Marko <robert.marko@sartura.hr>
-Date: Sat, 10 Sep 2022 15:46:09 +0200
-Subject: [PATCH] net: dsa: qca8k: add IPQ4019 built-in switch support
-
-Qualcomm IPQ40xx SoC-s have a variant of QCA8337N switch built-in.
-
-It shares most of the stuff with its external counterpart, however it is
-modified for the SoC.
-Namely, it doesn't have second CPU port (Port 6), so it has 6 ports
-instead of 7.
-It also has no built-in PHY-s but rather requires external PSGMII based
-companion PHY-s (QCA8072 and QCA8075) for which it first needs to carry
-out calibration before using them.
-PSGMII has a SoC built-in PHY that is used to connect to the PHY-s which
-unfortunately requires some magic values as the datasheet doesnt document
-the bits that are being set or the register at all.
-
-Since its built-in it is MMIO like other peripherals and doesn't have its
-own MDIO bus but depends on the SoC provided one.
-
-CPU connection is at Port 0 and it uses some kind of a internal connection
-and no traditional RGMII/SGMII.
-
-It also doesn't use in-band tagging like other qca8k switches so a out of
-band based tagger is used.
-
-Signed-off-by: Robert Marko <robert.marko@sartura.hr>
----
- drivers/net/dsa/qca/Kconfig | 8 +
- drivers/net/dsa/qca/Makefile | 1 +
- drivers/net/dsa/qca/qca8k-common.c | 6 +-
- drivers/net/dsa/qca/qca8k-ipq4019.c | 948 ++++++++++++++++++++++++++++
- drivers/net/dsa/qca/qca8k.h | 56 ++
- 5 files changed, 1016 insertions(+), 3 deletions(-)
- create mode 100644 drivers/net/dsa/qca/qca8k-ipq4019.c
-
---- a/drivers/net/dsa/qca/Kconfig
-+++ b/drivers/net/dsa/qca/Kconfig
-@@ -23,3 +23,11 @@ config NET_DSA_QCA8K_LEDS_SUPPORT
- help
- This enabled support for LEDs present on the Qualcomm Atheros
- QCA8K Ethernet switch chips.
-+
-+config NET_DSA_QCA8K_IPQ4019
-+ tristate "Qualcomm Atheros IPQ4019 Ethernet switch support"
-+ select NET_DSA_TAG_OOB
-+ select REGMAP_MMIO
-+ help
-+ This enables support for the switch built-into Qualcomm Atheros
-+ IPQ4019 SoCs.
---- a/drivers/net/dsa/qca/Makefile
-+++ b/drivers/net/dsa/qca/Makefile
-@@ -5,3 +5,4 @@ qca8k-y += qca8k-common.o qca8k-8xxx.
- ifdef CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT
- qca8k-y += qca8k-leds.o
- endif
-+obj-$(CONFIG_NET_DSA_QCA8K_IPQ4019) += qca8k-ipq4019.o qca8k-common.o
---- a/drivers/net/dsa/qca/qca8k-common.c
-+++ b/drivers/net/dsa/qca/qca8k-common.c
-@@ -412,7 +412,7 @@ static int qca8k_vlan_del(struct qca8k_p
-
- /* Check if we're the last member to be removed */
- del = true;
-- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-+ for (i = 0; i < priv->ds->num_ports; i++) {
- mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i);
-
- if ((reg & mask) != mask) {
-@@ -653,7 +653,7 @@ int qca8k_port_bridge_join(struct dsa_sw
- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
- port_mask = BIT(cpu_port);
-
-- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-+ for (i = 0; i < ds->num_ports; i++) {
- if (dsa_is_cpu_port(ds, i))
- continue;
- if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
-@@ -685,7 +685,7 @@ void qca8k_port_bridge_leave(struct dsa_
-
- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
-
-- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-+ for (i = 0; i < ds->num_ports; i++) {
- if (dsa_is_cpu_port(ds, i))
- continue;
- if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
---- /dev/null
-+++ b/drivers/net/dsa/qca/qca8k-ipq4019.c
-@@ -0,0 +1,948 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
-+ * Copyright (C) 2011-2012, 2020-2021 Gabor Juhos <juhosg@openwrt.org>
-+ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved.
-+ * Copyright (c) 2016 John Crispin <john@phrozen.org>
-+ * Copyright (c) 2022 Robert Marko <robert.marko@sartura.hr>
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/phy.h>
-+#include <linux/netdevice.h>
-+#include <linux/bitfield.h>
-+#include <linux/regmap.h>
-+#include <net/dsa.h>
-+#include <linux/of_net.h>
-+#include <linux/of_mdio.h>
-+#include <linux/of_platform.h>
-+#include <linux/mdio.h>
-+#include <linux/phylink.h>
-+
-+#include "qca8k.h"
-+
-+static struct regmap_config qca8k_ipq4019_regmap_config = {
-+ .reg_bits = 32,
-+ .val_bits = 32,
-+ .reg_stride = 4,
-+ .max_register = 0x16ac, /* end MIB - Port6 range */
-+ .rd_table = &qca8k_readable_table,
-+};
-+
-+static struct regmap_config qca8k_ipq4019_psgmii_phy_regmap_config = {
-+ .name = "psgmii-phy",
-+ .reg_bits = 32,
-+ .val_bits = 32,
-+ .reg_stride = 4,
-+ .max_register = 0x7fc,
-+};
-+
-+static enum dsa_tag_protocol
-+qca8k_ipq4019_get_tag_protocol(struct dsa_switch *ds, int port,
-+ enum dsa_tag_protocol mp)
-+{
-+ return DSA_TAG_PROTO_OOB;
-+}
-+
-+static struct phylink_pcs *
-+qca8k_ipq4019_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
-+ phy_interface_t interface)
-+{
-+ struct qca8k_priv *priv = ds->priv;
-+ struct phylink_pcs *pcs = NULL;
-+
-+ switch (interface) {
-+ case PHY_INTERFACE_MODE_PSGMII:
-+ switch (port) {
-+ case 0:
-+ pcs = &priv->pcs_port_0.pcs;
-+ break;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return pcs;
-+}
-+
-+static int qca8k_ipq4019_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
-+ phy_interface_t interface,
-+ const unsigned long *advertising,
-+ bool permit_pause_to_mac)
-+{
-+ return 0;
-+}
-+
-+static void qca8k_ipq4019_pcs_an_restart(struct phylink_pcs *pcs)
-+{
-+}
-+
-+static struct qca8k_pcs *pcs_to_qca8k_pcs(struct phylink_pcs *pcs)
-+{
-+ return container_of(pcs, struct qca8k_pcs, pcs);
-+}
-+
-+static void qca8k_ipq4019_pcs_get_state(struct phylink_pcs *pcs,
-+ struct phylink_link_state *state)
-+{
-+ struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv;
-+ int port = pcs_to_qca8k_pcs(pcs)->port;
-+ u32 reg;
-+ int ret;
-+
-+ ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), &reg);
-+ if (ret < 0) {
-+ state->link = false;
-+ return;
-+ }
-+
-+ state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP);
-+ state->an_complete = state->link;
-+ state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL :
-+ DUPLEX_HALF;
-+
-+ switch (reg & QCA8K_PORT_STATUS_SPEED) {
-+ case QCA8K_PORT_STATUS_SPEED_10:
-+ state->speed = SPEED_10;
-+ break;
-+ case QCA8K_PORT_STATUS_SPEED_100:
-+ state->speed = SPEED_100;
-+ break;
-+ case QCA8K_PORT_STATUS_SPEED_1000:
-+ state->speed = SPEED_1000;
-+ break;
-+ default:
-+ state->speed = SPEED_UNKNOWN;
-+ break;
-+ }
-+
-+ if (reg & QCA8K_PORT_STATUS_RXFLOW)
-+ state->pause |= MLO_PAUSE_RX;
-+ if (reg & QCA8K_PORT_STATUS_TXFLOW)
-+ state->pause |= MLO_PAUSE_TX;
-+}
-+
-+static const struct phylink_pcs_ops qca8k_pcs_ops = {
-+ .pcs_get_state = qca8k_ipq4019_pcs_get_state,
-+ .pcs_config = qca8k_ipq4019_pcs_config,
-+ .pcs_an_restart = qca8k_ipq4019_pcs_an_restart,
-+};
-+
-+static void qca8k_ipq4019_setup_pcs(struct qca8k_priv *priv,
-+ struct qca8k_pcs *qpcs,
-+ int port)
-+{
-+ qpcs->pcs.ops = &qca8k_pcs_ops;
-+
-+ /* We don't have interrupts for link changes, so we need to poll */
-+ qpcs->pcs.poll = true;
-+ qpcs->priv = priv;
-+ qpcs->port = port;
-+}
-+
-+static void qca8k_ipq4019_phylink_get_caps(struct dsa_switch *ds, int port,
-+ struct phylink_config *config)
-+{
-+ switch (port) {
-+ case 0: /* CPU port */
-+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
-+ config->supported_interfaces);
-+ break;
-+
-+ case 1:
-+ case 2:
-+ case 3:
-+ __set_bit(PHY_INTERFACE_MODE_PSGMII,
-+ config->supported_interfaces);
-+ break;
-+ case 4:
-+ case 5:
-+ phy_interface_set_rgmii(config->supported_interfaces);
-+ __set_bit(PHY_INTERFACE_MODE_PSGMII,
-+ config->supported_interfaces);
-+ break;
-+ }
-+
-+ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
-+ MAC_10 | MAC_100 | MAC_1000FD;
-+
-+ config->legacy_pre_march2020 = false;
-+}
-+
-+static void
-+qca8k_phylink_ipq4019_mac_link_down(struct dsa_switch *ds, int port,
-+ unsigned int mode,
-+ phy_interface_t interface)
-+{
-+ struct qca8k_priv *priv = ds->priv;
-+
-+ qca8k_port_set_status(priv, port, 0);
-+}
-+
-+static void
-+qca8k_phylink_ipq4019_mac_link_up(struct dsa_switch *ds, int port,
-+ unsigned int mode, phy_interface_t interface,
-+ struct phy_device *phydev, int speed,
-+ int duplex, bool tx_pause, bool rx_pause)
-+{
-+ struct qca8k_priv *priv = ds->priv;
-+ u32 reg;
-+
-+ if (phylink_autoneg_inband(mode)) {
-+ reg = QCA8K_PORT_STATUS_LINK_AUTO;
-+ } else {
-+ switch (speed) {
-+ case SPEED_10:
-+ reg = QCA8K_PORT_STATUS_SPEED_10;
-+ break;
-+ case SPEED_100:
-+ reg = QCA8K_PORT_STATUS_SPEED_100;
-+ break;
-+ case SPEED_1000:
-+ reg = QCA8K_PORT_STATUS_SPEED_1000;
-+ break;
-+ default:
-+ reg = QCA8K_PORT_STATUS_LINK_AUTO;
-+ break;
-+ }
-+
-+ if (duplex == DUPLEX_FULL)
-+ reg |= QCA8K_PORT_STATUS_DUPLEX;
-+
-+ if (rx_pause || dsa_is_cpu_port(ds, port))
-+ reg |= QCA8K_PORT_STATUS_RXFLOW;
-+
-+ if (tx_pause || dsa_is_cpu_port(ds, port))
-+ reg |= QCA8K_PORT_STATUS_TXFLOW;
-+ }
-+
-+ reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
-+
-+ qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg);
-+}
-+
-+static int psgmii_vco_calibrate(struct qca8k_priv *priv)
-+{
-+ int val, ret;
-+
-+ if (!priv->psgmii_ethphy) {
-+ dev_err(priv->dev, "PSGMII eth PHY missing, calibration failed!\n");
-+ return -ENODEV;
-+ }
-+
-+ /* Fix PSGMII RX 20bit */
-+ ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5b);
-+ /* Reset PHY PSGMII */
-+ ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x1b);
-+ /* Release PHY PSGMII reset */
-+ ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5b);
-+
-+ /* Poll for VCO PLL calibration finish - Malibu(QCA8075) */
-+ ret = phy_read_mmd_poll_timeout(priv->psgmii_ethphy,
-+ MDIO_MMD_PMAPMD,
-+ 0x28, val,
-+ (val & BIT(0)),
-+ 10000, 1000000,
-+ false);
-+ if (ret) {
-+ dev_err(priv->dev, "QCA807x PSGMII VCO calibration PLL not ready\n");
-+ return ret;
-+ }
-+ mdelay(50);
-+
-+ /* Freeze PSGMII RX CDR */
-+ ret = phy_write(priv->psgmii_ethphy, MII_RESV2, 0x2230);
-+
-+ /* Start PSGMIIPHY VCO PLL calibration */
-+ ret = regmap_set_bits(priv->psgmii,
-+ PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_1,
-+ PSGMIIPHY_REG_PLL_VCO_CALIB_RESTART);
-+
-+ /* Poll for PSGMIIPHY PLL calibration finish - Dakota(IPQ40xx) */
-+ ret = regmap_read_poll_timeout(priv->psgmii,
-+ PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_2,
-+ val, val & PSGMIIPHY_REG_PLL_VCO_CALIB_READY,
-+ 10000, 1000000);
-+ if (ret) {
-+ dev_err(priv->dev, "IPQ PSGMIIPHY VCO calibration PLL not ready\n");
-+ return ret;
-+ }
-+ mdelay(50);
-+
-+ /* Release PSGMII RX CDR */
-+ ret = phy_write(priv->psgmii_ethphy, MII_RESV2, 0x3230);
-+ /* Release PSGMII RX 20bit */
-+ ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5f);
-+ mdelay(200);
-+
-+ return ret;
-+}
-+
-+static void
-+qca8k_switch_port_loopback_on_off(struct qca8k_priv *priv, int port, int on)
-+{
-+ u32 val = QCA8K_PORT_LOOKUP_LOOPBACK_EN;
-+
-+ if (on == 0)
-+ val = 0;
-+
-+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
-+ QCA8K_PORT_LOOKUP_LOOPBACK_EN, val);
-+}
-+
-+static int
-+qca8k_wait_for_phy_link_state(struct phy_device *phy, int need_status)
-+{
-+ int a;
-+ u16 status;
-+
-+ for (a = 0; a < 100; a++) {
-+ status = phy_read(phy, MII_QCA8075_SSTATUS);
-+ status &= QCA8075_PHY_SPEC_STATUS_LINK;
-+ status = !!status;
-+ if (status == need_status)
-+ return 0;
-+ mdelay(8);
-+ }
-+
-+ return -1;
-+}
-+
-+static void
-+qca8k_phy_loopback_on_off(struct qca8k_priv *priv, struct phy_device *phy,
-+ int sw_port, int on)
-+{
-+ if (on) {
-+ phy_write(phy, MII_BMCR, BMCR_ANENABLE | BMCR_RESET);
-+ phy_modify(phy, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
-+ qca8k_wait_for_phy_link_state(phy, 0);
-+ qca8k_write(priv, QCA8K_REG_PORT_STATUS(sw_port), 0);
-+ phy_write(phy, MII_BMCR,
-+ BMCR_SPEED1000 |
-+ BMCR_FULLDPLX |
-+ BMCR_LOOPBACK);
-+ qca8k_wait_for_phy_link_state(phy, 1);
-+ qca8k_write(priv, QCA8K_REG_PORT_STATUS(sw_port),
-+ QCA8K_PORT_STATUS_SPEED_1000 |
-+ QCA8K_PORT_STATUS_TXMAC |
-+ QCA8K_PORT_STATUS_RXMAC |
-+ QCA8K_PORT_STATUS_DUPLEX);
-+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(sw_port),
-+ QCA8K_PORT_LOOKUP_STATE_FORWARD,
-+ QCA8K_PORT_LOOKUP_STATE_FORWARD);
-+ } else { /* off */
-+ qca8k_write(priv, QCA8K_REG_PORT_STATUS(sw_port), 0);
-+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(sw_port),
-+ QCA8K_PORT_LOOKUP_STATE_DISABLED,
-+ QCA8K_PORT_LOOKUP_STATE_DISABLED);
-+ phy_write(phy, MII_BMCR, BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_RESET);
-+ /* turn off the power of the phys - so that unused
-+ ports do not raise links */
-+ phy_modify(phy, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
-+ }
-+}
-+
-+static void
-+qca8k_phy_pkt_gen_prep(struct qca8k_priv *priv, struct phy_device *phy,
-+ int pkts_num, int on)
-+{
-+ if (on) {
-+ /* enable CRC checker and packets counters */
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_CRC_AND_PKTS_COUNT, 0);
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_CRC_AND_PKTS_COUNT,
-+ QCA8075_MMD7_CNT_FRAME_CHK_EN | QCA8075_MMD7_CNT_SELFCLR);
-+ qca8k_wait_for_phy_link_state(phy, 1);
-+ /* packet number */
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_PKT_NUMB, pkts_num);
-+ /* pkt size - 1504 bytes + 20 bytes */
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_PKT_SIZE, 1504);
-+ } else { /* off */
-+ /* packet number */
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_PKT_NUMB, 0);
-+ /* disable CRC checker and packet counter */
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_CRC_AND_PKTS_COUNT, 0);
-+ /* disable traffic gen */
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_CTRL, 0);
-+ }
-+}
-+
-+static void
-+qca8k_wait_for_phy_pkt_gen_fin(struct qca8k_priv *priv, struct phy_device *phy)
-+{
-+ int val;
-+ /* wait for all traffic end: 4096(pkt num)*1524(size)*8ns(125MHz)=49938us */
-+ phy_read_mmd_poll_timeout(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_CTRL,
-+ val, !(val & QCA8075_MMD7_PKT_GEN_INPROGR),
-+ 50000, 1000000, true);
-+}
-+
-+static void
-+qca8k_start_phy_pkt_gen(struct phy_device *phy)
-+{
-+ /* start traffic gen */
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_PKT_GEN_CTRL,
-+ QCA8075_MMD7_PKT_GEN_START | QCA8075_MMD7_PKT_GEN_INPROGR);
-+}
-+
-+static int
-+qca8k_start_all_phys_pkt_gens(struct qca8k_priv *priv)
-+{
-+ struct phy_device *phy;
-+ phy = phy_device_create(priv->bus, QCA8075_MDIO_BRDCST_PHY_ADDR,
-+ 0, 0, NULL);
-+ if (!phy) {
-+ dev_err(priv->dev, "unable to create mdio broadcast PHY(0x%x)\n",
-+ QCA8075_MDIO_BRDCST_PHY_ADDR);
-+ return -ENODEV;
-+ }
-+
-+ qca8k_start_phy_pkt_gen(phy);
-+
-+ phy_device_free(phy);
-+ return 0;
-+}
-+
-+static int
-+qca8k_get_phy_pkt_gen_test_result(struct phy_device *phy, int pkts_num)
-+{
-+ u32 tx_ok, tx_error;
-+ u32 rx_ok, rx_error;
-+ u32 tx_ok_high16;
-+ u32 rx_ok_high16;
-+ u32 tx_all_ok, rx_all_ok;
-+
-+ /* check counters */
-+ tx_ok = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_EG_FRAME_RECV_CNT_LO);
-+ tx_ok_high16 = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_EG_FRAME_RECV_CNT_HI);
-+ tx_error = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_EG_FRAME_ERR_CNT);
-+ rx_ok = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_IG_FRAME_RECV_CNT_LO);
-+ rx_ok_high16 = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_IG_FRAME_RECV_CNT_HI);
-+ rx_error = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_IG_FRAME_ERR_CNT);
-+ tx_all_ok = tx_ok + (tx_ok_high16 << 16);
-+ rx_all_ok = rx_ok + (rx_ok_high16 << 16);
-+
-+ if (tx_all_ok < pkts_num)
-+ return -1;
-+ if(rx_all_ok < pkts_num)
-+ return -2;
-+ if(tx_error)
-+ return -3;
-+ if(rx_error)
-+ return -4;
-+ return 0; /* test is ok */
-+}
-+
-+static
-+void qca8k_phy_broadcast_write_on_off(struct qca8k_priv *priv,
-+ struct phy_device *phy, int on)
-+{
-+ u32 val;
-+
-+ val = phy_read_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_MDIO_BRDCST_WRITE);
-+
-+ if (on == 0)
-+ val &= ~QCA8075_MMD7_MDIO_BRDCST_WRITE_EN;
-+ else
-+ val |= QCA8075_MMD7_MDIO_BRDCST_WRITE_EN;
-+
-+ phy_write_mmd(phy, MDIO_MMD_AN, QCA8075_MMD7_MDIO_BRDCST_WRITE, val);
-+}
-+
-+static int
-+qca8k_test_dsa_port_for_errors(struct qca8k_priv *priv, struct phy_device *phy,
-+ int port, int test_phase)
-+{
-+ int res = 0;
-+ const int test_pkts_num = QCA8075_PKT_GEN_PKTS_COUNT;
-+
-+ if (test_phase == 1) { /* start test preps */
-+ qca8k_phy_loopback_on_off(priv, phy, port, 1);
-+ qca8k_switch_port_loopback_on_off(priv, port, 1);
-+ qca8k_phy_broadcast_write_on_off(priv, phy, 1);
-+ qca8k_phy_pkt_gen_prep(priv, phy, test_pkts_num, 1);
-+ } else if (test_phase == 2) {
-+ /* wait for test results, collect it and cleanup */
-+ qca8k_wait_for_phy_pkt_gen_fin(priv, phy);
-+ res = qca8k_get_phy_pkt_gen_test_result(phy, test_pkts_num);
-+ qca8k_phy_pkt_gen_prep(priv, phy, test_pkts_num, 0);
-+ qca8k_phy_broadcast_write_on_off(priv, phy, 0);
-+ qca8k_switch_port_loopback_on_off(priv, port, 0);
-+ qca8k_phy_loopback_on_off(priv, phy, port, 0);
-+ }
-+
-+ return res;
-+}
-+
-+static int
-+qca8k_do_dsa_sw_ports_self_test(struct qca8k_priv *priv, int parallel_test)
-+{
-+ struct device_node *dn = priv->dev->of_node;
-+ struct device_node *ports, *port;
-+ struct device_node *phy_dn;
-+ struct phy_device *phy;
-+ int reg, err = 0, test_phase;
-+ u32 tests_result = 0;
-+
-+ ports = of_get_child_by_name(dn, "ports");
-+ if (!ports) {
-+ dev_err(priv->dev, "no ports child node found\n");
-+ return -EINVAL;
-+ }
-+
-+ for (test_phase = 1; test_phase <= 2; test_phase++) {
-+ if (parallel_test && test_phase == 2) {
-+ err = qca8k_start_all_phys_pkt_gens(priv);
-+ if (err)
-+ goto error;
-+ }
-+ for_each_available_child_of_node(ports, port) {
-+ err = of_property_read_u32(port, "reg", &reg);
-+ if (err)
-+ goto error;
-+ if (reg >= QCA8K_NUM_PORTS) {
-+ err = -EINVAL;
-+ goto error;
-+ }
-+ phy_dn = of_parse_phandle(port, "phy-handle", 0);
-+ if (phy_dn) {
-+ phy = of_phy_find_device(phy_dn);
-+ of_node_put(phy_dn);
-+ if (phy) {
-+ int result;
-+ result = qca8k_test_dsa_port_for_errors(priv,
-+ phy, reg, test_phase);
-+ if (!parallel_test && test_phase == 1)
-+ qca8k_start_phy_pkt_gen(phy);
-+ put_device(&phy->mdio.dev);
-+ if (test_phase == 2) {
-+ tests_result <<= 1;
-+ if (result)
-+ tests_result |= 1;
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+end:
-+ of_node_put(ports);
-+ qca8k_fdb_flush(priv);
-+ return tests_result;
-+error:
-+ tests_result |= 0xf000;
-+ goto end;
-+}
-+
-+static int
-+psgmii_vco_calibrate_and_test(struct dsa_switch *ds)
-+{
-+ int ret, a, test_result;
-+ struct qca8k_priv *priv = ds->priv;
-+
-+ for (a = 0; a <= QCA8K_PSGMII_CALB_NUM; a++) {
-+ ret = psgmii_vco_calibrate(priv);
-+ if (ret)
-+ return ret;
-+ /* first we run serial test */
-+ test_result = qca8k_do_dsa_sw_ports_self_test(priv, 0);
-+ /* and if it is ok then we run the test in parallel */
-+ if (!test_result)
-+ test_result = qca8k_do_dsa_sw_ports_self_test(priv, 1);
-+ if (!test_result) {
-+ if (a > 0) {
-+ dev_warn(priv->dev, "PSGMII work was stabilized after %d "
-+ "calibration retries !\n", a);
-+ }
-+ return 0;
-+ } else {
-+ schedule();
-+ if (a > 0 && a % 10 == 0) {
-+ dev_err(priv->dev, "PSGMII work is unstable !!! "
-+ "Let's try to wait a bit ... %d\n", a);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(msecs_to_jiffies(a * 100));
-+ }
-+ }
-+ }
-+
-+ panic("PSGMII work is unstable !!! "
-+ "Repeated recalibration attempts did not help(0x%x) !\n",
-+ test_result);
-+
-+ return -EFAULT;
-+}
-+
-+static int
-+ipq4019_psgmii_configure(struct dsa_switch *ds)
-+{
-+ struct qca8k_priv *priv = ds->priv;
-+ int ret;
-+
-+ if (!priv->psgmii_calibrated) {
-+ dev_info(ds->dev, "PSGMII calibration!\n");
-+ ret = psgmii_vco_calibrate_and_test(ds);
-+
-+ ret = regmap_clear_bits(priv->psgmii, PSGMIIPHY_MODE_CONTROL,
-+ PSGMIIPHY_MODE_ATHR_CSCO_MODE_25M);
-+ ret = regmap_write(priv->psgmii, PSGMIIPHY_TX_CONTROL,
-+ PSGMIIPHY_TX_CONTROL_MAGIC_VALUE);
-+
-+ priv->psgmii_calibrated = true;
-+
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static void
-+qca8k_phylink_ipq4019_mac_config(struct dsa_switch *ds, int port,
-+ unsigned int mode,
-+ const struct phylink_link_state *state)
-+{
-+ struct qca8k_priv *priv = ds->priv;
-+
-+ switch (port) {
-+ case 0:
-+ /* CPU port, no configuration needed */
-+ return;
-+ case 1:
-+ case 2:
-+ case 3:
-+ if (state->interface == PHY_INTERFACE_MODE_PSGMII)
-+ if (ipq4019_psgmii_configure(ds))
-+ dev_err(ds->dev, "PSGMII configuration failed!\n");
-+ return;
-+ case 4:
-+ case 5:
-+ if (state->interface == PHY_INTERFACE_MODE_RGMII ||
-+ state->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-+ state->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
-+ state->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
-+ regmap_set_bits(priv->regmap,
-+ QCA8K_IPQ4019_REG_RGMII_CTRL,
-+ QCA8K_IPQ4019_RGMII_CTRL_CLK);
-+ }
-+
-+ if (state->interface == PHY_INTERFACE_MODE_PSGMII)
-+ if (ipq4019_psgmii_configure(ds))
-+ dev_err(ds->dev, "PSGMII configuration failed!\n");
-+ return;
-+ default:
-+ dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
-+ return;
-+ }
-+}
-+
-+static int
-+qca8k_ipq4019_setup_port(struct dsa_switch *ds, int port)
-+{
-+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
-+ int ret;
-+
-+ /* CPU port gets connected to all user ports of the switch */
-+ if (dsa_is_cpu_port(ds, port)) {
-+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
-+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
-+ if (ret)
-+ return ret;
-+
-+ /* Disable CPU ARP Auto-learning by default */
-+ ret = regmap_clear_bits(priv->regmap,
-+ QCA8K_PORT_LOOKUP_CTRL(port),
-+ QCA8K_PORT_LOOKUP_LEARN);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* Individual user ports get connected to CPU port only */
-+ if (dsa_is_user_port(ds, port)) {
-+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
-+ QCA8K_PORT_LOOKUP_MEMBER,
-+ BIT(QCA8K_IPQ4019_CPU_PORT));
-+ if (ret)
-+ return ret;
-+
-+ /* Enable ARP Auto-learning by default */
-+ ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
-+ QCA8K_PORT_LOOKUP_LEARN);
-+ if (ret)
-+ return ret;
-+
-+ /* For port based vlans to work we need to set the
-+ * default egress vid
-+ */
-+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
-+ QCA8K_EGREES_VLAN_PORT_MASK(port),
-+ QCA8K_EGREES_VLAN_PORT(port, QCA8K_PORT_VID_DEF));
-+ if (ret)
-+ return ret;
-+
-+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
-+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
-+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+qca8k_ipq4019_setup(struct dsa_switch *ds)
-+{
-+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
-+ int ret, i;
-+
-+ /* Make sure that port 0 is the cpu port */
-+ if (!dsa_is_cpu_port(ds, QCA8K_IPQ4019_CPU_PORT)) {
-+ dev_err(priv->dev, "port %d is not the CPU port",
-+ QCA8K_IPQ4019_CPU_PORT);
-+ return -EINVAL;
-+ }
-+
-+ qca8k_ipq4019_setup_pcs(priv, &priv->pcs_port_0, 0);
-+
-+ /* Enable CPU Port */
-+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
-+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
-+ if (ret) {
-+ dev_err(priv->dev, "failed enabling CPU port");
-+ return ret;
-+ }
-+
-+ /* Enable MIB counters */
-+ ret = qca8k_mib_init(priv);
-+ if (ret)
-+ dev_warn(priv->dev, "MIB init failed");
-+
-+ /* Disable forwarding by default on all ports */
-+ for (i = 0; i < QCA8K_IPQ4019_NUM_PORTS; i++) {
-+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
-+ QCA8K_PORT_LOOKUP_MEMBER, 0);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* Enable QCA header mode on the CPU port */
-+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_IPQ4019_CPU_PORT),
-+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) |
-+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL));
-+ if (ret) {
-+ dev_err(priv->dev, "failed enabling QCA header mode");
-+ return ret;
-+ }
-+
-+ /* Disable MAC by default on all ports */
-+ for (i = 0; i < QCA8K_IPQ4019_NUM_PORTS; i++) {
-+ if (dsa_is_user_port(ds, i))
-+ qca8k_port_set_status(priv, i, 0);
-+ }
-+
-+ /* Forward all unknown frames to CPU port for Linux processing */
-+ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
-+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(QCA8K_IPQ4019_CPU_PORT)) |
-+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(QCA8K_IPQ4019_CPU_PORT)) |
-+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(QCA8K_IPQ4019_CPU_PORT)) |
-+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(QCA8K_IPQ4019_CPU_PORT)));
-+ if (ret)
-+ return ret;
-+
-+ /* Setup connection between CPU port & user ports */
-+ for (i = 0; i < QCA8K_IPQ4019_NUM_PORTS; i++) {
-+ ret = qca8k_ipq4019_setup_port(ds, i);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* Setup our port MTUs to match power on defaults */
-+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
-+ if (ret)
-+ dev_warn(priv->dev, "failed setting MTU settings");
-+
-+ /* Flush the FDB table */
-+ qca8k_fdb_flush(priv);
-+
-+ /* Set min a max ageing value supported */
-+ ds->ageing_time_min = 7000;
-+ ds->ageing_time_max = 458745000;
-+
-+ /* Set max number of LAGs supported */
-+ ds->num_lag_ids = QCA8K_NUM_LAGS;
-+
-+ /* CPU port HW learning doesnt work correctly, so let DSA handle it */
-+ ds->assisted_learning_on_cpu_port = true;
-+
-+ return 0;
-+}
-+
-+static const struct dsa_switch_ops qca8k_ipq4019_switch_ops = {
-+ .get_tag_protocol = qca8k_ipq4019_get_tag_protocol,
-+ .setup = qca8k_ipq4019_setup,
-+ .get_strings = qca8k_get_strings,
-+ .get_ethtool_stats = qca8k_get_ethtool_stats,
-+ .get_sset_count = qca8k_get_sset_count,
-+ .set_ageing_time = qca8k_set_ageing_time,
-+ .get_mac_eee = qca8k_get_mac_eee,
-+ .set_mac_eee = qca8k_set_mac_eee,
-+ .port_enable = qca8k_port_enable,
-+ .port_disable = qca8k_port_disable,
-+ .port_change_mtu = qca8k_port_change_mtu,
-+ .port_max_mtu = qca8k_port_max_mtu,
-+ .port_stp_state_set = qca8k_port_stp_state_set,
-+ .port_bridge_join = qca8k_port_bridge_join,
-+ .port_bridge_leave = qca8k_port_bridge_leave,
-+ .port_fast_age = qca8k_port_fast_age,
-+ .port_fdb_add = qca8k_port_fdb_add,
-+ .port_fdb_del = qca8k_port_fdb_del,
-+ .port_fdb_dump = qca8k_port_fdb_dump,
-+ .port_mdb_add = qca8k_port_mdb_add,
-+ .port_mdb_del = qca8k_port_mdb_del,
-+ .port_mirror_add = qca8k_port_mirror_add,
-+ .port_mirror_del = qca8k_port_mirror_del,
-+ .port_vlan_filtering = qca8k_port_vlan_filtering,
-+ .port_vlan_add = qca8k_port_vlan_add,
-+ .port_vlan_del = qca8k_port_vlan_del,
-+ .phylink_mac_select_pcs = qca8k_ipq4019_phylink_mac_select_pcs,
-+ .phylink_get_caps = qca8k_ipq4019_phylink_get_caps,
-+ .phylink_mac_config = qca8k_phylink_ipq4019_mac_config,
-+ .phylink_mac_link_down = qca8k_phylink_ipq4019_mac_link_down,
-+ .phylink_mac_link_up = qca8k_phylink_ipq4019_mac_link_up,
-+ .port_lag_join = qca8k_port_lag_join,
-+ .port_lag_leave = qca8k_port_lag_leave,
-+};
-+
-+static const struct qca8k_match_data ipq4019 = {
-+ .id = QCA8K_ID_IPQ4019,
-+ .mib_count = QCA8K_QCA833X_MIB_COUNT,
-+};
-+
-+static int
-+qca8k_ipq4019_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct qca8k_priv *priv;
-+ void __iomem *base, *psgmii;
-+ struct device_node *np = dev->of_node, *mdio_np, *psgmii_ethphy_np;
-+ int ret;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ priv->dev = dev;
-+ priv->info = &ipq4019;
-+
-+ /* Start by setting up the register mapping */
-+ base = devm_platform_ioremap_resource_byname(pdev, "base");
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ priv->regmap = devm_regmap_init_mmio(dev, base,
-+ &qca8k_ipq4019_regmap_config);
-+ if (IS_ERR(priv->regmap)) {
-+ ret = PTR_ERR(priv->regmap);
-+ dev_err(dev, "base regmap initialization failed, %d\n", ret);
-+ return ret;
-+ }
-+
-+ psgmii = devm_platform_ioremap_resource_byname(pdev, "psgmii_phy");
-+ if (IS_ERR(psgmii))
-+ return PTR_ERR(psgmii);
-+
-+ priv->psgmii = devm_regmap_init_mmio(dev, psgmii,
-+ &qca8k_ipq4019_psgmii_phy_regmap_config);
-+ if (IS_ERR(priv->psgmii)) {
-+ ret = PTR_ERR(priv->psgmii);
-+ dev_err(dev, "PSGMII regmap initialization failed, %d\n", ret);
-+ return ret;
-+ }
-+
-+ mdio_np = of_parse_phandle(np, "mdio", 0);
-+ if (!mdio_np) {
-+ dev_err(dev, "unable to get MDIO bus phandle\n");
-+ of_node_put(mdio_np);
-+ return -EINVAL;
-+ }
-+
-+ priv->bus = of_mdio_find_bus(mdio_np);
-+ of_node_put(mdio_np);
-+ if (!priv->bus) {
-+ dev_err(dev, "unable to find MDIO bus\n");
-+ return -EPROBE_DEFER;
-+ }
-+
-+ psgmii_ethphy_np = of_parse_phandle(np, "psgmii-ethphy", 0);
-+ if (!psgmii_ethphy_np) {
-+ dev_dbg(dev, "unable to get PSGMII eth PHY phandle\n");
-+ of_node_put(psgmii_ethphy_np);
-+ }
-+
-+ if (psgmii_ethphy_np) {
-+ priv->psgmii_ethphy = of_phy_find_device(psgmii_ethphy_np);
-+ of_node_put(psgmii_ethphy_np);
-+ if (!priv->psgmii_ethphy) {
-+ dev_err(dev, "unable to get PSGMII eth PHY\n");
-+ return -ENODEV;
-+ }
-+ }
-+
-+ /* Check the detected switch id */
-+ ret = qca8k_read_switch_id(priv);
-+ if (ret)
-+ return ret;
-+
-+ priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
-+ if (!priv->ds)
-+ return -ENOMEM;
-+
-+ priv->ds->dev = dev;
-+ priv->ds->num_ports = QCA8K_IPQ4019_NUM_PORTS;
-+ priv->ds->priv = priv;
-+ priv->ds->ops = &qca8k_ipq4019_switch_ops;
-+ mutex_init(&priv->reg_mutex);
-+ platform_set_drvdata(pdev, priv);
-+
-+ return dsa_register_switch(priv->ds);
-+}
-+
-+static int
-+qca8k_ipq4019_remove(struct platform_device *pdev)
-+{
-+ struct qca8k_priv *priv = dev_get_drvdata(&pdev->dev);
-+ int i;
-+
-+ if (!priv)
-+ return 0;
-+
-+ for (i = 0; i < QCA8K_IPQ4019_NUM_PORTS; i++)
-+ qca8k_port_set_status(priv, i, 0);
-+
-+ dsa_unregister_switch(priv->ds);
-+
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id qca8k_ipq4019_of_match[] = {
-+ { .compatible = "qca,ipq4019-qca8337n", },
-+ { /* sentinel */ },
-+};
-+
-+static struct platform_driver qca8k_ipq4019_driver = {
-+ .probe = qca8k_ipq4019_probe,
-+ .remove = qca8k_ipq4019_remove,
-+ .driver = {
-+ .name = "qca8k-ipq4019",
-+ .of_match_table = qca8k_ipq4019_of_match,
-+ },
-+};
-+
-+module_platform_driver(qca8k_ipq4019_driver);
-+
-+MODULE_AUTHOR("Mathieu Olivari, John Crispin <john@phrozen.org>");
-+MODULE_AUTHOR("Gabor Juhos <j4g8y7@gmail.com>, Robert Marko <robert.marko@sartura.hr>");
-+MODULE_DESCRIPTION("Qualcomm IPQ4019 built-in switch driver");
-+MODULE_LICENSE("GPL");
---- a/drivers/net/dsa/qca/qca8k.h
-+++ b/drivers/net/dsa/qca/qca8k.h
-@@ -19,7 +19,10 @@
- #define QCA8K_ETHERNET_TIMEOUT 5
-
- #define QCA8K_NUM_PORTS 7
-+#define QCA8K_IPQ4019_NUM_PORTS 6
- #define QCA8K_NUM_CPU_PORTS 2
-+#define QCA8K_IPQ4019_NUM_CPU_PORTS 1
-+#define QCA8K_IPQ4019_CPU_PORT 0
- #define QCA8K_MAX_MTU 9000
- #define QCA8K_NUM_LAGS 4
- #define QCA8K_NUM_PORTS_FOR_LAG 4
-@@ -28,6 +31,7 @@
- #define QCA8K_ID_QCA8327 0x12
- #define PHY_ID_QCA8337 0x004dd036
- #define QCA8K_ID_QCA8337 0x13
-+#define QCA8K_ID_IPQ4019 0x14
-
- #define QCA8K_QCA832X_MIB_COUNT 39
- #define QCA8K_QCA833X_MIB_COUNT 41
-@@ -265,6 +269,7 @@
- #define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3)
- #define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4)
- #define QCA8K_PORT_LOOKUP_LEARN BIT(20)
-+#define QCA8K_PORT_LOOKUP_LOOPBACK_EN BIT(21)
- #define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
-
- #define QCA8K_REG_GOL_TRUNK_CTRL0 0x700
-@@ -341,6 +346,53 @@
- #define MII_ATH_MMD_ADDR 0x0d
- #define MII_ATH_MMD_DATA 0x0e
-
-+/* IPQ4019 PSGMII PHY registers */
-+#define QCA8K_IPQ4019_REG_RGMII_CTRL 0x004
-+#define QCA8K_IPQ4019_RGMII_CTRL_RGMII_RXC GENMASK(1, 0)
-+#define QCA8K_IPQ4019_RGMII_CTRL_RGMII_TXC GENMASK(9, 8)
-+/* Some kind of CLK selection
-+ * 0: gcc_ess_dly2ns
-+ * 1: gcc_ess_clk
-+ */
-+#define QCA8K_IPQ4019_RGMII_CTRL_CLK BIT(10)
-+#define QCA8K_IPQ4019_RGMII_CTRL_DELAY_RMII0 GENMASK(17, 16)
-+#define QCA8K_IPQ4019_RGMII_CTRL_INVERT_RMII0_REF_CLK BIT(18)
-+#define QCA8K_IPQ4019_RGMII_CTRL_DELAY_RMII1 GENMASK(20, 19)
-+#define QCA8K_IPQ4019_RGMII_CTRL_INVERT_RMII1_REF_CLK BIT(21)
-+#define QCA8K_IPQ4019_RGMII_CTRL_INVERT_RMII0_MASTER_EN BIT(24)
-+#define QCA8K_IPQ4019_RGMII_CTRL_INVERT_RMII1_MASTER_EN BIT(25)
-+
-+#define PSGMIIPHY_MODE_CONTROL 0x1b4
-+#define PSGMIIPHY_MODE_ATHR_CSCO_MODE_25M BIT(0)
-+#define PSGMIIPHY_TX_CONTROL 0x288
-+#define PSGMIIPHY_TX_CONTROL_MAGIC_VALUE 0x8380
-+#define PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_1 0x9c
-+#define PSGMIIPHY_REG_PLL_VCO_CALIB_RESTART BIT(14)
-+#define PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_2 0xa0
-+#define PSGMIIPHY_REG_PLL_VCO_CALIB_READY BIT(0)
-+
-+#define QCA8K_PSGMII_CALB_NUM 100
-+#define MII_QCA8075_SSTATUS 0x11
-+#define QCA8075_PHY_SPEC_STATUS_LINK BIT(10)
-+#define QCA8075_MMD7_CRC_AND_PKTS_COUNT 0x8029
-+#define QCA8075_MMD7_PKT_GEN_PKT_NUMB 0x8021
-+#define QCA8075_MMD7_PKT_GEN_PKT_SIZE 0x8062
-+#define QCA8075_MMD7_PKT_GEN_CTRL 0x8020
-+#define QCA8075_MMD7_CNT_SELFCLR BIT(1)
-+#define QCA8075_MMD7_CNT_FRAME_CHK_EN BIT(0)
-+#define QCA8075_MMD7_PKT_GEN_START BIT(13)
-+#define QCA8075_MMD7_PKT_GEN_INPROGR BIT(15)
-+#define QCA8075_MMD7_IG_FRAME_RECV_CNT_HI 0x802a
-+#define QCA8075_MMD7_IG_FRAME_RECV_CNT_LO 0x802b
-+#define QCA8075_MMD7_IG_FRAME_ERR_CNT 0x802c
-+#define QCA8075_MMD7_EG_FRAME_RECV_CNT_HI 0x802d
-+#define QCA8075_MMD7_EG_FRAME_RECV_CNT_LO 0x802e
-+#define QCA8075_MMD7_EG_FRAME_ERR_CNT 0x802f
-+#define QCA8075_MMD7_MDIO_BRDCST_WRITE 0x8028
-+#define QCA8075_MMD7_MDIO_BRDCST_WRITE_EN BIT(15)
-+#define QCA8075_MDIO_BRDCST_PHY_ADDR 0x1f
-+#define QCA8075_PKT_GEN_PKTS_COUNT 4096
-+
- enum {
- QCA8K_PORT_SPEED_10M = 0,
- QCA8K_PORT_SPEED_100M = 1,
-@@ -466,6 +518,10 @@ struct qca8k_priv {
- struct qca8k_pcs pcs_port_6;
- const struct qca8k_match_data *info;
- struct qca8k_led ports_led[QCA8K_LED_COUNT];
-+ /* IPQ4019 specific */
-+ struct regmap *psgmii;
-+ struct phy_device *psgmii_ethphy;
-+ bool psgmii_calibrated;
- };
-
- struct qca8k_mib_desc {