kernel: Bump to 6.5.11 + kkit-linux-6.5.y

6.5.11: Pull latest fixes from stable tree

kkit-linux-6.5.y: LED support for 88X3310 PHY and 88E6393X switch.
This commit is contained in:
Tobias Waldekranz
2023-11-19 08:50:19 +01:00
committed by Joachim Wiberg
parent 55afbb2a94
commit febb998702
19 changed files with 1526 additions and 58 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.6"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
+1 -1
View File
@@ -24,7 +24,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.6"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
+1 -1
View File
@@ -21,7 +21,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INF
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.6"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
+1 -1
View File
@@ -23,7 +23,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INF
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.6"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
@@ -1,8 +1,8 @@
From 99e3fc4a7c6d31f5d0fdc7bb5c409c776c19012c Mon Sep 17 00:00:00 2001
From e1011848d2c9476e20e6a4053b8ab46ce2a1506f Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 5 Oct 2023 16:09:25 +0200
Subject: [PATCH 1/9] eth: fwnode: Fall back to NVMEM provided MAC address from
OF
Subject: [PATCH 01/15] eth: fwnode: Fall back to NVMEM provided MAC address
from OF
In the cases where the fwnode is an OF node, make use of any NVMEM
source of the interface's MAC address that might have been specified
@@ -1,7 +1,7 @@
From 5ddc784a4c8803aff2c3fa3c6595e9d32933d4aa Mon Sep 17 00:00:00 2001
From 1d6f30fce9f4516730439f72ee2134301d37654d Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 5 Sep 2023 13:08:29 +0200
Subject: [PATCH 2/9] net: dsa: mv88e6xxx: Create API to read a single stat
Subject: [PATCH 02/15] net: dsa: mv88e6xxx: Create API to read a single stat
counter
This change contains no functional change. We simply push the hardware
@@ -18,7 +18,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
2 files changed, 105 insertions(+), 82 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 7af2f08a62f1..1e944cf08233 100644
index 0d4b236d1e34..139f4d55a284 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1082,7 +1082,7 @@ static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
@@ -163,7 +163,7 @@ index 7af2f08a62f1..1e944cf08233 100644
mv88e6xxx_reg_lock(chip);
if (chip->info->ops->serdes_get_stats) {
@@ -4196,7 +4218,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
@@ -4198,7 +4220,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -172,7 +172,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4234,7 +4256,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -4236,7 +4258,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -181,7 +181,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
.serdes_power = mv88e6185_serdes_power,
.serdes_get_lane = mv88e6185_serdes_get_lane,
@@ -4277,7 +4299,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
@@ -4279,7 +4301,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -190,7 +190,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4323,7 +4345,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -4325,7 +4347,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -199,7 +199,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4366,7 +4388,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -4368,7 +4390,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -208,7 +208,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4415,7 +4437,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
@@ -4417,7 +4439,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -217,7 +217,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4477,7 +4499,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -4479,7 +4501,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -226,7 +226,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4515,7 +4537,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -4517,7 +4539,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -235,7 +235,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4563,7 +4585,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -4565,7 +4587,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -244,7 +244,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4612,7 +4634,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -4614,7 +4636,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -253,7 +253,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4668,7 +4690,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -4670,7 +4692,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -262,7 +262,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4717,7 +4739,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -4719,7 +4741,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -271,7 +271,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4769,7 +4791,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -4771,7 +4793,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -280,7 +280,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4820,7 +4842,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
@@ -4822,7 +4844,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -289,7 +289,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4885,7 +4907,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -4887,7 +4909,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -298,7 +298,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4948,7 +4970,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -4950,7 +4972,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -307,7 +307,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5014,7 +5036,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -5016,7 +5038,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -316,7 +316,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5074,7 +5096,7 @@ static const struct mv88e6xxx_ops mv88e6250_ops = {
@@ -5076,7 +5098,7 @@ static const struct mv88e6xxx_ops mv88e6250_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6250_stats_get_sset_count,
.stats_get_strings = mv88e6250_stats_get_strings,
@@ -325,7 +325,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6250_watchdog_ops,
@@ -5121,7 +5143,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -5123,7 +5145,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -334,7 +334,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5187,7 +5209,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -5189,7 +5211,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -343,7 +343,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5234,7 +5256,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -5236,7 +5258,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -352,7 +352,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5283,7 +5305,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
@@ -5285,7 +5307,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -361,7 +361,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5348,7 +5370,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -5350,7 +5372,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -370,7 +370,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5394,7 +5416,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -5396,7 +5418,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -379,7 +379,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5445,7 +5467,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -5447,7 +5469,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -388,7 +388,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5514,7 +5536,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -5516,7 +5538,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -397,7 +397,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5583,7 +5605,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -5585,7 +5607,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -406,7 +406,7 @@ index 7af2f08a62f1..1e944cf08233 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5652,7 +5674,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
@@ -5654,7 +5676,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -1,7 +1,7 @@
From 63c14938bdaa1891386989aa46bee4571c1c0777 Mon Sep 17 00:00:00 2001
From f960475a96d2852d06ee062c970e35074f87659c Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 5 Sep 2023 21:10:15 +0200
Subject: [PATCH 3/9] net: dsa: mv88e6xxx: Give each hw stat an ID
Subject: [PATCH 03/15] net: dsa: mv88e6xxx: Give each hw stat an ID
With the upcoming standard counter group support, we are no longer
reading out the whole set of counters, but rather mapping a subset to
@@ -17,7 +17,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
1 file changed, 78 insertions(+), 63 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 1e944cf08233..ea4fb0d3e628 100644
index 139f4d55a284..4afe5c212a36 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1019,68 +1019,83 @@ static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
@@ -1,7 +1,8 @@
From ffd5442fcbadcbd8733b9ac870d83d7561cca9fc Mon Sep 17 00:00:00 2001
From 6a612f46152d8567a16b7b15fdcc3081cbdbb3fb Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 5 Sep 2023 21:15:52 +0200
Subject: [PATCH 4/9] net: dsa: mv88e6xxx: Add "eth-mac" counter group support
Subject: [PATCH 04/15] net: dsa: mv88e6xxx: Add "eth-mac" counter group
support
After this change, mv88e6xxx ports can report the applicable subset of
their counters using ethtool's standardized "eth-mac" counter group.
@@ -12,7 +13,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
1 file changed, 52 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ea4fb0d3e628..ec3a4717bc44 100644
index 4afe5c212a36..2cfc072b41b1 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1403,6 +1403,57 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
@@ -73,7 +74,7 @@ index ea4fb0d3e628..ec3a4717bc44 100644
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
@@ -7160,6 +7211,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
@@ -7162,6 +7213,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.phylink_mac_link_up = mv88e6xxx_mac_link_up,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
@@ -1,7 +1,7 @@
From 2cfafa598282efc980baf00b312a61032b9f5aa9 Mon Sep 17 00:00:00 2001
From a85c55f3232d402780a22d42859bdc81150469b4 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 6 Sep 2023 10:55:53 +0200
Subject: [PATCH 5/9] net: dsa: mv88e6xxx: Add "rmon" counter group support
Subject: [PATCH 05/15] net: dsa: mv88e6xxx: Add "rmon" counter group support
After this change, mv88e6xxx ports can report the applicable subset of
their counters using ethtool's standardized "rmon" counter group.
@@ -12,7 +12,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
1 file changed, 56 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ec3a4717bc44..eb5990cfc7d4 100644
index 2cfc072b41b1..90dcd6c3be31 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1454,6 +1454,61 @@ static void mv88e6xxx_get_eth_mac_stats(struct dsa_switch *ds, int port,
@@ -77,7 +77,7 @@ index ec3a4717bc44..eb5990cfc7d4 100644
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
@@ -7212,6 +7267,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
@@ -7214,6 +7269,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_eth_mac_stats = mv88e6xxx_get_eth_mac_stats,
@@ -1,8 +1,8 @@
From 7abdce276172fe74e24fd30d204a75e388bbab6c Mon Sep 17 00:00:00 2001
From 6f684b1b9eb8a307b77aa4baa8531e2c423112af Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 21 Sep 2023 11:10:26 +0200
Subject: [PATCH 6/9] arm64: dts: marvell: cp11x: Provide clock names for MDIO
controllers
Subject: [PATCH 06/15] arm64: dts: marvell: cp11x: Provide clock names for
MDIO controllers
This will let the driver figure out the rate of the core clk, such
that custom MDC frequencies can be supported.
@@ -1,7 +1,7 @@
From 8dc464b6506fbc038ccdae0a88936989fdf32117 Mon Sep 17 00:00:00 2001
From d5e03e7b44c8ac414927751097d8d65caffc33b4 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 19 Sep 2023 18:19:40 +0200
Subject: [PATCH 7/9] net: mvmdio: Avoid excessive sleeps in polled mode
Subject: [PATCH 07/15] net: mvmdio: Avoid excessive sleeps in polled mode
Before this change, when operating in polled mode, i.e. no IRQ is
available, every individual C45 access would be hit with a 150us sleep
@@ -1,7 +1,7 @@
From 1956176490d4eec3a889a38626326b375782a55a Mon Sep 17 00:00:00 2001
From d389cc01295ebd7be228c8240f0061134b27f215 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 21 Sep 2023 11:12:55 +0200
Subject: [PATCH 8/9] net: mvmdio: Support setting the MDC frequency on XSMI
Subject: [PATCH 08/15] net: mvmdio: Support setting the MDC frequency on XSMI
controllers
Support the standard "clock-frequency" attribute to set the generated
@@ -1,7 +1,8 @@
From 0de9c5dfc6395eb2e3066488638ac86de58b8068 Mon Sep 17 00:00:00 2001
From 46bbea6b9d692ac7460e4e278cedee9f88b6da0b Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 19 Sep 2023 18:38:10 +0200
Subject: [PATCH 9/9] net: phy: marvell10g: Support firmware loading on 88X3310
Subject: [PATCH 09/15] net: phy: marvell10g: Support firmware loading on
88X3310
If a device is found waiting for firmware to be loaded into its RAM,
ask userspace for the binary and load it over XMDIO.
@@ -0,0 +1,63 @@
From 312d3efde0fbe7cec3bf7ba1908c213c9cf69337 Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:33 +0200
Subject: [PATCH 10/15] led: trig: netdev: Fix requesting offload device
When the netdev trigger is activates, it tries to determine what
device the LED blinks for, and what the current blink mode is.
The documentation for hw_control_get() says:
* Return 0 on success, a negative error number on failing parsing the
* initial mode. Error from this function is NOT FATAL as the device
* may be in a not supported initial state by the attached LED trigger.
*/
For the Marvell PHY and the Armada 370-rd board, the initial LED blink
mode is not supported by the trigger, so it returns an error. This
resulted in not getting the device the LED is blinking for. As a
result, the device is unknown and offloaded is never performed.
Change to condition to always get the device if offloading is
supported, and reduce the scope of testing for an error from
hw_control_get() to skip setting trigger internal state if there is an
error.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-2-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/leds/trigger/ledtrig-netdev.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 03c58e50cc44..e9e4da217249 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -564,15 +564,17 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
/* Check if hw control is active by default on the LED.
* Init already enabled mode in hw control.
*/
- if (supports_hw_control(led_cdev) &&
- !led_cdev->hw_control_get(led_cdev, &mode)) {
+ if (supports_hw_control(led_cdev)) {
dev = led_cdev->hw_control_get_device(led_cdev);
if (dev) {
const char *name = dev_name(dev);
set_device_name(trigger_data, name, strlen(name));
trigger_data->hw_control = true;
- trigger_data->mode = mode;
+
+ rc = led_cdev->hw_control_get(led_cdev, &mode);
+ if (!rc)
+ trigger_data->mode = mode;
}
}
--
2.34.1
@@ -0,0 +1,37 @@
From 83322015e7960ba0f1f3698e36333cfb6aecb931 Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:36 +0200
Subject: [PATCH 11/15] leds: trig-netdev: Disable offload on deactivation of
trigger
Ensure that the offloading of blinking is stopped when the trigger is
deactivated. Calling led_set_brightness() is documented as stopping
offload and setting the LED to a constant brightness.
Suggested-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-5-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/leds/trigger/ledtrig-netdev.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index e9e4da217249..cc3261543a5e 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -595,6 +595,8 @@ static void netdev_trig_deactivate(struct led_classdev *led_cdev)
cancel_delayed_work_sync(&trigger_data->work);
+ led_set_brightness(led_cdev, LED_OFF);
+
dev_put(trigger_data->net_dev);
kfree(trigger_data);
--
2.34.1
@@ -0,0 +1,157 @@
From a4f09c743da21f09b0fcc6e5842d665490f9f70e Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:34 +0200
Subject: [PATCH 12/15] net: phy: phy_device: Call into the PHY driver to set
LED offload
Linux LEDs can be requested to perform hardware accelerated blinking
to indicate link, RX, TX etc. Pass the rules for blinking to the PHY
driver, if it implements the ops needed to determine if a given
pattern can be offloaded, to offload it, and what the current offload
is. Additionally implement the op needed to get what device the LED is
for.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-3-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/phy/phy_device.c | 68 ++++++++++++++++++++++++++++++++++++
include/linux/phy.h | 33 +++++++++++++++++
2 files changed, 101 insertions(+)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index c7cf61fe41cf..d096d9d63617 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3020,6 +3020,61 @@ static int phy_led_blink_set(struct led_classdev *led_cdev,
return err;
}
+static __maybe_unused struct device *
+phy_led_hw_control_get_device(struct led_classdev *led_cdev)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+
+ if (phydev->attached_dev)
+ return &phydev->attached_dev->dev;
+ return NULL;
+}
+
+static int __maybe_unused
+phy_led_hw_control_get(struct led_classdev *led_cdev,
+ unsigned long *rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_get(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static int __maybe_unused
+phy_led_hw_control_set(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_set(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static __maybe_unused int phy_led_hw_is_supported(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_is_supported(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
static void phy_leds_unregister(struct phy_device *phydev)
{
struct phy_led *phyled;
@@ -3057,6 +3112,19 @@ static int of_phy_led(struct phy_device *phydev,
cdev->brightness_set_blocking = phy_led_set_brightness;
if (phydev->drv->led_blink_set)
cdev->blink_set = phy_led_blink_set;
+
+#ifdef CONFIG_LEDS_TRIGGERS
+ if (phydev->drv->led_hw_is_supported &&
+ phydev->drv->led_hw_control_set &&
+ phydev->drv->led_hw_control_get) {
+ cdev->hw_control_is_supported = phy_led_hw_is_supported;
+ cdev->hw_control_set = phy_led_hw_control_set;
+ cdev->hw_control_get = phy_led_hw_control_get;
+ cdev->hw_control_trigger = "netdev";
+ }
+
+ cdev->hw_control_get_device = phy_led_hw_control_get_device;
+#endif
cdev->max_brightness = 1;
init_data.devicename = dev_name(&phydev->mdio.dev);
init_data.fwnode = of_fwnode_handle(led);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 11c1e91563d4..0f9e4598c596 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1104,6 +1104,39 @@ struct phy_driver {
int (*led_blink_set)(struct phy_device *dev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off);
+ /**
+ * @led_hw_is_supported: Can the HW support the given rules.
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules The core is interested in these rules
+ *
+ * Return 0 if yes, -EOPNOTSUPP if not, or an error code.
+ */
+ int (*led_hw_is_supported)(struct phy_device *dev, u8 index,
+ unsigned long rules);
+ /**
+ * @led_hw_control_set: Set the HW to control the LED
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules The rules used to control the LED
+ *
+ * Returns 0, or a an error code.
+ */
+ int (*led_hw_control_set)(struct phy_device *dev, u8 index,
+ unsigned long rules);
+ /**
+ * @led_hw_control_get: Get how the HW is controlling the LED
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules Pointer to the rules used to control the LED
+ *
+ * Set *@rules to how the HW is currently blinking. Returns 0
+ * on success, or a error code if the current blinking cannot
+ * be represented in rules, or some other error happens.
+ */
+ int (*led_hw_control_get)(struct phy_device *dev, u8 index,
+ unsigned long *rules);
+
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
--
2.34.1
@@ -0,0 +1,535 @@
From 5adf394404d4c8ac25fb1e36d7d3f23b699b3104 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 15 Nov 2023 20:58:42 +0100
Subject: [PATCH 13/15] net: phy: marvell10g: Add LED support for 88X3310
Pickup the LEDs from the state in which the hardware reset or
bootloader left them, but also support further configuration via
device tree. This is primarily needed because the electrical polarity
and drive behavior is software controlled and not possible to set via
hardware strapping.
Trigger support:
- "none"
- "timer": Map 60-100 ms periods to the fast rate (81ms) and 1000-1600
ms periods to the slow rate (1300ms). Defer everything else to
software blinking
- "netdev": Offload (per-medium) link or duplex information to the
solid behavior; tx and/or rx activity to blink behavior.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/phy/marvell10g.c | 455 +++++++++++++++++++++++++++++++++++
1 file changed, 455 insertions(+)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 155f439d9c1c..05ad7c769e24 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -28,6 +28,7 @@
#include <linux/firmware.h>
#include <linux/hwmon.h>
#include <linux/marvell_phy.h>
+#include <linux/of.h>
#include <linux/phy.h>
#include <linux/sfp.h>
#include <linux/netdevice.h>
@@ -136,6 +137,14 @@ enum {
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN = 0x5,
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6,
MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII = 0x7,
+ MV_V2_LED0_CONTROL = 0xf020,
+ MV_V2_LED_CONTROL_POLARITY_MASK = 0x0003,
+ MV_V2_LED_CONTROL_POLARITY_SHIFT = 0,
+ MV_V2_LED_CONTROL_BLINK_RATE = BIT(2),
+ MV_V2_LED_CONTROL_SOLID_FUNC_MASK = 0x00f8,
+ MV_V2_LED_CONTROL_SOLID_FUNC_SHIFT = 3,
+ MV_V2_LED_CONTROL_BLINK_FUNC_MASK = 0x1f00,
+ MV_V2_LED_CONTROL_BLINK_FUNC_SHIFT = 8,
MV_V2_PORT_INTR_STS = 0xf040,
MV_V2_PORT_INTR_MASK = 0xf043,
MV_V2_PORT_INTR_STS_WOL_EN = BIT(8),
@@ -168,6 +177,16 @@ struct mv3310_chip {
#endif
};
+#define MV3310_N_LEDS 4
+
+struct mv3310_led {
+ u8 index;
+ u16 fw_ctrl;
+
+ unsigned copper:1;
+ unsigned fiber:1;
+};
+
struct mv3310_priv {
DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
@@ -178,6 +197,8 @@ struct mv3310_priv {
struct device *hwmon_dev;
char *hwmon_name;
+
+ struct mv3310_led led[MV3310_N_LEDS];
};
static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev)
@@ -185,6 +206,431 @@ static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev)
return phydev->drv->driver_data;
}
+enum mv3310_led_func {
+ MV3310_LED_FUNC_OFF = 0x00,
+ MV3310_LED_FUNC_TX_RX = 0x01,
+ MV3310_LED_FUNC_TX = 0x02,
+ MV3310_LED_FUNC_RX = 0x03,
+ MV3310_LED_FUNC_COLLISION = 0x04,
+ MV3310_LED_FUNC_LINK_COPPER = 0x05,
+ MV3310_LED_FUNC_LINK_FIBER = 0x06,
+ MV3310_LED_FUNC_LINK = 0x07,
+ MV3310_LED_FUNC_10M_LINK = 0x08,
+ MV3310_LED_FUNC_100M_LINK = 0x09,
+ MV3310_LED_FUNC_1G_LINK = 0x0a,
+ MV3310_LED_FUNC_10G_LINK = 0x0b,
+ MV3310_LED_FUNC_10M_100M_LINK = 0x0c,
+ MV3310_LED_FUNC_10M_100M_1G_LINK = 0x0d,
+ MV3310_LED_FUNC_100M_10G_LINK = 0x0e,
+ MV3310_LED_FUNC_1G_10G_LINK = 0x0f,
+ MV3310_LED_FUNC_1G_10G_SLAVE = 0x10,
+ MV3310_LED_FUNC_1G_10G_MASTER = 0x11,
+ MV3310_LED_FUNC_HALF_DUPLEX = 0x12,
+ MV3310_LED_FUNC_FULL_DUPLEX = 0x13,
+ MV3310_LED_FUNC_LINK_EEE = 0x14,
+ MV3310_LED_FUNC_2G5_LINK = 0x15,
+ MV3310_LED_FUNC_5G_LINK = 0x16,
+ MV3310_LED_FUNC_ON = 0x17,
+ MV3310_LED_FUNC_2G5_5G_SLAVE = 0x18,
+ MV3310_LED_FUNC_2G5_5G_MASTER = 0x19,
+
+ MV3310_LED_FUNC_SPEED_BLINK = 0x1f
+};
+
+static int mv3310_led_flags_from_funcs(struct mv3310_led *led,
+ enum mv3310_led_func solid,
+ enum mv3310_led_func blink,
+ unsigned long *flagsp)
+{
+ unsigned long flags = 0;
+
+ switch (solid) {
+ case MV3310_LED_FUNC_OFF:
+ break;
+ case MV3310_LED_FUNC_LINK_COPPER:
+ case MV3310_LED_FUNC_LINK_FIBER:
+ case MV3310_LED_FUNC_LINK:
+ flags |= TRIGGER_NETDEV_LINK;
+ break;
+ case MV3310_LED_FUNC_HALF_DUPLEX:
+ flags |= TRIGGER_NETDEV_HALF_DUPLEX;
+ break;
+ case MV3310_LED_FUNC_FULL_DUPLEX:
+ flags |= TRIGGER_NETDEV_FULL_DUPLEX;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (blink) {
+ case MV3310_LED_FUNC_OFF:
+ break;
+ case MV3310_LED_FUNC_TX:
+ flags |= TRIGGER_NETDEV_TX;
+ break;
+ case MV3310_LED_FUNC_RX:
+ flags |= TRIGGER_NETDEV_RX;
+ break;
+ case MV3310_LED_FUNC_TX_RX:
+ flags |= TRIGGER_NETDEV_TX | TRIGGER_NETDEV_RX;
+ break;
+ default:
+ return -EINVAL;
+
+ }
+
+ *flagsp = flags;
+ return 0;
+}
+
+static int mv3310_led_funcs_from_flags(struct mv3310_led *led,
+ unsigned long flags,
+ enum mv3310_led_func *solid,
+ enum mv3310_led_func *blink)
+{
+ unsigned long activity, duplex, link;
+
+ if (flags & ~(BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+ BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+ BIT(TRIGGER_NETDEV_TX) |
+ BIT(TRIGGER_NETDEV_RX)))
+ return -EINVAL;
+
+ link = flags & BIT(TRIGGER_NETDEV_LINK);
+
+ duplex = flags & (BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+ BIT(TRIGGER_NETDEV_FULL_DUPLEX));
+
+ activity = flags & (BIT(TRIGGER_NETDEV_TX) |
+ BIT(TRIGGER_NETDEV_RX));
+
+ if (link && duplex)
+ return -EINVAL;
+
+ if (solid) {
+ if (link) {
+ if (led->copper)
+ *solid = MV3310_LED_FUNC_LINK_COPPER;
+ else if (led->fiber)
+ *solid = MV3310_LED_FUNC_LINK_FIBER;
+ else
+ *solid = MV3310_LED_FUNC_LINK;
+ } else if (duplex) {
+ switch (duplex) {
+ case BIT(TRIGGER_NETDEV_HALF_DUPLEX):
+ *solid = MV3310_LED_FUNC_HALF_DUPLEX;
+ break;
+ case BIT(TRIGGER_NETDEV_FULL_DUPLEX):
+ *solid = MV3310_LED_FUNC_FULL_DUPLEX;
+ break;
+ default:
+ break;
+ }
+ } else {
+ *solid = MV3310_LED_FUNC_OFF;
+ }
+ }
+
+ if (blink) {
+ switch (activity) {
+ case 0:
+ *blink = MV3310_LED_FUNC_OFF;
+ break;
+ case BIT(TRIGGER_NETDEV_TX):
+ *blink = MV3310_LED_FUNC_TX;
+ break;
+ case BIT(TRIGGER_NETDEV_RX):
+ *blink = MV3310_LED_FUNC_RX;
+ break;
+ default:
+ *blink = MV3310_LED_FUNC_TX_RX;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int mv3310_led_get(struct phy_device *phydev,
+ struct mv3310_led *led,
+ enum mv3310_led_func *solid,
+ enum mv3310_led_func *blink,
+ bool *slow_blink)
+{
+ int ctrl;
+
+ ctrl = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ MV_V2_LED0_CONTROL + led->index);
+ if (ctrl < 0)
+ return ctrl;
+
+ *solid = (ctrl & MV_V2_LED_CONTROL_SOLID_FUNC_MASK) >>
+ MV_V2_LED_CONTROL_SOLID_FUNC_SHIFT;
+ *blink = (ctrl & MV_V2_LED_CONTROL_BLINK_FUNC_MASK) >>
+ MV_V2_LED_CONTROL_BLINK_FUNC_SHIFT;
+
+ *slow_blink = !!(ctrl & MV_V2_LED_CONTROL_BLINK_RATE);
+ return 0;
+}
+
+static int mv3310_led_set(struct phy_device *phydev,
+ struct mv3310_led *led,
+ enum mv3310_led_func solid,
+ enum mv3310_led_func blink,
+ bool slow_blink)
+{
+ u16 ctrl = led->fw_ctrl;
+
+ ctrl &= ~MV_V2_LED_CONTROL_SOLID_FUNC_MASK;
+ ctrl &= ~MV_V2_LED_CONTROL_BLINK_FUNC_MASK;
+ ctrl &= ~MV_V2_LED_CONTROL_BLINK_RATE;
+
+ ctrl |= solid << MV_V2_LED_CONTROL_SOLID_FUNC_SHIFT;
+ ctrl |= blink << MV_V2_LED_CONTROL_BLINK_FUNC_SHIFT;
+
+ if (slow_blink)
+ ctrl |= MV_V2_LED_CONTROL_BLINK_RATE;
+
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2,
+ MV_V2_LED0_CONTROL + led->index, ctrl);
+}
+
+
+enum mv3310_led_polarity {
+ MV3310_LED_POLARITY_ACTIVE_LOW = 0x0,
+ MV3310_LED_POLARITY_ACTIVE_HIGH = 0x1,
+ MV3310_LED_POLARITY_ACTIVE_LOW_TRISTATE = 0x2,
+ MV3310_LED_POLARITY_ACTIVE_HIGH_TRISTATE = 0x3,
+};
+
+static const char *mv3310_led_polarity_name[] = {
+ [MV3310_LED_POLARITY_ACTIVE_LOW] = "active-low",
+ [MV3310_LED_POLARITY_ACTIVE_HIGH] = "active-high",
+ [MV3310_LED_POLARITY_ACTIVE_LOW_TRISTATE] = "active-low-tristate",
+ [MV3310_LED_POLARITY_ACTIVE_HIGH_TRISTATE] = "active-high-tristate",
+};
+
+static int mv3310_led_polarity_from_str(const char *str,
+ enum mv3310_led_polarity *polarity)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mv3310_led_polarity_name); i++) {
+ if (!mv3310_led_polarity_name[i])
+ continue;
+
+ if (!strcmp(mv3310_led_polarity_name[i], str)) {
+ *polarity = i;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int mv3310_led_probe_of(struct phy_device *phydev,
+ struct device_node *np)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ enum mv3310_led_polarity polarity;
+ struct mv3310_led *led;
+ const char *str;
+ u32 index;
+ u16 ctrl;
+ int err;
+
+ err = of_property_read_u32(np, "reg", &index);
+ if (err)
+ return err;
+
+ if (index >= MV3310_N_LEDS)
+ return -EINVAL;
+
+ led = &priv->led[index];
+ ctrl = led->fw_ctrl;
+
+ err = of_property_read_string(np, "marvell,media", &str);
+ if (!err) {
+ if (!strcmp(str, "copper"))
+ led->copper = 1;
+ else if (!strcmp(str, "fiber"))
+ led->fiber = 1;
+ }
+
+ err = of_property_read_string(np, "marvell,polarity", &str);
+ err = err ? : mv3310_led_polarity_from_str(str, &polarity);
+ if (!err) {
+ ctrl &= ~MV_V2_LED_CONTROL_POLARITY_MASK;
+ ctrl |= polarity << MV_V2_LED_CONTROL_POLARITY_SHIFT;
+ }
+
+ if (ctrl != led->fw_ctrl) {
+ led->fw_ctrl = ctrl;
+
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2,
+ MV_V2_LED0_CONTROL + index, ctrl);
+ }
+
+ return 0;
+}
+
+static int mv3310_leds_probe(struct phy_device *phydev)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct device_node *pnp, *np;
+ int err, val, index;
+
+ /* Save the state config left by HW reset or bootloader, this
+ * may be further refined by configuration from DT, if
+ * available.
+ *
+ * The resulting state is used as the fallback when no trigger
+ * is active.
+ */
+ for (index = 0; index < MV3310_N_LEDS; index++) {
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ MV_V2_LED0_CONTROL + index);
+ if (val < 0)
+ return val;
+
+ priv->led[index] = (struct mv3310_led) {
+ .index = index,
+ .fw_ctrl = val,
+ };
+ }
+
+ if (!node)
+ return 0;
+
+ pnp = of_get_child_by_name(node, "leds");
+ if (!pnp)
+ return 0;
+
+ for_each_available_child_of_node(pnp, np) {
+ err = mv3310_led_probe_of(phydev, np);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int mv3310_led_brightness_set(struct phy_device *phydev,
+ u8 index, enum led_brightness value)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ enum mv3310_led_func solid;
+ struct mv3310_led *led;
+
+ if (index >= MV3310_N_LEDS)
+ return -ENODEV;
+
+ led = &priv->led[index];
+
+ if (value == LED_OFF)
+ solid = MV3310_LED_FUNC_OFF;
+ else
+ solid = MV3310_LED_FUNC_ON;
+
+ return mv3310_led_set(phydev, led, solid, MV3310_LED_FUNC_OFF, false);
+}
+
+static int mv3310_led_blink_set(struct phy_device *phydev, u8 index,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ struct mv3310_led *led;
+ bool slow_blink;
+ int err;
+
+ if (index >= MV3310_N_LEDS)
+ return -ENODEV;
+
+ led = &priv->led[index];
+
+ if (*delay_on != *delay_off)
+ /* Defer anything other than 50% duty cycles to
+ * software.
+ */
+ return -EINVAL;
+
+ /* Accept values within ~20% of our supported rates (80ms or
+ * 1300ms periods).
+ */
+ if ((*delay_on >= 30) && (*delay_on <= 50))
+ slow_blink = false;
+ else if (((*delay_on >= 500) && (*delay_on <= 800)) || (*delay_on == 0))
+ slow_blink = true;
+ else
+ return -EINVAL;
+
+ err = mv3310_led_set(phydev, led, MV3310_LED_FUNC_OFF,
+ MV3310_LED_FUNC_ON, slow_blink);
+ if (!err)
+ *delay_on = *delay_off = slow_blink ? 650 : 40;
+
+ return err;
+}
+
+static int mv3310_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long flags)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ struct mv3310_led *led;
+
+ if (index >= MV3310_N_LEDS)
+ return -ENODEV;
+
+ led = &priv->led[index];
+
+ return mv3310_led_funcs_from_flags(led, flags, NULL, NULL);
+}
+
+static int mv3310_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long flags)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ enum mv3310_led_func solid, blink;
+ struct mv3310_led *led;
+ int err;
+
+ if (index >= MV3310_N_LEDS)
+ return -ENODEV;
+
+ led = &priv->led[index];
+
+ err = mv3310_led_funcs_from_flags(led, flags, &solid, &blink);
+ if (err)
+ return err;
+
+ return mv3310_led_set(phydev, led, solid, blink, false);
+}
+
+static int mv3310_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *flags)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ enum mv3310_led_func solid, blink;
+ struct mv3310_led *led;
+ bool slow_blink;
+ int err;
+
+ if (index >= MV3310_N_LEDS)
+ return -ENODEV;
+
+ led = &priv->led[index];
+
+ err = mv3310_led_get(phydev, led, &solid, &blink, &slow_blink);
+ if (err)
+ return err;
+
+ return mv3310_led_flags_from_funcs(led, solid, blink, flags);
+}
+
+
#ifdef CONFIG_HWMON
static umode_t mv3310_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type,
@@ -697,6 +1143,10 @@ static int mv3310_probe(struct phy_device *phydev)
if (ret)
return ret;
+ ret = mv3310_leds_probe(phydev);
+ if (ret)
+ return ret;
+
chip->init_supported_interfaces(priv->supported_interfaces);
return phy_sfp_probe(phydev, &mv3310_sfp_ops);
@@ -1502,6 +1952,11 @@ static struct phy_driver mv3310_drivers[] = {
.set_loopback = genphy_c45_loopback,
.get_wol = mv3110_get_wol,
.set_wol = mv3110_set_wol,
+ .led_brightness_set = mv3310_led_brightness_set,
+ .led_blink_set = mv3310_led_blink_set,
+ .led_hw_is_supported = mv3310_led_hw_is_supported,
+ .led_hw_control_set = mv3310_led_hw_control_set,
+ .led_hw_control_get = mv3310_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88X3310,
--
2.34.1
@@ -0,0 +1,321 @@
From 913a57a304e8024f4cea872fa904cee867c469a2 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 16 Nov 2023 19:44:32 +0100
Subject: [PATCH 14/15] net: dsa: mv88e6xxx: Add LED infrastructure
Parse DT for LEDs and register them for devices that support it,
though no actual implementations exist yet.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 8 +-
drivers/net/dsa/mv88e6xxx/chip.h | 17 +++
drivers/net/dsa/mv88e6xxx/leds.c | 184 +++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/leds.h | 12 ++
5 files changed, 221 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c
create mode 100644 drivers/net/dsa/mv88e6xxx/leds.h
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index 1409e691ab77..ab07996aeb7f 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
mv88e6xxx-objs += global2_avb.o
mv88e6xxx-objs += global2_scratch.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
+mv88e6xxx-objs += leds.o
mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o
mv88e6xxx-objs += port_hidden.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 90dcd6c3be31..d343ea5cc4a1 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -37,6 +37,7 @@
#include "global1.h"
#include "global2.h"
#include "hwtstamp.h"
+#include "leds.h"
#include "phy.h"
#include "port.h"
#include "ptp.h"
@@ -4259,11 +4260,16 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
{
- return mv88e6xxx_setup_devlink_regions_port(ds, port);
+ int err = 0;
+
+ err = err ? : mv88e6xxx_setup_devlink_regions_port(ds, port);
+ err = err ? : mv88e6xxx_port_setup_leds(ds, port);
+ return err;
}
static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port)
{
+ /* LED resources are devm_ managed */
mv88e6xxx_teardown_devlink_regions_port(ds, port);
}
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 268c97cde8d8..fb0d2584af1b 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -205,6 +205,7 @@ struct mv88e6xxx_irq_ops;
struct mv88e6xxx_gpio_ops;
struct mv88e6xxx_avb_ops;
struct mv88e6xxx_ptp_ops;
+struct mv88e6xxx_led_ops;
struct mv88e6xxx_irq {
u16 masked;
@@ -329,6 +330,8 @@ struct mv88e6xxx_hw_stat {
int type;
};
+struct mv88e6xxx_led;
+
struct mv88e6xxx_chip {
const struct mv88e6xxx_info *info;
@@ -672,6 +675,9 @@ struct mv88e6xxx_ops {
/* Precision Time Protocol operations */
const struct mv88e6xxx_ptp_ops *ptp_ops;
+ /* LED operations */
+ const struct mv88e6xxx_led_ops *led_ops;
+
/* Phylink */
void (*phylink_get_caps)(struct mv88e6xxx_chip *chip, int port,
struct phylink_config *config);
@@ -748,6 +754,17 @@ struct mv88e6xxx_ptp_ops {
u32 cc_mult_dem;
};
+struct mv88e6xxx_led_ops {
+ int (*brightness_set)(struct mv88e6xxx_led *led,
+ enum led_brightness brightness);
+ int (*blink_set)(struct mv88e6xxx_led *led,
+ unsigned long *delay_on, unsigned long *delay_off);
+ int (*hw_control_is_supported)(struct mv88e6xxx_led *led,
+ unsigned long flags);
+ int (*hw_control_set)(struct mv88e6xxx_led *led, unsigned long flags);
+ int (*hw_control_get)(struct mv88e6xxx_led *led, unsigned long *flags);
+};
+
static inline bool mv88e6xxx_has_stu(struct mv88e6xxx_chip *chip)
{
return chip->info->max_sid > 0 &&
diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c
new file mode 100644
index 000000000000..42e1661e1f47
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/leds.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <net/dsa.h>
+
+#include "chip.h"
+#include "port.h"
+
+struct mv88e6xxx_led {
+ struct mv88e6xxx_chip *chip;
+ int port;
+ u8 index;
+
+ struct led_classdev ldev;
+};
+
+static int mv88e6xxx_led_brightness_set(struct led_classdev *ldev,
+ enum led_brightness brightness)
+{
+ const struct mv88e6xxx_led_ops *ops;
+ struct mv88e6xxx_led *led;
+
+ led = container_of(ldev, struct mv88e6xxx_led, ldev);
+ ops = led->chip->info->ops->led_ops;
+
+ if (!ops->brightness_set)
+ return -EOPNOTSUPP;
+
+ return ops->brightness_set(led, brightness);
+}
+
+static int mv88e6xxx_led_blink_set(struct led_classdev *ldev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ const struct mv88e6xxx_led_ops *ops;
+ struct mv88e6xxx_led *led;
+
+ led = container_of(ldev, struct mv88e6xxx_led, ldev);
+ ops = led->chip->info->ops->led_ops;
+
+ if (!ops->blink_set)
+ return -EOPNOTSUPP;
+
+ return ops->blink_set(led, delay_on, delay_off);
+}
+
+static int mv88e6xxx_led_hw_control_is_supported(struct led_classdev *ldev,
+ unsigned long flags)
+{
+ const struct mv88e6xxx_led_ops *ops;
+ struct mv88e6xxx_led *led;
+
+ led = container_of(ldev, struct mv88e6xxx_led, ldev);
+ ops = led->chip->info->ops->led_ops;
+
+ if (!ops->hw_control_is_supported)
+ return -EOPNOTSUPP;
+
+ return ops->hw_control_is_supported(led, flags);
+}
+
+static int mv88e6xxx_led_hw_control_set(struct led_classdev *ldev,
+ unsigned long flags)
+{
+ const struct mv88e6xxx_led_ops *ops;
+ struct mv88e6xxx_led *led;
+
+ led = container_of(ldev, struct mv88e6xxx_led, ldev);
+ ops = led->chip->info->ops->led_ops;
+
+ if (!ops->hw_control_set)
+ return -EOPNOTSUPP;
+
+ return ops->hw_control_set(led, flags);
+}
+
+static int mv88e6xxx_led_hw_control_get(struct led_classdev *ldev,
+ unsigned long *flags)
+{
+ const struct mv88e6xxx_led_ops *ops;
+ struct mv88e6xxx_led *led;
+
+ led = container_of(ldev, struct mv88e6xxx_led, ldev);
+ ops = led->chip->info->ops->led_ops;
+
+ if (!ops->hw_control_get)
+ return -EOPNOTSUPP;
+
+ return ops->hw_control_get(led, flags);
+}
+
+static struct device *mv88e6xxx_led_hw_control_get_device(struct led_classdev *ldev)
+{
+ struct mv88e6xxx_led *led;
+ struct dsa_port *dp;
+
+ led = container_of(ldev, struct mv88e6xxx_led, ldev);
+ dp = dsa_to_port(led->chip->ds, led->port);
+
+ if (dp && dp->slave)
+ return &dp->slave->dev;
+
+ return NULL;
+}
+
+static int mv88e6xxx_port_setup_led(struct mv88e6xxx_chip *chip, int port,
+ struct device_node *np)
+{
+ struct led_init_data init_data = {};
+ struct mv88e6xxx_led *led;
+ char *devname;
+ u32 index;
+ int err;
+
+ err = of_property_read_u32(np, "reg", &index);
+ if (err)
+ return err;
+
+ if (index >= 2)
+ return -EINVAL;
+
+ led = devm_kzalloc(chip->dev, sizeof(*led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ *led = (struct mv88e6xxx_led) {
+ .chip = chip,
+ .port = port,
+ .index = index,
+
+ .ldev = {
+ .max_brightness = 1,
+ .brightness_set_blocking = mv88e6xxx_led_brightness_set,
+ .blink_set = mv88e6xxx_led_blink_set,
+
+#ifdef CONFIG_LEDS_TRIGGERS
+ .hw_control_trigger = "netdev",
+ .hw_control_get_device = mv88e6xxx_led_hw_control_get_device,
+
+ .hw_control_is_supported = mv88e6xxx_led_hw_control_is_supported,
+ .hw_control_set = mv88e6xxx_led_hw_control_set,
+ .hw_control_get = mv88e6xxx_led_hw_control_get,
+#endif
+ },
+ };
+
+ devname = devm_kasprintf(chip->dev, GFP_KERNEL, "%s.%d",
+ dev_name(chip->dev), port);
+ if (!devname)
+ return -ENOMEM;
+
+ init_data = (struct led_init_data) {
+ .fwnode = of_fwnode_handle(np),
+ .devname_mandatory = true,
+ .devicename = devname,
+ };
+
+ return devm_led_classdev_register_ext(chip->dev, &led->ldev, &init_data);
+}
+
+int mv88e6xxx_port_setup_leds(struct dsa_switch *ds, int port)
+{
+ struct dsa_port *dp = dsa_to_port(ds, port);
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct device_node *pnp, *np;
+ int err;
+
+ if (!chip->info->ops->led_ops)
+ return 0;
+
+ if (!dp->dn)
+ return 0;
+
+ pnp = of_get_child_by_name(dp->dn, "leds");
+ if (!pnp)
+ return 0;
+
+ for_each_available_child_of_node(pnp, np) {
+ err = mv88e6xxx_port_setup_led(chip, port, np);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/dsa/mv88e6xxx/leds.h b/drivers/net/dsa/mv88e6xxx/leds.h
new file mode 100644
index 000000000000..8afa2a0c0527
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/leds.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* Marvell 88E6xxx Switch leds support. */
+
+#ifndef _MV88E6XXX_LEDS_H
+#define _MV88E6XXX_LEDS_H
+
+#include "chip.h"
+
+int mv88e6xxx_port_setup_leds(struct dsa_switch *ds, int port);
+
+#endif /* _MV88E6XXX_LEDS_H */
--
2.34.1
@@ -0,0 +1,353 @@
From 09fca5d7f66b1bdc6a5f72eb3d36bfd8c88bebcc Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 16 Nov 2023 21:59:35 +0100
Subject: [PATCH 15/15] net: dsa: mv88e6xxx: Add LED support for 6393X
Trigger support:
- "none"
- "timer"
- "netdev"
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 1 +
drivers/net/dsa/mv88e6xxx/leds.c | 219 +++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/leds.h | 2 +
drivers/net/dsa/mv88e6xxx/port.c | 33 +++++
drivers/net/dsa/mv88e6xxx/port.h | 7 +
5 files changed, 262 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index d343ea5cc4a1..7d6b2b85fc31 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -5833,6 +5833,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
+ .led_ops = &mv88e6393x_led_ops,
.phylink_get_caps = mv88e6393x_phylink_get_caps,
};
diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c
index 42e1661e1f47..02daf976100d 100644
--- a/drivers/net/dsa/mv88e6xxx/leds.c
+++ b/drivers/net/dsa/mv88e6xxx/leds.c
@@ -4,6 +4,13 @@
#include "chip.h"
#include "port.h"
+#define FLAG_ACT (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX))
+#define FLAG_LINK BIT(TRIGGER_NETDEV_LINK)
+#define FLAG_LINK_10 BIT(TRIGGER_NETDEV_LINK_10)
+#define FLAG_LINK_100 BIT(TRIGGER_NETDEV_LINK_100)
+#define FLAG_LINK_1G BIT(TRIGGER_NETDEV_LINK_1000)
+#define FLAG_FULL BIT(TRIGGER_NETDEV_FULL_DUPLEX)
+
struct mv88e6xxx_led {
struct mv88e6xxx_chip *chip;
int port;
@@ -12,6 +19,218 @@ struct mv88e6xxx_led {
struct led_classdev ldev;
};
+enum mv88e6393x_led_mode {
+ MV88E6393X_LED_MODE_BLINK = 0xd,
+ MV88E6393X_LED_MODE_OFF = 0xe,
+ MV88E6393X_LED_MODE_ON = 0xf,
+
+ MV88E6393X_LED_MODES = 0x10
+};
+
+static const unsigned long mv88e6393x_led_map_p1_p8[2][MV88E6393X_LED_MODES] = {
+ {
+ [0x1] = FLAG_ACT | FLAG_LINK_100 | FLAG_LINK_1G,
+ [0x2] = FLAG_ACT | FLAG_LINK_1G,
+ [0x3] = FLAG_ACT | FLAG_LINK,
+ [0x6] = FLAG_FULL,
+ [0x7] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_1G,
+ [0x8] = FLAG_LINK,
+ [0x9] = FLAG_LINK_10,
+ [0xa] = FLAG_ACT | FLAG_LINK_10,
+ [0xb] = FLAG_LINK_100 | FLAG_LINK_1G,
+ },
+ {
+ [0x1] = FLAG_ACT,
+ [0x2] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_100,
+ [0x3] = FLAG_LINK_1G,
+ [0x5] = FLAG_ACT | FLAG_LINK,
+ [0x6] = FLAG_ACT | FLAG_LINK_10 | FLAG_LINK_1G,
+ [0x7] = FLAG_LINK_10 | FLAG_LINK_1G,
+ [0x9] = FLAG_LINK_100,
+ [0xa] = FLAG_ACT | FLAG_LINK_100,
+ [0xb] = FLAG_LINK_10 | FLAG_LINK_100,
+ }
+};
+
+static const unsigned long mv88e6393x_led_map_p9_p10[2][MV88E6393X_LED_MODES] = {
+ {
+ [0x1] = FLAG_ACT | FLAG_LINK,
+ },
+ {
+ [0x6] = FLAG_FULL,
+ [0x7] = FLAG_ACT | FLAG_LINK,
+ [0x8] = FLAG_LINK,
+ }
+};
+
+const unsigned long *mv88e6393x_led_map(struct mv88e6xxx_led *led)
+{
+ switch (led->port) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ return mv88e6393x_led_map_p1_p8[led->index];
+ case 9:
+ case 10:
+ return mv88e6393x_led_map_p9_p10[led->index];
+ }
+
+ return NULL;
+}
+
+static int mv88e6393x_led_flags_to_mode(struct mv88e6xxx_led *led, unsigned long flags)
+{
+ const unsigned long *map = mv88e6393x_led_map(led);
+ int i;
+
+ if (!map)
+ return -ENODEV;
+
+ if (!flags)
+ return MV88E6393X_LED_MODE_OFF;
+
+ for (i = 0; i < MV88E6393X_LED_MODES; i++) {
+ if (map[i] == flags)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int mv88e6393x_led_mode_to_flags(struct mv88e6xxx_led *led, u8 mode,
+ unsigned long *flags)
+{
+ const unsigned long *map = mv88e6393x_led_map(led);
+
+ if (!map)
+ return -ENODEV;
+
+ if (mode == MV88E6393X_LED_MODE_OFF) {
+ *flags = 0;
+ return 0;
+ }
+
+ if (map[mode]) {
+ *flags = map[mode];
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int mv88e6393x_led_set(struct mv88e6xxx_led *led, int mode)
+{
+ u16 ctrl;
+ int err;
+
+ if (mode < 0)
+ return mode;
+
+ err = mv88e6393x_port_led_read(led->chip, led->port, 0, &ctrl);
+ if (err)
+ return err;
+
+ switch (led->index) {
+ case 0:
+ ctrl &= ~0x0f;
+ ctrl |= mode;
+ break;
+ case 1:
+ ctrl &= ~0xf0;
+ ctrl |= mode << 4;
+ }
+
+ return mv88e6393x_port_led_write(led->chip, led->port, 0, ctrl);
+}
+
+static int mv88e6393x_led_get(struct mv88e6xxx_led *led)
+{
+ u16 ctrl;
+ int err;
+
+ err = mv88e6393x_port_led_read(led->chip, led->port, 0, &ctrl);
+ if (err)
+ return err;
+
+ switch (led->index) {
+ case 0:
+ return ctrl & 0xf;
+ case 1:
+ return (ctrl >> 4) & 0xf;
+ }
+
+ return -EINVAL;
+}
+
+static int mv88e6393x_led_brightness_set(struct mv88e6xxx_led *led,
+ enum led_brightness brightness)
+{
+ if (brightness == LED_OFF)
+ return mv88e6393x_led_set(led, MV88E6393X_LED_MODE_OFF);
+
+ return mv88e6393x_led_set(led, MV88E6393X_LED_MODE_ON);
+}
+static int mv88e6393x_led_blink_set(struct mv88e6xxx_led *led,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ int err;
+
+ /* Defer anything other than 50% duty cycles to software */
+ if (*delay_on != *delay_off)
+ return -EINVAL;
+
+ /* Reject values outside ~20% of our default rate (84ms) */
+ if (*delay_on && ((*delay_on < 30) || (*delay_on > 50)))
+ return -EINVAL;
+
+ err = mv88e6393x_led_set(led, MV88E6393X_LED_MODE_BLINK);
+ if (!err)
+ *delay_on = *delay_off = 42;
+
+ return err;
+}
+
+static int mv88e6393x_led_hw_control_is_supported(struct mv88e6xxx_led *led,
+ unsigned long flags)
+{
+ int mode = mv88e6393x_led_flags_to_mode(led, flags);
+
+ return (mode < 0) ? mode : 0;
+}
+
+static int mv88e6393x_led_hw_control_set(struct mv88e6xxx_led *led,
+ unsigned long flags)
+{
+ int mode = mv88e6393x_led_flags_to_mode(led, flags);
+
+ return mv88e6393x_led_set(led, mode);
+}
+
+static int mv88e6393x_led_hw_control_get(struct mv88e6xxx_led *led,
+ unsigned long *flags)
+{
+ int mode = mv88e6393x_led_get(led);
+
+ if (mode < 0)
+ return mode;
+
+ return mv88e6393x_led_mode_to_flags(led, mode, flags);
+}
+
+const struct mv88e6xxx_led_ops mv88e6393x_led_ops = {
+ .brightness_set = mv88e6393x_led_brightness_set,
+ .blink_set = mv88e6393x_led_blink_set,
+ .hw_control_is_supported = mv88e6393x_led_hw_control_is_supported,
+ .hw_control_set = mv88e6393x_led_hw_control_set,
+ .hw_control_get = mv88e6393x_led_hw_control_get,
+};
+
static int mv88e6xxx_led_brightness_set(struct led_classdev *ldev,
enum led_brightness brightness)
{
diff --git a/drivers/net/dsa/mv88e6xxx/leds.h b/drivers/net/dsa/mv88e6xxx/leds.h
index 8afa2a0c0527..542345d23dc5 100644
--- a/drivers/net/dsa/mv88e6xxx/leds.h
+++ b/drivers/net/dsa/mv88e6xxx/leds.h
@@ -7,6 +7,8 @@
#include "chip.h"
+extern const struct mv88e6xxx_led_ops mv88e6393x_led_ops;
+
int mv88e6xxx_port_setup_leds(struct dsa_switch *ds, int port);
#endif /* _MV88E6XXX_LEDS_H */
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index dd66ec902d4c..e6733a3ab19f 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -1569,6 +1569,39 @@ int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
}
+/* Offset 0x16: LED Control Register */
+
+int mv88e6393x_port_led_write(struct mv88e6xxx_chip *chip, int port,
+ unsigned int pointer, u16 data)
+{
+ u16 cmd = BIT(15) | ((pointer & 0x7) << 12) | (data & 0x7ff);
+ int err;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_LED_CONTROL, cmd);
+ if (err)
+ return err;
+
+ return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_LED_CONTROL, 15, 0);
+}
+
+int mv88e6393x_port_led_read(struct mv88e6xxx_chip *chip, int port,
+ unsigned int pointer, u16 *data)
+{
+ u16 cmd = (pointer & 0x7) << 12;
+ int err;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_LED_CONTROL, cmd);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6393X_PORT_LED_CONTROL, &cmd);
+ if (err)
+ return err;
+
+ *data = cmd & 0x7ff;
+ return 0;
+}
+
/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
* Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
*/
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index 86deeb347cbc..3605a59d1399 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -294,6 +294,9 @@
/* Offset 0x13: OutFiltered Counter */
#define MV88E6XXX_PORT_OUT_FILTERED 0x13
+/* Offset 0x16: LED Control Register */
+#define MV88E6393X_PORT_LED_CONTROL 0x16
+
/* Offset 0x18: IEEE Priority Mapping Table */
#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18
#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000
@@ -410,6 +413,10 @@ int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port,
enum mv88e6xxx_policy_action action);
int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
u16 etype);
+int mv88e6393x_port_led_write(struct mv88e6xxx_chip *chip, int port,
+ unsigned int pointer, u16 data);
+int mv88e6393x_port_led_read(struct mv88e6xxx_chip *chip, int port,
+ unsigned int pointer, u16 *data);
int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
enum mv88e6xxx_egress_direction direction,
int port);
--
2.34.1