From 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 22 Oct 2024 10:36:11 +0000
Subject: [PATCH] 修改4g拨号为QMI,需要在系统里后台执行quectel-CM
---
kernel/drivers/net/phy/smsc.c | 182 +++++++++++++++++++++++++++++++++++----------
1 files changed, 140 insertions(+), 42 deletions(-)
diff --git a/kernel/drivers/net/phy/smsc.c b/kernel/drivers/net/phy/smsc.c
index c328208..b67de3f 100644
--- a/kernel/drivers/net/phy/smsc.c
+++ b/kernel/drivers/net/phy/smsc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* drivers/net/phy/smsc.c
*
@@ -7,15 +8,11 @@
*
* Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
* Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@shawell.net
*
*/
+#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
@@ -24,6 +21,17 @@
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/smscphy.h>
+
+/* Vendor-specific PHY Definitions */
+/* EDPD NLP / crossover time configuration */
+#define PHY_EDPD_CONFIG 16
+#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ 0x0001
+
+/* Control/Status Indication Register */
+#define SPECIAL_CTRL_STS 27
+#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ 0x8000
+#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ 0x4000
+#define SPECIAL_CTRL_STS_AMDIX_STATE_ 0x2000
struct smsc_hw_stat {
const char *string;
@@ -37,14 +45,22 @@
struct smsc_phy_priv {
bool energy_enable;
+ struct clk *refclk;
};
static int smsc_phy_config_intr(struct phy_device *phydev)
{
- int rc = phy_write (phydev, MII_LAN83C185_IM,
- ((PHY_INTERRUPT_ENABLED == phydev->interrupts)
- ? MII_LAN83C185_ISF_INT_PHYLIB_EVENTS
- : 0));
+ struct smsc_phy_priv *priv = phydev->priv;
+ u16 intmask = 0;
+ int rc;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ intmask = MII_LAN83C185_ISF_INT4 | MII_LAN83C185_ISF_INT6;
+ if (priv->energy_enable)
+ intmask |= MII_LAN83C185_ISF_INT7;
+ }
+
+ rc = phy_write(phydev, MII_LAN83C185_IM, intmask);
return rc < 0 ? rc : 0;
}
@@ -59,19 +75,21 @@
static int smsc_phy_config_init(struct phy_device *phydev)
{
struct smsc_phy_priv *priv = phydev->priv;
+ int rc;
- int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+ if (!priv->energy_enable)
+ return 0;
+
+ rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
if (rc < 0)
return rc;
- if (priv->energy_enable) {
- /* Enable energy detect mode for this SMSC Transceivers */
- rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
- rc | MII_LAN83C185_EDPWRDOWN);
- if (rc < 0)
- return rc;
- }
+ /* Enable energy detect mode for this SMSC Transceivers */
+ rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
+ rc | MII_LAN83C185_EDPWRDOWN);
+ if (rc < 0)
+ return rc;
return smsc_phy_ack_interrupt(phydev);
}
@@ -100,6 +118,57 @@
return smsc_phy_ack_interrupt(phydev);
}
+static int lan87xx_config_aneg(struct phy_device *phydev)
+{
+ int rc;
+ int val;
+
+ switch (phydev->mdix_ctrl) {
+ case ETH_TP_MDI:
+ val = SPECIAL_CTRL_STS_OVRRD_AMDIX_;
+ break;
+ case ETH_TP_MDI_X:
+ val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
+ SPECIAL_CTRL_STS_AMDIX_STATE_;
+ break;
+ case ETH_TP_MDI_AUTO:
+ val = SPECIAL_CTRL_STS_AMDIX_ENABLE_;
+ break;
+ default:
+ return genphy_config_aneg(phydev);
+ }
+
+ rc = phy_read(phydev, SPECIAL_CTRL_STS);
+ if (rc < 0)
+ return rc;
+
+ rc &= ~(SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
+ SPECIAL_CTRL_STS_AMDIX_ENABLE_ |
+ SPECIAL_CTRL_STS_AMDIX_STATE_);
+ rc |= val;
+ phy_write(phydev, SPECIAL_CTRL_STS, rc);
+
+ phydev->mdix = phydev->mdix_ctrl;
+ return genphy_config_aneg(phydev);
+}
+
+static int lan95xx_config_aneg_ext(struct phy_device *phydev)
+{
+ int rc;
+
+ if (phydev->phy_id != 0x0007c0f0) /* not (LAN9500A or LAN9505A) */
+ return lan87xx_config_aneg(phydev);
+
+ /* Extend Manual AutoMDIX timer */
+ rc = phy_read(phydev, PHY_EDPD_CONFIG);
+ if (rc < 0)
+ return rc;
+
+ rc |= PHY_EDPD_CONFIG_EXT_CROSSOVER_;
+ phy_write(phydev, PHY_EDPD_CONFIG, rc);
+ return lan87xx_config_aneg(phydev);
+}
+
/*
* The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
* plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
@@ -112,12 +181,13 @@
static int lan87xx_read_status(struct phy_device *phydev)
{
struct smsc_phy_priv *priv = phydev->priv;
+ int err;
- int err = genphy_read_status(phydev);
+ err = genphy_read_status(phydev);
+ if (err)
+ return err;
if (!phydev->link && priv->energy_enable) {
- int i;
-
/* Disable EDPD to wake up PHY */
int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
if (rc < 0)
@@ -128,16 +198,15 @@
if (rc < 0)
return rc;
- /* Wait max 640 ms to detect energy */
- for (i = 0; i < 64; i++) {
- /* Sleep to allow link test pulses to be sent */
- msleep(10);
- rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
- if (rc < 0)
- return rc;
- if (rc & MII_LAN83C185_ENERGYON)
- break;
- }
+ /* Wait max 640 ms to detect energy and the timeout is not
+ * an actual error.
+ */
+ read_poll_timeout(phy_read, rc,
+ rc & MII_LAN83C185_ENERGYON || rc < 0,
+ 10000, 640000, true, phydev,
+ MII_LAN83C185_CTRL_STATUS);
+ if (rc < 0)
+ return rc;
/* Re-enable EDPD */
rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
@@ -192,11 +261,20 @@
data[i] = smsc_get_stat(phydev, i);
}
+static void smsc_phy_remove(struct phy_device *phydev)
+{
+ struct smsc_phy_priv *priv = phydev->priv;
+
+ clk_disable_unprepare(priv->refclk);
+ clk_put(priv->refclk);
+}
+
static int smsc_phy_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
struct device_node *of_node = dev->of_node;
struct smsc_phy_priv *priv;
+ int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -209,6 +287,22 @@
phydev->priv = priv;
+ /* Make clk optional to keep DTB backward compatibility. */
+ priv->refclk = clk_get_optional(dev, NULL);
+ if (IS_ERR(priv->refclk))
+ return dev_err_probe(dev, PTR_ERR(priv->refclk),
+ "Failed to request clock\n");
+
+ ret = clk_prepare_enable(priv->refclk);
+ if (ret)
+ return ret;
+
+ ret = clk_set_rate(priv->refclk, 50 * 1000 * 1000);
+ if (ret) {
+ clk_disable_unprepare(priv->refclk);
+ return ret;
+ }
+
return 0;
}
@@ -218,8 +312,7 @@
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN83C185",
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
+ /* PHY_BASIC_FEATURES */
.probe = smsc_phy_probe,
@@ -238,8 +331,7 @@
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN8187",
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
+ /* PHY_BASIC_FEATURES */
.probe = smsc_phy_probe,
@@ -259,12 +351,14 @@
.suspend = genphy_suspend,
.resume = genphy_resume,
}, {
+ /* This covers internal PHY (phy_id: 0x0007C0C3) for
+ * LAN9500 (PID: 0x9500), LAN9514 (PID: 0xec00), LAN9505 (PID: 0x9505)
+ */
.phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN8700",
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
+ /* PHY_BASIC_FEATURES */
.probe = smsc_phy_probe,
@@ -272,6 +366,7 @@
.read_status = lan87xx_read_status,
.config_init = smsc_phy_config_init,
.soft_reset = smsc_phy_reset,
+ .config_aneg = lan87xx_config_aneg,
/* IRQ related */
.ack_interrupt = smsc_phy_ack_interrupt,
@@ -289,8 +384,7 @@
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN911x Internal PHY",
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
+ /* PHY_BASIC_FEATURES */
.probe = smsc_phy_probe,
@@ -304,19 +398,23 @@
.suspend = genphy_suspend,
.resume = genphy_resume,
}, {
+ /* This covers internal PHY (phy_id: 0x0007C0F0) for
+ * LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01)
+ */
.phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN8710/LAN8720",
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT | PHY_RST_AFTER_CLK_EN,
+ /* PHY_BASIC_FEATURES */
.probe = smsc_phy_probe,
+ .remove = smsc_phy_remove,
/* basic functions */
.read_status = lan87xx_read_status,
.config_init = smsc_phy_config_init,
.soft_reset = smsc_phy_reset,
+ .config_aneg = lan95xx_config_aneg_ext,
/* IRQ related */
.ack_interrupt = smsc_phy_ack_interrupt,
@@ -334,8 +432,8 @@
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN8740",
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
+ /* PHY_BASIC_FEATURES */
+ .flags = PHY_RST_AFTER_CLK_EN,
.probe = smsc_phy_probe,
--
Gitblit v1.6.2