net: ethernet: stmmac: add missing sgmii configure for ipq806x
authorChristian 'Ansuel' Marangi <ansuelsmth@gmail.com>
Tue, 14 Jun 2022 11:22:27 +0000 (13:22 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 16 Jun 2022 08:13:20 +0000 (10:13 +0200)
The different gmacid require different configuration based on the soc
and on the gmac id. Add these missing configuration taken from the
original driver.

Signed-off-by: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
Link: https://lore.kernel.org/r/20220614112228.1998-1-ansuelsmth@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/stmicro/stmmac/Kconfig
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c

index 929cfc2..c4bca16 100644 (file)
@@ -83,6 +83,7 @@ config DWMAC_IPQ806X
        default ARCH_QCOM
        depends on OF && (ARCH_QCOM || COMPILE_TEST)
        select MFD_SYSCON
+       select QCOM_SOCINFO
        help
          Support for QCA IPQ806X DWMAC Ethernet.
 
index f7dc845..832f442 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/stmmac.h>
 #include <linux/of_mdio.h>
 #include <linux/module.h>
+#include <linux/sys_soc.h>
+#include <linux/bitfield.h>
 
 #include "stmmac_platform.h"
 
 #define QSGMII_PHY_RX_SIGNAL_DETECT_EN         BIT(2)
 #define QSGMII_PHY_TX_DRIVER_EN                        BIT(3)
 #define QSGMII_PHY_QSGMII_EN                   BIT(7)
-#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET      12
-#define QSGMII_PHY_RX_DC_BIAS_OFFSET           18
-#define QSGMII_PHY_RX_INPUT_EQU_OFFSET         20
-#define QSGMII_PHY_CDR_PI_SLEW_OFFSET          22
-#define QSGMII_PHY_TX_DRV_AMP_OFFSET           28
+#define QSGMII_PHY_DEEMPHASIS_LVL_MASK         GENMASK(11, 10)
+#define QSGMII_PHY_DEEMPHASIS_LVL(x)           FIELD_PREP(QSGMII_PHY_DEEMPHASIS_LVL_MASK, (x))
+#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK                GENMASK(14, 12)
+#define QSGMII_PHY_PHASE_LOOP_GAIN(x)          FIELD_PREP(QSGMII_PHY_PHASE_LOOP_GAIN_MASK, (x))
+#define QSGMII_PHY_RX_DC_BIAS_MASK             GENMASK(19, 18)
+#define QSGMII_PHY_RX_DC_BIAS(x)               FIELD_PREP(QSGMII_PHY_RX_DC_BIAS_MASK, (x))
+#define QSGMII_PHY_RX_INPUT_EQU_MASK           GENMASK(21, 20)
+#define QSGMII_PHY_RX_INPUT_EQU(x)             FIELD_PREP(QSGMII_PHY_RX_INPUT_EQU_MASK, (x))
+#define QSGMII_PHY_CDR_PI_SLEW_MASK            GENMASK(23, 22)
+#define QSGMII_PHY_CDR_PI_SLEW(x)              FIELD_PREP(QSGMII_PHY_CDR_PI_SLEW_MASK, (x))
+#define QSGMII_PHY_TX_SLEW_MASK                        GENMASK(27, 26)
+#define QSGMII_PHY_TX_SLEW(x)                  FIELD_PREP(QSGMII_PHY_TX_SLEW_MASK, (x))
+#define QSGMII_PHY_TX_DRV_AMP_MASK             GENMASK(31, 28)
+#define QSGMII_PHY_TX_DRV_AMP(x)               FIELD_PREP(QSGMII_PHY_TX_DRV_AMP_MASK, (x))
 
 struct ipq806x_gmac {
        struct platform_device *pdev;
@@ -242,6 +253,64 @@ static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
        ipq806x_gmac_set_speed(gmac, speed);
 }
 
+static const struct soc_device_attribute ipq806x_gmac_soc_v1[] = {
+       {
+               .revision = "1.*",
+       },
+       {
+               /* sentinel */
+       }
+};
+
+static int
+ipq806x_gmac_configure_qsgmii_params(struct ipq806x_gmac *gmac)
+{
+       struct platform_device *pdev = gmac->pdev;
+       const struct soc_device_attribute *soc;
+       struct device *dev = &pdev->dev;
+       u32 qsgmii_param;
+
+       switch (gmac->id) {
+       case 1:
+               soc = soc_device_match(ipq806x_gmac_soc_v1);
+
+               if (soc)
+                       qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xc) |
+                                      QSGMII_PHY_TX_SLEW(0x2) |
+                                      QSGMII_PHY_DEEMPHASIS_LVL(0x2);
+               else
+                       qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xd) |
+                                      QSGMII_PHY_TX_SLEW(0x0) |
+                                      QSGMII_PHY_DEEMPHASIS_LVL(0x0);
+
+               qsgmii_param |= QSGMII_PHY_RX_DC_BIAS(0x2);
+               break;
+       case 2:
+       case 3:
+               qsgmii_param = QSGMII_PHY_RX_DC_BIAS(0x3) |
+                              QSGMII_PHY_TX_DRV_AMP(0xc);
+               break;
+       default: /* gmac 0 can't be set in SGMII mode */
+               dev_err(dev, "gmac id %d can't be in SGMII mode", gmac->id);
+               return -EINVAL;
+       }
+
+       /* Common params across all gmac id */
+       qsgmii_param |= QSGMII_PHY_CDR_EN |
+                       QSGMII_PHY_RX_FRONT_EN |
+                       QSGMII_PHY_RX_SIGNAL_DETECT_EN |
+                       QSGMII_PHY_TX_DRIVER_EN |
+                       QSGMII_PHY_QSGMII_EN |
+                       QSGMII_PHY_PHASE_LOOP_GAIN(0x4) |
+                       QSGMII_PHY_RX_INPUT_EQU(0x1) |
+                       QSGMII_PHY_CDR_PI_SLEW(0x2);
+
+       regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
+                    qsgmii_param);
+
+       return 0;
+}
+
 static int ipq806x_gmac_probe(struct platform_device *pdev)
 {
        struct plat_stmmacenet_data *plat_dat;
@@ -328,17 +397,9 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
        regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
 
        if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
-               regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
-                            QSGMII_PHY_CDR_EN |
-                            QSGMII_PHY_RX_FRONT_EN |
-                            QSGMII_PHY_RX_SIGNAL_DETECT_EN |
-                            QSGMII_PHY_TX_DRIVER_EN |
-                            QSGMII_PHY_QSGMII_EN |
-                            0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
-                            0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET |
-                            0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
-                            0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
-                            0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET);
+               err = ipq806x_gmac_configure_qsgmii_params(gmac);
+               if (err)
+                       goto err_remove_config_dt;
        }
 
        plat_dat->has_gmac = true;