[openwrt/openwrt] qualcommbe: support 10g-qxgmii in QCA8084 PHY driver

LEDE Commits lede-commits at lists.infradead.org
Tue Nov 11 08:21:58 PST 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/7656e74a95337279473e00c1940587b0590373ba

commit 7656e74a95337279473e00c1940587b0590373ba
Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
AuthorDate: Sun Nov 9 17:36:33 2025 -0600

    qualcommbe: support 10g-qxgmii in QCA8084 PHY driver
    
    The "old" QCA8084 PHY driver does not implement 10g-qxgmii support.
    This is blocking several devices which use the QCA8084 form being
    merged. Qualcomm has provided updated drivers for the MAC (ppe), PCS,
    and PHY via github. We only need to update the PHY driver.
    
    Update the QCA8084 PHY driver using the patches provided by Qualcomm.
    Re-organize the patches so that the changes go into the existing
    patches. The SERDES functionality is new, so it gets new patches. This
    is sufficient to enable 10g-qxgmii on ipq95xx platforms.
    
    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
    Link: https://github.com/openwrt/openwrt/pull/20721
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 ...hy-move-PHY-package-code-from-phy_device..patch | 524 +++++++++++++++++++++
 ...hy-add-getters-for-public-members-in-stru.patch |  60 +++
 ...-net-Document-Qualcomm-QCA8084-PHY-packag.patch | 344 +++++++++++++-
 ...-qca808x-Add-QCA8084-ethernet-phy-support.patch |  25 +-
 ...808x-Add-config_init-function-for-QCA8084.patch |   6 +-
 ...808x-Add-link_change_notify-function-for-.patch |   6 +-
 ...808x-Add-register-access-support-routines.patch |   2 +-
 ...et-phy-qca808x-Add-QCA8084-probe-function.patch |  42 +-
 ...808x-Add-package-clocks-and-resets-for-QC.patch |  49 +-
 ...qca808x-Add-QCA8084-package-init-function.patch |  54 ++-
 ...et-phy-Add-phy_package_remove_once-helper.patch |  36 ++
 ...808x-Add-QCA8084-SerDes-probe-and-remove-.patch | 437 +++++++++++++++++
 ...-qca808x-Add-QCA8084-SerDes-init-function.patch | 446 ++++++++++++++++++
 ...y-qca808x-Add-QCA8084-SerDes-speed-config.patch | 251 ++++++++++
 14 files changed, 2185 insertions(+), 97 deletions(-)

