Revert "net: ethernet: qualcomm: Remove QDF24xx support"
authorJakub Kicinski <kuba@kernel.org>
Wed, 24 Jan 2024 17:43:30 +0000 (09:43 -0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 24 Jan 2024 17:43:34 +0000 (09:43 -0800)
This reverts commit a2a7f98aeeec48118fac73c22bd54f8889815e16.

Konrad mentioned that Qualcomm appears to use these devices, still,
internally, even tho they never made it to the broader market.

Link: https://lore.kernel.org/all/0679f568-60e7-47d8-b86e-052a9eb4c103@linaro.org/
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/qualcomm/emac/Makefile
drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c [new file with mode: 0644]
drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c [new file with mode: 0644]
drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
drivers/net/ethernet/qualcomm/emac/emac-sgmii.h

index ffc00995acb9294f3031eb3d778d7e2aa034ec2d..61d15e091be25462dd0423bcfca14c14467e1611 100644 (file)
@@ -6,4 +6,5 @@
 obj-$(CONFIG_QCOM_EMAC) += qcom-emac.o
 
 qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o emac-ethtool.o \
-                 emac-sgmii-fsm9900.o
+                 emac-sgmii-fsm9900.o emac-sgmii-qdf2432.o \
+                 emac-sgmii-qdf2400.o
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2400.c
new file mode 100644 (file)
index 0000000..b29148c
--- /dev/null
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ */
+
+/* Qualcomm Technologies, Inc. QDF2400 EMAC SGMII Controller driver.
+ */
+
+#include <linux/iopoll.h>
+#include "emac.h"
+
+/* EMAC_SGMII register offsets */
+#define EMAC_SGMII_PHY_TX_PWR_CTRL             0x000C
+#define EMAC_SGMII_PHY_LANE_CTRL1              0x0018
+#define EMAC_SGMII_PHY_CDR_CTRL0               0x0058
+#define EMAC_SGMII_PHY_POW_DWN_CTRL0           0x0080
+#define EMAC_SGMII_PHY_RESET_CTRL              0x00a8
+#define EMAC_SGMII_PHY_INTERRUPT_MASK          0x00b4
+
+/* SGMII digital lane registers */
+#define EMAC_SGMII_LN_DRVR_CTRL0               0x000C
+#define EMAC_SGMII_LN_DRVR_CTRL1               0x0010
+#define EMAC_SGMII_LN_DRVR_TAP_EN              0x0018
+#define EMAC_SGMII_LN_TX_MARGINING             0x001C
+#define EMAC_SGMII_LN_TX_PRE                   0x0020
+#define EMAC_SGMII_LN_TX_POST                  0x0024
+#define EMAC_SGMII_LN_TX_BAND_MODE             0x0060
+#define EMAC_SGMII_LN_LANE_MODE                        0x0064
+#define EMAC_SGMII_LN_PARALLEL_RATE            0x007C
+#define EMAC_SGMII_LN_CML_CTRL_MODE0           0x00C0
+#define EMAC_SGMII_LN_MIXER_CTRL_MODE0         0x00D8
+#define EMAC_SGMII_LN_VGA_INITVAL              0x013C
+#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0       0x0184
+#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0       0x0190
+#define EMAC_SGMII_LN_UCDR_SO_CONFIG           0x019C
+#define EMAC_SGMII_LN_RX_BAND                  0x01A4
+#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0      0x01C0
+#define EMAC_SGMII_LN_RSM_CONFIG               0x01F8
+#define EMAC_SGMII_LN_SIGDET_ENABLES           0x0230
+#define EMAC_SGMII_LN_SIGDET_CNTRL             0x0234
+#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL    0x0238
+#define EMAC_SGMII_LN_RX_EN_SIGNAL             0x02AC
+#define EMAC_SGMII_LN_RX_MISC_CNTRL0           0x02B8
+#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV                0x02C8
+#define EMAC_SGMII_LN_RX_RESECODE_OFFSET       0x02CC
+
+/* SGMII digital lane register values */
+#define UCDR_STEP_BY_TWO_MODE0                 BIT(7)
+#define UCDR_xO_GAIN_MODE(x)                   ((x) & 0x7f)
+#define UCDR_ENABLE                            BIT(6)
+#define UCDR_SO_SATURATION(x)                  ((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS4                      BIT(7)
+#define SIGDET_EN_PS0_TO_PS2                   BIT(6)
+
+#define TXVAL_VALID_INIT                       BIT(4)
+#define KR_PCIGEN3_MODE                                BIT(0)
+
+#define MAIN_EN                                        BIT(0)
+
+#define TX_MARGINING_MUX                       BIT(6)
+#define TX_MARGINING(x)                                ((x) & 0x3f)
+
+#define TX_PRE_MUX                             BIT(6)
+
+#define TX_POST_MUX                            BIT(6)
+
+#define CML_GEAR_MODE(x)                       (((x) & 7) << 3)
+#define CML2CMOS_IBOOST_MODE(x)                        ((x) & 7)
+
+#define RESCODE_OFFSET(x)                      ((x) & 0x1f)
+
+#define MIXER_LOADB_MODE(x)                    (((x) & 0xf) << 2)
+#define MIXER_DATARATE_MODE(x)                 ((x) & 3)
+
+#define VGA_THRESH_DFE(x)                      ((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS0_TO_PS2               BIT(5)
+#define SIGDET_FLT_BYP                         BIT(0)
+
+#define SIGDET_LVL(x)                          (((x) & 0xf) << 4)
+
+#define SIGDET_DEGLITCH_CTRL(x)                        (((x) & 0xf) << 1)
+
+#define INVERT_PCS_RX_CLK                      BIT(7)
+
+#define DRVR_LOGIC_CLK_EN                      BIT(4)
+#define DRVR_LOGIC_CLK_DIV(x)                  ((x) & 0xf)
+
+#define PARALLEL_RATE_MODE0(x)                 ((x) & 0x3)
+
+#define BAND_MODE0(x)                          ((x) & 0x3)
+
+#define LANE_MODE(x)                           ((x) & 0x1f)
+
+#define CDR_PD_SEL_MODE0(x)                    (((x) & 0x3) << 5)
+#define EN_DLL_MODE0                           BIT(4)
+#define EN_IQ_DCC_MODE0                                BIT(3)
+#define EN_IQCAL_MODE0                         BIT(2)
+
+#define BYPASS_RSM_SAMP_CAL                    BIT(1)
+#define BYPASS_RSM_DLL_CAL                     BIT(0)
+
+#define L0_RX_EQUALIZE_ENABLE                  BIT(6)
+
+#define PWRDN_B                                        BIT(0)
+
+#define CDR_MAX_CNT(x)                         ((x) & 0xff)
+
+#define SERDES_START_WAIT_TIMES                        100
+
+struct emac_reg_write {
+       unsigned int offset;
+       u32 val;
+};
+
+static void emac_reg_write_all(void __iomem *base,
+                              const struct emac_reg_write *itr, size_t size)
+{
+       size_t i;
+
+       for (i = 0; i < size; ++itr, ++i)
+               writel(itr->val, base + itr->offset);
+}
+
+static const struct emac_reg_write sgmii_laned[] = {
+       /* CDR Settings */
+       {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
+               UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
+       {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
+       {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
+
+       /* TX/RX Settings */
+       {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},
+
+       {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
+       {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
+       {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
+       {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
+       {EMAC_SGMII_LN_TX_POST, TX_POST_MUX},
+
+       {EMAC_SGMII_LN_CML_CTRL_MODE0,
+               CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
+       {EMAC_SGMII_LN_MIXER_CTRL_MODE0,
+               MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
+       {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
+       {EMAC_SGMII_LN_SIGDET_ENABLES,
+               SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
+       {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},
+
+       {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
+       {EMAC_SGMII_LN_RX_MISC_CNTRL0, INVERT_PCS_RX_CLK},
+       {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
+               DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},
+
+       {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
+       {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(1)},
+       {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(2)},
+       {EMAC_SGMII_LN_DRVR_CTRL1, RESCODE_OFFSET(7)},
+       {EMAC_SGMII_LN_RX_RESECODE_OFFSET, RESCODE_OFFSET(9)},
+       {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
+       {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(2) |
+               EN_DLL_MODE0 | EN_IQ_DCC_MODE0 | EN_IQCAL_MODE0},
+       {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
+};
+
+static const struct emac_reg_write physical_coding_sublayer_programming[] = {
+       {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
+       {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
+       {EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
+       {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
+};
+
+int emac_sgmii_init_qdf2400(struct emac_adapter *adpt)
+{
+       struct emac_sgmii *phy = &adpt->phy;
+       void __iomem *phy_regs = phy->base;
+       void __iomem *laned = phy->digital;
+       unsigned int i;
+       u32 lnstatus;
+
+       /* PCS lane-x init */
+       emac_reg_write_all(phy->base, physical_coding_sublayer_programming,
+                          ARRAY_SIZE(physical_coding_sublayer_programming));
+
+       /* SGMII lane-x init */
+       emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned));
+
+       /* Power up PCS and start reset lane state machine */
+
+       writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
+       writel(1, laned + SGMII_LN_RSM_START);
+
+       /* Wait for c_ready assertion */
+       for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
+               lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
+               if (lnstatus & BIT(1))
+                       break;
+               usleep_range(100, 200);
+       }
+
+       if (i == SERDES_START_WAIT_TIMES) {
+               netdev_err(adpt->netdev, "SGMII failed to start\n");
+               return -EIO;
+       }
+
+       /* Disable digital and SERDES loopback */
+       writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
+       writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
+       writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);
+
+       /* Mask out all the SGMII Interrupt */
+       writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+       return 0;
+}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii-qdf2432.c
new file mode 100644 (file)
index 0000000..65519ee
--- /dev/null
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ */
+
+/* Qualcomm Technologies, Inc. QDF2432 EMAC SGMII Controller driver.
+ */
+
+#include <linux/iopoll.h>
+#include "emac.h"
+
+/* EMAC_SGMII register offsets */
+#define EMAC_SGMII_PHY_TX_PWR_CTRL             0x000C
+#define EMAC_SGMII_PHY_LANE_CTRL1              0x0018
+#define EMAC_SGMII_PHY_CDR_CTRL0               0x0058
+#define EMAC_SGMII_PHY_POW_DWN_CTRL0           0x0080
+#define EMAC_SGMII_PHY_RESET_CTRL              0x00a8
+#define EMAC_SGMII_PHY_INTERRUPT_MASK          0x00b4
+
+/* SGMII digital lane registers */
+#define EMAC_SGMII_LN_DRVR_CTRL0               0x000C
+#define EMAC_SGMII_LN_DRVR_TAP_EN              0x0018
+#define EMAC_SGMII_LN_TX_MARGINING             0x001C
+#define EMAC_SGMII_LN_TX_PRE                   0x0020
+#define EMAC_SGMII_LN_TX_POST                  0x0024
+#define EMAC_SGMII_LN_TX_BAND_MODE             0x0060
+#define EMAC_SGMII_LN_LANE_MODE                        0x0064
+#define EMAC_SGMII_LN_PARALLEL_RATE            0x0078
+#define EMAC_SGMII_LN_CML_CTRL_MODE0           0x00B8
+#define EMAC_SGMII_LN_MIXER_CTRL_MODE0         0x00D0
+#define EMAC_SGMII_LN_VGA_INITVAL              0x0134
+#define EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0       0x017C
+#define EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0       0x0188
+#define EMAC_SGMII_LN_UCDR_SO_CONFIG           0x0194
+#define EMAC_SGMII_LN_RX_BAND                  0x019C
+#define EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0      0x01B8
+#define EMAC_SGMII_LN_RSM_CONFIG               0x01F0
+#define EMAC_SGMII_LN_SIGDET_ENABLES           0x0224
+#define EMAC_SGMII_LN_SIGDET_CNTRL             0x0228
+#define EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL    0x022C
+#define EMAC_SGMII_LN_RX_EN_SIGNAL             0x02A0
+#define EMAC_SGMII_LN_RX_MISC_CNTRL0           0x02AC
+#define EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV                0x02BC
+
+/* SGMII digital lane register values */
+#define UCDR_STEP_BY_TWO_MODE0                 BIT(7)
+#define UCDR_xO_GAIN_MODE(x)                   ((x) & 0x7f)
+#define UCDR_ENABLE                            BIT(6)
+#define UCDR_SO_SATURATION(x)                  ((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS4                      BIT(7)
+#define SIGDET_EN_PS0_TO_PS2                   BIT(6)
+
+#define TXVAL_VALID_INIT                       BIT(4)
+#define KR_PCIGEN3_MODE                                BIT(0)
+
+#define MAIN_EN                                        BIT(0)
+
+#define TX_MARGINING_MUX                       BIT(6)
+#define TX_MARGINING(x)                                ((x) & 0x3f)
+
+#define TX_PRE_MUX                             BIT(6)
+
+#define TX_POST_MUX                            BIT(6)
+
+#define CML_GEAR_MODE(x)                       (((x) & 7) << 3)
+#define CML2CMOS_IBOOST_MODE(x)                        ((x) & 7)
+
+#define MIXER_LOADB_MODE(x)                    (((x) & 0xf) << 2)
+#define MIXER_DATARATE_MODE(x)                 ((x) & 3)
+
+#define VGA_THRESH_DFE(x)                      ((x) & 0x3f)
+
+#define SIGDET_LP_BYP_PS0_TO_PS2               BIT(5)
+#define SIGDET_FLT_BYP                         BIT(0)
+
+#define SIGDET_LVL(x)                          (((x) & 0xf) << 4)
+
+#define SIGDET_DEGLITCH_CTRL(x)                        (((x) & 0xf) << 1)
+
+#define DRVR_LOGIC_CLK_EN                      BIT(4)
+#define DRVR_LOGIC_CLK_DIV(x)                  ((x) & 0xf)
+
+#define PARALLEL_RATE_MODE0(x)                 ((x) & 0x3)
+
+#define BAND_MODE0(x)                          ((x) & 0x3)
+
+#define LANE_MODE(x)                           ((x) & 0x1f)
+
+#define CDR_PD_SEL_MODE0(x)                    (((x) & 0x3) << 5)
+#define BYPASS_RSM_SAMP_CAL                    BIT(1)
+#define BYPASS_RSM_DLL_CAL                     BIT(0)
+
+#define L0_RX_EQUALIZE_ENABLE                  BIT(6)
+
+#define PWRDN_B                                        BIT(0)
+
+#define CDR_MAX_CNT(x)                         ((x) & 0xff)
+
+#define SERDES_START_WAIT_TIMES                        100
+
+struct emac_reg_write {
+       unsigned int offset;
+       u32 val;
+};
+
+static void emac_reg_write_all(void __iomem *base,
+                              const struct emac_reg_write *itr, size_t size)
+{
+       size_t i;
+
+       for (i = 0; i < size; ++itr, ++i)
+               writel(itr->val, base + itr->offset);
+}
+
+static const struct emac_reg_write sgmii_laned[] = {
+       /* CDR Settings */
+       {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
+               UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
+       {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
+       {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
+
+       /* TX/RX Settings */
+       {EMAC_SGMII_LN_RX_EN_SIGNAL, SIGDET_LP_BYP_PS4 | SIGDET_EN_PS0_TO_PS2},
+
+       {EMAC_SGMII_LN_DRVR_CTRL0, TXVAL_VALID_INIT | KR_PCIGEN3_MODE},
+       {EMAC_SGMII_LN_DRVR_TAP_EN, MAIN_EN},
+       {EMAC_SGMII_LN_TX_MARGINING, TX_MARGINING_MUX | TX_MARGINING(25)},
+       {EMAC_SGMII_LN_TX_PRE, TX_PRE_MUX},
+       {EMAC_SGMII_LN_TX_POST, TX_POST_MUX},
+
+       {EMAC_SGMII_LN_CML_CTRL_MODE0,
+               CML_GEAR_MODE(1) | CML2CMOS_IBOOST_MODE(1)},
+       {EMAC_SGMII_LN_MIXER_CTRL_MODE0,
+               MIXER_LOADB_MODE(12) | MIXER_DATARATE_MODE(1)},
+       {EMAC_SGMII_LN_VGA_INITVAL, VGA_THRESH_DFE(31)},
+       {EMAC_SGMII_LN_SIGDET_ENABLES,
+               SIGDET_LP_BYP_PS0_TO_PS2 | SIGDET_FLT_BYP},
+       {EMAC_SGMII_LN_SIGDET_CNTRL, SIGDET_LVL(8)},
+
+       {EMAC_SGMII_LN_SIGDET_DEGLITCH_CNTRL, SIGDET_DEGLITCH_CTRL(4)},
+       {EMAC_SGMII_LN_RX_MISC_CNTRL0, 0},
+       {EMAC_SGMII_LN_DRVR_LOGIC_CLKDIV,
+               DRVR_LOGIC_CLK_EN | DRVR_LOGIC_CLK_DIV(4)},
+
+       {EMAC_SGMII_LN_PARALLEL_RATE, PARALLEL_RATE_MODE0(1)},
+       {EMAC_SGMII_LN_TX_BAND_MODE, BAND_MODE0(2)},
+       {EMAC_SGMII_LN_RX_BAND, BAND_MODE0(3)},
+       {EMAC_SGMII_LN_LANE_MODE, LANE_MODE(26)},
+       {EMAC_SGMII_LN_RX_RCVR_PATH1_MODE0, CDR_PD_SEL_MODE0(3)},
+       {EMAC_SGMII_LN_RSM_CONFIG, BYPASS_RSM_SAMP_CAL | BYPASS_RSM_DLL_CAL},
+};
+
+static const struct emac_reg_write physical_coding_sublayer_programming[] = {
+       {EMAC_SGMII_PHY_POW_DWN_CTRL0, PWRDN_B},
+       {EMAC_SGMII_PHY_CDR_CTRL0, CDR_MAX_CNT(15)},
+       {EMAC_SGMII_PHY_TX_PWR_CTRL, 0},
+       {EMAC_SGMII_PHY_LANE_CTRL1, L0_RX_EQUALIZE_ENABLE},
+};
+
+int emac_sgmii_init_qdf2432(struct emac_adapter *adpt)
+{
+       struct emac_sgmii *phy = &adpt->phy;
+       void __iomem *phy_regs = phy->base;
+       void __iomem *laned = phy->digital;
+       unsigned int i;
+       u32 lnstatus;
+
+       /* PCS lane-x init */
+       emac_reg_write_all(phy->base, physical_coding_sublayer_programming,
+                          ARRAY_SIZE(physical_coding_sublayer_programming));
+
+       /* SGMII lane-x init */
+       emac_reg_write_all(phy->digital, sgmii_laned, ARRAY_SIZE(sgmii_laned));
+
+       /* Power up PCS and start reset lane state machine */
+
+       writel(0, phy_regs + EMAC_SGMII_PHY_RESET_CTRL);
+       writel(1, laned + SGMII_LN_RSM_START);
+
+       /* Wait for c_ready assertion */
+       for (i = 0; i < SERDES_START_WAIT_TIMES; i++) {
+               lnstatus = readl(phy_regs + SGMII_PHY_LN_LANE_STATUS);
+               if (lnstatus & BIT(1))
+                       break;
+               usleep_range(100, 200);
+       }
+
+       if (i == SERDES_START_WAIT_TIMES) {
+               netdev_err(adpt->netdev, "SGMII failed to start\n");
+               return -EIO;
+       }
+
+       /* Disable digital and SERDES loopback */
+       writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN0);
+       writel(0, phy_regs + SGMII_PHY_LN_BIST_GEN2);
+       writel(0, phy_regs + SGMII_PHY_LN_CDR_CTRL1);
+
+       /* Mask out all the SGMII Interrupt */
+       writel(0, phy_regs + EMAC_SGMII_PHY_INTERRUPT_MASK);
+
+       return 0;
+}
index 573c82b21de5e76b11e26ec7261d5aae2700257e..e4bc18009d08799b5462a54bc13e2b5b412f2307 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/iopoll.h>
+#include <linux/acpi.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
@@ -274,11 +275,76 @@ static struct sgmii_ops fsm9900_ops = {
        .reset = emac_sgmii_common_reset,
 };
 
+static struct sgmii_ops qdf2432_ops = {
+       .init = emac_sgmii_init_qdf2432,
+       .open = emac_sgmii_common_open,
+       .close = emac_sgmii_common_close,
+       .link_change = emac_sgmii_common_link_change,
+       .reset = emac_sgmii_common_reset,
+};
+
+#ifdef CONFIG_ACPI
+static struct sgmii_ops qdf2400_ops = {
+       .init = emac_sgmii_init_qdf2400,
+       .open = emac_sgmii_common_open,
+       .close = emac_sgmii_common_close,
+       .link_change = emac_sgmii_common_link_change,
+       .reset = emac_sgmii_common_reset,
+};
+#endif
+
+static int emac_sgmii_acpi_match(struct device *dev, void *data)
+{
+#ifdef CONFIG_ACPI
+       static const struct acpi_device_id match_table[] = {
+               {
+                       .id = "QCOM8071",
+               },
+               {}
+       };
+       const struct acpi_device_id *id = acpi_match_device(match_table, dev);
+       struct sgmii_ops **ops = data;
+
+       if (id) {
+               acpi_handle handle = ACPI_HANDLE(dev);
+               unsigned long long hrv;
+               acpi_status status;
+
+               status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv);
+               if (status) {
+                       if (status == AE_NOT_FOUND)
+                               /* Older versions of the QDF2432 ACPI tables do
+                                * not have an _HRV property.
+                                */
+                               hrv = 1;
+                       else
+                               /* Something is wrong with the tables */
+                               return 0;
+               }
+
+               switch (hrv) {
+               case 1:
+                       *ops = &qdf2432_ops;
+                       return 1;
+               case 2:
+                       *ops = &qdf2400_ops;
+                       return 1;
+               }
+       }
+#endif
+
+       return 0;
+}
+
 static const struct of_device_id emac_sgmii_dt_match[] = {
        {
                .compatible = "qcom,fsm9900-emac-sgmii",
                .data = &fsm9900_ops,
        },
+       {
+               .compatible = "qcom,qdf2432-emac-sgmii",
+               .data = &qdf2432_ops,
+       },
        {}
 };
 
@@ -289,30 +355,44 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
        struct resource *res;
        int ret;
 
-       const struct of_device_id *match;
-       struct device_node *np;
+       if (has_acpi_companion(&pdev->dev)) {
+               struct device *dev;
 
-       np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0);
-       if (!np) {
-               dev_err(&pdev->dev, "missing internal-phy property\n");
-               return -ENODEV;
-       }
+               dev = device_find_child(&pdev->dev, &phy->sgmii_ops,
+                                       emac_sgmii_acpi_match);
 
-       sgmii_pdev = of_find_device_by_node(np);
-       of_node_put(np);
-       if (!sgmii_pdev) {
-               dev_err(&pdev->dev, "invalid internal-phy property\n");
-               return -ENODEV;
-       }
+               if (!dev) {
+                       dev_warn(&pdev->dev, "cannot find internal phy node\n");
+                       return 0;
+               }
 
-       match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev);
-       if (!match) {
-               dev_err(&pdev->dev, "unrecognized internal phy node\n");
-               ret = -ENODEV;
-               goto error_put_device;
-       }
+               sgmii_pdev = to_platform_device(dev);
+       } else {
+               const struct of_device_id *match;
+               struct device_node *np;
 
-       phy->sgmii_ops = (struct sgmii_ops *)match->data;
+               np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0);
+               if (!np) {
+                       dev_err(&pdev->dev, "missing internal-phy property\n");
+                       return -ENODEV;
+               }
+
+               sgmii_pdev = of_find_device_by_node(np);
+               of_node_put(np);
+               if (!sgmii_pdev) {
+                       dev_err(&pdev->dev, "invalid internal-phy property\n");
+                       return -ENODEV;
+               }
+
+               match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev);
+               if (!match) {
+                       dev_err(&pdev->dev, "unrecognized internal phy node\n");
+                       ret = -ENODEV;
+                       goto error_put_device;
+               }
+
+               phy->sgmii_ops = (struct sgmii_ops *)match->data;
+       }
 
        /* Base address is the first address */
        res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0);
index 7b7b0dc44225b0815fe3ccf007b8875a2f5f4764..6daeddacbcfaff11510eb876b831ca9b0621cfb2 100644 (file)
@@ -40,6 +40,8 @@ struct emac_sgmii {
 int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt);
 
 int emac_sgmii_init_fsm9900(struct emac_adapter *adpt);
+int emac_sgmii_init_qdf2432(struct emac_adapter *adpt);
+int emac_sgmii_init_qdf2400(struct emac_adapter *adpt);
 
 int emac_sgmii_init(struct emac_adapter *adpt);
 int emac_sgmii_open(struct emac_adapter *adpt);