[openwrt/openwrt] qualcommbe: v6.12: add QCA8084 ethernet PHY driver

LEDE Commits lede-commits at lists.infradead.org
Sat May 31 03:25:58 PDT 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/390e516a3b872c07b5231483658b75efc594f2c9

commit 390e516a3b872c07b5231483658b75efc594f2c9
Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
AuthorDate: Tue May 13 21:38:58 2025 -0500

    qualcommbe: v6.12: add QCA8084 ethernet PHY driver
    
    This driver is cherry-picked from target/linux/qualcommbe/patches-6.6.
    While Qualcomm did submit past patches for QCA8084, the code has since
    ben split from at803x. The existing OpenWRT version of the patch is
    the cleanest version I could find. Add it here.
    
    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
    Link: https://github.com/openwrt/openwrt/pull/18796
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 ...-net-Document-Qualcomm-QCA8084-PHY-packag.patch | 244 +++++++++++++++++++++
 ...-qca808x-Add-QCA8084-ethernet-phy-support.patch | 133 +++++++++++
 ...808x-Add-config_init-function-for-QCA8084.patch |  85 +++++++
 ...808x-Add-link_change_notify-function-for-.patch |  90 ++++++++
 ...808x-Add-register-access-support-routines.patch | 125 +++++++++++
 ...et-phy-qca808x-Add-QCA8084-probe-function.patch | 140 ++++++++++++
 ...808x-Add-package-clocks-and-resets-for-QC.patch | 132 +++++++++++
 ...qca808x-Add-QCA8084-package-init-function.patch | 171 +++++++++++++++
 8 files changed, 1120 insertions(+)