diff --git a/target/linux/qualcommbe/patches-6.12/0023-v6.15-net-phy-move-PHY-package-code-from-phy_device..patch b/target/linux/qualcommbe/patches-6.12/0023-v6.15-net-phy-move-PHY-package-code-from-phy_device..patch
new file mode 100644
index 0000000000..6fa5e4e23c
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0023-v6.15-net-phy-move-PHY-package-code-from-phy_device..patch
@@ -0,0 +1,524 @@
+From 986ec7ee75f2f1f7f93eb0e05f61f297f6123fce Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1 at gmail.com>
+Date: Mon, 3 Mar 2025 21:14:02 +0100
+Subject: [PATCH] v6.15: net: phy: move PHY package code from phy_device.c to
+ own source file
+
+This patch is the first step in moving the PHY package related code
+to its own source file. No functional change intended.
+
+Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
+Link: https://patch.msgid.link/57df5c19-fbcd-45a7-9afd-cd4f74d7fa76@gmail.com
+Signed-off-by: Jakub Kicinski <kuba at kernel.org>
+---
+ drivers/net/phy/Makefile      |   3 +-
+ drivers/net/phy/phy_device.c  | 237 ---------------------------------
+ drivers/net/phy/phy_package.c | 244 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 246 insertions(+), 238 deletions(-)
+ create mode 100644 drivers/net/phy/phy_package.c
+
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -2,7 +2,8 @@
+ # Makefile for Linux PHY drivers
+ 
+ libphy-y			:= phy.o phy-c45.o phy-core.o phy_device.o \
+-				   linkmode.o phy_link_topology.o
++				   linkmode.o phy_link_topology.o \
++				   phy_package.o
+ mdio-bus-y			+= mdio_bus.o mdio_device.o
+ 
+ ifdef CONFIG_MDIO_DEVICE
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1783,243 +1783,6 @@ bool phy_driver_is_genphy_10g(struct phy
+ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
+ 
+ /**
+- * phy_package_join - join a common PHY group
+- * @phydev: target phy_device struct
+- * @base_addr: cookie and base PHY address of PHY package for offset
+- *   calculation of global register access
+- * @priv_size: if non-zero allocate this amount of bytes for private data
+- *
+- * This joins a PHY group and provides a shared storage for all phydevs in
+- * this group. This is intended to be used for packages which contain
+- * more than one PHY, for example a quad PHY transceiver.
+- *
+- * The base_addr parameter serves as cookie which has to have the same values
+- * for all members of one group and as the base PHY address of the PHY package
+- * for offset calculation to access generic registers of a PHY package.
+- * Usually, one of the PHY addresses of the different PHYs in the package
+- * provides access to these global registers.
+- * The address which is given here, will be used in the phy_package_read()
+- * and phy_package_write() convenience functions as base and added to the
+- * passed offset in those functions.
+- *
+- * This will set the shared pointer of the phydev to the shared storage.
+- * If this is the first call for a this cookie the shared storage will be
+- * allocated. If priv_size is non-zero, the given amount of bytes are
+- * allocated for the priv member.
+- *
+- * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
+- * with the same cookie but a different priv_size is an error.
+- */
+-int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
+-{
+-	struct mii_bus *bus = phydev->mdio.bus;
+-	struct phy_package_shared *shared;
+-	int ret;
+-
+-	if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
+-		return -EINVAL;
+-
+-	mutex_lock(&bus->shared_lock);
+-	shared = bus->shared[base_addr];
+-	if (!shared) {
+-		ret = -ENOMEM;
+-		shared = kzalloc(sizeof(*shared), GFP_KERNEL);
+-		if (!shared)
+-			goto err_unlock;
+-		if (priv_size) {
+-			shared->priv = kzalloc(priv_size, GFP_KERNEL);
+-			if (!shared->priv)
+-				goto err_free;
+-			shared->priv_size = priv_size;
+-		}
+-		shared->base_addr = base_addr;
+-		shared->np = NULL;
+-		refcount_set(&shared->refcnt, 1);
+-		bus->shared[base_addr] = shared;
+-	} else {
+-		ret = -EINVAL;
+-		if (priv_size && priv_size != shared->priv_size)
+-			goto err_unlock;
+-		refcount_inc(&shared->refcnt);
+-	}
+-	mutex_unlock(&bus->shared_lock);
+-
+-	phydev->shared = shared;
+-
+-	return 0;
+-
+-err_free:
+-	kfree(shared);
+-err_unlock:
+-	mutex_unlock(&bus->shared_lock);
+-	return ret;
+-}
+-EXPORT_SYMBOL_GPL(phy_package_join);
+-
+-/**
+- * of_phy_package_join - join a common PHY group in PHY package
+- * @phydev: target phy_device struct
+- * @priv_size: if non-zero allocate this amount of bytes for private data
+- *
+- * This is a variant of phy_package_join for PHY package defined in DT.
+- *
+- * The parent node of the @phydev is checked as a valid PHY package node
+- * structure (by matching the node name "ethernet-phy-package") and the
+- * base_addr for the PHY package is passed to phy_package_join.
+- *
+- * With this configuration the shared struct will also have the np value
+- * filled to use additional DT defined properties in PHY specific
+- * probe_once and config_init_once PHY package OPs.
+- *
+- * Returns < 0 on error, 0 on success. Esp. calling phy_package_join()
+- * with the same cookie but a different priv_size is an error. Or a parent
+- * node is not detected or is not valid or doesn't match the expected node
+- * name for PHY package.
+- */
+-int of_phy_package_join(struct phy_device *phydev, size_t priv_size)
+-{
+-	struct device_node *node = phydev->mdio.dev.of_node;
+-	struct device_node *package_node;
+-	u32 base_addr;
+-	int ret;
+-
+-	if (!node)
+-		return -EINVAL;
+-
+-	package_node = of_get_parent(node);
+-	if (!package_node)
+-		return -EINVAL;
+-
+-	if (!of_node_name_eq(package_node, "ethernet-phy-package")) {
+-		ret = -EINVAL;
+-		goto exit;
+-	}
+-
+-	if (of_property_read_u32(package_node, "reg", &base_addr)) {
+-		ret = -EINVAL;
+-		goto exit;
+-	}
+-
+-	ret = phy_package_join(phydev, base_addr, priv_size);
+-	if (ret)
+-		goto exit;
+-
+-	phydev->shared->np = package_node;
+-
+-	return 0;
+-exit:
+-	of_node_put(package_node);
+-	return ret;
+-}
+-EXPORT_SYMBOL_GPL(of_phy_package_join);
+-
+-/**
+- * phy_package_leave - leave a common PHY group
+- * @phydev: target phy_device struct
+- *
+- * This leaves a PHY group created by phy_package_join(). If this phydev
+- * was the last user of the shared data between the group, this data is
+- * freed. Resets the phydev->shared pointer to NULL.
+- */
+-void phy_package_leave(struct phy_device *phydev)
+-{
+-	struct phy_package_shared *shared = phydev->shared;
+-	struct mii_bus *bus = phydev->mdio.bus;
+-
+-	if (!shared)
+-		return;
+-
+-	/* Decrease the node refcount on leave if present */
+-	if (shared->np)
+-		of_node_put(shared->np);
+-
+-	if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
+-		bus->shared[shared->base_addr] = NULL;
+-		mutex_unlock(&bus->shared_lock);
+-		kfree(shared->priv);
+-		kfree(shared);
+-	}
+-
+-	phydev->shared = NULL;
+-}
+-EXPORT_SYMBOL_GPL(phy_package_leave);
+-
+-static void devm_phy_package_leave(struct device *dev, void *res)
+-{
+-	phy_package_leave(*(struct phy_device **)res);
+-}
+-
+-/**
+- * devm_phy_package_join - resource managed phy_package_join()
+- * @dev: device that is registering this PHY package
+- * @phydev: target phy_device struct
+- * @base_addr: cookie and base PHY address of PHY package for offset
+- *   calculation of global register access
+- * @priv_size: if non-zero allocate this amount of bytes for private data
+- *
+- * Managed phy_package_join(). Shared storage fetched by this function,
+- * phy_package_leave() is automatically called on driver detach. See
+- * phy_package_join() for more information.
+- */
+-int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
+-			  int base_addr, size_t priv_size)
+-{
+-	struct phy_device **ptr;
+-	int ret;
+-
+-	ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
+-			   GFP_KERNEL);
+-	if (!ptr)
+-		return -ENOMEM;
+-
+-	ret = phy_package_join(phydev, base_addr, priv_size);
+-
+-	if (!ret) {
+-		*ptr = phydev;
+-		devres_add(dev, ptr);
+-	} else {
+-		devres_free(ptr);
+-	}
+-
+-	return ret;
+-}
+-EXPORT_SYMBOL_GPL(devm_phy_package_join);
+-
+-/**
+- * devm_of_phy_package_join - resource managed of_phy_package_join()
+- * @dev: device that is registering this PHY package
+- * @phydev: target phy_device struct
+- * @priv_size: if non-zero allocate this amount of bytes for private data
+- *
+- * Managed of_phy_package_join(). Shared storage fetched by this function,
+- * phy_package_leave() is automatically called on driver detach. See
+- * of_phy_package_join() for more information.
+- */
+-int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
+-			     size_t priv_size)
+-{
+-	struct phy_device **ptr;
+-	int ret;
+-
+-	ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
+-			   GFP_KERNEL);
+-	if (!ptr)
+-		return -ENOMEM;
+-
+-	ret = of_phy_package_join(phydev, priv_size);
+-
+-	if (!ret) {
+-		*ptr = phydev;
+-		devres_add(dev, ptr);
+-	} else {
+-		devres_free(ptr);
+-	}
+-
+-	return ret;
+-}
+-EXPORT_SYMBOL_GPL(devm_of_phy_package_join);
+-
+-/**
+  * phy_detach - detach a PHY device from its network device
+  * @phydev: target phy_device struct
+  *
+--- /dev/null
++++ b/drivers/net/phy/phy_package.c
+@@ -0,0 +1,244 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * PHY package support
++ */
++
++#include <linux/of.h>
++#include <linux/phy.h>
++
++/**
++ * phy_package_join - join a common PHY group
++ * @phydev: target phy_device struct
++ * @base_addr: cookie and base PHY address of PHY package for offset
++ *   calculation of global register access
++ * @priv_size: if non-zero allocate this amount of bytes for private data
++ *
++ * This joins a PHY group and provides a shared storage for all phydevs in
++ * this group. This is intended to be used for packages which contain
++ * more than one PHY, for example a quad PHY transceiver.
++ *
++ * The base_addr parameter serves as cookie which has to have the same values
++ * for all members of one group and as the base PHY address of the PHY package
++ * for offset calculation to access generic registers of a PHY package.
++ * Usually, one of the PHY addresses of the different PHYs in the package
++ * provides access to these global registers.
++ * The address which is given here, will be used in the phy_package_read()
++ * and phy_package_write() convenience functions as base and added to the
++ * passed offset in those functions.
++ *
++ * This will set the shared pointer of the phydev to the shared storage.
++ * If this is the first call for a this cookie the shared storage will be
++ * allocated. If priv_size is non-zero, the given amount of bytes are
++ * allocated for the priv member.
++ *
++ * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
++ * with the same cookie but a different priv_size is an error.
++ */
++int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
++{
++	struct mii_bus *bus = phydev->mdio.bus;
++	struct phy_package_shared *shared;
++	int ret;
++
++	if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
++		return -EINVAL;
++
++	mutex_lock(&bus->shared_lock);
++	shared = bus->shared[base_addr];
++	if (!shared) {
++		ret = -ENOMEM;
++		shared = kzalloc(sizeof(*shared), GFP_KERNEL);
++		if (!shared)
++			goto err_unlock;
++		if (priv_size) {
++			shared->priv = kzalloc(priv_size, GFP_KERNEL);
++			if (!shared->priv)
++				goto err_free;
++			shared->priv_size = priv_size;
++		}
++		shared->base_addr = base_addr;
++		shared->np = NULL;
++		refcount_set(&shared->refcnt, 1);
++		bus->shared[base_addr] = shared;
++	} else {
++		ret = -EINVAL;
++		if (priv_size && priv_size != shared->priv_size)
++			goto err_unlock;
++		refcount_inc(&shared->refcnt);
++	}
++	mutex_unlock(&bus->shared_lock);
++
++	phydev->shared = shared;
++
++	return 0;
++
++err_free:
++	kfree(shared);
++err_unlock:
++	mutex_unlock(&bus->shared_lock);
++	return ret;
++}
++EXPORT_SYMBOL_GPL(phy_package_join);
++
++/**
++ * of_phy_package_join - join a common PHY group in PHY package
++ * @phydev: target phy_device struct
++ * @priv_size: if non-zero allocate this amount of bytes for private data
++ *
++ * This is a variant of phy_package_join for PHY package defined in DT.
++ *
++ * The parent node of the @phydev is checked as a valid PHY package node
++ * structure (by matching the node name "ethernet-phy-package") and the
++ * base_addr for the PHY package is passed to phy_package_join.
++ *
++ * With this configuration the shared struct will also have the np value
++ * filled to use additional DT defined properties in PHY specific
++ * probe_once and config_init_once PHY package OPs.
++ *
++ * Returns < 0 on error, 0 on success. Esp. calling phy_package_join()
++ * with the same cookie but a different priv_size is an error. Or a parent
++ * node is not detected or is not valid or doesn't match the expected node
++ * name for PHY package.
++ */
++int of_phy_package_join(struct phy_device *phydev, size_t priv_size)
++{
++	struct device_node *node = phydev->mdio.dev.of_node;
++	struct device_node *package_node;
++	u32 base_addr;
++	int ret;
++
++	if (!node)
++		return -EINVAL;
++
++	package_node = of_get_parent(node);
++	if (!package_node)
++		return -EINVAL;
++
++	if (!of_node_name_eq(package_node, "ethernet-phy-package")) {
++		ret = -EINVAL;
++		goto exit;
++	}
++
++	if (of_property_read_u32(package_node, "reg", &base_addr)) {
++		ret = -EINVAL;
++		goto exit;
++	}
++
++	ret = phy_package_join(phydev, base_addr, priv_size);
++	if (ret)
++		goto exit;
++
++	phydev->shared->np = package_node;
++
++	return 0;
++exit:
++	of_node_put(package_node);
++	return ret;
++}
++EXPORT_SYMBOL_GPL(of_phy_package_join);
++
++/**
++ * phy_package_leave - leave a common PHY group
++ * @phydev: target phy_device struct
++ *
++ * This leaves a PHY group created by phy_package_join(). If this phydev
++ * was the last user of the shared data between the group, this data is
++ * freed. Resets the phydev->shared pointer to NULL.
++ */
++void phy_package_leave(struct phy_device *phydev)
++{
++	struct phy_package_shared *shared = phydev->shared;
++	struct mii_bus *bus = phydev->mdio.bus;
++
++	if (!shared)
++		return;
++
++	/* Decrease the node refcount on leave if present */
++	if (shared->np)
++		of_node_put(shared->np);
++
++	if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
++		bus->shared[shared->base_addr] = NULL;
++		mutex_unlock(&bus->shared_lock);
++		kfree(shared->priv);
++		kfree(shared);
++	}
++
++	phydev->shared = NULL;
++}
++EXPORT_SYMBOL_GPL(phy_package_leave);
++
++static void devm_phy_package_leave(struct device *dev, void *res)
++{
++	phy_package_leave(*(struct phy_device **)res);
++}
++
++/**
++ * devm_phy_package_join - resource managed phy_package_join()
++ * @dev: device that is registering this PHY package
++ * @phydev: target phy_device struct
++ * @base_addr: cookie and base PHY address of PHY package for offset
++ *   calculation of global register access
++ * @priv_size: if non-zero allocate this amount of bytes for private data
++ *
++ * Managed phy_package_join(). Shared storage fetched by this function,
++ * phy_package_leave() is automatically called on driver detach. See
++ * phy_package_join() for more information.
++ */
++int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
++			  int base_addr, size_t priv_size)
++{
++	struct phy_device **ptr;
++	int ret;
++
++	ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
++			   GFP_KERNEL);
++	if (!ptr)
++		return -ENOMEM;
++
++	ret = phy_package_join(phydev, base_addr, priv_size);
++
++	if (!ret) {
++		*ptr = phydev;
++		devres_add(dev, ptr);
++	} else {
++		devres_free(ptr);
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(devm_phy_package_join);
++
++/**
++ * devm_of_phy_package_join - resource managed of_phy_package_join()
++ * @dev: device that is registering this PHY package
++ * @phydev: target phy_device struct
++ * @priv_size: if non-zero allocate this amount of bytes for private data
++ *
++ * Managed of_phy_package_join(). Shared storage fetched by this function,
++ * phy_package_leave() is automatically called on driver detach. See
++ * of_phy_package_join() for more information.
++ */
++int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
++			     size_t priv_size)
++{
++	struct phy_device **ptr;
++	int ret;
++
++	ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
++			   GFP_KERNEL);
++	if (!ptr)
++		return -ENOMEM;
++
++	ret = of_phy_package_join(phydev, priv_size);
++
++	if (!ret) {
++		*ptr = phydev;
++		devres_add(dev, ptr);
++	} else {
++		devres_free(ptr);
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(devm_of_phy_package_join);
diff --git a/target/linux/qualcommbe/patches-6.12/0024-v6.15-net-phy-add-getters-for-public-members-in-stru.patch b/target/linux/qualcommbe/patches-6.12/0024-v6.15-net-phy-add-getters-for-public-members-in-stru.patch
new file mode 100644
index 0000000000..a05083d6fe
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0024-v6.15-net-phy-add-getters-for-public-members-in-stru.patch
@@ -0,0 +1,60 @@
+From e9ee1dd2ff2c130b2fb2bd01936224a8a6b49a7e Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1 at gmail.com>
+Date: Mon, 3 Mar 2025 21:15:09 +0100
+Subject: [PATCH] v6.15: net: phy: add getters for public members in struct
+ phy_package_shared
+
+Add getters for public members, this prepares for making struct
+phy_package_shared private to phylib. Declare the getters in a new header
+file phylib.h, which will be used by PHY drivers only.
+
+Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
+Link: https://patch.msgid.link/c6da0b27-4479-4717-9e16-643821b76bd8@gmail.com
+Signed-off-by: Jakub Kicinski <kuba at kernel.org>
+---
+ drivers/net/phy/phy_package.c | 14 ++++++++++++++
+ drivers/net/phy/phylib.h      | 15 +++++++++++++++
+ 2 files changed, 29 insertions(+)
+ create mode 100644 drivers/net/phy/phylib.h
+
+--- a/drivers/net/phy/phy_package.c
++++ b/drivers/net/phy/phy_package.c
+@@ -6,6 +6,20 @@
+ #include <linux/of.h>
+ #include <linux/phy.h>
+ 
++#include "phylib.h"
++
++struct device_node *phy_package_get_node(struct phy_device *phydev)
++{
++	return phydev->shared->np;
++}
++EXPORT_SYMBOL_GPL(phy_package_get_node);
++
++void *phy_package_get_priv(struct phy_device *phydev)
++{
++	return phydev->shared->priv;
++}
++EXPORT_SYMBOL_GPL(phy_package_get_priv);
++
+ /**
+  * phy_package_join - join a common PHY group
+  * @phydev: target phy_device struct
+--- /dev/null
++++ b/drivers/net/phy/phylib.h
+@@ -0,0 +1,15 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ * phylib header
++ */
++
++#ifndef __PHYLIB_H
++#define __PHYLIB_H
++
++struct device_node;
++struct phy_device;
++
++struct device_node *phy_package_get_node(struct phy_device *phydev);
++void *phy_package_get_priv(struct phy_device *phydev);
++
++#endif /* __PHYLIB_H */
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
index 1583258493..a9223c5a35 100644
--- 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
@@ -1,4 +1,4 @@
-From ae682f13d308682232069e5150e884fc10160598 Mon Sep 17 00:00:00 2001
+From 7b1c4e22532ded6b20ee41936fa38b5ca1e61ff9 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
@@ -17,16 +17,18 @@ also be integrated to the switch chip named as QCA8386.
 
 Change-Id: Idb2338d2673152cbd3c57e95968faa59e9d4a80f
 Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+Alex G: Update to match the patches that will be upstream.
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
 ---
- .../devicetree/bindings/net/qcom,qca8084.yaml | 198 ++++++++++++++++++
- include/dt-bindings/net/qcom,qca808x.h        |  14 ++
- 2 files changed, 212 insertions(+)
+ .../devicetree/bindings/net/qcom,qca8084.yaml | 488 ++++++++++++++++++
+ include/dt-bindings/net/qcom,qca808x.h        |  14 +
+ 2 files changed, 502 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 @@
+@@ -0,0 +1,488 @@
 +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 +%YAML 1.2
 +---
@@ -39,8 +41,8 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +  - 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.
++  Qualcomm QCA8084 is PHY package of 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
@@ -63,7 +65,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +                 |                     |             |
 +    Ref 50M clk  +--------+            |             |
 +    ------------>|        | clk & rst  |             |
-+    GPIO Reset   |QCA8K_CC+------------+             |
++    GPIO Reset   |QCA8K-CC+------------+             |
 +    ------------>|        |            |             |
 +                 +--------+            |             |
 +                 |                     V             |
@@ -71,17 +73,15 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +                 |  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).
++    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
@@ -102,10 +102,11 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +      - 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.
++    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:
@@ -130,30 +131,168 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +    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.
++    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]+)?$:
++  ^ethernet-phy@[a-f0-9]+$:
++    unevaluatedProperties: false
 +    $ref: ethernet-phy.yaml#
 +
 +    properties:
 +      compatible:
 +        const: ethernet-phy-id004d.d180
 +
++      qcom,xpcs-channel:
++        description:
++          When PCS1 works on the interface mode 10G-QXGMII, the integrated
++          XPCS including 4 channels is used to connected with the Quad PHYs,
++          each PHY needs to be specified the XPCS channel ID to deliver the
++          PHY link status to the XPCS.
++        $ref: /schemas/types.yaml#/definitions/uint32
++        enum: [0, 1, 2, 3]
++
 +    required:
 +      - compatible
 +      - reg
 +      - clocks
 +      - resets
 +
