From 0d74b2a1e5f35d534fb5433ffcd85aa6b967cd47 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 8 May 2024 01:48:14 +0100 Subject: [PATCH] generic: 6.1, 6.6: replace Airoha EN8811H PHY driver with upstream Backport driver from upcoming Linux 6.10 and put a pending fix on top to make sure the netdev trigger offloading behaves as expected. Signed-off-by: Daniel Golle --- ....h-removed-REPEAT_BYTE-from-kernel.h.patch | 161 +++++ ...per_-_bits-and-lower_-_bits-to-wordp.patch | 107 +++ ...1h-Add-the-Airoha-EN8811H-PHY-drive.patch} | 663 +++++++++--------- ...phy-air_en8811h-fix-some-error-codes.patch | 47 ++ ...t-phy-amd-Support-the-Altima-AMI101L.patch | 4 +- ....h-removed-REPEAT_BYTE-from-kernel.h.patch | 161 +++++ ...per_-_bits-and-lower_-_bits-to-wordp.patch | 107 +++ ...1h-Add-the-Airoha-EN8811H-PHY-drive.patch} | 661 ++++++++--------- ...phy-air_en8811h-fix-some-error-codes.patch | 47 ++ ...t-phy-amd-Support-the-Altima-AMI101L.patch | 4 +- ...11h-reset-netdev-rules-when-LED-is-s.patch | 45 ++ ...11h-reset-netdev-rules-when-LED-is-s.patch | 45 ++ 12 files changed, 1411 insertions(+), 641 deletions(-) create mode 100644 target/linux/generic/backport-6.1/301-v6.9-kernel.h-removed-REPEAT_BYTE-from-kernel.h.patch create mode 100644 target/linux/generic/backport-6.1/302-v6.9-kernel.h-Move-upper_-_bits-and-lower_-_bits-to-wordp.patch rename target/linux/generic/{pending-6.1/750-net-phy-airoha-Add-the-Airoha-EN8811H-PHY-driver.patch => backport-6.1/798-v6.10-net-phy-air_en8811h-Add-the-Airoha-EN8811H-PHY-drive.patch} (61%) create mode 100644 target/linux/generic/backport-6.1/799-v6.10-net-phy-air_en8811h-fix-some-error-codes.patch create mode 100644 target/linux/generic/backport-6.6/301-v6.9-kernel.h-removed-REPEAT_BYTE-from-kernel.h.patch create mode 100644 target/linux/generic/backport-6.6/302-v6.9-kernel.h-Move-upper_-_bits-and-lower_-_bits-to-wordp.patch rename target/linux/generic/{pending-6.6/750-net-phy-airoha-Add-the-Airoha-EN8811H-PHY-driver.patch => backport-6.6/798-v6.10-net-phy-air_en8811h-Add-the-Airoha-EN8811H-PHY-drive.patch} (61%) create mode 100644 target/linux/generic/backport-6.6/799-v6.10-net-phy-air_en8811h-fix-some-error-codes.patch create mode 100644 target/linux/generic/pending-6.1/742-net-phy-air_en8811h-reset-netdev-rules-when-LED-is-s.patch create mode 100644 target/linux/generic/pending-6.6/742-net-phy-air_en8811h-reset-netdev-rules-when-LED-is-s.patch diff --git a/target/linux/generic/backport-6.1/301-v6.9-kernel.h-removed-REPEAT_BYTE-from-kernel.h.patch b/target/linux/generic/backport-6.1/301-v6.9-kernel.h-removed-REPEAT_BYTE-from-kernel.h.patch new file mode 100644 index 0000000000..239adff1af --- /dev/null +++ b/target/linux/generic/backport-6.1/301-v6.9-kernel.h-removed-REPEAT_BYTE-from-kernel.h.patch @@ -0,0 +1,161 @@ +From 66a5c40f60f5d88ad8d47ba6a4ba05892853fa1f Mon Sep 17 00:00:00 2001 +From: Tanzir Hasan +Date: Tue, 26 Dec 2023 18:00:00 +0000 +Subject: [PATCH] kernel.h: removed REPEAT_BYTE from kernel.h + +This patch creates wordpart.h and includes it in asm/word-at-a-time.h +for all architectures. WORD_AT_A_TIME_CONSTANTS depends on kernel.h +because of REPEAT_BYTE. Moving this to another header and including it +where necessary allows us to not include the bloated kernel.h. Making +this implicit dependency on REPEAT_BYTE explicit allows for later +improvements in the lib/string.c inclusion list. + +Suggested-by: Al Viro +Suggested-by: Andy Shevchenko +Signed-off-by: Tanzir Hasan +Reviewed-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20231226-libstringheader-v6-1-80aa08c7652c@google.com +Signed-off-by: Kees Cook +--- + arch/arm/include/asm/word-at-a-time.h | 3 ++- + arch/arm64/include/asm/word-at-a-time.h | 3 ++- + arch/powerpc/include/asm/word-at-a-time.h | 4 ++-- + arch/riscv/include/asm/word-at-a-time.h | 3 ++- + arch/s390/include/asm/word-at-a-time.h | 3 ++- + arch/sh/include/asm/word-at-a-time.h | 2 ++ + arch/x86/include/asm/word-at-a-time.h | 3 ++- + arch/x86/kvm/mmu/mmu.c | 1 + + fs/namei.c | 2 +- + include/asm-generic/word-at-a-time.h | 3 ++- + include/linux/kernel.h | 8 -------- + include/linux/wordpart.h | 13 +++++++++++++ + 12 files changed, 31 insertions(+), 17 deletions(-) + create mode 100644 include/linux/wordpart.h + +--- a/arch/arm/include/asm/word-at-a-time.h ++++ b/arch/arm/include/asm/word-at-a-time.h +@@ -8,7 +8,8 @@ + * Little-endian word-at-a-time zero byte handling. + * Heavily based on the x86 algorithm. + */ +-#include ++#include ++#include + + struct word_at_a_time { + const unsigned long one_bits, high_bits; +--- a/arch/arm64/include/asm/word-at-a-time.h ++++ b/arch/arm64/include/asm/word-at-a-time.h +@@ -9,7 +9,8 @@ + + #ifndef __AARCH64EB__ + +-#include ++#include ++#include + + struct word_at_a_time { + const unsigned long one_bits, high_bits; +--- a/arch/powerpc/include/asm/word-at-a-time.h ++++ b/arch/powerpc/include/asm/word-at-a-time.h +@@ -4,8 +4,8 @@ + /* + * Word-at-a-time interfaces for PowerPC. + */ +- +-#include ++#include ++#include + #include + #include + +--- a/arch/sh/include/asm/word-at-a-time.h ++++ b/arch/sh/include/asm/word-at-a-time.h +@@ -5,6 +5,8 @@ + #ifdef CONFIG_CPU_BIG_ENDIAN + # include + #else ++#include ++#include + /* + * Little-endian version cribbed from x86. + */ +--- a/arch/x86/include/asm/word-at-a-time.h ++++ b/arch/x86/include/asm/word-at-a-time.h +@@ -2,7 +2,8 @@ + #ifndef _ASM_WORD_AT_A_TIME_H + #define _ASM_WORD_AT_A_TIME_H + +-#include ++#include ++#include + + /* + * This is largely generic for little-endian machines, but the +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + + #include + #include +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -17,8 +17,8 @@ + + #include + #include +-#include + #include ++#include + #include + #include + #include +--- a/include/asm-generic/word-at-a-time.h ++++ b/include/asm-generic/word-at-a-time.h +@@ -2,7 +2,8 @@ + #ifndef _ASM_WORD_AT_A_TIME_H + #define _ASM_WORD_AT_A_TIME_H + +-#include ++#include ++#include + #include + + #ifdef __BIG_ENDIAN +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -36,14 +36,6 @@ + + #define STACK_MAGIC 0xdeadbeef + +-/** +- * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value +- * @x: value to repeat +- * +- * NOTE: @x is not checked for > 0xff; larger values produce odd results. +- */ +-#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x)) +- + /* generic data direction definitions */ + #define READ 0 + #define WRITE 1 +--- /dev/null ++++ b/include/linux/wordpart.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef _LINUX_WORDPART_H ++#define _LINUX_WORDPART_H ++/** ++ * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value ++ * @x: value to repeat ++ * ++ * NOTE: @x is not checked for > 0xff; larger values produce odd results. ++ */ ++#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x)) ++ ++#endif // _LINUX_WORDPART_H diff --git a/target/linux/generic/backport-6.1/302-v6.9-kernel.h-Move-upper_-_bits-and-lower_-_bits-to-wordp.patch b/target/linux/generic/backport-6.1/302-v6.9-kernel.h-Move-upper_-_bits-and-lower_-_bits-to-wordp.patch new file mode 100644 index 0000000000..9bbd515852 --- /dev/null +++ b/target/linux/generic/backport-6.1/302-v6.9-kernel.h-Move-upper_-_bits-and-lower_-_bits-to-wordp.patch @@ -0,0 +1,107 @@ +From adeb04362d74188c1e22ccb824b15a0a7b3de2f4 Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Wed, 14 Feb 2024 19:26:32 +0200 +Subject: [PATCH] kernel.h: Move upper_*_bits() and lower_*_bits() to + wordpart.h + +The wordpart.h header is collecting APIs related to the handling +parts of the word (usually in byte granularity). The upper_*_bits() +and lower_*_bits() are good candidates to be moved to there. + +This helps to clean up header dependency hell with regard to kernel.h +as the latter gathers completely unrelated stuff together and slows +down compilation (especially when it's included into other header). + +Signed-off-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20240214172752.3605073-1-andriy.shevchenko@linux.intel.com +Reviewed-by: Randy Dunlap +Signed-off-by: Kees Cook +--- + include/linux/kernel.h | 30 ++---------------------------- + include/linux/wordpart.h | 29 +++++++++++++++++++++++++++++ + 2 files changed, 31 insertions(+), 28 deletions(-) + +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++ + #include + + #include +@@ -55,34 +57,6 @@ + } \ + ) + +-/** +- * upper_32_bits - return bits 32-63 of a number +- * @n: the number we're accessing +- * +- * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress +- * the "right shift count >= width of type" warning when that quantity is +- * 32-bits. +- */ +-#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) +- +-/** +- * lower_32_bits - return bits 0-31 of a number +- * @n: the number we're accessing +- */ +-#define lower_32_bits(n) ((u32)((n) & 0xffffffff)) +- +-/** +- * upper_16_bits - return bits 16-31 of a number +- * @n: the number we're accessing +- */ +-#define upper_16_bits(n) ((u16)((n) >> 16)) +- +-/** +- * lower_16_bits - return bits 0-15 of a number +- * @n: the number we're accessing +- */ +-#define lower_16_bits(n) ((u16)((n) & 0xffff)) +- + struct completion; + struct user; + +--- a/include/linux/wordpart.h ++++ b/include/linux/wordpart.h +@@ -2,6 +2,35 @@ + + #ifndef _LINUX_WORDPART_H + #define _LINUX_WORDPART_H ++ ++/** ++ * upper_32_bits - return bits 32-63 of a number ++ * @n: the number we're accessing ++ * ++ * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress ++ * the "right shift count >= width of type" warning when that quantity is ++ * 32-bits. ++ */ ++#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) ++ ++/** ++ * lower_32_bits - return bits 0-31 of a number ++ * @n: the number we're accessing ++ */ ++#define lower_32_bits(n) ((u32)((n) & 0xffffffff)) ++ ++/** ++ * upper_16_bits - return bits 16-31 of a number ++ * @n: the number we're accessing ++ */ ++#define upper_16_bits(n) ((u16)((n) >> 16)) ++ ++/** ++ * lower_16_bits - return bits 0-15 of a number ++ * @n: the number we're accessing ++ */ ++#define lower_16_bits(n) ((u16)((n) & 0xffff)) ++ + /** + * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value + * @x: value to repeat diff --git a/target/linux/generic/pending-6.1/750-net-phy-airoha-Add-the-Airoha-EN8811H-PHY-driver.patch b/target/linux/generic/backport-6.1/798-v6.10-net-phy-air_en8811h-Add-the-Airoha-EN8811H-PHY-drive.patch similarity index 61% rename from target/linux/generic/pending-6.1/750-net-phy-airoha-Add-the-Airoha-EN8811H-PHY-driver.patch rename to target/linux/generic/backport-6.1/798-v6.10-net-phy-air_en8811h-Add-the-Airoha-EN8811H-PHY-drive.patch index 1dfa1366eb..7f963b3cf6 100644 --- a/target/linux/generic/pending-6.1/750-net-phy-airoha-Add-the-Airoha-EN8811H-PHY-driver.patch +++ b/target/linux/generic/backport-6.1/798-v6.10-net-phy-air_en8811h-Add-the-Airoha-EN8811H-PHY-drive.patch @@ -1,88 +1,33 @@ -From patchwork Tue Feb 6 19:47:51 2024 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -X-Patchwork-Submitter: Eric Woudstra -X-Patchwork-Id: 13547762 -X-Patchwork-Delegate: kuba@kernel.org +From 71e79430117d56c409c5ea485a263bc0d8083390 Mon Sep 17 00:00:00 2001 From: Eric Woudstra -To: "David S. Miller" , - Eric Dumazet , - Jakub Kicinski , - Paolo Abeni , - Rob Herring , - Krzysztof Kozlowski , - Conor Dooley , - Andrew Lunn , - Heiner Kallweit , - Russell King , - Matthias Brugger , - AngeloGioacchino Del Regno , - "Frank Wunderlich" , - Daniel Golle , - Lucien Jheng , - Zhi-Jun You -Cc: netdev@vger.kernel.org, - devicetree@vger.kernel.org, - Eric Woudstra -Subject: [PATCH net-next 2/2] net: phy: air_en8811h: Add the Airoha EN8811H - PHY driver -Date: Tue, 6 Feb 2024 20:47:51 +0100 -Message-ID: <20240206194751.1901802-3-ericwouds@gmail.com> -X-Mailer: git-send-email 2.42.1 -In-Reply-To: <20240206194751.1901802-1-ericwouds@gmail.com> -References: <20240206194751.1901802-1-ericwouds@gmail.com> -Precedence: bulk -X-Mailing-List: netdev@vger.kernel.org -List-Id: -List-Subscribe: -List-Unsubscribe: -MIME-Version: 1.0 -X-Patchwork-Delegate: kuba@kernel.org +Date: Tue, 26 Mar 2024 17:23:05 +0100 +Subject: [PATCH] net: phy: air_en8811h: Add the Airoha EN8811H PHY driver -* Source originated from airoha's en8811h v1.2.1 driver - * Moved air_en8811h.h to air_en8811h.c - * Removed air_pbus_reg_write() as it writes to another device on mdio-bus - * Load firmware from /lib/firmware/airoha/ instead of /lib/firmware/ - * Added .get_rate_matching() - * Use generic phy_read/write() and phy_read/write_mmd() - * Edited .get_features() to use generic C45 functions - * Edited .config_aneg() and .read_status() to use a mix of generic C22/C45 - * Use led handling functions from mediatek-ge-soc.c - * Simplified led handling by storing led rules - * Cleanup macro definitions - * Cleanup code to pass checkpatch.pl - * General code cleanup +Add the driver for the Airoha EN8811H 2.5 Gigabit PHY. The phy supports +100/1000/2500 Mbps with auto negotiation only. -Changes from original RFC patch: +The driver uses two firmware files, for which updated versions are added to +linux-firmware already. - * Use the correct order in Kconfig and Makefile - * Change some register naming to correspond with datasheet - * Use phy_driver .read_page() and .write_page() - * Use module_phy_driver() - * Use get_unaligned_le16() instead of macro - * In .config_aneg() and .read_status() use genphy_xxx() C22 - * Use another vendor register to read real speed - * Load firmware only once and store firmware version - * Apply 2.5G LPA work-around (firmware before 24011202) - * Read 2.5G LPA from vendor register (firmware 24011202 and later) - -Changes to be committed: - modified: drivers/net/phy/Kconfig - modified: drivers/net/phy/Makefile - new file: drivers/net/phy/air_en8811h.c +Note: At phy-address + 8 there is another device on the mdio bus, that +belongs to the EN881H. While the original driver writes to it, Airoha +has confirmed this is not needed. Therefore, communication with this +device is not included in this driver. Signed-off-by: Eric Woudstra +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/20240326162305.303598-3-ericwouds@gmail.com +Signed-off-by: Jakub Kicinski --- drivers/net/phy/Kconfig | 5 + drivers/net/phy/Makefile | 1 + - drivers/net/phy/air_en8811h.c | 1006 +++++++++++++++++++++++++++++++++ - 3 files changed, 1012 insertions(+) + drivers/net/phy/air_en8811h.c | 1086 +++++++++++++++++++++++++++++++++ + 3 files changed, 1092 insertions(+) create mode 100644 drivers/net/phy/air_en8811h.c --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -69,6 +69,11 @@ config SFP +@@ -63,6 +63,11 @@ config SFP comment "MII PHY device drivers" @@ -92,7 +37,7 @@ Signed-off-by: Eric Woudstra + Currently supports the Airoha EN8811H PHY. + config AMD_PHY - tristate "AMD and Altima PHYs" + tristate "AMD PHYs" help --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -106,12 +51,10 @@ Signed-off-by: Eric Woudstra obj-$(CONFIG_AX88796B_PHY) += ax88796b.o --- /dev/null +++ b/drivers/net/phy/air_en8811h.c -@@ -0,0 +1,1006 @@ +@@ -0,0 +1,1086 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* -+ * Driver for Airoha Ethernet PHYs -+ * -+ * Currently supporting the EN8811H. ++ * Driver for the Airoha EN8811H 2.5 Gigabit PHY. + * + * Limitations of the EN8811H: + * - Only full duplex supported @@ -125,6 +68,7 @@ Signed-off-by: Eric Woudstra +#include +#include +#include ++#include +#include + +#define EN8811H_PHY_ID 0x03a2a411 @@ -135,12 +79,8 @@ Signed-off-by: Eric Woudstra +#define AIR_FW_ADDR_DM 0x00000000 +#define AIR_FW_ADDR_DSP 0x00100000 + -+/* u32 (DWORD) component macros */ -+#define LOWORD(d) ((u16)(u32)(d)) -+#define HIWORD(d) ((u16)(((u32)(d)) >> 16)) -+ +/* MII Registers */ -+#define AIR_AUX_CTRL_STATUS 0x1d ++#define AIR_AUX_CTRL_STATUS 0x1d +#define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2) +#define AIR_AUX_CTRL_STATUS_SPEED_100 0x4 +#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 @@ -151,32 +91,32 @@ Signed-off-by: Eric Woudstra +#define AIR_PHY_PAGE_EXTENDED_4 0x0004 + +/* MII Registers Page 4*/ -+#define AIR_PBUS_MODE 0x10 -+#define AIR_PBUS_MODE_ADDR_FIXED 0x0000 -+#define AIR_PBUS_MODE_ADDR_INCR BIT(15) -+#define AIR_PBUS_WR_ADDR_HIGH 0x11 -+#define AIR_PBUS_WR_ADDR_LOW 0x12 -+#define AIR_PBUS_WR_DATA_HIGH 0x13 -+#define AIR_PBUS_WR_DATA_LOW 0x14 -+#define AIR_PBUS_RD_ADDR_HIGH 0x15 -+#define AIR_PBUS_RD_ADDR_LOW 0x16 -+#define AIR_PBUS_RD_DATA_HIGH 0x17 -+#define AIR_PBUS_RD_DATA_LOW 0x18 ++#define AIR_BPBUS_MODE 0x10 ++#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000 ++#define AIR_BPBUS_MODE_ADDR_INCR BIT(15) ++#define AIR_BPBUS_WR_ADDR_HIGH 0x11 ++#define AIR_BPBUS_WR_ADDR_LOW 0x12 ++#define AIR_BPBUS_WR_DATA_HIGH 0x13 ++#define AIR_BPBUS_WR_DATA_LOW 0x14 ++#define AIR_BPBUS_RD_ADDR_HIGH 0x15 ++#define AIR_BPBUS_RD_ADDR_LOW 0x16 ++#define AIR_BPBUS_RD_DATA_HIGH 0x17 ++#define AIR_BPBUS_RD_DATA_LOW 0x18 + +/* Registers on MDIO_MMD_VEND1 */ +#define EN8811H_PHY_FW_STATUS 0x8009 +#define EN8811H_PHY_READY 0x02 + -+#define AIR_PHY_HOST_CMD_1 0x800c -+#define AIR_PHY_HOST_CMD_1_MODE1 0x0 -+#define AIR_PHY_HOST_CMD_2 0x800d -+#define AIR_PHY_HOST_CMD_2_MODE1 0x0 -+#define AIR_PHY_HOST_CMD_3 0x800e -+#define AIR_PHY_HOST_CMD_3_MODE1 0x1101 -+#define AIR_PHY_HOST_CMD_3_DOCMD 0x1100 -+#define AIR_PHY_HOST_CMD_4 0x800f -+#define AIR_PHY_HOST_CMD_4_MODE1 0x0002 -+#define AIR_PHY_HOST_CMD_4_INTCLR 0x00e4 ++#define AIR_PHY_MCU_CMD_1 0x800c ++#define AIR_PHY_MCU_CMD_1_MODE1 0x0 ++#define AIR_PHY_MCU_CMD_2 0x800d ++#define AIR_PHY_MCU_CMD_2_MODE1 0x0 ++#define AIR_PHY_MCU_CMD_3 0x800e ++#define AIR_PHY_MCU_CMD_3_MODE1 0x1101 ++#define AIR_PHY_MCU_CMD_3_DOCMD 0x1100 ++#define AIR_PHY_MCU_CMD_4 0x800f ++#define AIR_PHY_MCU_CMD_4_MODE1 0x0002 ++#define AIR_PHY_MCU_CMD_4_INTCLR 0x00e4 + +/* Registers on MDIO_MMD_VEND2 */ +#define AIR_PHY_LED_BCR 0x021 @@ -235,28 +175,21 @@ Signed-off-by: Eric Woudstra +#define EN8811H_FW_CTRL_2 0x800000 +#define EN8811H_FW_CTRL_2_LOADING BIT(11) + ++/* Led definitions */ +#define EN8811H_LED_COUNT 3 + -+/* GPIO5 <-> BASE_T_LED0 -+ * GPIO4 <-> BASE_T_LED1 -+ * GPIO3 <-> BASE_T_LED2 -+ * -+ * Default setup suitable for 2 leds connected: -+ * 100M link up triggers led0, only led0 blinking on traffic -+ * 1000M link up triggers led1, only led1 blinking on traffic -+ * 2500M link up triggers led0 and led1, both blinking on traffic -+ * Also suitable for 1 led connected: -+ * any link up triggers led2 ++/* Default LED setup: ++ * GPIO5 <-> LED0 On: Link detected, blink Rx/Tx ++ * GPIO4 <-> LED1 On: Link detected at 2500 or 1000 Mbps ++ * GPIO3 <-> LED2 On: Link detected at 2500 or 100 Mbps + */ -+#define AIR_DEFAULT_TRIGGER_LED0 (BIT(TRIGGER_NETDEV_LINK_2500) | \ -+ BIT(TRIGGER_NETDEV_LINK_100) | \ ++#define AIR_DEFAULT_TRIGGER_LED0 (BIT(TRIGGER_NETDEV_LINK) | \ + BIT(TRIGGER_NETDEV_RX) | \ + BIT(TRIGGER_NETDEV_TX)) +#define AIR_DEFAULT_TRIGGER_LED1 (BIT(TRIGGER_NETDEV_LINK_2500) | \ -+ BIT(TRIGGER_NETDEV_LINK_1000) | \ -+ BIT(TRIGGER_NETDEV_RX) | \ -+ BIT(TRIGGER_NETDEV_TX)) -+#define AIR_DEFAULT_TRIGGER_LED2 BIT(TRIGGER_NETDEV_LINK) ++ BIT(TRIGGER_NETDEV_LINK_1000)) ++#define AIR_DEFAULT_TRIGGER_LED2 (BIT(TRIGGER_NETDEV_LINK_2500) | \ ++ BIT(TRIGGER_NETDEV_LINK_100)) + +struct led { + unsigned long rules; @@ -265,6 +198,7 @@ Signed-off-by: Eric Woudstra + +struct en8811h_priv { + u32 firmware_version; ++ bool mcu_needs_restart; + struct led led[EN8811H_LED_COUNT]; +}; + @@ -274,12 +208,12 @@ Signed-off-by: Eric Woudstra +}; + +enum { -+ AIR_PHY_LED_DUR_BLINK_32M, -+ AIR_PHY_LED_DUR_BLINK_64M, -+ AIR_PHY_LED_DUR_BLINK_128M, -+ AIR_PHY_LED_DUR_BLINK_256M, -+ AIR_PHY_LED_DUR_BLINK_512M, -+ AIR_PHY_LED_DUR_BLINK_1024M, ++ AIR_PHY_LED_DUR_BLINK_32MS, ++ AIR_PHY_LED_DUR_BLINK_64MS, ++ AIR_PHY_LED_DUR_BLINK_128MS, ++ AIR_PHY_LED_DUR_BLINK_256MS, ++ AIR_PHY_LED_DUR_BLINK_512MS, ++ AIR_PHY_LED_DUR_BLINK_1024MS, +}; + +enum { @@ -298,16 +232,16 @@ Signed-off-by: Eric Woudstra +}; + +#define AIR_PHY_LED_DUR_UNIT 1024 -+#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64M) ++#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS) + -+static const unsigned long en8811h_led_trig = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) | -+ BIT(TRIGGER_NETDEV_LINK) | -+ BIT(TRIGGER_NETDEV_LINK_10) | -+ BIT(TRIGGER_NETDEV_LINK_100) | -+ BIT(TRIGGER_NETDEV_LINK_1000) | -+ BIT(TRIGGER_NETDEV_LINK_2500) | -+ BIT(TRIGGER_NETDEV_RX) | -+ BIT(TRIGGER_NETDEV_TX)); ++static const unsigned long en8811h_led_trig = BIT(TRIGGER_NETDEV_FULL_DUPLEX) | ++ BIT(TRIGGER_NETDEV_LINK) | ++ BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_LINK_2500) | ++ BIT(TRIGGER_NETDEV_RX) | ++ BIT(TRIGGER_NETDEV_TX); + +static int air_phy_read_page(struct phy_device *phydev) +{ @@ -324,23 +258,27 @@ Signed-off-by: Eric Woudstra +{ + int ret; + -+ ret = __phy_write(phydev, AIR_PBUS_MODE, AIR_PBUS_MODE_ADDR_FIXED); ++ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_ADDR_HIGH, HIWORD(pbus_address)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, ++ upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_ADDR_LOW, LOWORD(pbus_address)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, ++ lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_DATA_HIGH, HIWORD(pbus_data)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, ++ upper_16_bits(pbus_data)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_DATA_LOW, LOWORD(pbus_data)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, ++ lower_16_bits(pbus_data)); + if (ret < 0) + return ret; + @@ -350,17 +288,20 @@ Signed-off-by: Eric Woudstra +static int air_buckpbus_reg_write(struct phy_device *phydev, + u32 pbus_address, u32 pbus_data) +{ -+ int ret, saved_page; ++ int saved_page; ++ int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + -+ ret = __air_buckpbus_reg_write(phydev, pbus_address, pbus_data); -+ if (ret < 0) -+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, -+ pbus_address, ret); ++ if (saved_page >= 0) { ++ ret = __air_buckpbus_reg_write(phydev, pbus_address, ++ pbus_data); ++ if (ret < 0) ++ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ } + + return phy_restore_page(phydev, saved_page, ret); -+; +} + +static int __air_buckpbus_reg_read(struct phy_device *phydev, @@ -369,41 +310,122 @@ Signed-off-by: Eric Woudstra + int pbus_data_low, pbus_data_high; + int ret; + -+ ret = __phy_write(phydev, AIR_PBUS_MODE, AIR_PBUS_MODE_ADDR_FIXED); ++ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_RD_ADDR_HIGH, HIWORD(pbus_address)); ++ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, ++ upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_RD_ADDR_LOW, LOWORD(pbus_address)); ++ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, ++ lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + -+ pbus_data_high = __phy_read(phydev, AIR_PBUS_RD_DATA_HIGH); ++ pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) + return ret; + -+ pbus_data_low = __phy_read(phydev, AIR_PBUS_RD_DATA_LOW); ++ pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) + return ret; + -+ *pbus_data = (u16)pbus_data_low | ((u32)(u16)pbus_data_high << 16); ++ *pbus_data = pbus_data_low | (pbus_data_high << 16); + return 0; +} + +static int air_buckpbus_reg_read(struct phy_device *phydev, + u32 pbus_address, u32 *pbus_data) +{ -+ int ret, saved_page; ++ int saved_page; ++ int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + -+ ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); ++ if (saved_page >= 0) { ++ ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); ++ if (ret < 0) ++ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ } ++ ++ return phy_restore_page(phydev, saved_page, ret); ++} ++ ++static int __air_buckpbus_reg_modify(struct phy_device *phydev, ++ u32 pbus_address, u32 mask, u32 set) ++{ ++ int pbus_data_low, pbus_data_high; ++ u32 pbus_data_old, pbus_data_new; ++ int ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); ++ if (ret < 0) ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, ++ upper_16_bits(pbus_address)); ++ if (ret < 0) ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, ++ lower_16_bits(pbus_address)); ++ if (ret < 0) ++ return ret; ++ ++ pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); ++ if (pbus_data_high < 0) ++ return ret; ++ ++ pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); ++ if (pbus_data_low < 0) ++ return ret; ++ ++ pbus_data_old = pbus_data_low | (pbus_data_high << 16); ++ pbus_data_new = (pbus_data_old & ~mask) | set; ++ if (pbus_data_new == pbus_data_old) ++ return 0; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, ++ upper_16_bits(pbus_address)); + if (ret < 0) -+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, -+ pbus_address, ret); ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, ++ lower_16_bits(pbus_address)); ++ if (ret < 0) ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, ++ upper_16_bits(pbus_data_new)); ++ if (ret < 0) ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, ++ lower_16_bits(pbus_data_new)); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int air_buckpbus_reg_modify(struct phy_device *phydev, ++ u32 pbus_address, u32 mask, u32 set) ++{ ++ int saved_page; ++ int ret = 0; ++ ++ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); ++ ++ if (saved_page >= 0) { ++ ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask, ++ set); ++ if (ret < 0) ++ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ } + + return phy_restore_page(phydev, saved_page, ret); +} @@ -415,26 +437,28 @@ Signed-off-by: Eric Woudstra + int ret; + u16 val; + -+ ret = __phy_write(phydev, AIR_PBUS_MODE, AIR_PBUS_MODE_ADDR_INCR); ++ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_ADDR_HIGH, HIWORD(address)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, ++ upper_16_bits(address)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_ADDR_LOW, LOWORD(address)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, ++ lower_16_bits(address)); + if (ret < 0) + return ret; + + for (offset = 0; offset < fw->size; offset += 4) { + val = get_unaligned_le16(&fw->data[offset + 2]); -+ ret = __phy_write(phydev, AIR_PBUS_WR_DATA_HIGH, val); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, val); + if (ret < 0) + return ret; + + val = get_unaligned_le16(&fw->data[offset]); -+ ret = __phy_write(phydev, AIR_PBUS_WR_DATA_LOW, val); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, val); + if (ret < 0) + return ret; + } @@ -445,23 +469,43 @@ Signed-off-by: Eric Woudstra +static int air_write_buf(struct phy_device *phydev, u32 address, + const struct firmware *fw) +{ -+ int ret, saved_page; ++ int saved_page; ++ int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + -+ ret = __air_write_buf(phydev, address, fw); -+ if (ret < 0) -+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, -+ address, ret); ++ if (saved_page >= 0) { ++ ret = __air_write_buf(phydev, address, fw); ++ if (ret < 0) ++ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, ++ address, ret); ++ } + + return phy_restore_page(phydev, saved_page, ret); +} + ++static int en8811h_wait_mcu_ready(struct phy_device *phydev) ++{ ++ int ret, reg_value; ++ ++ /* Because of mdio-lock, may have to wait for multiple loads */ ++ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ++ EN8811H_PHY_FW_STATUS, reg_value, ++ reg_value == EN8811H_PHY_READY, ++ 20000, 7500000, true); ++ if (ret) { ++ phydev_err(phydev, "MCU not ready: 0x%x\n", reg_value); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ +static int en8811h_load_firmware(struct phy_device *phydev) +{ ++ struct en8811h_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + const struct firmware *fw1, *fw2; -+ u32 pbus_value; + int ret; + + ret = request_firmware_direct(&fw1, EN8811H_MD32_DM, dev); @@ -477,11 +521,9 @@ Signed-off-by: Eric Woudstra + if (ret < 0) + goto en8811h_load_firmware_out; + -+ ret = air_buckpbus_reg_read(phydev, EN8811H_FW_CTRL_2, &pbus_value); -+ if (ret < 0) -+ goto en8811h_load_firmware_out; -+ pbus_value |= EN8811H_FW_CTRL_2_LOADING; -+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_2, pbus_value); ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, ++ EN8811H_FW_CTRL_2_LOADING, ++ EN8811H_FW_CTRL_2_LOADING); + if (ret < 0) + goto en8811h_load_firmware_out; + @@ -493,11 +535,8 @@ Signed-off-by: Eric Woudstra + if (ret < 0) + goto en8811h_load_firmware_out; + -+ ret = air_buckpbus_reg_read(phydev, EN8811H_FW_CTRL_2, &pbus_value); -+ if (ret < 0) -+ goto en8811h_load_firmware_out; -+ pbus_value &= ~EN8811H_FW_CTRL_2_LOADING; -+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_2, pbus_value); ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, ++ EN8811H_FW_CTRL_2_LOADING, 0); + if (ret < 0) + goto en8811h_load_firmware_out; + @@ -506,7 +545,12 @@ Signed-off-by: Eric Woudstra + if (ret < 0) + goto en8811h_load_firmware_out; + -+ ret = 0; ++ ret = en8811h_wait_mcu_ready(phydev); ++ ++ air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, ++ &priv->firmware_version); ++ phydev_info(phydev, "MD32 firmware version: %08x\n", ++ priv->firmware_version); + +en8811h_load_firmware_out: + release_firmware(fw2); @@ -520,7 +564,7 @@ Signed-off-by: Eric Woudstra + return ret; +} + -+static int en8811h_restart_host(struct phy_device *phydev) ++static int en8811h_restart_mcu(struct phy_device *phydev) +{ + int ret; + @@ -529,8 +573,12 @@ Signed-off-by: Eric Woudstra + if (ret < 0) + return ret; + -+ return air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, ++ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_FINISH); ++ if (ret < 0) ++ return ret; ++ ++ return en8811h_wait_mcu_ready(phydev); +} + +static int air_hw_led_on_set(struct phy_device *phydev, u8 index, bool on) @@ -664,68 +712,46 @@ Signed-off-by: Eric Woudstra + u16 on = 0, blink = 0; + int ret; + -+ priv->led[index].rules = rules; -+ + if (index >= EN8811H_LED_COUNT) + return -EINVAL; + -+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) { ++ priv->led[index].rules = rules; ++ ++ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) ++ on |= AIR_PHY_LED_ON_FDX; ++ ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) + on |= AIR_PHY_LED_ON_LINK10; -+ if (rules & BIT(TRIGGER_NETDEV_RX)) -+ blink |= AIR_PHY_LED_BLINK_10RX; -+ if (rules & BIT(TRIGGER_NETDEV_TX)) -+ blink |= AIR_PHY_LED_BLINK_10TX; -+ } + -+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) { ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) + on |= AIR_PHY_LED_ON_LINK100; -+ if (rules & BIT(TRIGGER_NETDEV_RX)) -+ blink |= AIR_PHY_LED_BLINK_100RX; -+ if (rules & BIT(TRIGGER_NETDEV_TX)) -+ blink |= AIR_PHY_LED_BLINK_100TX; -+ } + -+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) { ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) + on |= AIR_PHY_LED_ON_LINK1000; -+ if (rules & BIT(TRIGGER_NETDEV_RX)) -+ blink |= AIR_PHY_LED_BLINK_1000RX; -+ if (rules & BIT(TRIGGER_NETDEV_TX)) -+ blink |= AIR_PHY_LED_BLINK_1000TX; -+ } + -+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) { ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) + on |= AIR_PHY_LED_ON_LINK2500; -+ if (rules & BIT(TRIGGER_NETDEV_RX)) -+ blink |= AIR_PHY_LED_BLINK_2500RX; -+ if (rules & BIT(TRIGGER_NETDEV_TX)) -+ blink |= AIR_PHY_LED_BLINK_2500TX; -+ } + -+ if (on == 0) { -+ if (rules & BIT(TRIGGER_NETDEV_RX)) { -+ blink |= AIR_PHY_LED_BLINK_10RX | -+ AIR_PHY_LED_BLINK_100RX | -+ AIR_PHY_LED_BLINK_1000RX | -+ AIR_PHY_LED_BLINK_2500RX; -+ } -+ if (rules & BIT(TRIGGER_NETDEV_TX)) { -+ blink |= AIR_PHY_LED_BLINK_10TX | -+ AIR_PHY_LED_BLINK_100TX | -+ AIR_PHY_LED_BLINK_1000TX | -+ AIR_PHY_LED_BLINK_2500TX; -+ } ++ if (rules & BIT(TRIGGER_NETDEV_RX)) { ++ blink |= AIR_PHY_LED_BLINK_10RX | ++ AIR_PHY_LED_BLINK_100RX | ++ AIR_PHY_LED_BLINK_1000RX | ++ AIR_PHY_LED_BLINK_2500RX; + } + -+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) -+ on |= AIR_PHY_LED_ON_FDX; -+ -+ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) -+ on |= AIR_PHY_LED_ON_HDX; ++ if (rules & BIT(TRIGGER_NETDEV_TX)) { ++ blink |= AIR_PHY_LED_BLINK_10TX | ++ AIR_PHY_LED_BLINK_100TX | ++ AIR_PHY_LED_BLINK_1000TX | ++ AIR_PHY_LED_BLINK_2500TX; ++ } + + if (blink || on) { + /* switch hw-control on, so led-on and led-blink are off */ -+ clear_bit(AIR_PHY_LED_STATE_FORCE_ON, &priv->led[index].state); -+ clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK, &priv->led[index].state); ++ clear_bit(AIR_PHY_LED_STATE_FORCE_ON, ++ &priv->led[index].state); ++ clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK, ++ &priv->led[index].state); + } else { + priv->led[index].rules = 0; + } @@ -742,28 +768,26 @@ Signed-off-by: Eric Woudstra + +static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol) +{ -+ int cl45_data; ++ int val = 0; + int err; + + if (index >= EN8811H_LED_COUNT) + return -EINVAL; + -+ cl45_data = phy_read_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index)); -+ if (cl45_data < 0) -+ return cl45_data; -+ + if (state == AIR_LED_ENABLE) -+ cl45_data |= AIR_PHY_LED_ON_ENABLE; ++ val |= AIR_PHY_LED_ON_ENABLE; + else -+ cl45_data &= ~AIR_PHY_LED_ON_ENABLE; ++ val &= ~AIR_PHY_LED_ON_ENABLE; + + if (pol == AIR_ACTIVE_HIGH) -+ cl45_data |= AIR_PHY_LED_ON_POLARITY; ++ val |= AIR_PHY_LED_ON_POLARITY; + else -+ cl45_data &= ~AIR_PHY_LED_ON_POLARITY; ++ val &= ~AIR_PHY_LED_ON_POLARITY; ++ ++ err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index), ++ AIR_PHY_LED_ON_ENABLE | ++ AIR_PHY_LED_ON_POLARITY, val); + -+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index), -+ cl45_data); + if (err < 0) + return err; + @@ -773,42 +797,40 @@ Signed-off-by: Eric Woudstra +static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode) +{ + struct en8811h_priv *priv = phydev->priv; -+ int cl45_data = dur; + int ret, i; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK, -+ cl45_data); ++ dur); + if (ret < 0) + return ret; + -+ cl45_data >>= 1; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_ON, -+ cl45_data); ++ dur >> 1); + if (ret < 0) + return ret; + -+ cl45_data = phy_read_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR); -+ if (cl45_data < 0) -+ return cl45_data; -+ + switch (mode) { + case AIR_LED_MODE_DISABLE: -+ cl45_data &= ~AIR_PHY_LED_BCR_EXT_CTRL; -+ cl45_data &= ~AIR_PHY_LED_BCR_MODE_MASK; ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_MODE_MASK, 0); ++ if (ret < 0) ++ return ret; + break; + case AIR_LED_MODE_USER_DEFINE: -+ cl45_data |= AIR_PHY_LED_BCR_EXT_CTRL; -+ cl45_data |= AIR_PHY_LED_BCR_CLK_EN; ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_CLK_EN, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_CLK_EN); ++ if (ret < 0) ++ return ret; + break; + default: + phydev_err(phydev, "LED mode %d is not supported\n", mode); + return -EINVAL; + } + -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, cl45_data); -+ if (ret < 0) -+ return ret; -+ + for (i = 0; i < num; ++i) { + ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH); + if (ret < 0) { @@ -837,21 +859,42 @@ Signed-off-by: Eric Woudstra +static int en8811h_probe(struct phy_device *phydev) +{ + struct en8811h_priv *priv; ++ int ret; + + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct en8811h_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; ++ phydev->priv = priv; ++ ++ ret = en8811h_load_firmware(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* mcu has just restarted after firmware load */ ++ priv->mcu_needs_restart = false; + + priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0; + priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1; + priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2; + -+ phydev->priv = priv; -+ + /* MDIO_DEVS1/2 empty, so set mmds_present bits here */ + phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; + ++ ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR, ++ AIR_LED_MODE_DISABLE); ++ if (ret < 0) { ++ phydev_err(phydev, "Failed to disable leds: %d\n", ret); ++ return ret; ++ } ++ ++ /* Configure led gpio pins as output */ ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT, ++ EN8811H_GPIO_OUTPUT_345, ++ EN8811H_GPIO_OUTPUT_345); ++ if (ret < 0) ++ return ret; ++ + return 0; +} + @@ -859,58 +902,41 @@ Signed-off-by: Eric Woudstra +{ + struct en8811h_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; -+ int ret, pollret, reg_value; + u32 pbus_value; ++ int ret; + -+ if (!priv->firmware_version) -+ ret = en8811h_load_firmware(phydev); -+ else -+ ret = en8811h_restart_host(phydev); -+ if (ret < 0) -+ return ret; -+ -+ /* Because of mdio-lock, may have to wait for multiple loads */ -+ pollret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, -+ EN8811H_PHY_FW_STATUS, reg_value, -+ reg_value == EN8811H_PHY_READY, -+ 20000, 7500000, true); -+ -+ ret = air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, &pbus_value); -+ if (ret < 0) -+ return ret; -+ -+ if (pollret || !pbus_value) { -+ phydev_err(phydev, "Firmware not ready: 0x%x\n", reg_value); -+ return -ENODEV; -+ } -+ -+ if (!priv->firmware_version) { -+ phydev_info(phydev, "MD32 firmware version: %08x\n", pbus_value); -+ priv->firmware_version = pbus_value; ++ /* If restart happened in .probe(), no need to restart now */ ++ if (priv->mcu_needs_restart) { ++ ret = en8811h_restart_mcu(phydev); ++ if (ret < 0) ++ return ret; ++ } else { ++ /* Next calls to .config_init() mcu needs to restart */ ++ priv->mcu_needs_restart = true; + } + -+ /* Select mode 1, the only mode supported */ -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_1, -+ AIR_PHY_HOST_CMD_1_MODE1); ++ /* Select mode 1, the only mode supported. ++ * Configures the SerDes for 2500Base-X with rate adaptation ++ */ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_1, ++ AIR_PHY_MCU_CMD_1_MODE1); + if (ret < 0) + return ret; -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_2, -+ AIR_PHY_HOST_CMD_2_MODE1); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_2, ++ AIR_PHY_MCU_CMD_2_MODE1); + if (ret < 0) + return ret; -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_3, -+ AIR_PHY_HOST_CMD_3_MODE1); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3, ++ AIR_PHY_MCU_CMD_3_MODE1); + if (ret < 0) + return ret; -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_4, -+ AIR_PHY_HOST_CMD_4_MODE1); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4, ++ AIR_PHY_MCU_CMD_4_MODE1); + if (ret < 0) + return ret; + + /* Serdes polarity */ -+ ret = air_buckpbus_reg_read(phydev, EN8811H_POLARITY, &pbus_value); -+ if (ret < 0) -+ return ret; ++ pbus_value = 0; + if (device_property_read_bool(dev, "airoha,pnswap-rx")) + pbus_value |= EN8811H_POLARITY_RX_REVERSE; + else @@ -919,7 +945,9 @@ Signed-off-by: Eric Woudstra + pbus_value &= ~EN8811H_POLARITY_TX_NORMAL; + else + pbus_value |= EN8811H_POLARITY_TX_NORMAL; -+ ret = air_buckpbus_reg_write(phydev, EN8811H_POLARITY, pbus_value); ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY, ++ EN8811H_POLARITY_RX_REVERSE | ++ EN8811H_POLARITY_TX_NORMAL, pbus_value); + if (ret < 0) + return ret; + @@ -930,14 +958,6 @@ Signed-off-by: Eric Woudstra + return ret; + } + -+ ret = air_buckpbus_reg_read(phydev, EN8811H_GPIO_OUTPUT, &pbus_value); -+ if (ret < 0) -+ return ret; -+ pbus_value |= EN8811H_GPIO_OUTPUT_345; -+ ret = air_buckpbus_reg_write(phydev, EN8811H_GPIO_OUTPUT, pbus_value); -+ if (ret < 0) -+ return ret; -+ + return 0; +} + @@ -959,17 +979,21 @@ Signed-off-by: Eric Woudstra +static int en8811h_config_aneg(struct phy_device *phydev) +{ + bool changed = false; -+ int err, val; -+ -+ val = 0; -+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, -+ phydev->advertising)) -+ val |= MDIO_AN_10GBT_CTRL_ADV2_5G; -+ err = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, -+ MDIO_AN_10GBT_CTRL_ADV2_5G, val); -+ if (err < 0) -+ return err; -+ if (err > 0) ++ int ret; ++ u32 adv; ++ ++ if (phydev->autoneg == AUTONEG_DISABLE) { ++ phydev_warn(phydev, "Disabling autoneg is not supported\n"); ++ return -EINVAL; ++ } ++ ++ adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); ++ ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, ++ MDIO_AN_10GBT_CTRL_ADV2_5G, adv); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) + changed = true; + + return __genphy_config_aneg(phydev, changed); @@ -991,6 +1015,7 @@ Signed-off-by: Eric Woudstra + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; ++ phydev->rate_matching = RATE_MATCH_PAUSE; + + ret = genphy_read_master_slave(phydev); + if (ret < 0) @@ -1008,7 +1033,7 @@ Signed-off-by: Eric Woudstra + phydev->lp_advertising, + pbus_value & EN8811H_2P5G_LPA_2P5G); + -+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) ++ if (phydev->autoneg_complete) + phy_resolve_aneg_pause(phydev); + + if (!phydev->link) @@ -1030,8 +1055,7 @@ Signed-off-by: Eric Woudstra + break; + } + -+ /* BUG in PHY firmware: MDIO_AN_10GBT_STAT_LP2_5G does not get set. -+ * Firmware before version 24011202 has no vendor register 2P5G_LPA. ++ /* Firmware before version 24011202 has no vendor register 2P5G_LPA. + * Assume link partner advertised it if connected at 2500Mbps. + */ + if (priv->firmware_version < 0x24011202) { @@ -1050,13 +1074,13 @@ Signed-off-by: Eric Woudstra +{ + int ret; + -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_3, -+ AIR_PHY_HOST_CMD_3_DOCMD); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3, ++ AIR_PHY_MCU_CMD_3_DOCMD); + if (ret < 0) + return ret; + -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_4, -+ AIR_PHY_HOST_CMD_4_INTCLR); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4, ++ AIR_PHY_MCU_CMD_4_INTCLR); + if (ret < 0) + return ret; + @@ -1105,6 +1129,7 @@ Signed-off-by: Eric Woudstra + { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) }, + { } +}; ++ +MODULE_DEVICE_TABLE(mdio, en8811h_tbl); +MODULE_FIRMWARE(EN8811H_MD32_DM); +MODULE_FIRMWARE(EN8811H_MD32_DSP); diff --git a/target/linux/generic/backport-6.1/799-v6.10-net-phy-air_en8811h-fix-some-error-codes.patch b/target/linux/generic/backport-6.1/799-v6.10-net-phy-air_en8811h-fix-some-error-codes.patch new file mode 100644 index 0000000000..1bd0eefe77 --- /dev/null +++ b/target/linux/generic/backport-6.1/799-v6.10-net-phy-air_en8811h-fix-some-error-codes.patch @@ -0,0 +1,47 @@ +From 87c33315af380ca12a2e59ac94edad4fe0481b4c Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Fri, 5 Apr 2024 13:08:59 +0300 +Subject: [PATCH] net: phy: air_en8811h: fix some error codes + +These error paths accidentally return "ret" which is zero/success +instead of the correct error code. + +Fixes: 71e79430117d ("net: phy: air_en8811h: Add the Airoha EN8811H PHY driver") +Signed-off-by: Dan Carpenter +Reviewed-by: Simon Horman +Link: https://lore.kernel.org/r/7ef2e230-dfb7-4a77-8973-9e5be1a99fc2@moroto.mountain +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/air_en8811h.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/phy/air_en8811h.c ++++ b/drivers/net/phy/air_en8811h.c +@@ -272,11 +272,11 @@ static int __air_buckpbus_reg_read(struc + + pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) +- return ret; ++ return pbus_data_high; + + pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) +- return ret; ++ return pbus_data_low; + + *pbus_data = pbus_data_low | (pbus_data_high << 16); + return 0; +@@ -323,11 +323,11 @@ static int __air_buckpbus_reg_modify(str + + pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) +- return ret; ++ return pbus_data_high; + + pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) +- return ret; ++ return pbus_data_low; + + pbus_data_old = pbus_data_low | (pbus_data_high << 16); + pbus_data_new = (pbus_data_old & ~mask) | set; diff --git a/target/linux/generic/backport-6.1/832-v6.7-net-phy-amd-Support-the-Altima-AMI101L.patch b/target/linux/generic/backport-6.1/832-v6.7-net-phy-amd-Support-the-Altima-AMI101L.patch index 2969462838..e8e73c1e5f 100644 --- a/target/linux/generic/backport-6.1/832-v6.7-net-phy-amd-Support-the-Altima-AMI101L.patch +++ b/target/linux/generic/backport-6.1/832-v6.7-net-phy-amd-Support-the-Altima-AMI101L.patch @@ -16,8 +16,8 @@ Signed-off-by: Linus Walleij --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -72,9 +72,9 @@ config SFP - comment "MII PHY device drivers" +@@ -77,9 +77,9 @@ config AIR_EN8811H_PHY + Currently supports the Airoha EN8811H PHY. config AMD_PHY - tristate "AMD PHYs" diff --git a/target/linux/generic/backport-6.6/301-v6.9-kernel.h-removed-REPEAT_BYTE-from-kernel.h.patch b/target/linux/generic/backport-6.6/301-v6.9-kernel.h-removed-REPEAT_BYTE-from-kernel.h.patch new file mode 100644 index 0000000000..adc924c09a --- /dev/null +++ b/target/linux/generic/backport-6.6/301-v6.9-kernel.h-removed-REPEAT_BYTE-from-kernel.h.patch @@ -0,0 +1,161 @@ +From 66a5c40f60f5d88ad8d47ba6a4ba05892853fa1f Mon Sep 17 00:00:00 2001 +From: Tanzir Hasan +Date: Tue, 26 Dec 2023 18:00:00 +0000 +Subject: [PATCH] kernel.h: removed REPEAT_BYTE from kernel.h + +This patch creates wordpart.h and includes it in asm/word-at-a-time.h +for all architectures. WORD_AT_A_TIME_CONSTANTS depends on kernel.h +because of REPEAT_BYTE. Moving this to another header and including it +where necessary allows us to not include the bloated kernel.h. Making +this implicit dependency on REPEAT_BYTE explicit allows for later +improvements in the lib/string.c inclusion list. + +Suggested-by: Al Viro +Suggested-by: Andy Shevchenko +Signed-off-by: Tanzir Hasan +Reviewed-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20231226-libstringheader-v6-1-80aa08c7652c@google.com +Signed-off-by: Kees Cook +--- + arch/arm/include/asm/word-at-a-time.h | 3 ++- + arch/arm64/include/asm/word-at-a-time.h | 3 ++- + arch/powerpc/include/asm/word-at-a-time.h | 4 ++-- + arch/riscv/include/asm/word-at-a-time.h | 3 ++- + arch/s390/include/asm/word-at-a-time.h | 3 ++- + arch/sh/include/asm/word-at-a-time.h | 2 ++ + arch/x86/include/asm/word-at-a-time.h | 3 ++- + arch/x86/kvm/mmu/mmu.c | 1 + + fs/namei.c | 2 +- + include/asm-generic/word-at-a-time.h | 3 ++- + include/linux/kernel.h | 8 -------- + include/linux/wordpart.h | 13 +++++++++++++ + 12 files changed, 31 insertions(+), 17 deletions(-) + create mode 100644 include/linux/wordpart.h + +--- a/arch/arm/include/asm/word-at-a-time.h ++++ b/arch/arm/include/asm/word-at-a-time.h +@@ -8,7 +8,8 @@ + * Little-endian word-at-a-time zero byte handling. + * Heavily based on the x86 algorithm. + */ +-#include ++#include ++#include + + struct word_at_a_time { + const unsigned long one_bits, high_bits; +--- a/arch/arm64/include/asm/word-at-a-time.h ++++ b/arch/arm64/include/asm/word-at-a-time.h +@@ -9,7 +9,8 @@ + + #ifndef __AARCH64EB__ + +-#include ++#include ++#include + + struct word_at_a_time { + const unsigned long one_bits, high_bits; +--- a/arch/powerpc/include/asm/word-at-a-time.h ++++ b/arch/powerpc/include/asm/word-at-a-time.h +@@ -4,8 +4,8 @@ + /* + * Word-at-a-time interfaces for PowerPC. + */ +- +-#include ++#include ++#include + #include + #include + +--- a/arch/sh/include/asm/word-at-a-time.h ++++ b/arch/sh/include/asm/word-at-a-time.h +@@ -5,6 +5,8 @@ + #ifdef CONFIG_CPU_BIG_ENDIAN + # include + #else ++#include ++#include + /* + * Little-endian version cribbed from x86. + */ +--- a/arch/x86/include/asm/word-at-a-time.h ++++ b/arch/x86/include/asm/word-at-a-time.h +@@ -2,7 +2,8 @@ + #ifndef _ASM_WORD_AT_A_TIME_H + #define _ASM_WORD_AT_A_TIME_H + +-#include ++#include ++#include + + /* + * This is largely generic for little-endian machines, but the +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + + #include + #include +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -17,8 +17,8 @@ + + #include + #include +-#include + #include ++#include + #include + #include + #include +--- a/include/asm-generic/word-at-a-time.h ++++ b/include/asm-generic/word-at-a-time.h +@@ -2,7 +2,8 @@ + #ifndef _ASM_WORD_AT_A_TIME_H + #define _ASM_WORD_AT_A_TIME_H + +-#include ++#include ++#include + #include + + #ifdef __BIG_ENDIAN +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -38,14 +38,6 @@ + + #define STACK_MAGIC 0xdeadbeef + +-/** +- * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value +- * @x: value to repeat +- * +- * NOTE: @x is not checked for > 0xff; larger values produce odd results. +- */ +-#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x)) +- + /* generic data direction definitions */ + #define READ 0 + #define WRITE 1 +--- /dev/null ++++ b/include/linux/wordpart.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef _LINUX_WORDPART_H ++#define _LINUX_WORDPART_H ++/** ++ * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value ++ * @x: value to repeat ++ * ++ * NOTE: @x is not checked for > 0xff; larger values produce odd results. ++ */ ++#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x)) ++ ++#endif // _LINUX_WORDPART_H diff --git a/target/linux/generic/backport-6.6/302-v6.9-kernel.h-Move-upper_-_bits-and-lower_-_bits-to-wordp.patch b/target/linux/generic/backport-6.6/302-v6.9-kernel.h-Move-upper_-_bits-and-lower_-_bits-to-wordp.patch new file mode 100644 index 0000000000..b9c40e6206 --- /dev/null +++ b/target/linux/generic/backport-6.6/302-v6.9-kernel.h-Move-upper_-_bits-and-lower_-_bits-to-wordp.patch @@ -0,0 +1,107 @@ +From adeb04362d74188c1e22ccb824b15a0a7b3de2f4 Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Wed, 14 Feb 2024 19:26:32 +0200 +Subject: [PATCH] kernel.h: Move upper_*_bits() and lower_*_bits() to + wordpart.h + +The wordpart.h header is collecting APIs related to the handling +parts of the word (usually in byte granularity). The upper_*_bits() +and lower_*_bits() are good candidates to be moved to there. + +This helps to clean up header dependency hell with regard to kernel.h +as the latter gathers completely unrelated stuff together and slows +down compilation (especially when it's included into other header). + +Signed-off-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20240214172752.3605073-1-andriy.shevchenko@linux.intel.com +Reviewed-by: Randy Dunlap +Signed-off-by: Kees Cook +--- + include/linux/kernel.h | 30 ++---------------------------- + include/linux/wordpart.h | 29 +++++++++++++++++++++++++++++ + 2 files changed, 31 insertions(+), 28 deletions(-) + +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -32,6 +32,8 @@ + #include + #include + #include ++#include ++ + #include + + #include +@@ -57,34 +59,6 @@ + } \ + ) + +-/** +- * upper_32_bits - return bits 32-63 of a number +- * @n: the number we're accessing +- * +- * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress +- * the "right shift count >= width of type" warning when that quantity is +- * 32-bits. +- */ +-#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) +- +-/** +- * lower_32_bits - return bits 0-31 of a number +- * @n: the number we're accessing +- */ +-#define lower_32_bits(n) ((u32)((n) & 0xffffffff)) +- +-/** +- * upper_16_bits - return bits 16-31 of a number +- * @n: the number we're accessing +- */ +-#define upper_16_bits(n) ((u16)((n) >> 16)) +- +-/** +- * lower_16_bits - return bits 0-15 of a number +- * @n: the number we're accessing +- */ +-#define lower_16_bits(n) ((u16)((n) & 0xffff)) +- + struct completion; + struct user; + +--- a/include/linux/wordpart.h ++++ b/include/linux/wordpart.h +@@ -2,6 +2,35 @@ + + #ifndef _LINUX_WORDPART_H + #define _LINUX_WORDPART_H ++ ++/** ++ * upper_32_bits - return bits 32-63 of a number ++ * @n: the number we're accessing ++ * ++ * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress ++ * the "right shift count >= width of type" warning when that quantity is ++ * 32-bits. ++ */ ++#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) ++ ++/** ++ * lower_32_bits - return bits 0-31 of a number ++ * @n: the number we're accessing ++ */ ++#define lower_32_bits(n) ((u32)((n) & 0xffffffff)) ++ ++/** ++ * upper_16_bits - return bits 16-31 of a number ++ * @n: the number we're accessing ++ */ ++#define upper_16_bits(n) ((u16)((n) >> 16)) ++ ++/** ++ * lower_16_bits - return bits 0-15 of a number ++ * @n: the number we're accessing ++ */ ++#define lower_16_bits(n) ((u16)((n) & 0xffff)) ++ + /** + * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value + * @x: value to repeat diff --git a/target/linux/generic/pending-6.6/750-net-phy-airoha-Add-the-Airoha-EN8811H-PHY-driver.patch b/target/linux/generic/backport-6.6/798-v6.10-net-phy-air_en8811h-Add-the-Airoha-EN8811H-PHY-drive.patch similarity index 61% rename from target/linux/generic/pending-6.6/750-net-phy-airoha-Add-the-Airoha-EN8811H-PHY-driver.patch rename to target/linux/generic/backport-6.6/798-v6.10-net-phy-air_en8811h-Add-the-Airoha-EN8811H-PHY-drive.patch index c811e40d49..5b627cf449 100644 --- a/target/linux/generic/pending-6.6/750-net-phy-airoha-Add-the-Airoha-EN8811H-PHY-driver.patch +++ b/target/linux/generic/backport-6.6/798-v6.10-net-phy-air_en8811h-Add-the-Airoha-EN8811H-PHY-drive.patch @@ -1,83 +1,28 @@ -From patchwork Tue Feb 6 19:47:51 2024 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -X-Patchwork-Submitter: Eric Woudstra -X-Patchwork-Id: 13547762 -X-Patchwork-Delegate: kuba@kernel.org +From 71e79430117d56c409c5ea485a263bc0d8083390 Mon Sep 17 00:00:00 2001 From: Eric Woudstra -To: "David S. Miller" , - Eric Dumazet , - Jakub Kicinski , - Paolo Abeni , - Rob Herring , - Krzysztof Kozlowski , - Conor Dooley , - Andrew Lunn , - Heiner Kallweit , - Russell King , - Matthias Brugger , - AngeloGioacchino Del Regno , - "Frank Wunderlich" , - Daniel Golle , - Lucien Jheng , - Zhi-Jun You -Cc: netdev@vger.kernel.org, - devicetree@vger.kernel.org, - Eric Woudstra -Subject: [PATCH net-next 2/2] net: phy: air_en8811h: Add the Airoha EN8811H - PHY driver -Date: Tue, 6 Feb 2024 20:47:51 +0100 -Message-ID: <20240206194751.1901802-3-ericwouds@gmail.com> -X-Mailer: git-send-email 2.42.1 -In-Reply-To: <20240206194751.1901802-1-ericwouds@gmail.com> -References: <20240206194751.1901802-1-ericwouds@gmail.com> -Precedence: bulk -X-Mailing-List: netdev@vger.kernel.org -List-Id: -List-Subscribe: -List-Unsubscribe: -MIME-Version: 1.0 -X-Patchwork-Delegate: kuba@kernel.org +Date: Tue, 26 Mar 2024 17:23:05 +0100 +Subject: [PATCH] net: phy: air_en8811h: Add the Airoha EN8811H PHY driver -* Source originated from airoha's en8811h v1.2.1 driver - * Moved air_en8811h.h to air_en8811h.c - * Removed air_pbus_reg_write() as it writes to another device on mdio-bus - * Load firmware from /lib/firmware/airoha/ instead of /lib/firmware/ - * Added .get_rate_matching() - * Use generic phy_read/write() and phy_read/write_mmd() - * Edited .get_features() to use generic C45 functions - * Edited .config_aneg() and .read_status() to use a mix of generic C22/C45 - * Use led handling functions from mediatek-ge-soc.c - * Simplified led handling by storing led rules - * Cleanup macro definitions - * Cleanup code to pass checkpatch.pl - * General code cleanup +Add the driver for the Airoha EN8811H 2.5 Gigabit PHY. The phy supports +100/1000/2500 Mbps with auto negotiation only. -Changes from original RFC patch: +The driver uses two firmware files, for which updated versions are added to +linux-firmware already. - * Use the correct order in Kconfig and Makefile - * Change some register naming to correspond with datasheet - * Use phy_driver .read_page() and .write_page() - * Use module_phy_driver() - * Use get_unaligned_le16() instead of macro - * In .config_aneg() and .read_status() use genphy_xxx() C22 - * Use another vendor register to read real speed - * Load firmware only once and store firmware version - * Apply 2.5G LPA work-around (firmware before 24011202) - * Read 2.5G LPA from vendor register (firmware 24011202 and later) - -Changes to be committed: - modified: drivers/net/phy/Kconfig - modified: drivers/net/phy/Makefile - new file: drivers/net/phy/air_en8811h.c +Note: At phy-address + 8 there is another device on the mdio bus, that +belongs to the EN881H. While the original driver writes to it, Airoha +has confirmed this is not needed. Therefore, communication with this +device is not included in this driver. Signed-off-by: Eric Woudstra +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/20240326162305.303598-3-ericwouds@gmail.com +Signed-off-by: Jakub Kicinski --- drivers/net/phy/Kconfig | 5 + drivers/net/phy/Makefile | 1 + - drivers/net/phy/air_en8811h.c | 1006 +++++++++++++++++++++++++++++++++ - 3 files changed, 1012 insertions(+) + drivers/net/phy/air_en8811h.c | 1086 +++++++++++++++++++++++++++++++++ + 3 files changed, 1092 insertions(+) create mode 100644 drivers/net/phy/air_en8811h.c --- a/drivers/net/phy/Kconfig @@ -92,7 +37,7 @@ Signed-off-by: Eric Woudstra + Currently supports the Airoha EN8811H PHY. + config AMD_PHY - tristate "AMD and Altima PHYs" + tristate "AMD PHYs" help --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -106,12 +51,10 @@ Signed-off-by: Eric Woudstra obj-$(CONFIG_AX88796B_PHY) += ax88796b.o --- /dev/null +++ b/drivers/net/phy/air_en8811h.c -@@ -0,0 +1,1006 @@ +@@ -0,0 +1,1086 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* -+ * Driver for Airoha Ethernet PHYs -+ * -+ * Currently supporting the EN8811H. ++ * Driver for the Airoha EN8811H 2.5 Gigabit PHY. + * + * Limitations of the EN8811H: + * - Only full duplex supported @@ -125,6 +68,7 @@ Signed-off-by: Eric Woudstra +#include +#include +#include ++#include +#include + +#define EN8811H_PHY_ID 0x03a2a411 @@ -135,12 +79,8 @@ Signed-off-by: Eric Woudstra +#define AIR_FW_ADDR_DM 0x00000000 +#define AIR_FW_ADDR_DSP 0x00100000 + -+/* u32 (DWORD) component macros */ -+#define LOWORD(d) ((u16)(u32)(d)) -+#define HIWORD(d) ((u16)(((u32)(d)) >> 16)) -+ +/* MII Registers */ -+#define AIR_AUX_CTRL_STATUS 0x1d ++#define AIR_AUX_CTRL_STATUS 0x1d +#define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2) +#define AIR_AUX_CTRL_STATUS_SPEED_100 0x4 +#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 @@ -151,32 +91,32 @@ Signed-off-by: Eric Woudstra +#define AIR_PHY_PAGE_EXTENDED_4 0x0004 + +/* MII Registers Page 4*/ -+#define AIR_PBUS_MODE 0x10 -+#define AIR_PBUS_MODE_ADDR_FIXED 0x0000 -+#define AIR_PBUS_MODE_ADDR_INCR BIT(15) -+#define AIR_PBUS_WR_ADDR_HIGH 0x11 -+#define AIR_PBUS_WR_ADDR_LOW 0x12 -+#define AIR_PBUS_WR_DATA_HIGH 0x13 -+#define AIR_PBUS_WR_DATA_LOW 0x14 -+#define AIR_PBUS_RD_ADDR_HIGH 0x15 -+#define AIR_PBUS_RD_ADDR_LOW 0x16 -+#define AIR_PBUS_RD_DATA_HIGH 0x17 -+#define AIR_PBUS_RD_DATA_LOW 0x18 ++#define AIR_BPBUS_MODE 0x10 ++#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000 ++#define AIR_BPBUS_MODE_ADDR_INCR BIT(15) ++#define AIR_BPBUS_WR_ADDR_HIGH 0x11 ++#define AIR_BPBUS_WR_ADDR_LOW 0x12 ++#define AIR_BPBUS_WR_DATA_HIGH 0x13 ++#define AIR_BPBUS_WR_DATA_LOW 0x14 ++#define AIR_BPBUS_RD_ADDR_HIGH 0x15 ++#define AIR_BPBUS_RD_ADDR_LOW 0x16 ++#define AIR_BPBUS_RD_DATA_HIGH 0x17 ++#define AIR_BPBUS_RD_DATA_LOW 0x18 + +/* Registers on MDIO_MMD_VEND1 */ +#define EN8811H_PHY_FW_STATUS 0x8009 +#define EN8811H_PHY_READY 0x02 + -+#define AIR_PHY_HOST_CMD_1 0x800c -+#define AIR_PHY_HOST_CMD_1_MODE1 0x0 -+#define AIR_PHY_HOST_CMD_2 0x800d -+#define AIR_PHY_HOST_CMD_2_MODE1 0x0 -+#define AIR_PHY_HOST_CMD_3 0x800e -+#define AIR_PHY_HOST_CMD_3_MODE1 0x1101 -+#define AIR_PHY_HOST_CMD_3_DOCMD 0x1100 -+#define AIR_PHY_HOST_CMD_4 0x800f -+#define AIR_PHY_HOST_CMD_4_MODE1 0x0002 -+#define AIR_PHY_HOST_CMD_4_INTCLR 0x00e4 ++#define AIR_PHY_MCU_CMD_1 0x800c ++#define AIR_PHY_MCU_CMD_1_MODE1 0x0 ++#define AIR_PHY_MCU_CMD_2 0x800d ++#define AIR_PHY_MCU_CMD_2_MODE1 0x0 ++#define AIR_PHY_MCU_CMD_3 0x800e ++#define AIR_PHY_MCU_CMD_3_MODE1 0x1101 ++#define AIR_PHY_MCU_CMD_3_DOCMD 0x1100 ++#define AIR_PHY_MCU_CMD_4 0x800f ++#define AIR_PHY_MCU_CMD_4_MODE1 0x0002 ++#define AIR_PHY_MCU_CMD_4_INTCLR 0x00e4 + +/* Registers on MDIO_MMD_VEND2 */ +#define AIR_PHY_LED_BCR 0x021 @@ -235,28 +175,21 @@ Signed-off-by: Eric Woudstra +#define EN8811H_FW_CTRL_2 0x800000 +#define EN8811H_FW_CTRL_2_LOADING BIT(11) + ++/* Led definitions */ +#define EN8811H_LED_COUNT 3 + -+/* GPIO5 <-> BASE_T_LED0 -+ * GPIO4 <-> BASE_T_LED1 -+ * GPIO3 <-> BASE_T_LED2 -+ * -+ * Default setup suitable for 2 leds connected: -+ * 100M link up triggers led0, only led0 blinking on traffic -+ * 1000M link up triggers led1, only led1 blinking on traffic -+ * 2500M link up triggers led0 and led1, both blinking on traffic -+ * Also suitable for 1 led connected: -+ * any link up triggers led2 ++/* Default LED setup: ++ * GPIO5 <-> LED0 On: Link detected, blink Rx/Tx ++ * GPIO4 <-> LED1 On: Link detected at 2500 or 1000 Mbps ++ * GPIO3 <-> LED2 On: Link detected at 2500 or 100 Mbps + */ -+#define AIR_DEFAULT_TRIGGER_LED0 (BIT(TRIGGER_NETDEV_LINK_2500) | \ -+ BIT(TRIGGER_NETDEV_LINK_100) | \ ++#define AIR_DEFAULT_TRIGGER_LED0 (BIT(TRIGGER_NETDEV_LINK) | \ + BIT(TRIGGER_NETDEV_RX) | \ + BIT(TRIGGER_NETDEV_TX)) +#define AIR_DEFAULT_TRIGGER_LED1 (BIT(TRIGGER_NETDEV_LINK_2500) | \ -+ BIT(TRIGGER_NETDEV_LINK_1000) | \ -+ BIT(TRIGGER_NETDEV_RX) | \ -+ BIT(TRIGGER_NETDEV_TX)) -+#define AIR_DEFAULT_TRIGGER_LED2 BIT(TRIGGER_NETDEV_LINK) ++ BIT(TRIGGER_NETDEV_LINK_1000)) ++#define AIR_DEFAULT_TRIGGER_LED2 (BIT(TRIGGER_NETDEV_LINK_2500) | \ ++ BIT(TRIGGER_NETDEV_LINK_100)) + +struct led { + unsigned long rules; @@ -265,6 +198,7 @@ Signed-off-by: Eric Woudstra + +struct en8811h_priv { + u32 firmware_version; ++ bool mcu_needs_restart; + struct led led[EN8811H_LED_COUNT]; +}; + @@ -274,12 +208,12 @@ Signed-off-by: Eric Woudstra +}; + +enum { -+ AIR_PHY_LED_DUR_BLINK_32M, -+ AIR_PHY_LED_DUR_BLINK_64M, -+ AIR_PHY_LED_DUR_BLINK_128M, -+ AIR_PHY_LED_DUR_BLINK_256M, -+ AIR_PHY_LED_DUR_BLINK_512M, -+ AIR_PHY_LED_DUR_BLINK_1024M, ++ AIR_PHY_LED_DUR_BLINK_32MS, ++ AIR_PHY_LED_DUR_BLINK_64MS, ++ AIR_PHY_LED_DUR_BLINK_128MS, ++ AIR_PHY_LED_DUR_BLINK_256MS, ++ AIR_PHY_LED_DUR_BLINK_512MS, ++ AIR_PHY_LED_DUR_BLINK_1024MS, +}; + +enum { @@ -298,16 +232,16 @@ Signed-off-by: Eric Woudstra +}; + +#define AIR_PHY_LED_DUR_UNIT 1024 -+#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64M) ++#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS) + -+static const unsigned long en8811h_led_trig = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) | -+ BIT(TRIGGER_NETDEV_LINK) | -+ BIT(TRIGGER_NETDEV_LINK_10) | -+ BIT(TRIGGER_NETDEV_LINK_100) | -+ BIT(TRIGGER_NETDEV_LINK_1000) | -+ BIT(TRIGGER_NETDEV_LINK_2500) | -+ BIT(TRIGGER_NETDEV_RX) | -+ BIT(TRIGGER_NETDEV_TX)); ++static const unsigned long en8811h_led_trig = BIT(TRIGGER_NETDEV_FULL_DUPLEX) | ++ BIT(TRIGGER_NETDEV_LINK) | ++ BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_LINK_2500) | ++ BIT(TRIGGER_NETDEV_RX) | ++ BIT(TRIGGER_NETDEV_TX); + +static int air_phy_read_page(struct phy_device *phydev) +{ @@ -324,23 +258,27 @@ Signed-off-by: Eric Woudstra +{ + int ret; + -+ ret = __phy_write(phydev, AIR_PBUS_MODE, AIR_PBUS_MODE_ADDR_FIXED); ++ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_ADDR_HIGH, HIWORD(pbus_address)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, ++ upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_ADDR_LOW, LOWORD(pbus_address)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, ++ lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_DATA_HIGH, HIWORD(pbus_data)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, ++ upper_16_bits(pbus_data)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_DATA_LOW, LOWORD(pbus_data)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, ++ lower_16_bits(pbus_data)); + if (ret < 0) + return ret; + @@ -350,17 +288,20 @@ Signed-off-by: Eric Woudstra +static int air_buckpbus_reg_write(struct phy_device *phydev, + u32 pbus_address, u32 pbus_data) +{ -+ int ret, saved_page; ++ int saved_page; ++ int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + -+ ret = __air_buckpbus_reg_write(phydev, pbus_address, pbus_data); -+ if (ret < 0) -+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, -+ pbus_address, ret); ++ if (saved_page >= 0) { ++ ret = __air_buckpbus_reg_write(phydev, pbus_address, ++ pbus_data); ++ if (ret < 0) ++ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ } + + return phy_restore_page(phydev, saved_page, ret); -+; +} + +static int __air_buckpbus_reg_read(struct phy_device *phydev, @@ -369,41 +310,122 @@ Signed-off-by: Eric Woudstra + int pbus_data_low, pbus_data_high; + int ret; + -+ ret = __phy_write(phydev, AIR_PBUS_MODE, AIR_PBUS_MODE_ADDR_FIXED); ++ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_RD_ADDR_HIGH, HIWORD(pbus_address)); ++ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, ++ upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_RD_ADDR_LOW, LOWORD(pbus_address)); ++ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, ++ lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + -+ pbus_data_high = __phy_read(phydev, AIR_PBUS_RD_DATA_HIGH); ++ pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) + return ret; + -+ pbus_data_low = __phy_read(phydev, AIR_PBUS_RD_DATA_LOW); ++ pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) + return ret; + -+ *pbus_data = (u16)pbus_data_low | ((u32)(u16)pbus_data_high << 16); ++ *pbus_data = pbus_data_low | (pbus_data_high << 16); + return 0; +} + +static int air_buckpbus_reg_read(struct phy_device *phydev, + u32 pbus_address, u32 *pbus_data) +{ -+ int ret, saved_page; ++ int saved_page; ++ int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + -+ ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); ++ if (saved_page >= 0) { ++ ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); ++ if (ret < 0) ++ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ } ++ ++ return phy_restore_page(phydev, saved_page, ret); ++} ++ ++static int __air_buckpbus_reg_modify(struct phy_device *phydev, ++ u32 pbus_address, u32 mask, u32 set) ++{ ++ int pbus_data_low, pbus_data_high; ++ u32 pbus_data_old, pbus_data_new; ++ int ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); ++ if (ret < 0) ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, ++ upper_16_bits(pbus_address)); ++ if (ret < 0) ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, ++ lower_16_bits(pbus_address)); ++ if (ret < 0) ++ return ret; ++ ++ pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); ++ if (pbus_data_high < 0) ++ return ret; ++ ++ pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); ++ if (pbus_data_low < 0) ++ return ret; ++ ++ pbus_data_old = pbus_data_low | (pbus_data_high << 16); ++ pbus_data_new = (pbus_data_old & ~mask) | set; ++ if (pbus_data_new == pbus_data_old) ++ return 0; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, ++ upper_16_bits(pbus_address)); + if (ret < 0) -+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, -+ pbus_address, ret); ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, ++ lower_16_bits(pbus_address)); ++ if (ret < 0) ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, ++ upper_16_bits(pbus_data_new)); ++ if (ret < 0) ++ return ret; ++ ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, ++ lower_16_bits(pbus_data_new)); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int air_buckpbus_reg_modify(struct phy_device *phydev, ++ u32 pbus_address, u32 mask, u32 set) ++{ ++ int saved_page; ++ int ret = 0; ++ ++ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); ++ ++ if (saved_page >= 0) { ++ ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask, ++ set); ++ if (ret < 0) ++ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ } + + return phy_restore_page(phydev, saved_page, ret); +} @@ -415,26 +437,28 @@ Signed-off-by: Eric Woudstra + int ret; + u16 val; + -+ ret = __phy_write(phydev, AIR_PBUS_MODE, AIR_PBUS_MODE_ADDR_INCR); ++ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_ADDR_HIGH, HIWORD(address)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, ++ upper_16_bits(address)); + if (ret < 0) + return ret; + -+ ret = __phy_write(phydev, AIR_PBUS_WR_ADDR_LOW, LOWORD(address)); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, ++ lower_16_bits(address)); + if (ret < 0) + return ret; + + for (offset = 0; offset < fw->size; offset += 4) { + val = get_unaligned_le16(&fw->data[offset + 2]); -+ ret = __phy_write(phydev, AIR_PBUS_WR_DATA_HIGH, val); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, val); + if (ret < 0) + return ret; + + val = get_unaligned_le16(&fw->data[offset]); -+ ret = __phy_write(phydev, AIR_PBUS_WR_DATA_LOW, val); ++ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, val); + if (ret < 0) + return ret; + } @@ -445,23 +469,43 @@ Signed-off-by: Eric Woudstra +static int air_write_buf(struct phy_device *phydev, u32 address, + const struct firmware *fw) +{ -+ int ret, saved_page; ++ int saved_page; ++ int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + -+ ret = __air_write_buf(phydev, address, fw); -+ if (ret < 0) -+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, -+ address, ret); ++ if (saved_page >= 0) { ++ ret = __air_write_buf(phydev, address, fw); ++ if (ret < 0) ++ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, ++ address, ret); ++ } + + return phy_restore_page(phydev, saved_page, ret); +} + ++static int en8811h_wait_mcu_ready(struct phy_device *phydev) ++{ ++ int ret, reg_value; ++ ++ /* Because of mdio-lock, may have to wait for multiple loads */ ++ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ++ EN8811H_PHY_FW_STATUS, reg_value, ++ reg_value == EN8811H_PHY_READY, ++ 20000, 7500000, true); ++ if (ret) { ++ phydev_err(phydev, "MCU not ready: 0x%x\n", reg_value); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ +static int en8811h_load_firmware(struct phy_device *phydev) +{ ++ struct en8811h_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + const struct firmware *fw1, *fw2; -+ u32 pbus_value; + int ret; + + ret = request_firmware_direct(&fw1, EN8811H_MD32_DM, dev); @@ -477,11 +521,9 @@ Signed-off-by: Eric Woudstra + if (ret < 0) + goto en8811h_load_firmware_out; + -+ ret = air_buckpbus_reg_read(phydev, EN8811H_FW_CTRL_2, &pbus_value); -+ if (ret < 0) -+ goto en8811h_load_firmware_out; -+ pbus_value |= EN8811H_FW_CTRL_2_LOADING; -+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_2, pbus_value); ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, ++ EN8811H_FW_CTRL_2_LOADING, ++ EN8811H_FW_CTRL_2_LOADING); + if (ret < 0) + goto en8811h_load_firmware_out; + @@ -493,11 +535,8 @@ Signed-off-by: Eric Woudstra + if (ret < 0) + goto en8811h_load_firmware_out; + -+ ret = air_buckpbus_reg_read(phydev, EN8811H_FW_CTRL_2, &pbus_value); -+ if (ret < 0) -+ goto en8811h_load_firmware_out; -+ pbus_value &= ~EN8811H_FW_CTRL_2_LOADING; -+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_2, pbus_value); ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, ++ EN8811H_FW_CTRL_2_LOADING, 0); + if (ret < 0) + goto en8811h_load_firmware_out; + @@ -506,7 +545,12 @@ Signed-off-by: Eric Woudstra + if (ret < 0) + goto en8811h_load_firmware_out; + -+ ret = 0; ++ ret = en8811h_wait_mcu_ready(phydev); ++ ++ air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, ++ &priv->firmware_version); ++ phydev_info(phydev, "MD32 firmware version: %08x\n", ++ priv->firmware_version); + +en8811h_load_firmware_out: + release_firmware(fw2); @@ -520,7 +564,7 @@ Signed-off-by: Eric Woudstra + return ret; +} + -+static int en8811h_restart_host(struct phy_device *phydev) ++static int en8811h_restart_mcu(struct phy_device *phydev) +{ + int ret; + @@ -529,8 +573,12 @@ Signed-off-by: Eric Woudstra + if (ret < 0) + return ret; + -+ return air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, ++ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_FINISH); ++ if (ret < 0) ++ return ret; ++ ++ return en8811h_wait_mcu_ready(phydev); +} + +static int air_hw_led_on_set(struct phy_device *phydev, u8 index, bool on) @@ -664,68 +712,46 @@ Signed-off-by: Eric Woudstra + u16 on = 0, blink = 0; + int ret; + -+ priv->led[index].rules = rules; -+ + if (index >= EN8811H_LED_COUNT) + return -EINVAL; + -+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) { ++ priv->led[index].rules = rules; ++ ++ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) ++ on |= AIR_PHY_LED_ON_FDX; ++ ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) + on |= AIR_PHY_LED_ON_LINK10; -+ if (rules & BIT(TRIGGER_NETDEV_RX)) -+ blink |= AIR_PHY_LED_BLINK_10RX; -+ if (rules & BIT(TRIGGER_NETDEV_TX)) -+ blink |= AIR_PHY_LED_BLINK_10TX; -+ } + -+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) { ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) + on |= AIR_PHY_LED_ON_LINK100; -+ if (rules & BIT(TRIGGER_NETDEV_RX)) -+ blink |= AIR_PHY_LED_BLINK_100RX; -+ if (rules & BIT(TRIGGER_NETDEV_TX)) -+ blink |= AIR_PHY_LED_BLINK_100TX; -+ } + -+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) { ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) + on |= AIR_PHY_LED_ON_LINK1000; -+ if (rules & BIT(TRIGGER_NETDEV_RX)) -+ blink |= AIR_PHY_LED_BLINK_1000RX; -+ if (rules & BIT(TRIGGER_NETDEV_TX)) -+ blink |= AIR_PHY_LED_BLINK_1000TX; -+ } + -+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) { ++ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) + on |= AIR_PHY_LED_ON_LINK2500; -+ if (rules & BIT(TRIGGER_NETDEV_RX)) -+ blink |= AIR_PHY_LED_BLINK_2500RX; -+ if (rules & BIT(TRIGGER_NETDEV_TX)) -+ blink |= AIR_PHY_LED_BLINK_2500TX; -+ } + -+ if (on == 0) { -+ if (rules & BIT(TRIGGER_NETDEV_RX)) { -+ blink |= AIR_PHY_LED_BLINK_10RX | -+ AIR_PHY_LED_BLINK_100RX | -+ AIR_PHY_LED_BLINK_1000RX | -+ AIR_PHY_LED_BLINK_2500RX; -+ } -+ if (rules & BIT(TRIGGER_NETDEV_TX)) { -+ blink |= AIR_PHY_LED_BLINK_10TX | -+ AIR_PHY_LED_BLINK_100TX | -+ AIR_PHY_LED_BLINK_1000TX | -+ AIR_PHY_LED_BLINK_2500TX; -+ } ++ if (rules & BIT(TRIGGER_NETDEV_RX)) { ++ blink |= AIR_PHY_LED_BLINK_10RX | ++ AIR_PHY_LED_BLINK_100RX | ++ AIR_PHY_LED_BLINK_1000RX | ++ AIR_PHY_LED_BLINK_2500RX; + } + -+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) -+ on |= AIR_PHY_LED_ON_FDX; -+ -+ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) -+ on |= AIR_PHY_LED_ON_HDX; ++ if (rules & BIT(TRIGGER_NETDEV_TX)) { ++ blink |= AIR_PHY_LED_BLINK_10TX | ++ AIR_PHY_LED_BLINK_100TX | ++ AIR_PHY_LED_BLINK_1000TX | ++ AIR_PHY_LED_BLINK_2500TX; ++ } + + if (blink || on) { + /* switch hw-control on, so led-on and led-blink are off */ -+ clear_bit(AIR_PHY_LED_STATE_FORCE_ON, &priv->led[index].state); -+ clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK, &priv->led[index].state); ++ clear_bit(AIR_PHY_LED_STATE_FORCE_ON, ++ &priv->led[index].state); ++ clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK, ++ &priv->led[index].state); + } else { + priv->led[index].rules = 0; + } @@ -742,28 +768,26 @@ Signed-off-by: Eric Woudstra + +static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol) +{ -+ int cl45_data; ++ int val = 0; + int err; + + if (index >= EN8811H_LED_COUNT) + return -EINVAL; + -+ cl45_data = phy_read_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index)); -+ if (cl45_data < 0) -+ return cl45_data; -+ + if (state == AIR_LED_ENABLE) -+ cl45_data |= AIR_PHY_LED_ON_ENABLE; ++ val |= AIR_PHY_LED_ON_ENABLE; + else -+ cl45_data &= ~AIR_PHY_LED_ON_ENABLE; ++ val &= ~AIR_PHY_LED_ON_ENABLE; + + if (pol == AIR_ACTIVE_HIGH) -+ cl45_data |= AIR_PHY_LED_ON_POLARITY; ++ val |= AIR_PHY_LED_ON_POLARITY; + else -+ cl45_data &= ~AIR_PHY_LED_ON_POLARITY; ++ val &= ~AIR_PHY_LED_ON_POLARITY; ++ ++ err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index), ++ AIR_PHY_LED_ON_ENABLE | ++ AIR_PHY_LED_ON_POLARITY, val); + -+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index), -+ cl45_data); + if (err < 0) + return err; + @@ -773,42 +797,40 @@ Signed-off-by: Eric Woudstra +static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode) +{ + struct en8811h_priv *priv = phydev->priv; -+ int cl45_data = dur; + int ret, i; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK, -+ cl45_data); ++ dur); + if (ret < 0) + return ret; + -+ cl45_data >>= 1; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_ON, -+ cl45_data); ++ dur >> 1); + if (ret < 0) + return ret; + -+ cl45_data = phy_read_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR); -+ if (cl45_data < 0) -+ return cl45_data; -+ + switch (mode) { + case AIR_LED_MODE_DISABLE: -+ cl45_data &= ~AIR_PHY_LED_BCR_EXT_CTRL; -+ cl45_data &= ~AIR_PHY_LED_BCR_MODE_MASK; ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_MODE_MASK, 0); ++ if (ret < 0) ++ return ret; + break; + case AIR_LED_MODE_USER_DEFINE: -+ cl45_data |= AIR_PHY_LED_BCR_EXT_CTRL; -+ cl45_data |= AIR_PHY_LED_BCR_CLK_EN; ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_CLK_EN, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_CLK_EN); ++ if (ret < 0) ++ return ret; + break; + default: + phydev_err(phydev, "LED mode %d is not supported\n", mode); + return -EINVAL; + } + -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, cl45_data); -+ if (ret < 0) -+ return ret; -+ + for (i = 0; i < num; ++i) { + ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH); + if (ret < 0) { @@ -837,21 +859,42 @@ Signed-off-by: Eric Woudstra +static int en8811h_probe(struct phy_device *phydev) +{ + struct en8811h_priv *priv; ++ int ret; + + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct en8811h_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; ++ phydev->priv = priv; ++ ++ ret = en8811h_load_firmware(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* mcu has just restarted after firmware load */ ++ priv->mcu_needs_restart = false; + + priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0; + priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1; + priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2; + -+ phydev->priv = priv; -+ + /* MDIO_DEVS1/2 empty, so set mmds_present bits here */ + phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; + ++ ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR, ++ AIR_LED_MODE_DISABLE); ++ if (ret < 0) { ++ phydev_err(phydev, "Failed to disable leds: %d\n", ret); ++ return ret; ++ } ++ ++ /* Configure led gpio pins as output */ ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT, ++ EN8811H_GPIO_OUTPUT_345, ++ EN8811H_GPIO_OUTPUT_345); ++ if (ret < 0) ++ return ret; ++ + return 0; +} + @@ -859,58 +902,41 @@ Signed-off-by: Eric Woudstra +{ + struct en8811h_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; -+ int ret, pollret, reg_value; + u32 pbus_value; ++ int ret; + -+ if (!priv->firmware_version) -+ ret = en8811h_load_firmware(phydev); -+ else -+ ret = en8811h_restart_host(phydev); -+ if (ret < 0) -+ return ret; -+ -+ /* Because of mdio-lock, may have to wait for multiple loads */ -+ pollret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, -+ EN8811H_PHY_FW_STATUS, reg_value, -+ reg_value == EN8811H_PHY_READY, -+ 20000, 7500000, true); -+ -+ ret = air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, &pbus_value); -+ if (ret < 0) -+ return ret; -+ -+ if (pollret || !pbus_value) { -+ phydev_err(phydev, "Firmware not ready: 0x%x\n", reg_value); -+ return -ENODEV; -+ } -+ -+ if (!priv->firmware_version) { -+ phydev_info(phydev, "MD32 firmware version: %08x\n", pbus_value); -+ priv->firmware_version = pbus_value; ++ /* If restart happened in .probe(), no need to restart now */ ++ if (priv->mcu_needs_restart) { ++ ret = en8811h_restart_mcu(phydev); ++ if (ret < 0) ++ return ret; ++ } else { ++ /* Next calls to .config_init() mcu needs to restart */ ++ priv->mcu_needs_restart = true; + } + -+ /* Select mode 1, the only mode supported */ -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_1, -+ AIR_PHY_HOST_CMD_1_MODE1); ++ /* Select mode 1, the only mode supported. ++ * Configures the SerDes for 2500Base-X with rate adaptation ++ */ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_1, ++ AIR_PHY_MCU_CMD_1_MODE1); + if (ret < 0) + return ret; -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_2, -+ AIR_PHY_HOST_CMD_2_MODE1); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_2, ++ AIR_PHY_MCU_CMD_2_MODE1); + if (ret < 0) + return ret; -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_3, -+ AIR_PHY_HOST_CMD_3_MODE1); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3, ++ AIR_PHY_MCU_CMD_3_MODE1); + if (ret < 0) + return ret; -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_4, -+ AIR_PHY_HOST_CMD_4_MODE1); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4, ++ AIR_PHY_MCU_CMD_4_MODE1); + if (ret < 0) + return ret; + + /* Serdes polarity */ -+ ret = air_buckpbus_reg_read(phydev, EN8811H_POLARITY, &pbus_value); -+ if (ret < 0) -+ return ret; ++ pbus_value = 0; + if (device_property_read_bool(dev, "airoha,pnswap-rx")) + pbus_value |= EN8811H_POLARITY_RX_REVERSE; + else @@ -919,7 +945,9 @@ Signed-off-by: Eric Woudstra + pbus_value &= ~EN8811H_POLARITY_TX_NORMAL; + else + pbus_value |= EN8811H_POLARITY_TX_NORMAL; -+ ret = air_buckpbus_reg_write(phydev, EN8811H_POLARITY, pbus_value); ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY, ++ EN8811H_POLARITY_RX_REVERSE | ++ EN8811H_POLARITY_TX_NORMAL, pbus_value); + if (ret < 0) + return ret; + @@ -930,14 +958,6 @@ Signed-off-by: Eric Woudstra + return ret; + } + -+ ret = air_buckpbus_reg_read(phydev, EN8811H_GPIO_OUTPUT, &pbus_value); -+ if (ret < 0) -+ return ret; -+ pbus_value |= EN8811H_GPIO_OUTPUT_345; -+ ret = air_buckpbus_reg_write(phydev, EN8811H_GPIO_OUTPUT, pbus_value); -+ if (ret < 0) -+ return ret; -+ + return 0; +} + @@ -959,17 +979,21 @@ Signed-off-by: Eric Woudstra +static int en8811h_config_aneg(struct phy_device *phydev) +{ + bool changed = false; -+ int err, val; -+ -+ val = 0; -+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, -+ phydev->advertising)) -+ val |= MDIO_AN_10GBT_CTRL_ADV2_5G; -+ err = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, -+ MDIO_AN_10GBT_CTRL_ADV2_5G, val); -+ if (err < 0) -+ return err; -+ if (err > 0) ++ int ret; ++ u32 adv; ++ ++ if (phydev->autoneg == AUTONEG_DISABLE) { ++ phydev_warn(phydev, "Disabling autoneg is not supported\n"); ++ return -EINVAL; ++ } ++ ++ adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); ++ ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, ++ MDIO_AN_10GBT_CTRL_ADV2_5G, adv); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) + changed = true; + + return __genphy_config_aneg(phydev, changed); @@ -991,6 +1015,7 @@ Signed-off-by: Eric Woudstra + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; ++ phydev->rate_matching = RATE_MATCH_PAUSE; + + ret = genphy_read_master_slave(phydev); + if (ret < 0) @@ -1008,7 +1033,7 @@ Signed-off-by: Eric Woudstra + phydev->lp_advertising, + pbus_value & EN8811H_2P5G_LPA_2P5G); + -+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) ++ if (phydev->autoneg_complete) + phy_resolve_aneg_pause(phydev); + + if (!phydev->link) @@ -1030,8 +1055,7 @@ Signed-off-by: Eric Woudstra + break; + } + -+ /* BUG in PHY firmware: MDIO_AN_10GBT_STAT_LP2_5G does not get set. -+ * Firmware before version 24011202 has no vendor register 2P5G_LPA. ++ /* Firmware before version 24011202 has no vendor register 2P5G_LPA. + * Assume link partner advertised it if connected at 2500Mbps. + */ + if (priv->firmware_version < 0x24011202) { @@ -1050,13 +1074,13 @@ Signed-off-by: Eric Woudstra +{ + int ret; + -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_3, -+ AIR_PHY_HOST_CMD_3_DOCMD); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3, ++ AIR_PHY_MCU_CMD_3_DOCMD); + if (ret < 0) + return ret; + -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_4, -+ AIR_PHY_HOST_CMD_4_INTCLR); ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4, ++ AIR_PHY_MCU_CMD_4_INTCLR); + if (ret < 0) + return ret; + @@ -1105,6 +1129,7 @@ Signed-off-by: Eric Woudstra + { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) }, + { } +}; ++ +MODULE_DEVICE_TABLE(mdio, en8811h_tbl); +MODULE_FIRMWARE(EN8811H_MD32_DM); +MODULE_FIRMWARE(EN8811H_MD32_DSP); diff --git a/target/linux/generic/backport-6.6/799-v6.10-net-phy-air_en8811h-fix-some-error-codes.patch b/target/linux/generic/backport-6.6/799-v6.10-net-phy-air_en8811h-fix-some-error-codes.patch new file mode 100644 index 0000000000..1bd0eefe77 --- /dev/null +++ b/target/linux/generic/backport-6.6/799-v6.10-net-phy-air_en8811h-fix-some-error-codes.patch @@ -0,0 +1,47 @@ +From 87c33315af380ca12a2e59ac94edad4fe0481b4c Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Fri, 5 Apr 2024 13:08:59 +0300 +Subject: [PATCH] net: phy: air_en8811h: fix some error codes + +These error paths accidentally return "ret" which is zero/success +instead of the correct error code. + +Fixes: 71e79430117d ("net: phy: air_en8811h: Add the Airoha EN8811H PHY driver") +Signed-off-by: Dan Carpenter +Reviewed-by: Simon Horman +Link: https://lore.kernel.org/r/7ef2e230-dfb7-4a77-8973-9e5be1a99fc2@moroto.mountain +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/air_en8811h.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/phy/air_en8811h.c ++++ b/drivers/net/phy/air_en8811h.c +@@ -272,11 +272,11 @@ static int __air_buckpbus_reg_read(struc + + pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) +- return ret; ++ return pbus_data_high; + + pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) +- return ret; ++ return pbus_data_low; + + *pbus_data = pbus_data_low | (pbus_data_high << 16); + return 0; +@@ -323,11 +323,11 @@ static int __air_buckpbus_reg_modify(str + + pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) +- return ret; ++ return pbus_data_high; + + pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) +- return ret; ++ return pbus_data_low; + + pbus_data_old = pbus_data_low | (pbus_data_high << 16); + pbus_data_new = (pbus_data_old & ~mask) | set; diff --git a/target/linux/generic/backport-6.6/832-v6.7-net-phy-amd-Support-the-Altima-AMI101L.patch b/target/linux/generic/backport-6.6/832-v6.7-net-phy-amd-Support-the-Altima-AMI101L.patch index fa2056b69a..07287206f6 100644 --- a/target/linux/generic/backport-6.6/832-v6.7-net-phy-amd-Support-the-Altima-AMI101L.patch +++ b/target/linux/generic/backport-6.6/832-v6.7-net-phy-amd-Support-the-Altima-AMI101L.patch @@ -16,8 +16,8 @@ Signed-off-by: Linus Walleij --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -69,9 +69,9 @@ config SFP - comment "MII PHY device drivers" +@@ -74,9 +74,9 @@ config AIR_EN8811H_PHY + Currently supports the Airoha EN8811H PHY. config AMD_PHY - tristate "AMD PHYs" diff --git a/target/linux/generic/pending-6.1/742-net-phy-air_en8811h-reset-netdev-rules-when-LED-is-s.patch b/target/linux/generic/pending-6.1/742-net-phy-air_en8811h-reset-netdev-rules-when-LED-is-s.patch new file mode 100644 index 0000000000..500567b4ed --- /dev/null +++ b/target/linux/generic/pending-6.1/742-net-phy-air_en8811h-reset-netdev-rules-when-LED-is-s.patch @@ -0,0 +1,45 @@ +From 9be9a00adfac8118b6d685e71696f83187308c66 Mon Sep 17 00:00:00 2001 +Message-ID: <9be9a00adfac8118b6d685e71696f83187308c66.1715125851.git.daniel@makrotopia.org> +From: Daniel Golle +Date: Tue, 7 May 2024 22:43:30 +0100 +Subject: [PATCH net] net: phy: air_en8811h: reset netdev rules when LED is set + manually +To: Andrew Lunn , + Heiner Kallweit , + Russell King , + David S. Miller , + Eric Dumazet , + Jakub Kicinski , + Paolo Abeni , + SkyLake Huang , + Eric Woudstra , + netdev@vger.kernel.org, + linux-kernel@vger.kernel.org + +Setting LED_OFF via the brightness_set should deactivate hw control, +so make sure netdev trigger rules also get cleared in that case. + +Fixes: 71e79430117d ("net: phy: air_en8811h: Add the Airoha EN8811H PHY driver") +Signed-off-by: Daniel Golle +--- +This is basically a stop-gap measure until unified LED handling has +been implemented accross all MediaTek and Airoha PHYs. +See also +https://patchwork.kernel.org/project/netdevbpf/patch/20240425023325.15586-3-SkyLake.Huang@mediatek.com/ + + drivers/net/phy/air_en8811h.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/phy/air_en8811h.c ++++ b/drivers/net/phy/air_en8811h.c +@@ -544,6 +544,10 @@ static int air_hw_led_on_set(struct phy_ + + changed |= (priv->led[index].rules != 0); + ++ /* clear netdev trigger rules in case LED_OFF has been set */ ++ if (!on) ++ priv->led[index].rules = 0; ++ + if (changed) + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, + AIR_PHY_LED_ON(index), diff --git a/target/linux/generic/pending-6.6/742-net-phy-air_en8811h-reset-netdev-rules-when-LED-is-s.patch b/target/linux/generic/pending-6.6/742-net-phy-air_en8811h-reset-netdev-rules-when-LED-is-s.patch new file mode 100644 index 0000000000..500567b4ed --- /dev/null +++ b/target/linux/generic/pending-6.6/742-net-phy-air_en8811h-reset-netdev-rules-when-LED-is-s.patch @@ -0,0 +1,45 @@ +From 9be9a00adfac8118b6d685e71696f83187308c66 Mon Sep 17 00:00:00 2001 +Message-ID: <9be9a00adfac8118b6d685e71696f83187308c66.1715125851.git.daniel@makrotopia.org> +From: Daniel Golle +Date: Tue, 7 May 2024 22:43:30 +0100 +Subject: [PATCH net] net: phy: air_en8811h: reset netdev rules when LED is set + manually +To: Andrew Lunn , + Heiner Kallweit , + Russell King , + David S. Miller , + Eric Dumazet , + Jakub Kicinski , + Paolo Abeni , + SkyLake Huang , + Eric Woudstra , + netdev@vger.kernel.org, + linux-kernel@vger.kernel.org + +Setting LED_OFF via the brightness_set should deactivate hw control, +so make sure netdev trigger rules also get cleared in that case. + +Fixes: 71e79430117d ("net: phy: air_en8811h: Add the Airoha EN8811H PHY driver") +Signed-off-by: Daniel Golle +--- +This is basically a stop-gap measure until unified LED handling has +been implemented accross all MediaTek and Airoha PHYs. +See also +https://patchwork.kernel.org/project/netdevbpf/patch/20240425023325.15586-3-SkyLake.Huang@mediatek.com/ + + drivers/net/phy/air_en8811h.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/phy/air_en8811h.c ++++ b/drivers/net/phy/air_en8811h.c +@@ -544,6 +544,10 @@ static int air_hw_led_on_set(struct phy_ + + changed |= (priv->led[index].rules != 0); + ++ /* clear netdev trigger rules in case LED_OFF has been set */ ++ if (!on) ++ priv->led[index].rules = 0; ++ + if (changed) + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, + AIR_PHY_LED_ON(index), -- 2.30.2