diff --git a/target/linux/qualcommbe/patches-6.12/0306-dt-bindings-net-Document-Qualcomm-QCA8084-PHY-packag.patch b/target/linux/qualcommbe/patches-6.12/0306-dt-bindings-net-Document-Qualcomm-QCA8084-PHY-packag.patch
new file mode 100644
index 0000000000..1583258493
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0306-dt-bindings-net-Document-Qualcomm-QCA8084-PHY-packag.patch
@@ -0,0 +1,244 @@
+From ae682f13d308682232069e5150e884fc10160598 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Mon, 29 Jan 2024 17:57:20 +0800
+Subject: [PATCH] dt-bindings: net: Document Qualcomm QCA8084 PHY package
+
+QCA8084 is quad PHY chip, which integrates 4 PHYs, 2 PCS
+interfaces (PCS0 and PCS1) and clock controller, which can
+also be integrated to the switch chip named as QCA8386.
+
+1. MDIO address of 4 PHYs, 2 PCS and 1 XPCS (PCS1 includes
+   PCS and XPCS, PCS0 includes PCS) can be configured.
+2. The package mode of PHY is optionally configured for the
+   interface mode of two PCSes working correctly.
+3. The package level clock and reset need to be initialized.
+4. The clock and reset per PHY device need to be initialized
+   so that the PHY register can be accessed.
+
+Change-Id: Idb2338d2673152cbd3c57e95968faa59e9d4a80f
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ .../devicetree/bindings/net/qcom,qca8084.yaml | 198 ++++++++++++++++++
+ include/dt-bindings/net/qcom,qca808x.h        |  14 ++
+ 2 files changed, 212 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/net/qcom,qca8084.yaml
+ create mode 100644 include/dt-bindings/net/qcom,qca808x.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/qcom,qca8084.yaml
+@@ -0,0 +1,198 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/net/qcom,qca8084.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Qualcomm QCA8084 Ethernet Quad PHY
++
++maintainers:
++  - Luo Jie <quic_luoj at quicinc.com>
++
++description:
++  Qualcomm QCA8084 is a four-port Ethernet transceiver, the
++  Ethernet port supports link speed 10/100/1000/2500 Mbps.
++  There are two PCSes (PCS0 and PCS1) integrated in the PHY
++  package, PCS1 includes XPCS and PCS to support the interface
++  mode 10G-QXGMII and SGMII, PCS0 includes a PCS to support the
++  interface mode SGMII only. There is also a clock controller
++  integrated in the PHY package. This four-port Ethernet
++  transceiver can also be integrated to the switch chip named
++  as QCA8386. The PHY package mode needs to be configured as the
++  correct value to apply the interface mode of two PCSes as
++  mentioned below.
++
++  QCA8084 expects an input reference clock 50 MHZ as the clock
++  source of the integrated clock controller, the integrated
++  clock controller supplies the clocks and resets to the
++  integrated PHY, PCS and PHY package.
++
++  - |
++                 +--| |--+-------------------+--| |--+
++                 | PCS1  |<------------+---->| PCS0  |
++                 +-------+             |     +-------+
++                 |                     |             |
++    Ref 50M clk  +--------+            |             |
++    ------------>|        | clk & rst  |             |
++    GPIO Reset   |QCA8K_CC+------------+             |
++    ------------>|        |            |             |
++                 +--------+            |             |
++                 |                     V             |
++                 +--------+--------+--------+--------+
++                 |  PHY0  |  PHY1  |  PHY2  |  PHY3  |
++                 +--------+--------+--------+--------+
++
++$ref: ethernet-phy-package.yaml#
++
++properties:
++  compatible:
++    const: qcom,qca8084-package
++
++  clocks:
++    description: PHY package level initial common clocks, which are
++      needed to be enabled after GPIO reset on the PHY package, these
++      clocks are supplied from the PHY integrated clock controller
++      (QCA8K-CC).
++    items:
++      - description: APB bridge clock
++      - description: AHB clock
++      - description: Security control clock
++      - description: TLMM clock
++      - description: TLMM AHB clock
++      - description: CNOC AHB clock
++      - description: MDIO AHB clock
++
++  clock-names:
++    items:
++      - const: apb_bridge
++      - const: ahb
++      - const: sec_ctrl_ahb
++      - const: tlmm
++      - const: tlmm_ahb
++      - const: cnoc_ahb
++      - const: mdio_ahb
++
++  resets:
++    description: PHY package level initial common reset, which are
++      needed to be deasserted after GPIO reset on the PHY package,
++      this reset is provided by the PHY integrated clock controller
++      to do PHY DSP reset.
++    maxItems: 1
++
++  qcom,package-mode:
++    description: |
++      The package mode of PHY supports to be configured as 3 modes
++      to apply the combinations of interface mode of two PCSes
++      correctly. This value should use one of the values defined in
++      dt-bindings/net/qcom,qca808x.h. The package mode 10G-QXGMII of
++      Quad PHY is used by default.
++
++      package mode             PCS1             PCS0
++      phy mode (0)             10G-QXGMII for   not used
++                               PHY0-PHY3
++
++      switch mode (1)          SGMII for        SGMII for
++                               switch MAC0      switch MAC5 (optional)
++
++      switch bypass MAC5 (2)   SGMII for        SGMII for
++                               switch MAC0      PHY3
++    $ref: /schemas/types.yaml#/definitions/uint32
++    enum: [0, 1, 2]
++    default: 0
++
++  qcom,phy-addr-fixup:
++    description: MDIO address for PHY0-PHY3, PCS0 and PCS1 including
++      PCS and XPCS, which can be optionally customized by programming
++      the security control register of PHY package. The hardware default
++      MDIO address of PHY0-PHY3, PCS0 and PCS1 including PCS and XPCS is
++      0-6.
++    $ref: /schemas/types.yaml#/definitions/uint32-array
++    minItems: 7
++    maxItems: 7
++
++patternProperties:
++  ^ethernet-phy(@[a-f0-9]+)?$:
++    $ref: ethernet-phy.yaml#
++
++    properties:
++      compatible:
++        const: ethernet-phy-id004d.d180
++
++    required:
++      - compatible
++      - reg
++      - clocks
++      - resets
++
++    unevaluatedProperties: false
++
++required:
++  - compatible
++  - clocks
++  - clock-names
++  - resets
++
++unevaluatedProperties: false
++
++examples:
++  - |
++    #include <dt-bindings/clock/qcom,qca8k-nsscc.h>
++    #include <dt-bindings/net/qcom,qca808x.h>
++    #include <dt-bindings/reset/qcom,qca8k-nsscc.h>
++
++    mdio {
++        #address-cells = <1>;
++        #size-cells = <0>;
++
++        ethernet-phy-package at 1 {
++            #address-cells = <1>;
++            #size-cells = <0>;
++            compatible = "qcom,qca8084-package";
++            reg = <1>;
++            clocks = <&qca8k_nsscc NSS_CC_APB_BRIDGE_CLK>,
++                     <&qca8k_nsscc NSS_CC_AHB_CLK>,
++                     <&qca8k_nsscc NSS_CC_SEC_CTRL_AHB_CLK>,
++                     <&qca8k_nsscc NSS_CC_TLMM_CLK>,
++                     <&qca8k_nsscc NSS_CC_TLMM_AHB_CLK>,
++                     <&qca8k_nsscc NSS_CC_CNOC_AHB_CLK>,
++                     <&qca8k_nsscc NSS_CC_MDIO_AHB_CLK>;
++            clock-names = "apb_bridge",
++                          "ahb",
++                          "sec_ctrl_ahb",
++                          "tlmm",
++                          "tlmm_ahb",
++                          "cnoc_ahb",
++                          "mdio_ahb";
++            resets = <&qca8k_nsscc NSS_CC_GEPHY_FULL_ARES>;
++            qcom,package-mode = <QCA808X_PCS1_SGMII_MAC_PCS0_SGMII_MAC>;
++            qcom,phy-addr-fixup = <1 2 3 4 5 6 7>;
++
++            ethernet-phy at 1 {
++                compatible = "ethernet-phy-id004d.d180";
++                reg = <1>;
++                clocks = <&qca8k_nsscc NSS_CC_GEPHY0_SYS_CLK>;
++                resets = <&qca8k_nsscc NSS_CC_GEPHY0_SYS_ARES>;
++            };
++
++            ethernet-phy at 2 {
++                compatible = "ethernet-phy-id004d.d180";
++                reg = <2>;
++                clocks = <&qca8k_nsscc NSS_CC_GEPHY1_SYS_CLK>;
++                resets = <&qca8k_nsscc NSS_CC_GEPHY1_SYS_ARES>;
++            };
++
++            ethernet-phy at 3 {
++                compatible = "ethernet-phy-id004d.d180";
++                reg = <3>;
++                clocks = <&qca8k_nsscc NSS_CC_GEPHY2_SYS_CLK>;
++                resets = <&qca8k_nsscc NSS_CC_GEPHY2_SYS_ARES>;
++            };
++
++            ethernet-phy at 4 {
++                compatible = "ethernet-phy-id004d.d180";
++                reg = <4>;
++                clocks = <&qca8k_nsscc NSS_CC_GEPHY3_SYS_CLK>;
++                resets = <&qca8k_nsscc NSS_CC_GEPHY3_SYS_ARES>;
++            };
++        };
++    };
+--- /dev/null
++++ b/include/dt-bindings/net/qcom,qca808x.h
+@@ -0,0 +1,14 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
++/*
++ * Device Tree constants for the Qualcomm QCA808X PHYs
++ */
++
++#ifndef _DT_BINDINGS_QCOM_QCA808X_H
++#define _DT_BINDINGS_QCOM_QCA808X_H
++
++/* PHY package modes of QCA8084 to apply the interface modes of two PCSes. */
++#define QCA808X_PCS1_10G_QXGMII_PCS0_UNUNSED		0
++#define QCA808X_PCS1_SGMII_MAC_PCS0_SGMII_MAC		1
++#define QCA808X_PCS1_SGMII_MAC_PCS0_SGMII_PHY		2
++
++#endif
diff --git a/target/linux/qualcommbe/patches-6.12/0307-net-phy-qca808x-Add-QCA8084-ethernet-phy-support.patch b/target/linux/qualcommbe/patches-6.12/0307-net-phy-qca808x-Add-QCA8084-ethernet-phy-support.patch
new file mode 100644
index 0000000000..edfe8d1404
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0307-net-phy-qca808x-Add-QCA8084-ethernet-phy-support.patch
@@ -0,0 +1,133 @@
+From 816bff9bcd2ff7c1e84dd14fc81c9c1bdaa609e7 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Thu, 6 Apr 2023 18:09:07 +0800
+Subject: [PATCH] net: phy: qca808x: Add QCA8084 ethernet phy support
+
+Add QCA8084 Quad-PHY support, which is a four-port PHY with
+maximum link capability of 2.5 Gbps. The features of each port
+are almost same as QCA8081. The slave seed and fast retrain
+configs are not needed for QCA8084. It includes two PCSes.
+
+PCS0 of QCA8084 supports the interface modes:
+PHY_INTERFACE_MODE_2500BASEX and PHY_INTERFACE_MODE_SGMII.
+
+PCS1 of QCA8084 supports the interface modes:
+PHY_INTERFACE_MODE_10G_QXGMII, PHY_INTERFACE_MODE_2500BASEX and
+PHY_INTERFACE_MODE_SGMII.
+
+The additional CDT configurations needed for QCA8084 compared
+with QCA8081.
+
+Change-Id: I12555fa70662682474ab4432204405b5e752fef6
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ drivers/net/phy/qcom/qca808x.c | 62 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 60 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -86,9 +86,16 @@
+ #define QCA8081_PHY_FIFO_RSTN			BIT(11)
+ 
+ #define QCA8081_PHY_ID				0x004dd101
++#define QCA8084_PHY_ID				0x004dd180
++
++#define QCA8084_MMD3_CDT_PULSE_CTRL		0x8075
++#define QCA8084_CDT_PULSE_THRESH_VAL		0xa060
++
++#define QCA8084_MMD3_CDT_NEAR_CTRL		0x807f
++#define QCA8084_CDT_NEAR_BYPASS			BIT(15)
+ 
+ MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");
+-MODULE_AUTHOR("Matus Ujhelyi");
++MODULE_AUTHOR("Matus Ujhelyi, Luo Jie");
+ MODULE_LICENSE("GPL");
+ 
+ struct qca808x_priv {
+@@ -153,7 +160,9 @@ static bool qca808x_is_prefer_master(str
+ 
+ static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)
+ {
+-	return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
++	return phydev_id_compare(phydev, QCA8081_PHY_ID) &&
++		linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
++				  phydev->supported);
+ }
+ 
+ static bool qca808x_is_1g_only(struct phy_device *phydev)
+@@ -273,6 +282,23 @@ static int qca808x_read_status(struct ph
+ 		return ret;
+ 
+ 	if (phydev->link) {
++		/* There are two PCSes available for QCA8084, which support
++		 * the following interface modes.
++		 *
++		 * 1. PHY_INTERFACE_MODE_10G_QXGMII utilizes PCS1 for all
++		 * available 4 ports, which is for all link speeds.
++		 *
++		 * 2. PHY_INTERFACE_MODE_2500BASEX utilizes PCS0 for the
++		 * fourth port, which is only for the link speed 2500M same
++		 * as QCA8081.
++		 *
++		 * 3. PHY_INTERFACE_MODE_SGMII utilizes PCS0 for the fourth
++		 * port, which is for the link speed 10M, 100M and 1000M same
++		 * as QCA8081.
++		 */
++		if (phydev->interface == PHY_INTERFACE_MODE_10G_QXGMII)
++			return 0;
++
+ 		if (phydev->speed == SPEED_2500)
+ 			phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+ 		else
+@@ -352,6 +378,18 @@ static int qca808x_cable_test_start(stru
+ 	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060);
+ 	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060);
+ 
++	if (phydev_id_compare(phydev, QCA8084_PHY_ID)) {
++		/* Adjust the positive and negative pulse thereshold of CDT. */
++		phy_write_mmd(phydev, MDIO_MMD_PCS,
++			      QCA8084_MMD3_CDT_PULSE_CTRL,
++			      QCA8084_CDT_PULSE_THRESH_VAL);
++
++		/* Disable the near bypass of CDT. */
++		phy_modify_mmd(phydev, MDIO_MMD_PCS,
++			       QCA8084_MMD3_CDT_NEAR_CTRL,
++			       QCA8084_CDT_NEAR_BYPASS, 0);
++	}
++
+ 	return 0;
+ }
+ 
+@@ -651,12 +689,32 @@ static struct phy_driver qca808x_driver[
+ 	.led_hw_control_set	= qca808x_led_hw_control_set,
+ 	.led_hw_control_get	= qca808x_led_hw_control_get,
+ 	.led_polarity_set	= qca808x_led_polarity_set,
++}, {
++	/* Qualcomm QCA8084 */
++	PHY_ID_MATCH_MODEL(QCA8084_PHY_ID),
++	.name			= "Qualcomm QCA8084",
++	.flags			= PHY_POLL_CABLE_TEST,
++	.config_intr		= at803x_config_intr,
++	.handle_interrupt	= at803x_handle_interrupt,
++	.get_tunable		= at803x_get_tunable,
++	.set_tunable		= at803x_set_tunable,
++	.set_wol		= at803x_set_wol,
++	.get_wol		= at803x_get_wol,
++	.get_features		= qca808x_get_features,
++	.config_aneg		= qca808x_config_aneg,
++	.suspend		= genphy_suspend,
++	.resume			= genphy_resume,
++	.read_status		= qca808x_read_status,
++	.soft_reset		= qca808x_soft_reset,
++	.cable_test_start	= qca808x_cable_test_start,
++	.cable_test_get_status	= qca808x_cable_test_get_status,
+ }, };
+ 
+ module_phy_driver(qca808x_driver);
+ 
+ static const struct mdio_device_id __maybe_unused qca808x_tbl[] = {
+ 	{ PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
++	{ PHY_ID_MATCH_MODEL(QCA8084_PHY_ID) },
+ 	{ }
+ };
+ 
diff --git a/target/linux/qualcommbe/patches-6.12/0308-net-phy-qca808x-Add-config_init-function-for-QCA8084.patch b/target/linux/qualcommbe/patches-6.12/0308-net-phy-qca808x-Add-config_init-function-for-QCA8084.patch
new file mode 100644
index 0000000000..196160188b
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0308-net-phy-qca808x-Add-config_init-function-for-QCA8084.patch
@@ -0,0 +1,85 @@
+From 5a57611512593212b7fd9c23b4d96486bab6dee3 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Wed, 8 Nov 2023 16:18:02 +0800
+Subject: [PATCH] net: phy: qca808x: Add config_init function for QCA8084
+
+1. The ADC of QCA8084 PHY must be configured as edge inverted
+and falling whenever it is initialized or reset. In addition,
+the default MSE (Mean square error) threshold value is adjusted,
+which comes into play during link partner detection to detect
+the valid link signal.
+
+2. Add the possible interface modes.
+   When QCA8084 works on the interface mode SGMII or 2500BASE-X, the
+   interface mode can be switched according to the PHY link speed.
+
+   When QCA8084 works on the 10G-QXGMII mode, which will be the only
+   possible interface mode.
+
+Change-Id: I832c0d0b069e95cc411a8a7b680a5f60e1d6041a
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ drivers/net/phy/qcom/qca808x.c | 38 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -94,6 +94,15 @@
+ #define QCA8084_MMD3_CDT_NEAR_CTRL		0x807f
+ #define QCA8084_CDT_NEAR_BYPASS			BIT(15)
+ 
++/* QCA8084 ADC clock edge */
++#define QCA8084_ADC_CLK_SEL			0x8b80
++#define QCA8084_ADC_CLK_SEL_ACLK		GENMASK(7, 4)
++#define QCA8084_ADC_CLK_SEL_ACLK_FALL		0xf
++#define QCA8084_ADC_CLK_SEL_ACLK_RISE		0x0
++
++#define QCA8084_MSE_THRESHOLD			0x800a
++#define QCA8084_MSE_THRESHOLD_2P5G_VAL		0x51c6
++
+ MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi, Luo Jie");
+ MODULE_LICENSE("GPL");
+@@ -660,6 +669,34 @@ static int qca808x_led_polarity_set(stru
+ 			      active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
+ }
+ 
++static int qca8084_config_init(struct phy_device *phydev)
++{
++	int ret;
++
++	if (phydev->interface == PHY_INTERFACE_MODE_10G_QXGMII)
++		__set_bit(PHY_INTERFACE_MODE_10G_QXGMII,
++			  phydev->possible_interfaces);
++	else
++		qca808x_fill_possible_interfaces(phydev);
++
++	/* Configure the ADC to convert the signal using falling edge
++	 * instead of the default rising edge.
++	 */
++	ret = at803x_debug_reg_mask(phydev, QCA8084_ADC_CLK_SEL,
++				    QCA8084_ADC_CLK_SEL_ACLK,
++				    FIELD_PREP(QCA8084_ADC_CLK_SEL_ACLK,
++					       QCA8084_ADC_CLK_SEL_ACLK_FALL));
++	if (ret < 0)
++		return ret;
++
++	/* Adjust MSE threshold value to avoid link issue with
++	 * some link partner.
++	 */
++	return phy_write_mmd(phydev, MDIO_MMD_PMAPMD,
++			     QCA8084_MSE_THRESHOLD,
++			     QCA8084_MSE_THRESHOLD_2P5G_VAL);
++}
++
+ static struct phy_driver qca808x_driver[] = {
+ {
+ 	/* Qualcomm QCA8081 */
+@@ -708,6 +745,7 @@ static struct phy_driver qca808x_driver[
+ 	.soft_reset		= qca808x_soft_reset,
+ 	.cable_test_start	= qca808x_cable_test_start,
+ 	.cable_test_get_status	= qca808x_cable_test_get_status,
++	.config_init		= qca8084_config_init,
+ }, };
+ 
+ module_phy_driver(qca808x_driver);
diff --git a/target/linux/qualcommbe/patches-6.12/0309-net-phy-qca808x-Add-link_change_notify-function-for-.patch b/target/linux/qualcommbe/patches-6.12/0309-net-phy-qca808x-Add-link_change_notify-function-for-.patch
new file mode 100644
index 0000000000..429b5c0535
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0309-net-phy-qca808x-Add-link_change_notify-function-for-.patch
@@ -0,0 +1,90 @@
+From d1f2a1810af1833196934977f57607432fda46b4 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Wed, 8 Nov 2023 18:01:14 +0800
+Subject: [PATCH] net: phy: qca808x: Add link_change_notify function for
+ QCA8084
+
+When the link is changed, QCA8084 needs to do the fifo reset and
+adjust the IPG level for the 10G-QXGMII link on the speed 1000M.
+
+Change-Id: I21de802c78496fb95f1c5119fe3894c9fdebbd65
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ drivers/net/phy/qcom/qca808x.c | 52 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -103,6 +103,14 @@
+ #define QCA8084_MSE_THRESHOLD			0x800a
+ #define QCA8084_MSE_THRESHOLD_2P5G_VAL		0x51c6
+ 
++/* QCA8084 FIFO reset control */
++#define QCA8084_FIFO_CONTROL			0x19
++#define QCA8084_FIFO_MAC_2_PHY			BIT(1)
++#define QCA8084_FIFO_PHY_2_MAC			BIT(0)
++
++#define QCA8084_MMD7_IPG_OP			0x901d
++#define QCA8084_IPG_10_TO_11_EN			BIT(0)
++
+ MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi, Luo Jie");
+ MODULE_LICENSE("GPL");
+@@ -697,6 +705,49 @@ static int qca8084_config_init(struct ph
+ 			     QCA8084_MSE_THRESHOLD_2P5G_VAL);
+ }
+ 
++static void qca8084_link_change_notify(struct phy_device *phydev)
++{
++	int ret;
++
++	/* Assert the FIFO between PHY and MAC. */
++	ret = phy_modify(phydev, QCA8084_FIFO_CONTROL,
++			 QCA8084_FIFO_MAC_2_PHY | QCA8084_FIFO_PHY_2_MAC,
++			 0);
++	if (ret) {
++		phydev_err(phydev, "Asserting PHY FIFO failed\n");
++		return;
++	}
++
++	/* If the PHY is in 10G_QXGMII mode, the FIFO needs to be kept in
++	 * reset state when link is down, otherwise the FIFO needs to be
++	 * de-asserted after waiting 50 ms to make the assert completed.
++	 */
++	if (phydev->interface != PHY_INTERFACE_MODE_10G_QXGMII ||
++	    phydev->link) {
++		msleep(50);
++
++		/* Deassert the FIFO between PHY and MAC. */
++		ret = phy_modify(phydev, QCA8084_FIFO_CONTROL,
++				 QCA8084_FIFO_MAC_2_PHY |
++				 QCA8084_FIFO_PHY_2_MAC,
++				 QCA8084_FIFO_MAC_2_PHY |
++				 QCA8084_FIFO_PHY_2_MAC);
++		if (ret) {
++			phydev_err(phydev, "De-asserting PHY FIFO failed\n");
++			return;
++		}
++	}
++
++	/* Enable IPG level 10 to 11 tuning for link speed 1000M in the
++	 * 10G_QXGMII mode.
++	 */
++	if (phydev->interface == PHY_INTERFACE_MODE_10G_QXGMII)
++		phy_modify_mmd(phydev, MDIO_MMD_AN, QCA8084_MMD7_IPG_OP,
++			       QCA8084_IPG_10_TO_11_EN,
++			       phydev->speed == SPEED_1000 ?
++			       QCA8084_IPG_10_TO_11_EN : 0);
++}
++
+ static struct phy_driver qca808x_driver[] = {
+ {
+ 	/* Qualcomm QCA8081 */
+@@ -746,6 +797,7 @@ static struct phy_driver qca808x_driver[
+ 	.cable_test_start	= qca808x_cable_test_start,
+ 	.cable_test_get_status	= qca808x_cable_test_get_status,
+ 	.config_init		= qca8084_config_init,
++	.link_change_notify	= qca8084_link_change_notify,
+ }, };
+ 
+ module_phy_driver(qca808x_driver);
diff --git a/target/linux/qualcommbe/patches-6.12/0310-net-phy-qca808x-Add-register-access-support-routines.patch b/target/linux/qualcommbe/patches-6.12/0310-net-phy-qca808x-Add-register-access-support-routines.patch
new file mode 100644
index 0000000000..899352a116
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0310-net-phy-qca808x-Add-register-access-support-routines.patch
@@ -0,0 +1,125 @@
+From c17f19be3bec0bf5467f4e14a21573836910f671 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Wed, 29 Nov 2023 15:21:22 +0800
+Subject: [PATCH] net: phy: qca808x: Add register access support routines for
+ QCA8084
+
+QCA8084 integrates clock controller and security control modules
+besides of the PHY and PCS. The 32bit registers in these modules
+are accessed using special MDIO sequences to read or write these
+registers.
+
+The MDIO address of PHY and PCS are configured by writing to the
+security control register. The package mode for QCA8084 is also
+configured in a similar manner.
+
+Change-Id: I9317307ef9bbc738a6adcbc3ea1be8e6528d711e
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ drivers/net/phy/qcom/qca808x.c | 88 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 88 insertions(+)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -111,6 +111,22 @@
+ #define QCA8084_MMD7_IPG_OP			0x901d
+ #define QCA8084_IPG_10_TO_11_EN			BIT(0)
+ 
++/* QCA8084 includes secure control module, which supports customizing the
++ * MDIO address of PHY device and PCS device and configuring package mode
++ * for the interface mode of PCS. The register of secure control is accessed
++ * by MDIO bus with the special MDIO sequences, where the 32 bits register
++ * address is split into 3 MDIO operations with 16 bits address.
++ */
++#define QCA8084_HIGH_ADDR_PREFIX		0x18
++#define QCA8084_LOW_ADDR_PREFIX			0x10
++
++/* Bottom two bits of REG must be zero */
++#define QCA8084_MII_REG_MASK			GENMASK(4, 0)
++#define QCA8084_MII_PHY_ADDR_MASK		GENMASK(7, 5)
++#define QCA8084_MII_PAGE_MASK			GENMASK(23, 8)
++#define QCA8084_MII_SW_ADDR_MASK		GENMASK(31, 24)
++#define QCA8084_MII_REG_DATA_UPPER_16_BITS	BIT(1)
++
+ MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi, Luo Jie");
+ MODULE_LICENSE("GPL");
+@@ -119,6 +135,78 @@ struct qca808x_priv {
+ 	int led_polarity_mode;
+ };
+ 
++static int __qca8084_set_page(struct mii_bus *bus, u16 sw_addr, u16 page)
++{
++	return __mdiobus_write(bus, QCA8084_HIGH_ADDR_PREFIX | (sw_addr >> 5),
++			       sw_addr & 0x1f, page);
++}
++
++static int __qca8084_mii_read(struct mii_bus *bus, u16 addr, u16 reg, u32 *val)
++{
++	int ret, data;
++
++	ret = __mdiobus_read(bus, addr, reg);
++	if (ret < 0)
++		return ret;
++
++	data = ret;
++	ret = __mdiobus_read(bus, addr,
++			     reg | QCA8084_MII_REG_DATA_UPPER_16_BITS);
++	if (ret < 0)
++		return ret;
++
++	*val =  data | ret << 16;
++
++	return 0;
++}
++
++static int __qca8084_mii_write(struct mii_bus *bus, u16 addr, u16 reg, u32 val)
++{
++	int ret;
++
++	ret = __mdiobus_write(bus, addr, reg, lower_16_bits(val));
++	if (!ret)
++		ret = __mdiobus_write(bus, addr,
++				      reg | QCA8084_MII_REG_DATA_UPPER_16_BITS,
++				      upper_16_bits(val));
++
++	return ret;
++}
++
++static int qca8084_mii_modify(struct phy_device *phydev, u32 regaddr,
++			      u32 clear, u32 set)
++{
++	u16 reg, addr, page, sw_addr;
++	struct mii_bus *bus;
++	u32 val;
++	int ret;
++
++	bus = phydev->mdio.bus;
++	mutex_lock(&bus->mdio_lock);
++
++	reg = FIELD_GET(QCA8084_MII_REG_MASK, regaddr);
++	addr = FIELD_GET(QCA8084_MII_PHY_ADDR_MASK, regaddr);
++	page = FIELD_GET(QCA8084_MII_PAGE_MASK, regaddr);
++	sw_addr = FIELD_GET(QCA8084_MII_SW_ADDR_MASK, regaddr);
++
++	ret = __qca8084_set_page(bus, sw_addr, page);
++	if (ret < 0)
++		goto qca8084_mii_modify_exit;
++
++	ret = __qca8084_mii_read(bus, QCA8084_LOW_ADDR_PREFIX | addr,
++				 reg, &val);
++	if (ret < 0)
++		goto qca8084_mii_modify_exit;
++
++	val &= ~clear;
++	val |= set;
++	ret = __qca8084_mii_write(bus, QCA8084_LOW_ADDR_PREFIX | addr,
++				  reg, val);
++qca8084_mii_modify_exit:
++	mutex_unlock(&bus->mdio_lock);
++	return ret;
++};
++
+ static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
+ {
+ 	int ret;
diff --git a/target/linux/qualcommbe/patches-6.12/0311-net-phy-qca808x-Add-QCA8084-probe-function.patch b/target/linux/qualcommbe/patches-6.12/0311-net-phy-qca808x-Add-QCA8084-probe-function.patch
new file mode 100644
index 0000000000..b8c5e9ee91
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0311-net-phy-qca808x-Add-QCA8084-probe-function.patch
@@ -0,0 +1,140 @@
+From 485f973c5b1d889bd1f48a188137d80d45004991 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Mon, 29 Jan 2024 10:51:38 +0800
+Subject: [PATCH] net: phy: qca808x: Add QCA8084 probe function
+
+Add the PHY package probe function. The MDIO slave address of
+PHY, PCS and XPCS can be optionally customized by configuring
+the PHY package level register.
+
+In addition, enable system clock of PHY and de-assert PHY in
+the probe function so that the register of PHY device can be
+accessed, and the features of PHY can be acquired.
+
+Change-Id: I2251b9c5c398a21a4ef547a727189a934ad3a44c
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ drivers/net/phy/qcom/qca808x.c | 91 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 91 insertions(+)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -2,6 +2,8 @@
+ 
+ #include <linux/phy.h>
+ #include <linux/module.h>
++#include <linux/of.h>
++#include <linux/clk.h>
+ 
+ #include "qcom.h"
+ 
+@@ -127,6 +129,21 @@
+ #define QCA8084_MII_SW_ADDR_MASK		GENMASK(31, 24)
+ #define QCA8084_MII_REG_DATA_UPPER_16_BITS	BIT(1)
+ 
++/* QCA8084 integrates 4 PHYs, PCS0 and PCS1(includes PCS and XPCS). */
++#define QCA8084_MDIO_DEVICE_NUM			7
++
++#define QCA8084_PCS_CFG				0xc90f014
++#define QCA8084_PCS_ADDR0_MASK			GENMASK(4, 0)
++#define QCA8084_PCS_ADDR1_MASK			GENMASK(9, 5)
++#define QCA8084_PCS_ADDR2_MASK			GENMASK(14, 10)
++
++#define QCA8084_EPHY_CFG			0xc90f018
++#define QCA8084_EPHY_ADDR0_MASK			GENMASK(4, 0)
++#define QCA8084_EPHY_ADDR1_MASK			GENMASK(9, 5)
++#define QCA8084_EPHY_ADDR2_MASK			GENMASK(14, 10)
++#define QCA8084_EPHY_ADDR3_MASK			GENMASK(19, 15)
++#define QCA8084_EPHY_LDO_EN			GENMASK(21, 20)
++
+ MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi, Luo Jie");
+ MODULE_LICENSE("GPL");
+@@ -836,6 +853,79 @@ static void qca8084_link_change_notify(s
+ 			       QCA8084_IPG_10_TO_11_EN : 0);
+ }
+ 
++static int qca8084_phy_package_probe_once(struct phy_device *phydev)
++{
++	int addr[QCA8084_MDIO_DEVICE_NUM] = {0, 1, 2, 3, 4, 5, 6};
++	struct phy_package_shared *shared = phydev->shared;
++	int ret, clear, set;
++
++	/* Program the MDIO address of PHY and PCS optionally, the MDIO
++	 * address 0-6 is used for PHY and PCS MDIO devices by default.
++	 */
++	ret = of_property_read_u32_array(shared->np,
++					 "qcom,phy-addr-fixup",
++					 addr, ARRAY_SIZE(addr));
++	if (ret && ret != -EINVAL)
++		return ret;
++
++	/* Configure the MDIO addresses for the four PHY devices. */
++	clear = QCA8084_EPHY_ADDR0_MASK | QCA8084_EPHY_ADDR1_MASK |
++		QCA8084_EPHY_ADDR2_MASK | QCA8084_EPHY_ADDR3_MASK;
++	set = FIELD_PREP(QCA8084_EPHY_ADDR0_MASK, addr[0]);
++	set |= FIELD_PREP(QCA8084_EPHY_ADDR1_MASK, addr[1]);
++	set |= FIELD_PREP(QCA8084_EPHY_ADDR2_MASK, addr[2]);
++	set |= FIELD_PREP(QCA8084_EPHY_ADDR3_MASK, addr[3]);
++
++	ret = qca8084_mii_modify(phydev, QCA8084_EPHY_CFG, clear, set);
++	if (ret)
++		return ret;
++
++	/* Configure the MDIO addresses for PCS0 and PCS1 including
++	 * PCS and XPCS.
++	 */
++	clear = QCA8084_PCS_ADDR0_MASK | QCA8084_PCS_ADDR1_MASK |
++		QCA8084_PCS_ADDR2_MASK;
++	set = FIELD_PREP(QCA8084_PCS_ADDR0_MASK, addr[4]);
++	set |= FIELD_PREP(QCA8084_PCS_ADDR1_MASK, addr[5]);
++	set |= FIELD_PREP(QCA8084_PCS_ADDR2_MASK, addr[6]);
++
++	return qca8084_mii_modify(phydev, QCA8084_PCS_CFG, clear, set);
++}
++
++static int qca8084_probe(struct phy_device *phydev)
++{
++	struct device *dev = &phydev->mdio.dev;
++	struct reset_control *rstc;
++	struct clk *clk;
++	int ret;
++
++	ret = devm_of_phy_package_join(dev, phydev, 0);
++	if (ret)
++		return ret;
++
++	if (phy_package_probe_once(phydev)) {
++		ret = qca8084_phy_package_probe_once(phydev);
++		if (ret)
++			return ret;
++	}
++
++	/* Enable clock of PHY device, so that the PHY register
++	 * can be accessed to get PHY features.
++	 */
++	clk = devm_clk_get_enabled(dev, NULL);
++	if (IS_ERR(clk))
++		return dev_err_probe(dev, PTR_ERR(clk),
++				     "Enable PHY clock failed\n");
++
++	/* De-assert PHY reset after the clock of PHY enabled. */
++	rstc = devm_reset_control_get_exclusive(dev, NULL);
++	if (IS_ERR(rstc))
++		return dev_err_probe(dev, PTR_ERR(rstc),
++				     "Get PHY reset failed\n");
++
++	return reset_control_deassert(rstc);
++}
++
+ static struct phy_driver qca808x_driver[] = {
+ {
+ 	/* Qualcomm QCA8081 */
+@@ -886,6 +976,7 @@ static struct phy_driver qca808x_driver[
+ 	.cable_test_get_status	= qca808x_cable_test_get_status,
+ 	.config_init		= qca8084_config_init,
+ 	.link_change_notify	= qca8084_link_change_notify,
++	.probe			= qca8084_probe,
+ }, };
+ 
+ module_phy_driver(qca808x_driver);
diff --git a/target/linux/qualcommbe/patches-6.12/0312-net-phy-qca808x-Add-package-clocks-and-resets-for-QC.patch b/target/linux/qualcommbe/patches-6.12/0312-net-phy-qca808x-Add-package-clocks-and-resets-for-QC.patch
new file mode 100644
index 0000000000..b41e725d30
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0312-net-phy-qca808x-Add-package-clocks-and-resets-for-QC.patch
@@ -0,0 +1,132 @@
+From 685566f8b765f522b7f4d4deb06bf84a557dc4ac Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Tue, 9 Apr 2024 16:30:55 +0800
+Subject: [PATCH] net: phy: qca808x: Add package clocks and resets for QCA8084
+
+Parse the PHY package clocks from the PHY package DTS node.
+These package level clocks will be enabled in the PHY package
+init function.
+
+Deassert PHY package reset, which is necessary for accessing
+the PHY registers.
+
+Change-Id: I254d0aa0a1155d3618c6f1fc7d7a5b6ecadccbaa
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ drivers/net/phy/qcom/qca808x.c | 67 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 64 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -4,6 +4,7 @@
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/clk.h>
++#include <linux/reset.h>
+ 
+ #include "qcom.h"
+ 
+@@ -148,10 +149,35 @@ MODULE_DESCRIPTION("Qualcomm Atheros QCA
+ MODULE_AUTHOR("Matus Ujhelyi, Luo Jie");
+ MODULE_LICENSE("GPL");
+ 
++enum {
++	APB_BRIDGE_CLK,
++	AHB_CLK,
++	SEC_CTRL_AHB_CLK,
++	TLMM_CLK,
++	TLMM_AHB_CLK,
++	CNOC_AHB_CLK,
++	MDIO_AHB_CLK,
++	PACKAGE_CLK_MAX
++};
++
+ struct qca808x_priv {
+ 	int led_polarity_mode;
+ };
+ 
++struct qca808x_shared_priv {
++	struct clk *clk[PACKAGE_CLK_MAX];
++};
++
++static const char *const qca8084_package_clk_name[PACKAGE_CLK_MAX] = {
++	[APB_BRIDGE_CLK] =	"apb_bridge",
++	[AHB_CLK] =		"ahb",
++	[SEC_CTRL_AHB_CLK] =	"sec_ctrl_ahb",
++	[TLMM_CLK] =		"tlmm",
++	[TLMM_AHB_CLK] =	"tlmm_ahb",
++	[CNOC_AHB_CLK] =	"cnoc_ahb",
++	[MDIO_AHB_CLK] =	"mdio_ahb",
++};
++
+ static int __qca8084_set_page(struct mii_bus *bus, u16 sw_addr, u16 page)
+ {
+ 	return __mdiobus_write(bus, QCA8084_HIGH_ADDR_PREFIX | (sw_addr >> 5),
+@@ -853,11 +879,24 @@ static void qca8084_link_change_notify(s
+ 			       QCA8084_IPG_10_TO_11_EN : 0);
+ }
+ 
++/* QCA8084 is a four-port PHY, which integrates the clock controller,
++ * 4 PHY devices and 2 PCS interfaces (PCS0 and PCS1). PCS1 includes
++ * XPCS and PCS to support 10G-QXGMII and SGMII. PCS0 includes one PCS
++ * to support SGMII.
++ *
++ * The clocks and resets are sourced from the integrated clock controller
++ * of the PHY package. This integrated clock controller is driven by a
++ * QCA8K clock provider that supplies the clocks and resets to the four
++ * PHYs, PCS and PHY package.
++ */
+ static int qca8084_phy_package_probe_once(struct phy_device *phydev)
+ {
+ 	int addr[QCA8084_MDIO_DEVICE_NUM] = {0, 1, 2, 3, 4, 5, 6};
+ 	struct phy_package_shared *shared = phydev->shared;
+-	int ret, clear, set;
++	struct qca808x_shared_priv *shared_priv;
++	struct reset_control *rstc;
++	int i, ret, clear, set;
++	struct clk *clk;
+ 
+ 	/* Program the MDIO address of PHY and PCS optionally, the MDIO
+ 	 * address 0-6 is used for PHY and PCS MDIO devices by default.
+@@ -889,17 +928,39 @@ static int qca8084_phy_package_probe_onc
+ 	set |= FIELD_PREP(QCA8084_PCS_ADDR1_MASK, addr[5]);
+ 	set |= FIELD_PREP(QCA8084_PCS_ADDR2_MASK, addr[6]);
+ 
+-	return qca8084_mii_modify(phydev, QCA8084_PCS_CFG, clear, set);
++	ret =  qca8084_mii_modify(phydev, QCA8084_PCS_CFG, clear, set);
++	if (ret)
++		return ret;
++
++	shared_priv = shared->priv;
++	for (i = 0; i < ARRAY_SIZE(qca8084_package_clk_name); i++) {
++		clk = of_clk_get_by_name(shared->np,
++					 qca8084_package_clk_name[i]);
++		if (IS_ERR(clk))
++			return dev_err_probe(&phydev->mdio.dev, PTR_ERR(clk),
++					     "package clock %s not ready\n",
++					     qca8084_package_clk_name[i]);
++		shared_priv->clk[i] = clk;
++	}
++
++	rstc = of_reset_control_get_exclusive(shared->np, NULL);
++	if (IS_ERR(rstc))
++		return dev_err_probe(&phydev->mdio.dev, PTR_ERR(rstc),
++				     "package reset not ready\n");
++
++	/* Deassert PHY package. */
++	return reset_control_deassert(rstc);
+ }
+ 
+ static int qca8084_probe(struct phy_device *phydev)
+ {
++	struct qca808x_shared_priv *shared_priv;
+ 	struct device *dev = &phydev->mdio.dev;
+ 	struct reset_control *rstc;
+ 	struct clk *clk;
+ 	int ret;
+ 
+-	ret = devm_of_phy_package_join(dev, phydev, 0);
++	ret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));
+ 	if (ret)
+ 		return ret;
+ 
diff --git a/target/linux/qualcommbe/patches-6.12/0313-net-phy-qca808x-Add-QCA8084-package-init-function.patch b/target/linux/qualcommbe/patches-6.12/0313-net-phy-qca808x-Add-QCA8084-package-init-function.patch
new file mode 100644
index 0000000000..bb5d0728e4
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0313-net-phy-qca808x-Add-QCA8084-package-init-function.patch
@@ -0,0 +1,171 @@
+From bf779b10b00fd79267d0ef625ae246df59ee23bd Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Thu, 25 Jan 2024 17:13:24 +0800
+Subject: [PATCH] net: phy: qca808x: Add QCA8084 package init function
+
+The package mode of PHY is configured for the interface mode of two
+PCSes working correctly.
+
+The PHY package level clocks are enabled and their rates configured.
+
+Change-Id: I63d4b22d2a70ee713cc6a6818b0f3c7aa098a5f5
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ drivers/net/phy/qcom/qca808x.c | 115 +++++++++++++++++++++++++++++++++
+ 1 file changed, 115 insertions(+)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -1,5 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0+
+ 
++#include <dt-bindings/net/qcom,qca808x.h>
+ #include <linux/phy.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
+@@ -145,6 +146,13 @@
+ #define QCA8084_EPHY_ADDR3_MASK			GENMASK(19, 15)
+ #define QCA8084_EPHY_LDO_EN			GENMASK(21, 20)
+ 
++#define QCA8084_WORK_MODE_CFG			0xc90f030
++#define QCA8084_WORK_MODE_MASK			GENMASK(5, 0)
++#define QCA8084_WORK_MODE_QXGMII		(BIT(5) | GENMASK(3, 0))
++#define QCA8084_WORK_MODE_QXGMII_PORT4_SGMII	(BIT(5) | GENMASK(2, 0))
++#define QCA8084_WORK_MODE_SWITCH		BIT(4)
++#define QCA8084_WORK_MODE_SWITCH_PORT4_SGMII	BIT(5)
++
+ MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi, Luo Jie");
+ MODULE_LICENSE("GPL");
+@@ -165,6 +173,7 @@ struct qca808x_priv {
+ };
+ 
+ struct qca808x_shared_priv {
++	int package_mode;
+ 	struct clk *clk[PACKAGE_CLK_MAX];
+ };
+ 
+@@ -808,10 +817,107 @@ static int qca808x_led_polarity_set(stru
+ 			      active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
+ }
+ 
++static int qca8084_package_clock_init(struct qca808x_shared_priv *shared_priv)
++{
++	int ret;
++
++	/* Configure clock rate 312.5MHZ for the PHY package
++	 * APB bridge clock tree.
++	 */
++	ret = clk_set_rate(shared_priv->clk[APB_BRIDGE_CLK], 312500000);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(shared_priv->clk[APB_BRIDGE_CLK]);
++	if (ret)
++		return ret;
++
++	/* Configure clock rate 104.17MHZ for the PHY package
++	 * AHB clock tree.
++	 */
++	ret = clk_set_rate(shared_priv->clk[AHB_CLK], 104170000);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(shared_priv->clk[AHB_CLK]);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(shared_priv->clk[SEC_CTRL_AHB_CLK]);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(shared_priv->clk[TLMM_CLK]);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(shared_priv->clk[TLMM_AHB_CLK]);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(shared_priv->clk[CNOC_AHB_CLK]);
++	if (ret)
++		return ret;
++
++	return clk_prepare_enable(shared_priv->clk[MDIO_AHB_CLK]);
++}
++
++static int qca8084_phy_package_config_init_once(struct phy_device *phydev)
++{
++	struct phy_package_shared *shared = phydev->shared;
++	struct qca808x_shared_priv *shared_priv;
++	int ret, mode;
++
++	shared_priv = shared->priv;
++	switch (shared_priv->package_mode) {
++	case QCA808X_PCS1_10G_QXGMII_PCS0_UNUNSED:
++		mode = QCA8084_WORK_MODE_QXGMII;
++		break;
++	case QCA808X_PCS1_SGMII_MAC_PCS0_SGMII_MAC:
++		mode = QCA8084_WORK_MODE_SWITCH;
++		break;
++	case QCA808X_PCS1_SGMII_MAC_PCS0_SGMII_PHY:
++		mode = QCA8084_WORK_MODE_SWITCH_PORT4_SGMII;
++		break;
++	default:
++		phydev_err(phydev, "Invalid qcom,package-mode %d\n",
++			   shared_priv->package_mode);
++		return -EINVAL;
++	}
++
++	ret = qca8084_mii_modify(phydev, QCA8084_WORK_MODE_CFG,
++				 QCA8084_WORK_MODE_MASK,
++				 FIELD_PREP(QCA8084_WORK_MODE_MASK, mode));
++	if (ret)
++		return ret;
++
++	/* Initialize the PHY package clock and reset, which is the
++	 * necessary config sequence after GPIO reset on the PHY package.
++	 */
++	ret = qca8084_package_clock_init(shared_priv);
++	if (ret)
++		return ret;
++
++	/* Enable efuse loading into analog circuit */
++	ret = qca8084_mii_modify(phydev, QCA8084_EPHY_CFG,
++				 QCA8084_EPHY_LDO_EN, 0);
++	if (ret)
++		return ret;
++
++	usleep_range(10000, 11000);
++	return ret;
++}
++
+ static int qca8084_config_init(struct phy_device *phydev)
+ {
+ 	int ret;
+ 
++	if (phy_package_init_once(phydev)) {
++		ret = qca8084_phy_package_config_init_once(phydev);
++		if (ret)
++			return ret;
++	}
++
+ 	if (phydev->interface == PHY_INTERFACE_MODE_10G_QXGMII)
+ 		__set_bit(PHY_INTERFACE_MODE_10G_QXGMII,
+ 			  phydev->possible_interfaces);
+@@ -948,6 +1054,15 @@ static int qca8084_phy_package_probe_onc
+ 		return dev_err_probe(&phydev->mdio.dev, PTR_ERR(rstc),
+ 				     "package reset not ready\n");
+ 
++	/* The package mode 10G-QXGMII of PCS1 is used for Quad PHY and
++	 * PCS0 is unused by default.
++	 */
++	shared_priv->package_mode = QCA808X_PCS1_10G_QXGMII_PCS0_UNUNSED;
++	ret = of_property_read_u32(shared->np, "qcom,package-mode",
++				   &shared_priv->package_mode);
++	if (ret && ret != -EINVAL)
++		return ret;
++
+ 	/* Deassert PHY package. */
+ 	return reset_control_deassert(rstc);
+ }




More information about the lede-commits mailing list