-+    unevaluatedProperties: false
++  ^pcs-phy@[a-f0-9]+$:
++    type: object
++    additionalProperties: false
++    description:
++      PCS device has the independent MDIO address, which controls
++      the interface mode used and provides the clocks such as
++      312.5 MHZ as RX and TX root clocks to the integrated clock
++      controller.
++    properties:
++      compatible:
++        const: qcom,qca8k-pcs-phy
++
++      reg:
++        items:
++          - description: PCS MDIO address.
++
++      clocks:
++        items:
++          - description: PCS clock.
++          - description: PCS RX root clock.
++          - description: PCS TX root clock.
++
++      clock-names:
++        items:
++          - const: pcs
++          - const: pcs_rx_root
++          - const: pcs_tx_root
++
++      resets:
++        items:
++          - description: PCS reset.
++
++    required:
++      - compatible
++      - reg
++      - clocks
++      - resets
++
++  ^xpcs-phy@[a-f0-9]+$:
++    type: object
++    additionalProperties: false
++    description:
++      XPCS device has the independent MDIO address, which includes 4
++      channels to connect with Quad PHYs.
++    properties:
++      compatible:
++        const: qcom,qca8k-xpcs-phy
++
++      reg:
++        items:
++          - description: XPCS MDIO address.
++
++      resets:
++        items:
++          - description: XPCS reset.
++
++      '#address-cells':
++        const: 1
++
++      '#size-cells':
++        const: 0
++
++    required:
++      - compatible
++      - reg
++      - resets
++      - '#address-cells'
++      - '#size-cells'
++
++    patternProperties:
++      "^channel@[0-3]+$":
++        type: object
++        additionalProperties: false
++        description:
++          XPCS is used to support 10G-QXGMII mode, which inlcudes 4 channels
++          to be connected with Quad PHYs, each channels has the dedicated
++          clocks and resets from the integrated clock controller of QCA8084.
++
++        properties:
++          reg:
++            items:
++              - description: XPCS channel ID
++
++          clocks:
++            items:
++              - description: XPCS XGMII RX clock
++              - description: XPCS XGMII TX clock
++              - description: XPCS RX clock
++              - description: XPCS TX clock
++              - description: Port RX clock
++              - description: Port TX clock
++              - description: RX source clock
++              - description: TX source clock
++
++          clock-names:
++            items:
++              - const: xgmii_rx
++              - const: xgmii_tx
++              - const: xpcs_rx
++              - const: xpcs_tx
++              - const: port_rx
++              - const: port_tx
++              - const: rx_src
++              - const: tx_src
++
++          resets:
++            items:
++              - description: XPCS XGMII RX reset
++              - description: XPCS XGMII TX reset
++              - description: XPCS RX reset
++              - description: XPCS TX reset
++              - description: Port RX reset
++              - description: Port TX reset
++
++          reset-names:
++            items:
++              - const: xgmii_rx
++              - const: xgmii_tx
++              - const: xpcs_rx
++              - const: xpcs_tx
++              - const: port_rx
++              - const: port_tx
++
++        required:
++          - reg
++          - clocks
++          - clock-names
++          - resets
++          - reset-names
 +
 +required:
 +  - compatible
@@ -161,6 +300,9 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +  - clock-names
 +  - resets
 +
++allOf:
++  - $ref: ethernet-phy-package.yaml#
++
 +unevaluatedProperties: false
 +
 +examples:
@@ -193,7 +335,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +                          "cnoc_ahb",
 +                          "mdio_ahb";
 +            resets = <&qca8k_nsscc NSS_CC_GEPHY_FULL_ARES>;
-+            qcom,package-mode = <QCA808X_PCS1_SGMII_MAC_PCS0_SGMII_MAC>;
++            qcom,package-mode = <QCA808X_PCS1_10G_QXGMII_PCS0_UNUNSED>;
 +            qcom,phy-addr-fixup = <1 2 3 4 5 6 7>;
 +
 +            ethernet-phy at 1 {
@@ -201,6 +343,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +                reg = <1>;
 +                clocks = <&qca8k_nsscc NSS_CC_GEPHY0_SYS_CLK>;
 +                resets = <&qca8k_nsscc NSS_CC_GEPHY0_SYS_ARES>;
++                qcom,xpcs-channel = <0>;
 +            };
 +
 +            ethernet-phy at 2 {
@@ -208,6 +351,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +                reg = <2>;
 +                clocks = <&qca8k_nsscc NSS_CC_GEPHY1_SYS_CLK>;
 +                resets = <&qca8k_nsscc NSS_CC_GEPHY1_SYS_ARES>;
++                qcom,xpcs-channel = <1>;
 +            };
 +
 +            ethernet-phy at 3 {
@@ -215,6 +359,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +                reg = <3>;
 +                clocks = <&qca8k_nsscc NSS_CC_GEPHY2_SYS_CLK>;
 +                resets = <&qca8k_nsscc NSS_CC_GEPHY2_SYS_ARES>;
++                qcom,xpcs-channel = <2>;
 +            };
 +
 +            ethernet-phy at 4 {
@@ -222,6 +367,153 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +                reg = <4>;
 +                clocks = <&qca8k_nsscc NSS_CC_GEPHY3_SYS_CLK>;
 +                resets = <&qca8k_nsscc NSS_CC_GEPHY3_SYS_ARES>;
++                qcom,xpcs-channel = <3>;
++            };
++
++            pcs-phy at 6 {
++                compatible = "qcom,qca8k-pcs-phy";
++                reg = <6>;
++                clocks = <&qca8k_nsscc NSS_CC_SRDS1_SYS_CLK>,
++                         <&qca8k_uniphy1_tx312p5m>,
++                         <&qca8k_uniphy1_rx312p5m>;
++                clock-names = "pcs", "pcs_rx_root", "pcs_tx_root";
++                resets = <&qca8k_nsscc NSS_CC_SRDS1_SYS_ARES>;
++            };
++
++            xpcs-phy at 7 {
++                compatible = "qcom,qca8k-xpcs-phy";
++                reg = <7>;
++                #address-cells = <1>;
++                #size-cells = <0>;
++                resets = <&qca8k_nsscc NSS_CC_XPCS_ARES>;
++
++                channel at 0 {
++                    reg = <0>;
++                    clocks = <&qca8k_nsscc NSS_CC_MAC1_SRDS1_CH0_XGMII_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC1_SRDS1_CH0_XGMII_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC1_SRDS1_CH0_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC1_SRDS1_CH0_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC1_GEPHY0_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC1_GEPHY0_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC1_RX_CLK_SRC>,
++                             <&qca8k_nsscc NSS_CC_MAC1_TX_CLK_SRC>;
++                    clock-names = "xgmii_rx",
++                                  "xgmii_tx",
++                                  "xpcs_rx",
++                                  "xpcs_tx",
++                                  "port_rx",
++                                  "port_tx",
++                                  "rx_src",
++                                  "tx_src";
++                    resets = <&qca8k_nsscc NSS_CC_MAC1_SRDS1_CH0_XGMII_TX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC1_SRDS1_CH0_XGMII_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC1_SRDS1_CH0_TX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC1_SRDS1_CH0_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC1_GEPHY0_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC1_GEPHY0_TX_ARES>;
++                    reset-names = "xgmii_rx",
++                                  "xgmii_tx",
++                                  "xpcs_rx",
++                                  "xpcs_tx",
++                                  "port_rx",
++                                  "port_tx";
++                };
++
++                channel at 1 {
++                    reg = <1>;
++                    clocks = <&qca8k_nsscc NSS_CC_MAC2_SRDS1_CH1_XGMII_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC2_SRDS1_CH1_XGMII_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC2_SRDS1_CH1_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC2_SRDS1_CH1_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC2_GEPHY1_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC2_GEPHY1_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC2_RX_CLK_SRC>,
++                             <&qca8k_nsscc NSS_CC_MAC2_TX_CLK_SRC>;
++                    clock-names = "xgmii_rx",
++                                  "xgmii_tx",
++                                  "xpcs_rx",
++                                  "xpcs_tx",
++                                  "port_rx",
++                                  "port_tx",
++                                  "rx_src",
++                                  "tx_src";
++                    resets = <&qca8k_nsscc NSS_CC_MAC2_SRDS1_CH1_XGMII_TX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC2_SRDS1_CH1_XGMII_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC2_SRDS1_CH1_TX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC2_SRDS1_CH1_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC2_GEPHY1_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC2_GEPHY1_TX_ARES>;
++                    reset-names = "xgmii_rx",
++                                  "xgmii_tx",
++                                  "xpcs_rx",
++                                  "xpcs_tx",
++                                  "port_rx",
++                                  "port_tx";
++                };
++
++                channel at 2 {
++                    reg = <2>;
++                    clocks = <&qca8k_nsscc NSS_CC_MAC3_SRDS1_CH2_XGMII_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC3_SRDS1_CH2_XGMII_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC3_SRDS1_CH2_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC3_SRDS1_CH2_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC3_GEPHY2_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC3_GEPHY2_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC3_RX_CLK_SRC>,
++                             <&qca8k_nsscc NSS_CC_MAC3_TX_CLK_SRC>;
++                    clock-names = "xgmii_rx",
++                                  "xgmii_tx",
++                                  "xpcs_rx",
++                                  "xpcs_tx",
++                                  "port_rx",
++                                  "port_tx",
++                                  "rx_src",
++                                  "tx_src";
++                    resets = <&qca8k_nsscc NSS_CC_MAC3_SRDS1_CH2_XGMII_TX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC3_SRDS1_CH2_XGMII_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC3_SRDS1_CH2_TX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC3_SRDS1_CH2_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC3_GEPHY2_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC3_GEPHY2_TX_ARES>;
++                    reset-names = "xgmii_rx",
++                                  "xgmii_tx",
++                                  "xpcs_rx",
++                                  "xpcs_tx",
++                                  "port_rx",
++                                  "port_tx";
++                };
++
++                channel at 3 {
++                    reg = <3>;
++                    clocks = <&qca8k_nsscc NSS_CC_MAC4_SRDS1_CH3_XGMII_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC4_SRDS1_CH3_XGMII_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC4_SRDS1_CH3_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC4_SRDS1_CH3_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC4_GEPHY3_RX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC4_GEPHY3_TX_CLK>,
++                             <&qca8k_nsscc NSS_CC_MAC4_RX_CLK_SRC>,
++                             <&qca8k_nsscc NSS_CC_MAC4_TX_CLK_SRC>;
++                    clock-names = "xgmii_rx",
++                                  "xgmii_tx",
++                                  "xpcs_rx",
++                                  "xpcs_tx",
++                                  "port_rx",
++                                  "port_tx",
++                                  "rx_src",
++                                  "tx_src";
++                    resets = <&qca8k_nsscc NSS_CC_MAC4_SRDS1_CH3_XGMII_TX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC4_SRDS1_CH3_XGMII_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC4_SRDS1_CH3_TX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC4_SRDS1_CH3_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC4_GEPHY3_RX_ARES>,
++                             <&qca8k_nsscc NSS_CC_MAC4_GEPHY3_TX_ARES>;
++                    reset-names = "xgmii_rx",
++                                  "xgmii_tx",
++                                  "xpcs_rx",
++                                  "xpcs_tx",
++                                  "port_rx",
++                                  "port_tx";
++                };
 +            };
 +        };
 +    };
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
index edfe8d1404..360517f9b5 100644
--- 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
@@ -1,4 +1,4 @@
-From 816bff9bcd2ff7c1e84dd14fc81c9c1bdaa609e7 Mon Sep 17 00:00:00 2001
+From 60c44842f9611be237ab3f68afe8ebf2d9595fb2 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
@@ -20,9 +20,11 @@ with QCA8081.
 
 Change-Id: I12555fa70662682474ab4432204405b5e752fef6
 Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+Alex G: Update to match the patches that will be upstream.
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
 ---
- drivers/net/phy/qcom/qca808x.c | 62 ++++++++++++++++++++++++++++++++--
- 1 file changed, 60 insertions(+), 2 deletions(-)
+ drivers/net/phy/qcom/qca808x.c | 65 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 63 insertions(+), 2 deletions(-)
 
 --- a/drivers/net/phy/qcom/qca808x.c
 +++ b/drivers/net/phy/qcom/qca808x.c
@@ -44,7 +46,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  MODULE_LICENSE("GPL");
  
  struct qca808x_priv {
-@@ -153,7 +160,9 @@ static bool qca808x_is_prefer_master(str
+@@ -153,13 +160,18 @@ static bool qca808x_is_prefer_master(str
  
  static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)
  {
@@ -55,7 +57,16 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  }
  
  static bool qca808x_is_1g_only(struct phy_device *phydev)
-@@ -273,6 +282,23 @@ static int qca808x_read_status(struct ph
+ {
+ 	int ret;
+ 
++	if (!phydev_id_compare(phydev, QCA8081_PHY_ID))
++		return false;
++
+ 	ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
+ 	if (ret < 0)
+ 		return true;
+@@ -273,6 +285,23 @@ static int qca808x_read_status(struct ph
  		return ret;
  
  	if (phydev->link) {
@@ -79,7 +90,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  		if (phydev->speed == SPEED_2500)
  			phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
  		else
-@@ -352,6 +378,18 @@ static int qca808x_cable_test_start(stru
+@@ -352,6 +381,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);
  
@@ -98,7 +109,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  	return 0;
  }
  
-@@ -651,12 +689,32 @@ static struct phy_driver qca808x_driver[
+@@ -651,12 +692,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,
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
index 196160188b..8ac94c84c7 100644
--- 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
@@ -1,4 +1,4 @@
-From 5a57611512593212b7fd9c23b4d96486bab6dee3 Mon Sep 17 00:00:00 2001
+From c052b9a4ab869cc54976402b3f9dbdef5bdb9f27 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
@@ -40,7 +40,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  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
+@@ -663,6 +672,34 @@ static int qca808x_led_polarity_set(stru
  			      active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
  }
  
@@ -75,7 +75,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  static struct phy_driver qca808x_driver[] = {
  {
  	/* Qualcomm QCA8081 */
-@@ -708,6 +745,7 @@ static struct phy_driver qca808x_driver[
+@@ -711,6 +748,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,
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
index 429b5c0535..e00a582831 100644
--- 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
@@ -1,4 +1,4 @@
-From d1f2a1810af1833196934977f57607432fda46b4 Mon Sep 17 00:00:00 2001
+From aec49c172cd9c739c1d97ff2d42b9718bb20b609 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
@@ -30,7 +30,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  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
+@@ -700,6 +708,49 @@ static int qca8084_config_init(struct ph
  			     QCA8084_MSE_THRESHOLD_2P5G_VAL);
  }
  
@@ -80,7 +80,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  static struct phy_driver qca808x_driver[] = {
  {
  	/* Qualcomm QCA8081 */
-@@ -746,6 +797,7 @@ static struct phy_driver qca808x_driver[
+@@ -749,6 +800,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,
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
index 899352a116..c1673ae645 100644
--- 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
@@ -1,4 +1,4 @@
-From c17f19be3bec0bf5467f4e14a21573836910f671 Mon Sep 17 00:00:00 2001
+From cea8043def0c0867370c2efd5a1cd73bf4d3e5ba 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
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
index b8c5e9ee91..e74fc0b09f 100644
--- 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
@@ -1,4 +1,4 @@
-From 485f973c5b1d889bd1f48a188137d80d45004991 Mon Sep 17 00:00:00 2001
+From a7fe2c13f3188bf01b60fb15063d028c76dd2f1a 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
@@ -13,22 +13,45 @@ accessed, and the features of PHY can be acquired.
 
 Change-Id: I2251b9c5c398a21a4ef547a727189a934ad3a44c
 Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+Alex G: include <linux/reset.h>
+        include "phylib.h" for phy_package_*() declarations
+        select PHY_PACKAGE in Kconfig
+        use phy_package_get_node() instead of phylib->shared->np
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+freckup c89414adf2ec7c
+
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
 ---
- drivers/net/phy/qcom/qca808x.c | 91 ++++++++++++++++++++++++++++++++++
- 1 file changed, 91 insertions(+)
+ drivers/net/phy/qcom/Kconfig   |  1 +
+ drivers/net/phy/qcom/qca808x.c | 92 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 93 insertions(+)
 
+--- a/drivers/net/phy/qcom/Kconfig
++++ b/drivers/net/phy/qcom/Kconfig
+@@ -18,6 +18,7 @@ config QCA83XX_PHY
+ config QCA808X_PHY
+ 	tristate "Qualcomm QCA808x PHYs"
+ 	select QCOM_NET_PHYLIB
++	select PHY_PACKAGE
+ 	help
+ 	  Currently supports the QCA8081 model
+ 
 --- a/drivers/net/phy/qcom/qca808x.c
 +++ b/drivers/net/phy/qcom/qca808x.c
-@@ -2,6 +2,8 @@
+@@ -2,7 +2,11 @@
  
  #include <linux/phy.h>
  #include <linux/module.h>
 +#include <linux/of.h>
++#include <linux/reset.h>
 +#include <linux/clk.h>
  
++#include "../phylib.h"
  #include "qcom.h"
  
-@@ -127,6 +129,21 @@
+ /* ADC threshold */
+@@ -127,6 +131,21 @@
  #define QCA8084_MII_SW_ADDR_MASK		GENMASK(31, 24)
  #define QCA8084_MII_REG_DATA_UPPER_16_BITS	BIT(1)
  
@@ -50,21 +73,20 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  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
+@@ -839,6 +858,78 @@ 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;
++	struct device_node *np = phy_package_get_node(phydev);
 +	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",
++	ret = of_property_read_u32_array(np, "qcom,phy-addr-fixup",
 +					 addr, ARRAY_SIZE(addr));
 +	if (ret && ret != -EINVAL)
 +		return ret;
@@ -130,7 +152,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  static struct phy_driver qca808x_driver[] = {
  {
  	/* Qualcomm QCA8081 */
-@@ -886,6 +976,7 @@ static struct phy_driver qca808x_driver[
+@@ -889,6 +980,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,
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
index b41e725d30..50346520b3 100644
--- 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
@@ -1,4 +1,4 @@
-From 685566f8b765f522b7f4d4deb06bf84a557dc4ac Mon Sep 17 00:00:00 2001
+From 57379fe257895b374d35ce6578ecd62ce1cc1a4d 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
@@ -12,21 +12,16 @@ the PHY registers.
 
 Change-Id: I254d0aa0a1155d3618c6f1fc7d7a5b6ecadccbaa
 Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+Alex G: Use accessors for struct phy_package_shared
+        Update to match the patches that will be upstream.
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
 ---
- drivers/net/phy/qcom/qca808x.c | 67 ++++++++++++++++++++++++++++++++--
- 1 file changed, 64 insertions(+), 3 deletions(-)
+ drivers/net/phy/qcom/qca808x.c | 74 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 71 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
+@@ -150,10 +150,39 @@ MODULE_DESCRIPTION("Qualcomm Atheros QCA
  MODULE_AUTHOR("Matus Ujhelyi, Luo Jie");
  MODULE_LICENSE("GPL");
  
@@ -38,6 +33,8 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +	TLMM_AHB_CLK,
 +	CNOC_AHB_CLK,
 +	MDIO_AHB_CLK,
++	MDIO_MASTER_AHB_CLK,
++	SWITCH_CORE_CLK,
 +	PACKAGE_CLK_MAX
 +};
 +
@@ -57,12 +54,14 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +	[TLMM_AHB_CLK] =	"tlmm_ahb",
 +	[CNOC_AHB_CLK] =	"cnoc_ahb",
 +	[MDIO_AHB_CLK] =	"mdio_ahb",
++	[MDIO_MASTER_AHB_CLK] =	"mdio_master_ahb",
++	[SWITCH_CORE_CLK] =	"switch_core",
 +};
 +
  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
+@@ -858,11 +887,24 @@ static void qca8084_link_change_notify(s
  			       QCA8084_IPG_10_TO_11_EN : 0);
  }
  
@@ -79,7 +78,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  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;
+ 	struct device_node *np = phy_package_get_node(phydev);
 -	int ret, clear, set;
 +	struct qca808x_shared_priv *shared_priv;
 +	struct reset_control *rstc;
@@ -88,7 +87,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  
  	/* 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
+@@ -893,17 +935,43 @@ 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]);
  
@@ -97,18 +96,22 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +	if (ret)
 +		return ret;
 +
-+	shared_priv = shared->priv;
++	shared_priv = phy_package_get_priv(phydev);
 +	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]);
++		clk = of_clk_get_by_name(np, qca8084_package_clk_name[i]);
++		if (IS_ERR(clk)) {
++			if (PTR_ERR(clk) == -EINVAL)
++				clk = NULL;
++			else
++				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);
++	rstc = of_reset_control_get_exclusive(np, NULL);
 +	if (IS_ERR(rstc))
 +		return dev_err_probe(&phydev->mdio.dev, PTR_ERR(rstc),
 +				     "package reset not ready\n");
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
index bb5d0728e4..5af66c290f 100644
--- 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
@@ -1,4 +1,4 @@
-From bf779b10b00fd79267d0ef625ae246df59ee23bd Mon Sep 17 00:00:00 2001
+From d39dc53424bcc778f1e468015490577e7bf0c7b6 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
@@ -10,9 +10,12 @@ The PHY package level clocks are enabled and their rates configured.
 
 Change-Id: I63d4b22d2a70ee713cc6a6818b0f3c7aa098a5f5
 Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+Alex G: Use phy_package_get_*() accessors
+        Update to match the patches that will be upstream.
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
 ---
- drivers/net/phy/qcom/qca808x.c | 115 +++++++++++++++++++++++++++++++++
- 1 file changed, 115 insertions(+)
+ drivers/net/phy/qcom/qca808x.c | 118 +++++++++++++++++++++++++++++++++
+ 1 file changed, 118 insertions(+)
 
 --- a/drivers/net/phy/qcom/qca808x.c
 +++ b/drivers/net/phy/qcom/qca808x.c
@@ -23,21 +26,20 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  #include <linux/phy.h>
  #include <linux/module.h>
  #include <linux/of.h>
-@@ -145,6 +146,13 @@
+@@ -146,6 +147,12 @@
  #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 {
+@@ -168,6 +175,7 @@ struct qca808x_priv {
  };
  
  struct qca808x_shared_priv {
@@ -45,7 +47,7 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  	struct clk *clk[PACKAGE_CLK_MAX];
  };
  
-@@ -808,10 +817,107 @@ static int qca808x_led_polarity_set(stru
+@@ -816,10 +824,111 @@ static int qca808x_led_polarity_set(stru
  			      active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
  }
  
@@ -60,6 +62,10 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +	if (ret)
 +		return ret;
 +
++	ret = clk_prepare_enable(shared_priv->clk[SWITCH_CORE_CLK]);
++	if (ret)
++		return ret;
++
 +	ret = clk_prepare_enable(shared_priv->clk[APB_BRIDGE_CLK]);
 +	if (ret)
 +		return ret;
@@ -91,16 +97,19 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +	if (ret)
 +		return ret;
 +
++	ret = clk_prepare_enable(shared_priv->clk[MDIO_MASTER_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;
++	shared_priv = phy_package_get_priv(phydev);
 +	switch (shared_priv->package_mode) {
 +	case QCA808X_PCS1_10G_QXGMII_PCS0_UNUNSED:
 +		mode = QCA8084_WORK_MODE_QXGMII;
@@ -123,13 +132,6 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +	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);
@@ -137,7 +139,11 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
 +		return ret;
 +
 +	usleep_range(10000, 11000);
-+	return ret;
++
++	/* Initialize the PHY package clock and reset, which is the
++	 * necessary config sequence after GPIO reset on the PHY package.
++	 */
++	return qca8084_package_clock_init(shared_priv);
 +}
 +
  static int qca8084_config_init(struct phy_device *phydev)
@@ -153,19 +159,19 @@ Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
  	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");
+@@ -954,6 +1063,15 @@ static int qca8084_phy_package_probe_onc
+ 		shared_priv->clk[i] = clk;
+ 	}
  
 +	/* 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",
++	ret = of_property_read_u32(np, "qcom,package-mode",
 +				   &shared_priv->package_mode);
 +	if (ret && ret != -EINVAL)
 +		return ret;
 +
- 	/* Deassert PHY package. */
- 	return reset_control_deassert(rstc);
- }
+ 	rstc = of_reset_control_get_exclusive(np, NULL);
+ 	if (IS_ERR(rstc))
+ 		return dev_err_probe(&phydev->mdio.dev, PTR_ERR(rstc),
diff --git a/target/linux/qualcommbe/patches-6.12/0370-net-phy-Add-phy_package_remove_once-helper.patch b/target/linux/qualcommbe/patches-6.12/0370-net-phy-Add-phy_package_remove_once-helper.patch
new file mode 100644
index 0000000000..e46c6042ae
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0370-net-phy-Add-phy_package_remove_once-helper.patch
@@ -0,0 +1,36 @@
+From d11eba3e178a9d42a579c656b2c9b643f4ce3e1e Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Mon, 23 Sep 2024 18:46:34 +0800
+Subject: [PATCH] net: phy: Add phy_package_remove_once helper
+
+QCA8084 PHY package needs to do the PHY package clean up,
+add phy_package_remove_once helper to support.
+
+Change-Id: I3cd73bc7be1b1d531435ef72f48db0682548decf
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ include/linux/phy.h | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -366,6 +366,7 @@ struct phy_package_shared {
+ /* used as bit number in atomic bitops */
+ #define PHY_SHARED_F_INIT_DONE  0
+ #define PHY_SHARED_F_PROBE_DONE 1
++#define PHY_SHARED_F_REMOVE_DONE 2
+ 
+ /**
+  * struct mii_bus - Represents an MDIO bus
+@@ -2245,6 +2246,11 @@ static inline bool phy_package_probe_onc
+ 	return __phy_package_set_once(phydev, PHY_SHARED_F_PROBE_DONE);
+ }
+ 
++static inline bool phy_package_remove_once(struct phy_device *phydev)
++{
++	return __phy_package_set_once(phydev, PHY_SHARED_F_REMOVE_DONE);
++}
++
+ extern const struct bus_type mdio_bus_type;
+ 
+ struct mdio_board_info {
diff --git a/target/linux/qualcommbe/patches-6.12/0371-net-phy-qca808x-Add-QCA8084-SerDes-probe-and-remove-.patch b/target/linux/qualcommbe/patches-6.12/0371-net-phy-qca808x-Add-QCA8084-SerDes-probe-and-remove-.patch
new file mode 100644
index 0000000000..a0c84bddeb
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0371-net-phy-qca808x-Add-QCA8084-SerDes-probe-and-remove-.patch
@@ -0,0 +1,437 @@
+From c12b79af730116936504afe97234f9afb6ac8fc0 Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Mon, 23 Sep 2024 20:28:24 +0800
+Subject: [PATCH] net: phy: qca808x: Add QCA8084 SerDes probe and remove
+ functions
+
+QCA8084 PHY package integrates the XPCS and PCS, which is used
+to support 10G-QXGMII. XPCS includes 4 channels to connect with
+Quad PHY, and PCS controls the interface mode configured.
+
+XPCS and PCS are probed and removed by PHY package.
+
+Change-Id: Ided0a5cd4c996dc2a2a0d0598e930fab060caaf8
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+Alex G: Use phy_package_get_*() accessors
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+---
+ drivers/net/phy/qcom/Makefile         |   2 +-
+ drivers/net/phy/qcom/qca8084_serdes.c | 249 ++++++++++++++++++++++++++
+ drivers/net/phy/qcom/qca8084_serdes.h |  18 ++
+ drivers/net/phy/qcom/qca808x.c        |  53 ++++++
+ 4 files changed, 321 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/phy/qcom/qca8084_serdes.c
+ create mode 100644 drivers/net/phy/qcom/qca8084_serdes.h
+
+--- a/drivers/net/phy/qcom/Makefile
++++ b/drivers/net/phy/qcom/Makefile
+@@ -2,5 +2,5 @@
+ obj-$(CONFIG_QCOM_NET_PHYLIB)	+= qcom-phy-lib.o
+ obj-$(CONFIG_AT803X_PHY)	+= at803x.o
+ obj-$(CONFIG_QCA83XX_PHY)	+= qca83xx.o
+-obj-$(CONFIG_QCA808X_PHY)	+= qca808x.o
++obj-$(CONFIG_QCA808X_PHY)	+= qca808x.o qca8084_serdes.o
+ obj-$(CONFIG_QCA807X_PHY)	+= qca807x.o
+--- /dev/null
++++ b/drivers/net/phy/qcom/qca8084_serdes.c
+@@ -0,0 +1,249 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
++ */
++
++#include <linux/clk.h>
++#include <linux/dev_printk.h>
++#include <linux/mdio.h>
++#include <linux/of.h>
++#include <linux/phy.h>
++#include <linux/property.h>
++#include <linux/reset.h>
++
++#include "qca8084_serdes.h"
++
++/* XPCS includes 4 channels, each channel has the different MMD ID for
++ * configuring auto-negotiation complete interrupt, mii-4bit, auto-
++ * negotiation capabilities and TX configuration for the connected PHY.
++ *
++ * MMD31 is for channel 0;
++ * MMD26 is for channel 1;
++ * MMD27 is for channel 2;
++ * MMD28 is for channel 3;
++ */
++#define QCA8084_CHANNEL_MAX			4
++
++enum pcs_clk_id {
++	PCS_CLK,
++	PCS_RX_ROOT_CLK,
++	PCS_TX_ROOT_CLK,
++	PCS_CLK_MAX
++};
++
++enum xpcs_clk_id {
++	XPCS_XGMII_RX_CLK,
++	XPCS_XGMII_TX_CLK,
++	XPCS_RX_CLK,
++	XPCS_TX_CLK,
++	XPCS_PORT_RX_CLK,
++	XPCS_PORT_TX_CLK,
++	XPCS_RX_SRC_CLK,
++	XPCS_TX_SRC_CLK,
++	XPCS_CLK_MAX
++};
++
++struct qca8084_xpcs_channel_priv {
++	int ch_id;
++	struct reset_control *rstcs;
++	struct clk *clks[XPCS_CLK_MAX];
++};
++
++struct qca8084_pcs_data {
++	struct reset_control *rstc;
++	struct clk *clks[PCS_CLK_MAX];
++};
++
++struct qca8084_xpcs_data {
++	struct reset_control *rstc;
++	struct qca8084_xpcs_channel_priv xpcs_ch[QCA8084_CHANNEL_MAX];
++};
++
++static const char *const xpcs_clock_names[XPCS_CLK_MAX] = {
++	[XPCS_XGMII_RX_CLK] =	"xgmii_rx",
++	[XPCS_XGMII_TX_CLK] =	"xgmii_tx",
++	[XPCS_RX_CLK] =		"xpcs_rx",
++	[XPCS_TX_CLK] =		"xpcs_tx",
++	[XPCS_PORT_RX_CLK] =	"port_rx",
++	[XPCS_PORT_TX_CLK] =	"port_tx",
++	[XPCS_RX_SRC_CLK] =	"rx_src",
++	[XPCS_TX_SRC_CLK] =	"tx_src",
++};
++
++static const char *const pcs_clock_names[PCS_CLK_MAX] = {
++	[PCS_CLK] =		"pcs",
++	[PCS_RX_ROOT_CLK] =	"pcs_rx_root",
++	[PCS_TX_ROOT_CLK] =	"pcs_tx_root",
++};
++
++struct mdio_device *qca8084_package_pcs_probe(struct device_node *pcs_np)
++{
++	struct qca8084_pcs_data *pcs_data;
++	struct mdio_device *mdiodev;
++	struct reset_control *rstc;
++	struct device *dev;
++	struct clk *clk;
++	int i;
++
++	mdiodev = fwnode_mdio_find_device(of_fwnode_handle(pcs_np));
++	if (!mdiodev)
++		return ERR_PTR(-EPROBE_DEFER);
++
++	dev = &mdiodev->dev;
++	pcs_data = devm_kzalloc(dev, sizeof(*pcs_data), GFP_KERNEL);
++	if (!pcs_data) {
++		dev_err(dev, "Allocate PCS data failed\n");
++		return ERR_PTR(-ENOMEM);
++	}
++
++	rstc = devm_reset_control_get_exclusive(dev, NULL);
++	if (IS_ERR(rstc)) {
++		dev_err(dev, "Get PCS reset failed\n");
++		return ERR_CAST(rstc);
++	}
++
++	pcs_data->rstc = rstc;
++
++	for (i = 0; i < ARRAY_SIZE(pcs_clock_names); i++) {
++		clk = devm_clk_get(dev, pcs_clock_names[i]);
++		if (IS_ERR(clk)) {
++			dev_err(dev, "Failed to get the PCS clock ID %s\n",
++				pcs_clock_names[i]);
++			return ERR_CAST(clk);
++		}
++		pcs_data->clks[i] = clk;
++	}
++
++	mdiodev_set_drvdata(mdiodev, pcs_data);
++
++	return mdiodev;
++}
++
++struct mdio_device *qca8084_package_xpcs_probe(struct device_node *xpcs_np)
++{
++	struct qca8084_xpcs_data *xpcs_data;
++	struct mdio_device *mdiodev;
++	struct reset_control *rstc;
++	struct device_node *child;
++	struct device *dev;
++	struct clk *clk;
++	int i, j, node;
++
++	mdiodev = fwnode_mdio_find_device(of_fwnode_handle(xpcs_np));
++	if (!mdiodev)
++		return ERR_PTR(-EPROBE_DEFER);
++
++	dev = &mdiodev->dev;
++
++	xpcs_data = devm_kzalloc(dev, sizeof(*xpcs_data), GFP_KERNEL);
++	if (!xpcs_data) {
++		dev_err(dev, "Allocate XPCS data failed\n");
++		return ERR_PTR(-ENOMEM);
++	}
++
++	rstc = devm_reset_control_get_exclusive(dev, NULL);
++	if (IS_ERR(rstc)) {
++		dev_err(dev, "Get XPCS reset failed\n");
++		return ERR_CAST(rstc);
++	}
++
++	xpcs_data->rstc = rstc;
++
++	/* Sanity check the number of channel sub nodes */
++	node = of_get_available_child_count(xpcs_np);
++	if (node != QCA8084_CHANNEL_MAX)
++		return ERR_PTR(-EINVAL);
++
++	node = 0;
++	for_each_available_child_of_node(xpcs_np, child) {
++		struct qca8084_xpcs_channel_priv *ch_data;
++		u32 channel;
++
++		/* The subnode name must be 'channel'. */
++		if (!(of_node_name_eq(child, "channel")))
++			continue;
++
++		if (of_property_read_u32(child, "reg", &channel)) {
++			dev_err(dev, "%s: Failed to get reg\n",
++				child->full_name);
++
++			mdiodev = ERR_PTR(-EINVAL);
++			goto put_ch_clk_rst;
++		}
++
++		if (channel >= QCA8084_CHANNEL_MAX) {
++			dev_err(dev, "%s: Invalid reg %d\n",
++				child->full_name, channel);
++
++			mdiodev = ERR_PTR(-EINVAL);
++			goto put_ch_clk_rst;
++		}
++
++		ch_data = &xpcs_data->xpcs_ch[node];
++		ch_data->ch_id = channel;
++
++		ch_data->rstcs = of_reset_control_array_get_exclusive(child);
++		if (IS_ERR(ch_data->rstcs)) {
++			dev_err(dev, "%s: Failed to get reset\n",
++				child->full_name);
++
++			mdiodev = ERR_CAST(ch_data->rstcs);
++			goto put_ch_clk_rst;
++		}
++
++		for (j = 0; j < ARRAY_SIZE(xpcs_clock_names); j++) {
++			clk = of_clk_get_by_name(child, xpcs_clock_names[j]);
++			if (IS_ERR(clk)) {
++				dev_err(dev, "Failed to get the clock ID %s\n",
++					xpcs_clock_names[j]);
++				mdiodev = ERR_CAST(clk);
++				goto put_ch_child;
++			}
++			ch_data->clks[j] = clk;
++		}
++
++		node++;
++	}
++
++	mdiodev_set_drvdata(mdiodev, xpcs_data);
++
++	return mdiodev;
++
++put_ch_child:
++	node++;
++
++put_ch_clk_rst:
++	for (i = 0; i < node; i++) {
++		j--;
++		while (j >= 0) {
++			clk_put(xpcs_data->xpcs_ch[i].clks[j]);
++			j--;
++		}
++
++		j = ARRAY_SIZE(xpcs_clock_names);
++	}
++
++	for (i = 0; i < node; i++)
++		reset_control_put(xpcs_data->xpcs_ch[i].rstcs);
++
++	of_node_put(child);
++
++	return mdiodev;
++}
++
++void qca8084_package_xpcs_and_pcs_remove(struct mdio_device *xpcs_mdiodev,
++					 struct mdio_device *pcs_mdiodev)
++{
++	struct qca8084_xpcs_data *xpcs_data = mdiodev_get_drvdata(xpcs_mdiodev);
++	int i, j;
++
++	for (i = 0; i < ARRAY_SIZE(xpcs_data->xpcs_ch); i++) {
++		reset_control_put(xpcs_data->xpcs_ch[i].rstcs);
++
++		for (j = 0; j < ARRAY_SIZE(xpcs_data->xpcs_ch[i].clks); j++)
++			clk_put(xpcs_data->xpcs_ch[i].clks[j]);
++	}
++
++	mdio_device_put(xpcs_mdiodev);
++	mdio_device_put(pcs_mdiodev);
++}
+--- /dev/null
++++ b/drivers/net/phy/qcom/qca8084_serdes.h
+@@ -0,0 +1,18 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Driver for QCA8084 SerDes
++ *
++ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ */
++
++#ifndef _QCA8084_SERDES_H_
++#define _QCA8084_SERDES_H_
++
++#include <linux/mdio.h>
++#include <linux/of.h>
++
++struct mdio_device *qca8084_package_pcs_probe(struct device_node *pcs_np);
++struct mdio_device *qca8084_package_xpcs_probe(struct device_node *xpcs_np);
++void qca8084_package_xpcs_and_pcs_remove(struct mdio_device *xpcs_mdiodev,
++					 struct mdio_device *pcs_mdiodev);
++#endif /* _QCA8084_SERDES_H_ */
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -8,6 +8,7 @@
+ #include <linux/clk.h>
+ 
+ #include "../phylib.h"
++#include "qca8084_serdes.h"
+ #include "qcom.h"
+ 
+ /* ADC threshold */
+@@ -172,11 +173,13 @@ enum {
+ 
+ struct qca808x_priv {
+ 	int led_polarity_mode;
++	int channel_id;
+ };
+ 
+ struct qca808x_shared_priv {
+ 	int package_mode;
+ 	struct clk *clk[PACKAGE_CLK_MAX];
++	struct mdio_device *mdiodev[2];	/* PCS and XPCS mdio device */
+ };
+ 
+ static const char *const qca8084_package_clk_name[PACKAGE_CLK_MAX] = {
+@@ -354,6 +357,8 @@ static int qca808x_probe(struct phy_devi
+ {
+ 	struct device *dev = &phydev->mdio.dev;
+ 	struct qca808x_priv *priv;
++	u32 ch_id = 0;
++	int ret;
+ 
+ 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ 	if (!priv)
+@@ -362,6 +367,14 @@ static int qca808x_probe(struct phy_devi
+ 	/* Init LED polarity mode to -1 */
+ 	priv->led_polarity_mode = -1;
+ 
++	/* DT property qcom,xpcs-channel" is optional and only available for
++	 * 10G-QXGMII mode.
++	 */
++	ret = of_property_read_u32(dev->of_node, "qcom,xpcs-channel", &ch_id);
++	if (ret && ret != -EINVAL)
++		return ret;
++
++	priv->channel_id = ch_id;
+ 	phydev->priv = priv;
+ 
+ 	return 0;
+@@ -1012,6 +1025,7 @@ static int qca8084_phy_package_probe_onc
+ 	struct device_node *np = phy_package_get_node(phydev);
+ 	struct qca808x_shared_priv *shared_priv;
+ 	struct reset_control *rstc;
++	struct device_node *child;
+ 	int i, ret, clear, set;
+ 	struct clk *clk;
+ 
+@@ -1072,6 +1086,26 @@ static int qca8084_phy_package_probe_onc
+ 	if (ret && ret != -EINVAL)
+ 		return ret;
+ 
++	for_each_available_child_of_node(np, child) {
++		struct mdio_device *mdiodev;
++
++		if (of_node_name_eq(child, "pcs-phy")) {
++			mdiodev = qca8084_package_pcs_probe(child);
++			if (IS_ERR(mdiodev))
++				return PTR_ERR(mdiodev);
++
++			shared_priv->mdiodev[0] = mdiodev;
++		}
++
++		if (of_node_name_eq(child, "xpcs-phy")) {
++			mdiodev = qca8084_package_xpcs_probe(child);
++			if (IS_ERR(mdiodev))
++				return PTR_ERR(mdiodev);
++
++			shared_priv->mdiodev[1] = mdiodev;
++		}
++	}
++
+ 	rstc = of_reset_control_get_exclusive(np, NULL);
+ 	if (IS_ERR(rstc))
+ 		return dev_err_probe(&phydev->mdio.dev, PTR_ERR(rstc),
+@@ -1081,6 +1115,14 @@ static int qca8084_phy_package_probe_onc
+ 	return reset_control_deassert(rstc);
+ }
+ 
++static void qca8084_phy_package_remove_once(struct phy_device *phydev)
++{
++	struct qca808x_shared_priv *shared_priv = phy_package_get_priv(phydev);;
++
++	qca8084_package_xpcs_and_pcs_remove(shared_priv->mdiodev[1],
++					    shared_priv->mdiodev[0]);
++}
++
+ static int qca8084_probe(struct phy_device *phydev)
+ {
+ 	struct qca808x_shared_priv *shared_priv;
+@@ -1099,6 +1141,10 @@ static int qca8084_probe(struct phy_devi
+ 			return ret;
+ 	}
+ 
++	ret = qca808x_probe(phydev);
++	if (ret)
++		return ret;
++
+ 	/* Enable clock of PHY device, so that the PHY register
+ 	 * can be accessed to get PHY features.
+ 	 */
+@@ -1116,6 +1162,12 @@ static int qca8084_probe(struct phy_devi
+ 	return reset_control_deassert(rstc);
+ }
+ 
++static void qca8084_remove(struct phy_device *phydev)
++{
++	if (phy_package_remove_once(phydev))
++		qca8084_phy_package_remove_once(phydev);
++}
++
+ static struct phy_driver qca808x_driver[] = {
+ {
+ 	/* Qualcomm QCA8081 */
+@@ -1167,6 +1219,7 @@ static struct phy_driver qca808x_driver[
+ 	.config_init		= qca8084_config_init,
+ 	.link_change_notify	= qca8084_link_change_notify,
+ 	.probe			= qca8084_probe,
++	.remove			= qca8084_remove,
+ }, };
+ 
+ module_phy_driver(qca808x_driver);
diff --git a/target/linux/qualcommbe/patches-6.12/0372-net-phy-qca808x-Add-QCA8084-SerDes-init-function.patch b/target/linux/qualcommbe/patches-6.12/0372-net-phy-qca808x-Add-QCA8084-SerDes-init-function.patch
new file mode 100644
index 0000000000..688d7ac474
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0372-net-phy-qca808x-Add-QCA8084-SerDes-init-function.patch
@@ -0,0 +1,446 @@
+From d137b725f8f4a7d49a809dcd73c5b836495ec44d Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Mon, 23 Sep 2024 20:59:40 +0800
+Subject: [PATCH] net: phy: qca808x: Add QCA8084 SerDes init function
+
+When QCA8084 works on 10G-QXGMII, the XPCS and PCS need to be
+configured in the PHY package init function.
+
+Change-Id: Iac48c44f0e80adf055fa9c2095e99a04ba24c4bb
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+---
+ drivers/net/phy/qcom/qca8084_serdes.c | 374 ++++++++++++++++++++++++++
+ drivers/net/phy/qcom/qca8084_serdes.h |   2 +
+ drivers/net/phy/qcom/qca808x.c        |  11 +
+ 3 files changed, 387 insertions(+)
+
+--- a/drivers/net/phy/qcom/qca8084_serdes.c
++++ b/drivers/net/phy/qcom/qca8084_serdes.c
+@@ -24,6 +24,92 @@
+  */
+ #define QCA8084_CHANNEL_MAX			4
+ 
++/* MII registers */
++#define PLL_POWER_ON_AND_RESET			0x0
++#define PCS_ANA_SW_RESET			BIT(6)
++
++#define PLL_CONTROL				6
++#define PLL_CONTROL_CMLDIV2_IBSEL_MASK		GENMASK(5, 4)
++
++/* MMD_PMAPMD registers */
++#define CDR_CONTRL				0x20
++#define SSC_FIX_MODE				BIT(3)
++
++#define CALIBRATION4				0x78
++#define CALIBRATION_DONE			BIT(7)
++
++#define MODE_CONTROL				0x11b
++#define MODE_CONTROL_SEL_MASK			GENMASK(12, 8)
++#define MODE_CONTROL_XPCS			0x10
++#define MODE_CONTROL_SGMII_PLUS			0x8
++#define MODE_CONTROL_SGMII			0x4
++#define MODE_CONTROL_SGMII_SEL_MASK		GENMASK(6, 4)
++#define MODE_CONTROL_SGMII_PHY			1
++#define MODE_CONTROL_SGMII_MAC			2
++
++#define QP_USXG_OPTION1				0x180
++#define QP_USXG_OPTION1_DATAPASS		BIT(0)
++#define QP_USXG_OPTION1_DATAPASS_SGMII		0
++#define QP_USXG_OPTION1_DATAPASS_USXGMII	1
++
++#define BYPASS_TUNNING_IPG			0x189
++#define BYPASS_TUNNING_IPG_MASK			GENMASK(11, 0)
++
++/* MDIO_MMD_PCS register */
++#define PCS_CONTROL2				0x7
++#define PCS_TYPE_MASK				GENMASK(3, 0)
++#define PCS_TYPE_BASER				0
++
++#define PCS_EEE_CONTROL				0x14
++#define EEE_CAPABILITY				BIT(6)
++
++#define PCS_STATUS1				0x20
++#define PCS_BASER_UP				BIT(12)
++
++#define DIG_CTRL1				0x8000
++#define DIG_CTRL1_USXGMII_EN			BIT(9)
++#define DIG_CTRL1_XPCS_RESET			BIT(15)
++#define FIFO_RESET_CH0				BIT(10)
++#define FIFO_RESET_CH1_CH2_CH3			BIT(5)
++
++#define EEE_MODE_CONTROL			0x8006
++#define EEE_LCT_RES				GENMASK(11, 8)
++#define EEE_SIGN				BIT(6)
++#define EEE_LRX_EN				BIT(1)
++#define EEE_LTX_EN				BIT(0)
++
++#define PCS_TPC					0x8007
++#define PCS_QXGMII_MODE_MASK			GENMASK(12, 10)
++#define PCS_QXGMII_EN				0x5
++
++#define EEE_RX_TIMER				0x8009
++#define EEE_RX_TIMER_100US_RES			GENMASK(7, 0)
++#define EEE_RX_TIMER_RWR_RES			GENMASK(12, 8)
++
++#define AM_LINK_TIMER				0x800a
++#define AM_LINK_TIMER_VAL			0x6018
++
++#define EEE_MODE_CONTROL1			0x800b
++#define TRANS_LPI_MODE				BIT(0)
++#define TRANS_RX_LPI_MODE			BIT(8)
++
++/* QXGMII channel MMD register */
++#define MII_CONTROL				0x0
++#define AUTO_NEGOTIATION_EN			BIT(12)
++#define AUTO_NEGOTIATION_RESTART		BIT(9)
++#define PCS_SPEED_2500				BIT(5)
++#define PCS_SPEED_1000				BIT(6)
++#define PCS_SPEED_100				BIT(13)
++#define PCS_SPEED_10				0
++
++#define DIG_CONTROL2				0x8001
++#define MII_BIT_CONTROL				BIT(8)
++#define TX_CONFIG				BIT(3)
++#define AUTO_NEGOTIATION_CMPLT_INTR		BIT(0)
++
++#define XAUI_CONTROL				0x8004
++#define TX_IPG_CHECK_DISABLE			BIT(0)
++
+ enum pcs_clk_id {
+ 	PCS_CLK,
+ 	PCS_RX_ROOT_CLK,
+@@ -76,6 +162,8 @@ static const char *const pcs_clock_names
+ 	[PCS_TX_ROOT_CLK] =	"pcs_tx_root",
+ };
+ 
++static const int qca8084_xpcs_ch_mmd[QCA8084_CHANNEL_MAX] = { 31, 26, 27, 28 };
++
+ struct mdio_device *qca8084_package_pcs_probe(struct device_node *pcs_np)
+ {
+ 	struct qca8084_pcs_data *pcs_data;
+@@ -247,3 +335,289 @@ void qca8084_package_xpcs_and_pcs_remove
+ 	mdio_device_put(xpcs_mdiodev);
+ 	mdio_device_put(pcs_mdiodev);
+ }
++
++static int qca8084_pcs_set_interface_mode(struct mdio_device *mdio_dev,
++					  phy_interface_t ifmode)
++{
++	int ret, hw_ifmode, data;
++
++	switch (ifmode) {
++	case PHY_INTERFACE_MODE_SGMII:
++		hw_ifmode = MODE_CONTROL_SGMII;
++		data = QP_USXG_OPTION1_DATAPASS_SGMII;
++		break;
++	case PHY_INTERFACE_MODE_2500BASEX:
++		hw_ifmode = MODE_CONTROL_SGMII_PLUS;
++		data = QP_USXG_OPTION1_DATAPASS_SGMII;
++		break;
++	case PHY_INTERFACE_MODE_10G_QXGMII:
++		hw_ifmode = MODE_CONTROL_XPCS;
++		data = QP_USXG_OPTION1_DATAPASS_USXGMII;
++		break;
++	default:
++		return -EOPNOTSUPP;
++	}
++
++	/* For PLL stable under high temperature */
++	ret = mdiodev_modify(mdio_dev, PLL_CONTROL,
++			     PLL_CONTROL_CMLDIV2_IBSEL_MASK,
++			     FIELD_PREP(PLL_CONTROL_CMLDIV2_IBSEL_MASK, 3));
++	if (ret)
++		return ret;
++
++	/* Configure the interface mode of PCS */
++	ret = mdiodev_c45_modify(mdio_dev, MDIO_MMD_PMAPMD, MODE_CONTROL,
++				 MODE_CONTROL_SEL_MASK,
++				 FIELD_PREP(MODE_CONTROL_SEL_MASK, hw_ifmode));
++	if (ret)
++		return ret;
++
++	/* Data pass selects SGMII or USXGMII */
++	return mdiodev_c45_modify(mdio_dev, MDIO_MMD_PMAPMD, QP_USXG_OPTION1,
++				  QP_USXG_OPTION1_DATAPASS,
++				  FIELD_PREP(QP_USXG_OPTION1_DATAPASS, data));
++}
++
++static int qca8084_do_calibration(struct mdio_device *mdio_dev)
++{
++	int ret;
++
++	ret = mdiodev_modify(mdio_dev, PLL_POWER_ON_AND_RESET,
++			     PCS_ANA_SW_RESET, 0);
++	if (ret)
++		return ret;
++
++	usleep_range(10000, 11000);
++	ret = mdiodev_modify(mdio_dev, PLL_POWER_ON_AND_RESET,
++			     PCS_ANA_SW_RESET, PCS_ANA_SW_RESET);
++	if (ret)
++		return ret;
++
++	/* Wait calibration done */
++	return read_poll_timeout(mdiodev_c45_read, ret,
++				 (ret & CALIBRATION_DONE),
++				 100, 100000, true, mdio_dev,
++				 MDIO_MMD_PMAPMD, CALIBRATION4);
++}
++
++
++static int qca8084_xpcs_set_mode(struct mdio_device *xpcs_mdiodev)
++{
++	int ret, val, i;
++
++	/* Configure BaseR mode */
++	ret = mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS, PCS_CONTROL2,
++				 PCS_TYPE_MASK,
++				 FIELD_PREP(PCS_TYPE_MASK, PCS_TYPE_BASER));
++	if (ret)
++		return ret;
++
++	/* Wait BaseR link up */
++	ret = read_poll_timeout(mdiodev_c45_read, val,
++				(val & PCS_BASER_UP), 1000, 100000, true,
++				xpcs_mdiodev,
++				MDIO_MMD_PCS, PCS_STATUS1);
++	if (ret) {
++		dev_err(&xpcs_mdiodev->dev, "BaseR link failed!\n");
++		return ret;
++	}
++
++	/* Enable USXGMII mode */
++	ret = mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS, DIG_CTRL1,
++				 DIG_CTRL1_USXGMII_EN,
++				 DIG_CTRL1_USXGMII_EN);
++	if (ret)
++		return ret;
++
++	/* Configure QXGMII mode */
++	ret = mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS, PCS_TPC,
++				 PCS_QXGMII_MODE_MASK,
++				 FIELD_PREP(PCS_QXGMII_MODE_MASK,
++					    PCS_QXGMII_EN));
++	if (ret)
++		return ret;
++
++	/* Configure AM interval */
++	ret = mdiodev_c45_write(xpcs_mdiodev, MDIO_MMD_PCS, AM_LINK_TIMER,
++				AM_LINK_TIMER_VAL);
++	if (ret)
++		return ret;
++
++	/* Reset XPCS */
++	ret = mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS, DIG_CTRL1,
++				 DIG_CTRL1_XPCS_RESET,
++				 DIG_CTRL1_XPCS_RESET);
++	if (ret)
++		return ret;
++
++	/* Wait XPCS reset done */
++	ret = read_poll_timeout(mdiodev_c45_read, val,
++				!(val & DIG_CTRL1_XPCS_RESET),
++				1000, 100000, true, xpcs_mdiodev,
++				MDIO_MMD_PCS, DIG_CTRL1);
++	if (ret) {
++		dev_err(&xpcs_mdiodev->dev, "XPCS reset failed!\n");
++		return ret;
++	}
++
++	/* Enable auto-negotiation complete interrupt, using mii-4bit
++	 * and TX configureation of PHY side on all XPCS channels.
++	 */
++	for (i = 0; i < QCA8084_CHANNEL_MAX; i++) {
++		ret = mdiodev_c45_modify(xpcs_mdiodev, qca8084_xpcs_ch_mmd[i],
++					 DIG_CONTROL2,
++					 (MII_BIT_CONTROL | TX_CONFIG |
++					 AUTO_NEGOTIATION_CMPLT_INTR),
++					 (TX_CONFIG | AUTO_NEGOTIATION_CMPLT_INTR));
++		if (ret)
++			return ret;
++
++		/* Enable auto-negotiation capability */
++		ret = mdiodev_c45_modify(xpcs_mdiodev, qca8084_xpcs_ch_mmd[i],
++					 MII_CONTROL,
++					 AUTO_NEGOTIATION_EN,
++					 AUTO_NEGOTIATION_EN);
++		if (ret)
++			return ret;
++
++		/* Disable TX IPG check */
++		ret = mdiodev_c45_modify(xpcs_mdiodev, qca8084_xpcs_ch_mmd[i],
++					 XAUI_CONTROL,
++					 TX_IPG_CHECK_DISABLE,
++					 TX_IPG_CHECK_DISABLE);
++		if (ret)
++			return ret;
++	}
++
++	/* Check EEE capability supported or not */
++	ret = mdiodev_c45_read(xpcs_mdiodev, MDIO_MMD_PCS, PCS_EEE_CONTROL);
++	if (ret < 0)
++		return ret;
++
++	if (ret & EEE_CAPABILITY) {
++		ret = mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS,
++					 EEE_MODE_CONTROL,
++					 EEE_LCT_RES | EEE_SIGN,
++					 FIELD_PREP(EEE_LCT_RES, 1) | EEE_SIGN);
++		if (ret)
++			return ret;
++
++		ret = mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS,
++					 EEE_RX_TIMER,
++					 EEE_RX_TIMER_100US_RES | EEE_RX_TIMER_RWR_RES,
++					 FIELD_PREP(EEE_RX_TIMER_100US_RES, 0xc8) |
++					 FIELD_PREP(EEE_RX_TIMER_RWR_RES, 0x1c));
++		if (ret)
++			return ret;
++
++		/* Enable EEE LPI */
++		ret = mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS,
++					 EEE_MODE_CONTROL1,
++					 TRANS_LPI_MODE | TRANS_RX_LPI_MODE,
++					 TRANS_LPI_MODE | TRANS_RX_LPI_MODE);
++		if (ret)
++			return ret;
++
++		/* Enable TX/RX LPI pattern */
++		ret = mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS,
++					 EEE_MODE_CONTROL,
++					 EEE_LRX_EN | EEE_LTX_EN,
++					 EEE_LRX_EN | EEE_LTX_EN);
++	}
++
++	return ret;
++}
++
++static int qca8084_pcs_set_mode(struct mdio_device *xpcs_mdiodev,
++				       struct mdio_device *pcs_mdiodev)
++{
++	struct qca8084_xpcs_data *xpcs_data = mdiodev_get_drvdata(xpcs_mdiodev);
++	struct qca8084_pcs_data *pcs_data = mdiodev_get_drvdata(pcs_mdiodev);
++	struct qca8084_xpcs_channel_priv xpcs_ch;
++	int ret, channel;
++
++	/* Enable clock and de-assert for PCS. */
++	ret = clk_prepare_enable(pcs_data->clks[PCS_CLK]);
++	if (ret)
++		return ret;
++
++	ret = reset_control_deassert(pcs_data->rstc);
++	if (ret)
++		return ret;
++
++	/* IPG tunning selection for RX, TX and XGMII of all channels. */
++	ret = mdiodev_c45_modify(pcs_mdiodev, MDIO_MMD_PMAPMD,
++				 BYPASS_TUNNING_IPG,
++				 BYPASS_TUNNING_IPG_MASK, 0);
++	if (ret)
++		return ret;
++
++	reset_control_assert(xpcs_data->rstc);
++
++	ret = qca8084_pcs_set_interface_mode(pcs_mdiodev,
++					     PHY_INTERFACE_MODE_10G_QXGMII);
++	if (ret)
++		return ret;
++
++	/* Reset of 4 channels */
++	for (channel = 0; channel < QCA8084_CHANNEL_MAX; channel++) {
++		xpcs_ch = xpcs_data->xpcs_ch[channel];
++		ret = reset_control_reset(xpcs_ch.rstcs);
++		if (ret)
++			return ret;
++	}
++
++	ret = qca8084_do_calibration(pcs_mdiodev);
++	if (ret) {
++		dev_err(&pcs_mdiodev->dev, "PCS calibration timeout!\n");
++		return ret;
++	}
++
++	/* Enable PCS SSC to fix mode */
++	ret = mdiodev_c45_modify(pcs_mdiodev, MDIO_MMD_PMAPMD,
++				 CDR_CONTRL, SSC_FIX_MODE, SSC_FIX_MODE);
++	if (ret)
++		return ret;
++
++	return reset_control_deassert(xpcs_data->rstc);
++}
++
++static int qca8084_xpcs_clock_parent_set(struct mdio_device *xpcs_mdiodev,
++					 struct mdio_device *pcs_mdiodev)
++{
++	struct qca8084_xpcs_data *xpcs_data = mdiodev_get_drvdata(xpcs_mdiodev);
++	struct qca8084_pcs_data *pcs_data = mdiodev_get_drvdata(pcs_mdiodev);
++	struct qca8084_xpcs_channel_priv xpcs_ch;
++	int ret, channel;
++
++	for (channel = 0; channel < QCA8084_CHANNEL_MAX; channel++) {
++		xpcs_ch = xpcs_data->xpcs_ch[channel];
++		ret = clk_set_parent(xpcs_ch.clks[XPCS_RX_SRC_CLK],
++				     pcs_data->clks[PCS_RX_ROOT_CLK]);
++		if (ret)
++			return ret;
++
++		ret = clk_set_parent(xpcs_ch.clks[XPCS_TX_SRC_CLK],
++				     pcs_data->clks[PCS_TX_ROOT_CLK]);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++int qca8084_qxgmii_set_mode(struct mdio_device *xpcs_mdiodev,
++			    struct mdio_device *pcs_mdiodev)
++{
++	int ret;
++
++	ret = qca8084_xpcs_clock_parent_set(xpcs_mdiodev, pcs_mdiodev);
++	if (ret)
++		return ret;
++
++	ret = qca8084_pcs_set_mode(xpcs_mdiodev, pcs_mdiodev);
++	if (ret)
++		return ret;
++
++	return qca8084_xpcs_set_mode(xpcs_mdiodev);
++}
+--- a/drivers/net/phy/qcom/qca8084_serdes.h
++++ b/drivers/net/phy/qcom/qca8084_serdes.h
+@@ -15,4 +15,6 @@ struct mdio_device *qca8084_package_pcs_
+ struct mdio_device *qca8084_package_xpcs_probe(struct device_node *xpcs_np);
+ void qca8084_package_xpcs_and_pcs_remove(struct mdio_device *xpcs_mdiodev,
+ 					 struct mdio_device *pcs_mdiodev);
++int qca8084_qxgmii_set_mode(struct mdio_device *xpcs_mdiodev,
++			    struct mdio_device *pcs_mdiodev);
+ #endif /* _QCA8084_SERDES_H_ */
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -926,6 +926,14 @@ static int qca8084_phy_package_config_in
+ 
+ 	usleep_range(10000, 11000);
+ 
++	/* Configure PCS working on 10G-QXGMII mode */
++	if (phydev->interface == PHY_INTERFACE_MODE_10G_QXGMII) {
++		ret = qca8084_qxgmii_set_mode(shared_priv->mdiodev[1],
++					      shared_priv->mdiodev[0]);
++		if (ret)
++			return ret;
++	}
++
+ 	/* Initialize the PHY package clock and reset, which is the
+ 	 * necessary config sequence after GPIO reset on the PHY package.
+ 	 */
+@@ -1164,6 +1172,9 @@ static int qca8084_probe(struct phy_devi
+ 
+ static void qca8084_remove(struct phy_device *phydev)
+ {
++	if (phydev->interface != PHY_INTERFACE_MODE_10G_QXGMII)
++		return;
++
+ 	if (phy_package_remove_once(phydev))
+ 		qca8084_phy_package_remove_once(phydev);
+ }
diff --git a/target/linux/qualcommbe/patches-6.12/0373-net-phy-qca808x-Add-QCA8084-SerDes-speed-config.patch b/target/linux/qualcommbe/patches-6.12/0373-net-phy-qca808x-Add-QCA8084-SerDes-speed-config.patch
new file mode 100644
index 0000000000..1244837fd5
--- /dev/null
+++ b/target/linux/qualcommbe/patches-6.12/0373-net-phy-qca808x-Add-QCA8084-SerDes-speed-config.patch
@@ -0,0 +1,251 @@
+From 2f5b7e167d847a5b5b74a91f991d48635453c55f Mon Sep 17 00:00:00 2001
+From: Luo Jie <quic_luoj at quicinc.com>
+Date: Mon, 23 Sep 2024 21:24:56 +0800
+Subject: [PATCH] net: phy: qca808x: Add QCA8084 SerDes speed config
+
+When the link of PHY is changed, the XPCS channel needs to be
+configured to adapt the current link status.
+
+Change-Id: I50d8973691dff133fc6bec1e9a1043bb646811fc
+Signed-off-by: Luo Jie <quic_luoj at quicinc.com>
+Alex G: Use phy_package_get_*() accessors
+Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+---
+ drivers/net/phy/qcom/qca8084_serdes.c | 159 ++++++++++++++++++++++++++
+ drivers/net/phy/qcom/qca8084_serdes.h |   3 +
+ drivers/net/phy/qcom/qca808x.c        |  15 ++-
+ 3 files changed, 175 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/qcom/qca8084_serdes.c
++++ b/drivers/net/phy/qcom/qca8084_serdes.c
+@@ -4,6 +4,7 @@
+  */
+ 
+ #include <linux/clk.h>
++#include <linux/clk-provider.h>
+ #include <linux/dev_printk.h>
+ #include <linux/mdio.h>
+ #include <linux/of.h>
+@@ -55,6 +56,13 @@
+ #define BYPASS_TUNNING_IPG			0x189
+ #define BYPASS_TUNNING_IPG_MASK			GENMASK(11, 0)
+ 
++#define QP_USXG_RESET				0x18c
++#define QP_USXG_SGMII_FUNC_RESET		BIT(4)
++#define QP_USXG_P3_FUNC_RESET			BIT(3)
++#define QP_USXG_P2_FUNC_RESET			BIT(2)
++#define QP_USXG_P1_FUNC_RESET			BIT(1)
++#define QP_USXG_P0_FUNC_RESET			BIT(0)
++
+ /* MDIO_MMD_PCS register */
+ #define PCS_CONTROL2				0x7
+ #define PCS_TYPE_MASK				GENMASK(3, 0)
+@@ -107,6 +115,9 @@
+ #define TX_CONFIG				BIT(3)
+ #define AUTO_NEGOTIATION_CMPLT_INTR		BIT(0)
+ 
++#define PCS_ERR_SEL				0x8002
++#define PCS_AN_COMPLETE				BIT(0)
++
+ #define XAUI_CONTROL				0x8004
+ #define TX_IPG_CHECK_DISABLE			BIT(0)
+ 
+@@ -621,3 +632,151 @@ int qca8084_qxgmii_set_mode(struct mdio_
+ 
+ 	return qca8084_xpcs_set_mode(xpcs_mdiodev);
+ }
++
++static int qca8084_pcs_ipg_tune_reset(struct mdio_device *mdio_dev,
++				      int reset_function)
++{
++	int ret;
++
++	ret = mdiodev_c45_modify(mdio_dev, MDIO_MMD_PMAPMD, QP_USXG_RESET,
++				 reset_function, 0);
++	if (ret)
++		return ret;
++
++	usleep_range(1000, 1100);
++
++	return mdiodev_c45_modify(mdio_dev, MDIO_MMD_PMAPMD, QP_USXG_RESET,
++				  reset_function, reset_function);
++}
++
++static int qca8084_xpcs_an_restart(struct mdio_device *xpcs_mdiodev,
++				   int channel)
++{
++	int ret, mmd;
++
++	mmd = qca8084_xpcs_ch_mmd[channel];
++
++	/* Restart auto-negotiation */
++	ret = mdiodev_c45_modify(xpcs_mdiodev, mmd, MII_CONTROL,
++				 AUTO_NEGOTIATION_RESTART,
++				 AUTO_NEGOTIATION_RESTART);
++	if (ret)
++		return ret;
++
++	usleep_range(1000, 1100);
++
++	/* Clear pcs auto-negotiation complete interrupt */
++	return mdiodev_c45_modify(xpcs_mdiodev, mmd, PCS_ERR_SEL,
++				  PCS_AN_COMPLETE, 0);
++}
++
++void qca8084_qxgmii_set_speed(struct mdio_device *xpcs_mdiodev,
++			      struct mdio_device *pcs_mdiodev,
++			      int channel, int speed)
++{
++	struct qca8084_xpcs_data *xpcs_data = mdiodev_get_drvdata(xpcs_mdiodev);
++	struct qca8084_xpcs_channel_priv *xpcs_ch;
++	int mmd, i, ret, xpcs_rate;
++	unsigned long rate;
++
++	for (i = 0; i < QCA8084_CHANNEL_MAX; i++) {
++		xpcs_ch = &(xpcs_data->xpcs_ch[channel]);
++		if (channel == xpcs_ch->ch_id)
++			break;
++	}
++
++	if (i == QCA8084_CHANNEL_MAX) {
++		dev_err(&xpcs_mdiodev->dev, "Invalid channel %d\n", channel);
++		return;
++	}
++
++	mmd = qca8084_xpcs_ch_mmd[channel];
++
++	ret = qca8084_xpcs_an_restart(xpcs_mdiodev, channel);
++	if (ret)
++		return;
++
++	switch (speed) {
++	case SPEED_2500:
++		rate = 312500000;
++		xpcs_rate = PCS_SPEED_2500;
++		break;
++	case SPEED_1000:
++		rate = 125000000;
++		xpcs_rate = PCS_SPEED_1000;
++		break;
++	case SPEED_100:
++		rate = 25000000;
++		xpcs_rate = PCS_SPEED_100;
++		break;
++	case SPEED_10:
++	default:
++		rate = 2500000;
++		xpcs_rate = PCS_SPEED_10;
++		break;
++	}
++
++	clk_set_rate(xpcs_ch->clks[XPCS_RX_CLK], rate);
++	clk_set_rate(xpcs_ch->clks[XPCS_TX_CLK], rate);
++
++	/* XGMII takes the different clock rate 78.125Mhz from XPCS clock
++	 * when linked at 2500M.
++	 */
++	if (speed == SPEED_2500)
++		rate = 78125000;
++
++	clk_set_rate(xpcs_ch->clks[XPCS_XGMII_RX_CLK], rate);
++	clk_set_rate(xpcs_ch->clks[XPCS_XGMII_TX_CLK], rate);
++
++	ret = mdiodev_c45_modify(xpcs_mdiodev, mmd, MII_CONTROL,
++				 PCS_SPEED_2500 | PCS_SPEED_1000 |
++				 PCS_SPEED_100 | PCS_SPEED_10,
++				 xpcs_rate);
++	if (ret)
++		return;
++
++	/* Disable clocks if link down with unknown speed. The channel clocks
++	 * are disabled by default, __clk_is_enabled() is used to avoid
++	 * disabling the clocks that is already in the disabled status.
++	 */
++	if (speed == SPEED_UNKNOWN) {
++		if (__clk_is_enabled(xpcs_ch->clks[XPCS_RX_CLK]))
++			clk_disable_unprepare(xpcs_ch->clks[XPCS_RX_CLK]);
++		if (__clk_is_enabled(xpcs_ch->clks[XPCS_TX_CLK]))
++			clk_disable_unprepare(xpcs_ch->clks[XPCS_TX_CLK]);
++		if (__clk_is_enabled(xpcs_ch->clks[XPCS_PORT_RX_CLK]))
++			clk_disable_unprepare(xpcs_ch->clks[XPCS_PORT_RX_CLK]);
++		if (__clk_is_enabled(xpcs_ch->clks[XPCS_PORT_TX_CLK]))
++			clk_disable_unprepare(xpcs_ch->clks[XPCS_PORT_TX_CLK]);
++		if (__clk_is_enabled(xpcs_ch->clks[XPCS_XGMII_RX_CLK]))
++			clk_disable_unprepare(xpcs_ch->clks[XPCS_XGMII_RX_CLK]);
++		if (__clk_is_enabled(xpcs_ch->clks[XPCS_XGMII_TX_CLK]))
++			clk_disable_unprepare(xpcs_ch->clks[XPCS_XGMII_TX_CLK]);
++	} else {
++		clk_prepare_enable(xpcs_ch->clks[XPCS_RX_CLK]);
++		clk_prepare_enable(xpcs_ch->clks[XPCS_TX_CLK]);
++		clk_prepare_enable(xpcs_ch->clks[XPCS_PORT_RX_CLK]);
++		clk_prepare_enable(xpcs_ch->clks[XPCS_PORT_TX_CLK]);
++		clk_prepare_enable(xpcs_ch->clks[XPCS_XGMII_RX_CLK]);
++		clk_prepare_enable(xpcs_ch->clks[XPCS_XGMII_TX_CLK]);
++	}
++
++	msleep(100);
++
++	ret = reset_control_reset(xpcs_ch->rstcs);
++	if (ret)
++		return;
++
++	/* Reset IPG tune of PCS device. */
++	ret = qca8084_pcs_ipg_tune_reset(pcs_mdiodev, BIT(channel));
++	if (ret)
++		return;
++
++	if (channel == 0)
++		mdiodev_c45_modify(xpcs_mdiodev, MDIO_MMD_PCS, DIG_CTRL1,
++				   FIFO_RESET_CH0, FIFO_RESET_CH0);
++	else
++		mdiodev_c45_modify(xpcs_mdiodev, mmd, DIG_CTRL1,
++				   FIFO_RESET_CH1_CH2_CH3,
++				   FIFO_RESET_CH1_CH2_CH3);
++}
+--- a/drivers/net/phy/qcom/qca8084_serdes.h
++++ b/drivers/net/phy/qcom/qca8084_serdes.h
+@@ -17,4 +17,7 @@ void qca8084_package_xpcs_and_pcs_remove
+ 					 struct mdio_device *pcs_mdiodev);
+ int qca8084_qxgmii_set_mode(struct mdio_device *xpcs_mdiodev,
+ 			    struct mdio_device *pcs_mdiodev);
++void qca8084_qxgmii_set_speed(struct mdio_device *xpcs_mdiodev,
++			      struct mdio_device *pcs_mdiodev,
++			      int channel, int speed);
+ #endif /* _QCA8084_SERDES_H_ */
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -976,6 +976,7 @@ static int qca8084_config_init(struct ph
+ 
+ static void qca8084_link_change_notify(struct phy_device *phydev)
+ {
++	struct qca808x_shared_priv *shared_priv;
+ 	int ret;
+ 
+ 	/* Assert the FIFO between PHY and MAC. */
+@@ -1007,14 +1008,24 @@ static void qca8084_link_change_notify(s
+ 		}
+ 	}
+ 
+-	/* Enable IPG level 10 to 11 tuning for link speed 1000M in the
++	/* Enable IPG level 10 to 11 tuning for link speed 1000M and
++	 * configure the related XPCS channel with the phydev in the
+ 	 * 10G_QXGMII mode.
+ 	 */
+-	if (phydev->interface == PHY_INTERFACE_MODE_10G_QXGMII)
++	if (phydev->interface == PHY_INTERFACE_MODE_10G_QXGMII) {
++		shared_priv = phy_package_get_priv(phydev);
++		struct qca808x_priv *priv = phydev->priv;
++
+ 		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);
++
++		qca8084_qxgmii_set_speed(shared_priv->mdiodev[1],
++					 shared_priv->mdiodev[0],
++					 priv->channel_id,
++					 phydev->speed);
++	}
+ }
+ 
+ /* QCA8084 is a four-port PHY, which integrates the clock controller,




More information about the lede-commits mailing list